hotfix(customer-card-deactivate): Hotfix due to Keycard ISA Login Error

This commit is contained in:
Nino
2025-10-24 11:18:25 +02:00
parent 1b6b726036
commit 353864e2f0
25 changed files with 1060 additions and 786 deletions

View File

@@ -1,4 +1,4 @@
<ng-container *ifRole="'Store'"> <!-- <ng-container *ifRole="'Store'">
@if (customerType !== 'b2b') { @if (customerType !== 'b2b') {
<shared-checkbox <shared-checkbox
[ngModel]="p4mUser" [ngModel]="p4mUser"
@@ -8,15 +8,17 @@
Kundenkarte Kundenkarte
</shared-checkbox> </shared-checkbox>
} }
</ng-container> </ng-container> -->
@for (option of filteredOptions$ | async; track option) { @for (option of filteredOptions$ | async; track option) {
@if (option?.enabled !== false) { @if (option?.enabled !== false) {
<shared-checkbox <shared-checkbox
[ngModel]="option.value === customerType" [ngModel]="option.value === customerType"
(ngModelChange)="setValue({ customerType: $event ? option.value : undefined })" (ngModelChange)="
setValue({ customerType: $event ? option.value : undefined })
"
[disabled]="isOptionDisabled(option)" [disabled]="isOptionDisabled(option)"
[name]="option.value" [name]="option.value"
> >
{{ option.label }} {{ option.label }}
</shared-checkbox> </shared-checkbox>
} }

View File

@@ -21,7 +21,13 @@ import { OptionDTO } from '@generated/swagger/checkout-api';
import { UiCheckboxComponent } from '@ui/checkbox'; import { UiCheckboxComponent } from '@ui/checkbox';
import { first, isBoolean, isString } from 'lodash'; import { first, isBoolean, isString } from 'lodash';
import { combineLatest, Observable, Subject } from 'rxjs'; import { combineLatest, Observable, Subject } from 'rxjs';
import { distinctUntilChanged, filter, map, shareReplay, switchMap } from 'rxjs/operators'; import {
distinctUntilChanged,
filter,
map,
shareReplay,
switchMap,
} from 'rxjs/operators';
export interface CustomerTypeSelectorState { export interface CustomerTypeSelectorState {
processId: number; processId: number;
@@ -58,18 +64,18 @@ export class CustomerTypeSelectorComponent
@Input() @Input()
get value() { get value() {
if (this.p4mUser) { // if (this.p4mUser) {
return `${this.customerType}-p4m`; // return `${this.customerType}-p4m`;
} // }
return this.customerType; return this.customerType;
} }
set value(value: string) { set value(value: string) {
if (value.includes('-p4m')) { // if (value.includes('-p4m')) {
this.p4mUser = true; // this.p4mUser = true;
this.customerType = value.replace('-p4m', ''); // this.customerType = value.replace('-p4m', '');
} else { // } else {
this.customerType = value; this.customerType = value;
} // }
} }
@Output() @Output()
@@ -111,30 +117,35 @@ export class CustomerTypeSelectorComponent
get filteredOptions$() { get filteredOptions$() {
const options$ = this.select((s) => s.options).pipe(distinctUntilChanged()); const options$ = this.select((s) => s.options).pipe(distinctUntilChanged());
const p4mUser$ = this.select((s) => s.p4mUser).pipe(distinctUntilChanged()); const p4mUser$ = this.select((s) => s.p4mUser).pipe(distinctUntilChanged());
const customerType$ = this.select((s) => s.customerType).pipe(distinctUntilChanged()); const customerType$ = this.select((s) => s.customerType).pipe(
distinctUntilChanged(),
);
return combineLatest([options$, p4mUser$, customerType$]).pipe( return combineLatest([options$, p4mUser$, customerType$]).pipe(
filter(([options]) => options?.length > 0), filter(([options]) => options?.length > 0),
map(([options, p4mUser, customerType]) => { map(([options, p4mUser, customerType]) => {
const initial = { p4mUser: this.p4mUser, customerType: this.customerType }; const initial = {
p4mUser: this.p4mUser,
customerType: this.customerType,
};
let result: OptionDTO[] = options; let result: OptionDTO[] = options;
if (p4mUser) { // if (p4mUser) {
result = result.filter((o) => o.value === 'store' || (o.value === 'webshop' && o.enabled !== false)); // result = result.filter((o) => o.value === 'store' || (o.value === 'webshop' && o.enabled !== false));
result = result.map((o) => { // result = result.map((o) => {
if (o.value === 'store') { // if (o.value === 'store') {
return { ...o, enabled: false }; // return { ...o, enabled: false };
} // }
return o; // return o;
}); // });
} // }
if (customerType === 'b2b' && this.p4mUser) { if (customerType === 'b2b' && this.p4mUser) {
this.p4mUser = false; this.p4mUser = false;
} }
if (initial.p4mUser !== this.p4mUser || initial.customerType !== this.customerType) { // if (initial.p4mUser !== this.p4mUser || initial.customerType !== this.customerType) {
this.setValue({ customerType: this.customerType, p4mUser: this.p4mUser }); // this.setValue({ customerType: this.customerType, p4mUser: this.p4mUser });
} // }
return result; return result;
}), }),
@@ -224,42 +235,53 @@ export class CustomerTypeSelectorComponent
if (typeof value === 'string') { if (typeof value === 'string') {
this.value = value; this.value = value;
} else { } else {
if (isBoolean(value.p4mUser)) { // if (isBoolean(value.p4mUser)) {
this.p4mUser = value.p4mUser; // this.p4mUser = value.p4mUser;
} // }
if (isString(value.customerType)) { if (isString(value.customerType)) {
this.customerType = value.customerType; this.customerType = value.customerType;
} else if (this.p4mUser) { // } else if (this.p4mUser) {
// Implementierung wie im PBI #3467 beschrieben // // Implementierung wie im PBI #3467 beschrieben
// wenn customerType nicht gesetzt wird und p4mUser true ist, // // wenn customerType nicht gesetzt wird und p4mUser true ist,
// dann customerType auf store setzen. // // dann customerType auf store setzen.
// wenn dies nicht möglich ist da der Warenkob keinen store Kunden zulässt, // // wenn dies nicht möglich ist da der Warenkob keinen store Kunden zulässt,
// dann customerType auf webshop setzen. // // dann customerType auf webshop setzen.
// wenn dies nicht möglich ist da der Warenkob keinen webshop Kunden zulässt, // // wenn dies nicht möglich ist da der Warenkob keinen webshop Kunden zulässt,
// dann customerType auf den ersten verfügbaren setzen und p4mUser auf false setzen. // // dann customerType auf den ersten verfügbaren setzen und p4mUser auf false setzen.
if (this.enabledOptions.some((o) => o.value === 'store')) { // if (this.enabledOptions.some((o) => o.value === 'store')) {
this.customerType = 'store'; // this.customerType = 'store';
} else if (this.enabledOptions.some((o) => o.value === 'webshop')) { // } else if (this.enabledOptions.some((o) => o.value === 'webshop')) {
this.customerType = 'webshop'; // this.customerType = 'webshop';
} else { // } else {
this.p4mUser = false; // this.p4mUser = false;
const includesGuest = this.enabledOptions.some((o) => o.value === 'guest'); // const includesGuest = this.enabledOptions.some(
this.customerType = includesGuest ? 'guest' : first(this.enabledOptions)?.value; // (o) => o.value === 'guest',
} // );
// this.customerType = includesGuest
// ? 'guest'
// : first(this.enabledOptions)?.value;
// }
} else { } else {
// wenn customerType nicht gesetzt wird und p4mUser false ist, // wenn customerType nicht gesetzt wird und p4mUser false ist,
// dann customerType auf den ersten verfügbaren setzen der nicht mit dem aktuellen customerType übereinstimmt. // dann customerType auf den ersten verfügbaren setzen der nicht mit dem aktuellen customerType übereinstimmt.
this.customerType = this.customerType =
first(this.enabledOptions.filter((o) => o.value === this.customerType))?.value ?? this.customerType; first(
this.enabledOptions.filter((o) => o.value === this.customerType),
)?.value ?? this.customerType;
} }
} }
if (this.customerType !== initial.customerType || this.p4mUser !== initial.p4mUser) { if (
this.customerType !== initial.customerType ||
this.p4mUser !== initial.p4mUser
) {
this.onChange(this.value); this.onChange(this.value);
this.onTouched(); this.onTouched();
this.valueChanges.emit(this.value); this.valueChanges.emit(this.value);
} }
this.checkboxes?.find((c) => c.name === this.customerType)?.writeValue(true); this.checkboxes
?.find((c) => c.name === this.customerType)
?.writeValue(true);
} }
} }

View File

@@ -7,6 +7,6 @@ export * from './interests';
export * from './name'; export * from './name';
export * from './newsletter'; export * from './newsletter';
export * from './organisation'; export * from './organisation';
export * from './p4m-number'; // export * from './p4m-number';
export * from './phone-numbers'; export * from './phone-numbers';
export * from './form-block'; export * from './form-block';

View File

@@ -1,4 +1,4 @@
// start:ng42.barrel // // start:ng42.barrel
export * from './p4m-number-form-block.component'; // export * from './p4m-number-form-block.component';
export * from './p4m-number-form-block.module'; // export * from './p4m-number-form-block.module';
// end:ng42.barrel // // end:ng42.barrel

View File

@@ -1,4 +1,4 @@
<shared-form-control label="Kundenkartencode" class="flex-grow"> <!-- <shared-form-control label="Kundenkartencode" class="flex-grow">
<input <input
placeholder="Kundenkartencode" placeholder="Kundenkartencode"
class="input-control" class="input-control"
@@ -13,4 +13,4 @@
<button type="button" (click)="scan()"> <button type="button" (click)="scan()">
<shared-icon icon="barcode-scan" [size]="32"></shared-icon> <shared-icon icon="barcode-scan" [size]="32"></shared-icon>
</button> </button>
} } -->

View File

@@ -1,49 +1,49 @@
import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; // import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { UntypedFormControl, Validators } from '@angular/forms'; // import { UntypedFormControl, Validators } from '@angular/forms';
import { FormBlockControl } from '../form-block'; // import { FormBlockControl } from '../form-block';
import { ScanAdapterService } from '@adapter/scan'; // import { ScanAdapterService } from '@adapter/scan';
@Component({ // @Component({
selector: 'app-p4m-number-form-block', // selector: 'app-p4m-number-form-block',
templateUrl: 'p4m-number-form-block.component.html', // templateUrl: 'p4m-number-form-block.component.html',
styleUrls: ['p4m-number-form-block.component.scss'], // styleUrls: ['p4m-number-form-block.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush, // changeDetection: ChangeDetectionStrategy.OnPush,
standalone: false, // standalone: false,
}) // })
export class P4mNumberFormBlockComponent extends FormBlockControl<string> { // export class P4mNumberFormBlockComponent extends FormBlockControl<string> {
get tabIndexEnd() { // get tabIndexEnd() {
return this.tabIndexStart; // return this.tabIndexStart;
} // }
constructor( // constructor(
private scanAdapter: ScanAdapterService, // private scanAdapter: ScanAdapterService,
private changeDetectorRef: ChangeDetectorRef, // private changeDetectorRef: ChangeDetectorRef,
) { // ) {
super(); // super();
} // }
updateValidators(): void { // updateValidators(): void {
this.control.setValidators([...this.getValidatorFn()]); // this.control.setValidators([...this.getValidatorFn()]);
this.control.setAsyncValidators(this.getAsyncValidatorFn()); // this.control.setAsyncValidators(this.getAsyncValidatorFn());
this.control.updateValueAndValidity(); // this.control.updateValueAndValidity();
} // }
initializeControl(data?: string): void { // initializeControl(data?: string): void {
this.control = new UntypedFormControl(data ?? '', [Validators.required], this.getAsyncValidatorFn()); // this.control = new UntypedFormControl(data ?? '', [Validators.required], this.getAsyncValidatorFn());
} // }
_patchValue(update: { previous: string; current: string }): void { // _patchValue(update: { previous: string; current: string }): void {
this.control.patchValue(update.current); // this.control.patchValue(update.current);
} // }
scan() { // scan() {
this.scanAdapter.scan().subscribe((result) => { // this.scanAdapter.scan().subscribe((result) => {
this.control.patchValue(result); // this.control.patchValue(result);
this.changeDetectorRef.markForCheck(); // this.changeDetectorRef.markForCheck();
}); // });
} // }
canScan() { // canScan() {
return this.scanAdapter.isReady(); // return this.scanAdapter.isReady();
} // }
} // }

View File

@@ -1,14 +1,14 @@
import { NgModule } from '@angular/core'; // import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common'; // import { CommonModule } from '@angular/common';
import { P4mNumberFormBlockComponent } from './p4m-number-form-block.component'; // import { P4mNumberFormBlockComponent } from './p4m-number-form-block.component';
import { ReactiveFormsModule } from '@angular/forms'; // import { ReactiveFormsModule } from '@angular/forms';
import { IconComponent } from '@shared/components/icon'; // import { IconComponent } from '@shared/components/icon';
import { FormControlComponent } from '@shared/components/form-control'; // import { FormControlComponent } from '@shared/components/form-control';
@NgModule({ // @NgModule({
imports: [CommonModule, ReactiveFormsModule, FormControlComponent, IconComponent], // imports: [CommonModule, ReactiveFormsModule, FormControlComponent, IconComponent],
exports: [P4mNumberFormBlockComponent], // exports: [P4mNumberFormBlockComponent],
declarations: [P4mNumberFormBlockComponent], // declarations: [P4mNumberFormBlockComponent],
}) // })
export class P4mNumberFormBlockModule {} // export class P4mNumberFormBlockModule {}

View File

@@ -1,5 +1,12 @@
import { HttpErrorResponse } from '@angular/common/http'; import { HttpErrorResponse } from '@angular/common/http';
import { ChangeDetectorRef, Directive, OnDestroy, OnInit, ViewChild, inject } from '@angular/core'; import {
ChangeDetectorRef,
Directive,
OnDestroy,
OnInit,
ViewChild,
inject,
} from '@angular/core';
import { import {
AbstractControl, AbstractControl,
AsyncValidatorFn, AsyncValidatorFn,
@@ -11,7 +18,12 @@ import {
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { BreadcrumbService } from '@core/breadcrumb'; import { BreadcrumbService } from '@core/breadcrumb';
import { CrmCustomerService } from '@domain/crm'; import { CrmCustomerService } from '@domain/crm';
import { AddressDTO, CustomerDTO, PayerDTO, ShippingAddressDTO } from '@generated/swagger/crm-api'; import {
AddressDTO,
CustomerDTO,
PayerDTO,
ShippingAddressDTO,
} from '@generated/swagger/crm-api';
import { UiErrorModalComponent, UiModalService } from '@ui/modal'; import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { UiValidators } from '@ui/validators'; import { UiValidators } from '@ui/validators';
import { isNull } from 'lodash'; import { isNull } from 'lodash';
@@ -42,7 +54,10 @@ import {
mapCustomerInfoDtoToCustomerCreateFormData, mapCustomerInfoDtoToCustomerCreateFormData,
} from './customer-create-form-data'; } from './customer-create-form-data';
import { AddressSelectionModalService } from '../modals'; import { AddressSelectionModalService } from '../modals';
import { CustomerCreateNavigation, CustomerSearchNavigation } from '@shared/services/navigation'; import {
CustomerCreateNavigation,
CustomerSearchNavigation,
} from '@shared/services/navigation';
@Directive() @Directive()
export abstract class AbstractCreateCustomer implements OnInit, OnDestroy { export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
@@ -104,7 +119,12 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
); );
this.processId$ this.processId$
.pipe(startWith(undefined), bufferCount(2, 1), takeUntil(this.onDestroy$), delay(100)) .pipe(
startWith(undefined),
bufferCount(2, 1),
takeUntil(this.onDestroy$),
delay(100),
)
.subscribe(async ([previous, current]) => { .subscribe(async ([previous, current]) => {
if (previous === undefined) { if (previous === undefined) {
await this._initFormData(); await this._initFormData();
@@ -155,7 +175,10 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
} }
} }
async addOrUpdateBreadcrumb(processId: number, formData: CustomerCreateFormData) { async addOrUpdateBreadcrumb(
processId: number,
formData: CustomerCreateFormData,
) {
await this.breadcrumb.addOrUpdateBreadcrumbIfNotExists({ await this.breadcrumb.addOrUpdateBreadcrumbIfNotExists({
key: processId, key: processId,
name: 'Kundendaten erfassen', name: 'Kundendaten erfassen',
@@ -195,7 +218,10 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
console.log('customerTypeChanged', customerType); console.log('customerTypeChanged', customerType);
} }
addFormBlock(key: keyof CustomerCreateFormData, block: FormBlock<any, AbstractControl>) { addFormBlock(
key: keyof CustomerCreateFormData,
block: FormBlock<any, AbstractControl>,
) {
this.form.addControl(key, block.control); this.form.addControl(key, block.control);
this.cdr.markForCheck(); this.cdr.markForCheck();
} }
@@ -232,7 +258,10 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
return true; return true;
} }
// Check Year + Month // Check Year + Month
else if (inputDate.getFullYear() === minBirthDate.getFullYear() && inputDate.getMonth() < minBirthDate.getMonth()) { else if (
inputDate.getFullYear() === minBirthDate.getFullYear() &&
inputDate.getMonth() < minBirthDate.getMonth()
) {
return true; return true;
} }
// Check Year + Month + Day // Check Year + Month + Day
@@ -279,70 +308,80 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
); );
}; };
checkLoyalityCardValidator: AsyncValidatorFn = (control) => { // checkLoyalityCardValidator: AsyncValidatorFn = (control) => {
return of(control.value).pipe( // return of(control.value).pipe(
delay(500), // delay(500),
mergeMap((value) => { // mergeMap((value) => {
const customerId = this.formData?._meta?.customerDto?.id ?? this.formData?._meta?.customerInfoDto?.id; // const customerId = this.formData?._meta?.customerDto?.id ?? this.formData?._meta?.customerInfoDto?.id;
return this.customerService.checkLoyaltyCard({ loyaltyCardNumber: value, customerId }).pipe( // return this.customerService.checkLoyaltyCard({ loyaltyCardNumber: value, customerId }).pipe(
map((response) => { // map((response) => {
if (response.error) { // if (response.error) {
throw response.message; // throw response.message;
} // }
/** // /**
* #4485 Kubi // Verhalten mit angelegte aber nicht verknüpfte Kundenkartencode in Kundensuche und Kundendaten erfassen ist nicht gleich // * #4485 Kubi // Verhalten mit angelegte aber nicht verknüpfte Kundenkartencode in Kundensuche und Kundendaten erfassen ist nicht gleich
* Fall1: Kundenkarte hat Daten in point4more: // * Fall1: Kundenkarte hat Daten in point4more:
* Sobald Kundenkartencode in Feld "Kundenkartencode" reingegeben wird- werden die Daten von point4more in Formular "Kundendaten Erfassen" eingefügt und ersetzen (im Ganzen, nicht inkremental) die Daten in Felder, falls welche schon reingetippt werden. // * Sobald Kundenkartencode in Feld "Kundenkartencode" reingegeben wird- werden die Daten von point4more in Formular "Kundendaten Erfassen" eingefügt und ersetzen (im Ganzen, nicht inkremental) die Daten in Felder, falls welche schon reingetippt werden.
* Fall2: Kundenkarte hat keine Daten in point4more: // * Fall2: Kundenkarte hat keine Daten in point4more:
* Sobald Kundenkartencode in Feld "Kundenkartencode" reingegeben wird- bleiben die Daten in Formular "Kundendaten Erfassen" in Felder, falls welche schon reingetippt werden. // * Sobald Kundenkartencode in Feld "Kundenkartencode" reingegeben wird- bleiben die Daten in Formular "Kundendaten Erfassen" in Felder, falls welche schon reingetippt werden.
*/ // */
if (response.result && response.result.customer) { // if (response.result && response.result.customer) {
const customer = response.result.customer; // const customer = response.result.customer;
const data = mapCustomerInfoDtoToCustomerCreateFormData(customer); // const data = mapCustomerInfoDtoToCustomerCreateFormData(customer);
if (data.name.firstName && data.name.lastName) { // if (data.name.firstName && data.name.lastName) {
// Fall1 // // Fall1
this._formData.next(data); // this._formData.next(data);
} else { // } else {
// Fall2 Hier müssen die Metadaten gesetzt werden um eine verknüfung zur kundenkarte zu ermöglichen. // // Fall2 Hier müssen die Metadaten gesetzt werden um eine verknüfung zur kundenkarte zu ermöglichen.
const current = this.formData; // const current = this.formData;
current._meta = data._meta; // current._meta = data._meta;
current.p4m = data.p4m; // current.p4m = data.p4m;
} // }
} // }
return null; // return null;
}), // }),
catchError((error) => { // catchError((error) => {
if (error instanceof HttpErrorResponse) { // if (error instanceof HttpErrorResponse) {
if (error?.error?.invalidProperties?.loyaltyCardNumber) { // if (error?.error?.invalidProperties?.loyaltyCardNumber) {
return of({ invalid: error.error.invalidProperties.loyaltyCardNumber }); // return of({ invalid: error.error.invalidProperties.loyaltyCardNumber });
} else { // } else {
return of({ invalid: 'Kundenkartencode ist ungültig' }); // return of({ invalid: 'Kundenkartencode ist ungültig' });
} // }
} // }
}), // }),
); // );
}), // }),
tap(() => { // tap(() => {
control.markAsTouched(); // control.markAsTouched();
this.cdr.markForCheck(); // this.cdr.markForCheck();
}), // }),
); // );
}; // };
async navigateToCustomerDetails(customer: CustomerDTO) { async navigateToCustomerDetails(customer: CustomerDTO) {
const processId = await this.processId$.pipe(first()).toPromise(); const processId = await this.processId$.pipe(first()).toPromise();
const route = this.customerSearchNavigation.detailsRoute({ processId, customerId: customer.id, customer }); const route = this.customerSearchNavigation.detailsRoute({
processId,
customerId: customer.id,
customer,
});
return this.router.navigate(route.path, { queryParams: route.urlTree.queryParams }); return this.router.navigate(route.path, {
queryParams: route.urlTree.queryParams,
});
} }
async validateAddressData(address: AddressDTO): Promise<AddressDTO> { async validateAddressData(address: AddressDTO): Promise<AddressDTO> {
const addressValidationResult = await this.addressVlidationModal.validateAddress(address); const addressValidationResult =
await this.addressVlidationModal.validateAddress(address);
if (addressValidationResult !== undefined && (addressValidationResult as any) !== 'continue') { if (
addressValidationResult !== undefined &&
(addressValidationResult as any) !== 'continue'
) {
address = addressValidationResult; address = addressValidationResult;
} }
@@ -389,7 +428,9 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
} catch (error) { } catch (error) {
this.form.enable(); this.form.enable();
setTimeout(() => { setTimeout(() => {
this.addressFormBlock.setAddressValidationError(error.error.invalidProperties); this.addressFormBlock.setAddressValidationError(
error.error.invalidProperties,
);
}, 10); }, 10);
return; return;
@@ -397,7 +438,10 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
} }
} }
if (data.birthDate && isNull(UiValidators.date(new UntypedFormControl(data.birthDate)))) { if (
data.birthDate &&
isNull(UiValidators.date(new UntypedFormControl(data.birthDate)))
) {
customer.dateOfBirth = data.birthDate; customer.dateOfBirth = data.birthDate;
} }
@@ -406,11 +450,15 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
if (this.validateShippingAddress) { if (this.validateShippingAddress) {
try { try {
billingAddress.address = await this.validateAddressData(billingAddress.address); billingAddress.address = await this.validateAddressData(
billingAddress.address,
);
} catch (error) { } catch (error) {
this.form.enable(); this.form.enable();
setTimeout(() => { setTimeout(() => {
this.addressFormBlock.setAddressValidationError(error.error.invalidProperties); this.addressFormBlock.setAddressValidationError(
error.error.invalidProperties,
);
}, 10); }, 10);
return; return;
@@ -426,15 +474,21 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
} }
if (data.deviatingDeliveryAddress?.deviatingAddress) { if (data.deviatingDeliveryAddress?.deviatingAddress) {
const shippingAddress = this.mapToShippingAddress(data.deviatingDeliveryAddress); const shippingAddress = this.mapToShippingAddress(
data.deviatingDeliveryAddress,
);
if (this.validateShippingAddress) { if (this.validateShippingAddress) {
try { try {
shippingAddress.address = await this.validateAddressData(shippingAddress.address); shippingAddress.address = await this.validateAddressData(
shippingAddress.address,
);
} catch (error) { } catch (error) {
this.form.enable(); this.form.enable();
setTimeout(() => { setTimeout(() => {
this.deviatingDeliveryAddressFormBlock.setAddressValidationError(error.error.invalidProperties); this.deviatingDeliveryAddressFormBlock.setAddressValidationError(
error.error.invalidProperties,
);
}, 10); }, 10);
return; return;
@@ -474,7 +528,13 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
}; };
} }
mapToBillingAddress({ name, address, email, organisation, phoneNumbers }: DeviatingAddressFormBlockData): PayerDTO { mapToBillingAddress({
name,
address,
email,
organisation,
phoneNumbers,
}: DeviatingAddressFormBlockData): PayerDTO {
return { return {
gender: name?.gender, gender: name?.gender,
title: name?.title, title: name?.title,

View File

@@ -1,10 +1,10 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { CreateB2BCustomerModule } from './create-b2b-customer/create-b2b-customer.module'; import { CreateB2BCustomerModule } from './create-b2b-customer/create-b2b-customer.module';
import { CreateGuestCustomerModule } from './create-guest-customer'; import { CreateGuestCustomerModule } from './create-guest-customer';
import { CreateP4MCustomerModule } from './create-p4m-customer'; // import { CreateP4MCustomerModule } from './create-p4m-customer';
import { CreateStoreCustomerModule } from './create-store-customer/create-store-customer.module'; import { CreateStoreCustomerModule } from './create-store-customer/create-store-customer.module';
import { CreateWebshopCustomerModule } from './create-webshop-customer/create-webshop-customer.module'; import { CreateWebshopCustomerModule } from './create-webshop-customer/create-webshop-customer.module';
import { UpdateP4MWebshopCustomerModule } from './update-p4m-webshop-customer'; // import { UpdateP4MWebshopCustomerModule } from './update-p4m-webshop-customer';
import { CreateCustomerComponent } from './create-customer.component'; import { CreateCustomerComponent } from './create-customer.component';
@NgModule({ @NgModule({
@@ -13,8 +13,8 @@ import { CreateCustomerComponent } from './create-customer.component';
CreateGuestCustomerModule, CreateGuestCustomerModule,
CreateStoreCustomerModule, CreateStoreCustomerModule,
CreateWebshopCustomerModule, CreateWebshopCustomerModule,
CreateP4MCustomerModule, // CreateP4MCustomerModule,
UpdateP4MWebshopCustomerModule, // UpdateP4MWebshopCustomerModule,
CreateCustomerComponent, CreateCustomerComponent,
], ],
exports: [ exports: [
@@ -22,8 +22,8 @@ import { CreateCustomerComponent } from './create-customer.component';
CreateGuestCustomerModule, CreateGuestCustomerModule,
CreateStoreCustomerModule, CreateStoreCustomerModule,
CreateWebshopCustomerModule, CreateWebshopCustomerModule,
CreateP4MCustomerModule, // CreateP4MCustomerModule,
UpdateP4MWebshopCustomerModule, // UpdateP4MWebshopCustomerModule,
CreateCustomerComponent, CreateCustomerComponent,
], ],
}) })

View File

@@ -1,9 +1,9 @@
@if (formData$ | async; as data) { <!-- @if (formData$ | async; as data) {
<form (keydown.enter)="$event.preventDefault()"> <form (keydown.enter)="$event.preventDefault()">
<h1 class="title flex flex-row items-center justify-center"> <h1 class="title flex flex-row items-center justify-center">
Kundendaten erfassen Kundendaten erfassen
<!-- <span <span
class="rounded-full ml-4 h-8 w-8 text-xl text-center border-2 border-solid border-brand text-brand">i</span> --> class="rounded-full ml-4 h-8 w-8 text-xl text-center border-2 border-solid border-brand text-brand">i</span>
</h1> </h1>
<p class="description"> <p class="description">
Um Sie als Kunde beim nächsten Um Sie als Kunde beim nächsten
@@ -135,4 +135,4 @@
</button> </button>
</div> </div>
</form> </form>
} } -->

View File

@@ -1,292 +1,292 @@
import { Component, ChangeDetectionStrategy, ViewChild, OnInit } from '@angular/core'; // import { Component, ChangeDetectionStrategy, ViewChild, OnInit } from '@angular/core';
import { AsyncValidatorFn, ValidatorFn, Validators } from '@angular/forms'; // import { AsyncValidatorFn, ValidatorFn, Validators } from '@angular/forms';
import { Result } from '@domain/defs'; // import { Result } from '@domain/defs';
import { CustomerDTO, CustomerInfoDTO, KeyValueDTOOfStringAndString } from '@generated/swagger/crm-api'; // import { CustomerDTO, CustomerInfoDTO, KeyValueDTOOfStringAndString } from '@generated/swagger/crm-api';
import { UiErrorModalComponent, UiModalResult } from '@ui/modal'; // import { UiErrorModalComponent, UiModalResult } from '@ui/modal';
import { NEVER, Observable, of } from 'rxjs'; // import { NEVER, Observable, of } from 'rxjs';
import { catchError, distinctUntilChanged, first, map, switchMap, takeUntil, withLatestFrom } from 'rxjs/operators'; // import { catchError, distinctUntilChanged, first, map, switchMap, takeUntil, withLatestFrom } from 'rxjs/operators';
import { // import {
AddressFormBlockComponent, // AddressFormBlockComponent,
AddressFormBlockData, // AddressFormBlockData,
DeviatingAddressFormBlockComponent, // DeviatingAddressFormBlockComponent,
} from '../../components/form-blocks'; // } from '../../components/form-blocks';
import { NameFormBlockData } from '../../components/form-blocks/name/name-form-block-data'; // import { NameFormBlockData } from '../../components/form-blocks/name/name-form-block-data';
import { WebshopCustomnerAlreadyExistsModalComponent, WebshopCustomnerAlreadyExistsModalData } from '../../modals'; // import { WebshopCustomnerAlreadyExistsModalComponent, WebshopCustomnerAlreadyExistsModalData } from '../../modals';
import { validateEmail } from '../../validators/email-validator'; // import { validateEmail } from '../../validators/email-validator';
import { AbstractCreateCustomer } from '../abstract-create-customer'; // import { AbstractCreateCustomer } from '../abstract-create-customer';
import { encodeFormData, mapCustomerDtoToCustomerCreateFormData } from '../customer-create-form-data'; // import { encodeFormData, mapCustomerDtoToCustomerCreateFormData } from '../customer-create-form-data';
import { zipCodeValidator } from '../../validators/zip-code-validator'; // import { zipCodeValidator } from '../../validators/zip-code-validator';
@Component({ // @Component({
selector: 'app-create-p4m-customer', // selector: 'app-create-p4m-customer',
templateUrl: 'create-p4m-customer.component.html', // templateUrl: 'create-p4m-customer.component.html',
styleUrls: ['../create-customer.scss', 'create-p4m-customer.component.scss'], // styleUrls: ['../create-customer.scss', 'create-p4m-customer.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush, // changeDetection: ChangeDetectionStrategy.OnPush,
standalone: false, // standalone: false,
}) // })
export class CreateP4MCustomerComponent extends AbstractCreateCustomer implements OnInit { // export class CreateP4MCustomerComponent extends AbstractCreateCustomer implements OnInit {
validateAddress = true; // validateAddress = true;
validateShippingAddress = true; // validateShippingAddress = true;
get _customerType() { // get _customerType() {
return this.activatedRoute.snapshot.data.customerType; // return this.activatedRoute.snapshot.data.customerType;
} // }
get customerType() { // get customerType() {
return `${this._customerType}-p4m`; // return `${this._customerType}-p4m`;
} // }
nameRequiredMarks: (keyof NameFormBlockData)[] = ['gender', 'firstName', 'lastName']; // nameRequiredMarks: (keyof NameFormBlockData)[] = ['gender', 'firstName', 'lastName'];
nameValidationFns: Record<keyof NameFormBlockData, ValidatorFn[]> = { // nameValidationFns: Record<keyof NameFormBlockData, ValidatorFn[]> = {
firstName: [Validators.required], // firstName: [Validators.required],
lastName: [Validators.required], // lastName: [Validators.required],
gender: [Validators.required], // gender: [Validators.required],
title: [], // title: [],
}; // };
emailRequiredMark: boolean; // emailRequiredMark: boolean;
emailValidatorFn: ValidatorFn[]; // emailValidatorFn: ValidatorFn[];
asyncEmailVlaidtorFn: AsyncValidatorFn[]; // asyncEmailVlaidtorFn: AsyncValidatorFn[];
asyncLoyaltyCardValidatorFn: AsyncValidatorFn[]; // asyncLoyaltyCardValidatorFn: AsyncValidatorFn[];
shippingAddressRequiredMarks: (keyof AddressFormBlockData)[] = [ // shippingAddressRequiredMarks: (keyof AddressFormBlockData)[] = [
'street', // 'street',
'streetNumber', // 'streetNumber',
'zipCode', // 'zipCode',
'city', // 'city',
'country', // 'country',
]; // ];
shippingAddressValidators: Record<string, ValidatorFn[]> = { // shippingAddressValidators: Record<string, ValidatorFn[]> = {
street: [Validators.required], // street: [Validators.required],
streetNumber: [Validators.required], // streetNumber: [Validators.required],
zipCode: [Validators.required, zipCodeValidator()], // zipCode: [Validators.required, zipCodeValidator()],
city: [Validators.required], // city: [Validators.required],
country: [Validators.required], // country: [Validators.required],
}; // };
addressRequiredMarks: (keyof AddressFormBlockData)[]; // addressRequiredMarks: (keyof AddressFormBlockData)[];
addressValidatorFns: Record<string, ValidatorFn[]>; // addressValidatorFns: Record<string, ValidatorFn[]>;
@ViewChild(AddressFormBlockComponent, { static: false }) // @ViewChild(AddressFormBlockComponent, { static: false })
addressFormBlock: AddressFormBlockComponent; // addressFormBlock: AddressFormBlockComponent;
@ViewChild(DeviatingAddressFormBlockComponent, { static: false }) // @ViewChild(DeviatingAddressFormBlockComponent, { static: false })
deviatingDeliveryAddressFormBlock: DeviatingAddressFormBlockComponent; // deviatingDeliveryAddressFormBlock: DeviatingAddressFormBlockComponent;
agbValidatorFns = [Validators.requiredTrue]; // agbValidatorFns = [Validators.requiredTrue];
birthDateValidatorFns = []; // birthDateValidatorFns = [];
existingCustomer$: Observable<CustomerInfoDTO | CustomerDTO | null>; // existingCustomer$: Observable<CustomerInfoDTO | CustomerDTO | null>;
ngOnInit(): void { // ngOnInit(): void {
super.ngOnInit(); // super.ngOnInit();
this.initMarksAndValidators(); // this.initMarksAndValidators();
this.existingCustomer$ = this.customerExists$.pipe( // this.existingCustomer$ = this.customerExists$.pipe(
distinctUntilChanged(), // distinctUntilChanged(),
switchMap((exists) => { // switchMap((exists) => {
if (exists) { // if (exists) {
return this.fetchCustomerInfo(); // return this.fetchCustomerInfo();
} // }
return of(null); // return of(null);
}), // }),
); // );
this.existingCustomer$ // this.existingCustomer$
.pipe( // .pipe(
takeUntil(this.onDestroy$), // takeUntil(this.onDestroy$),
switchMap((info) => { // switchMap((info) => {
if (info) { // if (info) {
return this.customerService.getCustomer(info.id, 2).pipe( // return this.customerService.getCustomer(info.id, 2).pipe(
map((res) => res.result), // map((res) => res.result),
catchError((err) => NEVER), // catchError((err) => NEVER),
); // );
} // }
return NEVER; // return NEVER;
}), // }),
withLatestFrom(this.processId$), // withLatestFrom(this.processId$),
) // )
.subscribe(([customer, processId]) => { // .subscribe(([customer, processId]) => {
if (customer) { // if (customer) {
this.modal // this.modal
.open({ // .open({
content: WebshopCustomnerAlreadyExistsModalComponent, // content: WebshopCustomnerAlreadyExistsModalComponent,
data: { // data: {
customer, // customer,
processId, // processId,
} as WebshopCustomnerAlreadyExistsModalData, // } as WebshopCustomnerAlreadyExistsModalData,
title: 'Es existiert bereits ein Onlinekonto mit dieser E-Mail-Adresse', // title: 'Es existiert bereits ein Onlinekonto mit dieser E-Mail-Adresse',
}) // })
.afterClosed$.subscribe(async (result: UiModalResult<boolean>) => { // .afterClosed$.subscribe(async (result: UiModalResult<boolean>) => {
if (result.data) { // if (result.data) {
this.navigateToUpdatePage(customer); // this.navigateToUpdatePage(customer);
} else { // } else {
this.formData.email = ''; // this.formData.email = '';
this.cdr.markForCheck(); // this.cdr.markForCheck();
} // }
}); // });
} // }
}); // });
} // }
async navigateToUpdatePage(customer: CustomerDTO) { // async navigateToUpdatePage(customer: CustomerDTO) {
const processId = await this.processId$.pipe(first()).toPromise(); // const processId = await this.processId$.pipe(first()).toPromise();
this.router.navigate(['/kunde', processId, 'customer', 'create', 'webshop-p4m', 'update'], { // this.router.navigate(['/kunde', processId, 'customer', 'create', 'webshop-p4m', 'update'], {
queryParams: { // queryParams: {
formData: encodeFormData({ // formData: encodeFormData({
...mapCustomerDtoToCustomerCreateFormData(customer), // ...mapCustomerDtoToCustomerCreateFormData(customer),
p4m: this.formData.p4m, // p4m: this.formData.p4m,
}), // }),
}, // },
}); // });
} // }
initMarksAndValidators() { // initMarksAndValidators() {
this.asyncLoyaltyCardValidatorFn = [this.checkLoyalityCardValidator]; // this.asyncLoyaltyCardValidatorFn = [this.checkLoyalityCardValidator];
this.birthDateValidatorFns = [Validators.required, this.minBirthDateValidator()]; // this.birthDateValidatorFns = [Validators.required, this.minBirthDateValidator()];
if (this._customerType === 'webshop') { // if (this._customerType === 'webshop') {
this.emailRequiredMark = true; // this.emailRequiredMark = true;
this.emailValidatorFn = [Validators.required, Validators.email, validateEmail]; // this.emailValidatorFn = [Validators.required, Validators.email, validateEmail];
this.asyncEmailVlaidtorFn = [this.emailExistsValidator]; // this.asyncEmailVlaidtorFn = [this.emailExistsValidator];
this.addressRequiredMarks = this.shippingAddressRequiredMarks; // this.addressRequiredMarks = this.shippingAddressRequiredMarks;
this.addressValidatorFns = this.shippingAddressValidators; // this.addressValidatorFns = this.shippingAddressValidators;
} else { // } else {
this.emailRequiredMark = false; // this.emailRequiredMark = false;
this.emailValidatorFn = [Validators.email, validateEmail]; // this.emailValidatorFn = [Validators.email, validateEmail];
} // }
} // }
fetchCustomerInfo(): Observable<CustomerDTO | null> { // fetchCustomerInfo(): Observable<CustomerDTO | null> {
const email = this.formData.email; // const email = this.formData.email;
return this.customerService.getOnlineCustomerByEmail(email).pipe( // return this.customerService.getOnlineCustomerByEmail(email).pipe(
map((result) => { // map((result) => {
if (result) { // if (result) {
return result; // return result;
} // }
return null; // return null;
}), // }),
catchError((err) => { // catchError((err) => {
this.modal.open({ // this.modal.open({
content: UiErrorModalComponent, // content: UiErrorModalComponent,
data: err, // data: err,
}); // });
return [null]; // return [null];
}), // }),
); // );
} // }
getInterests(): KeyValueDTOOfStringAndString[] { // getInterests(): KeyValueDTOOfStringAndString[] {
const interests: KeyValueDTOOfStringAndString[] = []; // const interests: KeyValueDTOOfStringAndString[] = [];
for (const key in this.formData.interests) { // for (const key in this.formData.interests) {
if (this.formData.interests[key]) { // if (this.formData.interests[key]) {
interests.push({ key, group: 'KUBI_INTERESSEN' }); // interests.push({ key, group: 'KUBI_INTERESSEN' });
} // }
} // }
return interests; // return interests;
} // }
getNewsletter(): KeyValueDTOOfStringAndString | undefined { // getNewsletter(): KeyValueDTOOfStringAndString | undefined {
if (this.formData.newsletter) { // if (this.formData.newsletter) {
return { key: 'kubi_newsletter', group: 'KUBI_NEWSLETTER' }; // return { key: 'kubi_newsletter', group: 'KUBI_NEWSLETTER' };
} // }
} // }
static MapCustomerInfoDtoToCustomerDto(customerInfoDto: CustomerInfoDTO): CustomerDTO { // static MapCustomerInfoDtoToCustomerDto(customerInfoDto: CustomerInfoDTO): CustomerDTO {
return { // return {
address: customerInfoDto.address, // address: customerInfoDto.address,
agentComment: customerInfoDto.agentComment, // agentComment: customerInfoDto.agentComment,
bonusCard: customerInfoDto.bonusCard, // bonusCard: customerInfoDto.bonusCard,
campaignCode: customerInfoDto.campaignCode, // campaignCode: customerInfoDto.campaignCode,
communicationDetails: customerInfoDto.communicationDetails, // communicationDetails: customerInfoDto.communicationDetails,
createdInBranch: customerInfoDto.createdInBranch, // createdInBranch: customerInfoDto.createdInBranch,
customerGroup: customerInfoDto.customerGroup, // customerGroup: customerInfoDto.customerGroup,
customerNumber: customerInfoDto.customerNumber, // customerNumber: customerInfoDto.customerNumber,
customerStatus: customerInfoDto.customerStatus, // customerStatus: customerInfoDto.customerStatus,
customerType: customerInfoDto.customerType, // customerType: customerInfoDto.customerType,
dateOfBirth: customerInfoDto.dateOfBirth, // dateOfBirth: customerInfoDto.dateOfBirth,
features: customerInfoDto.features, // features: customerInfoDto.features,
firstName: customerInfoDto.firstName, // firstName: customerInfoDto.firstName,
lastName: customerInfoDto.lastName, // lastName: customerInfoDto.lastName,
gender: customerInfoDto.gender, // gender: customerInfoDto.gender,
hasOnlineAccount: customerInfoDto.hasOnlineAccount, // hasOnlineAccount: customerInfoDto.hasOnlineAccount,
isGuestAccount: customerInfoDto.isGuestAccount, // isGuestAccount: customerInfoDto.isGuestAccount,
label: customerInfoDto.label, // label: customerInfoDto.label,
notificationChannels: customerInfoDto.notificationChannels, // notificationChannels: customerInfoDto.notificationChannels,
organisation: customerInfoDto.organisation, // organisation: customerInfoDto.organisation,
title: customerInfoDto.title, // title: customerInfoDto.title,
id: customerInfoDto.id, // id: customerInfoDto.id,
pId: customerInfoDto.pId, // pId: customerInfoDto.pId,
}; // };
} // }
async saveCustomer(customer: CustomerDTO): Promise<CustomerDTO> { // async saveCustomer(customer: CustomerDTO): Promise<CustomerDTO> {
const isWebshop = this._customerType === 'webshop'; // const isWebshop = this._customerType === 'webshop';
let res: Result<CustomerDTO>; // let res: Result<CustomerDTO>;
const { customerDto, customerInfoDto } = this.formData?._meta ?? {}; // const { customerDto, customerInfoDto } = this.formData?._meta ?? {};
if (customerDto) { // if (customerDto) {
customer = { ...customerDto, ...customer }; // customer = { ...customerDto, ...customer };
} else if (customerInfoDto) { // } else if (customerInfoDto) {
customer = { ...CreateP4MCustomerComponent.MapCustomerInfoDtoToCustomerDto(customerInfoDto), ...customer }; // customer = { ...CreateP4MCustomerComponent.MapCustomerInfoDtoToCustomerDto(customerInfoDto), ...customer };
} // }
const p4mFeature = customer.features?.find((attr) => attr.key === 'p4mUser'); // const p4mFeature = customer.features?.find((attr) => attr.key === 'p4mUser');
if (p4mFeature) { // if (p4mFeature) {
p4mFeature.value = this.formData.p4m; // p4mFeature.value = this.formData.p4m;
} else { // } else {
customer.features.push({ // customer.features.push({
key: 'p4mUser', // key: 'p4mUser',
value: this.formData.p4m, // value: this.formData.p4m,
}); // });
} // }
const interests = this.getInterests(); // const interests = this.getInterests();
if (interests.length > 0) { // if (interests.length > 0) {
customer.features?.push(...interests); // customer.features?.push(...interests);
// TODO: Klärung wie Interessen zukünftig gespeichert werden // // TODO: Klärung wie Interessen zukünftig gespeichert werden
// await this._loyaltyCardService // // await this._loyaltyCardService
// .LoyaltyCardSaveInteressen({ // // .LoyaltyCardSaveInteressen({
// customerId: res.result.id, // // customerId: res.result.id,
// interessen: this.getInterests(), // // interessen: this.getInterests(),
// }) // // })
// .toPromise(); // // .toPromise();
} // }
const newsletter = this.getNewsletter(); // const newsletter = this.getNewsletter();
if (newsletter) { // if (newsletter) {
customer.features.push(newsletter); // customer.features.push(newsletter);
} else { // } else {
customer.features = customer.features.filter( // customer.features = customer.features.filter(
(feature) => feature.key !== 'kubi_newsletter' && feature.group !== 'KUBI_NEWSLETTER', // (feature) => feature.key !== 'kubi_newsletter' && feature.group !== 'KUBI_NEWSLETTER',
); // );
} // }
if (isWebshop) { // if (isWebshop) {
if (customer.id > 0) { // if (customer.id > 0) {
if (this.formData?._meta?.hasLocalityCard) { // if (this.formData?._meta?.hasLocalityCard) {
res = await this.customerService.updateStoreP4MToWebshopP4M(customer); // res = await this.customerService.updateStoreP4MToWebshopP4M(customer);
} else { // } else {
res = await this.customerService.updateToP4MOnlineCustomer(customer); // res = await this.customerService.updateToP4MOnlineCustomer(customer);
} // }
} else { // } else {
res = await this.customerService.createOnlineCustomer(customer).toPromise(); // res = await this.customerService.createOnlineCustomer(customer).toPromise();
} // }
} else { // } else {
res = await this.customerService.createStoreCustomer(customer).toPromise(); // res = await this.customerService.createStoreCustomer(customer).toPromise();
} // }
return res.result; // return res.result;
} // }
} // }

View File

@@ -1,45 +1,45 @@
import { NgModule } from '@angular/core'; // import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common'; // import { CommonModule } from '@angular/common';
import { CreateP4MCustomerComponent } from './create-p4m-customer.component'; // import { CreateP4MCustomerComponent } from './create-p4m-customer.component';
import { // import {
AddressFormBlockModule, // AddressFormBlockModule,
BirthDateFormBlockModule, // BirthDateFormBlockModule,
InterestsFormBlockModule, // InterestsFormBlockModule,
NameFormBlockModule, // NameFormBlockModule,
OrganisationFormBlockModule, // OrganisationFormBlockModule,
P4mNumberFormBlockModule, // P4mNumberFormBlockModule,
NewsletterFormBlockModule, // NewsletterFormBlockModule,
DeviatingAddressFormBlockComponentModule, // DeviatingAddressFormBlockComponentModule,
AcceptAGBFormBlockModule, // AcceptAGBFormBlockModule,
EmailFormBlockModule, // EmailFormBlockModule,
PhoneNumbersFormBlockModule, // PhoneNumbersFormBlockModule,
} from '../../components/form-blocks'; // } from '../../components/form-blocks';
import { CustomerTypeSelectorModule } from '../../components/customer-type-selector'; // import { CustomerTypeSelectorModule } from '../../components/customer-type-selector';
import { UiSpinnerModule } from '@ui/spinner'; // import { UiSpinnerModule } from '@ui/spinner';
import { UiIconModule } from '@ui/icon'; // import { UiIconModule } from '@ui/icon';
import { RouterModule } from '@angular/router'; // import { RouterModule } from '@angular/router';
@NgModule({ // @NgModule({
imports: [ // imports: [
CommonModule, // CommonModule,
CustomerTypeSelectorModule, // CustomerTypeSelectorModule,
AddressFormBlockModule, // AddressFormBlockModule,
BirthDateFormBlockModule, // BirthDateFormBlockModule,
InterestsFormBlockModule, // InterestsFormBlockModule,
NameFormBlockModule, // NameFormBlockModule,
OrganisationFormBlockModule, // OrganisationFormBlockModule,
P4mNumberFormBlockModule, // P4mNumberFormBlockModule,
NewsletterFormBlockModule, // NewsletterFormBlockModule,
DeviatingAddressFormBlockComponentModule, // DeviatingAddressFormBlockComponentModule,
AcceptAGBFormBlockModule, // AcceptAGBFormBlockModule,
EmailFormBlockModule, // EmailFormBlockModule,
PhoneNumbersFormBlockModule, // PhoneNumbersFormBlockModule,
UiSpinnerModule, // UiSpinnerModule,
UiIconModule, // UiIconModule,
RouterModule, // RouterModule,
], // ],
exports: [CreateP4MCustomerComponent], // exports: [CreateP4MCustomerComponent],
declarations: [CreateP4MCustomerComponent], // declarations: [CreateP4MCustomerComponent],
}) // })
export class CreateP4MCustomerModule {} // export class CreateP4MCustomerModule {}

View File

@@ -1,2 +1,2 @@
export * from './create-p4m-customer.component'; // export * from './create-p4m-customer.component';
export * from './create-p4m-customer.module'; // export * from './create-p4m-customer.module';

View File

@@ -1,6 +1,6 @@
import { Component, ChangeDetectionStrategy, ViewChild } from '@angular/core'; import { Component, ChangeDetectionStrategy, ViewChild } from '@angular/core';
import { ValidatorFn, Validators } from '@angular/forms'; import { ValidatorFn, Validators } from '@angular/forms';
import { CustomerDTO } from '@generated/swagger/crm-api'; import { CustomerDTO, CustomerInfoDTO } from '@generated/swagger/crm-api';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { import {
AddressFormBlockComponent, AddressFormBlockComponent,
@@ -10,13 +10,16 @@ import {
import { NameFormBlockData } from '../../components/form-blocks/name/name-form-block-data'; import { NameFormBlockData } from '../../components/form-blocks/name/name-form-block-data';
import { validateEmail } from '../../validators/email-validator'; import { validateEmail } from '../../validators/email-validator';
import { AbstractCreateCustomer } from '../abstract-create-customer'; import { AbstractCreateCustomer } from '../abstract-create-customer';
import { CreateP4MCustomerComponent } from '../create-p4m-customer'; // import { CreateP4MCustomerComponent } from '../create-p4m-customer';
import { zipCodeValidator } from '../../validators/zip-code-validator'; import { zipCodeValidator } from '../../validators/zip-code-validator';
@Component({ @Component({
selector: 'app-create-webshop-customer', selector: 'app-create-webshop-customer',
templateUrl: 'create-webshop-customer.component.html', templateUrl: 'create-webshop-customer.component.html',
styleUrls: ['../create-customer.scss', 'create-webshop-customer.component.scss'], styleUrls: [
'../create-customer.scss',
'create-webshop-customer.component.scss',
],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
standalone: false, standalone: false,
}) })
@@ -26,7 +29,11 @@ export class CreateWebshopCustomerComponent extends AbstractCreateCustomer {
validateAddress = true; validateAddress = true;
validateShippingAddress = true; validateShippingAddress = true;
nameRequiredMarks: (keyof NameFormBlockData)[] = ['gender', 'firstName', 'lastName']; nameRequiredMarks: (keyof NameFormBlockData)[] = [
'gender',
'firstName',
'lastName',
];
nameValidationFns: Record<keyof NameFormBlockData, ValidatorFn[]> = { nameValidationFns: Record<keyof NameFormBlockData, ValidatorFn[]> = {
firstName: [Validators.required], firstName: [Validators.required],
@@ -35,7 +42,13 @@ export class CreateWebshopCustomerComponent extends AbstractCreateCustomer {
title: [], title: [],
}; };
addressRequiredMarks: (keyof AddressFormBlockData)[] = ['street', 'streetNumber', 'zipCode', 'city', 'country']; addressRequiredMarks: (keyof AddressFormBlockData)[] = [
'street',
'streetNumber',
'zipCode',
'city',
'country',
];
addressValidators: Record<string, ValidatorFn[]> = { addressValidators: Record<string, ValidatorFn[]> = {
street: [Validators.required], street: [Validators.required],
@@ -68,7 +81,11 @@ export class CreateWebshopCustomerComponent extends AbstractCreateCustomer {
if (customerDto) { if (customerDto) {
customer = { ...customerDto, ...customer }; customer = { ...customerDto, ...customer };
} else if (customerInfoDto) { } else if (customerInfoDto) {
customer = { ...CreateP4MCustomerComponent.MapCustomerInfoDtoToCustomerDto(customerInfoDto), ...customer }; customer = {
// ...CreateP4MCustomerComponent.MapCustomerInfoDtoToCustomerDto(customerInfoDto),
...this.mapCustomerInfoDtoToCustomerDto(customerInfoDto),
...customer,
};
} }
const res = await this.customerService.updateToOnlineCustomer(customer); const res = await this.customerService.updateToOnlineCustomer(customer);
@@ -80,4 +97,34 @@ export class CreateWebshopCustomerComponent extends AbstractCreateCustomer {
.toPromise(); .toPromise();
} }
} }
mapCustomerInfoDtoToCustomerDto(
customerInfoDto: CustomerInfoDTO,
): CustomerDTO {
return {
address: customerInfoDto.address,
agentComment: customerInfoDto.agentComment,
bonusCard: customerInfoDto.bonusCard,
campaignCode: customerInfoDto.campaignCode,
communicationDetails: customerInfoDto.communicationDetails,
createdInBranch: customerInfoDto.createdInBranch,
customerGroup: customerInfoDto.customerGroup,
customerNumber: customerInfoDto.customerNumber,
customerStatus: customerInfoDto.customerStatus,
customerType: customerInfoDto.customerType,
dateOfBirth: customerInfoDto.dateOfBirth,
features: customerInfoDto.features,
firstName: customerInfoDto.firstName,
lastName: customerInfoDto.lastName,
gender: customerInfoDto.gender,
hasOnlineAccount: customerInfoDto.hasOnlineAccount,
isGuestAccount: customerInfoDto.isGuestAccount,
label: customerInfoDto.label,
notificationChannels: customerInfoDto.notificationChannels,
organisation: customerInfoDto.organisation,
title: customerInfoDto.title,
id: customerInfoDto.id,
pId: customerInfoDto.pId,
};
}
} }

View File

@@ -1,7 +1,7 @@
import { CustomerDTO, Gender } from '@generated/swagger/crm-api'; import { CustomerDTO, Gender } from '@generated/swagger/crm-api';
export interface CreateCustomerQueryParams { export interface CreateCustomerQueryParams {
p4mNumber?: string; // p4mNumber?: string;
customerId?: number; customerId?: number;
gender?: Gender; gender?: Gender;
title?: string; title?: string;

View File

@@ -1,6 +1,6 @@
export * from './create-b2b-customer'; export * from './create-b2b-customer';
export * from './create-guest-customer'; export * from './create-guest-customer';
export * from './create-p4m-customer'; // export * from './create-p4m-customer';
export * from './create-store-customer'; export * from './create-store-customer';
export * from './create-webshop-customer'; export * from './create-webshop-customer';
export * from './defs'; export * from './defs';

View File

@@ -1,4 +1,4 @@
@if (formData$ | async; as data) { <!-- @if (formData$ | async; as data) {
<form (keydown.enter)="$event.preventDefault()"> <form (keydown.enter)="$event.preventDefault()">
<h1 class="title flex flex-row items-center justify-center">Kundenkartendaten erfasen</h1> <h1 class="title flex flex-row items-center justify-center">Kundenkartendaten erfasen</h1>
<p class="description">Bitte erfassen Sie die Kundenkarte</p> <p class="description">Bitte erfassen Sie die Kundenkarte</p>
@@ -106,4 +106,4 @@
</button> </button>
</div> </div>
</form> </form>
} } -->

View File

@@ -1,156 +1,156 @@
import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core'; // import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core';
import { AsyncValidatorFn, ValidatorFn, Validators } from '@angular/forms'; // import { AsyncValidatorFn, ValidatorFn, Validators } from '@angular/forms';
import { Result } from '@domain/defs'; // import { Result } from '@domain/defs';
import { CustomerDTO, KeyValueDTOOfStringAndString, PayerDTO } from '@generated/swagger/crm-api'; // import { CustomerDTO, KeyValueDTOOfStringAndString, PayerDTO } from '@generated/swagger/crm-api';
import { AddressFormBlockData } from '../../components/form-blocks'; // import { AddressFormBlockData } from '../../components/form-blocks';
import { NameFormBlockData } from '../../components/form-blocks/name/name-form-block-data'; // import { NameFormBlockData } from '../../components/form-blocks/name/name-form-block-data';
import { AbstractCreateCustomer } from '../abstract-create-customer'; // import { AbstractCreateCustomer } from '../abstract-create-customer';
import { CreateP4MCustomerComponent } from '../create-p4m-customer'; // import { CreateP4MCustomerComponent } from '../create-p4m-customer';
@Component({ // @Component({
selector: 'page-update-p4m-webshop-customer', // selector: 'page-update-p4m-webshop-customer',
templateUrl: 'update-p4m-webshop-customer.component.html', // templateUrl: 'update-p4m-webshop-customer.component.html',
styleUrls: ['../create-customer.scss', 'update-p4m-webshop-customer.component.scss'], // styleUrls: ['../create-customer.scss', 'update-p4m-webshop-customer.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush, // changeDetection: ChangeDetectionStrategy.OnPush,
standalone: false, // standalone: false,
}) // })
export class UpdateP4MWebshopCustomerComponent extends AbstractCreateCustomer implements OnInit { // export class UpdateP4MWebshopCustomerComponent extends AbstractCreateCustomer implements OnInit {
customerType = 'webshop-p4m/update'; // customerType = 'webshop-p4m/update';
validateAddress = true; // validateAddress = true;
validateShippingAddress = true; // validateShippingAddress = true;
agbValidatorFns = [Validators.requiredTrue]; // agbValidatorFns = [Validators.requiredTrue];
birthDateValidatorFns = [Validators.required, this.minBirthDateValidator()]; // birthDateValidatorFns = [Validators.required, this.minBirthDateValidator()];
nameRequiredMarks: (keyof NameFormBlockData)[] = ['gender', 'firstName', 'lastName']; // nameRequiredMarks: (keyof NameFormBlockData)[] = ['gender', 'firstName', 'lastName'];
nameValidationFns: Record<keyof NameFormBlockData, ValidatorFn[]> = { // nameValidationFns: Record<keyof NameFormBlockData, ValidatorFn[]> = {
firstName: [Validators.required], // firstName: [Validators.required],
lastName: [Validators.required], // lastName: [Validators.required],
gender: [Validators.required], // gender: [Validators.required],
title: [], // title: [],
}; // };
addressRequiredMarks: (keyof AddressFormBlockData)[] = ['street', 'streetNumber', 'zipCode', 'city', 'country']; // addressRequiredMarks: (keyof AddressFormBlockData)[] = ['street', 'streetNumber', 'zipCode', 'city', 'country'];
addressValidatorFns: Record<string, ValidatorFn[]> = { // addressValidatorFns: Record<string, ValidatorFn[]> = {
street: [Validators.required], // street: [Validators.required],
streetNumber: [Validators.required], // streetNumber: [Validators.required],
zipCode: [Validators.required], // zipCode: [Validators.required],
city: [Validators.required], // city: [Validators.required],
country: [Validators.required], // country: [Validators.required],
}; // };
asyncLoyaltyCardValidatorFn: AsyncValidatorFn[] = [this.checkLoyalityCardValidator]; // asyncLoyaltyCardValidatorFn: AsyncValidatorFn[] = [this.checkLoyalityCardValidator];
get billingAddress(): PayerDTO | undefined { // get billingAddress(): PayerDTO | undefined {
const payers = this.formData?._meta?.customerDto?.payers; // const payers = this.formData?._meta?.customerDto?.payers;
if (!payers || payers.length === 0) { // if (!payers || payers.length === 0) {
return undefined; // return undefined;
} // }
// the default payer is the payer with the latest isDefault(Date) value // // the default payer is the payer with the latest isDefault(Date) value
const defaultPayer = payers.reduce((prev, curr) => // const defaultPayer = payers.reduce((prev, curr) =>
new Date(prev.isDefault) > new Date(curr.isDefault) ? prev : curr, // new Date(prev.isDefault) > new Date(curr.isDefault) ? prev : curr,
); // );
return defaultPayer.payer.data; // return defaultPayer.payer.data;
} // }
get shippingAddress() { // get shippingAddress() {
const shippingAddresses = this.formData?._meta?.customerDto?.shippingAddresses; // const shippingAddresses = this.formData?._meta?.customerDto?.shippingAddresses;
if (!shippingAddresses || shippingAddresses.length === 0) { // if (!shippingAddresses || shippingAddresses.length === 0) {
return undefined; // return undefined;
} // }
// the default shipping address is the shipping address with the latest isDefault(Date) value // // the default shipping address is the shipping address with the latest isDefault(Date) value
const defaultShippingAddress = shippingAddresses.reduce((prev, curr) => // const defaultShippingAddress = shippingAddresses.reduce((prev, curr) =>
new Date(prev.data.isDefault) > new Date(curr.data.isDefault) ? prev : curr, // new Date(prev.data.isDefault) > new Date(curr.data.isDefault) ? prev : curr,
); // );
return defaultShippingAddress.data; // return defaultShippingAddress.data;
} // }
ngOnInit() { // ngOnInit() {
super.ngOnInit(); // super.ngOnInit();
} // }
getInterests(): KeyValueDTOOfStringAndString[] { // getInterests(): KeyValueDTOOfStringAndString[] {
const interests: KeyValueDTOOfStringAndString[] = []; // const interests: KeyValueDTOOfStringAndString[] = [];
for (const key in this.formData.interests) { // for (const key in this.formData.interests) {
if (this.formData.interests[key]) { // if (this.formData.interests[key]) {
interests.push({ key, group: 'KUBI_INTERESSEN' }); // interests.push({ key, group: 'KUBI_INTERESSEN' });
} // }
} // }
return interests; // return interests;
} // }
getNewsletter(): KeyValueDTOOfStringAndString | undefined { // getNewsletter(): KeyValueDTOOfStringAndString | undefined {
if (this.formData.newsletter) { // if (this.formData.newsletter) {
return { key: 'kubi_newsletter', group: 'KUBI_NEWSLETTER' }; // return { key: 'kubi_newsletter', group: 'KUBI_NEWSLETTER' };
} // }
} // }
async saveCustomer(customer: CustomerDTO): Promise<CustomerDTO> { // async saveCustomer(customer: CustomerDTO): Promise<CustomerDTO> {
let res: Result<CustomerDTO>; // let res: Result<CustomerDTO>;
const { customerDto, customerInfoDto } = this.formData?._meta ?? {}; // const { customerDto, customerInfoDto } = this.formData?._meta ?? {};
if (customerDto) { // if (customerDto) {
customer = { ...customerDto, shippingAddresses: [], payers: [], ...customer }; // customer = { ...customerDto, shippingAddresses: [], payers: [], ...customer };
if (customerDto.shippingAddresses?.length) { // if (customerDto.shippingAddresses?.length) {
customer.shippingAddresses.unshift(...customerDto.shippingAddresses); // customer.shippingAddresses.unshift(...customerDto.shippingAddresses);
} // }
if (customerDto.payers?.length) { // if (customerDto.payers?.length) {
customer.payers.unshift(...customerDto.payers); // customer.payers.unshift(...customerDto.payers);
} // }
} else if (customerInfoDto) { // } else if (customerInfoDto) {
customer = { ...CreateP4MCustomerComponent.MapCustomerInfoDtoToCustomerDto(customerInfoDto), ...customer }; // customer = { ...CreateP4MCustomerComponent.MapCustomerInfoDtoToCustomerDto(customerInfoDto), ...customer };
} // }
const p4mFeature = customer.features?.find((attr) => attr.key === 'p4mUser'); // const p4mFeature = customer.features?.find((attr) => attr.key === 'p4mUser');
if (p4mFeature) { // if (p4mFeature) {
p4mFeature.value = this.formData.p4m; // p4mFeature.value = this.formData.p4m;
} else { // } else {
customer.features.push({ // customer.features.push({
key: 'p4mUser', // key: 'p4mUser',
value: this.formData.p4m, // value: this.formData.p4m,
}); // });
} // }
const interests = this.getInterests(); // const interests = this.getInterests();
if (interests.length > 0) { // if (interests.length > 0) {
customer.features?.push(...interests); // customer.features?.push(...interests);
// TODO: Klärung wie Interessen zukünftig gespeichert werden // // TODO: Klärung wie Interessen zukünftig gespeichert werden
// await this._loyaltyCardService // // await this._loyaltyCardService
// .LoyaltyCardSaveInteressen({ // // .LoyaltyCardSaveInteressen({
// customerId: res.result.id, // // customerId: res.result.id,
// interessen: this.getInterests(), // // interessen: this.getInterests(),
// }) // // })
// .toPromise(); // // .toPromise();
} // }
const newsletter = this.getNewsletter(); // const newsletter = this.getNewsletter();
if (newsletter) { // if (newsletter) {
customer.features.push(newsletter); // customer.features.push(newsletter);
} else { // } else {
customer.features = customer.features.filter( // customer.features = customer.features.filter(
(feature) => feature.key !== 'kubi_newsletter' && feature.group !== 'KUBI_NEWSLETTER', // (feature) => feature.key !== 'kubi_newsletter' && feature.group !== 'KUBI_NEWSLETTER',
); // );
} // }
res = await this.customerService.updateToP4MOnlineCustomer(customer); // res = await this.customerService.updateToP4MOnlineCustomer(customer);
return res.result; // return res.result;
} // }
} // }

View File

@@ -1,48 +1,48 @@
import { NgModule } from '@angular/core'; // import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common'; // import { CommonModule } from '@angular/common';
import { UpdateP4MWebshopCustomerComponent } from './update-p4m-webshop-customer.component'; // import { UpdateP4MWebshopCustomerComponent } from './update-p4m-webshop-customer.component';
import { // import {
AddressFormBlockModule, // AddressFormBlockModule,
BirthDateFormBlockModule, // BirthDateFormBlockModule,
InterestsFormBlockModule, // InterestsFormBlockModule,
NameFormBlockModule, // NameFormBlockModule,
OrganisationFormBlockModule, // OrganisationFormBlockModule,
P4mNumberFormBlockModule, // P4mNumberFormBlockModule,
NewsletterFormBlockModule, // NewsletterFormBlockModule,
DeviatingAddressFormBlockComponentModule, // DeviatingAddressFormBlockComponentModule,
AcceptAGBFormBlockModule, // AcceptAGBFormBlockModule,
EmailFormBlockModule, // EmailFormBlockModule,
PhoneNumbersFormBlockModule, // PhoneNumbersFormBlockModule,
} from '../../components/form-blocks'; // } from '../../components/form-blocks';
import { UiFormControlModule } from '@ui/form-control'; // import { UiFormControlModule } from '@ui/form-control';
import { UiInputModule } from '@ui/input'; // import { UiInputModule } from '@ui/input';
import { CustomerPipesModule } from '@shared/pipes/customer'; // import { CustomerPipesModule } from '@shared/pipes/customer';
import { CustomerTypeSelectorModule } from '../../components/customer-type-selector'; // import { CustomerTypeSelectorModule } from '../../components/customer-type-selector';
import { UiSpinnerModule } from '@ui/spinner'; // import { UiSpinnerModule } from '@ui/spinner';
@NgModule({ // @NgModule({
imports: [ // imports: [
CommonModule, // CommonModule,
CustomerTypeSelectorModule, // CustomerTypeSelectorModule,
AddressFormBlockModule, // AddressFormBlockModule,
BirthDateFormBlockModule, // BirthDateFormBlockModule,
InterestsFormBlockModule, // InterestsFormBlockModule,
NameFormBlockModule, // NameFormBlockModule,
OrganisationFormBlockModule, // OrganisationFormBlockModule,
P4mNumberFormBlockModule, // P4mNumberFormBlockModule,
NewsletterFormBlockModule, // NewsletterFormBlockModule,
DeviatingAddressFormBlockComponentModule, // DeviatingAddressFormBlockComponentModule,
AcceptAGBFormBlockModule, // AcceptAGBFormBlockModule,
EmailFormBlockModule, // EmailFormBlockModule,
PhoneNumbersFormBlockModule, // PhoneNumbersFormBlockModule,
UiFormControlModule, // UiFormControlModule,
UiInputModule, // UiInputModule,
CustomerPipesModule, // CustomerPipesModule,
UiSpinnerModule, // UiSpinnerModule,
], // ],
exports: [UpdateP4MWebshopCustomerComponent], // exports: [UpdateP4MWebshopCustomerComponent],
declarations: [UpdateP4MWebshopCustomerComponent], // declarations: [UpdateP4MWebshopCustomerComponent],
}) // })
export class UpdateP4MWebshopCustomerModule {} // export class UpdateP4MWebshopCustomerModule {}

View File

@@ -1,15 +1,33 @@
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, inject, effect, untracked } from '@angular/core'; import {
Component,
ChangeDetectionStrategy,
OnInit,
OnDestroy,
inject,
effect,
untracked,
} from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { BehaviorSubject, Subject, Subscription, fromEvent } from 'rxjs'; import {
BehaviorSubject,
Subject,
Subscription,
firstValueFrom,
fromEvent,
} from 'rxjs';
import { CustomerSearchStore } from './store/customer-search.store'; import { CustomerSearchStore } from './store/customer-search.store';
import { provideComponentStore } from '@ngrx/component-store'; import { provideComponentStore } from '@ngrx/component-store';
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb'; import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
import { delay, filter, first, switchMap, takeUntil } from 'rxjs/operators'; import { delay, filter, first, switchMap, takeUntil } from 'rxjs/operators';
import { CustomerCreateNavigation, CustomerSearchNavigation } from '@shared/services/navigation'; import {
CustomerCreateNavigation,
CustomerSearchNavigation,
} from '@shared/services/navigation';
import { CustomerSearchMainAutocompleteProvider } from './providers/customer-search-main-autocomplete.provider'; import { CustomerSearchMainAutocompleteProvider } from './providers/customer-search-main-autocomplete.provider';
import { FilterAutocompleteProvider } from '@shared/components/filter'; import { FilterAutocompleteProvider } from '@shared/components/filter';
import { toSignal } from '@angular/core/rxjs-interop'; import { toSignal } from '@angular/core/rxjs-interop';
import { provideCancelSearchSubject } from '@shared/services/cancel-subject'; import { provideCancelSearchSubject } from '@shared/services/cancel-subject';
import { injectFeedbackErrorDialog } from '@isa/ui/dialog';
@Component({ @Component({
selector: 'page-customer-search', selector: 'page-customer-search',
@@ -28,6 +46,7 @@ import { provideCancelSearchSubject } from '@shared/services/cancel-subject';
standalone: false, standalone: false,
}) })
export class CustomerSearchComponent implements OnInit, OnDestroy { export class CustomerSearchComponent implements OnInit, OnDestroy {
#errorFeedbackDialog = injectFeedbackErrorDialog();
private _store = inject(CustomerSearchStore); private _store = inject(CustomerSearchStore);
private _activatedRoute = inject(ActivatedRoute); private _activatedRoute = inject(ActivatedRoute);
private _router = inject(Router); private _router = inject(Router);
@@ -37,7 +56,11 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
private searchStore = inject(CustomerSearchStore); private searchStore = inject(CustomerSearchStore);
keyEscPressed = toSignal(fromEvent(document, 'keydown').pipe(filter((e: KeyboardEvent) => e.key === 'Escape'))); keyEscPressed = toSignal(
fromEvent(document, 'keydown').pipe(
filter((e: KeyboardEvent) => e.key === 'Escape'),
),
);
get breadcrumb() { get breadcrumb() {
let breadcrumb: string; let breadcrumb: string;
@@ -53,7 +76,9 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
private _breadcrumbs$ = this._store.processId$.pipe( private _breadcrumbs$ = this._store.processId$.pipe(
filter((id) => !!id), filter((id) => !!id),
switchMap((id) => this._breadcrumbService.getBreadcrumbsByKeyAndTag$(id, 'customer')), switchMap((id) =>
this._breadcrumbService.getBreadcrumbsByKeyAndTag$(id, 'customer'),
),
); );
side$ = new BehaviorSubject<string | undefined>(undefined); side$ = new BehaviorSubject<string | undefined>(undefined);
@@ -97,53 +122,77 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
this.checkDetailsBreadcrumb(); this.checkDetailsBreadcrumb();
}); });
this._eventsSubscription = this._router.events.pipe(takeUntil(this._onDestroy$)).subscribe((event) => { this._eventsSubscription = this._router.events
if (event instanceof NavigationEnd) {
this.checkAndUpdateProcessId();
this.checkAndUpdateSide();
this.checkAndUpdateCustomerId();
this.checkBreadcrumbs();
}
});
this._store.customerListResponse$
.pipe(takeUntil(this._onDestroy$)) .pipe(takeUntil(this._onDestroy$))
.subscribe(async ([response, filter, processId, restored, skipNavigation]) => { .subscribe((event) => {
if (this._store.processId === processId) { if (event instanceof NavigationEnd) {
if (skipNavigation) { this.checkAndUpdateProcessId();
return; this.checkAndUpdateSide();
} this.checkAndUpdateCustomerId();
if (response.hits === 1) {
// Navigate to details page
const customer = response.result[0];
if (customer.id < 0) {
// navigate to create customer
const route = this._createNavigation.upgradeCustomerRoute({ processId, customerInfo: customer });
await this._router.navigate(route.path, { queryParams: route.queryParams });
return;
} else {
const route = this._navigation.detailsRoute({ processId, customerId: customer.id });
await this._router.navigate(route.path, { queryParams: filter.getQueryParams() });
}
} else if (response.hits > 1) {
const route = this._navigation.listRoute({ processId, filter });
if (
(['details'].includes(this.breadcrumb) &&
response?.result?.some((c) => c.id === this._store.customerId)) ||
restored
) {
await this._router.navigate([], { queryParams: route.queryParams });
} else {
await this._router.navigate(route.path, { queryParams: route.queryParams });
}
}
this.checkBreadcrumbs(); this.checkBreadcrumbs();
} }
}); });
this._store.customerListResponse$
.pipe(takeUntil(this._onDestroy$))
.subscribe(
async ([response, filter, processId, restored, skipNavigation]) => {
if (this._store.processId === processId) {
if (skipNavigation) {
return;
}
if (response.hits === 1) {
// Navigate to details page
const customer = response.result[0];
if (customer.id < 0) {
// #5375 - Zusätzlich soll bei Kunden bei denen ein Upgrade möglich ist ein Dialog angezeigt werden, dass Kundenneuanlage mit Kundenkarte nicht möglich ist
await firstValueFrom(
this.#errorFeedbackDialog({
data: {
errorMessage:
'Kundenneuanlage mit Kundenkarte nicht möglich',
},
}).closed,
);
// navigate to create customer
// const route = this._createNavigation.upgradeCustomerRoute({ processId, customerInfo: customer });
// await this._router.navigate(route.path, { queryParams: route.queryParams });
return;
} else {
const route = this._navigation.detailsRoute({
processId,
customerId: customer.id,
});
await this._router.navigate(route.path, {
queryParams: filter.getQueryParams(),
});
}
} else if (response.hits > 1) {
const route = this._navigation.listRoute({ processId, filter });
if (
(['details'].includes(this.breadcrumb) &&
response?.result?.some(
(c) => c.id === this._store.customerId,
)) ||
restored
) {
await this._router.navigate([], {
queryParams: route.queryParams,
});
} else {
await this._router.navigate(route.path, {
queryParams: route.queryParams,
});
}
}
this.checkBreadcrumbs();
}
},
);
} }
ngOnDestroy(): void { ngOnDestroy(): void {
@@ -169,7 +218,11 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
this._store.setProcessId(processId); this._store.setProcessId(processId);
this._store.reset(this._activatedRoute.snapshot.queryParams); this._store.reset(this._activatedRoute.snapshot.queryParams);
if (!['main', 'filter'].some((s) => s === this.breadcrumb)) { if (!['main', 'filter'].some((s) => s === this.breadcrumb)) {
const skipNavigation = ['orders', 'order-details', 'order-details-history'].includes(this.breadcrumb); const skipNavigation = [
'orders',
'order-details',
'order-details-history',
].includes(this.breadcrumb);
this._store.search({ skipNavigation }); this._store.search({ skipNavigation });
} }
} }
@@ -229,7 +282,9 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
const mainBreadcrumb = await this.getMainBreadcrumb(); const mainBreadcrumb = await this.getMainBreadcrumb();
if (!mainBreadcrumb) { if (!mainBreadcrumb) {
const navigation = this._navigation.defaultRoute({ processId: this._store.processId }); const navigation = this._navigation.defaultRoute({
processId: this._store.processId,
});
const breadcrumb: Breadcrumb = { const breadcrumb: Breadcrumb = {
key: this._store.processId, key: this._store.processId,
tags: ['customer', 'search', 'main'], tags: ['customer', 'search', 'main'],
@@ -242,14 +297,19 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
this._breadcrumbService.addBreadcrumb(breadcrumb); this._breadcrumbService.addBreadcrumb(breadcrumb);
} else { } else {
this._breadcrumbService.patchBreadcrumb(mainBreadcrumb.id, { this._breadcrumbService.patchBreadcrumb(mainBreadcrumb.id, {
params: { ...this.snapshot.queryParams, ...(mainBreadcrumb.params ?? {}) }, params: {
...this.snapshot.queryParams,
...(mainBreadcrumb.params ?? {}),
},
}); });
} }
} }
async getCreateCustomerBreadcrumb(): Promise<Breadcrumb | undefined> { async getCreateCustomerBreadcrumb(): Promise<Breadcrumb | undefined> {
const breadcrumbs = await this.getBreadcrumbs(); const breadcrumbs = await this.getBreadcrumbs();
return breadcrumbs.find((b) => b.tags.includes('create') && b.tags.includes('customer')); return breadcrumbs.find(
(b) => b.tags.includes('create') && b.tags.includes('customer'),
);
} }
async checkCreateCustomerBreadcrumb() { async checkCreateCustomerBreadcrumb() {
@@ -262,7 +322,9 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
async getSearchBreadcrumb(): Promise<Breadcrumb | undefined> { async getSearchBreadcrumb(): Promise<Breadcrumb | undefined> {
const breadcrumbs = await this.getBreadcrumbs(); const breadcrumbs = await this.getBreadcrumbs();
return breadcrumbs.find((b) => b.tags.includes('list') && b.tags.includes('search')); return breadcrumbs.find(
(b) => b.tags.includes('list') && b.tags.includes('search'),
);
} }
async checkSearchBreadcrumb() { async checkSearchBreadcrumb() {
@@ -288,7 +350,9 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
const name = this._store.queryParams?.main_qs || 'Suche'; const name = this._store.queryParams?.main_qs || 'Suche';
if (!searchBreadcrumb) { if (!searchBreadcrumb) {
const navigation = this._navigation.listRoute({ processId: this._store.processId }); const navigation = this._navigation.listRoute({
processId: this._store.processId,
});
const breadcrumb: Breadcrumb = { const breadcrumb: Breadcrumb = {
key: this._store.processId, key: this._store.processId,
tags: ['customer', 'search', 'list'], tags: ['customer', 'search', 'list'],
@@ -300,7 +364,10 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
this._breadcrumbService.addBreadcrumb(breadcrumb); this._breadcrumbService.addBreadcrumb(breadcrumb);
} else { } else {
this._breadcrumbService.patchBreadcrumb(searchBreadcrumb.id, { params: this.snapshot.queryParams, name }); this._breadcrumbService.patchBreadcrumb(searchBreadcrumb.id, {
params: this.snapshot.queryParams,
name,
});
} }
} else { } else {
if (searchBreadcrumb) { if (searchBreadcrumb) {
@@ -311,7 +378,9 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
async getDetailsBreadcrumb(): Promise<Breadcrumb | undefined> { async getDetailsBreadcrumb(): Promise<Breadcrumb | undefined> {
const breadcrumbs = await this.getBreadcrumbs(); const breadcrumbs = await this.getBreadcrumbs();
return breadcrumbs.find((b) => b.tags.includes('details') && b.tags.includes('search')); return breadcrumbs.find(
(b) => b.tags.includes('details') && b.tags.includes('search'),
);
} }
async checkDetailsBreadcrumb() { async checkDetailsBreadcrumb() {
@@ -333,7 +402,8 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
].includes(this.breadcrumb) ].includes(this.breadcrumb)
) { ) {
const customer = this._store.customer; const customer = this._store.customer;
const fullName = `${customer?.firstName ?? ''} ${customer?.lastName ?? ''}`.trim(); const fullName =
`${customer?.firstName ?? ''} ${customer?.lastName ?? ''}`.trim();
if (!detailsBreadcrumb) { if (!detailsBreadcrumb) {
const navigation = this._navigation.detailsRoute({ const navigation = this._navigation.detailsRoute({
@@ -515,7 +585,10 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
async checkOrderDetailsBreadcrumb() { async checkOrderDetailsBreadcrumb() {
const orderDetailsBreadcrumb = await this.getOrderDetailsBreadcrumb(); const orderDetailsBreadcrumb = await this.getOrderDetailsBreadcrumb();
if (this.breadcrumb === 'order-details' || this.breadcrumb === 'order-details-history') { if (
this.breadcrumb === 'order-details' ||
this.breadcrumb === 'order-details-history'
) {
if (!orderDetailsBreadcrumb) { if (!orderDetailsBreadcrumb) {
const navigation = this._navigation.orderDetialsRoute({ const navigation = this._navigation.orderDetialsRoute({
processId: this._store.processId, processId: this._store.processId,
@@ -546,7 +619,8 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
} }
async checkOrderDetailsHistoryBreadcrumb() { async checkOrderDetailsHistoryBreadcrumb() {
const orderDetailsHistoryBreadcrumb = await this.getOrderDetailsHistoryBreadcrumb(); const orderDetailsHistoryBreadcrumb =
await this.getOrderDetailsHistoryBreadcrumb();
if (this.breadcrumb === 'order-details-history') { if (this.breadcrumb === 'order-details-history') {
if (!orderDetailsHistoryBreadcrumb) { if (!orderDetailsHistoryBreadcrumb) {
@@ -569,7 +643,9 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
this._breadcrumbService.addBreadcrumb(breadcrumb); this._breadcrumbService.addBreadcrumb(breadcrumb);
} }
} else if (orderDetailsHistoryBreadcrumb) { } else if (orderDetailsHistoryBreadcrumb) {
this._breadcrumbService.removeBreadcrumb(orderDetailsHistoryBreadcrumb.id); this._breadcrumbService.removeBreadcrumb(
orderDetailsHistoryBreadcrumb.id,
);
} }
} }

View File

@@ -1,5 +1,10 @@
import { inject, Injectable } from '@angular/core'; import { inject, Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Params, Router, RouterStateSnapshot } from '@angular/router'; import {
ActivatedRouteSnapshot,
Params,
Router,
RouterStateSnapshot,
} from '@angular/router';
import { DomainCheckoutService } from '@domain/checkout'; import { DomainCheckoutService } from '@domain/checkout';
import { CustomerCreateFormData, decodeFormData } from '../create-customer'; import { CustomerCreateFormData, decodeFormData } from '../create-customer';
import { CustomerCreateNavigation } from '@shared/services/navigation'; import { CustomerCreateNavigation } from '@shared/services/navigation';
@@ -9,7 +14,10 @@ export class CustomerCreateGuard {
private checkoutService = inject(DomainCheckoutService); private checkoutService = inject(DomainCheckoutService);
private customerCreateNavigation = inject(CustomerCreateNavigation); private customerCreateNavigation = inject(CustomerCreateNavigation);
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> { async canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot,
): Promise<boolean> {
// exit with true if canActivateChild will be called // exit with true if canActivateChild will be called
if (route.firstChild) { if (route.firstChild) {
return true; return true;
@@ -19,10 +27,15 @@ export class CustomerCreateGuard {
const processId = this.getProcessId(route); const processId = this.getProcessId(route);
const formData = this.getFormData(route); const formData = this.getFormData(route);
const canActivateCustomerType = await this.setableCustomerTypes(processId, formData); const canActivateCustomerType = await this.setableCustomerTypes(
processId,
formData,
);
if (canActivateCustomerType[customerType] !== true) { if (canActivateCustomerType[customerType] !== true) {
customerType = Object.keys(canActivateCustomerType).find((key) => canActivateCustomerType[key]); customerType = Object.keys(canActivateCustomerType).find(
(key) => canActivateCustomerType[key],
);
} }
await this.navigate(processId, customerType, route.queryParams); await this.navigate(processId, customerType, route.queryParams);
@@ -30,9 +43,14 @@ export class CustomerCreateGuard {
return true; return true;
} }
async canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> { async canActivateChild(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot,
): Promise<boolean> {
const processId = this.getProcessId(route); const processId = this.getProcessId(route);
const customerType = route.routeConfig.path?.replace('create/', '')?.replace('/update', ''); const customerType = route.routeConfig.path
?.replace('create/', '')
?.replace('/update', '');
if (customerType === 'create-customer-main') { if (customerType === 'create-customer-main') {
return true; return true;
@@ -40,29 +58,39 @@ export class CustomerCreateGuard {
const formData = this.getFormData(route); const formData = this.getFormData(route);
const canActivateCustomerType = await this.setableCustomerTypes(processId, formData); const canActivateCustomerType = await this.setableCustomerTypes(
processId,
formData,
);
if (canActivateCustomerType[customerType]) { if (canActivateCustomerType[customerType]) {
return true; return true;
} }
const activatableCustomerType = Object.keys(canActivateCustomerType)?.find((key) => canActivateCustomerType[key]); const activatableCustomerType = Object.keys(canActivateCustomerType)?.find(
(key) => canActivateCustomerType[key],
);
await this.navigate(processId, activatableCustomerType, route.queryParams); await this.navigate(processId, activatableCustomerType, route.queryParams);
return false; return false;
} }
async setableCustomerTypes(processId: number, formData: CustomerCreateFormData): Promise<Record<string, boolean>> { async setableCustomerTypes(
const res = await this.checkoutService.getSetableCustomerTypes(processId).toPromise(); processId: number,
formData: CustomerCreateFormData,
): Promise<Record<string, boolean>> {
const res = await this.checkoutService
.getSetableCustomerTypes(processId)
.toPromise();
if (res.store) { // if (res.store) {
res['store-p4m'] = true; // res['store-p4m'] = true;
} // }
if (res.webshop) { // if (res.webshop) {
res['webshop-p4m'] = true; // res['webshop-p4m'] = true;
} // }
if (formData?._meta) { if (formData?._meta) {
const customerType = formData._meta.customerType; const customerType = formData._meta.customerType;
@@ -107,7 +135,11 @@ export class CustomerCreateGuard {
return {}; return {};
} }
navigate(processId: number, customerType: string, queryParams: Params): Promise<boolean> { navigate(
processId: number,
customerType: string,
queryParams: Params,
): Promise<boolean> {
const path = this.customerCreateNavigation.createCustomerRoute({ const path = this.customerCreateNavigation.createCustomerRoute({
customerType, customerType,
processId, processId,

View File

@@ -31,7 +31,9 @@ export class CantAddCustomerToCartModalComponent {
get option() { get option() {
return ( return (
this.ref.data.upgradeableTo?.options.values.find((upgradeOption) => this.ref.data.upgradeableTo?.options.values.find((upgradeOption) =>
this.ref.data.required.options.values.some((requiredOption) => upgradeOption.key === requiredOption.key), this.ref.data.required.options.values.some(
(requiredOption) => upgradeOption.key === requiredOption.key,
),
) || { value: this.queryParams } ) || { value: this.queryParams }
); );
} }
@@ -39,7 +41,9 @@ export class CantAddCustomerToCartModalComponent {
get queryParams() { get queryParams() {
let option = this.ref.data.required?.options.values.find((f) => f.selected); let option = this.ref.data.required?.options.values.find((f) => f.selected);
if (!option) { if (!option) {
option = this.ref.data.required?.options.values.find((f) => (isBoolean(f.enabled) ? f.enabled : true)); option = this.ref.data.required?.options.values.find((f) =>
isBoolean(f.enabled) ? f.enabled : true,
);
} }
return option ? { customertype: option.value } : {}; return option ? { customertype: option.value } : {};
} }
@@ -57,27 +61,29 @@ export class CantAddCustomerToCartModalComponent {
const queryParams: Record<string, string> = {}; const queryParams: Record<string, string> = {};
if (customer) { if (customer) {
queryParams['formData'] = encodeFormData(mapCustomerDtoToCustomerCreateFormData(customer)); queryParams['formData'] = encodeFormData(
mapCustomerDtoToCustomerCreateFormData(customer),
);
} }
if (option === 'webshop' && attributes.some((a) => a.key === 'p4mUser')) { // if (option === 'webshop' && attributes.some((a) => a.key === 'p4mUser')) {
const nav = this.customerCreateNavigation.createCustomerRoute({ // const nav = this.customerCreateNavigation.createCustomerRoute({
processId: this.applicationService.activatedProcessId, // processId: this.applicationService.activatedProcessId,
customerType: 'webshop-p4m', // customerType: 'webshop-p4m',
}); // });
this.router.navigate(nav.path, { // this.router.navigate(nav.path, {
queryParams: { ...nav.queryParams, ...queryParams }, // queryParams: { ...nav.queryParams, ...queryParams },
}); // });
} else { // } else {
const nav = this.customerCreateNavigation.createCustomerRoute({ const nav = this.customerCreateNavigation.createCustomerRoute({
processId: this.applicationService.activatedProcessId, processId: this.applicationService.activatedProcessId,
customerType: option as any, customerType: option as any,
}); });
this.router.navigate(nav.path, { this.router.navigate(nav.path, {
queryParams: { ...nav.queryParams, ...queryParams }, queryParams: { ...nav.queryParams, ...queryParams },
}); });
} // }
this.ref.close(); this.ref.close();
} }

View File

@@ -1,7 +1,11 @@
<div class="font-bold text-center border-t border-b border-solid border-disabled-customer -mx-4 py-4"> <div
class="font-bold text-center border-t border-b border-solid border-disabled-customer -mx-4 py-4"
>
{{ customer?.communicationDetails?.email }} {{ customer?.communicationDetails?.email }}
</div> </div>
<div class="grid grid-flow-row gap-1 text-sm font-bold border-b border-solid border-disabled-customer -mx-4 py-4 px-14"> <div
class="grid grid-flow-row gap-1 text-sm font-bold border-b border-solid border-disabled-customer -mx-4 py-4 px-14"
>
@if (customer?.organisation?.name) { @if (customer?.organisation?.name) {
<span>{{ customer?.organisation?.name }}</span> <span>{{ customer?.organisation?.name }}</span>
} }
@@ -16,23 +20,26 @@
</div> </div>
<div class="grid grid-flow-col gap-4 justify-around mt-12"> <div class="grid grid-flow-col gap-4 justify-around mt-12">
<button class="border-2 border-solid border-brand rounded-full font-bold text-brand px-6 py-3 text-lg" (click)="close(false)"> <button
class="border-2 border-solid border-brand rounded-full font-bold text-brand px-6 py-3 text-lg"
(click)="close(false)"
>
neues Onlinekonto anlegen neues Onlinekonto anlegen
</button> </button>
@if (!isWebshopWithP4M) { @if (!isWebshopWithP4M) {
<button <button
class="border-2 border-solid border-brand rounded-full font-bold text-white px-6 py-3 text-lg bg-brand" class="border-2 border-solid border-brand rounded-full font-bold text-white px-6 py-3 text-lg bg-brand"
(click)="close(true)" (click)="close(true)"
> >
Daten übernehmen Daten übernehmen
</button> </button>
} }
@if (isWebshopWithP4M) { <!-- @if (isWebshopWithP4M) {
<button <button
class="border-2 border-solid border-brand rounded-full font-bold text-white px-6 py-3 text-lg bg-brand" class="border-2 border-solid border-brand rounded-full font-bold text-white px-6 py-3 text-lg bg-brand"
(click)="selectCustomer()" (click)="selectCustomer()"
> >
Datensatz auswählen Datensatz auswählen
</button> </button>
} } -->
</div> </div>

View File

@@ -9,11 +9,11 @@ import { CustomerCreateGuard } from './guards/customer-create.guard';
import { import {
CreateB2BCustomerComponent, CreateB2BCustomerComponent,
CreateGuestCustomerComponent, CreateGuestCustomerComponent,
CreateP4MCustomerComponent, // CreateP4MCustomerComponent,
CreateStoreCustomerComponent, CreateStoreCustomerComponent,
CreateWebshopCustomerComponent, CreateWebshopCustomerComponent,
} from './create-customer'; } from './create-customer';
import { UpdateP4MWebshopCustomerComponent } from './create-customer/update-p4m-webshop-customer'; // import { UpdateP4MWebshopCustomerComponent } from './create-customer/update-p4m-webshop-customer';
import { CreateCustomerComponent } from './create-customer/create-customer.component'; import { CreateCustomerComponent } from './create-customer/create-customer.component';
import { CustomerDataEditB2BComponent } from './customer-search/edit-main-view/customer-data-edit-b2b.component'; import { CustomerDataEditB2BComponent } from './customer-search/edit-main-view/customer-data-edit-b2b.component';
import { CustomerDataEditB2CComponent } from './customer-search/edit-main-view/customer-data-edit-b2c.component'; import { CustomerDataEditB2CComponent } from './customer-search/edit-main-view/customer-data-edit-b2c.component';
@@ -40,8 +40,16 @@ export const routes: Routes = [
path: '', path: '',
component: CustomerSearchComponent, component: CustomerSearchComponent,
children: [ children: [
{ path: 'search', component: CustomerMainViewComponent, data: { side: 'main', breadcrumb: 'main' } }, {
{ path: 'search/list', component: CustomerResultsMainViewComponent, data: { breadcrumb: 'search' } }, path: 'search',
component: CustomerMainViewComponent,
data: { side: 'main', breadcrumb: 'main' },
},
{
path: 'search/list',
component: CustomerResultsMainViewComponent,
data: { breadcrumb: 'search' },
},
{ {
path: 'search/filter', path: 'search/filter',
component: CustomerFilterMainViewComponent, component: CustomerFilterMainViewComponent,
@@ -80,7 +88,10 @@ export const routes: Routes = [
{ {
path: 'search/:customerId/orders/:orderId/:orderItemId/history', path: 'search/:customerId/orders/:orderId/:orderItemId/history',
component: CustomerOrderDetailsHistoryMainViewComponent, component: CustomerOrderDetailsHistoryMainViewComponent,
data: { side: 'order-details', breadcrumb: 'order-details-history' }, data: {
side: 'order-details',
breadcrumb: 'order-details-history',
},
}, },
{ {
path: 'search/:customerId/edit/b2b', path: 'search/:customerId/edit/b2b',
@@ -140,13 +151,13 @@ export const routes: Routes = [
{ path: 'create/webshop', component: CreateWebshopCustomerComponent }, { path: 'create/webshop', component: CreateWebshopCustomerComponent },
{ path: 'create/b2b', component: CreateB2BCustomerComponent }, { path: 'create/b2b', component: CreateB2BCustomerComponent },
{ path: 'create/guest', component: CreateGuestCustomerComponent }, { path: 'create/guest', component: CreateGuestCustomerComponent },
{ path: 'create/webshop-p4m', component: CreateP4MCustomerComponent, data: { customerType: 'webshop' } }, // { path: 'create/webshop-p4m', component: CreateP4MCustomerComponent, data: { customerType: 'webshop' } },
{ path: 'create/store-p4m', component: CreateP4MCustomerComponent, data: { customerType: 'store' } }, // { path: 'create/store-p4m', component: CreateP4MCustomerComponent, data: { customerType: 'store' } },
{ // {
path: 'create/webshop-p4m/update', // path: 'create/webshop-p4m/update',
component: UpdateP4MWebshopCustomerComponent, // component: UpdateP4MWebshopCustomerComponent,
data: { customerType: 'webshop' }, // data: { customerType: 'webshop' },
}, // },
{ {
path: 'create-customer-main', path: 'create-customer-main',
outlet: 'side', outlet: 'side',

View File

@@ -3,7 +3,10 @@ import { Injectable } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { CustomerInfoDTO } from '@generated/swagger/crm-api'; import { CustomerInfoDTO } from '@generated/swagger/crm-api';
import { NavigationRoute } from './defs/navigation-route'; import { NavigationRoute } from './defs/navigation-route';
import { encodeFormData, mapCustomerInfoDtoToCustomerCreateFormData } from 'apps/isa-app/src/page/customer'; import {
encodeFormData,
mapCustomerInfoDtoToCustomerCreateFormData,
} from 'apps/isa-app/src/page/customer';
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class CustomerCreateNavigation { export class CustomerCreateNavigation {
@@ -33,7 +36,9 @@ export class CustomerCreateNavigation {
navigateToDefault(params: { processId: NumberInput }): Promise<boolean> { navigateToDefault(params: { processId: NumberInput }): Promise<boolean> {
const route = this.defaultRoute(params); const route = this.defaultRoute(params);
return this._router.navigate(route.path, { queryParams: route.queryParams }); return this._router.navigate(route.path, {
queryParams: route.queryParams,
});
} }
createCustomerRoute(params: { createCustomerRoute(params: {
@@ -54,7 +59,9 @@ export class CustomerCreateNavigation {
]; ];
let formData = params?.customerInfo let formData = params?.customerInfo
? encodeFormData(mapCustomerInfoDtoToCustomerCreateFormData(params.customerInfo)) ? encodeFormData(
mapCustomerInfoDtoToCustomerCreateFormData(params.customerInfo),
)
: undefined; : undefined;
const urlTree = this._router.createUrlTree(path, { const urlTree = this._router.createUrlTree(path, {
@@ -79,7 +86,9 @@ export class CustomerCreateNavigation {
processId: NumberInput; processId: NumberInput;
customerInfo: CustomerInfoDTO; customerInfo: CustomerInfoDTO;
}): NavigationRoute { }): NavigationRoute {
const formData = encodeFormData(mapCustomerInfoDtoToCustomerCreateFormData(customerInfo)); const formData = encodeFormData(
mapCustomerInfoDtoToCustomerCreateFormData(customerInfo),
);
const path = [ const path = [
'/kunde', '/kunde',
coerceNumberProperty(processId), coerceNumberProperty(processId),
@@ -88,14 +97,16 @@ export class CustomerCreateNavigation {
outlets: { outlets: {
primary: [ primary: [
'create', 'create',
customerInfo?.features?.find((feature) => feature.key === 'webshop') ? 'webshop-p4m' : 'store-p4m', // customerInfo?.features?.find((feature) => feature.key === 'webshop') ? 'webshop-p4m' : 'store-p4m',
], ],
side: 'create-customer-main', side: 'create-customer-main',
}, },
}, },
]; ];
const urlTree = this._router.createUrlTree(path, { queryParams: { formData } }); const urlTree = this._router.createUrlTree(path, {
queryParams: { formData },
});
return { return {
path, path,