Merged PR 223: #810 Fix Mapping of DestinationDTO

+ NgRx Store Setup für Customer (der Store wird noch nicht verwendet, ich würde aber versuchen nach und nach den Customer Store von ngxs zu NgRx umzuziehen)
Der ngxs Store sowie die gesamte Logik ist undurchschaubar und wird uns mittelfristig vor Probleme stellen.

Related work items: #810, #811, #829, #832
This commit is contained in:
Sebastian Neumair
2020-07-13 14:04:37 +00:00
committed by Lorenz Hilpert
39 changed files with 1956 additions and 409 deletions

View File

@@ -0,0 +1,81 @@
import { Organisation, User } from '../models/user.model';
import { CustomerMapping } from './customer.mapping';
import { TestBed } from '@angular/core/testing';
import { DatePipe } from '@angular/common';
fdescribe('CustomerMapping', () => {
let mapper: CustomerMapping;
const mockUser: User = {
id: 123,
first_name: 'Vorname',
last_name: 'Nachname',
title: 'Dr',
gender: 'Herr',
email: 'test@test.de',
phone_number: '017012345678',
mobile_number: '019998765432',
organisation: {
name: 'Mock Org',
department: 'Mock Dept.',
vatId: '123',
},
delivery_addres: {
id: 456,
first_name: 'Vorname Addresse',
last_name: 'Nachname Addresse',
street: 'Test Strasse',
streetNo: 12,
zip: '80636',
city: 'Munich',
country: 'Deutschland',
},
};
beforeEach(() => {
TestBed.configureTestingModule({
providers: [DatePipe, CustomerMapping],
});
mapper = TestBed.get(CustomerMapping);
});
it('should be created', () => {
expect(mapper instanceof CustomerMapping).toBeTruthy();
});
describe('fromOrganisationToOrganisationDTO', () => {
const mockOrganisation: Organisation = mockUser.organisation;
it('should map the provided organisation (Organisation) to OrganisationDTO', () => {
const result = mapper.fromOrganisationToOrganisationDTO(mockOrganisation);
expect(result.vatId).toEqual(mockOrganisation.vatId);
expect(result.department).toEqual(mockOrganisation.department);
expect(result.name).toEqual(mockOrganisation.name);
});
});
describe('fromUserToCommunicationDetails', () => {
it('should map the provided user (User) to communication details (CommunicationDetailsDTO)', () => {
const result = mapper.fromUserToCommunicationDetails(mockUser);
expect(result.phone).toEqual(mockUser.phone_number);
expect(result.mobile).toEqual(mockUser.mobile_number);
expect(result.email).toEqual(mockUser.email);
});
});
describe('fromUserToShippingAddressDTO', () => {
it('should map the provided user (User) to shipping address (ShippingAddressDTO)', () => {
const result = mapper.fromUserToShippingAddressDTO(mockUser);
expect(result.title).toEqual(mockUser.delivery_addres.title);
expect(result.gender).toEqual(2);
expect(result.firstName).toEqual(mockUser.delivery_addres.first_name);
expect(result.lastName).toEqual(mockUser.delivery_addres.last_name);
expect(result.source).toEqual(mockUser.delivery_addres.id);
});
});
});

View File

@@ -9,12 +9,15 @@ import {
CommunicationDetailsDTO,
AssignedPayerDTO,
CustomerInfoDTO,
ShippingAddressDTO,
PayerDTO,
CustomerDTO,
ShippingAddressDTO,
} from '@swagger/crm';
import { NotificationChannels } from '../models/notification-channels.enum';
import { EntityDTOContainerOfBranchDTO } from '@swagger/checkout';
import {
EntityDTOContainerOfBranchDTO,
ShippingAddressDTO as CheckoutShippingAddressDTO,
} from '@swagger/checkout';
import { DatePipe } from '@angular/common';
import { BACKEND_API_TIMESTAMP_FORMAT } from '../utils/app.formats';
import { KeyValueDTOOfStringAndString } from '@swagger/cat';
@@ -60,7 +63,9 @@ export class CustomerMapping {
zipCode: customer.delivery_addres.zip + '',
street: customer.delivery_addres.street,
streetNumber: customer.delivery_addres.streetNo + '',
info: customer.delivery_addres.note ? customer.delivery_addres.note : null,
info: customer.delivery_addres.note
? customer.delivery_addres.note
: null,
};
}
@@ -71,7 +76,9 @@ export class CustomerMapping {
zipCode: customer.invoice_address.zip + '',
street: customer.invoice_address.street,
streetNumber: customer.invoice_address.streetNo + '',
info: customer.invoice_address.note ? customer.invoice_address.note : null,
info: customer.invoice_address.note
? customer.invoice_address.note
: null,
};
}
@@ -84,14 +91,20 @@ export class CustomerMapping {
};
}
if (Array.isArray(customer.poossible_delivery_addresses) && customer.poossible_delivery_addresses.length > 0) {
if (
Array.isArray(customer.poossible_delivery_addresses) &&
customer.poossible_delivery_addresses.length > 0
) {
customer.poossible_delivery_addresses.forEach((adrs: Address) => {
addresses.push(this.addressesItem(adrs));
shippingAddresses.push(this.addressesItem(adrs));
});
}
if (Array.isArray(customer.poossible_invoice_addresses) && customer.poossible_invoice_addresses.length > 0) {
if (
Array.isArray(customer.poossible_invoice_addresses) &&
customer.poossible_invoice_addresses.length > 0
) {
customer.poossible_invoice_addresses.forEach((adrs: Address) => {
if (adrs) {
addresses.push(this.addressesItem(adrs));
@@ -178,7 +191,9 @@ export class CustomerMapping {
}
}
private addressesItem(address: Address): EntityDTOContainerOfShippingAddressDTO {
private addressesItem(
address: Address
): EntityDTOContainerOfShippingAddressDTO {
if (!address) {
return;
}
@@ -214,7 +229,9 @@ export class CustomerMapping {
customerInfoDTOtoUser(customerInfo: CustomerInfoDTO): User {
if (isNullOrUndefined(customerInfo)) {
throw new Error('argument customerInfo:CustomerInfoDTO is null or undefined.');
throw new Error(
'argument customerInfo:CustomerInfoDTO is null or undefined.'
);
}
const id = customerInfo.id;
@@ -252,18 +269,22 @@ export class CustomerMapping {
customerInfo.notificationChannels === NotificationChannels.EmailSms;
}
let address: Address;
let baseAddres: Address = {} as Address;
if (!!customerInfo.address) {
address = {
baseAddres = {
id: Date.now() + Math.random(),
title: customerInfo.title,
first_name: customerInfo.firstName,
last_name: customerInfo.lastName,
city: customerInfo.address.city ? customerInfo.address.city : undefined,
zip: customerInfo.address.zipCode ? customerInfo.address.zipCode : undefined,
zip: customerInfo.address.zipCode
? customerInfo.address.zipCode
: undefined,
country: customerInfo.address.country,
street: customerInfo.address.street,
streetNo: customerInfo.address.streetNumber ? +customerInfo.address.streetNumber : undefined,
streetNo: customerInfo.address.streetNumber
? +customerInfo.address.streetNumber
: undefined,
};
}
@@ -310,7 +331,8 @@ export class CustomerMapping {
payement_method: null, // missing info from API
tolino: false, // missing info from API
title: null, // missing info from API
delivery_addres: address,
base_addres: baseAddres,
hasOnlineAccount: customerInfo.hasOnlineAccount,
isGuestAccount: customerInfo.isGuestAccount,
features: features,
changed: customerInfo.changed,
@@ -334,7 +356,9 @@ export class CustomerMapping {
customerDTOtoUser(customerDto: CustomerDTO): User {
if (isNullOrUndefined(customerDto)) {
throw new Error('argument customerDto:CustomerInfoDTO is null or undefined.');
throw new Error(
'argument customerDto:CustomerInfoDTO is null or undefined.'
);
}
const id = customerDto.id;
@@ -365,15 +389,16 @@ export class CustomerMapping {
let notificationEmail = false;
if (customerDto.notificationChannels) {
notificationSms =
customerDto.notificationChannels === NotificationChannels.Sms || customerDto.notificationChannels === NotificationChannels.EmailSms;
customerDto.notificationChannels === NotificationChannels.Sms ||
customerDto.notificationChannels === NotificationChannels.EmailSms;
notificationEmail =
customerDto.notificationChannels === NotificationChannels.Email ||
customerDto.notificationChannels === NotificationChannels.EmailSms;
}
let address: Address;
let baseAddres: Address;
if (!!customerDto.address) {
address = {
baseAddres = {
id: Date.now() + Math.random(),
title: customerDto.title,
first_name: customerDto.firstName,
@@ -422,7 +447,9 @@ export class CustomerMapping {
mobile_number: mobileNumber,
newUser: newUser,
customer_card: false,
createdInBranch: customerDto.createdInBranch ? customerDto.createdInBranch.id : null,
createdInBranch: customerDto.createdInBranch
? customerDto.createdInBranch.id
: null,
newsletter: false, // missing info from API
shop: false,
notificationSms: notificationSms,
@@ -430,21 +457,22 @@ export class CustomerMapping {
payement_method: null, // missing info from API
tolino: false, // missing info from API
title: null, // missing info from API
delivery_addres: address,
invoice_address: address,
poossible_delivery_addresses: [address],
poossible_invoice_addresses: [address],
features: features,
changed: customerDto.changed,
created: customerDto.created,
customerNumber: customerDto.customerNumber,
organisation: organisation,
hasOnlineAccount: customerDto.hasOnlineAccount,
};
}
fromShippingAddressDtoToAddress(shippingAddress: ShippingAddressDTO): Address {
fromShippingAddressDtoToAddress(
shippingAddress: ShippingAddressDTO
): Address {
if (isNullOrUndefined(shippingAddress)) {
throw new Error('argument shippingAddress:ShippingAddressDTO is null or undefined.');
throw new Error(
'argument shippingAddress:ShippingAddressDTO is null or undefined.'
);
}
let gender = '';
@@ -497,7 +525,10 @@ export class CustomerMapping {
};
}
fromAddressToShippingAddressDTO(address: Address, forUpdate: boolean): ShippingAddressDTO {
fromAddressToShippingAddressDTO(
address: Address,
forUpdate: boolean
): ShippingAddressDTO {
if (isNullOrUndefined(address)) {
throw new Error('argument address:Address is null or undefined.');
}
@@ -529,7 +560,10 @@ export class CustomerMapping {
lastName: address.last_name,
gender: this.getGender(address.gender),
status: 1,
isDefault: this.datePipe.transform(new Date(), BACKEND_API_TIMESTAMP_FORMAT),
isDefault: this.datePipe.transform(
new Date(),
BACKEND_API_TIMESTAMP_FORMAT
),
organisation: <OrganisationDTO>{
name: address.company_name,
department: address.company_department,
@@ -584,7 +618,10 @@ export class CustomerMapping {
lastName: address.last_name,
gender: this.getGender(address.gender),
status: 1,
isDefault: this.datePipe.transform(new Date(), BACKEND_API_TIMESTAMP_FORMAT),
isDefault: this.datePipe.transform(
new Date(),
BACKEND_API_TIMESTAMP_FORMAT
),
address: _address,
payerNumber: address.payer_number,
payerStatus: address.payer_status,
@@ -599,7 +636,9 @@ export class CustomerMapping {
fromAssignedPayerDtoToAddress(assignedPayers: AssignedPayerDTO): Address {
if (isNullOrUndefined(assignedPayers)) {
throw new Error('argument shippingAddress:ShippingAddressDTO is null or undefined.');
throw new Error(
'argument shippingAddress:ShippingAddressDTO is null or undefined.'
);
}
let id = null;
@@ -612,7 +651,11 @@ export class CustomerMapping {
}
let gender = '';
if (!!assignedPayers.payer && !!assignedPayers.payer.data && !!assignedPayers.payer.data.gender) {
if (
!!assignedPayers.payer &&
!!assignedPayers.payer.data &&
!!assignedPayers.payer.data.gender
) {
gender = this.getGenderFromCode(assignedPayers.payer.data.gender);
}
@@ -621,7 +664,11 @@ export class CustomerMapping {
let street = '';
let streetNo = null;
let zip: string = null;
if (!!assignedPayers.payer && !!assignedPayers.payer.data && !!assignedPayers.payer.data.address) {
if (
!!assignedPayers.payer &&
!!assignedPayers.payer.data &&
!!assignedPayers.payer.data.address
) {
country = assignedPayers.payer.data.address.country;
city = assignedPayers.payer.data.address.city;
street = assignedPayers.payer.data.address.street;
@@ -643,7 +690,11 @@ export class CustomerMapping {
let company_name = null;
let company_department = null;
let company_tax_number = null;
if (!!assignedPayers.payer && !!assignedPayers.payer.data && !!assignedPayers.payer.data.organisation) {
if (
!!assignedPayers.payer &&
!!assignedPayers.payer.data &&
!!assignedPayers.payer.data.organisation
) {
company_name = assignedPayers.payer.data.organisation.name;
company_department = assignedPayers.payer.data.organisation.department;
company_tax_number = assignedPayers.payer.data.organisation.vatId;
@@ -706,7 +757,9 @@ export class CustomerMapping {
zipCode: customer.delivery_addres.zip + '',
street: customer.delivery_addres.street,
streetNumber: customer.delivery_addres.streetNo + '',
info: customer.delivery_addres.note ? customer.delivery_addres.note : null,
info: customer.delivery_addres.note
? customer.delivery_addres.note
: null,
};
}
@@ -767,4 +820,44 @@ export class CustomerMapping {
? NotificationChannels.Sms
: NotificationChannels.NotSet;
}
fromOrganisationToOrganisationDTO(
organisation: Organisation
): OrganisationDTO {
if (!organisation) {
return {};
}
return {
name: organisation.name,
department: organisation.department,
vatId: organisation.vatId,
};
}
fromUserToCommunicationDetails(user: User): CommunicationDetailsDTO {
return {
phone: user.phone_number,
mobile: user.mobile_number,
email: user.email,
};
}
fromUserToShippingAddressDTO(user: User): CheckoutShippingAddressDTO {
const deliveryDetails = user.delivery_addres;
if (!deliveryDetails) {
throw Error('No Delivery Address set.');
}
return {
title: deliveryDetails.title,
gender: this.getGender(user.gender),
firstName: deliveryDetails.first_name,
lastName: deliveryDetails.last_name,
organisation: this.fromOrganisationToOrganisationDTO(user.organisation),
communicationDetails: this.fromUserToCommunicationDetails(user),
address: this.fromAddressToAddressDTO(deliveryDetails),
source: deliveryDetails.id,
};
}
}

View File

@@ -12,6 +12,7 @@ export interface User {
email?: string;
mobile_number?: string;
phone_number?: string;
base_addres?: Address;
delivery_addres?: Address;
invoice_address?: Address;
shop?: boolean;
@@ -26,6 +27,7 @@ export interface User {
notificationEmail?: boolean;
createdInBranch?: number;
customerId?: string;
hasOnlineAccount?: boolean;
isGuestAccount?: boolean;
features?: Features[];
changed?: string;

View File

@@ -1,7 +1,5 @@
import { TestBed } from '@angular/core/testing';
import { CustomerService } from './customer.service';
describe('CustomerService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
});

View File

@@ -1,6 +1,9 @@
import { Injectable } from '@angular/core';
import { QueryTokenDTO } from '@swagger/cat';
import { CustomerService as CustomerApiService, PayerService } from '@swagger/crm';
import {
CustomerService as CustomerApiService,
PayerService,
} from '@swagger/crm';
import { map, switchMap, catchError } from 'rxjs/operators';
import { Observable, of, combineLatest, BehaviorSubject } from 'rxjs';
import { CustomerMapping } from '../mappings/customer.mapping';
@@ -28,7 +31,11 @@ import { CustomerFilters } from '../../modules/customer';
})
export class CustomerService {
addAddressError$ = new BehaviorSubject<any>(null);
constructor(private customerService: CustomerApiService, private mapper: CustomerMapping, private payerService: PayerService) {}
constructor(
private customerService: CustomerApiService,
private mapper: CustomerMapping,
private payerService: PayerService
) {}
createCustomer(_customer: User): Observable<User> {
const customer: CustomerDTO = this.mapper.fromUser(_customer);
@@ -97,7 +104,9 @@ export class CustomerService {
filter?: CustomerFilters
): Observable<CustomerSearchResponse> {
const noFilters = filter
? isNullOrUndefined(filter.bonuscard) && isNullOrUndefined(filter.guestaccount) && isNullOrUndefined(filter.onlineshop)
? isNullOrUndefined(filter.bonuscard) &&
isNullOrUndefined(filter.guestaccount) &&
isNullOrUndefined(filter.onlineshop)
? true
: false
: false;
@@ -112,9 +121,15 @@ export class CustomerService {
filter:
filter && !noFilters
? {
['bonuscard']: !isNullOrUndefined(filter.bonuscard) ? String(filter.bonuscard) : undefined,
['guestaccount']: !isNullOrUndefined(filter.guestaccount) ? String(filter.guestaccount) : undefined,
['onlineshop']: !isNullOrUndefined(filter.onlineshop) ? String(filter.onlineshop) : undefined,
['bonuscard']: !isNullOrUndefined(filter.bonuscard)
? String(filter.bonuscard)
: undefined,
['guestaccount']: !isNullOrUndefined(filter.guestaccount)
? String(filter.guestaccount)
: undefined,
['onlineshop']: !isNullOrUndefined(filter.onlineshop)
? String(filter.onlineshop)
: undefined,
}
: undefined,
};
@@ -125,7 +140,9 @@ export class CustomerService {
throw new Error(response.message);
}
return {
customers: response.result.map((t) => this.mapper.customerInfoDTOtoUser(t)),
customers: response.result.map((t) =>
this.mapper.customerInfoDTOtoUser(t)
),
hits: response.hits,
message: response.message,
};
@@ -133,47 +150,61 @@ export class CustomerService {
);
}
getCustomer(customer$: Observable<ResponseArgsOfCustomerDTO>): Observable<User> {
getCustomer(
customer$: Observable<ResponseArgsOfCustomerDTO>
): Observable<User> {
return customer$.pipe(
map((response: ResponseArgsOfCustomerDTO) => {
if (response.error) {
throw new Error(response.message);
}
return {
shippingAddresses: response.result.shippingAddresses.map((addressEnity) => addressEnity.id),
shippingAddresses: response.result.shippingAddresses.map(
(addressEnity) => addressEnity.id
),
user: this.mapper.customerDTOtoUser(response.result),
};
}),
switchMap((customerResult) => {
const user = customerResult.user;
if (!customerResult.shippingAddresses || customerResult.shippingAddresses.length === 0) {
if (
!customerResult.shippingAddresses ||
customerResult.shippingAddresses.length === 0
) {
return of(customerResult.user);
}
const observablesOfShippingAddresses = customerResult.shippingAddresses.map((t) => {
return this.customerService.CustomerGetShippingaddress(t).pipe(
map((response) => {
if (response.error) {
throw new Error(response.message);
}
return response.result;
})
);
});
const shippingAddresses$ = combineLatest(observablesOfShippingAddresses);
const observablesOfShippingAddresses = customerResult.shippingAddresses.map(
(t) => {
return this.customerService.CustomerGetShippingaddress(t).pipe(
map((response) => {
if (response.error) {
throw new Error(response.message);
}
return response.result;
})
);
}
);
const shippingAddresses$ = combineLatest(
observablesOfShippingAddresses
);
return shippingAddresses$.pipe(
switchMap((address: ShippingAddressDTO[]) => {
const updatedUser = user;
if (!!address) {
const addresses = address.map((t) => {
return { ...this.mapper.fromShippingAddressDtoToAddress(t), synced: true };
return {
...this.mapper.fromShippingAddressDtoToAddress(t),
synced: true,
};
});
const defaultAddresses = addresses.reduce((ad1, ad2) => {
const defaultAddress = addresses.reduce((ad1, ad2) => {
if (ad1.defaultSince >= ad2.defaultSince) {
return ad1;
}
return ad2;
});
updatedUser.delivery_addres = defaultAddresses;
updatedUser.delivery_addres = defaultAddress;
updatedUser.poossible_delivery_addresses = addresses;
}
return of(updatedUser);
@@ -182,30 +213,39 @@ export class CustomerService {
}),
switchMap((customer: User) => {
const updateCustomer = customer;
return this.customerService.CustomerGetAssignedPayersByCustomerId(customer.id).pipe(
map((response) => {
if (response.error) {
throw new Error(response.message);
}
return { customer: customer, assignedPayers: response.result };
}),
switchMap((response) => {
if (Array.isArray(response.assignedPayers) && response.assignedPayers.length > 0) {
const invoiceAddresses = response.assignedPayers.map((t) => {
return { ...this.mapper.fromAssignedPayerDtoToAddress(t), synced: true };
});
const defaultAddresses = invoiceAddresses.reduce((ad1, ad2) => {
if (ad1.defaultSince >= ad2.defaultSince) {
return ad1;
}
return ad2;
});
updateCustomer.poossible_invoice_addresses = invoiceAddresses;
updateCustomer.invoice_address = defaultAddresses;
}
return of(updateCustomer);
})
);
return this.customerService
.CustomerGetAssignedPayersByCustomerId(customer.id)
.pipe(
map((response) => {
if (response.error) {
throw new Error(response.message);
}
return { customer: customer, assignedPayers: response.result };
}),
switchMap((response) => {
if (
Array.isArray(response.assignedPayers) &&
response.assignedPayers.length > 0
) {
const invoiceAddresses = response.assignedPayers.map((t) => {
return {
...this.mapper.fromAssignedPayerDtoToAddress(t),
synced: true,
};
});
const defaultAddress = invoiceAddresses.reduce((ad1, ad2) => {
if (ad1.defaultSince >= ad2.defaultSince) {
return ad1;
}
return ad2;
});
updateCustomer.poossible_invoice_addresses = invoiceAddresses;
updateCustomer.invoice_address = defaultAddress;
}
return of(updateCustomer);
})
);
})
);
}
@@ -223,7 +263,12 @@ export class CustomerService {
if (response.error) {
throw new Error(response.message);
}
return { customers: response.result.map((t) => this.mapper.customerInfoDTOtoUser(t)), hits: 0 };
return {
customers: response.result.map((t) =>
this.mapper.customerInfoDTOtoUser(t)
),
hits: 0,
};
})
);
}
@@ -249,25 +294,32 @@ export class CustomerService {
isDefault: true,
};
if (shippingAddress.synced === true) {
return this.customerService.CustomerModifyShippingAddressFlag(params).pipe(
map((response) => {
if (response.error) {
throw new Error(response.message);
}
return response.result;
})
);
return this.customerService
.CustomerModifyShippingAddressFlag(params)
.pipe(
map((response) => {
if (response.error) {
throw new Error(response.message);
}
return response.result;
})
);
} else {
return this.addShippingAddress(customerId, { ...shippingAddress, id: null }).pipe(
return this.addShippingAddress(customerId, {
...shippingAddress,
id: null,
}).pipe(
switchMap(() => {
return this.customerService.CustomerModifyShippingAddressFlag(params).pipe(
map((response) => {
if (response.error) {
throw new Error(response.message);
}
return response.result;
})
);
return this.customerService
.CustomerModifyShippingAddressFlag(params)
.pipe(
map((response) => {
if (response.error) {
throw new Error(response.message);
}
return response.result;
})
);
})
);
}
@@ -292,7 +344,10 @@ export class CustomerService {
})
);
} else {
return this.addInvoiceAddress(customerId, { ...invoiceAddress, id: null }).pipe(
return this.addInvoiceAddress(customerId, {
...invoiceAddress,
id: null,
}).pipe(
switchMap((payerDto: PayerDTO) => {
const params = {
payerId: payerDto.id,
@@ -316,7 +371,10 @@ export class CustomerService {
if (!isNullOrUndefined(shippingAddress.id)) {
const params = {
shippingAddressId: shippingAddress.id,
shippingAddress: this.mapper.fromAddressToShippingAddressDTO(shippingAddress, !isNullOrUndefined(shippingAddress.id)),
shippingAddress: this.mapper.fromAddressToShippingAddressDTO(
shippingAddress,
!isNullOrUndefined(shippingAddress.id)
),
customerId: customerId,
};
return this.customerService.CustomerUpdateShippingAddress(params).pipe(
@@ -344,7 +402,10 @@ export class CustomerService {
);
} else {
const params = {
shippingAddress: this.mapper.fromAddressToShippingAddressDTO(shippingAddress, !isNullOrUndefined(shippingAddress.id)),
shippingAddress: this.mapper.fromAddressToShippingAddressDTO(
shippingAddress,
!isNullOrUndefined(shippingAddress.id)
),
customerId: customerId,
};
return this.customerService.CustomerCreateShippingAddress(params).pipe(
@@ -404,15 +465,17 @@ export class CustomerService {
payerId: payerResponse.result.id,
isDefault: true,
};
return this.customerService.CustomerAddPayerReference(referenceParamsparams).pipe(
map((response) => {
if (response.error) {
throw new Error(response.message);
}
this.addAddressError$.next(undefined);
return response.result.payer.data;
})
);
return this.customerService
.CustomerAddPayerReference(referenceParamsparams)
.pipe(
map((response) => {
if (response.error) {
throw new Error(response.message);
}
this.addAddressError$.next(undefined);
return response.result.payer.data;
})
);
})
);
} else {
@@ -450,7 +513,10 @@ export class CustomerService {
if (response.error) {
throw new Error(response.message);
}
return response.result.map((t, index) => <Country>{ index, id: t.id, key: t.isO3166_A_3, value: t.name });
return response.result.map(
(t, index) =>
<Country>{ index, id: t.id, key: t.isO3166_A_3, value: t.name }
);
})
);
}

View File

@@ -10,7 +10,10 @@ import {
import { LoadBranches, LoadUserBranch } from '../actions/branch.actions';
import { BranchSelectors } from '../selectors/branch.selector';
import { isNullOrUndefined } from 'util';
import { RemoveProcessNewState, ReloadProcessData } from '../actions/process.actions';
import {
RemoveProcessNewState,
ReloadProcessData,
} from '../actions/process.actions';
import { UserStateService } from '../../services/user-state.service';
import { UserStateSyncData } from '../../models/user-state-sync.model';
import { ReloadCustomersData } from '../actions/customer.actions';
@@ -20,7 +23,7 @@ import { ReloadProductsData } from '../actions/product.actions';
import { ReloadBreadcrumbsData } from '../actions/breadcrumb.actions';
import { Router } from '@angular/router';
import { Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, switchMap, tap } from 'rxjs/operators';
import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';
import { ModuleSwitcher } from '../../models/app-switcher.enum';
import { ModuleSwitcherService } from '../../services/module-switcher.service';
import { ReloadFiltersData } from '../actions/filter.actions';
@@ -31,7 +34,7 @@ import { ReloadRemission } from '../actions/remission.actions';
import { ReloadFormState } from '../actions/forms.actions';
import { FILIALE_LANDING_PAGE } from '../../utils/app.constants';
export const SYNC_DATA_VERSION = 210;
export const SYNC_DATA_VERSION = 211;
export class AppStateModel {
currentProcesssId: number;
@@ -101,9 +104,13 @@ export class AppState {
}
@Action(AppSetCurrentProcess)
appSetCurrentProcess(ctx: StateContext<AppStateModel>, { payload }: AppSetCurrentProcess) {
appSetCurrentProcess(
ctx: StateContext<AppStateModel>,
{ payload }: AppSetCurrentProcess
) {
const state = ctx.getState();
const processExists = state.processIds.findIndex((t) => t === payload) !== -1;
const processExists =
state.processIds.findIndex((t) => t === payload) !== -1;
if (processExists) {
ctx.patchState({
currentProcesssId: payload,
@@ -115,18 +122,23 @@ export class AppState {
@Action(AppAddProcess)
appAddProcess(ctx: StateContext<AppStateModel>, { payload }: AppAddProcess) {
const state = ctx.getState();
const processExists = state.processIds.findIndex((t) => t === payload) !== -1;
const processExists =
state.processIds.findIndex((t) => t === payload) !== -1;
if (!processExists) {
const processIds = [...state.processIds, payload];
const currentProcesssId = payload;
ctx.patchState({ currentProcesssId, processIds });
const branchesLoaded = this.store.selectSnapshot(BranchSelectors.getBranches);
const branchesLoaded = this.store.selectSnapshot(
BranchSelectors.getBranches
);
if (!branchesLoaded || Object.keys(branchesLoaded).length === 0) {
this.store.dispatch(new LoadBranches());
}
const userBranch = this.store.selectSnapshot(BranchSelectors.getUserBranch);
const userBranch = this.store.selectSnapshot(
BranchSelectors.getUserBranch
);
if (isNullOrUndefined(userBranch)) {
this.store.dispatch(new LoadUserBranch());
}
@@ -136,7 +148,10 @@ export class AppState {
}
@Action(AppDeleteProcess)
appDeleteProcess(ctx: StateContext<AppStateModel>, { payload }: AppDeleteProcess) {
appDeleteProcess(
ctx: StateContext<AppStateModel>,
{ payload }: AppDeleteProcess
) {
const state = ctx.getState();
const currentIds = state.processIds;
if (currentIds) {
@@ -147,7 +162,10 @@ export class AppState {
}
@Action(AppSwitchModule)
appSwitchModule(ctx: StateContext<AppStateModel>, { payload }: AppSwitchModule) {
appSwitchModule(
ctx: StateContext<AppStateModel>,
{ payload }: AppSwitchModule
) {
const state = ctx.getState();
ctx.patchState({ activeModule: payload });
this.syncApiState(state.processIds, payload);
@@ -157,7 +175,10 @@ export class AppState {
* Save store data on backend
*/
@Action(AppUserDataSync)
appUserDataSynced(ctx: StateContext<AppStateModel>, { data, sync }: AppUserDataSync) {
appUserDataSynced(
ctx: StateContext<AppStateModel>,
{ data, sync }: AppUserDataSync
) {
const state = ctx.getState();
let currentUserData: UserStateSyncData = {};
@@ -184,7 +205,10 @@ export class AppState {
* Initial store loading from API, triggered once on page load
*/
@Action(ReloadSavedState)
reloadSavedState(ctx: StateContext<AppStateModel>, { data, sync }: ReloadSavedState) {
reloadSavedState(
ctx: StateContext<AppStateModel>,
{ data, sync }: ReloadSavedState
) {
const state = ctx.getState();
let currentUserData: UserStateSyncData = {};
@@ -208,7 +232,10 @@ export class AppState {
if (sync && syncedData.version === SYNC_DATA_VERSION) {
this.reloadDataFromAPI(syncedData);
if (syncedData.currentProcesssId || syncedData.activeModule === ModuleSwitcher.Branch) {
if (
syncedData.currentProcesssId ||
syncedData.activeModule === ModuleSwitcher.Branch
) {
ctx.patchState({
...state,
synced: true,
@@ -235,11 +262,19 @@ export class AppState {
return;
}
if (data.customers) {
this.store.dispatch(new ReloadCustomersData(data.customers, data.lastCreatedCustomerId, data.cachedCustomerSearch));
this.store.dispatch(
new ReloadCustomersData(
data.customers,
data.lastCreatedCustomerId,
data.cachedCustomerSearch
)
);
}
if (data.products) {
this.store.dispatch(new ReloadProductsData(data.products, data.cachedProductResults));
this.store.dispatch(
new ReloadProductsData(data.products, data.cachedProductResults)
);
}
if (data.carts) {
@@ -259,7 +294,9 @@ export class AppState {
}
if (data.processes) {
this.store.dispatch(new ReloadProcessData(data.processes, data.recentArticles));
this.store.dispatch(
new ReloadProcessData(data.processes, data.recentArticles)
);
}
if (data.formsState) {
@@ -267,11 +304,20 @@ export class AppState {
}
if (data.activeModule === ModuleSwitcher.Customer) {
if (data.processes && data.currentProcesssId && data.processes[data.currentProcesssId]) {
if (
data.processes &&
data.currentProcesssId &&
data.processes[data.currentProcesssId]
) {
const currentProcesssId = data.currentProcesssId;
const currentRoute = data.processes[currentProcesssId].currentRoute;
if (currentRoute && currentRoute.length > 0) {
this.routingAvailableAction(data, currentProcesssId, currentRoute, data.activeModule);
this.routingAvailableAction(
data,
currentProcesssId,
currentRoute,
data.activeModule
);
} else {
this.router.navigate(['/dashboard']);
}
@@ -283,7 +329,12 @@ export class AppState {
const currentProcesssId = -1;
const currentRoute = data.branchProcess.currentRoute;
if (currentRoute && currentRoute.length > 0) {
this.routingAvailableAction(data, currentProcesssId, currentRoute, data.activeModule);
this.routingAvailableAction(
data,
currentProcesssId,
currentRoute,
data.activeModule
);
} else {
this.router.navigate([FILIALE_LANDING_PAGE]);
}
@@ -297,11 +348,24 @@ export class AppState {
}
if (data.activeModule === ModuleSwitcher.Branch) {
this.moduleSwitcherService.switch(ModuleSwitcher.Branch, data.branchProcess);
this.moduleSwitcherService.switch(
ModuleSwitcher.Branch,
data.branchProcess
);
}
if (data.processesBreadcrumbs && data.activeCrumbs && (data.currentProcesssId || data.activeModule === ModuleSwitcher.Branch)) {
this.store.dispatch(new ReloadBreadcrumbsData(data.processesBreadcrumbs, data.activeCrumbs, data.previusMenuPath));
if (
data.processesBreadcrumbs &&
data.activeCrumbs &&
(data.currentProcesssId || data.activeModule === ModuleSwitcher.Branch)
) {
this.store.dispatch(
new ReloadBreadcrumbsData(
data.processesBreadcrumbs,
data.activeCrumbs,
data.previusMenuPath
)
);
}
if (data.filters && data.processesSelectedFilters && data.dropdownFilters) {
@@ -327,16 +391,28 @@ export class AppState {
);
}
private routingAvailableAction(data: UserStateSyncData, currentProcesssId: number, currentRoute: string, module: ModuleSwitcher) {
const hasActiveCrumbsAvailableForProcess = data.activeCrumbs && data.activeCrumbs[currentProcesssId];
private routingAvailableAction(
data: UserStateSyncData,
currentProcesssId: number,
currentRoute: string,
module: ModuleSwitcher
) {
const hasActiveCrumbsAvailableForProcess =
data.activeCrumbs && data.activeCrumbs[currentProcesssId];
const activeCrumbs = data.activeCrumbs[currentProcesssId];
const hasProcessBreadcrumbsAvailableForProcess = data.processesBreadcrumbs && data.processesBreadcrumbs[activeCrumbs];
const hasProcessBreadcrumbsAvailableForProcess =
data.processesBreadcrumbs && data.processesBreadcrumbs[activeCrumbs];
const breadcrumb = hasProcessBreadcrumbsAvailableForProcess
? data.processesBreadcrumbs[activeCrumbs].find((t) => t.processId === currentProcesssId)
? data.processesBreadcrumbs[activeCrumbs].find(
(t) => t.processId === currentProcesssId
)
: null;
const breadcrumbPath = breadcrumb && breadcrumb.breadcrumbs ? breadcrumb.breadcrumbs.find((t) => t && t.path === currentRoute) : null;
const breadcrumbPath =
breadcrumb && breadcrumb.breadcrumbs
? breadcrumb.breadcrumbs.find((t) => t && t.path === currentRoute)
: null;
if (
hasActiveCrumbsAvailableForProcess &&

View File

@@ -1,16 +1,26 @@
import { State, Action, StateContext, Store, Selector } from '@ngxs/store';
import * as actions from '../actions/cart.actions';
import { AddCartToProcess, SetFinishedOrderData, ChangeCurrentRoute } from '../actions/process.actions';
import {
AddCartToProcess,
SetFinishedOrderData,
ChangeCurrentRoute,
} from '../actions/process.actions';
import { DeleteCartEntry } from '../actions/cart-entry.actions';
import { ProcessSelectors } from '../selectors/process.selectors';
import { CheckoutService } from '../../services/checkout.service';
import { tap, catchError } from 'rxjs/operators';
import { ShoppingCartDTO, PaymentDTO, CheckoutDTO, BuyerDTO, PayerDTO } from '@swagger/checkout';
import {
ShoppingCartDTO,
PaymentDTO,
CheckoutDTO,
BuyerDTO,
PayerDTO,
DestinationDTO,
} from '@swagger/checkout';
import { DisplayOrderDTO, EnvironmentChannel } from '@swagger/oms';
import { User } from '../../models/user.model';
import { CustomerMapping } from '../../mappings/customer.mapping';
import { OrganisationDTO } from '@swagger/crm';
import { DestinationDTO } from '@swagger/checkout';
import { UserStateSyncData } from '../../models/user-state-sync.model';
import { AppUserDataSync } from '../actions/app.actions';
import { of } from 'rxjs';
@@ -48,7 +58,10 @@ export class CartState {
}
@Action(actions.SetCartToProcess)
setCartToProcess(ctx: StateContext<CartStateModel>, {}: actions.SetCartToProcess) {
setCartToProcess(
ctx: StateContext<CartStateModel>,
{}: actions.SetCartToProcess
) {
return this.checkoutService.createCart().pipe(
tap((cart: ShoppingCartDTO) => {
const state = ctx.getState();
@@ -62,28 +75,41 @@ export class CartState {
}
@Action(actions.SetCartData)
addItemToCart(ctx: StateContext<CartStateModel>, { cartEntryId }: actions.SetCartData) {
addItemToCart(
ctx: StateContext<CartStateModel>,
{ cartEntryId }: actions.SetCartData
) {
const state = ctx.getState();
const currentProcess = this.store.selectSnapshot(ProcessSelectors.getCurrentProcess);
const currentProcess = this.store.selectSnapshot(
ProcessSelectors.getCurrentProcess
);
if (!currentProcess) {
return;
}
const carts = { ...state.carts };
carts[currentProcess.cartId] = [...carts[currentProcess.cartId], cartEntryId];
carts[currentProcess.cartId] = [
...carts[currentProcess.cartId],
cartEntryId,
];
ctx.patchState({ carts });
this.syncApiState(carts);
}
@Action(actions.DeleteProductFromCart)
deleteProductFromCart(ctx: StateContext<CartStateModel>, { cartId, cartEntryId }: actions.DeleteProductFromCart) {
deleteProductFromCart(
ctx: StateContext<CartStateModel>,
{ cartId, cartEntryId }: actions.DeleteProductFromCart
) {
const state = ctx.getState();
const allCarts = { ...state.carts };
const cartEntries = allCarts[cartId];
// Remove product from
const productToDelete = cartEntries.find((entryId: number) => entryId === cartEntryId);
const productToDelete = cartEntries.find(
(entryId: number) => entryId === cartEntryId
);
if (productToDelete) {
this.store.dispatch(new DeleteCartEntry(cartEntryId, true));
}
@@ -99,7 +125,10 @@ export class CartState {
}
@Action(actions.DeleteCart)
deleteCart(ctx: StateContext<CartStateModel>, { cartId }: actions.DeleteCart) {
deleteCart(
ctx: StateContext<CartStateModel>,
{ cartId }: actions.DeleteCart
) {
const state = ctx.getState();
const carts = { ...state.carts };
const cartEntries = carts[cartId];
@@ -122,16 +151,26 @@ export class CartState {
}
@Action(actions.CreateOrder)
createOrder(ctx: StateContext<CartStateModel>, { checkoutId }: actions.CreateOrder) {
createOrder(
ctx: StateContext<CartStateModel>,
{ checkoutId }: actions.CreateOrder
) {
return this.checkoutService.createOrder(checkoutId).pipe(
tap((order: { failedItemIds: { id: number; type: number }[]; displayOrder: DisplayOrderDTO[] }) => {
this.store.dispatch(new SetFinishedOrderData(order));
}),
tap(
(order: {
failedItemIds: { id: number; type: number }[];
displayOrder: DisplayOrderDTO[];
}) => {
this.store.dispatch(new SetFinishedOrderData(order));
}
),
catchError((error) => {
const status = error.status;
const message = error && error.error ? error.error.message : undefined;
const invalidProperties =
error && error.error && error.error.invalidProperties ? JSON.stringify(error.error.invalidProperties) : undefined;
error && error.error && error.error.invalidProperties
? JSON.stringify(error.error.invalidProperties)
: undefined;
this.errorService.addErrors(status, message, invalidProperties);
this.openCart();
return of(undefined);
@@ -151,63 +190,104 @@ export class CartState {
}
@Action(actions.SetPaymentTypeToCheckout)
getPaymentToCheckout(ctx: StateContext<CartStateModel>, { checkoutId, customer, isDelivery }: actions.SetPaymentTypeToCheckout) {
getPaymentToCheckout(
ctx: StateContext<CartStateModel>,
{ checkoutId, customer, isDelivery }: actions.SetPaymentTypeToCheckout
) {
return this.checkoutService.getPayments(checkoutId).pipe(
tap((payment: PaymentDTO) => {
const type = payment.availablePaymentTypes[0].key;
this.store.dispatch(new actions.SetPaymentToCheckout(checkoutId, type, customer, isDelivery));
this.store.dispatch(
new actions.SetPaymentToCheckout(
checkoutId,
type,
customer,
isDelivery
)
);
})
);
}
@Action(actions.SetPaymentToCheckout)
setPaymentToCheckout(ctx: StateContext<CartStateModel>, { checkoutId, type, customer, isDelivery }: actions.SetPaymentToCheckout) {
setPaymentToCheckout(
ctx: StateContext<CartStateModel>,
{ checkoutId, type, customer, isDelivery }: actions.SetPaymentToCheckout
) {
return this.checkoutService.setPaymentType(checkoutId, type).pipe(
tap((checkout: CheckoutDTO) => {
this.store.dispatch(new actions.SetBuyerToCheckout(checkout.id, customer, isDelivery));
this.store.dispatch(
new actions.SetBuyerToCheckout(checkout.id, customer, isDelivery)
);
})
);
}
@Action(actions.SetBuyerToCheckout)
setBuyerToCheckout(ctx: StateContext<CartStateModel>, { checkoutId, customer, isDelivery }: actions.SetBuyerToCheckout) {
return this.checkoutService.setBuyer(checkoutId, this.buyerObject(customer)).pipe(
tap((checkout: CheckoutDTO) => {
if (!isDelivery) {
this.store.dispatch(new actions.CreateOrder(checkout.id));
} else {
this.store.dispatch(new actions.SetPayerToCheckout(checkout.id, customer));
}
})
);
setBuyerToCheckout(
ctx: StateContext<CartStateModel>,
{ checkoutId, customer, isDelivery }: actions.SetBuyerToCheckout
) {
return this.checkoutService
.setBuyer(checkoutId, this.buyerObject(customer))
.pipe(
tap((checkout: CheckoutDTO) => {
if (!isDelivery) {
this.store.dispatch(new actions.CreateOrder(checkout.id));
} else {
this.store.dispatch(
new actions.SetPayerToCheckout(checkout.id, customer)
);
}
})
);
}
@Action(actions.SetPayerToCheckout)
setPayerToCheckout(ctx: StateContext<CartStateModel>, { checkoutId, customer }: actions.SetPayerToCheckout) {
return this.checkoutService.setPayer(checkoutId, this.payerObject(customer)).pipe(
tap((checkout: CheckoutDTO) => {
this.store.dispatch(new actions.CreateOrder(checkout.id));
})
);
setPayerToCheckout(
ctx: StateContext<CartStateModel>,
{ checkoutId, customer }: actions.SetPayerToCheckout
) {
return this.checkoutService
.setPayer(checkoutId, this.payerObject(customer))
.pipe(
tap((checkout: CheckoutDTO) => {
this.store.dispatch(new actions.CreateOrder(checkout.id));
})
);
}
@Action(actions.SetDestinationToCheckout)
setDestinationToCheckout(
ctx: StateContext<CartStateModel>,
{ checkoutId, destinationId, customer, target }: actions.SetDestinationToCheckout
{
checkoutId,
destinationId,
customer,
target,
}: actions.SetDestinationToCheckout
) {
const dest = this.destinationObject(customer, destinationId, target);
return this.checkoutService.setDestination(checkoutId, destinationId, dest);
}
@Action(actions.ReloadCartData)
reloadCarts(ctx: StateContext<CartStateModel>, { carts }: actions.ReloadCartData) {
reloadCarts(
ctx: StateContext<CartStateModel>,
{ carts }: actions.ReloadCartData
) {
ctx.setState({ carts: { ...carts } });
}
@Action(actions.SetNotificationChannel)
setNotificationChannel(ctx: StateContext<CartStateModel>, { checkoutId, notificationChannel }: actions.SetNotificationChannel) {
return this.checkoutService.setNotificationChannel(checkoutId, notificationChannel);
setNotificationChannel(
ctx: StateContext<CartStateModel>,
{ checkoutId, notificationChannel }: actions.SetNotificationChannel
) {
return this.checkoutService.setNotificationChannel(
checkoutId,
notificationChannel
);
}
private syncApiState(carts: { [key: number]: number[] }) {
@@ -239,7 +319,9 @@ export class CartState {
}
private payerObject(customer: User) {
const invoice = customer.invoice_address ? customer.invoice_address : customer.delivery_addres;
const invoice = customer.invoice_address
? customer.invoice_address
: customer.delivery_addres;
const transformed = this.customerMapper.fromUser(customer);
let organisation: OrganisationDTO = {};
@@ -274,25 +356,27 @@ export class CartState {
return payerDTO;
}
private destinationObject(customer: User, destinationId: number, target?: EnvironmentChannel) {
private destinationObject(
customer: User,
destinationId: number,
target?: EnvironmentChannel
) {
const delivery = customer.delivery_addres;
if (!delivery) {
this.cartService.addOrderErrorEvent();
throw new Error(
`Delvery address is missing for customer: ${customer.first_name + ' ' + customer.last_name} when trying to set destination object.
`Delvery address is missing for customer: ${
customer.first_name + ' ' + customer.last_name
} when trying to set destination object.
Source => cart.state.ts.destinationObject. Line 238`
);
}
const transformed = this.customerMapper.fromUser(customer);
const shippingAddress = this.customerMapper.fromUserToShippingAddressDTO(
customer
);
const destinationDTO: DestinationDTO = {
shippingAddress: {
gender: this.customerMapper.getGender(delivery.gender),
communicationDetails: transformed.communicationDetails,
firstName: delivery.first_name,
lastName: delivery.last_name,
address: transformed.address,
source: delivery.id,
},
shippingAddress,
target: target ? target : 2,
id: destinationId,
};

View File

@@ -40,7 +40,10 @@ export class CustomerState {
constructor(private store: Store, private customerService: CustomerService) {}
@Action(actions.SearchUser)
searchUser(ctx: StateContext<CustomerStateModel>, { payload }: actions.SearchUser): Observable<User[]> {
searchUser(
ctx: StateContext<CustomerStateModel>,
{ payload }: actions.SearchUser
): Observable<User[]> {
return this.customerService.searchCustomer(payload).pipe(
map((response: CustomerSearchResponse) => response.customers),
tap((_customers: User[]) => {
@@ -55,21 +58,30 @@ export class CustomerState {
customers = { ...customers, [t.id]: t };
});
ctx.patchState({ customers });
this.syncApiState(customers, state.lastCreatedCustomerId, state.cachedCustomerSearch);
this.syncApiState(
customers,
state.lastCreatedCustomerId,
state.cachedCustomerSearch
);
this.store.dispatch(new AddCustomerIds(customerIds));
})
);
}
@Action(actions.AddCustomers)
addCustomers(ctx: StateContext<CustomerStateModel>, { payload }: actions.AddCustomers) {
addCustomers(
ctx: StateContext<CustomerStateModel>,
{ payload }: actions.AddCustomers
) {
const state = ctx.getState();
if (!state) {
return;
}
const currentCustomers = state.customers;
const newCustomers = payload.filter((t) => t !== undefined);
const currentCustomerIds = this.store.selectSnapshot(ProcessSelectors.getCustomerIds);
const currentCustomerIds = this.store.selectSnapshot(
ProcessSelectors.getCustomerIds
);
const customerIds = [];
let customers = currentCustomers;
if (!!currentCustomerIds) {
@@ -84,12 +96,19 @@ export class CustomerState {
}
});
ctx.patchState({ customers });
this.syncApiState(customers, state.lastCreatedCustomerId, state.cachedCustomerSearch);
this.syncApiState(
customers,
state.lastCreatedCustomerId,
state.cachedCustomerSearch
);
this.store.dispatch(new AddCustomerIds(customerIds));
}
@Action(actions.SetActiveUser)
setActiveUser(ctx: StateContext<CustomerStateModel>, { payload, cartHasItemForDownload, cartEntriesIds }: actions.SetActiveUser) {
setActiveUser(
ctx: StateContext<CustomerStateModel>,
{ payload, cartHasItemForDownload, cartEntriesIds }: actions.SetActiveUser
) {
const state = ctx.getState();
if (!state) {
return;
@@ -101,14 +120,21 @@ export class CustomerState {
ctx.patchState({ customers });
this.store.dispatch(new SetActiveCustomer(_customer.id));
this.store.dispatch(new UpdateProcessName(_customer.last_name));
this.syncApiState(customers, state.lastCreatedCustomerId, state.cachedCustomerSearch);
this.syncApiState(
customers,
state.lastCreatedCustomerId,
state.cachedCustomerSearch
);
}
})
);
}
@Action(actions.AddUser)
addUser(ctx: StateContext<CustomerStateModel>, { payload, setActiveUser }: actions.AddUser) {
addUser(
ctx: StateContext<CustomerStateModel>,
{ payload, setActiveUser }: actions.AddUser
) {
const state = ctx.getState();
let customerApi$: Observable<User>;
let isOnline = false;
@@ -126,10 +152,21 @@ export class CustomerState {
}
return customerApi$.pipe(
tap((addedCustomer: User) => {
this.store.dispatch(new SetOnlineCustomerCreationStatus({ error: false, invalidProperties: null }));
this.store.dispatch(
new SetOnlineCustomerCreationStatus({
error: false,
invalidProperties: null,
})
);
if (state.customers[addedCustomer.id] === undefined) {
const customers = { ...state.customers, [addedCustomer.id]: addedCustomer };
ctx.patchState({ customers, lastCreatedCustomerId: addedCustomer.id });
const customers = {
...state.customers,
[addedCustomer.id]: addedCustomer,
};
ctx.patchState({
customers,
lastCreatedCustomerId: addedCustomer.id,
});
}
if (setActiveUser) {
@@ -153,7 +190,8 @@ export class CustomerState {
this.store.dispatch(
new SetOnlineCustomerCreationStatus({
error: true,
invalidProperties: error && error.error ? error.error.invalidProperties : undefined,
invalidProperties:
error && error.error ? error.error.invalidProperties : undefined,
})
);
console.error(error);
@@ -163,24 +201,40 @@ export class CustomerState {
}
@Action(actions.SetUserDetails)
editUser(ctx: StateContext<CustomerStateModel>, { payload, addBreadcrumb }: actions.SetUserDetails) {
editUser(
ctx: StateContext<CustomerStateModel>,
{ payload, addBreadcrumb }: actions.SetUserDetails
) {
const state = ctx.getState();
const id = +payload.id;
if (!state) {
return;
}
if (payload.features && payload.features.findIndex((v) => v.key === 'onlineshop') >= 0) {
const customers = { ...state.customers, [id]: { ...payload, id: id, error: null } };
if (
payload.features &&
payload.features.findIndex((v) => v.key === 'onlineshop') >= 0
) {
const customers = {
...state.customers,
[id]: { ...payload, id: id, error: null },
};
ctx.patchState({ customers });
this.syncApiState(customers, state.lastCreatedCustomerId, state.cachedCustomerSearch);
this.syncApiState(
customers,
state.lastCreatedCustomerId,
state.cachedCustomerSearch
);
return;
}
return this.customerService.updateCustomer(payload).pipe(
catchError((error) => {
console.error(error);
const customers = { ...state.customers, [id]: { ...state.customers[id], id: id, error: error } };
const customers = {
...state.customers,
[id]: { ...state.customers[id], id: id, error: error },
};
ctx.patchState({ customers });
return of(undefined);
}),
@@ -188,7 +242,10 @@ export class CustomerState {
if (!addedCustomer) {
return;
}
const customers = { ...state.customers, [id]: { ...payload, id: id, error: null } };
const customers = {
...state.customers,
[id]: { ...payload, id: id, error: null },
};
ctx.patchState({ customers });
if (addBreadcrumb) {
this.store.dispatch(
@@ -201,13 +258,20 @@ export class CustomerState {
)
);
}
this.syncApiState(customers, state.lastCreatedCustomerId, state.cachedCustomerSearch);
this.syncApiState(
customers,
state.lastCreatedCustomerId,
state.cachedCustomerSearch
);
})
);
}
@Action(actions.SetUserDetailsById)
getUserDetails(ctx: StateContext<CustomerStateModel>, { payload, addBreadcrumb }: actions.SetUserDetailsById) {
getUserDetails(
ctx: StateContext<CustomerStateModel>,
{ payload, addBreadcrumb }: actions.SetUserDetailsById
) {
const state = ctx.getState();
if (!state) {
return;
@@ -215,7 +279,12 @@ export class CustomerState {
return this.customerService.getCustomerById(payload).pipe(
tap((user: User) => {
if (user) {
ctx.setState(this.updateCustomer({ ...user, id: +payload }, state.lastCreatedCustomerId));
ctx.setState(
this.updateCustomer(
{ ...user, id: +payload },
state.lastCreatedCustomerId
)
);
}
})
);
@@ -229,7 +298,10 @@ export class CustomerState {
}
@Action(actions.DeleteCustomerForProcess)
deleteCustomerForProcess(ctx: StateContext<CustomerStateModel>, { payload }: actions.DeleteCustomerForProcess) {
deleteCustomerForProcess(
ctx: StateContext<CustomerStateModel>,
{ payload }: actions.DeleteCustomerForProcess
) {
const state = ctx.getState();
if (!state) {
return;
@@ -238,19 +310,29 @@ export class CustomerState {
delete customers[payload];
ctx.patchState({ customers });
this.store.dispatch(new RemoveCustomerId(payload));
this.syncApiState(customers, state.lastCreatedCustomerId, state.cachedCustomerSearch);
this.syncApiState(
customers,
state.lastCreatedCustomerId,
state.cachedCustomerSearch
);
return this.customerService.deleteCustomer(payload);
}
@Action(actions.SetDefaultShippingAddress)
setDefaultShippingAddress(ctx: StateContext<CustomerStateModel>, { customerId, shippingAddress }: actions.SetDefaultShippingAddress) {
setDefaultShippingAddress(
ctx: StateContext<CustomerStateModel>,
{ customerId, shippingAddress }: actions.SetDefaultShippingAddress
) {
const state = ctx.getState();
if (!state) {
return;
}
const currentCustomers = state.customers;
const shipping$ = this.customerService.setShippingAddressAsDefault(shippingAddress, customerId);
const shipping$ = this.customerService.setShippingAddressAsDefault(
shippingAddress,
customerId
);
if (!shipping$) {
return;
}
@@ -259,23 +341,38 @@ export class CustomerState {
const customer = currentCustomers[customerId];
const updatedCustomer = {
...customer,
delivery_addres: customer.poossible_delivery_addresses.find((t) => t.id === shippingAddress.id),
delivery_addres: customer.poossible_delivery_addresses.find(
(t) => t.id === shippingAddress.id
),
};
const customers = {
...currentCustomers,
[updatedCustomer.id]: updatedCustomer,
};
const customers = { ...currentCustomers, [updatedCustomer.id]: updatedCustomer };
ctx.patchState({ customers });
this.syncApiState(customers, state.lastCreatedCustomerId, state.cachedCustomerSearch);
this.syncApiState(
customers,
state.lastCreatedCustomerId,
state.cachedCustomerSearch
);
})
);
}
@Action(actions.SetDefaultInvoiceAddress)
setDefaultInvoiceAddress(ctx: StateContext<CustomerStateModel>, { customerId, invoiceAddress }: actions.SetDefaultInvoiceAddress) {
setDefaultInvoiceAddress(
ctx: StateContext<CustomerStateModel>,
{ customerId, invoiceAddress }: actions.SetDefaultInvoiceAddress
) {
const state = ctx.getState();
if (!state) {
return;
}
const currentCustomers = state.customers;
const invoice$ = this.customerService.setInvoiceAddressAsDefault(invoiceAddress, customerId);
const invoice$ = this.customerService.setInvoiceAddressAsDefault(
invoiceAddress,
customerId
);
if (!invoice$) {
return;
}
@@ -284,17 +381,29 @@ export class CustomerState {
const customer = currentCustomers[customerId];
const updatedCustomer = {
...customer,
invoice_address: customer.poossible_invoice_addresses.find((t) => t.id === invoiceAddress.id),
invoice_address: customer.poossible_invoice_addresses.find(
(t) => t.id === invoiceAddress.id
),
};
const customers = {
...currentCustomers,
[updatedCustomer.id]: updatedCustomer,
};
const customers = { ...currentCustomers, [updatedCustomer.id]: updatedCustomer };
ctx.patchState({ customers });
this.syncApiState(customers, state.lastCreatedCustomerId, state.cachedCustomerSearch);
this.syncApiState(
customers,
state.lastCreatedCustomerId,
state.cachedCustomerSearch
);
})
);
}
@Action(actions.AddNewShippingAddress)
addNewShippingAddress(ctx: StateContext<CustomerStateModel>, { customerId, shippingAddress }: actions.AddNewShippingAddress) {
addNewShippingAddress(
ctx: StateContext<CustomerStateModel>,
{ customerId, shippingAddress }: actions.AddNewShippingAddress
) {
const state = ctx.getState();
if (!state) {
return;
@@ -310,27 +419,53 @@ export class CustomerState {
updatedCustomer = <User>{
...customer,
delivery_addres: address,
poossible_delivery_addresses: [...customer.poossible_delivery_addresses.filter((t) => t.id !== address.id), address],
poossible_invoice_addresses: [...customer.poossible_invoice_addresses.filter((t) => t.id !== address.id), address],
poossible_delivery_addresses: [
...(customer.poossible_delivery_addresses.filter(
(t) => t.id !== address.id
) || []),
address,
],
poossible_invoice_addresses: [
...(customer.poossible_invoice_addresses.filter(
(t) => t.id !== address.id
) || []),
address,
],
};
} else {
updatedCustomer = <User>{
...customer,
delivery_addres: address,
poossible_delivery_addresses: [...customer.poossible_delivery_addresses, address],
poossible_invoice_addresses: [...customer.poossible_invoice_addresses, address],
poossible_delivery_addresses: [
...(customer.poossible_delivery_addresses || []),
address,
],
poossible_invoice_addresses: [
...(customer.poossible_invoice_addresses || []),
address,
],
};
}
this.store.dispatch(new actions.SetUserDetailsById(customerId));
const customers = { ...currentCustomers, [updatedCustomer.id]: updatedCustomer };
const customers = {
...currentCustomers,
[updatedCustomer.id]: updatedCustomer,
};
ctx.patchState({ customers });
this.syncApiState(customers, state.lastCreatedCustomerId, state.cachedCustomerSearch);
this.syncApiState(
customers,
state.lastCreatedCustomerId,
state.cachedCustomerSearch
);
})
);
}
@Action(actions.AddNewInvoiceAddress)
addNewInvoiceAddress(ctx: StateContext<CustomerStateModel>, { customerId, invoiceAddress }: actions.AddNewInvoiceAddress) {
addNewInvoiceAddress(
ctx: StateContext<CustomerStateModel>,
{ customerId, invoiceAddress }: actions.AddNewInvoiceAddress
) {
const state = ctx.getState();
if (!state) {
return;
@@ -346,27 +481,53 @@ export class CustomerState {
updatedCustomer = <User>{
...customer,
invoice_address: address,
poossible_delivery_addresses: [...customer.poossible_delivery_addresses.filter((t) => t && t.id !== address.id), address],
poossible_invoice_addresses: [...customer.poossible_invoice_addresses.filter((t) => t && t.id !== address.id), address],
poossible_delivery_addresses: [
...(customer.poossible_delivery_addresses.filter(
(t) => t && t.id !== address.id
) || []),
address,
],
poossible_invoice_addresses: [
...(customer.poossible_invoice_addresses.filter(
(t) => t && t.id !== address.id
) || []),
address,
],
};
} else {
updatedCustomer = <User>{
...customer,
invoice_address: address,
poossible_delivery_addresses: [...customer.poossible_delivery_addresses, address],
poossible_invoice_addresses: [...customer.poossible_invoice_addresses, address],
poossible_delivery_addresses: [
...(customer.poossible_delivery_addresses || []),
address,
],
poossible_invoice_addresses: [
...(customer.poossible_invoice_addresses || []),
address,
],
};
}
this.store.dispatch(new actions.SetUserDetailsById(customerId));
const customers = { ...currentCustomers, [updatedCustomer.id]: updatedCustomer };
const customers = {
...currentCustomers,
[updatedCustomer.id]: updatedCustomer,
};
ctx.patchState({ customers });
this.syncApiState(customers, state.lastCreatedCustomerId, state.cachedCustomerSearch);
this.syncApiState(
customers,
state.lastCreatedCustomerId,
state.cachedCustomerSearch
);
})
);
}
@Action(actions.SetLastCreatedCustomerId)
setLastCreatedCustomerId(ctx: StateContext<CustomerStateModel>, { customerId }: actions.SetLastCreatedCustomerId) {
setLastCreatedCustomerId(
ctx: StateContext<CustomerStateModel>,
{ customerId }: actions.SetLastCreatedCustomerId
) {
const state = ctx.getState();
if (!state) {
return;
@@ -376,30 +537,45 @@ export class CustomerState {
}
@Action(actions.SetCachedCustomers)
setCachedCustomers(ctx: StateContext<CustomerStateModel>, { cachedCustomerSearch }: actions.SetCachedCustomers) {
setCachedCustomers(
ctx: StateContext<CustomerStateModel>,
{ cachedCustomerSearch }: actions.SetCachedCustomers
) {
const state = ctx.getState();
const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
const currentProcessId = this.store.selectSnapshot(
AppState.getCurrentProcessId
);
if (currentProcessId) {
const cachedCustomers = { ...state.cachedCustomerSearch };
cachedCustomers[currentProcessId] = cachedCustomerSearch;
ctx.patchState({ cachedCustomerSearch: cachedCustomers });
this.syncApiState(state.customers, state.lastCreatedCustomerId, cachedCustomers);
this.syncApiState(
state.customers,
state.lastCreatedCustomerId,
cachedCustomers
);
}
}
@Action(actions.ClearCachedCustomers)
clearCachedCustomers(ctx: StateContext<CustomerStateModel>) {
const state = ctx.getState();
const currentProcessId = this.store.selectSnapshot(AppState.getCurrentProcessId);
const currentProcessId = this.store.selectSnapshot(
AppState.getCurrentProcessId
);
if (currentProcessId) {
const cachedCustomers = { ...state.cachedCustomerSearch };
cachedCustomers[currentProcessId] = undefined;
ctx.patchState({ cachedCustomerSearch: cachedCustomers });
this.syncApiState(state.customers, state.lastCreatedCustomerId, cachedCustomers);
this.syncApiState(
state.customers,
state.lastCreatedCustomerId,
cachedCustomers
);
}
}
@@ -414,7 +590,11 @@ export class CustomerState {
@Action(actions.ReloadCustomersData)
reloadProcesses(
ctx: StateContext<CustomerStateModel>,
{ customers, lastCreatedCustomerId, cachedCustomerSearch }: actions.ReloadCustomersData
{
customers,
lastCreatedCustomerId,
cachedCustomerSearch,
}: actions.ReloadCustomersData
) {
ctx.patchState({ customers, lastCreatedCustomerId, cachedCustomerSearch });
}

View File

@@ -1,7 +1,6 @@
import {
Component,
OnInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
OnDestroy,
Output,
@@ -25,8 +24,12 @@ import { AddBreadcrumb } from '../../../../core/store/actions/breadcrumb.actions
import { SharedSelectors } from '../../../../core/store/selectors/shared.selectors';
import { Observable, Subject } from 'rxjs';
import { ProcessCart } from '../../../../core/models/process-cart.model';
import { map, filter, take, takeUntil } from 'rxjs/operators';
import { deliveryFilter, CartReviewItem, cartToCartReviewArray } from '../../pages/cart-review/cart-review.component';
import { map, filter, takeUntil } from 'rxjs/operators';
import {
deliveryFilter,
CartReviewItem,
cartToCartReviewArray,
} from '../../pages/cart-review/cart-review.component';
import { Address } from '../../../../core/models/user.model';
import { isArrayMinLength } from '../../../../core/utils/app.utils';
import { DeleteProductFromCart } from 'apps/sales/src/app/core/store/actions/cart.actions';
@@ -49,7 +52,11 @@ export class DeliveryCartComponent implements OnInit, OnDestroy {
lastDeletedItemIndex = -1;
destroy$ = new Subject();
constructor(private store: Store, private router: Router, private cdr: ChangeDetectorRef) {}
constructor(
private store: Store,
private router: Router,
private cdr: ChangeDetectorRef
) {}
ngOnInit() {
this.delivery$ = this.cartData$.pipe(
@@ -87,7 +94,14 @@ export class DeliveryCartComponent implements OnInit, OnDestroy {
}
const customer = cart.customer;
if (customer.delivery_addres) {
const { first_name, last_name, street, streetNo, zip, city } = customer.delivery_addres;
const {
first_name,
last_name,
street,
streetNo,
zip,
city,
} = customer.delivery_addres;
this.deliveryAddress = `${first_name} ${last_name} | ${street} ${streetNo}, ${zip} ${city}`;
}
this.detectChanges();
@@ -111,7 +125,9 @@ export class DeliveryCartComponent implements OnInit, OnDestroy {
this.store.dispatch(new SetDetailsCustomer(customerId));
this.store.dispatch(new ChangeCurrentRoute(currentRoute));
this.store.dispatch(new AddBreadcrumb(newBread, 'shoppingCart'));
this.router.navigate([currentRoute], { queryParams: { cart: true, notEditable: true } });
this.router.navigate([currentRoute], {
queryParams: { cart: true, notEditable: true },
});
}
}
@@ -120,7 +136,10 @@ export class DeliveryCartComponent implements OnInit, OnDestroy {
this.store.dispatch(
new AddBreadcrumb(
{
name: item.product.name ? item.product.name.substring(0, 12) + (item.product.name.length > 12 ? '...' : '') : '',
name: item.product.name
? item.product.name.substring(0, 12) +
(item.product.name.length > 12 ? '...' : '')
: '',
path: '/product/details/' + item.id,
},
'product'
@@ -133,12 +152,18 @@ export class DeliveryCartComponent implements OnInit, OnDestroy {
}
validateDeliveryAddress(processCart) {
const deliveryExist = processCart.cart.some((item: Cart) => item.deliveryType === DeliveryOption.DELIVERY);
const deliveryExist = processCart.cart.some(
(item: Cart) => item.deliveryType === DeliveryOption.DELIVERY
);
const missingAddress =
processCart.customer && (!this.isAddressSet(processCart.customer.delivery_addres) || !processCart.customer.email);
processCart.customer &&
(!this.isAddressSet(processCart.customer.delivery_addres) ||
!processCart.customer.email);
if (deliveryExist && missingAddress) {
this.store.dispatch(new UpdateCustomerFormState(CustomerFormState.MISSING_DELIVERY));
this.store.dispatch(
new UpdateCustomerFormState(CustomerFormState.MISSING_DELIVERY)
);
const currentRoute = `customer/search/missing-data/${processCart.customer.id}`;
this.store.dispatch(new ChangeCurrentRoute(currentRoute));
this.router.navigate([currentRoute], { queryParams: { card: 'create' } });
@@ -169,20 +194,29 @@ export class DeliveryCartComponent implements OnInit, OnDestroy {
}
getDeleteAnimation(index: number) {
const animation = index >= this.lastDeletedItemIndex && this.lastDeletedItemIndex !== -1 ? 'delete' : '';
const animation =
index >= this.lastDeletedItemIndex && this.lastDeletedItemIndex !== -1
? 'delete'
: '';
return animation;
}
deleteItem(item: CartReviewItem, index: number) {
this.lastDeletedItemIndex = index;
if (item) {
this.store.dispatch(new DeleteProductFromCart(item.cartId, item.cartEntryId));
this.store.dispatch(
new DeleteProductFromCart(item.cartId, item.cartEntryId)
);
}
}
detectChanges() {
setTimeout(() => {
if (this.cdr !== null && this.cdr !== undefined && !(this.cdr as ViewRef).destroyed) {
if (
this.cdr !== null &&
this.cdr !== undefined &&
!(this.cdr as ViewRef).destroyed
) {
this.cdr.detectChanges();
}
}, 0);

View File

@@ -1,7 +1,10 @@
import { Component, OnInit, OnDestroy, Input } from '@angular/core';
import { ModalService, ButtonComponent } from '@libs/ui';
import { Breadcrumb } from '../../../../core/models/breadcrumb.model';
import { ChangeCurrentRoute, EmptyFinishedOrders } from '../../../../core/store/actions/process.actions';
import {
ChangeCurrentRoute,
EmptyFinishedOrders,
} from '../../../../core/store/actions/process.actions';
import { Store, Select } from '@ngxs/store';
import { Router } from '@angular/router';
import { AddBreadcrumb } from '../../../../core/store/actions/breadcrumb.actions';
@@ -10,8 +13,15 @@ import { ProcessSelectors } from '../../../../core/store/selectors/process.selec
import { Observable, Subject, of, forkJoin } from 'rxjs';
import { takeUntil, switchMap, filter, map } from 'rxjs/operators';
import { CheckoutService } from '../../../../core/services/checkout.service';
import { CheckoutDTO, EntityDTOContainerOfDestinationDTO } from '@swagger/checkout';
import { SetPaymentTypeToCheckout, SetDestinationToCheckout, SetNotificationChannel } from '../../../../core/store/actions/cart.actions';
import {
CheckoutDTO,
EntityDTOContainerOfDestinationDTO,
} from '@swagger/checkout';
import {
SetPaymentTypeToCheckout,
SetDestinationToCheckout,
SetNotificationChannel,
} from '../../../../core/store/actions/cart.actions';
import { User } from '../../../../core/models/user.model';
import { CustomerSelectors } from 'apps/sales/src/app/core/store/selectors/customer.selectors';
import { isNullOrUndefined } from 'util';
@@ -99,19 +109,31 @@ export class PayMethodComponent implements OnInit, OnDestroy {
return this.checkoutService.createCheckout(this.cartId).pipe(
takeUntil(this.destroy$),
switchMap((checkout: CheckoutDTO) => {
return this.setNotificationChannel(checkout, this.customer, this.delivery || this.download);
return this.setNotificationChannel(
checkout,
this.customer,
this.delivery || this.download
);
}),
switchMap((response) => {
if (this.delivery || this.download) {
const deliveryShippingDestionation = response.checkout.destinations.find(
(dest: EntityDTOContainerOfDestinationDTO) => this.delivery && dest.data.target === 2
(dest: EntityDTOContainerOfDestinationDTO) =>
this.delivery && dest.data.target === 2
);
const downloadShippingDestionation = response.checkout.destinations.find(
(dest: EntityDTOContainerOfDestinationDTO) => this.download && dest.data.target === 16
(dest: EntityDTOContainerOfDestinationDTO) =>
this.download && dest.data.target === 16
);
if (!deliveryShippingDestionation && !downloadShippingDestionation) {
return forkJoin(
this.store.dispatch(new SetPaymentTypeToCheckout(response.checkout.id, this.customer, response.delivery)),
this.store.dispatch(
new SetPaymentTypeToCheckout(
response.checkout.id,
this.customer,
response.delivery
)
),
of({
checkout: response.checkout,
delivery: response.delivery,
@@ -122,12 +144,13 @@ export class PayMethodComponent implements OnInit, OnDestroy {
);
}
if (deliveryShippingDestionation && !downloadShippingDestionation) {
// TODO HERE TTHE ERROR HAPPENS
return forkJoin(
this.store.dispatch(
new SetDestinationToCheckout(
response.checkout.id,
deliveryShippingDestionation.id,
response.customer,
this.customer,
deliveryShippingDestionation.data.target
)
),
@@ -139,13 +162,16 @@ export class PayMethodComponent implements OnInit, OnDestroy {
downloadDestinationDTO: undefined,
})
);
} else if (!deliveryShippingDestionation && downloadShippingDestionation) {
} else if (
!deliveryShippingDestionation &&
downloadShippingDestionation
) {
return forkJoin(
this.store.dispatch(
new SetDestinationToCheckout(
response.checkout.id,
downloadShippingDestionation.id,
response.customer,
this.customer,
downloadShippingDestionation.data.target
)
),
@@ -157,13 +183,16 @@ export class PayMethodComponent implements OnInit, OnDestroy {
downloadDestinationDTO: undefined,
})
);
} else if (deliveryShippingDestionation && downloadShippingDestionation) {
} else if (
deliveryShippingDestionation &&
downloadShippingDestionation
) {
return forkJoin(
this.store.dispatch(
new SetDestinationToCheckout(
response.checkout.id,
deliveryShippingDestionation.id,
response.customer,
this.customer,
deliveryShippingDestionation.data.target
)
),
@@ -177,7 +206,13 @@ export class PayMethodComponent implements OnInit, OnDestroy {
);
} else {
return forkJoin(
this.store.dispatch(new SetPaymentTypeToCheckout(response.checkout.id, this.customer, response.delivery)),
this.store.dispatch(
new SetPaymentTypeToCheckout(
response.checkout.id,
this.customer,
response.delivery
)
),
of({
checkout: response.checkout,
delivery: response.delivery,
@@ -189,7 +224,13 @@ export class PayMethodComponent implements OnInit, OnDestroy {
}
} else {
return forkJoin(
this.store.dispatch(new SetPaymentTypeToCheckout(response.checkout.id, this.customer, response.delivery)),
this.store.dispatch(
new SetPaymentTypeToCheckout(
response.checkout.id,
this.customer,
response.delivery
)
),
of({
checkout: response.checkout,
delivery: response.delivery,
@@ -202,8 +243,19 @@ export class PayMethodComponent implements OnInit, OnDestroy {
}),
switchMap(([, data]) => {
if (data.finished) {
return forkJoin(of({}), of({ checkout: data.checkout, delivery: data.delivery, finished: true }));
} else if (!data.finished && data.downloadDestinationNedded && !isNullOrUndefined(data.downloadDestinationDTO)) {
return forkJoin(
of({}),
of({
checkout: data.checkout,
delivery: data.delivery,
finished: true,
})
);
} else if (
!data.finished &&
data.downloadDestinationNedded &&
!isNullOrUndefined(data.downloadDestinationDTO)
) {
return forkJoin(
this.store.dispatch(
new SetDestinationToCheckout(
@@ -213,12 +265,26 @@ export class PayMethodComponent implements OnInit, OnDestroy {
data.downloadDestinationDTO.target
)
),
of({ checkout: data.checkout, delivery: data.delivery, finished: false })
of({
checkout: data.checkout,
delivery: data.delivery,
finished: false,
})
);
} else {
return forkJoin(
this.store.dispatch(new SetPaymentTypeToCheckout(data.checkout.id, this.customer, data.delivery)),
of({ checkout: data.checkout, delivery: data.delivery, finished: true })
this.store.dispatch(
new SetPaymentTypeToCheckout(
data.checkout.id,
this.customer,
data.delivery
)
),
of({
checkout: data.checkout,
delivery: data.delivery,
finished: true,
})
);
}
}),
@@ -226,7 +292,13 @@ export class PayMethodComponent implements OnInit, OnDestroy {
if (data.finished) {
return of({});
} else {
return this.store.dispatch(new SetPaymentTypeToCheckout(data.checkout.id, this.customer, data.delivery));
return this.store.dispatch(
new SetPaymentTypeToCheckout(
data.checkout.id,
this.customer,
data.delivery
)
);
}
})
);
@@ -251,13 +323,17 @@ export class PayMethodComponent implements OnInit, OnDestroy {
customer: User,
delivery: boolean
): Observable<{ checkout: CheckoutDTO; customer: User; delivery: boolean }> {
const user: User = this.store.selectSnapshot(CustomerSelectors.getCurrentProcessActiveUser);
const notificationChannel = this.customerMap.getNotificationChannels(user);
return this.store.dispatch(new SetNotificationChannel(checkout.id, notificationChannel)).pipe(
map(() => {
return { checkout, customer, delivery };
})
const user: User = this.store.selectSnapshot(
CustomerSelectors.getCurrentProcessActiveUser
);
const notificationChannel = this.customerMap.getNotificationChannels(user);
return this.store
.dispatch(new SetNotificationChannel(checkout.id, notificationChannel))
.pipe(
map(() => {
return { checkout, customer, delivery };
})
);
}
ngOnDestroy() {

View File

@@ -269,6 +269,7 @@ export class CreateCustomerCardComponent implements OnInit, OnDestroy {
if (this.cartHasItemsForDownload) {
this.headerText =
// tslint:disable-next-line: max-line-length
'Um Ihnen das ebook bereitstellen zu können, brauchen Sie ein Onlinekonto bei Hugendubel. Wir richten es Ihnen gerne sofort ein.';
}
}
@@ -308,7 +309,11 @@ export class CreateCustomerCardComponent implements OnInit, OnDestroy {
this.formState = process.customerFormState;
this.canBeSetToActiveUser = !process.closeDirectlyTab;
this.customerFormState = process.customerFormState;
if (process.customerFormState === CustomerFormState.MISSING_DELIVERY) {
if (
process.customerFormState === CustomerFormState.MISSING_DELIVERY &&
this.customer.customer &&
this.customer.customer.hasOnlineAccount
) {
this.buildSetDeliveryAddressForm(this.fb, this.customer.customer);
this.customerHelper.customerUpdateRedirect();
this.id = this.customer.customer.id;
@@ -316,7 +321,9 @@ export class CreateCustomerCardComponent implements OnInit, OnDestroy {
this.btnText = 'Weiter';
this.create = false;
} else if (
process.customerFormState === CustomerFormState.MISSING_ONLINE
process.customerFormState === CustomerFormState.MISSING_ONLINE ||
(process.customerFormState === CustomerFormState.MISSING_DELIVERY &&
!this.customer.customer.hasOnlineAccount)
) {
this.buildSetDeliveryAddressForm(this.fb, this.customer.customer);
this.customerHelper.customerUpdateRedirect();

View File

@@ -1,14 +1,36 @@
import { Store, Select } from '@ngxs/store';
import { Component, OnInit, OnDestroy, Input, ViewChild, ChangeDetectorRef } from '@angular/core';
import { FormGroup, FormBuilder, Validators, AbstractControl } from '@angular/forms';
import {
Component,
OnInit,
OnDestroy,
Input,
ViewChild,
ChangeDetectorRef,
} from '@angular/core';
import {
FormGroup,
FormBuilder,
Validators,
AbstractControl,
} from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { Subject, Observable, of } from 'rxjs';
import { SharedSelectors } from '../../../../core/store/selectors/shared.selectors';
import { EditCustomerData } from '../../../../core/models/edit-customer.model';
import { takeUntil, distinctUntilChanged, take, map, filter, switchMap } from 'rxjs/operators';
import {
takeUntil,
distinctUntilChanged,
take,
map,
filter,
switchMap,
} from 'rxjs/operators';
import { User, Address } from '../../../../core/models/user.model';
import { ChangeCurrentRoute } from 'apps/sales/src/app/core/store/actions/process.actions';
import { AddNewShippingAddress, AddNewInvoiceAddress } from 'apps/sales/src/app/core/store/actions/customer.actions';
import {
AddNewShippingAddress,
AddNewInvoiceAddress,
} from 'apps/sales/src/app/core/store/actions/customer.actions';
import { GENDERS, TIITLES } from '../../dropdown-values';
import { CountrySelector } from 'apps/sales/src/app/core/store/selectors/countries.selector';
import { Country } from 'apps/sales/src/app/core/models/country.model';
@@ -35,9 +57,14 @@ export class CustomerAddressFormComponent implements OnInit, OnDestroy {
@Input() title: string;
@Input() addressId: string;
@Input() isBillingForm = true;
@Select(SharedSelectors.getCustomerEditData) customerEditData$: Observable<EditCustomerData>;
@Select(CountrySelector.getCountriesIterable) countries$: Observable<Country[]>;
@ViewChild('suggestions', { static: false }) suggestions: AddressSugestionsComponent;
@Select(SharedSelectors.getCustomerEditData) customerEditData$: Observable<
EditCustomerData
>;
@Select(CountrySelector.getCountriesIterable) countries$: Observable<
Country[]
>;
@ViewChild('suggestions', { static: false })
suggestions: AddressSugestionsComponent;
@ViewChild('postBtn', { static: false }) postBtn: ButtonComponent;
form: FormGroup;
submitted = false;
@@ -74,7 +101,7 @@ export class CustomerAddressFormComponent implements OnInit, OnDestroy {
private cdrf: ChangeDetectorRef,
private errorService: ErrorService,
private route: ActivatedRoute
) { }
) {}
ngOnInit(): void {
if (this.customerInput) {
@@ -82,9 +109,13 @@ export class CustomerAddressFormComponent implements OnInit, OnDestroy {
this.customer = this.customerInput;
if (this.isBillingForm) {
this.selecetedAddress = this.customerInput.poossible_invoice_addresses.find((address: Address) => address.id === +this.addressId);
this.selecetedAddress = this.customerInput.poossible_invoice_addresses.find(
(address: Address) => address.id === +this.addressId
);
} else {
this.selecetedAddress = this.customerInput.poossible_delivery_addresses.find((address: Address) => address.id === +this.addressId);
this.selecetedAddress = this.customerInput.poossible_delivery_addresses.find(
(address: Address) => address.id === +this.addressId
);
}
this.buildForm(this.fb, this.selecetedAddress);
this.onFormChange();
@@ -113,11 +144,13 @@ export class CustomerAddressFormComponent implements OnInit, OnDestroy {
this.countryList = data;
});
this.route.queryParams.pipe(takeUntil(this.destroy$)).subscribe((queryParams) => {
if (queryParams && queryParams['notEditable']) {
this.notEditable = true;
}
});
this.route.queryParams
.pipe(takeUntil(this.destroy$))
.subscribe((queryParams) => {
if (queryParams && queryParams['notEditable']) {
this.notEditable = true;
}
});
this.setCompanyValidators();
}
@@ -126,7 +159,9 @@ export class CustomerAddressFormComponent implements OnInit, OnDestroy {
// store address form data on changes
this.form.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((v) => {
const formStateString = JSON.stringify(v);
this.store.dispatch(new SaveFormState(ADDRESS_FORM_STATE_KEY, formStateString));
this.store.dispatch(
new SaveFormState(ADDRESS_FORM_STATE_KEY, formStateString)
);
});
}
@@ -155,8 +190,15 @@ export class CustomerAddressFormComponent implements OnInit, OnDestroy {
if (key !== 'FirstName' && key !== 'LastName') {
showErrorPopUp = true;
}
if (keysChecked === Object.keys(invalidProperties).length && showErrorPopUp) {
this.errorService.addErrors(409, null, JSON.stringify(invalidProperties));
if (
keysChecked === Object.keys(invalidProperties).length &&
showErrorPopUp
) {
this.errorService.addErrors(
409,
null,
JSON.stringify(invalidProperties)
);
}
});
scrollToFirstInvalidElement();
@@ -216,7 +258,12 @@ export class CustomerAddressFormComponent implements OnInit, OnDestroy {
}
if (this.isBillingForm) {
this.store
.dispatch(new AddNewInvoiceAddress(updatedCustomer.id, updatedCustomer.invoice_address))
.dispatch(
new AddNewInvoiceAddress(
updatedCustomer.id,
updatedCustomer.invoice_address
)
)
.pipe(
takeUntil(this.destroy$),
switchMap(() => {
@@ -228,16 +275,25 @@ export class CustomerAddressFormComponent implements OnInit, OnDestroy {
this.addAddressErrorHandler(invalidProperties);
this.postBtn.stopLoading();
} else {
const queryParams = this.notEditable ? { notEditable: true } : undefined;
const queryParams = this.notEditable
? { notEditable: true }
: undefined;
const currentRoute = `customer/edit/${this.customer.id}/billing`;
this.store.dispatch(new ChangeCurrentRoute(currentRoute, false, queryParams));
this.store.dispatch(
new ChangeCurrentRoute(currentRoute, false, queryParams)
);
this.postBtn.stopLoading();
this.router.navigate([currentRoute], { queryParams: queryParams });
}
});
} else {
this.store
.dispatch(new AddNewShippingAddress(updatedCustomer.id, updatedCustomer.delivery_addres))
.dispatch(
new AddNewShippingAddress(
updatedCustomer.id,
updatedCustomer.delivery_addres
)
)
.pipe(
takeUntil(this.destroy$),
switchMap(() => {
@@ -249,9 +305,13 @@ export class CustomerAddressFormComponent implements OnInit, OnDestroy {
this.addAddressErrorHandler(invalidProperties);
this.postBtn.stopLoading();
} else {
const queryParams = this.notEditable ? { notEditable: true } : undefined;
const queryParams = this.notEditable
? { notEditable: true }
: undefined;
const currentRoute = `customer/edit/${this.customer.id}/delivery`;
this.store.dispatch(new ChangeCurrentRoute(currentRoute, false, queryParams));
this.store.dispatch(
new ChangeCurrentRoute(currentRoute, false, queryParams)
);
this.postBtn.stopLoading();
this.router.navigate([currentRoute], { queryParams: queryParams });
}
@@ -324,7 +384,9 @@ export class CustomerAddressFormComponent implements OnInit, OnDestroy {
}
countryKey(country: string) {
return this.store.selectSnapshot(CountrySelector.getCountriesIterable).find((t) => t.value === country).key;
return this.store
.selectSnapshot(CountrySelector.getCountriesIterable)
.find((t) => t.value === country).key;
}
private updateUserData(): User {
@@ -332,25 +394,29 @@ export class CustomerAddressFormComponent implements OnInit, OnDestroy {
const updatedCustomer: User = { ...this.customer };
if (this.isBillingForm) {
updatedCustomer.poossible_invoice_addresses = updatedCustomer.poossible_invoice_addresses.map((address: Address) => {
if (address.id === +this.addressId) {
return updateAddress;
}
updatedCustomer.poossible_invoice_addresses = updatedCustomer.poossible_invoice_addresses.map(
(address: Address) => {
if (address.id === +this.addressId) {
return updateAddress;
}
return address;
});
return address;
}
);
if (updatedCustomer.invoice_address.id === updateAddress.id) {
updatedCustomer.invoice_address = updateAddress;
}
} else {
updatedCustomer.poossible_delivery_addresses = updatedCustomer.poossible_delivery_addresses.map((address: Address) => {
if (address.id === +this.addressId) {
return updateAddress;
}
updatedCustomer.poossible_delivery_addresses = updatedCustomer.poossible_delivery_addresses.map(
(address: Address) => {
if (address.id === +this.addressId) {
return updateAddress;
}
return address;
});
return address;
}
);
if (updatedCustomer.delivery_addres.id === updateAddress.id) {
updatedCustomer.delivery_addres = updateAddress;
@@ -365,10 +431,16 @@ export class CustomerAddressFormComponent implements OnInit, OnDestroy {
const updatedCustomer: User = { ...this.customer };
if (this.isBillingForm) {
updatedCustomer.poossible_invoice_addresses = [...updatedCustomer.poossible_invoice_addresses, newAddress];
updatedCustomer.poossible_invoice_addresses = [
...(updatedCustomer.poossible_invoice_addresses || []),
newAddress,
];
updatedCustomer.invoice_address = newAddress;
} else {
updatedCustomer.poossible_delivery_addresses = [...updatedCustomer.poossible_delivery_addresses, newAddress];
updatedCustomer.poossible_delivery_addresses = [
...(updatedCustomer.poossible_delivery_addresses || []),
newAddress,
];
updatedCustomer.delivery_addres = newAddress;
}
@@ -417,9 +489,13 @@ export class CustomerAddressFormComponent implements OnInit, OnDestroy {
this.form.get('city').value,
this.countryKey(this.form.get('country').value),
this.form.get('company').value ? this.form.get('company').value : null,
this.form.get('department').value ? this.form.get('department').value : null,
this.form.get('department').value
? this.form.get('department').value
: null,
this.form.get('note').value ? this.form.get('note').value : null,
this.form.get('tax_number').value ? this.form.get('tax_number').value : null,
this.form.get('tax_number').value
? this.form.get('tax_number').value
: null,
this.form.get('title').value ? this.form.get('title').value : null,
this.form.get('gender').value ? this.form.get('gender').value : null
);
@@ -427,7 +503,11 @@ export class CustomerAddressFormComponent implements OnInit, OnDestroy {
return data;
}
private updateDataForSelectedOption(field: string, value: string, defaultValue: string) {
private updateDataForSelectedOption(
field: string,
value: string,
defaultValue: string
) {
if (value !== defaultValue) {
this.form.get(field).patchValue(value);
} else {
@@ -448,33 +528,95 @@ export class CustomerAddressFormComponent implements OnInit, OnDestroy {
.subscribe((value) => {
const savedAddress = value ? JSON.parse(value) : undefined;
this.form = fb.group({
id: [address ? address.id : this.getProperty(savedAddress, 'id') || ''],
firstName: [address ? address.first_name : this.getProperty(savedAddress, 'firstName') || '', Validators.required],
lastName: [address ? address.last_name : this.getProperty(savedAddress, 'lastName') || '', Validators.required],
id: [
address ? address.id : this.getProperty(savedAddress, 'id') || '',
],
firstName: [
address
? address.first_name
: this.getProperty(savedAddress, 'firstName') || '',
Validators.required,
],
lastName: [
address
? address.last_name
: this.getProperty(savedAddress, 'lastName') || '',
Validators.required,
],
address: [
address ? (address.street ? address.street : '') : this.getProperty(savedAddress, 'address') || '',
address
? address.street
? address.street
: ''
: this.getProperty(savedAddress, 'address') || '',
Validators.required,
],
streetNo: [
address ? (address.streetNo ? address.streetNo : '') : this.getProperty(savedAddress, 'streetNo') || '',
address
? address.streetNo
? address.streetNo
: ''
: this.getProperty(savedAddress, 'streetNo') || '',
Validators.required,
],
zipCode: [
address
? address.zip
? address.zip
: ''
: this.getProperty(savedAddress, 'zipCode') || '',
Validators.required,
],
city: [
address
? address.city
? address.city
: ''
: this.getProperty(savedAddress, 'city') || '',
Validators.required,
],
country: [
this.getProperty(savedAddress, 'country') ||
this.getCountryFromAddress(address),
Validators.required,
],
zipCode: [address ? (address.zip ? address.zip : '') : this.getProperty(savedAddress, 'zipCode') || '', Validators.required],
city: [address ? (address.city ? address.city : '') : this.getProperty(savedAddress, 'city') || '', Validators.required],
country: [this.getProperty(savedAddress, 'country') || this.getCountryFromAddress(address), Validators.required],
gender: [
address ? address.gender : this.getProperty(savedAddress, 'gender') || '',
address
? address.gender
: this.getProperty(savedAddress, 'gender') || '',
[Validators.required, CustomValidators.validateGender],
],
company: [address ? (address.company_name ? address.company_name : '') : this.getProperty(savedAddress, 'company') || ''],
company: [
address
? address.company_name
? address.company_name
: ''
: this.getProperty(savedAddress, 'company') || '',
],
department: [
address ? (address.company_department ? address.company_department : '') : this.getProperty(savedAddress, 'department') || '',
address
? address.company_department
? address.company_department
: ''
: this.getProperty(savedAddress, 'department') || '',
],
tax_number: [
address ? (address.company_tax_number ? address.company_tax_number : '') : this.getProperty(savedAddress, 'tax_number') || '',
address
? address.company_tax_number
? address.company_tax_number
: ''
: this.getProperty(savedAddress, 'tax_number') || '',
],
title: [
address
? address.title
: this.getProperty(savedAddress, 'title') || '',
],
note: [
address
? address.note
: this.getProperty(savedAddress, 'note') || '',
],
title: [address ? address.title : this.getProperty(savedAddress, 'title') || ''],
note: [address ? address.note : this.getProperty(savedAddress, 'note') || ''],
});
});
}
@@ -484,7 +626,9 @@ export class CustomerAddressFormComponent implements OnInit, OnDestroy {
return '';
}
const countries = this.store.selectSnapshot(CountrySelector.getCountriesIterable);
const countries = this.store.selectSnapshot(
CountrySelector.getCountriesIterable
);
const country = countries.find((t) => t.key === address.country);
if (isNullOrUndefined(country)) {
return address.country;
@@ -502,11 +646,21 @@ export class CustomerAddressFormComponent implements OnInit, OnDestroy {
const addressesLength = address.length;
address.forEach((add) => {
processedItems++;
const street = add.street ? add.street : (this.form.get('address').value as string);
const streetNo = add.streetNumber ? add.streetNumber : (this.form.get('streetNo').value as string);
const zipCode = add.zipCode ? add.zipCode : (this.form.get('zipCode').value as string);
const city = add.city ? add.city : (this.form.get('city').value as string);
const countryValue = add.country ? add.country : (this.form.get('country').value as string);
const street = add.street
? add.street
: (this.form.get('address').value as string);
const streetNo = add.streetNumber
? add.streetNumber
: (this.form.get('streetNo').value as string);
const zipCode = add.zipCode
? add.zipCode
: (this.form.get('zipCode').value as string);
const city = add.city
? add.city
: (this.form.get('city').value as string);
const countryValue = add.country
? add.country
: (this.form.get('country').value as string);
if (city && street && streetNo && zipCode && countryValue) {
this.addressSuggestions.push({
@@ -520,7 +674,10 @@ export class CustomerAddressFormComponent implements OnInit, OnDestroy {
zip: zipCode,
});
}
if (processedItems === addressesLength && this.addressSuggestions.length === addressesLength) {
if (
processedItems === addressesLength &&
this.addressSuggestions.length === addressesLength
) {
this.cdrf.detectChanges();
this.openSuggestions();
}

View File

@@ -1,4 +1,11 @@
import { Component, OnInit, Input, AfterViewInit, ViewChild, OnDestroy } from '@angular/core';
import {
Component,
OnInit,
Input,
AfterViewInit,
ViewChild,
OnDestroy,
} from '@angular/core';
import { Router } from '@angular/router';
import { Store, Select } from '@ngxs/store';
import { Observable, Subject } from 'rxjs';
@@ -8,34 +15,50 @@ import { SearchInputComponent } from '@libs/ui';
import { Process } from '../../../../core/models/process.model';
import { Breadcrumb } from '../../../../core/models/breadcrumb.model';
import { AddBreadcrumb } from '../../../../core/store/actions/breadcrumb.actions';
import { AddProcess, ChangeCurrentRoute, AddCustomerSearch } from '../../../../core/store/actions/process.actions';
import {
AddProcess,
ChangeCurrentRoute,
AddCustomerSearch,
} from '../../../../core/store/actions/process.actions';
import { SharedSelectors } from '../../../../core/store/selectors/shared.selectors';
import { CustomerSearchResult } from '../../../../core/models/customer-search-result.model';
import { AppState } from 'apps/sales/src/app/core/store/state/app.state';
import { CustomerService } from 'apps/sales/src/app/core/services/customer.service';
import { CustomerSearchResponse } from 'apps/sales/src/app/core/models/customer-search-response.model';
import { CUSTOMER_SCROLL_INDEX } from 'apps/sales/src/app/core/utils/app.constants';
import { ClearCachedCustomers, SetCachedCustomers } from 'apps/sales/src/app/core/store/actions/customer.actions';
import {
ClearCachedCustomers,
SetCachedCustomers,
} from 'apps/sales/src/app/core/store/actions/customer.actions';
import { CustomerFeatures } from 'apps/sales/src/app/core/models/customer-features.model';
import { CustomerSearchEmptyModalComponent } from '../customer-search-empty-modal/customer-search-empty-modal.component';
@Component({
selector: 'app-search-customer-card',
templateUrl: './customer-search-card.component.html',
styleUrls: ['./customer-search-card.component.scss']
styleUrls: ['./customer-search-card.component.scss'],
})
export class CustomerSearchCardComponent implements OnInit, AfterViewInit, OnDestroy {
@Select(SharedSelectors.getSearchedCustomers) customers$: Observable<CustomerSearchResult>;
export class CustomerSearchCardComponent
implements OnInit, AfterViewInit, OnDestroy {
@Select(SharedSelectors.getSearchedCustomers) customers$: Observable<
CustomerSearchResult
>;
destroy$ = new Subject();
processes: Process[];
searchError = '';
@Input() searchParams = '';
@ViewChild('searchInput', { static: false }) searchInput: SearchInputComponent;
@ViewChild('searchEmptyModal', { static: false }) searchEmptyModal: CustomerSearchEmptyModalComponent;
@ViewChild('searchInput', { static: false })
searchInput: SearchInputComponent;
@ViewChild('searchEmptyModal', { static: false })
searchEmptyModal: CustomerSearchEmptyModalComponent;
constructor(private store: Store, private router: Router, private customerService: CustomerService) { }
constructor(
private store: Store,
private router: Router,
private customerService: CustomerService
) {}
ngOnInit() {
this.store.dispatch(new ClearCachedCustomers());
@@ -62,8 +85,8 @@ export class CustomerSearchCardComponent implements OnInit, AfterViewInit, OnDes
.pipe(take(1), takeUntil(this.destroy$))
.subscribe((r: CustomerSearchResponse) => {
if (r.customers.length > 0) {
const filteredCustomer = r.customers.filter(data => {
if (!data.features) {
const filteredCustomer = r.customers.filter((data) => {
if (isNullOrUndefined(data) || !data.features) {
return true;
}
const customerFeatures = new CustomerFeatures(data.features);
@@ -72,22 +95,28 @@ export class CustomerSearchCardComponent implements OnInit, AfterViewInit, OnDes
}
return true;
});
const response = { ...r, customers: filteredCustomer, hits: filteredCustomer ? filteredCustomer.length : 0 };
const response = {
...r,
customers: filteredCustomer,
hits: filteredCustomer ? filteredCustomer.length : 0,
};
this.store.dispatch(
new AddBreadcrumb(
{
name:
(searchParams.length > 12 ? searchParams.substring(0, 12) + '...' : searchParams) +
(searchParams.length > 12
? searchParams.substring(0, 12) + '...'
: searchParams) +
` (${
!isNullOrUndefined(response)
? !isNullOrUndefined(response.hits)
? response.hits
: response.customers
!isNullOrUndefined(response)
? !isNullOrUndefined(response.hits)
? response.hits
: response.customers
? response.customers.length
: 0
: 0
: 0
} Ergebnisse)`,
path: '/customer/results'
path: '/customer/results',
},
'customer'
)
@@ -97,7 +126,7 @@ export class CustomerSearchCardComponent implements OnInit, AfterViewInit, OnDes
query: searchParams,
skip: 0,
take: 5,
firstLoad: true
firstLoad: true,
})
);
sessionStorage.removeItem(CUSTOMER_SCROLL_INDEX);
@@ -119,7 +148,7 @@ export class CustomerSearchCardComponent implements OnInit, AfterViewInit, OnDes
const newProcess = <Process>{
id: 1,
name: 'Vorgang 1',
currentRoute: '/product/search'
currentRoute: '/product/search',
};
this.store.dispatch(new AddProcess(newProcess));
@@ -127,7 +156,7 @@ export class CustomerSearchCardComponent implements OnInit, AfterViewInit, OnDes
new AddBreadcrumb(
<Breadcrumb>{
name: 'Artikelsuche',
path: '/product/search'
path: '/product/search',
},
'customer'
)

View File

@@ -3,12 +3,14 @@ import { User } from '../../../../core/models/user.model';
import { Observable, BehaviorSubject, Subject } from 'rxjs';
import { takeUntil, debounceTime, take } from 'rxjs/operators';
import { Store } from '@ngxs/store';
import { CurrentCustomerPageLoaded, AddCustomers } from '../../../../core/store/actions/customer.actions';
import {
CurrentCustomerPageLoaded,
AddCustomers,
} from '../../../../core/store/actions/customer.actions';
import { CustomerService } from '../../../../core/services/customer.service';
import { CustomerSearchResponse } from '../../../../core/models/customer-search-response.model';
import { CustomerFilters } from './customer-search-result.component';
import { AddBreadcrumb, AddBreadcrumbNoDub } from '../../../../core/store/actions/breadcrumb.actions';
import { isArrayMinLength } from 'apps/sales/src/app/core/utils/app.utils';
import { AddBreadcrumbNoDub } from '../../../../core/store/actions/breadcrumb.actions';
import { isNullOrUndefined } from 'util';
import { CustomerSelectors } from 'apps/sales/src/app/core/store/selectors/customer.selectors';
@@ -16,7 +18,9 @@ export class CustomerSearchDataSource extends DataSource<User | undefined> {
private pageSize = 10;
public cachedData = Array.from<User>({ length: 0 });
private fetchedPages = new Set<number>();
private dataStream = new BehaviorSubject<(User | undefined)[]>(this.cachedData);
private dataStream = new BehaviorSubject<(User | undefined)[]>(
this.cachedData
);
destroy$ = new Subject();
public loading = true;
public results = false;
@@ -35,21 +39,22 @@ export class CustomerSearchDataSource extends DataSource<User | undefined> {
super();
}
connect(collectionViewer: CollectionViewer): Observable<(User | undefined)[]> {
collectionViewer.viewChange.pipe(takeUntil(this.destroy$)).subscribe(range => {
const startPage = this.getPageForIndex(range.start);
const endPage = this.getPageForIndex(range.end - 1);
for (let i = startPage; i <= endPage; i++) {
this.fetchPage(i);
}
});
connect(
collectionViewer: CollectionViewer
): Observable<(User | undefined)[]> {
collectionViewer.viewChange
.pipe(takeUntil(this.destroy$))
.subscribe((range) => {
const startPage = this.getPageForIndex(range.start);
const endPage = this.getPageForIndex(range.end - 1);
for (let i = startPage; i <= endPage; i++) {
this.fetchPage(i);
}
});
this.dataStream
.pipe(
takeUntil(this.destroy$),
debounceTime(1000)
)
.subscribe(i => {
.pipe(takeUntil(this.destroy$), debounceTime(1000))
.subscribe((i) => {
this.store.dispatch(new AddCustomers([...i]));
});
@@ -79,7 +84,14 @@ export class CustomerSearchDataSource extends DataSource<User | undefined> {
const customerSource$ = !this.scan
? page === 0 && this.first
? this.store.select(CustomerSelectors.getCachedCustomers)
: this.customerService.searchCustomer(this.search, false, page * this.pageSize, this.pageSize, false, this.customerFilters)
: this.customerService.searchCustomer(
this.search,
false,
page * this.pageSize,
this.pageSize,
false,
this.customerFilters
)
: this.customerService.scannCustomer(this.search);
customerSource$.pipe(take(1)).subscribe((data: CustomerSearchResponse) => {
if (!data) {
@@ -92,8 +104,14 @@ export class CustomerSearchDataSource extends DataSource<User | undefined> {
new AddBreadcrumbNoDub(
{
name:
(this.search.length > 12 ? this.search.substring(0, 12) + '...' : this.search) +
` (${!isNullOrUndefined(data.hits) ? data.hits : data.customers.length} Ergebnisse)`,
(this.search.length > 12
? this.search.substring(0, 12) + '...'
: this.search) +
` (${
!isNullOrUndefined(data.hits)
? data.hits
: data.customers.length
} Ergebnisse)`,
path: '/customer/results',
},
'customer'
@@ -106,7 +124,11 @@ export class CustomerSearchDataSource extends DataSource<User | undefined> {
this.allHits = data.hits;
}
this.cachedData.splice(page * this.pageSize, this.pageSize, ...data.customers);
this.cachedData.splice(
page * this.pageSize,
this.pageSize,
...data.customers
);
this.dataStream.next(this.cachedData);
if (page === 0) {

View File

@@ -9,17 +9,29 @@
</div>
<div class="filters" *ngIf="ds">
<app-checkbox
[option]="{ value: 'Gastkunde', disabled: false, selected: filters.guestaccount !== undefined }"
[option]="{
value: 'Gastkunde',
disabled: false,
selected: filters.guestaccount !== undefined
}"
[negative]="selectedFilterMode === 1"
(valueChanges)="updateFilter($event, 'guestaccount')"
></app-checkbox>
<app-checkbox
[option]="{ value: 'Kundenkarte', disabled: false, selected: filters.bonuscard !== undefined }"
[option]="{
value: 'Kundenkarte',
disabled: false,
selected: filters.bonuscard !== undefined
}"
[negative]="selectedFilterMode === 1"
(valueChanges)="updateFilter($event, 'bonuscard')"
></app-checkbox>
<app-checkbox
[option]="{ value: 'Onlinekonto', disabled: false, selected: filters.onlineshop !== undefined }"
[option]="{
value: 'Onlinekonto',
disabled: false,
selected: filters.onlineshop !== undefined
}"
[negative]="selectedFilterMode === 1"
(valueChanges)="updateFilter($event, 'onlineshop')"
></app-checkbox>
@@ -36,23 +48,39 @@
<span>
Kunde nicht gefunden?
</span>
<app-button (action)="redirectToCustomerCreate()">Neue Kundendaten erfassen</app-button>
<app-button (action)="redirectToCustomerCreate()"
>Neue Kundendaten erfassen</app-button
>
</div>
</div>
<cdk-virtual-scroll-viewport itemSize="144" #viewport
[perfectScrollbar]="{minScrollbarLength: 20}">
<div *cdkVirtualFor="let customer of ds; let i = index; let last = last" class="virtual-item">
<cdk-virtual-scroll-viewport
itemSize="144"
#viewport
[perfectScrollbar]="{ minScrollbarLength: 20 }"
>
<div
*cdkVirtualFor="let customer of ds; let i = index; let last = last"
class="virtual-item"
>
<div class="user">
<div class="user-info-container" *ngIf="customer != null; else loadingComponent" (click)="details(customer, i)">
<div
class="user-info-container"
*ngIf="customer != null; else loadingComponent"
(click)="details(customer, i)"
>
<div class="info">
<div class="user-info">
<div class="name-created-date">
<h1 class="user-title">{{ customer.first_name }} {{ customer.last_name }}</h1>
<h1 class="user-title">
{{ customer.first_name }} {{ customer.last_name }}
</h1>
<span>{{ customer.created | date: 'dd.MM.yy' }}</span>
</div>
<div class="user-location">
<span class="user-label">PLZ und Wohnort</span>
<span class="user-data">{{ getCustomerDeliveryAddress(customer) }}</span>
<span class="user-data">{{
getCustomerDeliveryAddress(customer)
}}</span>
</div>
<div class="user-email">
<span class="user-label">E-Mail</span>
@@ -61,13 +89,25 @@
</div>
<div
class="user-actions"
[ngClass]="{ 'additional-visible': customer.customer_card || customer.shop || customer.newsletter || customer.tolino }"
[ngClass]="{
'additional-visible':
customer.customer_card ||
customer.shop ||
customer.newsletter ||
customer.tolino
}"
></div>
</div>
<div class="additional">
<ng-container>
<div class="data" *ngFor="let features of customer.features">
<lib-icon name="Check_2" alt="check" height="11px" width="15px" pr="5px"></lib-icon>
<lib-icon
name="Check_2"
alt="check"
height="11px"
width="15px"
pr="5px"
></lib-icon>
<span>{{ features.description }}</span>
</div>
</ng-container>
@@ -93,13 +133,16 @@
</div>
<div class="note" *ngIf="last">
<span class="note-text">
Hinweis: Aus Datenschutzgründen werden nur Teilinformationen dargestellt. Tab auf einen Kunden um mehr zu erfahren.
Hinweis: Aus Datenschutzgründen werden nur Teilinformationen
dargestellt. Tab auf einen Kunden um mehr zu erfahren.
</span>
<div class="new-customer-container">
<span>
Kunde nicht gefunden?
</span>
<app-button (action)="redirectToCustomerCreate()">Neue Kundendaten erfassen</app-button>
<app-button (action)="redirectToCustomerCreate()"
>Neue Kundendaten erfassen</app-button
>
</div>
</div>
</div>

View File

@@ -275,10 +275,10 @@ export class CustomerSearchResultComponent implements OnInit {
if (!user) {
return '';
}
if (!user.delivery_addres) {
if (!user.base_addres) {
return '';
}
const address = user.delivery_addres;
const address = user.base_addres;
const plz = address
? isNullOrUndefined(address.zip)
? ''

View File

@@ -1,9 +1,11 @@
import { combineReducers, Action } from '@ngrx/store';
import { CustomerState } from './customer.state';
import { shelfReducer } from './shelf';
import { customersReducer } from './customers';
const _customerReducer = combineReducers<CustomerState>({
shelf: shelfReducer,
customers: customersReducer,
});
export function customerReducer(state: CustomerState, action: Action) {

View File

@@ -1,5 +1,7 @@
import { ShelfState } from './shelf';
import { CustomersState } from './customers';
export interface CustomerState {
shelf: ShelfState;
customers: CustomersState;
}

View File

@@ -0,0 +1,91 @@
import { createAction, props } from '@ngrx/store';
import {
StrictHttpResponse,
ListResponseArgsOfCustomerInfoDTO,
ResponseArgsOfCustomerDTO,
ListResponseArgsOfShippingAddressDTO,
ListResponseArgsOfAssignedPayerDTO,
} from '@swagger/crm';
import { Customer } from './defs';
const prefix = `[Customer] [Customers]`;
export const fetchCustomer = createAction(
`${prefix} Fetch Customer`,
props<{ id: number }>()
);
export const fetchCustomerDone = createAction(
`${prefix} Fetch Customer Done`,
props<{
id: number;
response: StrictHttpResponse<ResponseArgsOfCustomerDTO>;
}>()
);
export const fetchCustomers = createAction(
`${prefix} Fetch Customers`,
props<{ query: any }>()
);
export const fetchCustomersDone = createAction(
`${prefix} Fetch Customers Done`,
props<{
id: number;
response: StrictHttpResponse<ListResponseArgsOfCustomerInfoDTO>;
}>()
);
export const addCustomer = createAction(
`${prefix} Add Customer`,
props<{
id: number;
customer: Customer;
}>()
);
export const addCustomers = createAction(
`${prefix} Add Customers`,
props<{
ids: number[];
customers: Customer[];
}>()
);
export const updateCustomer = createAction(
`${prefix} Add Customers`,
props<{
id: number;
customers: Partial<Customer>;
}>()
);
export const fetchPayerAddresses = createAction(
`${prefix} Fetch Payer Address`,
props<{
id: number;
}>()
);
export const fetchPayerAddressesDone = createAction(
`${prefix} Fetch Payer Address Done`,
props<{
id: number;
response: StrictHttpResponse<ListResponseArgsOfAssignedPayerDTO>;
}>()
);
export const fetchShippingyAddresses = createAction(
`${prefix} Fetch Shipping Address`,
props<{
id: number;
}>()
);
export const fetchShippingAddressesDone = createAction(
`${prefix} Fetch Shipping Address Done`,
props<{
id: number;
response: StrictHttpResponse<ListResponseArgsOfShippingAddressDTO>;
}>()
);

View File

@@ -0,0 +1,73 @@
import { Injectable } from '@angular/core';
import { CustomerService } from '@swagger/crm';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { flatMap, map } from 'rxjs/operators';
import * as actions from './customers.actions';
import { customerDtoToCustomer } from './mappers';
import { NEVER } from 'rxjs';
import { Store } from '@ngrx/store';
@Injectable({ providedIn: 'root' })
export class CustomersEffects {
constructor(
private actions$: Actions,
private crmService: CustomerService,
private store: Store<any>
) {}
fetchCustomer$ = createEffect(() =>
this.actions$.pipe(
ofType(actions.fetchCustomer),
flatMap((action) =>
this.crmService
.CustomerGetCustomerResponse({ customerId: action.id })
.pipe(
map((response) =>
actions.fetchCustomerDone({ id: action.id, response })
)
)
)
)
);
fetchCustomerDone$ = createEffect(() =>
this.actions$.pipe(
ofType(actions.fetchCustomerDone),
flatMap((action) => {
if (action.response.ok) {
const result = action.response.body;
if (!result || !result.result) {
return NEVER;
}
const customer = customerDtoToCustomer(result.result);
return [actions.addCustomer({ id: action.id, customer })];
}
return NEVER;
})
)
);
fetchPayerAddress$ = createEffect(() =>
this.actions$.pipe(
ofType(actions.fetchPayerAddresses),
flatMap((action) =>
this.crmService
.CustomerGetAssignedPayersByCustomerIdResponse(action.id)
.pipe(
map((response) =>
actions.fetchPayerAddressesDone({ id: action.id, response })
)
)
)
)
);
fetchPayerAddressDone$ = createEffect(() =>
this.actions$.pipe(ofType(actions.fetchPayerAddressesDone))
);
fetchShippingAddress$ = createEffect(() => this.actions$.pipe());
fetchShippingAddressDone$ = createEffect(() => this.actions$.pipe());
}

View File

@@ -0,0 +1,47 @@
import { TestBed } from '@angular/core/testing';
import { Store } from '@ngrx/store';
import { CustomersState } from './customers.state';
import { CustomersStateFacade } from './customers.facade';
import { of } from 'rxjs';
import * as CustomersSelectors from './customers.selectors';
fdescribe('#CustomersStateFacade', () => {
let facade: CustomersStateFacade;
let store: jasmine.SpyObj<Store<CustomersState>>;
const id = 123;
beforeEach(async () => {
TestBed.configureTestingModule({
providers: [
CustomersStateFacade,
{
provide: Store,
useValue: jasmine.createSpyObj<Store<CustomersState>>('store', {
select: of({}),
}),
},
],
});
});
beforeEach(() => {
facade = TestBed.get(CustomersStateFacade);
store = TestBed.get(Store);
});
it('should be created', () => {
expect(facade instanceof CustomersStateFacade).toBeTruthy();
});
describe('#getGeneralAddress$', () => {
it('should select the general address from store', () => {
facade.getGeneralAddress$(id);
expect(store.select).toHaveBeenCalledWith(
CustomersSelectors.selectGeneralAddress,
id
);
});
});
});

View File

@@ -0,0 +1,57 @@
import { Injectable } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { CustomersState } from './customers.state';
import {
QueryTokenDTO,
CustomerInfoDTO,
AddressDTO,
ShippingAddressDTO,
AssignedPayerDTO,
} from '@swagger/crm';
import * as CustomersSelectors from './customers.selectors';
@Injectable({ providedIn: 'root' })
export class CustomersStateFacade {
constructor(private store: Store<any>) {}
public getGeneralAddress$(customerId: number): Observable<AddressDTO> {
return this.store.select(
CustomersSelectors.selectGeneralAddress,
customerId
);
}
public getPayerAddresses$(
customerId: number
): Observable<ShippingAddressDTO[]> {
return;
}
public getShippingAddresses$(
customerId: number
): Observable<AssignedPayerDTO[]> {
return;
}
public setBaseCustomer(customer: CustomerInfoDTO) {
// import mapper
// dispatch action to set customer
}
public setInvoiceAddresses(customerId: number, address: AddressDTO[]) {}
public setDeliveryAddresses(customerId: number, address: AddressDTO[]) {}
private fetchCustomer(id?: number) {
// fetch single customer
}
private fetchCustomers() {
// fetch multiple customers
}
private getQueryToken(): QueryTokenDTO {
return;
}
}

View File

@@ -0,0 +1,16 @@
import {
INITIAL_CUSTOMERS_STATE,
customersStateAdapter,
CustomersState,
} from './customers.state';
import * as actions from './customers.actions';
import { createReducer, on, Action } from '@ngrx/store';
export const _customersReducer = createReducer(
INITIAL_CUSTOMERS_STATE,
on(actions.addCustomer, (s, a) => customersStateAdapter.addOne(a.customer, s))
);
export function customersReducer(state: CustomersState, action: Action) {
return _customersReducer(state, action);
}

View File

@@ -0,0 +1,22 @@
import { CustomersState } from './customers.state';
import { customersStateMock } from './mocks';
import * as CustomersSelectors from './customers.selectors';
import { Dictionary } from '@cmf/core';
import { Customer } from './defs';
fdescribe('#CustomersSelectors', () => {
let entities: Dictionary<Customer>;
describe('selectGeneralAddress', () => {
beforeEach(() => {
entities = customersStateMock.entities;
});
it('should select the general address for the provided customerId', () => {
const id = 123;
expect(
CustomersSelectors.selectGeneralAddress.projector(entities, 123)
).toEqual(entities[id].addresses.generalAddress);
});
});
});

View File

@@ -0,0 +1,70 @@
import { createSelector } from '@ngrx/store';
import { Dictionary } from '@cmf/core';
import { customersStateAdapter } from './customers.state';
import { selectCustomerState } from '../customer.selector';
import { Customer } from './defs';
export const selectCustomersState = createSelector(
selectCustomerState,
(s) => s.customers
);
export const { selectAll, selectEntities } = customersStateAdapter.getSelectors(
selectCustomersState
);
export const selectCustomers = createSelector(
selectEntities,
(entities: Dictionary<Customer>) => entities
);
export const selectCustomer = createSelector(
selectEntities,
(entities: Dictionary<Customer>, id: number) => entities[id]
);
export const selectAddresses = createSelector(
selectEntities,
(entities: Dictionary<Customer>, id: number) =>
entities[id] && entities[id].addresses
);
export const selectGeneralAddress = createSelector(
selectEntities,
(entities: Dictionary<Customer>, id: number) =>
entities[id] &&
entities[id].addresses &&
entities[id].addresses.generalAddress
);
export const selectShippingAddresses = createSelector(
selectEntities,
(entities: Dictionary<Customer>, id: number) =>
entities[id] && entities[id].addresses.shippingAddresses
);
export const selectDefaultShippingAddress = createSelector(
selectEntities,
(entities: Dictionary<Customer>, id: number) =>
entities[id] &&
entities[id].addresses.shippingAddresses &&
entities[id].addresses.shippingAddresses.find(
(address) => address.isDefault
)
);
export const selectPayerAddresses = createSelector(
selectEntities,
(entities: Dictionary<Customer>, id: number) =>
entities[id] &&
entities[id].addresses &&
entities[id].addresses.payerAddresses
);
export const selectDefaultPayerAddresses = createSelector(
selectEntities,
(entities: Dictionary<Customer>, id: number) =>
entities[id] &&
entities[id].addresses &&
entities[id].addresses.payerAddresses.find((address) => address.isDefault)
);

View File

@@ -0,0 +1,26 @@
import { Customer } from './defs';
import { EntityState, createEntityAdapter } from '@ngrx/entity';
export interface CustomersState extends EntityState<Customer> {}
export const customersStateAdapter = createEntityAdapter<Customer>();
export const INITIAL_CUSTOMERS_STATE: CustomersState = {
...customersStateAdapter.getInitialState(),
};
export const INITIAL_CUSTOMER: Customer = {
id: undefined,
baseData: {},
addresses: {
generalAddress: {},
shippingAddresses: [],
payerAddresses: [],
shippingAddressIds: [],
payerAddressIds: [],
},
detailsLoaded: false,
};

View File

@@ -0,0 +1,10 @@
import { AddressDTO, ShippingAddressDTO, AssignedPayerDTO } from '@swagger/crm';
export interface CustomerAddresses {
generalAddress: AddressDTO;
shippingAddresses: ShippingAddressDTO[];
payerAddresses: AssignedPayerDTO[];
shippingAddressIds: number[];
payerAddressIds: number[];
}

View File

@@ -0,0 +1,29 @@
import {
EntityDTOContainerOfBranchDTO,
CustomerType,
CustomerStatus,
Gender,
NotificationChannel,
CommunicationDetailsDTO,
} from '@swagger/crm';
export interface CustomerBaseData {
/** Basisdaten */
gender?: Gender;
title?: string;
firstName?: string;
lastName?: string;
dateOfBirth?: string;
/** Kundentyp */
customerGroup?: string;
createdInBranch?: EntityDTOContainerOfBranchDTO;
customerNumber?: string;
customerType?: CustomerType;
customerStatus?: CustomerStatus;
isGuestAccount?: boolean;
hasOnlineAccount?: boolean;
notificationChannels?: NotificationChannel;
communicationDetails?: CommunicationDetailsDTO;
}

View File

@@ -0,0 +1,15 @@
import { CustomerBaseData } from './customer-base-data';
import { CustomerAddresses } from './customer-address';
export interface Customer {
id: number;
/** Stammdaten */
baseData: CustomerBaseData;
/** Addresdaten */
addresses: CustomerAddresses;
/** Wurden die Kundendetails geladen? */
detailsLoaded?: boolean;
}

View File

@@ -0,0 +1,6 @@
// start:ng42.barrel
export * from './customer-address';
export * from './customer-base-data';
export * from './customer.model';
// end:ng42.barrel

View File

@@ -0,0 +1,9 @@
// start:ng42.barrel
export * from './customers.actions';
export * from './customers.effects';
export * from './customers.facade';
export * from './customers.reducer';
export * from './customers.selectors';
export * from './customers.state';
// end:ng42.barrel

View File

@@ -0,0 +1,19 @@
import { CustomerDTO } from '@swagger/crm';
import { CustomerAddresses } from '../defs';
export function customerDtoToCustomerAddresses(
customerDto: CustomerDTO
): CustomerAddresses {
return {
generalAddress: customerDto.address,
shippingAddresses: [],
payerAddresses: [],
shippingAddressIds: customerDto.shippingAddresses.map(
(addressData) => addressData.id
),
payerAddressIds: customerDto.payers
.filter((addressData) => addressData.payer)
.map((addressData) => addressData.payer.id),
};
}

View File

@@ -0,0 +1,39 @@
import { CustomerDTO } from '@swagger/crm';
import { CustomerBaseData } from '../defs';
export function customerDtoToCustomerBaseData(
customerDto: CustomerDTO
): CustomerBaseData {
const {
gender,
title,
firstName,
lastName,
dateOfBirth,
customerGroup,
createdInBranch,
customerNumber,
customerType,
customerStatus,
isGuestAccount,
notificationChannels,
hasOnlineAccount,
communicationDetails,
} = customerDto;
return {
gender,
title,
firstName,
lastName,
dateOfBirth,
customerGroup,
createdInBranch,
customerNumber,
customerType,
customerStatus,
isGuestAccount,
notificationChannels,
hasOnlineAccount,
communicationDetails,
};
}

View File

@@ -0,0 +1,12 @@
import { CustomerDTO } from '@swagger/crm/lib';
import { Customer } from '../defs';
import { customerDtoToCustomerBaseData } from './customer-dto-to-customer-base-data.mapper';
import { customerDtoToCustomerAddresses } from './customer-dto-to-customer-addresses.mapper';
export function customerDtoToCustomer(customerDto: CustomerDTO): Customer {
return {
id: customerDto.id,
baseData: customerDtoToCustomerBaseData(customerDto),
addresses: customerDtoToCustomerAddresses(customerDto),
};
}

View File

@@ -0,0 +1,5 @@
// start:ng42.barrel
export * from './customer-dto-to-customer-base-data.mapper';
export * from './customer-dto-to-customer-addresses.mapper';
export * from './customer-dto-to-customer.mapper';
// end:ng42.barrel

View File

@@ -0,0 +1,46 @@
import { CustomersState } from '../customers.state';
export const customersStateMock: CustomersState = {
ids: [123, 456, 789],
entities: {
123: {
id: 123,
baseData: {},
addresses: {
generalAddress: {},
shippingAddresses: [],
payerAddresses: [],
shippingAddressIds: [],
payerAddressIds: [],
},
detailsLoaded: false,
},
456: {
id: 456,
baseData: {},
addresses: {
generalAddress: {},
shippingAddresses: [],
payerAddresses: [],
shippingAddressIds: [],
payerAddressIds: [],
},
detailsLoaded: false,
},
789: {
id: 789,
baseData: {},
addresses: {
generalAddress: {},
shippingAddresses: [],
payerAddresses: [],
shippingAddressIds: [],
payerAddressIds: [],
},
detailsLoaded: false,
},
},
};

View File

@@ -0,0 +1,4 @@
// start:ng42.barrel
export * from './customers-state.mock';
// end:ng42.barrel

View File

@@ -20,7 +20,6 @@ import {
ListResponseArgsOfOrderItemListItemDTO,
ResponseArgsOfIEnumerableOfInputDTO,
} from '@swagger/oms';
import { BranchService } from '@sales/core-services';
import { SearchStateFacade } from './search.facade';
import { of, NEVER } from 'rxjs';
import {

0
prod
View File