mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
ANlage und bearbeiten von Adressen
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<span class="text-[22px] font-bold"> {{ customer?.lastName }} {{ customer?.firstName }} </span>
|
||||
<span class="text-[22px] font-bold"> {{ customerName }} </span>
|
||||
<div>
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-row items-center">
|
||||
|
||||
@@ -15,5 +15,19 @@ export class CustomerResultListItemFullComponent {
|
||||
@Input()
|
||||
customer: CustomerInfoDTO;
|
||||
|
||||
get customerName() {
|
||||
if (!this.customer) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const isB2b = this.customer.features?.some((f) => f.key === 'b2b') && this.customer.organisation?.name;
|
||||
|
||||
if (!isB2b) {
|
||||
return `${this.customer.lastName} ${this.customer.firstName}`;
|
||||
} else {
|
||||
return `${this.customer.organisation.name}`;
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col justify-between grow">
|
||||
<span class="text-[22px] font-bold"> {{ customer?.lastName }} {{ customer?.firstName }} </span>
|
||||
<span class="text-[22px] font-bold"> {{ customerName }} </span>
|
||||
<div>
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-row items-center">
|
||||
|
||||
@@ -15,5 +15,19 @@ export class CustomerResultListItemComponent {
|
||||
@Input()
|
||||
customer: CustomerInfoDTO;
|
||||
|
||||
get customerName() {
|
||||
if (!this.customer) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const isB2b = this.customer.features?.some((f) => f.key === 'b2b') && this.customer.organisation?.name;
|
||||
|
||||
if (!isB2b) {
|
||||
return `${this.customer.lastName} ${this.customer.firstName}`;
|
||||
} else {
|
||||
return `${this.customer.organisation.name}`;
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Component, ChangeDetectionStrategy, ViewChild } from '@angular/core';
|
||||
import { ValidatorFn, Validators } from '@angular/forms';
|
||||
import { CustomerDTO } from '@swagger/crm';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { DeviatingAddressFormBlockComponent } from '../../components/form-blocks';
|
||||
import { AddressFormBlockComponent, AddressFormBlockData } from '../../components/form-blocks/address';
|
||||
import { NameFormBlockData } from '../../components/form-blocks/name/name-form-block-data';
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<shared-breadcrumb [key]="processId$ | async" [tags]="['customer']" class="mb-9"></shared-breadcrumb>
|
||||
<shared-breadcrumb [key]="processId$ | async" [tags]="['customer']" class="mb-3"></shared-breadcrumb>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
:host {
|
||||
@apply block bg-surface text-surface-content rounded px-6 py-8;
|
||||
}
|
||||
|
||||
form {
|
||||
@apply grid grid-cols-2 gap-x-8;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<h1 class="text-2xl text-center font-bold mb-6">Rechnungsadresse hinzufügen</h1>
|
||||
|
||||
<form [formGroup]="formGroup" (ngSubmit)="save()">
|
||||
<shared-form-control label="Anrede">
|
||||
<shared-select formControlName="gender" placeholder="Anrede" tabindex="1" [autofocus]="true">
|
||||
<shared-select-option [value]="2">Herr</shared-select-option>
|
||||
<shared-select-option [value]="4">Frau</shared-select-option>
|
||||
</shared-select>
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Titel">
|
||||
<shared-select formControlName="title" placeholder="Titel" tabindex="2">
|
||||
<shared-select-option value="Dipl.-Ing.">Dipl.-Ing.</shared-select-option>
|
||||
<shared-select-option value="Dr.">Dr.</shared-select-option>
|
||||
<shared-select-option value="Dr. med.">Dr. med.</shared-select-option>
|
||||
<shared-select-option value="Prof.">Prof.</shared-select-option>
|
||||
<shared-select-option value="Prof. Dr.">Prof. Dr.</shared-select-option>
|
||||
<shared-select-option value="RA">RA</shared-select-option>
|
||||
</shared-select>
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Nachname">
|
||||
<input class="input-control" placeholder="Nachname" type="text" formControlName="lastName" tabindex="3" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Vorname">
|
||||
<input class="input-control" placeholder="Vorname" type="text" formControlName="firstName" tabindex="4" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Firma" class="col-span-2">
|
||||
<input class="input-control" placeholder="Firma" type="text" formControlName="organisation" tabindex="5" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Straße">
|
||||
<input class="input-control" placeholder="Straße" type="text" formControlName="street" tabindex="6" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Hausnummer">
|
||||
<input class="input-control" placeholder="Hausnummer" type="text" formControlName="streetNumber" tabindex="7" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="PLZ">
|
||||
<input class="input-control" placeholder="PLZ" type="text" formControlName="zipCode" tabindex="8" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Ort">
|
||||
<input class="input-control" placeholder="Ort" type="text" formControlName="city" tabindex="9" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Adresszusatz" class="col-span-2">
|
||||
<input class="input-control" placeholder="Adresszusatz" type="text" formControlName="info" tabindex="10" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control class="col-span-2" label="Land">
|
||||
<shared-select placeholder="Land" formControlName="country" tabindex="11">
|
||||
<shared-select-option *ngFor="let country of countries$ | async" [value]="country.isO3166_A_3">
|
||||
{{ country.name }}
|
||||
</shared-select-option>
|
||||
</shared-select>
|
||||
</shared-form-control>
|
||||
|
||||
<div class="text-center col-span-2">
|
||||
<shared-checkbox>Diese Rechnungsadresse als Standard Adresse festlegen</shared-checkbox>
|
||||
</div>
|
||||
<div class="mt-6 text-center col-span-2">
|
||||
<button
|
||||
[disabled]="formGroup.invalid || formGroup.disabled"
|
||||
type="submit"
|
||||
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white"
|
||||
>
|
||||
Speichern
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -0,0 +1,91 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { CheckboxComponent } from '@shared/components/checkbox';
|
||||
import { FormControl, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
||||
import { SelectModule } from '@shared/components/select';
|
||||
import { FormControlComponent } from '@shared/components/form-control';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
import { AddressDTO, Gender, PayerDTO } from '@swagger/crm';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { AsyncPipe, NgForOf } from '@angular/common';
|
||||
import { AddressSelectionModalService } from '@shared/modals/address-selection-modal';
|
||||
import { CustomerSearchStore } from '../store';
|
||||
import { CustomerSearchNavigation } from '../../navigations';
|
||||
|
||||
@Component({
|
||||
selector: 'page-add-billing-address-main-view',
|
||||
templateUrl: 'add-billing-address-main-view.component.html',
|
||||
styleUrls: ['add-billing-address-main-view.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: { class: 'page-add-billing-address-main-view' },
|
||||
standalone: true,
|
||||
imports: [AsyncPipe, NgForOf, ReactiveFormsModule, SelectModule, FormControlComponent, CheckboxComponent],
|
||||
})
|
||||
export class AddBillingAddressMainViewComponent {
|
||||
formGroup = new FormGroup({
|
||||
gender: new FormControl<Gender>(0, [Validators.required, Validators.min(1)]),
|
||||
title: new FormControl<string>(undefined),
|
||||
firstName: new FormControl<string>(undefined, [Validators.required]),
|
||||
lastName: new FormControl<string>(undefined, [Validators.required]),
|
||||
organisation: new FormControl<string>(undefined),
|
||||
street: new FormControl<string>(undefined, [Validators.required]),
|
||||
streetNumber: new FormControl<string>(undefined, [Validators.required]),
|
||||
zipCode: new FormControl<string>(undefined, [Validators.required]),
|
||||
city: new FormControl<string>(undefined, [Validators.required]),
|
||||
country: new FormControl<string>('DEU', [Validators.required]),
|
||||
info: new FormControl<string>(undefined),
|
||||
isDefault: new FormControl<boolean>(false),
|
||||
});
|
||||
|
||||
countries$ = this._customerService.getCountries().pipe(map((res) => res.result));
|
||||
|
||||
constructor(
|
||||
private _customerService: CrmCustomerService,
|
||||
private _addressSelection: AddressSelectionModalService,
|
||||
private _store: CustomerSearchStore,
|
||||
private _navigation: CustomerSearchNavigation
|
||||
) {}
|
||||
|
||||
async save() {
|
||||
if (this.formGroup.invalid) {
|
||||
this.formGroup.markAllAsTouched();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.formGroup.disable();
|
||||
|
||||
const formData = this.formGroup.value;
|
||||
|
||||
const address: AddressDTO = {
|
||||
street: formData.street,
|
||||
streetNumber: formData.streetNumber,
|
||||
zipCode: formData.zipCode,
|
||||
city: formData.city,
|
||||
country: formData.country,
|
||||
info: formData.info,
|
||||
};
|
||||
|
||||
const addressValidationResult = await this._addressSelection.validateAddress(address);
|
||||
|
||||
if (addressValidationResult === undefined) {
|
||||
this.formGroup.enable();
|
||||
return;
|
||||
}
|
||||
|
||||
const payer: PayerDTO = {
|
||||
gender: formData.gender,
|
||||
title: formData.title,
|
||||
firstName: formData.firstName,
|
||||
lastName: formData.lastName,
|
||||
organisation: formData.organisation ? { name: formData.organisation } : undefined,
|
||||
address: addressValidationResult,
|
||||
};
|
||||
|
||||
const result = await this._customerService.createPayer(this._store.customerId, payer, formData.isDefault);
|
||||
|
||||
this._navigation.navigateToDetails({ processId: this._store.processId, customerId: this._store.customerId });
|
||||
} catch (error) {
|
||||
this.formGroup.enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
:host {
|
||||
@apply block bg-surface text-surface-content rounded px-6 py-8;
|
||||
}
|
||||
|
||||
form {
|
||||
@apply grid grid-cols-2 gap-x-8;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<h1 class="text-2xl text-center font-bold mb-6">Lieferadresse hinzufügen</h1>
|
||||
|
||||
<form [formGroup]="formGroup" (ngSubmit)="save()">
|
||||
<ng-container *ngIf="isBusinessKonto$ | async">
|
||||
<shared-form-control label="Firma" class="col-span-2">
|
||||
<input class="input-control" placeholder="Firma" type="text" formControlName="organisation" tabindex="1" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Abteilung">
|
||||
<input class="input-control" placeholder="Abteilung" type="text" formControlName="department" tabindex="2" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="USt-ID">
|
||||
<input class="input-control" placeholder="Abteilung" type="text" formControlName="vatId" tabindex="3" />
|
||||
</shared-form-control>
|
||||
</ng-container>
|
||||
|
||||
<shared-form-control label="Anrede">
|
||||
<shared-select formControlName="gender" placeholder="Anrede" tabindex="4" [autofocus]="true">
|
||||
<shared-select-option [value]="2">Herr</shared-select-option>
|
||||
<shared-select-option [value]="4">Frau</shared-select-option>
|
||||
</shared-select>
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Titel">
|
||||
<shared-select formControlName="title" placeholder="Titel" tabindex="5">
|
||||
<shared-select-option value="Dipl.-Ing.">Dipl.-Ing.</shared-select-option>
|
||||
<shared-select-option value="Dr.">Dr.</shared-select-option>
|
||||
<shared-select-option value="Dr. med.">Dr. med.</shared-select-option>
|
||||
<shared-select-option value="Prof.">Prof.</shared-select-option>
|
||||
<shared-select-option value="Prof. Dr.">Prof. Dr.</shared-select-option>
|
||||
<shared-select-option value="RA">RA</shared-select-option>
|
||||
</shared-select>
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Nachname">
|
||||
<input class="input-control" placeholder="Nachname" type="text" formControlName="lastName" tabindex="6" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Vorname">
|
||||
<input class="input-control" placeholder="Vorname" type="text" formControlName="firstName" tabindex="7" />
|
||||
</shared-form-control>
|
||||
|
||||
<ng-container *ngIf="!(isBusinessKonto$ | async)">
|
||||
<shared-form-control label="Firma" class="col-span-2">
|
||||
<input class="input-control" placeholder="Firma" type="text" formControlName="organisation" tabindex="8" />
|
||||
</shared-form-control>
|
||||
</ng-container>
|
||||
|
||||
<shared-form-control label="Straße">
|
||||
<input class="input-control" placeholder="Straße" type="text" formControlName="street" tabindex="9" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Hausnummer">
|
||||
<input class="input-control" placeholder="Hausnummer" type="text" formControlName="streetNumber" tabindex="10" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="PLZ">
|
||||
<input class="input-control" placeholder="PLZ" type="text" formControlName="zipCode" tabindex="11" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Ort">
|
||||
<input class="input-control" placeholder="Ort" type="text" formControlName="city" tabindex="12" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Adresszusatz" class="col-span-2">
|
||||
<input class="input-control" placeholder="Adresszusatz" type="text" formControlName="info" tabindex="13" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control class="col-span-2" label="Land">
|
||||
<shared-select placeholder="Land" formControlName="country" tabindex="14">
|
||||
<shared-select-option *ngFor="let country of countries$ | async" [value]="country.isO3166_A_3">
|
||||
{{ country.name }}
|
||||
</shared-select-option>
|
||||
</shared-select>
|
||||
</shared-form-control>
|
||||
|
||||
<div class="text-center col-span-2">
|
||||
<shared-checkbox>Diese Lieferadresse als Standard Adresse festlegen</shared-checkbox>
|
||||
</div>
|
||||
<div class="mt-6 text-center col-span-2">
|
||||
<button
|
||||
[disabled]="formGroup.invalid || formGroup.disabled"
|
||||
type="submit"
|
||||
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white"
|
||||
tabindex="15"
|
||||
>
|
||||
Speichern
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -0,0 +1,121 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy } from '@angular/core';
|
||||
import { CheckboxComponent } from '@shared/components/checkbox';
|
||||
import { FormControl, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
||||
import { SelectModule } from '@shared/components/select';
|
||||
import { FormControlComponent } from '@shared/components/form-control';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
import { AddressDTO, Gender, ShippingAddressDTO } from '@swagger/crm';
|
||||
import { map, takeUntil } from 'rxjs/operators';
|
||||
import { AsyncPipe, NgForOf, NgIf } from '@angular/common';
|
||||
import { AddressSelectionModalService } from '@shared/modals/address-selection-modal';
|
||||
import { CustomerSearchStore } from '../store';
|
||||
import { CustomerSearchNavigation } from '../../navigations';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'page-add-shipping-address-main-view',
|
||||
templateUrl: 'add-shipping-address-main-view.component.html',
|
||||
styleUrls: ['add-shipping-address-main-view.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: { class: 'page-add-shipping-address-main-view' },
|
||||
standalone: true,
|
||||
imports: [AsyncPipe, NgIf, NgForOf, ReactiveFormsModule, SelectModule, FormControlComponent, CheckboxComponent],
|
||||
})
|
||||
export class AddShippingAddressMainViewComponent implements OnInit, OnDestroy {
|
||||
private _onDestroy = new Subject<void>();
|
||||
|
||||
formGroup = new FormGroup({
|
||||
gender: new FormControl<Gender>(0, [Validators.required, Validators.min(1)]),
|
||||
title: new FormControl<string>(undefined),
|
||||
firstName: new FormControl<string>(undefined, [Validators.required]),
|
||||
lastName: new FormControl<string>(undefined, [Validators.required]),
|
||||
organisation: new FormControl<string>(undefined),
|
||||
department: new FormControl<string>(undefined),
|
||||
vatId: new FormControl<string>(undefined),
|
||||
street: new FormControl<string>(undefined, [Validators.required]),
|
||||
streetNumber: new FormControl<string>(undefined, [Validators.required]),
|
||||
zipCode: new FormControl<string>(undefined, [Validators.required]),
|
||||
city: new FormControl<string>(undefined, [Validators.required]),
|
||||
country: new FormControl<string>('DEU', [Validators.required]),
|
||||
info: new FormControl<string>(undefined),
|
||||
isDefault: new FormControl<boolean>(false),
|
||||
});
|
||||
|
||||
countries$ = this._customerService.getCountries().pipe(map((res) => res.result));
|
||||
|
||||
isBusinessKonto$ = this._store.isBusinessKonto$;
|
||||
|
||||
constructor(
|
||||
private _customerService: CrmCustomerService,
|
||||
private _addressSelection: AddressSelectionModalService,
|
||||
private _store: CustomerSearchStore,
|
||||
private _navigation: CustomerSearchNavigation
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this._store.customer$.pipe(takeUntil(this._onDestroy)).subscribe(() => {
|
||||
if (this._store.isBusinessKonto) {
|
||||
this.formGroup.controls.organisation.setValidators([Validators.required]);
|
||||
} else {
|
||||
this.formGroup.controls.organisation.clearValidators();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this._onDestroy.next();
|
||||
this._onDestroy.complete();
|
||||
}
|
||||
|
||||
async save() {
|
||||
if (this.formGroup.invalid) {
|
||||
this.formGroup.markAllAsTouched();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.formGroup.disable();
|
||||
|
||||
const formData = this.formGroup.value;
|
||||
|
||||
const address: AddressDTO = {
|
||||
street: formData.street,
|
||||
streetNumber: formData.streetNumber,
|
||||
zipCode: formData.zipCode,
|
||||
city: formData.city,
|
||||
country: formData.country,
|
||||
info: formData.info,
|
||||
};
|
||||
|
||||
const addressValidationResult = await this._addressSelection.validateAddress(address);
|
||||
|
||||
if (addressValidationResult === undefined) {
|
||||
this.formGroup.enable();
|
||||
return;
|
||||
}
|
||||
|
||||
const addOrganization = this._store.isBusinessKonto || formData.organisation !== undefined;
|
||||
|
||||
const shippingAddress: ShippingAddressDTO = {
|
||||
gender: formData.gender,
|
||||
title: formData.title,
|
||||
firstName: formData.firstName,
|
||||
lastName: formData.lastName,
|
||||
organisation: addOrganization
|
||||
? {
|
||||
name: formData.organisation,
|
||||
department: formData.department,
|
||||
vatId: formData.vatId,
|
||||
}
|
||||
: undefined,
|
||||
address: addressValidationResult,
|
||||
};
|
||||
|
||||
const result = await this._customerService.createShippingAddress(this._store.customerId, shippingAddress, formData.isDefault);
|
||||
|
||||
this._navigation.navigateToDetails({ processId: this._store.processId, customerId: this._store.customerId });
|
||||
} catch (error) {
|
||||
this.formGroup.enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,11 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy } from '@angular/core';
|
||||
import { ActivatedRoute, NavigationEnd, Params, Router } from '@angular/router';
|
||||
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
|
||||
import { BehaviorSubject, Subject, Subscription } from 'rxjs';
|
||||
import { CustomerSearchStore } from './store/customer-search.store';
|
||||
import { provideComponentStore } from '@ngrx/component-store';
|
||||
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
|
||||
import { filter, first, map, switchMap, take, takeUntil } from 'rxjs/operators';
|
||||
import { filter, first, switchMap, takeUntil } from 'rxjs/operators';
|
||||
import { CustomerSearchNavigation } from '../navigations';
|
||||
import { Filter } from '@shared/components/filter';
|
||||
import { cloneDeep, isEqual } from 'lodash';
|
||||
|
||||
@Component({
|
||||
selector: 'page-customer-search',
|
||||
@@ -84,8 +82,8 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
|
||||
await this._router.navigate(route.path, { queryParams: route.queryParams });
|
||||
} else if (response.hits > 1) {
|
||||
const route = this._navigation.listRoute({ processId, filter });
|
||||
|
||||
if (['details', 'history', 'edit'].includes(this._breadcrumb)) {
|
||||
console.log('_breadcrumb', this._breadcrumb);
|
||||
if (['details', 'history', 'edit', 'add-billing-address'].includes(this._breadcrumb)) {
|
||||
await this._router.navigate([], { queryParams: route.queryParams });
|
||||
} else {
|
||||
await this._router.navigate(route.path, { queryParams: route.queryParams });
|
||||
@@ -152,15 +150,15 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
async checkBreadcrumbs(force = false) {
|
||||
let breadcumb: string;
|
||||
let breadcrumb: string;
|
||||
|
||||
breadcumb = this.snapshot.data?.breadcumb;
|
||||
breadcrumb = this.snapshot.data?.breadcrumb;
|
||||
|
||||
if (!breadcumb) {
|
||||
breadcumb = this.firstChildSnapshot.data?.breadcumb;
|
||||
if (!breadcrumb) {
|
||||
breadcrumb = this.firstChildSnapshot.data?.breadcrumb;
|
||||
}
|
||||
|
||||
this._breadcrumb = breadcumb;
|
||||
this._breadcrumb = breadcrumb;
|
||||
await this.checkMainBreadcrumb();
|
||||
await this.checkSearchBreadcrumb();
|
||||
await this.checkDetailsBreadcrumb();
|
||||
@@ -319,7 +317,7 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
|
||||
const navigation = this._navigation.editRoute({
|
||||
processId: this._store.processId,
|
||||
customerId: this._store.customerId,
|
||||
isB2b: this._store.customer?.features?.['b2b'] ?? false,
|
||||
isB2b: this._store.isBusinessKonto,
|
||||
});
|
||||
|
||||
const breadcrumb: Breadcrumb = {
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
<div class="grid grid-flow-col items-center justify-between px-4 py-2 border-t-2 border-solid border-surface-2">
|
||||
<h3 class="font-bold text-xl">Rechnungsadresse</h3>
|
||||
<a
|
||||
*ngIf="addBillingAddressRoute$ | async; let addRoute"
|
||||
type="button"
|
||||
class="text-brand font-bold"
|
||||
[routerLink]="addRoute.path"
|
||||
[queryParams]="addRoute.queryParams"
|
||||
[queryParamsHandling]="'merge'"
|
||||
>
|
||||
Hinzufügen
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-flow-row">
|
||||
<label
|
||||
class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 flex flex-row justify-between items-center"
|
||||
*ngIf="showCustomerAddress$ | async"
|
||||
>
|
||||
<input
|
||||
*ngIf="isNotBusinessKonto$ | async"
|
||||
name="shipping-address"
|
||||
type="radio"
|
||||
[checked]="!(customer$ | async)"
|
||||
(change)="selectCustomerAddress()"
|
||||
/>
|
||||
<div class="ml-2 flex flex-row justify-between items-center grow">
|
||||
<span class="truncate">
|
||||
{{ customer$ | async | address }}
|
||||
</span>
|
||||
<a
|
||||
*ngIf="editRoute$ | async; let editRoute"
|
||||
[routerLink]="editRoute.path"
|
||||
[queryParams]="editRoute.queryParams"
|
||||
[queryParamsHandling]="'merge'"
|
||||
class="text-brand font-bold"
|
||||
type="button"
|
||||
>
|
||||
Bearbeiten
|
||||
</a>
|
||||
</div>
|
||||
</label>
|
||||
<label
|
||||
class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 cursor-pointer flex flex-row items-center justify-start"
|
||||
*ngFor="let assignedPayer of assignedPayers$ | async"
|
||||
>
|
||||
<input
|
||||
name="assigned-payer"
|
||||
type="radio"
|
||||
[value]="assignedPayer"
|
||||
[checked]="(selectedPayer$ | async)?.payer.id === assignedPayer.payer.id"
|
||||
(change)="selectPayer(assignedPayer)"
|
||||
/>
|
||||
<div class="flex flex-row justify-between items-center grow">
|
||||
<span class="ml-2">
|
||||
{{ assignedPayer.payer.data | address }}
|
||||
</span>
|
||||
<ng-container *ngIf="canEditAddress$ | async">
|
||||
<a
|
||||
*ngIf="editRoute(assignedPayer.payer.id); let editRoute"
|
||||
class="text-brand font-bold"
|
||||
[routerLink]="editRoute.path"
|
||||
[queryParams]="editRoute.queryParams"
|
||||
[queryParamsHandling]="'merge'"
|
||||
>
|
||||
Bearbeiten
|
||||
</a>
|
||||
</ng-container>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
@@ -0,0 +1,153 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy } from '@angular/core';
|
||||
import { CustomerSearchStore } from '../../store';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
import { map, switchMap, takeUntil, tap } from 'rxjs/operators';
|
||||
import { Observable, Subject, combineLatest } from 'rxjs';
|
||||
import { AssignedPayerDTO, ListResponseArgsOfAssignedPayerDTO } from '@swagger/crm';
|
||||
import { AsyncPipe, NgFor, NgIf } from '@angular/common';
|
||||
import { CustomerPipesModule } from '@shared/pipes/customer';
|
||||
import { ComponentStore, tapResponse } from '@ngrx/component-store';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { CustomerSearchNavigation } from '../../../navigations';
|
||||
import { RouterLink } from '@angular/router';
|
||||
|
||||
interface DetailsMainViewBillingAddressesComponentState {
|
||||
assignedPayers: AssignedPayerDTO[];
|
||||
selectedPayer: AssignedPayerDTO;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'page-details-main-view-billing-addresses',
|
||||
templateUrl: 'details-main-view-billing-addresses.component.html',
|
||||
styleUrls: ['details-main-view-billing-addresses.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: { class: 'page-details-main-view-billing-addresses' },
|
||||
standalone: true,
|
||||
imports: [NgIf, NgFor, AsyncPipe, CustomerPipesModule, RouterLink],
|
||||
})
|
||||
export class DetailsMainViewBillingAddressesComponent extends ComponentStore<DetailsMainViewBillingAddressesComponentState>
|
||||
implements OnInit, OnDestroy {
|
||||
assignedPayers$ = this.select((state) => state.assignedPayers);
|
||||
|
||||
selectedPayer$ = this.select((state) => state.selectedPayer);
|
||||
|
||||
isNotBusinessKonto$ = this._store.isBusinessKonto$.pipe(map((isBusinessKonto) => !isBusinessKonto));
|
||||
|
||||
showCustomerAddress$ = combineLatest([this._store.isBusinessKonto$, this._store.isMitarbeiter$, this._store.isKundenkarte$]).pipe(
|
||||
map(([isBusinessKonto, isMitarbeiter, isKundenkarte]) => isBusinessKonto || isMitarbeiter || isKundenkarte)
|
||||
);
|
||||
|
||||
get showCustomerAddress() {
|
||||
return this._store.isBusinessKonto || this._store.isMitarbeiter;
|
||||
}
|
||||
|
||||
canAddNewAddress$ = combineLatest([
|
||||
this._store.isOnlinekonto$,
|
||||
this._store.isOnlineKontoMitKundenkarte$,
|
||||
this._store.isKundenkarte$,
|
||||
this._store.isMitarbeiter$,
|
||||
]).pipe(
|
||||
map(
|
||||
([isOnlinekonto, isOnlineKontoMitKundenkarte, isKundenkarte, isMitarbeiter]) =>
|
||||
isOnlinekonto || isOnlineKontoMitKundenkarte || isKundenkarte || isMitarbeiter
|
||||
)
|
||||
);
|
||||
|
||||
canEditAddress$ = combineLatest([this._store.isKundenkarte$]).pipe(map(([isKundenkarte]) => isKundenkarte));
|
||||
|
||||
customer$ = this._store.customer$;
|
||||
|
||||
private _onDestroy$ = new Subject<void>();
|
||||
|
||||
editRoute$ = combineLatest([this._store.processId$, this._store.customerId$, this._store.isBusinessKonto$]).pipe(
|
||||
map(([processId, customerId, isB2b]) => this._navigation.editRoute({ processId, customerId, isB2b }))
|
||||
);
|
||||
|
||||
addBillingAddressRoute$ = combineLatest([this.canAddNewAddress$, this._store.processId$, this._store.customerId$]).pipe(
|
||||
map(([canAddNewAddress, processId, customerId]) =>
|
||||
canAddNewAddress ? this._navigation.addBillingAddressRoute({ processId, customerId }) : undefined
|
||||
)
|
||||
);
|
||||
|
||||
constructor(
|
||||
private _store: CustomerSearchStore,
|
||||
private _customerService: CrmCustomerService,
|
||||
private _modal: UiModalService,
|
||||
private _navigation: CustomerSearchNavigation
|
||||
) {
|
||||
super({
|
||||
assignedPayers: [],
|
||||
selectedPayer: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
editRoute(payerId: number) {
|
||||
return this._navigation.editBillingAddressRoute({ customerId: this._store.customerId, payerId, processId: this._store.processId });
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this._store.customerId$.pipe(takeUntil(this._onDestroy$)).subscribe((customerId) => {
|
||||
this.resetStore();
|
||||
if (customerId) {
|
||||
this.loadAssignedPayers(customerId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this._onDestroy$.next();
|
||||
this._onDestroy$.complete();
|
||||
}
|
||||
|
||||
loadAssignedPayers = this.effect((customerId$: Observable<number>) =>
|
||||
customerId$.pipe(
|
||||
switchMap((customerId) =>
|
||||
this._customerService
|
||||
.getAssignedPayers({ customerId })
|
||||
.pipe(tapResponse(this.handleLoadAssignedPayersResponse, this.handleLoadAssignedPayersError))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
handleLoadAssignedPayersResponse = (response: ListResponseArgsOfAssignedPayerDTO) => {
|
||||
const selectedPayer = response.result.reduce<AssignedPayerDTO>((selected, payer) => {
|
||||
if (!selected) {
|
||||
return payer;
|
||||
}
|
||||
|
||||
if (new Date(selected.isDefault).getTime() < new Date(payer.isDefault).getTime()) {
|
||||
return payer;
|
||||
}
|
||||
|
||||
return selected;
|
||||
}, undefined);
|
||||
|
||||
this.patchState({
|
||||
assignedPayers: response.result,
|
||||
selectedPayer,
|
||||
});
|
||||
};
|
||||
|
||||
handleLoadAssignedPayersError = (err: any) => {
|
||||
this._modal.error('Laden der Rechnungsadressen fehlgeschlagen', err);
|
||||
};
|
||||
|
||||
resetStore() {
|
||||
this.patchState({
|
||||
assignedPayers: [],
|
||||
selectedPayer: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
selectPayer(payer: AssignedPayerDTO) {
|
||||
this.patchState({
|
||||
selectedPayer: payer,
|
||||
});
|
||||
}
|
||||
|
||||
selectCustomerAddress() {
|
||||
this.patchState({
|
||||
selectedPayer: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<div class="grid grid-flow-col items-center justify-between px-4 py-2 border-t-2 border-solid border-surface-2">
|
||||
<h3 class="font-bold text-xl">Lieferadresse</h3>
|
||||
<a
|
||||
*ngIf="addShippingAddressRoute$ | async; let addRoute"
|
||||
type="button"
|
||||
class="text-brand font-bold"
|
||||
[routerLink]="addRoute.path"
|
||||
[queryParams]="addRoute.queryParams"
|
||||
[queryParamsHandling]="'merge'"
|
||||
>
|
||||
Hinzufügen
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-flow-row">
|
||||
<label
|
||||
class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 cursor-pointer flex flex-row justify-start items-center"
|
||||
*ngIf="showCustomerAddress$ | async"
|
||||
>
|
||||
<input name="shipping-address" type="radio" [checked]="!(selectedShippingAddress$ | async)" (change)="selectCustomerAddress()" />
|
||||
<div class="ml-2 flex flex-row justify-between items-center grow">
|
||||
<span class="truncate">
|
||||
{{ customer$ | async | address }}
|
||||
</span>
|
||||
<a
|
||||
*ngIf="editRoute$ | async; let editRoute"
|
||||
[routerLink]="editRoute.path"
|
||||
[queryParams]="editRoute.queryParams"
|
||||
[queryParamsHandling]="'merge'"
|
||||
class="text-brand font-bold"
|
||||
type="button"
|
||||
>
|
||||
Bearbeiten
|
||||
</a>
|
||||
</div>
|
||||
</label>
|
||||
<label
|
||||
class="px-4 py-3 font-bold border-t-2 border-solid border-surface-2 cursor-pointer flex flex-row justify-start items-center"
|
||||
*ngFor="let shippingAddress of shippingAddresses$ | async"
|
||||
>
|
||||
<input
|
||||
name="shipping-address"
|
||||
type="radio"
|
||||
[value]="shippingAddress"
|
||||
[checked]="(selectedShippingAddress$ | async)?.id === shippingAddress.id"
|
||||
(change)="selectShippingAddress(shippingAddress)"
|
||||
/>
|
||||
<div class="ml-2 flex flex-row justify-between items-center grow">
|
||||
<span class="ml-2">
|
||||
{{ shippingAddress | address }}
|
||||
</span>
|
||||
<a *ngIf="canEditAddress$ | async" class="text-brand font-bold" type="button">
|
||||
Bearbeiten
|
||||
</a>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
@@ -0,0 +1,150 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy } from '@angular/core';
|
||||
import { CustomerSearchStore } from '../../store';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
import { map, switchMap, takeUntil } from 'rxjs/operators';
|
||||
import { Observable, Subject, combineLatest } from 'rxjs';
|
||||
import { ListResponseArgsOfAssignedPayerDTO, ShippingAddressDTO } from '@swagger/crm';
|
||||
import { AsyncPipe, NgFor, NgIf } from '@angular/common';
|
||||
import { CustomerPipesModule } from '@shared/pipes/customer';
|
||||
import { ComponentStore, tapResponse } from '@ngrx/component-store';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { CustomerSearchNavigation } from '../../../navigations';
|
||||
import { RouterLink } from '@angular/router';
|
||||
|
||||
interface DetailsMainViewDeliveryAddressesComponentState {
|
||||
shippingAddresses: ShippingAddressDTO[];
|
||||
selectedShippingAddress: ShippingAddressDTO;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'page-details-main-view-delivery-addresses',
|
||||
templateUrl: 'details-main-view-delivery-addresses.component.html',
|
||||
styleUrls: ['details-main-view-delivery-addresses.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: { class: 'page-details-main-view-delivery-addresses' },
|
||||
standalone: true,
|
||||
imports: [NgIf, NgFor, AsyncPipe, CustomerPipesModule, RouterLink],
|
||||
})
|
||||
export class DetailsMainViewDeliveryAddressesComponent extends ComponentStore<DetailsMainViewDeliveryAddressesComponentState>
|
||||
implements OnInit, OnDestroy {
|
||||
shippingAddresses$ = this.select((state) => state.shippingAddresses);
|
||||
|
||||
selectedShippingAddress$ = this.select((state) => state.selectedShippingAddress);
|
||||
|
||||
private _onDestroy$ = new Subject<void>();
|
||||
|
||||
showCustomerAddress$ = combineLatest([this._store.isBusinessKonto$, this._store.isMitarbeiter$, this._store.isKundenkarte$]).pipe(
|
||||
map(([isBusinessKonto, isMitarbeiter, isKundenkarte]) => isBusinessKonto || isMitarbeiter || isKundenkarte)
|
||||
);
|
||||
|
||||
get showCustomerAddress() {
|
||||
return this._store.isBusinessKonto || this._store.isMitarbeiter;
|
||||
}
|
||||
|
||||
customer$ = this._store.customer$;
|
||||
|
||||
canAddNewAddress$ = combineLatest([
|
||||
this._store.isOnlinekonto$,
|
||||
this._store.isOnlineKontoMitKundenkarte$,
|
||||
this._store.isKundenkarte$,
|
||||
this._store.isBusinessKonto$,
|
||||
this._store.isMitarbeiter$,
|
||||
]).pipe(
|
||||
map(
|
||||
([isOnlinekonto, isOnlineKontoMitKundenkarte, isKundenkarte, isBusinessKonto, isMitarbeiter]) =>
|
||||
isOnlinekonto || isOnlineKontoMitKundenkarte || isKundenkarte || isBusinessKonto || isMitarbeiter
|
||||
)
|
||||
);
|
||||
|
||||
editRoute$ = combineLatest([this._store.processId$, this._store.customerId$, this._store.isBusinessKonto$]).pipe(
|
||||
map(([processId, customerId, isB2b]) => this._navigation.editRoute({ processId, customerId, isB2b }))
|
||||
);
|
||||
|
||||
addShippingAddressRoute$ = combineLatest([this.canAddNewAddress$, this._store.processId$, this._store.customerId$]).pipe(
|
||||
map(([canAddNewAddress, processId, customerId]) =>
|
||||
canAddNewAddress ? this._navigation.addShippingAddressRoute({ processId, customerId }) : undefined
|
||||
)
|
||||
);
|
||||
|
||||
canEditAddress$ = combineLatest([this._store.isKundenkarte$, this._store.isBusinessKonto$, this._store.isMitarbeiter$]).pipe(
|
||||
map(([isKundenkarte, isBusinessKonto, isMitarbeiter]) => isKundenkarte || isBusinessKonto || isMitarbeiter)
|
||||
);
|
||||
|
||||
constructor(
|
||||
private _store: CustomerSearchStore,
|
||||
private _customerService: CrmCustomerService,
|
||||
private _modal: UiModalService,
|
||||
private _navigation: CustomerSearchNavigation
|
||||
) {
|
||||
super({
|
||||
shippingAddresses: [],
|
||||
selectedShippingAddress: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this._store.customerId$.pipe(takeUntil(this._onDestroy$)).subscribe((customerId) => {
|
||||
this.resetStore();
|
||||
if (customerId) {
|
||||
this.loadShippingAddresses(customerId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this._onDestroy$.next();
|
||||
this._onDestroy$.complete();
|
||||
}
|
||||
|
||||
loadShippingAddresses = this.effect((customerId$: Observable<number>) =>
|
||||
customerId$.pipe(
|
||||
switchMap((customerId) =>
|
||||
this._customerService
|
||||
.getShippingAddresses({ customerId })
|
||||
.pipe(tapResponse(this.handleLoadShippingAddressesResponse, this.handleLoadAssignedPayersError))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
handleLoadShippingAddressesResponse = (response: ListResponseArgsOfAssignedPayerDTO) => {
|
||||
const selectedShippingAddress = response.result.reduce<ShippingAddressDTO>((selected, shipping) => {
|
||||
if (!this.showCustomerAddress && !selected) {
|
||||
return shipping;
|
||||
}
|
||||
|
||||
if (selected && shipping && new Date(selected.isDefault).getTime() < new Date(shipping.isDefault).getTime()) {
|
||||
return shipping;
|
||||
}
|
||||
|
||||
return selected;
|
||||
}, undefined);
|
||||
|
||||
this.patchState({
|
||||
shippingAddresses: response.result,
|
||||
selectedShippingAddress,
|
||||
});
|
||||
};
|
||||
|
||||
handleLoadAssignedPayersError = (err: any) => {
|
||||
this._modal.error('Laden der Lieferadressen fehlgeschlagen', err);
|
||||
};
|
||||
|
||||
resetStore() {
|
||||
this.patchState({
|
||||
shippingAddresses: [],
|
||||
selectedShippingAddress: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
selectShippingAddress(shippingAddress: ShippingAddressDTO) {
|
||||
this.patchState({
|
||||
selectedShippingAddress: shippingAddress,
|
||||
});
|
||||
}
|
||||
|
||||
selectCustomerAddress() {
|
||||
this.patchState({
|
||||
selectedShippingAddress: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
}
|
||||
|
||||
.data-label {
|
||||
@apply w-[10.75rem];
|
||||
@apply w-52;
|
||||
}
|
||||
|
||||
.data-value {
|
||||
|
||||
@@ -8,11 +8,14 @@
|
||||
class="btn btn-label font-bold text-brand"
|
||||
[routerLink]="historyRoute.path"
|
||||
[queryParams]="historyRoute.queryParams"
|
||||
[queryParamsHandling]="'merge'"
|
||||
>Historie</a
|
||||
>
|
||||
</div>
|
||||
<div class="customer-details-header-body text-center -mt-3">
|
||||
<h1 class="text-[1.625rem] font-bold">Kundendetails</h1>
|
||||
<h1 class="text-[1.625rem] font-bold">
|
||||
{{ (isBusinessKonto$ | async) ? 'Firmendetails' : 'Kundendetails' }}
|
||||
</h1>
|
||||
<p>Sind Ihre Kundendaten korrekt?</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -22,6 +25,7 @@
|
||||
*ngIf="editRoute$ | async; let editRoute"
|
||||
[routerLink]="editRoute.path"
|
||||
[queryParams]="editRoute.queryParams"
|
||||
[queryParamsHandling]="'merge'"
|
||||
class="btn btn-label font-bold text-brand"
|
||||
type="button"
|
||||
>Bearbeiten</a
|
||||
@@ -41,7 +45,26 @@
|
||||
<div class="data-label">Kundennummer-DIG</div>
|
||||
<div class="data-value">{{ customerNumberDig }}</div>
|
||||
</div>
|
||||
<div class="flex flex-row" *ngIf="customerNumberBeeline$ | async; let customerNumberBeeline">
|
||||
<div class="data-label">Kundennummer-BEELINE</div>
|
||||
<div class="data-value">{{ customerNumberBeeline }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<ng-container *ngIf="isBusinessKonto$ | async">
|
||||
<div class="customer-details-customer-main-row">
|
||||
<div class="data-label">Firmenname</div>
|
||||
<div class="data-value">{{ organisationName$ | async }}</div>
|
||||
</div>
|
||||
<div class="customer-details-customer-main-row">
|
||||
<div class="data-label">Abteilung</div>
|
||||
<div class="data-value">{{ department$ | async }}</div>
|
||||
</div>
|
||||
<div class="customer-details-customer-main-row">
|
||||
<div class="data-label">USt-ID</div>
|
||||
<div class="data-value">{{ vatId$ | async }}</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div class="customer-details-customer-main-row">
|
||||
<div class="data-label">Anrede</div>
|
||||
<div class="data-value">{{ gender$ | async }}</div>
|
||||
@@ -62,6 +85,7 @@
|
||||
<div class="data-label">E-Mail</div>
|
||||
<div class="data-value">{{ email$ | async }}</div>
|
||||
</div>
|
||||
|
||||
<div class="customer-details-customer-main-row">
|
||||
<div class="data-label">Straße</div>
|
||||
<div class="data-value">{{ street$ | async }}</div>
|
||||
@@ -86,6 +110,7 @@
|
||||
<div class="data-label">Land</div>
|
||||
<div class="data-value">{{ country$ | async | country }}</div>
|
||||
</div>
|
||||
|
||||
<div class="customer-details-customer-main-row">
|
||||
<div class="data-label">Festnetznr.</div>
|
||||
<div class="data-value">{{ landline$ | async }}</div>
|
||||
@@ -94,12 +119,18 @@
|
||||
<div class="data-label">Mobilnr.</div>
|
||||
<div class="data-value">{{ mobile$ | async }}</div>
|
||||
</div>
|
||||
<div class="customer-details-customer-main-row">
|
||||
<div class="data-label">Abteilung</div>
|
||||
<div class="data-value">{{ department$ | async }}</div>
|
||||
</div>
|
||||
<div class="customer-details-customer-main-row">
|
||||
<div class="data-label">USt-ID</div>
|
||||
<div class="data-value">{{ vatId$ | async }}</div>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="!(isBusinessKonto$ | async)">
|
||||
<div class="customer-details-customer-main-row">
|
||||
<div class="data-label">Abteilung</div>
|
||||
<div class="data-value">{{ department$ | async }}</div>
|
||||
</div>
|
||||
<div class="customer-details-customer-main-row">
|
||||
<div class="data-label">USt-ID</div>
|
||||
<div class="data-value">{{ vatId$ | async }}</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<page-details-main-view-billing-addresses></page-details-main-view-billing-addresses>
|
||||
<page-details-main-view-delivery-addresses></page-details-main-view-delivery-addresses>
|
||||
</ng-template>
|
||||
|
||||
@@ -40,6 +40,8 @@ export class CustomerDetailsViewMainComponent {
|
||||
|
||||
customerNumberDig$ = this._store.select((s) => s.customer?.linkedRecords?.find((r) => r.repository === 'dig')?.number);
|
||||
|
||||
customerNumberBeeline$ = this._store.select((s) => s.customer?.linkedRecords?.find((r) => r.repository === 'beeline')?.number);
|
||||
|
||||
gender$ = this._store.select((s) => GENDER_MAP[s.customer?.gender]);
|
||||
|
||||
title$ = this._store.select((s) => s.customer?.title);
|
||||
@@ -66,9 +68,13 @@ export class CustomerDetailsViewMainComponent {
|
||||
|
||||
mobile$ = this._store.select((s) => s.customer?.communicationDetails?.mobile);
|
||||
|
||||
organisationName$ = this._store.select((s) => s.customer?.organisation?.name);
|
||||
|
||||
department$ = this._store.select((s) => s.customer?.organisation?.department);
|
||||
|
||||
vatId$ = this._store.select((s) => s.customer?.organisation?.vatId);
|
||||
|
||||
isBusinessKonto$ = this._store.isBusinessKonto$;
|
||||
|
||||
constructor(private _store: CustomerSearchStore, private _navigation: CustomerSearchNavigation) {}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,11 @@ import { CommonModule } from '@angular/common';
|
||||
import { CustomerDetailsViewMainComponent } from './details-main-view.component';
|
||||
import { CountryPipe } from '@shared/pipes/country';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { DetailsMainViewBillingAddressesComponent } from './details-main-view-billing-addresses/details-main-view-billing-addresses.component';
|
||||
import { DetailsMainViewDeliveryAddressesComponent } from './details-main-view-delivery-addresses/details-main-view-delivery-addresses.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, CountryPipe, RouterModule],
|
||||
imports: [CommonModule, CountryPipe, RouterModule, DetailsMainViewBillingAddressesComponent, DetailsMainViewDeliveryAddressesComponent],
|
||||
exports: [CustomerDetailsViewMainComponent],
|
||||
declarations: [CustomerDetailsViewMainComponent],
|
||||
})
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
:host {
|
||||
@apply block bg-surface text-surface-content rounded px-6 py-8;
|
||||
}
|
||||
|
||||
form {
|
||||
@apply grid grid-cols-2 gap-x-8;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<h1 class="text-2xl text-center font-bold mb-6">Rechnungsadresse bearbeiten</h1>
|
||||
|
||||
<form [formGroup]="formGroup" (ngSubmit)="save()">
|
||||
<shared-form-control label="Anrede">
|
||||
<shared-select formControlName="gender" placeholder="Anrede" tabindex="1" [autofocus]="true">
|
||||
<shared-select-option [value]="2">Herr</shared-select-option>
|
||||
<shared-select-option [value]="4">Frau</shared-select-option>
|
||||
</shared-select>
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Titel">
|
||||
<shared-select formControlName="title" placeholder="Titel" tabindex="2">
|
||||
<shared-select-option value="Dipl.-Ing.">Dipl.-Ing.</shared-select-option>
|
||||
<shared-select-option value="Dr.">Dr.</shared-select-option>
|
||||
<shared-select-option value="Dr. med.">Dr. med.</shared-select-option>
|
||||
<shared-select-option value="Prof.">Prof.</shared-select-option>
|
||||
<shared-select-option value="Prof. Dr.">Prof. Dr.</shared-select-option>
|
||||
<shared-select-option value="RA">RA</shared-select-option>
|
||||
</shared-select>
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Nachname">
|
||||
<input class="input-control" placeholder="Nachname" type="text" formControlName="lastName" tabindex="3" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Vorname">
|
||||
<input class="input-control" placeholder="Vorname" type="text" formControlName="firstName" tabindex="4" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Firma" class="col-span-2">
|
||||
<input class="input-control" placeholder="Firma" type="text" formControlName="organisation" tabindex="5" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Straße">
|
||||
<input class="input-control" placeholder="Straße" type="text" formControlName="street" tabindex="6" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Hausnummer">
|
||||
<input class="input-control" placeholder="Hausnummer" type="text" formControlName="streetNumber" tabindex="7" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="PLZ">
|
||||
<input class="input-control" placeholder="PLZ" type="text" formControlName="zipCode" tabindex="8" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Ort">
|
||||
<input class="input-control" placeholder="Ort" type="text" formControlName="city" tabindex="9" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Adresszusatz" class="col-span-2">
|
||||
<input class="input-control" placeholder="Adresszusatz" type="text" formControlName="info" tabindex="10" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control class="col-span-2" label="Land">
|
||||
<shared-select placeholder="Land" formControlName="country" tabindex="11">
|
||||
<shared-select-option *ngFor="let country of countries$ | async" [value]="country.isO3166_A_3">
|
||||
{{ country.name }}
|
||||
</shared-select-option>
|
||||
</shared-select>
|
||||
</shared-form-control>
|
||||
|
||||
<div class="text-center col-span-2">
|
||||
<shared-checkbox>Diese Rechnungsadresse als Standard Adresse festlegen</shared-checkbox>
|
||||
</div>
|
||||
<div class="mt-6 text-center col-span-2">
|
||||
<button
|
||||
[disabled]="formGroup.invalid || formGroup.disabled"
|
||||
type="submit"
|
||||
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white"
|
||||
>
|
||||
Speichern
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -0,0 +1,148 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy } from '@angular/core';
|
||||
import { CheckboxComponent } from '@shared/components/checkbox';
|
||||
import { FormControl, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
||||
import { SelectModule } from '@shared/components/select';
|
||||
import { FormControlComponent } from '@shared/components/form-control';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
import { AddressDTO, Gender, PayerDTO } from '@swagger/crm';
|
||||
import { map, switchMap, takeUntil } from 'rxjs/operators';
|
||||
import { AsyncPipe, NgForOf } from '@angular/common';
|
||||
import { AddressSelectionModalService } from '@shared/modals/address-selection-modal';
|
||||
import { CustomerSearchStore } from '../store';
|
||||
import { CustomerSearchNavigation } from '../../navigations';
|
||||
import { ComponentStore } from '@ngrx/component-store';
|
||||
import { Subject } from 'rxjs';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
|
||||
export interface EditBillingAddressMainViewState {
|
||||
payer?: PayerDTO;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'page-edit-billing-address-main-view',
|
||||
templateUrl: 'edit-billing-address-main-view.component.html',
|
||||
styleUrls: ['edit-billing-address-main-view.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: { class: 'page-edit-billing-address-main-view' },
|
||||
standalone: true,
|
||||
imports: [AsyncPipe, NgForOf, ReactiveFormsModule, SelectModule, FormControlComponent, CheckboxComponent],
|
||||
})
|
||||
export class EditBillingAddressMainViewComponent extends ComponentStore<EditBillingAddressMainViewState> implements OnInit, OnDestroy {
|
||||
private _onDestroy$ = new Subject<void>();
|
||||
|
||||
formGroup = new FormGroup({
|
||||
gender: new FormControl<Gender>(0, [Validators.required, Validators.min(1)]),
|
||||
title: new FormControl<string>(undefined),
|
||||
firstName: new FormControl<string>(undefined, [Validators.required]),
|
||||
lastName: new FormControl<string>(undefined, [Validators.required]),
|
||||
organisation: new FormControl<string>(undefined),
|
||||
street: new FormControl<string>(undefined, [Validators.required]),
|
||||
streetNumber: new FormControl<string>(undefined, [Validators.required]),
|
||||
zipCode: new FormControl<string>(undefined, [Validators.required]),
|
||||
city: new FormControl<string>(undefined, [Validators.required]),
|
||||
country: new FormControl<string>('DEU', [Validators.required]),
|
||||
info: new FormControl<string>(undefined),
|
||||
isDefault: new FormControl<boolean>(false),
|
||||
});
|
||||
|
||||
countries$ = this._customerService.getCountries().pipe(map((res) => res.result));
|
||||
|
||||
payerId$ = this._activatedRoute.params.pipe(
|
||||
map((params) => params.payerId),
|
||||
switchMap((payerId) => this._customerService.getPayer(payerId).pipe(map((res) => res.result)))
|
||||
);
|
||||
|
||||
get payerId() {
|
||||
return this.get((s) => s.payer?.id);
|
||||
}
|
||||
|
||||
get payer() {
|
||||
return this.get((s) => s.payer);
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _customerService: CrmCustomerService,
|
||||
private _addressSelection: AddressSelectionModalService,
|
||||
private _store: CustomerSearchStore,
|
||||
private _navigation: CustomerSearchNavigation,
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _modal: UiModalService
|
||||
) {
|
||||
super({ payer: undefined });
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.payerId$.pipe(takeUntil(this._onDestroy$)).subscribe((payer) => {
|
||||
this.patchState({ payer });
|
||||
this.patchFormGroup(payer);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this._onDestroy$.next();
|
||||
this._onDestroy$.complete();
|
||||
}
|
||||
|
||||
patchFormGroup(payer: PayerDTO) {
|
||||
this.formGroup.patchValue({
|
||||
gender: payer.gender ?? 0,
|
||||
title: payer.title,
|
||||
lastName: payer.lastName,
|
||||
firstName: payer.firstName,
|
||||
organisation: payer.organisation?.name,
|
||||
street: payer.address.street,
|
||||
streetNumber: payer.address.streetNumber,
|
||||
zipCode: payer.address.zipCode,
|
||||
city: payer.address.city,
|
||||
country: payer.address.country,
|
||||
info: payer.address.info,
|
||||
});
|
||||
}
|
||||
|
||||
async save() {
|
||||
if (this.formGroup.invalid) {
|
||||
this.formGroup.markAllAsTouched();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.formGroup.disable();
|
||||
|
||||
const formData = this.formGroup.value;
|
||||
|
||||
const address: AddressDTO = {
|
||||
street: formData.street,
|
||||
streetNumber: formData.streetNumber,
|
||||
zipCode: formData.zipCode,
|
||||
city: formData.city,
|
||||
country: formData.country,
|
||||
info: formData.info,
|
||||
};
|
||||
|
||||
const addressValidationResult = await this._addressSelection.validateAddress(address);
|
||||
|
||||
if (addressValidationResult === undefined) {
|
||||
this.formGroup.enable();
|
||||
return;
|
||||
}
|
||||
|
||||
const payer: PayerDTO = {
|
||||
...this.payer,
|
||||
gender: formData.gender,
|
||||
title: formData.title,
|
||||
firstName: formData.firstName,
|
||||
lastName: formData.lastName,
|
||||
organisation: formData.organisation ? { name: formData.organisation } : undefined,
|
||||
address: addressValidationResult,
|
||||
};
|
||||
|
||||
const result = await this._customerService.updatePayer(this._store.customerId, this.payerId, payer, formData.isDefault).toPromise();
|
||||
|
||||
this._navigation.navigateToDetails({ processId: this._store.processId, customerId: this._store.customerId });
|
||||
} catch (error) {
|
||||
this.formGroup.enable();
|
||||
this._modal.error('Fehler beim speichern der Rechnungsadresse', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
<div class="customer-edit-header-actions flex flex-row justify-end pt-1 px-1">
|
||||
<a *ngIf="detailsRoute$ | async; let route" [routerLink]="route.path" [queryParams]="route.queryParams" class="btn btn-label">
|
||||
<a
|
||||
*ngIf="detailsRoute$ | async; let route"
|
||||
[routerLink]="route.path"
|
||||
[queryParams]="route.queryParams"
|
||||
[queryParamsHandling]="'merge'"
|
||||
class="btn btn-label"
|
||||
>
|
||||
<ui-icon [icon]="'close'"></ui-icon>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
<div class="customer-edit-header-actions flex flex-row justify-end pt-1 px-1">
|
||||
<a *ngIf="detailsRoute$ | async; let route" [routerLink]="route.path" [queryParams]="route.queryParams" class="btn btn-label">
|
||||
<a
|
||||
*ngIf="detailsRoute$ | async; let route"
|
||||
[routerLink]="route.path"
|
||||
[queryParams]="route.queryParams"
|
||||
[queryParamsHandling]="'merge'"
|
||||
class="btn btn-label"
|
||||
>
|
||||
<ui-icon [icon]="'close'"></ui-icon>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
:host {
|
||||
@apply block bg-surface text-surface-content rounded px-6 py-8;
|
||||
}
|
||||
|
||||
form {
|
||||
@apply grid grid-cols-2 gap-x-8;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<h1 class="text-2xl text-center font-bold mb-6">Lieferadresse bearbeiten</h1>
|
||||
|
||||
<form [formGroup]="formGroup" (ngSubmit)="save()">
|
||||
<ng-container *ngIf="isBusinessKonto$ | async">
|
||||
<shared-form-control label="Firma" class="col-span-2">
|
||||
<input class="input-control" placeholder="Firma" type="text" formControlName="organisation" tabindex="1" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Abteilung">
|
||||
<input class="input-control" placeholder="Abteilung" type="text" formControlName="department" tabindex="2" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="USt-ID">
|
||||
<input class="input-control" placeholder="Abteilung" type="text" formControlName="vatId" tabindex="3" />
|
||||
</shared-form-control>
|
||||
</ng-container>
|
||||
|
||||
<shared-form-control label="Anrede">
|
||||
<shared-select formControlName="gender" placeholder="Anrede" tabindex="4" [autofocus]="true">
|
||||
<shared-select-option [value]="2">Herr</shared-select-option>
|
||||
<shared-select-option [value]="4">Frau</shared-select-option>
|
||||
</shared-select>
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Titel">
|
||||
<shared-select formControlName="title" placeholder="Titel" tabindex="5">
|
||||
<shared-select-option value="Dipl.-Ing.">Dipl.-Ing.</shared-select-option>
|
||||
<shared-select-option value="Dr.">Dr.</shared-select-option>
|
||||
<shared-select-option value="Dr. med.">Dr. med.</shared-select-option>
|
||||
<shared-select-option value="Prof.">Prof.</shared-select-option>
|
||||
<shared-select-option value="Prof. Dr.">Prof. Dr.</shared-select-option>
|
||||
<shared-select-option value="RA">RA</shared-select-option>
|
||||
</shared-select>
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Nachname">
|
||||
<input class="input-control" placeholder="Nachname" type="text" formControlName="lastName" tabindex="6" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Vorname">
|
||||
<input class="input-control" placeholder="Vorname" type="text" formControlName="firstName" tabindex="7" />
|
||||
</shared-form-control>
|
||||
|
||||
<ng-container *ngIf="!(isBusinessKonto$ | async)">
|
||||
<shared-form-control label="Firma" class="col-span-2">
|
||||
<input class="input-control" placeholder="Firma" type="text" formControlName="organisation" tabindex="8" />
|
||||
</shared-form-control>
|
||||
</ng-container>
|
||||
|
||||
<shared-form-control label="Straße">
|
||||
<input class="input-control" placeholder="Straße" type="text" formControlName="street" tabindex="9" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Hausnummer">
|
||||
<input class="input-control" placeholder="Hausnummer" type="text" formControlName="streetNumber" tabindex="10" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="PLZ">
|
||||
<input class="input-control" placeholder="PLZ" type="text" formControlName="zipCode" tabindex="11" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Ort">
|
||||
<input class="input-control" placeholder="Ort" type="text" formControlName="city" tabindex="12" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control label="Adresszusatz" class="col-span-2">
|
||||
<input class="input-control" placeholder="Adresszusatz" type="text" formControlName="info" tabindex="13" />
|
||||
</shared-form-control>
|
||||
|
||||
<shared-form-control class="col-span-2" label="Land">
|
||||
<shared-select placeholder="Land" formControlName="country" tabindex="14">
|
||||
<shared-select-option *ngFor="let country of countries$ | async" [value]="country.isO3166_A_3">
|
||||
{{ country.name }}
|
||||
</shared-select-option>
|
||||
</shared-select>
|
||||
</shared-form-control>
|
||||
|
||||
<div class="text-center col-span-2">
|
||||
<shared-checkbox>Diese Lieferadresse als Standard Adresse festlegen</shared-checkbox>
|
||||
</div>
|
||||
<div class="mt-6 text-center col-span-2">
|
||||
<button
|
||||
[disabled]="formGroup.invalid || formGroup.disabled"
|
||||
type="submit"
|
||||
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white"
|
||||
tabindex="15"
|
||||
>
|
||||
Speichern
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -0,0 +1,121 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy } from '@angular/core';
|
||||
import { CheckboxComponent } from '@shared/components/checkbox';
|
||||
import { FormControl, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
||||
import { SelectModule } from '@shared/components/select';
|
||||
import { FormControlComponent } from '@shared/components/form-control';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
import { AddressDTO, Gender, ShippingAddressDTO } from '@swagger/crm';
|
||||
import { map, takeUntil } from 'rxjs/operators';
|
||||
import { AsyncPipe, NgForOf, NgIf } from '@angular/common';
|
||||
import { AddressSelectionModalService } from '@shared/modals/address-selection-modal';
|
||||
import { CustomerSearchStore } from '../store';
|
||||
import { CustomerSearchNavigation } from '../../navigations';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'page-edit-shipping-address-main-view',
|
||||
templateUrl: 'edit-shipping-address-main-view.component.html',
|
||||
styleUrls: ['edit-shipping-address-main-view.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: { class: 'page-edit-shipping-address-main-view' },
|
||||
standalone: true,
|
||||
imports: [AsyncPipe, NgIf, NgForOf, ReactiveFormsModule, SelectModule, FormControlComponent, CheckboxComponent],
|
||||
})
|
||||
export class EditShippingAddressMainViewComponent implements OnInit, OnDestroy {
|
||||
private _onDestroy = new Subject<void>();
|
||||
|
||||
formGroup = new FormGroup({
|
||||
gender: new FormControl<Gender>(0, [Validators.required, Validators.min(1)]),
|
||||
title: new FormControl<string>(undefined),
|
||||
firstName: new FormControl<string>(undefined, [Validators.required]),
|
||||
lastName: new FormControl<string>(undefined, [Validators.required]),
|
||||
organisation: new FormControl<string>(undefined),
|
||||
department: new FormControl<string>(undefined),
|
||||
vatId: new FormControl<string>(undefined),
|
||||
street: new FormControl<string>(undefined, [Validators.required]),
|
||||
streetNumber: new FormControl<string>(undefined, [Validators.required]),
|
||||
zipCode: new FormControl<string>(undefined, [Validators.required]),
|
||||
city: new FormControl<string>(undefined, [Validators.required]),
|
||||
country: new FormControl<string>('DEU', [Validators.required]),
|
||||
info: new FormControl<string>(undefined),
|
||||
isDefault: new FormControl<boolean>(false),
|
||||
});
|
||||
|
||||
countries$ = this._customerService.getCountries().pipe(map((res) => res.result));
|
||||
|
||||
isBusinessKonto$ = this._store.isBusinessKonto$;
|
||||
|
||||
constructor(
|
||||
private _customerService: CrmCustomerService,
|
||||
private _addressSelection: AddressSelectionModalService,
|
||||
private _store: CustomerSearchStore,
|
||||
private _navigation: CustomerSearchNavigation
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this._store.customer$.pipe(takeUntil(this._onDestroy)).subscribe(() => {
|
||||
if (this._store.isBusinessKonto) {
|
||||
this.formGroup.controls.organisation.setValidators([Validators.required]);
|
||||
} else {
|
||||
this.formGroup.controls.organisation.clearValidators();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this._onDestroy.next();
|
||||
this._onDestroy.complete();
|
||||
}
|
||||
|
||||
async save() {
|
||||
if (this.formGroup.invalid) {
|
||||
this.formGroup.markAllAsTouched();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.formGroup.disable();
|
||||
|
||||
const formData = this.formGroup.value;
|
||||
|
||||
const address: AddressDTO = {
|
||||
street: formData.street,
|
||||
streetNumber: formData.streetNumber,
|
||||
zipCode: formData.zipCode,
|
||||
city: formData.city,
|
||||
country: formData.country,
|
||||
info: formData.info,
|
||||
};
|
||||
|
||||
const addressValidationResult = await this._addressSelection.validateAddress(address);
|
||||
|
||||
if (addressValidationResult === undefined) {
|
||||
this.formGroup.enable();
|
||||
return;
|
||||
}
|
||||
|
||||
const addOrganization = this._store.isBusinessKonto || formData.organisation !== undefined;
|
||||
|
||||
const shippingAddress: ShippingAddressDTO = {
|
||||
gender: formData.gender,
|
||||
title: formData.title,
|
||||
firstName: formData.firstName,
|
||||
lastName: formData.lastName,
|
||||
organisation: addOrganization
|
||||
? {
|
||||
name: formData.organisation,
|
||||
department: formData.department,
|
||||
vatId: formData.vatId,
|
||||
}
|
||||
: undefined,
|
||||
address: addressValidationResult,
|
||||
};
|
||||
|
||||
const result = await this._customerService.createShippingAddress(this._store.customerId, shippingAddress, formData.isDefault);
|
||||
|
||||
this._navigation.navigateToDetails({ processId: this._store.processId, customerId: this._store.customerId });
|
||||
} catch (error) {
|
||||
this.formGroup.enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,42 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
|
||||
|
||||
customer$ = this.select(S.selectCustomer);
|
||||
|
||||
get isBestellungOhneKonto() {
|
||||
return this.get(S.selectIsBestellungOhneKonto);
|
||||
}
|
||||
|
||||
isBestellungOhneKonto$ = this.select(S.selectIsBestellungOhneKonto);
|
||||
|
||||
get isOnlinekonto() {
|
||||
return this.get(S.selectIsOnlinekonto);
|
||||
}
|
||||
|
||||
isOnlinekonto$ = this.select(S.selectIsOnlinekonto);
|
||||
|
||||
get isOnlineKontoMitKundenkarte() {
|
||||
return this.get(S.selectIsOnlinekontoMitKundenkundenkarte);
|
||||
}
|
||||
|
||||
isOnlineKontoMitKundenkarte$ = this.select(S.selectIsOnlinekontoMitKundenkundenkarte);
|
||||
|
||||
get isKundenkarte() {
|
||||
return this.get(S.selectIsKundenkarte);
|
||||
}
|
||||
|
||||
isKundenkarte$ = this.select(S.selectIsKundenkarte);
|
||||
|
||||
get isBusinessKonto() {
|
||||
return this.get(S.selectIsBusinessKonto);
|
||||
}
|
||||
|
||||
isBusinessKonto$ = this.select(S.selectIsBusinessKonto);
|
||||
|
||||
get isMitarbeiter() {
|
||||
return this.get(S.selectIsMitarbeiter);
|
||||
}
|
||||
|
||||
isMitarbeiter$ = this.select(S.selectIsMitarbeiter);
|
||||
|
||||
get queryParams() {
|
||||
return this.get(S.selectQueryParams);
|
||||
}
|
||||
@@ -109,7 +145,7 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
|
||||
}),
|
||||
switchMap((customerId) =>
|
||||
this._customerService
|
||||
.getCustomer(customerId)
|
||||
.getCustomer(customerId, 2)
|
||||
.pipe(tapResponse(this.handleSelectCustomerResponse, this.handleSelectCustomerError, this.handleSelectCustomerComplete))
|
||||
)
|
||||
)
|
||||
|
||||
@@ -19,6 +19,54 @@ export function selectCustomerId(s: CustomerSearchState) {
|
||||
return selectCustomer(s)?.id;
|
||||
}
|
||||
|
||||
export function selecthasB2bFeature(s: CustomerSearchState) {
|
||||
return !!selectCustomer(s)?.features?.some((c) => c.key === 'b2b');
|
||||
}
|
||||
|
||||
export function selectHasGuestFeature(s: CustomerSearchState) {
|
||||
return !!selectCustomer(s)?.features?.some((c) => c.key === 'guest');
|
||||
}
|
||||
|
||||
export function selectHasWebshopFeature(s: CustomerSearchState) {
|
||||
return !!selectCustomer(s)?.features?.some((c) => c.key === 'webshop');
|
||||
}
|
||||
|
||||
export function selectHasP4mUserFeature(s: CustomerSearchState) {
|
||||
return !!selectCustomer(s)?.features?.some((c) => c.key === 'p4mUser');
|
||||
}
|
||||
|
||||
export function selectHasStaffFeature(s: CustomerSearchState) {
|
||||
return !!selectCustomer(s)?.features?.some((c) => c.key === 'staff');
|
||||
}
|
||||
|
||||
export function selectHasStoreFeature(s: CustomerSearchState) {
|
||||
return !!selectCustomer(s)?.features?.some((c) => c.key === 'store');
|
||||
}
|
||||
|
||||
export function selectIsBestellungOhneKonto(s: CustomerSearchState) {
|
||||
return selectHasWebshopFeature(s) && selectHasGuestFeature(s);
|
||||
}
|
||||
|
||||
export function selectIsOnlinekonto(s: CustomerSearchState) {
|
||||
return selectHasWebshopFeature(s) && !selectHasGuestFeature(s);
|
||||
}
|
||||
|
||||
export function selectIsOnlinekontoMitKundenkundenkarte(s: CustomerSearchState) {
|
||||
return selectHasWebshopFeature(s) && selectHasP4mUserFeature(s);
|
||||
}
|
||||
|
||||
export function selectIsKundenkarte(s: CustomerSearchState) {
|
||||
return selectHasP4mUserFeature(s) && selectHasStoreFeature(s);
|
||||
}
|
||||
|
||||
export function selectIsBusinessKonto(s: CustomerSearchState) {
|
||||
return selecthasB2bFeature(s) && !selectHasStaffFeature(s);
|
||||
}
|
||||
|
||||
export function selectIsMitarbeiter(s: CustomerSearchState) {
|
||||
return selectHasStaffFeature(s);
|
||||
}
|
||||
|
||||
export function selectFilter(s: CustomerSearchState) {
|
||||
if (!s.defaultFilter) return undefined;
|
||||
|
||||
|
||||
@@ -45,6 +45,76 @@ export class CustomerSearchNavigation {
|
||||
return this._router.navigate(route.path, { queryParams: route.queryParams });
|
||||
}
|
||||
|
||||
addBillingAddressRoute(params: { processId: NumberInput; customerId: NumberInput }): NavigationRoute {
|
||||
const path = [
|
||||
'/kunde',
|
||||
coerceNumberProperty(params.processId),
|
||||
'customer',
|
||||
coerceNumberProperty(params.customerId),
|
||||
'billingaddress',
|
||||
'add',
|
||||
];
|
||||
|
||||
const urlTree = this._router.createUrlTree(path, { queryParams: {} });
|
||||
|
||||
return {
|
||||
path,
|
||||
urlTree,
|
||||
};
|
||||
}
|
||||
|
||||
navigateToAddBillingAddress(params: { processId: NumberInput; customerId: NumberInput }): Promise<boolean> {
|
||||
const route = this.addBillingAddressRoute(params);
|
||||
return this._router.navigate(route.path, { queryParams: route.queryParams });
|
||||
}
|
||||
|
||||
editBillingAddressRoute(params: { processId: NumberInput; customerId: NumberInput; payerId: NumberInput }): NavigationRoute {
|
||||
const path = [
|
||||
'/kunde',
|
||||
coerceNumberProperty(params.processId),
|
||||
'customer',
|
||||
coerceNumberProperty(params.customerId),
|
||||
'billingaddress',
|
||||
coerceNumberProperty(params.payerId),
|
||||
'edit',
|
||||
];
|
||||
|
||||
const urlTree = this._router.createUrlTree(path, { queryParams: {} });
|
||||
|
||||
return {
|
||||
path,
|
||||
urlTree,
|
||||
};
|
||||
}
|
||||
|
||||
navigateToEditBillingAddress(params: { processId: NumberInput; customerId: NumberInput; payerId: NumberInput }): Promise<boolean> {
|
||||
const route = this.editBillingAddressRoute(params);
|
||||
return this._router.navigate(route.path, { queryParams: route.queryParams });
|
||||
}
|
||||
|
||||
addShippingAddressRoute(params: { processId: NumberInput; customerId: NumberInput }): NavigationRoute {
|
||||
const path = [
|
||||
'/kunde',
|
||||
coerceNumberProperty(params.processId),
|
||||
'customer',
|
||||
coerceNumberProperty(params.customerId),
|
||||
'shippingaddress',
|
||||
'add',
|
||||
];
|
||||
|
||||
const urlTree = this._router.createUrlTree(path, { queryParams: {} });
|
||||
|
||||
return {
|
||||
path,
|
||||
urlTree,
|
||||
};
|
||||
}
|
||||
|
||||
navigateToAddShippingAddress(params: { processId: NumberInput; customerId: NumberInput }): Promise<boolean> {
|
||||
const route = this.addShippingAddressRoute(params);
|
||||
return this._router.navigate(route.path, { queryParams: route.queryParams });
|
||||
}
|
||||
|
||||
historyRoute(params: { processId: NumberInput; customerId: NumberInput }): NavigationRoute {
|
||||
const path = ['/kunde', coerceNumberProperty(params.processId), 'customer', coerceNumberProperty(params.customerId), 'history'];
|
||||
|
||||
|
||||
@@ -17,6 +17,10 @@ import { UpdateP4MWebshopCustomerComponent } from './create-customer/update-p4m-
|
||||
import { CreateCustomerComponent } from './create-customer/create-customer.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 { AddBillingAddressMainViewComponent } from './customer-search/add-billing-address-main-view/add-billing-address-main-view.component';
|
||||
import { AddShippingAddressMainViewComponent } from './customer-search/add-shipping-address-main-view/add-shipping-address-main-view.component';
|
||||
import { EditBillingAddressMainViewComponent } from './customer-search/edit-billing-address-main-view/edit-billing-address-main-view.component';
|
||||
import { EditShippingAddressMainViewComponent } from './customer-search/edit-shipping-address-main-view/edit-shipping-address-main-view.component';
|
||||
|
||||
export const routes: Routes = [
|
||||
{
|
||||
@@ -42,14 +46,34 @@ export const routes: Routes = [
|
||||
path: '',
|
||||
component: CustomerSearchComponent,
|
||||
children: [
|
||||
{ path: '', component: CustomerFilterMainViewComponent, data: { side: 'main', breadcumb: 'main' } },
|
||||
{ path: 'search', component: CustomerResultsMainViewComponent, data: { breadcumb: 'search' } },
|
||||
{ path: 'filter', component: CustomerFilterMainViewComponent, data: { side: 'results', breadcumb: 'search' } },
|
||||
{ path: ':customerId', component: CustomerDetailsViewMainComponent, data: { side: 'results', breadcumb: 'details' } },
|
||||
{ path: ':customerId/history', component: CustomerHistoryMainViewComponent, data: { side: 'results', breadcumb: 'history' } },
|
||||
{ path: ':customerId/edit/b2b', component: CustomerDataEditB2BComponent, data: { side: 'results', breadcumb: 'edit' } },
|
||||
{ path: ':customerId/edit', component: CustomerDataEditB2CComponent, data: { side: 'results', breadcumb: 'edit' } },
|
||||
// { path: ':customerId/orders', component: CustomerSearchComponent, data: { side: 'orderItems' } },
|
||||
{ path: '', component: CustomerFilterMainViewComponent, data: { side: 'main', breadcrumb: 'main' } },
|
||||
{ path: 'search', component: CustomerResultsMainViewComponent, data: { breadcrumb: 'search' } },
|
||||
{ path: 'filter', component: CustomerFilterMainViewComponent, data: { side: 'results', breadcrumb: 'search' } },
|
||||
{ path: ':customerId', component: CustomerDetailsViewMainComponent, data: { side: 'results', breadcrumb: 'details' } },
|
||||
{ path: ':customerId/history', component: CustomerHistoryMainViewComponent, data: { side: 'results', breadcrumb: 'history' } },
|
||||
{ path: ':customerId/edit/b2b', component: CustomerDataEditB2BComponent, data: { side: 'results', breadcrumb: 'edit' } },
|
||||
{ path: ':customerId/edit', component: CustomerDataEditB2CComponent, data: { side: 'results', breadcrumb: 'edit' } },
|
||||
{
|
||||
path: ':customerId/billingaddress/add',
|
||||
component: AddBillingAddressMainViewComponent,
|
||||
data: { side: 'results', breadcrumb: 'add-billing-address' },
|
||||
},
|
||||
{
|
||||
path: ':customerId/billingaddress/:payerId/edit',
|
||||
component: EditBillingAddressMainViewComponent,
|
||||
data: { side: 'results', breadcrumb: 'edit-billing-address' },
|
||||
},
|
||||
{
|
||||
path: ':customerId/shippingaddress/add',
|
||||
component: AddShippingAddressMainViewComponent,
|
||||
data: { side: 'results', breadcrumb: 'add-shipping-address' },
|
||||
},
|
||||
{
|
||||
path: ':customerId/shippingaddress/:shippingAddressId/edit',
|
||||
component: EditShippingAddressMainViewComponent,
|
||||
data: { side: 'results', breadcrumb: 'edit-shipping-address' },
|
||||
},
|
||||
// { path: ':customerId/orders', component: CustomerSearchComponent, data: { side: 'orderItems' } }, EditBillingAddressMainViewComponent
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<div class="wrapper">
|
||||
<h2>Bitte überprüfen Sie die eingegebenen Adressdaten</h2>
|
||||
<p>Vorschläge:</p>
|
||||
|
||||
<ul class="content">
|
||||
<li *ngFor="let item of ref?.data">
|
||||
<span>{{ item.street }} {{ item.streetNumber }}, {{ item.zipCode }} {{ item.city }}</span>
|
||||
<button (click)="ref.close(item)">Übernehmen</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="center">
|
||||
<button class="select-btn" (click)="ref.close('continue')">Eingegebene Adresse übernehmen</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
:host {
|
||||
@apply bg-white;
|
||||
}
|
||||
|
||||
h2,
|
||||
p {
|
||||
@apply text-center text-p2;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply font-bold text-xl;
|
||||
}
|
||||
|
||||
ul {
|
||||
@apply list-none text-p2 -mx-4 p-0 mt-px-35;
|
||||
|
||||
li {
|
||||
@apply flex flex-row items-center justify-between border-glitter border-t-4 border-b-0 border-solid border-r-0 border-l-0 py-px-15 px-px-25;
|
||||
|
||||
&:last-child {
|
||||
@apply border-b-4;
|
||||
}
|
||||
|
||||
button {
|
||||
@apply border-none outline-none bg-transparent text-brand text-p1 text-right font-bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.center {
|
||||
@apply text-center;
|
||||
}
|
||||
|
||||
.select-btn {
|
||||
@apply border-none outline-none bg-brand text-white font-bold text-p1 px-px-25 py-px-15 rounded-full my-8;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { AddressDTO } from '@swagger/crm';
|
||||
import { UiModalRef } from '@ui/modal';
|
||||
|
||||
@Component({
|
||||
selector: 'page-address-selection-modal',
|
||||
templateUrl: 'address-selection-modal.component.html',
|
||||
styleUrls: ['address-selection-modal.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class AddressSelectionModalComponent {
|
||||
constructor(public ref: UiModalRef<AddressDTO[] | string>) {}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { AddressSelectionModalComponent } from './address-selection-modal.component';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiIconModule],
|
||||
exports: [AddressSelectionModalComponent],
|
||||
declarations: [AddressSelectionModalComponent],
|
||||
})
|
||||
export class AddressSelectionModalModule {}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
import { AddressDTO } from '@swagger/crm';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { AddressSelectionModalComponent } from './address-selection-modal.component';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddressSelectionModalService {
|
||||
constructor(private customerService: CrmCustomerService, private modal: UiModalService) {}
|
||||
|
||||
async validateAddress(address: AddressDTO): Promise<AddressDTO> {
|
||||
if (address.street && address.streetNumber && address.zipCode && address.city && address.country) {
|
||||
try {
|
||||
let addresses = await this.customerService
|
||||
.validateAddress(address)
|
||||
.pipe(
|
||||
map((response) =>
|
||||
response.result?.map((ad) => ({
|
||||
...address,
|
||||
...ad,
|
||||
}))
|
||||
)
|
||||
)
|
||||
.toPromise();
|
||||
|
||||
if (addresses?.length > 0) {
|
||||
const modalResult = await this.modal.open({ content: AddressSelectionModalComponent, data: addresses }).afterClosed$.toPromise();
|
||||
if (modalResult?.data) {
|
||||
if (modalResult.data === 'continue') {
|
||||
return address;
|
||||
} else {
|
||||
return modalResult.data;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
return address;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './lib/address-selection-modal.component';
|
||||
export * from './lib/address-selection-modal.module';
|
||||
export * from './lib/address-selection-modal.service';
|
||||
Reference in New Issue
Block a user