Merge branch 'release/2.0' into develop

This commit is contained in:
Lorenz Hilpert
2022-08-23 14:24:21 +02:00
8 changed files with 176 additions and 56 deletions

View File

@@ -318,9 +318,22 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
const fb = this._fb;
const notificationChannel = await this.notificationChannel$.pipe(first()).toPromise();
const communicationDetails = await this.communicationDetails$.pipe(first()).toPromise();
let selectedNotificationChannel = 0;
if ((notificationChannel & 1) === 1 && communicationDetails.email) {
selectedNotificationChannel += 1;
}
if ((notificationChannel & 2) === 2 && communicationDetails.mobile) {
selectedNotificationChannel += 2;
}
// #1967 Wenn E-Mail und SMS als NotificationChannel gesetzt sind, nur E-Mail anhaken
if ((selectedNotificationChannel & 3) === 3) {
selectedNotificationChannel = 1;
}
this.control = fb.group({
notificationChannel: new FormGroup({
selected: new FormControl((notificationChannel & 3) === 3 || communicationDetails.email ? 1 : notificationChannel),
selected: new FormControl(selectedNotificationChannel),
email: new FormControl(communicationDetails ? communicationDetails.email : '', emailNotificationValidator),
mobile: new FormControl(communicationDetails ? communicationDetails.mobile : '', mobileNotificationValidator),
}),

View File

@@ -1,10 +1,8 @@
<shared-goods-in-out-order-details (actionHandled)="actionHandled($event)" [itemsSelectable]="true">
<shared-goods-in-out-order-details-header
[order]="order$ | async"
(editClick)="navigateToEditPage($event)"
></shared-goods-in-out-order-details-header>
<shared-goods-in-out-order-details-header [order]="order$ | async" (editClick)="navigateToEditPage($event)">
</shared-goods-in-out-order-details-header>
<shared-goods-in-out-order-details-item
*ngFor="let item of itemsWithProcessingStatus$ | async"
*ngFor="let item of items$ | async"
[orderItem]="item"
[order]="order$ | async"
></shared-goods-in-out-order-details-item>

View File

@@ -4,12 +4,14 @@ import { BreadcrumbService } from '@core/breadcrumb';
import { DomainGoodsService, DomainOmsService, OrderItemsContext } from '@domain/oms';
import { ComponentStore, tapResponse } from '@ngrx/component-store';
import { ListResponseArgsOfOrderItemListItemDTO, OrderItemListItemDTO, OrderItemProcessingStatusValue } from '@swagger/oms';
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
import { combineLatest, Observable, Subject } from 'rxjs';
import { debounceTime, filter, first, map, shareReplay, switchMap, takeUntil, tap, withLatestFrom } from 'rxjs/operators';
export interface GoodsOutDetailsComponentState {
fetching: boolean;
orderNumber?: string;
buyerNumber?: string;
processingStatus?: OrderItemProcessingStatusValue;
compartmentCode?: string;
items?: OrderItemListItemDTO[];
@@ -25,6 +27,8 @@ export interface GoodsOutDetailsComponentState {
export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComponentState> implements OnInit, OnDestroy {
orderNumber$ = this.select((s) => decodeURIComponent(s.orderNumber ?? '') || undefined);
buyerNumber$ = this.select((s) => s.buyerNumber);
compartmentCode$ = this.select((s) => decodeURIComponent(s.compartmentCode ?? '') || undefined);
processingStatus$ = this.select((s) => s.processingStatus);
@@ -37,10 +41,6 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
return this.get((s) => s.items);
}
itemsWithProcessingStatus$ = combineLatest([this.items$, this.processingStatus$]).pipe(
map(([items, processingStatus]) => items.filter((item) => item.processingStatus === processingStatus))
);
order$ = this.orderId$.pipe(
filter((orderId) => !!orderId),
switchMap((orderId) => this._omsService.getOrder(orderId)),
@@ -60,7 +60,8 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
private _domainGoodsInService: DomainGoodsService,
private _omsService: DomainOmsService,
private _breadcrumb: BreadcrumbService,
private _router: Router
private _router: Router,
private _uiModal: UiModalService
) {
super({
fetching: false,
@@ -68,6 +69,11 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
}
ngOnInit() {
this._activatedRoute.queryParams.pipe(takeUntil(this._onDestroy$)).subscribe((params) => {
const buyerNumber: string = decodeURIComponent(params.buyerNumber ?? '');
this.patchState({ buyerNumber });
});
this._activatedRoute.params.pipe(takeUntil(this._onDestroy$)).subscribe(async (params) => {
const orderNumber: string = params?.orderNumber;
const compartmentCode = params?.compartmentCode;
@@ -92,6 +98,9 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
key: this.processId,
name: item?.compartmentCode || item?.orderNumber,
path: this.getDetailsPath(item),
params: {
buyerNumber: item.buyerNumber,
},
section: 'customer',
tags: ['goods-out', 'details', item?.compartmentCode || item?.orderNumber],
});
@@ -122,8 +131,8 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
$.pipe(
tap(() => this.patchState({ fetching: false })),
debounceTime(500),
withLatestFrom(this.orderNumber$, this.compartmentCode$, this.processingStatus$),
switchMap(([_, orderNumber, compartmentCode, processingStatus]) => {
withLatestFrom(this.orderNumber$, this.compartmentCode$),
switchMap(([_, orderNumber, compartmentCode]) => {
let request$: Observable<ListResponseArgsOfOrderItemListItemDTO>;
if (compartmentCode) {
request$ = this._domainGoodsInService.getWarenausgabeItemByCompartment(compartmentCode);
@@ -131,14 +140,20 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
request$ = this._domainGoodsInService.getWarenausgabeItemByOrderNumber(orderNumber);
}
return request$.pipe(
return combineLatest([request$, this.processingStatus$, this.buyerNumber$]).pipe(
tapResponse(
(res) => {
this.patchState({
items: res.result,
orderId: res.result[0].orderId,
([res, processingStatus, buyerNumber]) => {
const items = res.result.filter((item) => {
return item.processingStatus === processingStatus && (!!buyerNumber ? item.buyerNumber === buyerNumber : true);
});
this.updateBreadcrumb(res.result.find((item) => item.processingStatus === processingStatus));
this.openModalIfItemsHaveDifferentCustomers(items);
this.patchState({
items,
orderId: items[0].orderId,
});
this.updateBreadcrumb(items[0]);
},
(err) => {},
() => {
@@ -150,12 +165,25 @@ export class GoodsOutDetailsComponent extends ComponentStore<GoodsOutDetailsComp
)
);
openModalIfItemsHaveDifferentCustomers(items: OrderItemListItemDTO[]) {
const buyerNumbers = new Set(items.map((item) => item.buyerNumber));
if (buyerNumbers.size > 1) {
this._uiModal.open({
content: UiMessageModalComponent,
title: 'Achtung',
data: {
message: 'Anzeige ist fehlerhaft.\nEs wurden mehrere Positionen gefunden, die mehreren Kunden unterschiedlichen sind.',
},
});
}
}
navigateToEditPage(orderItem: OrderItemListItemDTO) {
this._router.navigate([this.getEditPath(orderItem)]);
this._router.navigate([this.getEditPath(orderItem)], { queryParams: { buyerNumber: orderItem.buyerNumber } });
}
navigateToDetailsPage(item: OrderItemListItemDTO) {
this._router.navigate([this.getDetailsPath(item)]);
this._router.navigate([this.getDetailsPath(item)], { queryParams: { buyerNumber: item.buyerNumber } });
}
navigateToLandingPage() {

View File

@@ -2,8 +2,10 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { BreadcrumbService } from '@core/breadcrumb';
import { DomainGoodsService } from '@domain/oms';
import { OrderItemListItemDTO } from '@swagger/oms';
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
import { combineLatest, Observable } from 'rxjs';
import { map, shareReplay, switchMap, withLatestFrom } from 'rxjs/operators';
import { map, shareReplay, switchMap, tap, withLatestFrom } from 'rxjs/operators';
@Component({
selector: 'page-goods-out-edit',
@@ -28,14 +30,22 @@ export class GoodsOutEditComponent implements OnInit {
map((params) => decodeURIComponent(params?.compartmentCode ?? '') || undefined)
);
buyerNumber$ = this._activatedRoute.queryParams.pipe(map((params) => params.buyerNumber));
items$ = combineLatest([this.orderNumber$, this.compartmentCode$]).pipe(
switchMap(([orderNumber, compartmentCode]) =>
compartmentCode
? this._domainGoodsInService.getWarenausgabeItemByCompartment(compartmentCode)
: this._domainGoodsInService.getWarenausgabeItemByOrderNumber(orderNumber)
),
withLatestFrom(this.processingStatus$),
map(([response, processingStatus]) => response.result.filter((item) => item.processingStatus === +processingStatus)),
withLatestFrom(this.processingStatus$, this.buyerNumber$),
map(([response, processingStatus, buyerNumber]) => {
console.log(response, processingStatus, buyerNumber);
return response.result.filter(
(item) => item.processingStatus === +processingStatus && (!!buyerNumber ? item.buyerNumber === buyerNumber : true)
);
}),
tap((items) => this.openModalIfItemsHaveDifferentCustomers(items)),
shareReplay()
);
@@ -43,7 +53,8 @@ export class GoodsOutEditComponent implements OnInit {
private _activatedRoute: ActivatedRoute,
private _breadcrumb: BreadcrumbService,
private _domainGoodsInService: DomainGoodsService,
private _router: Router
private _router: Router,
private _uiModal: UiModalService
) {}
ngOnInit() {
@@ -54,6 +65,7 @@ export class GoodsOutEditComponent implements OnInit {
const orderNumber = this._activatedRoute.snapshot.params.orderNumber;
const compartmentCode = this._activatedRoute.snapshot.params.compartmentCode;
const processingStatus = this._activatedRoute.snapshot.params.processingStatus;
const buyerNumber = this._activatedRoute.snapshot.queryParams.buyerNumber;
await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
key: this.processId,
name: 'Bearbeiten',
@@ -61,6 +73,7 @@ export class GoodsOutEditComponent implements OnInit {
? `/kunde/${this.processId}/goods/out/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}/edit`
: `/kunde/${this.processId}/goods/out/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}/edit`,
section: 'customer',
params: { buyerNumber },
tags: ['goods-out', 'edit', compartmentCode || orderNumber],
});
}
@@ -69,10 +82,27 @@ export class GoodsOutEditComponent implements OnInit {
const orderNumber = this._activatedRoute.snapshot.params.orderNumber;
const compartmentCode = this._activatedRoute.snapshot.params.compartmentCode;
const processingStatus = options?.processingStatus ? options.processingStatus : this._activatedRoute.snapshot.params.processingStatus;
const buyerNumber = this._activatedRoute.snapshot.queryParams.buyerNumber;
compartmentCode
? this._router.navigate([
`/kunde/${this.processId}/goods/out/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}`,
])
: this._router.navigate([`/kunde/${this.processId}/goods/out/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}`]);
? this._router.navigate(
[`/kunde/${this.processId}/goods/out/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}`],
{ queryParams: { buyerNumber } }
)
: this._router.navigate([`/kunde/${this.processId}/goods/out/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}`], {
queryParams: { buyerNumber },
});
}
openModalIfItemsHaveDifferentCustomers(items: OrderItemListItemDTO[]) {
const buyerNumbers = new Set(items.map((item) => item.buyerNumber));
if (buyerNumbers.size > 1) {
this._uiModal.open({
content: UiMessageModalComponent,
title: 'Achtung',
data: {
message: 'Anzeige ist fehlerhaft.\nEs wurden mehrere Positionen gefunden, die unterschiedlichen Kunden zugeordnet sind.',
},
});
}
}
}

View File

@@ -258,9 +258,14 @@ export class GoodsOutSearchResultsComponent extends ComponentStore<GoodsOutSearc
const compartmentCode = orderItem.compartmentCode;
if (compartmentCode) {
this._router.navigate([
`/kunde/${processId}/goods/out/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}`,
]);
this._router.navigate(
[`/kunde/${processId}/goods/out/details/compartment/${encodeURIComponent(compartmentCode)}/${processingStatus}`],
{
queryParams: {
buyerNumber: orderItem.buyerNumber,
},
}
);
} else {
this._router.navigate([`/kunde/${processId}/goods/out/details/order/${encodeURIComponent(orderNumber)}/${processingStatus}`]);
}

View File

@@ -107,9 +107,18 @@ export class AddProductModalComponent implements OnInit, OnDestroy {
return;
}
const item = { ...this.item };
if (!item.retailPrice) {
item.retailPrice = {
value: { value: 0, currency: 'EUR' },
vat: item.retailPrice?.vat,
};
}
try {
const result = await this._remiService
.addProductToRemit(this.item, this.selectedReason, this.form.value.quantity)
.addProductToRemit(item, this.selectedReason, this.form.value.quantity)
.pipe(first())
.toPromise();

View File

@@ -1,11 +1,11 @@
<ng-container *ngIf="requiredCapacities?.length > 1">
<div class="progress-outer">
<div class="progress-inner" [style.width]="capacityPercentage + '%'"></div>
<div class="progress-inner" [style.width]="leistungPercentage + '%'"></div>
</div>
<div class="mt-px-2 text-active-branch">Leistungsplätze: {{ capacity }} von {{ maxCapacity }} Exemplaren</div>
<div class="mt-px-2 text-active-branch">Leistungsplätze: {{ leistung }} von {{ maxLeistung }} Exemplaren</div>
<div class="progress-outer">
<div class="progress-inner" [style.width]="staplePercentage + '%'"></div>
<div class="progress-inner" [style.width]="stapelPercentage + '%'"></div>
</div>
<div class="mt-px-2 text-active-branch">Stapelplätze: {{ staple }} von {{ maxStaple }} Titel</div>
<div class="mt-px-2 text-active-branch">Stapelplätze: {{ stapel }} von {{ maxStapel }} Titel</div>
</ng-container>

View File

@@ -11,38 +11,75 @@ export class RequiredCapacitiesComponent {
@Input()
requiredCapacities: ValueTupleOfStringAndIntegerAndIntegerAndNullableIntegerAndString[];
get capacity() {
return this.requiredCapacities?.find((_) => true)?.item3 || 0;
get leistungCapacity() {
return this.requiredCapacities?.find((cap) => cap.item1 === 'Leistung') || undefined;
}
get maxCapacity() {
return Math.max(this.capacity, this.requiredCapacities?.find((_) => true)?.item2);
get leistung() {
const capacity = this.leistungCapacity;
if (!capacity) {
return 0;
}
return capacity.item3 > capacity.item2 ? capacity.item2 : capacity.item3;
}
get capacityPercentage() {
if (this.maxCapacity > 0) {
return (this.capacity / this.maxCapacity) * 100;
get maxLeistung() {
const capacity = this.leistungCapacity;
if (!capacity) {
return 0;
}
const maxLeistung =
(capacity.item4 || 0) < capacity.item2
? capacity.item4 || (capacity.item3 > capacity.item2 ? capacity.item2 : capacity.item3) || 0
: capacity.item2;
return Math.max(this.leistung, maxLeistung);
}
get leistungPercentage() {
if (this.leistung === this.maxLeistung) {
return 100;
}
if (this.maxLeistung > 0) {
return Math.min(Math.max((this.leistung / this.maxLeistung) * 100, 0), 100);
}
return 0;
}
get staple() {
if (this.requiredCapacities?.length > 0) {
return this.requiredCapacities[1].item3;
}
return 0;
get stapelCapacity() {
return this.requiredCapacities?.find((cap) => cap.item1 === 'Stapel') || undefined;
}
get maxStaple() {
if (this.requiredCapacities?.length > 0) {
return Math.max(this.staple, this.requiredCapacities[1].item2);
get stapel() {
const capacity = this.stapelCapacity;
if (!capacity) {
return 0;
}
return 0;
return capacity.item3 > capacity.item2 ? capacity.item2 : capacity.item3;
}
get staplePercentage() {
if (this.maxStaple > 0) {
return (this.staple / this.maxStaple) * 100;
get maxStapel() {
const capacity = this.stapelCapacity;
if (!capacity) {
return 0;
}
const maxStapel =
(capacity.item4 || 0) < capacity.item2
? capacity.item4 || (capacity.item3 > capacity.item2 ? capacity.item2 : capacity.item3) || 0
: capacity.item2;
return Math.max(this.stapel, maxStapel);
}
get stapelPercentage() {
if (this.stapel === this.maxStapel) {
return 100;
}
if (this.maxStapel > 0) {
return Math.min(Math.max((this.stapel / this.maxStapel) * 100, 0), 100);
}
return 0;
}