mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Compare commits
71 Commits
feature/45
...
fix/4689-W
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8057ebf473 | ||
|
|
42fa108bb6 | ||
|
|
2692588357 | ||
|
|
ec26b5f4c0 | ||
|
|
ff985bda64 | ||
|
|
ca255cb592 | ||
|
|
8df5052c76 | ||
|
|
c78ddb5c8c | ||
|
|
5d84b4a55a | ||
|
|
a6142a5d86 | ||
|
|
fdf50fe11e | ||
|
|
e8bf922a67 | ||
|
|
f202ff5291 | ||
|
|
0c25859b6b | ||
|
|
215cb89aff | ||
|
|
9256a79087 | ||
|
|
f1ff9c6c55 | ||
|
|
3f05e57554 | ||
|
|
2062bf3bab | ||
|
|
2d71a567ff | ||
|
|
547e615522 | ||
|
|
5d904e9d88 | ||
|
|
b7ccde4d44 | ||
|
|
2bc97ee574 | ||
|
|
f054614cfe | ||
|
|
0aa1cddf72 | ||
|
|
d39521b9f2 | ||
|
|
f5468d7f8e | ||
|
|
4ad99270bd | ||
|
|
4e098ae962 | ||
|
|
8e00e646fb | ||
|
|
4fad5a7c2f | ||
|
|
5ece030ec8 | ||
|
|
54d7c525a9 | ||
|
|
41d4dc4663 | ||
|
|
c266c51572 | ||
|
|
4ea50f68d1 | ||
|
|
e5d61c8622 | ||
|
|
d06c64c08a | ||
|
|
91ebc3e27f | ||
|
|
d643c19642 | ||
|
|
afd1f5e302 | ||
|
|
4099aa0a57 | ||
|
|
ebe11b75d1 | ||
|
|
81f7270cf7 | ||
|
|
570a8800a0 | ||
|
|
25aecffafc | ||
|
|
7c48c63584 | ||
|
|
5bf32b2e72 | ||
|
|
f44fbe3fdb | ||
|
|
5df075f448 | ||
|
|
9cee33e286 | ||
|
|
42bf7e4120 | ||
|
|
77ff7ca1a8 | ||
|
|
7f195ee627 | ||
|
|
79bec55818 | ||
|
|
35093afaff | ||
|
|
358ba3963c | ||
|
|
d47e617f8c | ||
|
|
55bd001146 | ||
|
|
a9f11426a7 | ||
|
|
10b86756d2 | ||
|
|
262dd084c1 | ||
|
|
abc58c8a78 | ||
|
|
866cd23e41 | ||
|
|
fdcf12c022 | ||
|
|
432f1161af | ||
|
|
82dbce5744 | ||
|
|
a4b9f5fcf1 | ||
|
|
7ea9359c30 | ||
|
|
b9a4b0d315 |
@@ -458,10 +458,6 @@ export class DomainAvailabilityService {
|
||||
return [2, 32, 256, 1024, 2048, 4096].some((code) => availability?.availabilityType === code);
|
||||
}
|
||||
|
||||
private _priceIsEmpty(price: PriceDTO) {
|
||||
return isEmpty(price?.value) || isEmpty(price?.vat);
|
||||
}
|
||||
|
||||
private _mapToTakeAwayAvailability({
|
||||
response,
|
||||
supplier,
|
||||
@@ -482,7 +478,7 @@ export class DomainAvailabilityService {
|
||||
inStock: inStock,
|
||||
supplierSSC: quantity <= inStock ? '999' : '',
|
||||
supplierSSCText: quantity <= inStock ? 'Filialentnahme' : '',
|
||||
price: this._priceIsEmpty(price) ? stockInfo?.retailPrice : price,
|
||||
price: stockInfo?.retailPrice ?? price, // #4553 Es soll nun immer der retailPrice aus der InStock Abfrage verwendet werden, egal ob "price" empty ist oder nicht
|
||||
supplier: { id: supplier?.id },
|
||||
// TODO: Change after API Update
|
||||
// LH: 2021-03-09 preis Property hat nun ein Fallback auf retailPrice
|
||||
|
||||
@@ -1021,7 +1021,11 @@ export class DomainCheckoutService {
|
||||
|
||||
//#region Common
|
||||
|
||||
@memorize()
|
||||
// Fix für Ticket #4619 Versand Artikel im Warenkob -> keine Änderung bei Kundendaten erfassen
|
||||
// Auskommentiert, da dieser Aufruf oftmals mit gleichen Parametern aufgerufen wird (ohne ausgewählten Kunden nur ein leeres Objekt bei customerFeatures)
|
||||
// memorize macht keinen deepCompare von Objekten und denkt hier, dass immer der gleiche Return Wert zurückkommt, allerdings ist das hier oft nicht der Fall
|
||||
// und der Decorator memorized dann fälschlicherweise
|
||||
// @memorize()
|
||||
canSetCustomer({
|
||||
processId,
|
||||
customerFeatures,
|
||||
|
||||
@@ -1,37 +1,60 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActionHandler } from '@core/command';
|
||||
import { DomainPrinterService } from '@domain/printer';
|
||||
import { DomainPrinterService, Printer } from '@domain/printer';
|
||||
import { PrintModalComponent, PrintModalData } from '@modal/printer';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { NativeContainerService } from 'native-container';
|
||||
import { OrderItemsContext } from './order-items.context';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
|
||||
@Injectable()
|
||||
export class PrintCompartmentLabelActionHandler extends ActionHandler<OrderItemsContext> {
|
||||
constructor(
|
||||
private uiModal: UiModalService,
|
||||
private domainPrinterService: DomainPrinterService,
|
||||
private nativeContainerService: NativeContainerService
|
||||
private nativeContainerService: NativeContainerService,
|
||||
private _environmentSerivce: EnvironmentService
|
||||
) {
|
||||
super('PRINT_COMPARTMENTLABEL');
|
||||
}
|
||||
printCompartmentLabelHelper(printer: string, orderItemSubsetIds: number[]) {
|
||||
return this.domainPrinterService
|
||||
.printCompartmentLabel({
|
||||
printer,
|
||||
orderItemSubsetIds,
|
||||
})
|
||||
.toPromise();
|
||||
}
|
||||
|
||||
async handler(data: OrderItemsContext): Promise<OrderItemsContext> {
|
||||
await this.uiModal
|
||||
.open({
|
||||
content: PrintModalComponent,
|
||||
config: { showScrollbarY: false },
|
||||
data: {
|
||||
printImmediately: !this.nativeContainerService.isNative,
|
||||
printerType: 'Label',
|
||||
print: (printer) =>
|
||||
this.domainPrinterService
|
||||
.printCompartmentLabel({ printer, orderItemSubsetIds: data.items.map((item) => item.orderItemSubsetId) })
|
||||
.toPromise(),
|
||||
} as PrintModalData,
|
||||
})
|
||||
.afterClosed$.toPromise();
|
||||
const printerList = await this.domainPrinterService.getAvailableLabelPrinters().toPromise();
|
||||
let printer: Printer;
|
||||
|
||||
if (Array.isArray(printerList)) {
|
||||
printer = printerList.find((printer) => printer.selected === true);
|
||||
}
|
||||
if (!printer || this._environmentSerivce.matchTablet()) {
|
||||
await this.uiModal
|
||||
.open({
|
||||
content: PrintModalComponent,
|
||||
config: { showScrollbarY: false },
|
||||
data: {
|
||||
printImmediately: !this._environmentSerivce.matchTablet(),
|
||||
printerType: 'Label',
|
||||
print: (printer) =>
|
||||
this.printCompartmentLabelHelper(
|
||||
printer,
|
||||
data.items.map((item) => item.orderItemSubsetId)
|
||||
),
|
||||
} as PrintModalData,
|
||||
})
|
||||
.afterClosed$.toPromise();
|
||||
} else {
|
||||
await this.printCompartmentLabelHelper(
|
||||
printer.key,
|
||||
data.items.map((item) => item.orderItemSubsetId)
|
||||
);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,45 +6,60 @@ import { UiModalService } from '@ui/modal';
|
||||
import { PrintModalComponent, PrintModalData } from '@modal/printer';
|
||||
import { groupBy } from '@ui/common';
|
||||
import { NativeContainerService } from 'native-container';
|
||||
import { ReceiptDTO } from '@swagger/oms';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
|
||||
@Injectable()
|
||||
export class PrintShippingNoteActionHandler extends ActionHandler<OrderItemsContext> {
|
||||
constructor(
|
||||
private uiModal: UiModalService,
|
||||
private domainPrinterService: DomainPrinterService,
|
||||
private nativeContainerService: NativeContainerService
|
||||
private nativeContainerService: NativeContainerService,
|
||||
private _environmentSerivce: EnvironmentService
|
||||
) {
|
||||
super('PRINT_SHIPPINGNOTE');
|
||||
}
|
||||
|
||||
async printShippingNoteHelper(printer: string, receipts: ReceiptDTO[]) {
|
||||
try {
|
||||
for (const group of groupBy(receipts, (receipt) => receipt?.buyer?.buyerNumber)) {
|
||||
await this.domainPrinterService.printShippingNote({ printer, receipts: group?.items?.map((r) => r?.id) }).toPromise();
|
||||
}
|
||||
return {
|
||||
error: false,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return {
|
||||
error: true,
|
||||
message: error?.message || error,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async handler(data: OrderItemsContext): Promise<OrderItemsContext> {
|
||||
await this.uiModal
|
||||
.open({
|
||||
content: PrintModalComponent,
|
||||
config: { showScrollbarY: false },
|
||||
data: {
|
||||
printImmediately: !this.nativeContainerService.isNative,
|
||||
printerType: 'Label',
|
||||
print: async (printer) => {
|
||||
try {
|
||||
const receipts = data?.receipts?.filter((r) => r?.receiptType & 1);
|
||||
for (const group of groupBy(receipts, (receipt) => receipt?.buyer?.buyerNumber)) {
|
||||
await this.domainPrinterService.printShippingNote({ printer, receipts: group?.items?.map((r) => r?.id) }).toPromise();
|
||||
}
|
||||
return {
|
||||
error: false,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return {
|
||||
error: true,
|
||||
message: error?.message || error,
|
||||
};
|
||||
}
|
||||
},
|
||||
} as PrintModalData,
|
||||
})
|
||||
.afterClosed$.toPromise();
|
||||
const printerList = await this.domainPrinterService.getAvailableLabelPrinters().toPromise();
|
||||
const receipts = data?.receipts?.filter((r) => r?.receiptType & 1);
|
||||
let printer: Printer;
|
||||
|
||||
if (Array.isArray(printerList)) {
|
||||
printer = printerList.find((printer) => printer.selected === true);
|
||||
}
|
||||
if (!printer || this._environmentSerivce.matchTablet()) {
|
||||
await this.uiModal
|
||||
.open({
|
||||
content: PrintModalComponent,
|
||||
config: { showScrollbarY: false },
|
||||
data: {
|
||||
printImmediately: !this.nativeContainerService.isNative,
|
||||
printerType: 'Label',
|
||||
print: async (printer) => await this.printShippingNoteHelper(printer, receipts),
|
||||
} as PrintModalData,
|
||||
})
|
||||
.afterClosed$.toPromise();
|
||||
} else {
|
||||
await this.printShippingNoteHelper(printer.key, receipts);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ export class PickupShelfOutService extends PickupShelfIOService {
|
||||
);
|
||||
}
|
||||
|
||||
const { orderdate } = args.filter?.getQueryToken()?.filter ?? {};
|
||||
const { orderdate, supplier_id } = args.filter?.getQueryToken()?.filter ?? {};
|
||||
|
||||
return this._abholfachService.AbholfachWarenausgabe({
|
||||
input: {
|
||||
@@ -45,6 +45,7 @@ export class PickupShelfOutService extends PickupShelfIOService {
|
||||
archive: String(true),
|
||||
all_branches: String(true),
|
||||
orderdate,
|
||||
supplier_id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,23 +2,26 @@ import { Injectable } from '@angular/core';
|
||||
import { Logger, LogLevel } from '@core/logger';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { UserStateService } from '@swagger/isa';
|
||||
import { debounceTime, switchMap } from 'rxjs/operators';
|
||||
import { debounceTime, switchMap, takeUntil } from 'rxjs/operators';
|
||||
import { RootState } from './root.state';
|
||||
import packageInfo from 'package';
|
||||
import { environment } from '../../environments/environment';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class RootStateService {
|
||||
static LOCAL_STORAGE_KEY = 'ISA_APP_INITIALSTATE';
|
||||
|
||||
private _cancelSave = new Subject<void>();
|
||||
|
||||
constructor(private readonly _userStateService: UserStateService, private _logger: Logger, private _store: Store) {
|
||||
if (!environment.production) {
|
||||
console.log('Die UserState kann in der Konsole mit der Funktion "clearUserState()" geleert werden.');
|
||||
|
||||
window['clearUserState'] = () => {
|
||||
this.clear();
|
||||
};
|
||||
}
|
||||
|
||||
window['clearUserState'] = () => {
|
||||
this.clear();
|
||||
};
|
||||
}
|
||||
|
||||
async init() {
|
||||
@@ -31,7 +34,8 @@ export class RootStateService {
|
||||
this._store
|
||||
.select((state) => state)
|
||||
.pipe(
|
||||
debounceTime(500),
|
||||
takeUntil(this._cancelSave),
|
||||
debounceTime(1000),
|
||||
switchMap((state) => {
|
||||
const raw = JSON.stringify({ ...state, version: packageInfo.version });
|
||||
RootStateService.SaveToLocalStorageRaw(raw);
|
||||
@@ -64,13 +68,17 @@ export class RootStateService {
|
||||
return false;
|
||||
}
|
||||
|
||||
clear() {
|
||||
this._userStateService
|
||||
.UserStateResetUserState()
|
||||
.toPromise()
|
||||
.catch((error) => this._logger.log(LogLevel.ERROR, error));
|
||||
RootStateService.RemoveFromLocalStorage();
|
||||
window.location.reload();
|
||||
async clear() {
|
||||
try {
|
||||
this._cancelSave.next();
|
||||
await this._userStateService.UserStateResetUserState().toPromise();
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
RootStateService.RemoveFromLocalStorage();
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
window.location.reload();
|
||||
} catch (error) {
|
||||
this._logger.log(LogLevel.ERROR, error);
|
||||
}
|
||||
}
|
||||
|
||||
static SaveToLocalStorage(state: RootState) {
|
||||
|
||||
@@ -280,6 +280,11 @@
|
||||
"name": "apps",
|
||||
"data": "M226-160q-28 0-47-19t-19-47q0-28 19-47t47-19q28 0 47 19t19 47q0 28-19 47t-47 19Zm254 0q-28 0-47-19t-19-47q0-28 19-47t47-19q28 0 47 19t19 47q0 28-19 47t-47 19Zm254 0q-28 0-47-19t-19-47q0-28 19-47t47-19q28 0 47 19t19 47q0 28-19 47t-47 19ZM226-414q-28 0-47-19t-19-47q0-28 19-47t47-19q28 0 47 19t19 47q0 28-19 47t-47 19Zm254 0q-28 0-47-19t-19-47q0-28 19-47t47-19q28 0 47 19t19 47q0 28-19 47t-47 19Zm254 0q-28 0-47-19t-19-47q0-28 19-47t47-19q28 0 47 19t19 47q0 28-19 47t-47 19ZM226-668q-28 0-47-19t-19-47q0-28 19-47t47-19q28 0 47 19t19 47q0 28-19 47t-47 19Zm254 0q-28 0-47-19t-19-47q0-28 19-47t47-19q28 0 47 19t19 47q0 28-19 47t-47 19Zm254 0q-28 0-47-19t-19-47q0-28 19-47t47-19q28 0 47 19t19 47q0 28-19 47t-47 19Z",
|
||||
"viewBox": "0 -960 960 960"
|
||||
},
|
||||
{
|
||||
"name": "gift",
|
||||
"data": "M2 21V10H0V4H5.2C5.11667 3.85 5.0625 3.69167 5.0375 3.525C5.0125 3.35833 5 3.18333 5 3C5 2.16667 5.29167 1.45833 5.875 0.875C6.45833 0.291667 7.16667 0 8 0C8.38333 0 8.74167 0.0708333 9.075 0.2125C9.40833 0.354167 9.71667 0.55 10 0.8C10.2833 0.533333 10.5917 0.333333 10.925 0.2C11.2583 0.0666667 11.6167 0 12 0C12.8333 0 13.5417 0.291667 14.125 0.875C14.7083 1.45833 15 2.16667 15 3C15 3.18333 14.9833 3.35417 14.95 3.5125C14.9167 3.67083 14.8667 3.83333 14.8 4H20V10H18V21H2ZM12 2C11.7167 2 11.4792 2.09583 11.2875 2.2875C11.0958 2.47917 11 2.71667 11 3C11 3.28333 11.0958 3.52083 11.2875 3.7125C11.4792 3.90417 11.7167 4 12 4C12.2833 4 12.5208 3.90417 12.7125 3.7125C12.9042 3.52083 13 3.28333 13 3C13 2.71667 12.9042 2.47917 12.7125 2.2875C12.5208 2.09583 12.2833 2 12 2ZM7 3C7 3.28333 7.09583 3.52083 7.2875 3.7125C7.47917 3.90417 7.71667 4 8 4C8.28333 4 8.52083 3.90417 8.7125 3.7125C8.90417 3.52083 9 3.28333 9 3C9 2.71667 8.90417 2.47917 8.7125 2.2875C8.52083 2.09583 8.28333 2 8 2C7.71667 2 7.47917 2.09583 7.2875 2.2875C7.09583 2.47917 7 2.71667 7 3ZM2 6V8H9V6H2ZM9 19V10H4V19H9ZM11 19H16V10H11V19ZM18 8V6H11V8H18Z",
|
||||
"viewBox": "0 0 20 21"
|
||||
}
|
||||
|
||||
],
|
||||
|
||||
5
apps/isa-app/src/assets/images/bookmark_responsive.svg
Normal file
5
apps/isa-app/src/assets/images/bookmark_responsive.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg width="48" height="51" viewBox="0 0 48 51" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 4.47368C8 2.01878 9.99009 0 12.445 0L43.555 0C46.0099 0 48 2.01878 48 4.47368H8Z" fill="#172062"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 4.445C0 1.99009 1.99009 0 4.445 0L42.7807 0V43.4808C42.7807 46.7878 39.2981 48.9368 36.3423 47.4537L23.376 40.948C22.1212 40.3183 20.6426 40.3186 19.3879 40.9486L6.4397 47.4505C3.48377 48.9348 0 46.7859 0 43.4782L0 4.445Z" fill="#0556B4"/>
|
||||
<rect x="19" y="19" width="18" height="17" fill="#0556B4"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 606 B |
@@ -75,6 +75,12 @@
|
||||
"licence": {
|
||||
"scandit": "Ae7z0WDdRDFqG6oYuAXzesYGJpDLDqt+xWtQHOESiOjaSkB7IEIDJAk534U+cg1zGnk++4hOEK9hXEGR01NLTjh76w1fDL0U63OUjo50EHBXIUvzAVSur3pRY+1ER7SvSEWaT0hDOLYvYrTpdECtt1graN9yMvJzXD38VJKUfssT92p+YENV2Hul3eXIvaVjHqXE/yvupF+MlOMMUMhX0/Km/yTU9H9SjBdsXYihZmYWbt2JotO3Zs1ojXb0+3La10xb01S1q0XdDN6El3XMVilEtdmrP3WoGois8vpQBvOCEvduxCfILFAqjeWXTZvXSut9u+kQKpK8uHW4rVV6iVClpZfPYqKJqTh78AI9gpnfb/zO9GfQEDS3g7wI5WbQKqaNRzhTVowFRri4Ep9R5TRC1bnd00RC4zVaMkbu5kBOA7YoRjgUiYWHKJpi/VokZWyN6u1lsi5mTUbQkm1ZWfX5I/iUVYBgyHZYl+8kfFkwLPXGZNrF4xqubjKiCZRQj0oyNjHOBeHqvAekzhk7scX2g/NN+liRQv4ur413b+uXacSiiYIrLhtGgzrz1KRrtu19uB5odk3LoerDoiYXat7wEg9zUYT/+uBfO2X+uS7L5LW0PMI3hV+joQVpDk5SlA2868Nx0KWtPWmMf7xCuFIhDskfBsXZNRTblqxkk0RzzSqtjx9ihGr+/Tuzm8Pm0s4OQqV7b+++/Zn+Vo4rCqMTwutjOO7dqhah5hbOT1MqY/6VcjCXyDad3BXXr+WYU4GtYTe8Ytjkm/ZTG3fImoDbMchEcqnCw3oxG5e/gkdurE8g/mZlFOtzAN7KkqIsg6qLaC5COjfLPXsi/A=="
|
||||
},
|
||||
"gender": {
|
||||
"0": "Keine Anrede",
|
||||
"1": "Enby",
|
||||
"2": "Herr",
|
||||
"4": "Frau"
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
|
||||
}
|
||||
@@ -74,5 +74,11 @@
|
||||
"licence": {
|
||||
"scandit": "Ae7z0WDdRDFqG6oYuAXzesYGJpDLDqt+xWtQHOESiOjaSkB7IEIDJAk534U+cg1zGnk++4hOEK9hXEGR01NLTjh76w1fDL0U63OUjo50EHBXIUvzAVSur3pRY+1ER7SvSEWaT0hDOLYvYrTpdECtt1graN9yMvJzXD38VJKUfssT92p+YENV2Hul3eXIvaVjHqXE/yvupF+MlOMMUMhX0/Km/yTU9H9SjBdsXYihZmYWbt2JotO3Zs1ojXb0+3La10xb01S1q0XdDN6El3XMVilEtdmrP3WoGois8vpQBvOCEvduxCfILFAqjeWXTZvXSut9u+kQKpK8uHW4rVV6iVClpZfPYqKJqTh78AI9gpnfb/zO9GfQEDS3g7wI5WbQKqaNRzhTVowFRri4Ep9R5TRC1bnd00RC4zVaMkbu5kBOA7YoRjgUiYWHKJpi/VokZWyN6u1lsi5mTUbQkm1ZWfX5I/iUVYBgyHZYl+8kfFkwLPXGZNrF4xqubjKiCZRQj0oyNjHOBeHqvAekzhk7scX2g/NN+liRQv4ur413b+uXacSiiYIrLhtGgzrz1KRrtu19uB5odk3LoerDoiYXat7wEg9zUYT/+uBfO2X+uS7L5LW0PMI3hV+joQVpDk5SlA2868Nx0KWtPWmMf7xCuFIhDskfBsXZNRTblqxkk0RzzSqtjx9ihGr+/Tuzm8Pm0s4OQqV7b+++/Zn+Vo4rCqMTwutjOO7dqhah5hbOT1MqY/6VcjCXyDad3BXXr+WYU4GtYTe8Ytjkm/ZTG3fImoDbMchEcqnCw3oxG5e/gkdurE8g/mZlFOtzAN7KkqIsg6qLaC5COjfLPXsi/A=="
|
||||
},
|
||||
"gender": {
|
||||
"0": "Keine Anrede",
|
||||
"1": "Enby",
|
||||
"2": "Herr",
|
||||
"4": "Frau"
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
@@ -76,5 +76,11 @@
|
||||
"licence": {
|
||||
"scandit": "Ae7z0WDdRDFqG6oYuAXzesYGJpDLDqt+xWtQHOESiOjaSkB7IEIDJAk534U+cg1zGnk++4hOEK9hXEGR01NLTjh76w1fDL0U63OUjo50EHBXIUvzAVSur3pRY+1ER7SvSEWaT0hDOLYvYrTpdECtt1graN9yMvJzXD38VJKUfssT92p+YENV2Hul3eXIvaVjHqXE/yvupF+MlOMMUMhX0/Km/yTU9H9SjBdsXYihZmYWbt2JotO3Zs1ojXb0+3La10xb01S1q0XdDN6El3XMVilEtdmrP3WoGois8vpQBvOCEvduxCfILFAqjeWXTZvXSut9u+kQKpK8uHW4rVV6iVClpZfPYqKJqTh78AI9gpnfb/zO9GfQEDS3g7wI5WbQKqaNRzhTVowFRri4Ep9R5TRC1bnd00RC4zVaMkbu5kBOA7YoRjgUiYWHKJpi/VokZWyN6u1lsi5mTUbQkm1ZWfX5I/iUVYBgyHZYl+8kfFkwLPXGZNrF4xqubjKiCZRQj0oyNjHOBeHqvAekzhk7scX2g/NN+liRQv4ur413b+uXacSiiYIrLhtGgzrz1KRrtu19uB5odk3LoerDoiYXat7wEg9zUYT/+uBfO2X+uS7L5LW0PMI3hV+joQVpDk5SlA2868Nx0KWtPWmMf7xCuFIhDskfBsXZNRTblqxkk0RzzSqtjx9ihGr+/Tuzm8Pm0s4OQqV7b+++/Zn+Vo4rCqMTwutjOO7dqhah5hbOT1MqY/6VcjCXyDad3BXXr+WYU4GtYTe8Ytjkm/ZTG3fImoDbMchEcqnCw3oxG5e/gkdurE8g/mZlFOtzAN7KkqIsg6qLaC5COjfLPXsi/A=="
|
||||
},
|
||||
"gender": {
|
||||
"0": "Keine Anrede",
|
||||
"1": "Enby",
|
||||
"2": "Herr",
|
||||
"4": "Frau"
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
@@ -75,5 +75,11 @@
|
||||
"licence": {
|
||||
"scandit": "AVljxT/dG+TAIDDL2jTxm843juR2OtZ6lHLxRpYR7x9uYiSvY2IAHdRx8tjsf9KU7wK0F5cAeb/nLMHF6Vor9ps79wvuBQw6G3N0IW978b78ZUgPOFzxHUAMuD8dbkDZlX8r9y1cOd9sT3UNEwGrQ4siUt2oCkigyTxJAgYs1ijnjQid7q42hHk3tMXywrAYeu5MhF0TV1H77DRDMxPHD/xiR0zhFQRB2Dtnm1+e3LHKCyQjZ/zknEpQB6HS7UbCBoEDj4tohb83E6oqmQFWwt85/Jk9f49gxXakIcNODnQI5H63kSqpEmV9Al1a5L+WGZ6Bq1gwBbnD8FBXlVqxoooiFXW7jzzBa9LNmQiQ5J8yEkIsPeyOHec7F4ERvVONSMYwWyH39ZweSiRsZRM1UsFPhN96bCT5MEwkjPFn4gji6TPGEceJZvV3HwsiCT5Bgjla4bvDsZ2jYvAr9tSij8kIii9dHvsWlrimt+szHJLSz+8uNI6jAvXyr2f3oRxZD/F9osZHVWkgtAc+vVWqkxVJCqmpmoHOXI6TFSqSjYHddhZyU5r2lgQt0+NI6k/bV3iN7Le1RJCP/wuSDCTZjzsU1igB7UnIN2Y70CqCjIeVH9qlxaI1YAC9lwFv1FZvsiueYeJP1n39mmXCSELVtzxgIBEX5yaIHNbbGXd+e8JUgcO8vJ2JA2kJudaU+xfYR5SY//+J1kPsNSbnBnM25LL+LjeRB3QTfqV5sFq8ORWcIMITvkEaRfP3PVcOzb+hO4Ren4ezhJuyADulmvG8a9Kxxk6ymzBbE7a93SGVbxp7OQNEmvTn5+B9wJ7/l1mtvZL2TilrDZBQVMYWrGuUGpA="
|
||||
},
|
||||
"gender": {
|
||||
"0": "Keine Anrede",
|
||||
"1": "Enby",
|
||||
"2": "Herr",
|
||||
"4": "Frau"
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
@@ -75,5 +75,11 @@
|
||||
"licence": {
|
||||
"scandit": "AVljxT/dG+TAIDDL2jTxm843juR2OtZ6lHLxRpYR7x9uYiSvY2IAHdRx8tjsf9KU7wK0F5cAeb/nLMHF6Vor9ps79wvuBQw6G3N0IW978b78ZUgPOFzxHUAMuD8dbkDZlX8r9y1cOd9sT3UNEwGrQ4siUt2oCkigyTxJAgYs1ijnjQid7q42hHk3tMXywrAYeu5MhF0TV1H77DRDMxPHD/xiR0zhFQRB2Dtnm1+e3LHKCyQjZ/zknEpQB6HS7UbCBoEDj4tohb83E6oqmQFWwt85/Jk9f49gxXakIcNODnQI5H63kSqpEmV9Al1a5L+WGZ6Bq1gwBbnD8FBXlVqxoooiFXW7jzzBa9LNmQiQ5J8yEkIsPeyOHec7F4ERvVONSMYwWyH39ZweSiRsZRM1UsFPhN96bCT5MEwkjPFn4gji6TPGEceJZvV3HwsiCT5Bgjla4bvDsZ2jYvAr9tSij8kIii9dHvsWlrimt+szHJLSz+8uNI6jAvXyr2f3oRxZD/F9osZHVWkgtAc+vVWqkxVJCqmpmoHOXI6TFSqSjYHddhZyU5r2lgQt0+NI6k/bV3iN7Le1RJCP/wuSDCTZjzsU1igB7UnIN2Y70CqCjIeVH9qlxaI1YAC9lwFv1FZvsiueYeJP1n39mmXCSELVtzxgIBEX5yaIHNbbGXd+e8JUgcO8vJ2JA2kJudaU+xfYR5SY//+J1kPsNSbnBnM25LL+LjeRB3QTfqV5sFq8ORWcIMITvkEaRfP3PVcOzb+hO4Ren4ezhJuyADulmvG8a9Kxxk6ymzBbE7a93SGVbxp7OQNEmvTn5+B9wJ7/l1mtvZL2TilrDZBQVMYWrGuUGpA="
|
||||
},
|
||||
"gender": {
|
||||
"0": "Keine Anrede",
|
||||
"1": "Enby",
|
||||
"2": "Herr",
|
||||
"4": "Frau"
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
@@ -76,5 +76,11 @@
|
||||
"licence": {
|
||||
"scandit": "Ae7z0WDdRDFqG6oYuAXzesYGJpDLDqt+xWtQHOESiOjaSkB7IEIDJAk534U+cg1zGnk++4hOEK9hXEGR01NLTjh76w1fDL0U63OUjo50EHBXIUvzAVSur3pRY+1ER7SvSEWaT0hDOLYvYrTpdECtt1graN9yMvJzXD38VJKUfssT92p+YENV2Hul3eXIvaVjHqXE/yvupF+MlOMMUMhX0/Km/yTU9H9SjBdsXYihZmYWbt2JotO3Zs1ojXb0+3La10xb01S1q0XdDN6El3XMVilEtdmrP3WoGois8vpQBvOCEvduxCfILFAqjeWXTZvXSut9u+kQKpK8uHW4rVV6iVClpZfPYqKJqTh78AI9gpnfb/zO9GfQEDS3g7wI5WbQKqaNRzhTVowFRri4Ep9R5TRC1bnd00RC4zVaMkbu5kBOA7YoRjgUiYWHKJpi/VokZWyN6u1lsi5mTUbQkm1ZWfX5I/iUVYBgyHZYl+8kfFkwLPXGZNrF4xqubjKiCZRQj0oyNjHOBeHqvAekzhk7scX2g/NN+liRQv4ur413b+uXacSiiYIrLhtGgzrz1KRrtu19uB5odk3LoerDoiYXat7wEg9zUYT/+uBfO2X+uS7L5LW0PMI3hV+joQVpDk5SlA2868Nx0KWtPWmMf7xCuFIhDskfBsXZNRTblqxkk0RzzSqtjx9ihGr+/Tuzm8Pm0s4OQqV7b+++/Zn+Vo4rCqMTwutjOO7dqhah5hbOT1MqY/6VcjCXyDad3BXXr+WYU4GtYTe8Ytjkm/ZTG3fImoDbMchEcqnCw3oxG5e/gkdurE8g/mZlFOtzAN7KkqIsg6qLaC5COjfLPXsi/A=="
|
||||
},
|
||||
"gender": {
|
||||
"0": "Keine Anrede",
|
||||
"1": "Enby",
|
||||
"2": "Herr",
|
||||
"4": "Frau"
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
<div class="page-price-update-item__item-card p-5 h-[212px] bg-white">
|
||||
<div class="page-price-update-item__item-thumbnail text-center mr-4 w-[47px] h-[73px]">
|
||||
<img
|
||||
class="page-price-update-item__item-image w-[47px] h-[73px]"
|
||||
class="page-price-update-item__item-image w-[47px] max-h-[73px]"
|
||||
loading="lazy"
|
||||
*ngIf="item?.product?.ean | productImage; let productImage"
|
||||
[src]="productImage"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="page-article-details__wrapper">
|
||||
<div #detailsContainer class="page-article-details__container px-5" *ngIf="store.item$ | async; let item">
|
||||
<div class="page-article-details__product-details mb-3">
|
||||
<div class="page-article-details__product-bookmark justify-self-end">
|
||||
<div class="page-article-details__product-bookmark flex fixed justify-self-end">
|
||||
<div *ngIf="showArchivBadge$ | async" class="archiv-badge">
|
||||
<button [uiOverlayTrigger]="archivTooltip" class="p-0 m-0 outline-none border-none bg-transparent relative -top-[0.3125rem]">
|
||||
<img src="/assets/images/bookmark_benachrichtigung_archiv.svg" alt="Archiv Badge" />
|
||||
@@ -30,9 +30,9 @@
|
||||
</div>
|
||||
<div *ngIf="showPromotionBadge$ | async" class="promotion-badge">
|
||||
<button [uiOverlayTrigger]="promotionTooltip" class="p-0 m-0 outline-none border-none bg-transparent relative -top-[0.3125rem]">
|
||||
<ui-icon-badge icon="gift" alt="Prämienkatalog Badge"></ui-icon-badge>
|
||||
<shared-icon-badge icon="gift" alt="Prämienkatalog Badge"></shared-icon-badge>
|
||||
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #promotionTooltip [closeable]="true">
|
||||
Dieser Artikel befindet sich im Prämienkatalog.
|
||||
Der Artikel ist als Prämie für {{ promotionPoints$ | async }} Punkte erhältlich.
|
||||
</ui-tooltip>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -76,7 +76,12 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
|
||||
|
||||
showSubscriptionBadge$ = this.store.item$.pipe(map((item) => item?.features?.find((i) => i.key === 'PFO')));
|
||||
|
||||
showPromotionBadge$ = this.store.item$.pipe(map((item) => item?.features?.find((i) => i.key === 'Promotion')));
|
||||
hasPromotionFeature$ = this.store.item$.pipe(map((item) => !!item?.features?.find((i) => i.key === 'Promotion')));
|
||||
promotionPoints$ = this.store.item$.pipe(map((item) => item?.redemptionPoints));
|
||||
|
||||
showPromotionBadge$ = combineLatest([this.hasPromotionFeature$, this.promotionPoints$]).pipe(
|
||||
map(([hasPromotionFeature, promotionPoints]) => hasPromotionFeature && promotionPoints > 0)
|
||||
);
|
||||
|
||||
showArchivBadge$ = this.store.item$.pipe(map((item) => item?.features?.find((i) => i.key === 'ARC')));
|
||||
|
||||
@@ -338,7 +343,7 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
|
||||
const item = await this.store.item$.pipe(first()).toPromise();
|
||||
const modal = this.uiModal.open<BranchDTO>({
|
||||
content: ModalAvailabilitiesComponent,
|
||||
title: 'Weitere Verfügbarkeiten',
|
||||
title: 'Bestände in anderen Filialen',
|
||||
data: {
|
||||
item,
|
||||
},
|
||||
|
||||
@@ -13,6 +13,7 @@ import { UiCommonModule } from '@ui/common';
|
||||
import { OrderDeadlinePipeModule } from '@shared/pipes/order-deadline';
|
||||
import { IconModule } from '@shared/components/icon';
|
||||
import { ArticleDetailsTextComponent } from './article-details-text/article-details-text.component';
|
||||
import { IconBadgeComponent } from 'apps/shared/components/icon/src/lib/badge/icon-badge.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -28,6 +29,7 @@ import { ArticleDetailsTextComponent } from './article-details-text/article-deta
|
||||
PipesModule,
|
||||
OrderDeadlinePipeModule,
|
||||
ArticleDetailsTextComponent,
|
||||
IconBadgeComponent,
|
||||
],
|
||||
exports: [ArticleDetailsComponent, ArticleRecommendationsComponent],
|
||||
declarations: [ArticleDetailsComponent, ArticleRecommendationsComponent],
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<p>Neben dem Titel "{{ item.product?.name }}" gibt es noch andere Artikel, die Sie interessieren könnten.</p>
|
||||
|
||||
<div class="articles">
|
||||
<span class="label">
|
||||
<span class="label mb-2">
|
||||
<ui-icon icon="recommendation" size="20px"></ui-icon>
|
||||
Artikel
|
||||
</span>
|
||||
@@ -28,9 +28,10 @@
|
||||
(click)="close.emit()"
|
||||
>
|
||||
<img [src]="recommendation.product?.ean | productImage: 195:315:true" alt="product-image" />
|
||||
|
||||
<span class="format">{{ recommendation.product?.formatDetail }}</span>
|
||||
<span class="price">{{ recommendation.catalogAvailability?.price?.value?.value | currency: ' ' }} EUR</span>
|
||||
<div class="flex flex-col">
|
||||
<span class="format">{{ recommendation.product?.formatDetail }}</span>
|
||||
<span class="price">{{ recommendation.catalogAvailability?.price?.value?.value | currency: ' ' }} EUR</span>
|
||||
</div>
|
||||
</a>
|
||||
</ui-slider>
|
||||
</ng-container>
|
||||
|
||||
@@ -29,12 +29,12 @@ p {
|
||||
}
|
||||
|
||||
.article {
|
||||
@apply flex flex-col mr-7 mt-4 no-underline text-black;
|
||||
@apply flex flex-col mr-7 mt-4 no-underline text-black h-full min-w-[11rem] justify-between;
|
||||
|
||||
img {
|
||||
@apply rounded-xl;
|
||||
height: 315px;
|
||||
max-width: 195px;
|
||||
max-height: 19.6875rem;
|
||||
max-width: 11rem;
|
||||
box-shadow: 0 0 15px #949393;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
>
|
||||
<div class="page-search-result-item__item-thumbnail text-center mr-4 w-[3.125rem] h-[4.9375rem]">
|
||||
<img
|
||||
class="page-search-result-item__item-image w-[3.125rem] h-[4.9375rem]"
|
||||
class="page-search-result-item__item-image w-[3.125rem] max-h-[4.9375rem]"
|
||||
loading="lazy"
|
||||
*ngIf="item?.imageId | thumbnailUrl; let thumbnailUrl"
|
||||
[src]="thumbnailUrl"
|
||||
|
||||
@@ -155,7 +155,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
|
||||
|
||||
const cleanQueryParams = this.cleanupQueryParams(queryParams);
|
||||
|
||||
if (this.route.outlet === 'primary' && processChanged) {
|
||||
if (this.route.outlet === 'primary' || processChanged) {
|
||||
this.scrollToItem(this._getScrollIndexFromCache());
|
||||
}
|
||||
|
||||
@@ -209,7 +209,6 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
|
||||
if (searchCompleted.state.hits === 1) {
|
||||
const item = searchCompleted.state.items.find((f) => f);
|
||||
const ean = this.route?.snapshot?.params?.ean;
|
||||
const itemId = this.route?.snapshot?.params?.id ? Number(this.route?.snapshot?.params?.id) : item.id; // Nicht zum ersten Item der Liste springen wenn bereits eines selektiert ist
|
||||
|
||||
// Navigation from Cart uses ean
|
||||
if (!!ean) {
|
||||
@@ -224,7 +223,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
|
||||
await this._navigationService
|
||||
.getArticleDetailsPath({
|
||||
processId,
|
||||
itemId,
|
||||
itemId: item.id,
|
||||
extras: { queryParams: params },
|
||||
})
|
||||
.navigate();
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { ShoppingCartItemDTO } from '@swagger/checkout';
|
||||
|
||||
export interface CheckoutDummyData extends ShoppingCartItemDTO {}
|
||||
export interface CheckoutDummyData extends ShoppingCartItemDTO {
|
||||
changeDataFromCart?: boolean;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { ItemDTO } from '@swagger/cat';
|
||||
import { DateAdapter } from '@ui/common';
|
||||
@@ -9,7 +8,8 @@ import { Subject } from 'rxjs';
|
||||
import { first, shareReplay, takeUntil } from 'rxjs/operators';
|
||||
import { CheckoutDummyData } from './checkout-dummy-data';
|
||||
import { CheckoutDummyStore } from './checkout-dummy.store';
|
||||
import { CheckoutNavigationService } from '@shared/services';
|
||||
import { CheckoutNavigationService, CustomerSearchNavigation } from '@shared/services';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'page-checkout-dummy',
|
||||
@@ -38,14 +38,15 @@ export class CheckoutDummyComponent implements OnInit, OnDestroy {
|
||||
_onDestroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
private _router: Router,
|
||||
private _fb: UntypedFormBuilder,
|
||||
private _dateAdapter: DateAdapter,
|
||||
private _modal: UiModalService,
|
||||
private _store: CheckoutDummyStore,
|
||||
private _ref: UiModalRef<any, CheckoutDummyData>,
|
||||
private readonly _applicationService: ApplicationService,
|
||||
private readonly _checkoutNavigationService: CheckoutNavigationService
|
||||
private readonly _checkoutNavigationService: CheckoutNavigationService,
|
||||
private readonly _customerNavigationService: CustomerSearchNavigation,
|
||||
private _router: Router
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -58,7 +59,7 @@ export class CheckoutDummyComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
});
|
||||
|
||||
if (!!this._ref?.data && Object.keys(this._ref?.data).length !== 0) {
|
||||
if (this.hasShoppingCartItemToUpdate()) {
|
||||
const data = this._ref?.data;
|
||||
this._store.patchState({ shoppingCartItem: data });
|
||||
this.populateFormFromModalData(data);
|
||||
@@ -149,6 +150,14 @@ export class CheckoutDummyComponent implements OnInit, OnDestroy {
|
||||
this.control.markAsUntouched();
|
||||
}
|
||||
|
||||
hasShoppingCartItemToUpdate(): boolean {
|
||||
const hasShoppingCartItem = !!this._ref.data?.id;
|
||||
if (!!this._ref?.data && hasShoppingCartItem) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async nextItem() {
|
||||
if (this.control.invalid || this.control.disabled) {
|
||||
this.control.enable();
|
||||
@@ -158,7 +167,7 @@ export class CheckoutDummyComponent implements OnInit, OnDestroy {
|
||||
|
||||
try {
|
||||
const branch = await this._store.currentBranch$.pipe(first()).toPromise();
|
||||
if (!!this._ref?.data && Object.keys(this._ref?.data).length !== 0) {
|
||||
if (this.hasShoppingCartItemToUpdate()) {
|
||||
await this._store.createAddToCartItem(this.control, branch, true);
|
||||
this._store.updateCart(() => {});
|
||||
} else {
|
||||
@@ -187,16 +196,17 @@ export class CheckoutDummyComponent implements OnInit, OnDestroy {
|
||||
|
||||
try {
|
||||
const branch = await this._store.currentBranch$.pipe(first()).toPromise();
|
||||
if (!!this._ref?.data && Object.keys(this._ref?.data).length !== 0) {
|
||||
if (this.hasShoppingCartItemToUpdate()) {
|
||||
await this._store.createAddToCartItem(this.control, branch, true);
|
||||
this._store.updateCart(async () => {
|
||||
// Set filter for navigation to customer search if customer is not set
|
||||
const customer = await this._store.customer$.pipe(first()).toPromise();
|
||||
const customerFilter = await this._store.customerFilter$.pipe(first()).toPromise();
|
||||
let filter: { [key: string]: string };
|
||||
if (!customer) {
|
||||
if (!customer && !this._ref?.data?.changeDataFromCart) {
|
||||
filter = customerFilter;
|
||||
this._router.navigate(['/kunde', this._applicationService.activatedProcessId, 'customer', 'search'], {
|
||||
const path = this._customerNavigationService.defaultRoute({ processId: this._applicationService.activatedProcessId }).path;
|
||||
await this._router.navigate(path, {
|
||||
queryParams: { customertype: filter.customertype },
|
||||
});
|
||||
} else {
|
||||
@@ -211,9 +221,10 @@ export class CheckoutDummyComponent implements OnInit, OnDestroy {
|
||||
const customer = await this._store.customer$.pipe(first()).toPromise();
|
||||
const customerFilter = await this._store.customerFilter$.pipe(first()).toPromise();
|
||||
let filter: { [key: string]: string };
|
||||
if (!customer) {
|
||||
if (!customer && !this._ref?.data?.changeDataFromCart) {
|
||||
filter = customerFilter;
|
||||
this._router.navigate(['/kunde', this._applicationService.activatedProcessId, 'customer', 'search'], {
|
||||
const path = this._customerNavigationService.defaultRoute({ processId: this._applicationService.activatedProcessId }).path;
|
||||
await this._router.navigate(path, {
|
||||
queryParams: { customertype: filter.customertype },
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
<div class="btn-wrapper">
|
||||
<a class="cta-primary" [routerLink]="productSearchBasePath">Artikel suchen</a>
|
||||
<button class="cta-secondary" (click)="openDummyModal()">Neuanlage</button>
|
||||
<button class="cta-secondary" (click)="openDummyModal({})">Neuanlage</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -54,7 +54,7 @@
|
||||
<button
|
||||
*ngIf="group.orderType === 'Dummy'"
|
||||
class="text-brand border-none font-bold text-p1 outline-none pl-4"
|
||||
(click)="openDummyModal()"
|
||||
(click)="openDummyModal({ changeDataFromCart: true })"
|
||||
>
|
||||
Hinzufügen
|
||||
</button>
|
||||
|
||||
@@ -292,15 +292,15 @@ export class CheckoutReviewComponent implements OnInit, OnDestroy, AfterViewInit
|
||||
this._store.notificationsControl = undefined;
|
||||
}
|
||||
|
||||
openDummyModal(data?: CheckoutDummyData) {
|
||||
openDummyModal({ data, changeDataFromCart = false }: { data?: CheckoutDummyData; changeDataFromCart?: boolean }) {
|
||||
this.uiModal.open({
|
||||
content: CheckoutDummyComponent,
|
||||
data,
|
||||
data: { ...data, changeDataFromCart },
|
||||
});
|
||||
}
|
||||
|
||||
changeDummyItem({ shoppingCartItem }: { shoppingCartItem: ShoppingCartItemDTO }) {
|
||||
this.openDummyModal(shoppingCartItem);
|
||||
this.openDummyModal({ data: shoppingCartItem, changeDataFromCart: true });
|
||||
}
|
||||
|
||||
async changeItem({ shoppingCartItem }: { shoppingCartItem: ShoppingCartItemDTO }) {
|
||||
|
||||
@@ -5,14 +5,10 @@
|
||||
<ng-container *ngIf="buyer$ | async; let buyer">
|
||||
<div *ngIf="!(showAddresses$ | async)" class="flex flex-row items-start justify-between p-5">
|
||||
<div class="flex flex-row flex-wrap pr-4">
|
||||
<ng-container *ngIf="!!buyer?.lastName && !!buyer?.firstName; else organisation">
|
||||
<div class="mr-3">Nachname, Vorname</div>
|
||||
<div class="font-bold">{{ buyer?.lastName }}, {{ buyer?.firstName }}</div>
|
||||
<ng-container *ngIf="getNameFromBuyer(buyer); let name">
|
||||
<div class="mr-3">{{ name.label }}</div>
|
||||
<div class="font-bold">{{ name.value }}</div>
|
||||
</ng-container>
|
||||
<ng-template #organisation>
|
||||
<div class="mr-3">Firmenname</div>
|
||||
<div class="font-bold">{{ buyer?.organisation?.name }}</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
<button (click)="changeAddress()" class="text-p1 font-bold text-[#F70400]">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, OnInit, inject } from '@angular/core';
|
||||
import { emailNotificationValidator, mobileNotificationValidator } from '@shared/components/notification-channel-control';
|
||||
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { combineLatest } from 'rxjs';
|
||||
@@ -7,7 +7,8 @@ import { first, map, switchMap, takeUntil, withLatestFrom } from 'rxjs/operators
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { Router } from '@angular/router';
|
||||
import { NotificationChannel } from '@swagger/checkout';
|
||||
import { BuyerDTO, NotificationChannel } from '@swagger/checkout';
|
||||
import { CustomerSearchNavigation } from '@shared/services';
|
||||
|
||||
@Component({
|
||||
selector: 'page-checkout-review-details',
|
||||
@@ -16,6 +17,8 @@ import { NotificationChannel } from '@swagger/checkout';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class CheckoutReviewDetailsComponent implements OnInit {
|
||||
customerNavigation = inject(CustomerSearchNavigation);
|
||||
|
||||
control: UntypedFormGroup;
|
||||
|
||||
customerFeatures$ = this._store.customerFeatures$;
|
||||
@@ -23,20 +26,6 @@ export class CheckoutReviewDetailsComponent implements OnInit {
|
||||
payer$ = this._store.payer$;
|
||||
buyer$ = this._store.buyer$;
|
||||
|
||||
showAddresses$ = this._store.shoppingCartItems$.pipe(
|
||||
takeUntil(this._store.orderCompleted),
|
||||
withLatestFrom(this.customerFeatures$),
|
||||
map(
|
||||
([items, customerFeatures]) =>
|
||||
items.some(
|
||||
(item) =>
|
||||
item.features?.orderType === 'Versand' ||
|
||||
item.features?.orderType === 'B2B-Versand' ||
|
||||
item.features?.orderType === 'DIG-Versand'
|
||||
) || !!customerFeatures?.b2b
|
||||
)
|
||||
);
|
||||
|
||||
showNotificationChannels$ = combineLatest([this._store.shoppingCartItems$, this.payer$, this.buyer$]).pipe(
|
||||
takeUntil(this._store.orderCompleted),
|
||||
map(
|
||||
@@ -65,6 +54,22 @@ export class CheckoutReviewDetailsComponent implements OnInit {
|
||||
switchMap((processId) => this._domainCheckoutService.getShippingAddress({ processId }))
|
||||
);
|
||||
|
||||
showAddresses$ = this._store.shoppingCartItems$.pipe(
|
||||
takeUntil(this._store.orderCompleted),
|
||||
withLatestFrom(this.customerFeatures$, this.payer$, this.shippingAddress$),
|
||||
map(([items, customerFeatures, payer, shippingAddress]) => {
|
||||
const hasShippingOrBillingAddresses = !!payer?.address || !!shippingAddress;
|
||||
const hasShippingFeature = items.some(
|
||||
(item) =>
|
||||
item.features?.orderType === 'Versand' || item.features?.orderType === 'B2B-Versand' || item.features?.orderType === 'DIG-Versand'
|
||||
);
|
||||
|
||||
const isB2bCustomer = !!customerFeatures?.b2b;
|
||||
|
||||
return hasShippingOrBillingAddresses && (hasShippingFeature || isB2bCustomer);
|
||||
})
|
||||
);
|
||||
|
||||
notificationChannelLoading$ = this._store.notificationChannelLoading$;
|
||||
|
||||
constructor(
|
||||
@@ -118,6 +123,20 @@ export class CheckoutReviewDetailsComponent implements OnInit {
|
||||
this._store.onNotificationChange(notificationChannels);
|
||||
}
|
||||
|
||||
getNameFromBuyer(buyer: BuyerDTO): { value: string; label: string } {
|
||||
if (buyer?.lastName && buyer?.firstName) {
|
||||
return { value: `${buyer?.lastName}, ${buyer?.firstName}`, label: 'Nachname, Vorname' };
|
||||
} else if (buyer?.lastName) {
|
||||
return { value: buyer?.lastName, label: 'Nachname, Vorname' };
|
||||
} else if (buyer?.firstName) {
|
||||
return { value: buyer?.firstName, label: 'Nachname, Vorname' };
|
||||
} else if (buyer?.organisation?.name) {
|
||||
return { value: buyer?.organisation?.name, label: 'Firmenname' };
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async changeAddress() {
|
||||
const processId = this._application.activatedProcessId;
|
||||
const customer = await this._domainCheckoutService.getBuyer({ processId }).pipe(first()).toPromise();
|
||||
@@ -126,7 +145,8 @@ export class CheckoutReviewDetailsComponent implements OnInit {
|
||||
return;
|
||||
}
|
||||
const customerId = customer.source;
|
||||
this._router.navigate(['/kunde', this._application.activatedProcessId, 'customer', 'search', `${customerId}`]);
|
||||
await this.customerNavigation.navigateToDetails({ processId, customerId, customer: { customerNumber: customer.buyerNumber } });
|
||||
// this._router.navigate(['/kunde', this._application.activatedProcessId, 'customer', 'search', `${customerId}`]);
|
||||
}
|
||||
|
||||
async navigateToCustomerSearch(processId: number) {
|
||||
|
||||
@@ -17,7 +17,7 @@ button {
|
||||
grid-area: item-thumbnail;
|
||||
@apply mr-8 w-[3.75rem] h-[5.9375rem];
|
||||
img {
|
||||
@apply w-[3.75rem] h-[5.9375rem] rounded shadow-cta;
|
||||
@apply w-[3.75rem] max-h-[5.9375rem] rounded shadow-cta;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,8 @@
|
||||
<span class="w-32">Vorgangs-ID</span>
|
||||
<ng-container *ngIf="customer$ | async; let customer">
|
||||
<a
|
||||
data-which="Vorgangs-ID"
|
||||
data-what="link"
|
||||
*ngIf="customer$ | async; let customer"
|
||||
class="font-bold text-[#0556B4] no-underline"
|
||||
[routerLink]="['/kunde', processId, 'customer', 'search', customer?.id, 'orders', displayOrder.id]"
|
||||
@@ -102,7 +104,7 @@
|
||||
>
|
||||
<div class="page-checkout-summary__items-thumbnail flex flex-row">
|
||||
<a [routerLink]="getProductSearchDetailsPath(order?.product?.ean)" [queryParams]="getProductSearchDetailsQueryParams(order)">
|
||||
<img class="w-[3.125rem] h-20 mr-2" [src]="order.product?.ean | productImage: 195:315:true" />
|
||||
<img class="w-[3.125rem] max-h-20 mr-2" [src]="order.product?.ean | productImage: 195:315:true" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -226,11 +228,12 @@
|
||||
<div class="absolute left-1/2 bottom-10 inline-grid grid-flow-col gap-4 justify-center transform -translate-x-1/2">
|
||||
<button
|
||||
*ifRole="'Store'"
|
||||
[disabled]="isPrinting$ | async"
|
||||
type="button"
|
||||
class="px-6 py-2 rounded-full border-2 border-solid border-brand text-brand bg-white font-bold text-lg whitespace-nowrap h-14"
|
||||
class="px-6 py-2 rounded-full border-2 border-solid border-brand text-brand bg-white font-bold text-lg whitespace-nowrap h-14 flex flex-row items-center justify-center print-button"
|
||||
(click)="printOrderConfirmation()"
|
||||
>
|
||||
Bestellbestätigung drucken
|
||||
<ui-spinner class="min-h-4 min-w-4" [show]="isPrinting$ | async"> Bestellbestätigung drucken </ui-spinner>
|
||||
</button>
|
||||
|
||||
<button
|
||||
|
||||
@@ -96,6 +96,12 @@ hr {
|
||||
}
|
||||
}
|
||||
|
||||
.print-button {
|
||||
&:disabled {
|
||||
@apply bg-inactive-branch border-solid border-inactive-branch text-white cursor-not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.last {
|
||||
@apply pb-5;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import { DateAdapter } from '@ui/common';
|
||||
import { CheckoutNavigationService, PickUpShelfOutNavigationService, ProductCatalogNavigationService } from '@shared/services';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { SendOrderConfirmationModalService } from '@shared/modals/send-order-confirmation-modal';
|
||||
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||
import { ToasterService } from '@shared/shell';
|
||||
|
||||
@Component({
|
||||
@@ -136,6 +135,8 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
|
||||
)
|
||||
);
|
||||
|
||||
isPrinting$ = new BehaviorSubject(false);
|
||||
|
||||
totalPriceCurrency$ = this.displayOrders$.pipe(map((displayOrders) => displayOrders[0]?.items[0]?.price?.value?.currency));
|
||||
|
||||
containsDeliveryOrder$ = this.displayOrders$.pipe(
|
||||
@@ -161,6 +162,10 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
|
||||
return this._environmentService.matchDesktopLarge$;
|
||||
}
|
||||
|
||||
get isTablet() {
|
||||
return this._environmentService.matchTablet();
|
||||
}
|
||||
|
||||
expanded: boolean[] = [];
|
||||
|
||||
constructor(
|
||||
@@ -291,22 +296,9 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
|
||||
if (takeNowOrders.length != 1) return;
|
||||
|
||||
try {
|
||||
for (const takeNowOrder of takeNowOrders) {
|
||||
for (const orderItem of takeNowOrder.items.filter((item) => item.features?.orderType === 'Rücklage')) {
|
||||
await this.omsService
|
||||
.changeOrderStatus(takeNowOrder.id, orderItem.id, orderItem.subsetItems[0]?.id, {
|
||||
processingStatus: 128,
|
||||
})
|
||||
.toPromise();
|
||||
}
|
||||
}
|
||||
|
||||
await this.router.navigate(
|
||||
this._shelfOutNavigationService.detailRoute({
|
||||
processId: Date.now(),
|
||||
item: { orderId: takeNowOrders[0].id, orderNumber: takeNowOrders[0].orderNumber, processingStatus: 128 },
|
||||
}).path
|
||||
);
|
||||
await this.router.navigate(this._shelfOutNavigationService.listRoute({ processId: Date.now() }).path, {
|
||||
queryParams: { main_qs: takeNowOrders[0].orderNumber, filter_supplier_id: '16' },
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
@@ -319,27 +311,57 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
async printOrderConfirmation() {
|
||||
this.isPrinting$.next(true);
|
||||
const orders = await this.displayOrders$.pipe(first()).toPromise();
|
||||
await this.uiModal
|
||||
.open({
|
||||
content: PrintModalComponent,
|
||||
data: {
|
||||
printerType: 'Label',
|
||||
print: async (printer) => {
|
||||
try {
|
||||
const result = await this.domainPrinterService.printOrder({ orderIds: orders.map((o) => o.id), printer }).toPromise();
|
||||
this._toaster.open({ type: 'success', message: 'Bestellbestätigung wurde gedruckt' });
|
||||
return result;
|
||||
} catch (error) {
|
||||
this._toaster.open({ type: 'danger', message: 'Fehler beim Drucken der Bestellbestätigung' });
|
||||
}
|
||||
const selectedPrinter = await this.domainPrinterService
|
||||
.getAvailableLabelPrinters()
|
||||
.pipe(
|
||||
first(),
|
||||
map((printers) => {
|
||||
if (Array.isArray(printers)) return printers.find((printer) => printer.selected === true);
|
||||
})
|
||||
)
|
||||
.toPromise();
|
||||
|
||||
console.log(selectedPrinter);
|
||||
if (!selectedPrinter || this.isTablet) {
|
||||
await this.uiModal
|
||||
.open({
|
||||
content: PrintModalComponent,
|
||||
data: {
|
||||
printerType: 'Label',
|
||||
printImmediately: !this.isTablet,
|
||||
print: async (printer) => {
|
||||
try {
|
||||
const result = await this.domainPrinterService.printOrder({ orderIds: orders.map((o) => o.id), printer }).toPromise();
|
||||
this._toaster.open({ type: 'success', message: 'Bestellbestätigung wurde gedruckt' });
|
||||
return result;
|
||||
} catch (error) {
|
||||
this._toaster.open({ type: 'danger', message: 'Fehler beim Drucken der Bestellbestätigung' });
|
||||
} finally {
|
||||
this.isPrinting$.next(false);
|
||||
}
|
||||
},
|
||||
} as PrintModalData,
|
||||
config: {
|
||||
panelClass: [],
|
||||
showScrollbarY: false,
|
||||
},
|
||||
} as PrintModalData,
|
||||
config: {
|
||||
panelClass: [],
|
||||
showScrollbarY: false,
|
||||
},
|
||||
})
|
||||
.afterClosed$.toPromise();
|
||||
})
|
||||
.afterClosed$.toPromise();
|
||||
this.isPrinting$.next(false);
|
||||
} else {
|
||||
try {
|
||||
const result = await this.domainPrinterService
|
||||
.printOrder({ orderIds: orders.map((o) => o.id), printer: selectedPrinter.key })
|
||||
.toPromise();
|
||||
this._toaster.open({ type: 'success', message: 'Bestellbestätigung wurde gedruckt' });
|
||||
return result;
|
||||
} catch (error) {
|
||||
this._toaster.open({ type: 'danger', message: 'Fehler beim Drucken der Bestellbestätigung' });
|
||||
} finally {
|
||||
this.isPrinting$.next(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +140,19 @@
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</div>
|
||||
<div class="page-customer-order-details-item__tracking-details" *ngIf="getOrderItemTrackingData(orderItem); let trackingData">
|
||||
<div class="label">{{ trackingData.length > 1 ? 'Sendungsnummern' : 'Sendungsnummer' }}</div>
|
||||
<ng-container *ngFor="let tracking of trackingData">
|
||||
<ng-container *ngIf="tracking.trackingProvider === 'DHL' && !isNative; else noTrackingLink">
|
||||
<a class="value text-[#0556B4]" [href]="getTrackingNumberLink(tracking.trackingNumber)" target="_blank"
|
||||
>{{ tracking.trackingProvider }}: {{ tracking.trackingNumber }}</a
|
||||
>
|
||||
</ng-container>
|
||||
<ng-template #noTrackingLink>
|
||||
<p class="value">{{ tracking.trackingProvider }}: {{ tracking.trackingNumber }}</p>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<hr class="border-[#EDEFF0] border-t-2 my-4" />
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ button {
|
||||
|
||||
.page-customer-order-details-item__thumbnail {
|
||||
img {
|
||||
@apply rounded shadow-cta w-[3.625rem] h-[5.9375rem];
|
||||
@apply rounded shadow-cta w-[3.625rem] max-h-[5.9375rem];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,18 @@ button {
|
||||
}
|
||||
}
|
||||
|
||||
.page-customer-order-details-item__tracking-details {
|
||||
@apply flex gap-x-7;
|
||||
|
||||
.label {
|
||||
@apply w-[8.125rem];
|
||||
}
|
||||
|
||||
.value {
|
||||
@apply flex flex-row items-center font-bold;
|
||||
}
|
||||
}
|
||||
|
||||
.page-customer-order-details-item__comment {
|
||||
textarea {
|
||||
@apply w-full flex-grow rounded bg-[#EDEFF0] border-[#AEB7C1] border border-solid outline-none text-p2 p-4;
|
||||
|
||||
@@ -18,6 +18,7 @@ import { isEqual } from 'lodash';
|
||||
import { combineLatest, NEVER, Subject, Observable } from 'rxjs';
|
||||
import { catchError, filter, first, map, switchMap, withLatestFrom } from 'rxjs/operators';
|
||||
import { CustomerOrderDetailsStore } from '../customer-order-details.store';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
|
||||
export interface CustomerOrderDetailsItemComponentState {
|
||||
orderItem?: OrderItemListItemDTO;
|
||||
@@ -142,11 +143,16 @@ export class CustomerOrderDetailsItemComponent extends ComponentStore<CustomerOr
|
||||
|
||||
private _onDestroy$ = new Subject();
|
||||
|
||||
get isNative() {
|
||||
return this._environment.isNative();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _store: CustomerOrderDetailsStore,
|
||||
private _domainReceiptService: DomainReceiptService,
|
||||
private _omsService: DomainOmsService,
|
||||
private _cdr: ChangeDetectorRef
|
||||
private _cdr: ChangeDetectorRef,
|
||||
private _environment: EnvironmentService
|
||||
) {
|
||||
super({
|
||||
more: false,
|
||||
@@ -231,6 +237,35 @@ export class CustomerOrderDetailsItemComponent extends ComponentStore<CustomerOr
|
||||
return orderItems?.find((orderItem) => orderItem.data.id === orderItemListItem.orderItemId)?.data?.features?.orderType;
|
||||
}
|
||||
|
||||
getOrderItemTrackingData(orderItemListItem: OrderItemListItemDTO): Array<{ trackingProvider: string; trackingNumber: string }> {
|
||||
const orderItems = this.order?.items;
|
||||
const completeTrackingInformation = orderItems
|
||||
?.find((orderItem) => orderItem.data.id === orderItemListItem.orderItemId)
|
||||
?.data?.subsetItems?.find((subsetItem) => subsetItem.id === orderItemListItem.orderItemSubsetId)?.data?.trackingNumber;
|
||||
|
||||
if (!completeTrackingInformation) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Beispielnummer: 'DHL: 124124' - Bei mehreren Tracking-Informationen muss noch ein Splitter eingebaut werden, je nach dem welcher Trenner verwendet wird
|
||||
const trackingInformationPairs = completeTrackingInformation.split(':').map((obj) => obj.trim());
|
||||
return this._trackingTransformationHelper(trackingInformationPairs);
|
||||
}
|
||||
|
||||
// Macht aus einem String Array ein Array von Objekten mit den keys trackingProvider und trackingNumber
|
||||
private _trackingTransformationHelper(trackingInformationPairs: string[]): Array<{ trackingProvider: string; trackingNumber: string }> {
|
||||
return trackingInformationPairs.reduce((acc, current, index, array) => {
|
||||
if (index % 2 === 0) {
|
||||
acc.push({ trackingProvider: current, trackingNumber: array[index + 1] });
|
||||
}
|
||||
return acc;
|
||||
}, [] as { trackingProvider: string; trackingNumber: string }[]);
|
||||
}
|
||||
|
||||
getTrackingNumberLink(trackingNumber: string) {
|
||||
return `https://www.dhl.de/de/privatkunden/dhl-sendungsverfolgung.html?piececode=${trackingNumber}`;
|
||||
}
|
||||
|
||||
triggerResize() {
|
||||
this.autosize.reset();
|
||||
}
|
||||
|
||||
@@ -345,7 +345,7 @@ export class CustomerOrderDetailsComponent implements OnInit, AfterViewInit, OnD
|
||||
if (action.command.includes('ARRIVED')) {
|
||||
navigateTo = await this.arrivedActionNavigation();
|
||||
}
|
||||
if (action.command.includes('PRINT_PRICEDIFFQRCODELABEL')) {
|
||||
if (action.command.includes('PRINT_PRICEDIFFQRCODELABEL') || action.command.includes('BACKTOSTOCK')) {
|
||||
navigateTo = 'main';
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
>
|
||||
<div class="page-customer-order-item__item-thumbnail text-center mr-4 w-[3.125rem] h-[4.9375rem]">
|
||||
<img
|
||||
class="page-customer-order-item__item-image w-[3.125rem] h-[4.9375rem]"
|
||||
class="page-customer-order-item__item-image w-[3.125rem] max-h-[4.9375rem]"
|
||||
loading="lazy"
|
||||
*ngIf="item?.product?.ean | productImage; let productImage"
|
||||
[src]="productImage"
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
[tabindex]="tabIndexStart"
|
||||
[autofocus]="focusAfterInit"
|
||||
>
|
||||
<shared-select-option [value]="2">Herr</shared-select-option>
|
||||
<shared-select-option [value]="4">Frau</shared-select-option>
|
||||
<shared-select-option *ngFor="let gender of genderSettings.genders" [value]="gender.value">{{ gender.label }}</shared-select-option>
|
||||
</shared-select>
|
||||
</shared-form-control>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { FormBlockGroup } from '../form-block';
|
||||
import { NameFormBlockData } from './name-form-block-data';
|
||||
import { Gender } from '@swagger/crm';
|
||||
import { GenderSettingsService } from '@shared/services';
|
||||
|
||||
@Component({
|
||||
selector: 'app-name-form-block',
|
||||
@@ -15,18 +15,7 @@ export class NameFormBlockComponent extends FormBlockGroup<NameFormBlockData> {
|
||||
return this.tabIndexStart + 3;
|
||||
}
|
||||
|
||||
displayGenderNameFn = (gender: Gender) => {
|
||||
if (gender == 2) {
|
||||
return 'Herr';
|
||||
}
|
||||
if (gender == 4) {
|
||||
return 'Frau';
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
constructor() {
|
||||
constructor(public genderSettings: GenderSettingsService) {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ import { AbstractControl, AsyncValidatorFn, UntypedFormControl, UntypedFormGroup
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
import { AddressDTO, CustomerDTO, CustomerInfoDTO, PayerDTO, ShippingAddressDTO } from '@swagger/crm';
|
||||
import { AddressDTO, CustomerDTO, PayerDTO, ShippingAddressDTO } from '@swagger/crm';
|
||||
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
|
||||
import { UiValidators } from '@ui/validators';
|
||||
import { isNull, merge } from 'lodash';
|
||||
import { isNull } from 'lodash';
|
||||
import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
|
||||
import {
|
||||
first,
|
||||
@@ -106,7 +106,8 @@ export abstract class AbstractCreateCustomer implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.updateBreadcrumb(this.latestProcessId, this.formData);
|
||||
// Fix für #4676 - Breadcrumb wurde beim Schließen des Prozesses neu erstellt und nicht korrekt gelöscht
|
||||
// this.updateBreadcrumb(this.latestProcessId, this.formData);
|
||||
this.onDestroy$.next();
|
||||
this.onDestroy$.complete();
|
||||
this.busy$.complete();
|
||||
|
||||
@@ -41,7 +41,7 @@ export class CreateB2BCustomerComponent extends AbstractCreateCustomer {
|
||||
deviatingNameRequiredMarks: (keyof NameFormBlockData)[] = ['gender', 'firstName', 'lastName'];
|
||||
|
||||
deviatingNameValidationFns: Record<string, ValidatorFn[]> = {
|
||||
gender: [Validators.required, Validators.min(1)],
|
||||
gender: [Validators.required],
|
||||
firstName: [Validators.required],
|
||||
lastName: [Validators.required],
|
||||
};
|
||||
|
||||
@@ -25,7 +25,7 @@ export class CreateGuestCustomerComponent extends AbstractCreateCustomer {
|
||||
nameValidationFns: Record<keyof NameFormBlockData, ValidatorFn[]> = {
|
||||
firstName: [Validators.required],
|
||||
lastName: [Validators.required],
|
||||
gender: [Validators.required, Validators.min(1)],
|
||||
gender: [Validators.required],
|
||||
title: [],
|
||||
};
|
||||
|
||||
@@ -44,7 +44,7 @@ export class CreateGuestCustomerComponent extends AbstractCreateCustomer {
|
||||
deviatingNameRequiredMarks: (keyof NameFormBlockData)[] = ['gender', 'firstName', 'lastName'];
|
||||
|
||||
deviatingNameValidationFns: Record<string, ValidatorFn[]> = {
|
||||
gender: [Validators.required, Validators.min(1)],
|
||||
gender: [Validators.required],
|
||||
firstName: [Validators.required],
|
||||
lastName: [Validators.required],
|
||||
};
|
||||
|
||||
@@ -64,6 +64,12 @@
|
||||
>
|
||||
</app-name-form-block>
|
||||
|
||||
<p class="info" *ngIf="customerType === 'webshop-p4m'">
|
||||
Wir werden Ihnen Werbung zu ähnlichen Produkten oder Dienstleistungen aus unserem Sortiment per E-Mail zusenden. Sie können der
|
||||
Verwendung Ihrer Daten jederzeit z.B. mittels der in den E-Mails enthaltenen Abmeldelinks widersprechen, ohne dass hierfür andere als
|
||||
die Übermittlungskosten nach den Basistarifen entstehen.
|
||||
</p>
|
||||
|
||||
<app-email-form-block
|
||||
class="flex-grow"
|
||||
#email
|
||||
|
||||
@@ -36,7 +36,7 @@ export class CreateP4MCustomerComponent extends AbstractCreateCustomer implement
|
||||
nameValidationFns: Record<keyof NameFormBlockData, ValidatorFn[]> = {
|
||||
firstName: [Validators.required],
|
||||
lastName: [Validators.required],
|
||||
gender: [Validators.required, Validators.min(1)],
|
||||
gender: [Validators.required],
|
||||
title: [],
|
||||
};
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ export class CreateStoreCustomerComponent extends AbstractCreateCustomer {
|
||||
|
||||
nameValidationFns: Record<string, ValidatorFn[]> = {
|
||||
title: [],
|
||||
gender: [Validators.required, Validators.min(1)],
|
||||
gender: [Validators.required],
|
||||
firstName: [Validators.required],
|
||||
lastName: [Validators.required],
|
||||
};
|
||||
|
||||
@@ -25,7 +25,7 @@ export class CreateWebshopCustomerComponent extends AbstractCreateCustomer {
|
||||
nameValidationFns: Record<keyof NameFormBlockData, ValidatorFn[]> = {
|
||||
firstName: [Validators.required],
|
||||
lastName: [Validators.required],
|
||||
gender: [Validators.required, Validators.min(1)],
|
||||
gender: [Validators.required],
|
||||
title: [],
|
||||
};
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ export class UpdateP4MWebshopCustomerComponent extends AbstractCreateCustomer im
|
||||
nameValidationFns: Record<keyof NameFormBlockData, ValidatorFn[]> = {
|
||||
firstName: [Validators.required],
|
||||
lastName: [Validators.required],
|
||||
gender: [Validators.required, Validators.min(1)],
|
||||
gender: [Validators.required],
|
||||
title: [],
|
||||
};
|
||||
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
<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-option *ngFor="let gender of genderSettings.genders" [value]="gender.value">{{ gender.label }}</shared-select-option>
|
||||
</shared-select>
|
||||
</shared-form-control>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { map } 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 '@shared/services';
|
||||
import { CustomerSearchNavigation, GenderSettingsService } from '@shared/services';
|
||||
import { IconComponent } from '@shared/components/icon';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { RouterLink } from '@angular/router';
|
||||
@@ -35,7 +35,7 @@ import { RouterLink } from '@angular/router';
|
||||
})
|
||||
export class AddBillingAddressMainViewComponent {
|
||||
formGroup = new FormGroup({
|
||||
gender: new FormControl<Gender>(0, [Validators.required, Validators.min(1)]),
|
||||
gender: new FormControl<Gender>(undefined, [Validators.required]),
|
||||
title: new FormControl<string>(undefined),
|
||||
firstName: new FormControl<string>(undefined, [Validators.required]),
|
||||
lastName: new FormControl<string>(undefined, [Validators.required]),
|
||||
@@ -59,7 +59,8 @@ export class AddBillingAddressMainViewComponent {
|
||||
private _customerService: CrmCustomerService,
|
||||
private _addressSelection: AddressSelectionModalService,
|
||||
private _store: CustomerSearchStore,
|
||||
private _navigation: CustomerSearchNavigation
|
||||
private _navigation: CustomerSearchNavigation,
|
||||
public genderSettings: GenderSettingsService
|
||||
) {}
|
||||
|
||||
async save() {
|
||||
|
||||
@@ -27,8 +27,7 @@
|
||||
|
||||
<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-option *ngFor="let gender of genderSettings.genders" [value]="gender.value">{{ gender.label }}</shared-select-option>
|
||||
</shared-select>
|
||||
</shared-form-control>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ 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 '@shared/services';
|
||||
import { CustomerSearchNavigation, GenderSettingsService } from '@shared/services';
|
||||
import { Subject, combineLatest } from 'rxjs';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { IconComponent } from '@shared/components/icon';
|
||||
@@ -41,7 +41,7 @@ export class AddShippingAddressMainViewComponent implements OnInit, OnDestroy {
|
||||
);
|
||||
|
||||
formGroup = new FormGroup({
|
||||
gender: new FormControl<Gender>(0, [Validators.required, Validators.min(1)]),
|
||||
gender: new FormControl<Gender>(undefined, [Validators.required]),
|
||||
title: new FormControl<string>(undefined),
|
||||
firstName: new FormControl<string>(undefined, [Validators.required]),
|
||||
lastName: new FormControl<string>(undefined, [Validators.required]),
|
||||
@@ -65,7 +65,8 @@ export class AddShippingAddressMainViewComponent implements OnInit, OnDestroy {
|
||||
private _customerService: CrmCustomerService,
|
||||
private _addressSelection: AddressSelectionModalService,
|
||||
private _store: CustomerSearchStore,
|
||||
private _navigation: CustomerSearchNavigation
|
||||
private _navigation: CustomerSearchNavigation,
|
||||
public genderSettings: GenderSettingsService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
@@ -39,7 +39,9 @@
|
||||
<div class="customer-details-customer-main-data px-5 py-3 grid grid-flow-row gap-3">
|
||||
<div class="flex flex-row">
|
||||
<div class="data-label">Erstellungsdatum</div>
|
||||
<div class="data-value">{{ created$ | async | date: 'dd.MM.yyyy' }} | {{ created$ | async | date: 'HH:mm' }} Uhr</div>
|
||||
<div *ngIf="created$ | async; let created" class="data-value">
|
||||
{{ created | date: 'dd.MM.yyyy' }} | {{ created | date: 'HH:mm' }} Uhr
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row">
|
||||
<div class="data-label">Kundennummer</div>
|
||||
@@ -111,7 +113,7 @@
|
||||
</div>
|
||||
<div class="customer-details-customer-main-row">
|
||||
<div class="data-label">Land</div>
|
||||
<div class="data-value">{{ country$ | async | country }}</div>
|
||||
<div *ngIf="country$ | async; let country" class="data-value">{{ country | country }}</div>
|
||||
</div>
|
||||
<div class="customer-details-customer-main-row">
|
||||
<div class="data-label">Festnetznr.</div>
|
||||
@@ -123,6 +125,16 @@
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="!(isBusinessKonto$ | async)">
|
||||
<div class="customer-details-customer-main-row">
|
||||
<div class="data-label">Geburtstag</div>
|
||||
<div class="data-value">{{ dateOfBirth$ | async | date: 'dd.MM.yyyy' }}</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!(isBusinessKonto$ | async) && (organisationName$ | 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>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, inject } from '@angular/core';
|
||||
import { Subject, combineLatest } from 'rxjs';
|
||||
import { first, map, switchMap, takeUntil } from 'rxjs/operators';
|
||||
import { CustomerSearchNavigation } from '@shared/services';
|
||||
import { CustomerSearchNavigation, GenderSettingsService } from '@shared/services';
|
||||
import { CustomerSearchStore } from '../store';
|
||||
import { ShippingAddressDTO, NotificationChannel, ShoppingCartDTO, PayerDTO, BuyerDTO } from '@swagger/checkout';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
@@ -10,16 +10,11 @@ import { UiModalService } from '@ui/modal';
|
||||
import { ComponentStore } from '@ngrx/component-store';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { CheckoutNavigationService, ProductCatalogNavigationService } from '@shared/services';
|
||||
import { Router } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { log, logAsync } from '@utils/common';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
import { MessageModalComponent, MessageModalData } from '@shared/modals/message-modal';
|
||||
|
||||
const GENDER_MAP = {
|
||||
2: 'Herr',
|
||||
4: 'Frau',
|
||||
};
|
||||
|
||||
export interface CustomerDetailsViewMainState {
|
||||
isBusy: boolean;
|
||||
shoppingCart: ShoppingCartDTO;
|
||||
@@ -38,7 +33,9 @@ export class CustomerDetailsViewMainComponent extends ComponentStore<CustomerDet
|
||||
|
||||
customerService = inject(CrmCustomerService);
|
||||
|
||||
fetching$ = this._store.fetchingCustomer$;
|
||||
fetching$ = combineLatest([this._store.fetchingCustomer$, this._store.fetchingCustomerList$]).pipe(
|
||||
map(([fetchingCustomer, fetchingList]) => fetchingCustomer || fetchingList)
|
||||
);
|
||||
|
||||
isBusy$ = this.select((s) => s.isBusy);
|
||||
|
||||
@@ -86,7 +83,7 @@ export class CustomerDetailsViewMainComponent extends ComponentStore<CustomerDet
|
||||
|
||||
customerNumberBeeline$ = this._store.select((s) => s.customer?.linkedRecords?.find((r) => r.repository === 'beeline')?.number);
|
||||
|
||||
gender$ = this._store.select((s) => GENDER_MAP[s.customer?.gender]);
|
||||
gender$ = this._store.select((s) => this._genderSettings.getGenderByValue(s.customer?.gender));
|
||||
|
||||
title$ = this._store.select((s) => s.customer?.title);
|
||||
|
||||
@@ -124,6 +121,8 @@ export class CustomerDetailsViewMainComponent extends ComponentStore<CustomerDet
|
||||
|
||||
shoppingCartHasNoItems$ = this.shoppingCartHasItems$.pipe(map((hasItems) => !hasItems));
|
||||
|
||||
dateOfBirth$ = this._store.select((s) => s.customer?.dateOfBirth);
|
||||
|
||||
get isBusy() {
|
||||
return this.get((s) => s.isBusy);
|
||||
}
|
||||
@@ -181,6 +180,10 @@ export class CustomerDetailsViewMainComponent extends ComponentStore<CustomerDet
|
||||
return this.get((s) => s.payer);
|
||||
}
|
||||
|
||||
get snapshot() {
|
||||
return this._activatedRoute.snapshot;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _store: CustomerSearchStore,
|
||||
private _navigation: CustomerSearchNavigation,
|
||||
@@ -189,7 +192,9 @@ export class CustomerDetailsViewMainComponent extends ComponentStore<CustomerDet
|
||||
private _application: ApplicationService,
|
||||
private _catalogNavigation: ProductCatalogNavigationService,
|
||||
private _checkoutNavigation: CheckoutNavigationService,
|
||||
private _router: Router
|
||||
private _router: Router,
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _genderSettings: GenderSettingsService
|
||||
) {
|
||||
super({ isBusy: false, shoppingCart: undefined, shippingAddress: undefined, payer: undefined });
|
||||
}
|
||||
@@ -222,6 +227,21 @@ export class CustomerDetailsViewMainComponent extends ComponentStore<CustomerDet
|
||||
.subscribe((shoppingCart) => {
|
||||
this.patchState({ shoppingCart });
|
||||
});
|
||||
|
||||
// #4564 Fix - Da der Kunde bei einer erneuten Suche auf undefined gesetzt wird, muss man diesen erneut nach erfolgreicher Suche setzen.
|
||||
// Dies geschieht bereits in der customer-search.component.ts immer wenn eine Navigation ausgeführt wird (sprich für Fälle in denen ein neuer Kunde gesetzt wird).
|
||||
// Falls aber nach exakt dem gleichen Kunden gesucht wird, muss man diesen hier manuell erneut setzen, ansonsten bleibt dieser im Store auf undefined.
|
||||
// Da dies nur für die Detailansicht relevant ist, wird hier auch auf hits 1 überprüft, ansonsten befindet man sich sowieso in der Trefferliste.
|
||||
this._store.customerListResponse$.pipe(takeUntil(this._onDestroy$)).subscribe(([result]) => {
|
||||
if (result.hits === 1) {
|
||||
const customerId = result?.result[0].id;
|
||||
const selectedCustomerId = +this.snapshot.params.customerId;
|
||||
|
||||
if (customerId === selectedCustomerId) {
|
||||
this._store.selectCustomer({ customerId });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
@@ -409,12 +429,12 @@ export class CustomerDetailsViewMainComponent extends ComponentStore<CustomerDet
|
||||
|
||||
@log
|
||||
_patchProcessName() {
|
||||
let name = `${this.customer.firstName} ${this.customer.lastName}`;
|
||||
let name = `${this.customer.firstName ?? ''} ${this.customer.lastName ?? ''}`;
|
||||
|
||||
// Ticket #4458 Es kann vorkommen, dass B2B Konten keinen Firmennamen hinterlegt haben
|
||||
// zusätzlich kanne es bei Mitarbeiter Konten vorkommen, dass die Namen in der Organisation statt im Kundennamen hinterlegt sind
|
||||
if ((this._store.isBusinessKonto && this.customer.organisation?.name) || (!this.customer.firstName && !this.customer.lastName)) {
|
||||
name = `${this.customer.organisation?.name}`;
|
||||
name = `${this.customer.organisation?.name ?? ''}`;
|
||||
}
|
||||
|
||||
this._application.patchProcess(this.processId, {
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
<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-option *ngFor="let gender of genderSettings.genders" [value]="gender.value">{{ gender.label }}</shared-select-option>
|
||||
</shared-select>
|
||||
</shared-form-control>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ 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 '@shared/services';
|
||||
import { CustomerSearchNavigation, GenderSettingsService } from '@shared/services';
|
||||
import { ComponentStore } from '@ngrx/component-store';
|
||||
import { Subject, combineLatest } from 'rxjs';
|
||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
||||
@@ -39,7 +39,7 @@ export class EditBillingAddressMainViewComponent extends ComponentStore<EditBill
|
||||
private _cdr = inject(ChangeDetectorRef);
|
||||
|
||||
formGroup = new FormGroup({
|
||||
gender: new FormControl<Gender>(0, [Validators.required, Validators.min(1)]),
|
||||
gender: new FormControl<Gender>(undefined, [Validators.required]),
|
||||
title: new FormControl<string>(undefined),
|
||||
firstName: new FormControl<string>(undefined, [Validators.required]),
|
||||
lastName: new FormControl<string>(undefined, [Validators.required]),
|
||||
@@ -74,7 +74,8 @@ export class EditBillingAddressMainViewComponent extends ComponentStore<EditBill
|
||||
private _store: CustomerSearchStore,
|
||||
private _navigation: CustomerSearchNavigation,
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _modal: UiModalService
|
||||
private _modal: UiModalService,
|
||||
public genderSettings: GenderSettingsService
|
||||
) {
|
||||
super({ payer: undefined });
|
||||
}
|
||||
|
||||
@@ -28,8 +28,7 @@
|
||||
|
||||
<ui-form-control [clearable]="true" label="Anrede" variant="inline">
|
||||
<ui-select formControlName="gender" tabindex="4">
|
||||
<ui-select-option [value]="2" label="Herr"></ui-select-option>
|
||||
<ui-select-option [value]="4" label="Frau"></ui-select-option>
|
||||
<ui-select-option *ngFor="let gender of genderSettings.genders" [value]="gender.value" [label]="gender.label"></ui-select-option>
|
||||
</ui-select>
|
||||
</ui-form-control>
|
||||
<ui-form-control [clearable]="true" label="Titel" variant="inline">
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
<form *ngIf="control" [formGroup]="control" (ngSubmit)="submit()">
|
||||
<ui-form-control [clearable]="true" label="Anrede" variant="inline">
|
||||
<ui-select formControlName="gender" tabindex="1">
|
||||
<ui-select-option [value]="2" label="Herr"></ui-select-option>
|
||||
<ui-select-option [value]="4" label="Frau"></ui-select-option>
|
||||
<ui-select-option *ngFor="let gender of genderSettings.genders" [value]="gender.value" [label]="gender.label"></ui-select-option>
|
||||
</ui-select>
|
||||
</ui-form-control>
|
||||
<ui-form-control [clearable]="true" label="Titel" variant="inline">
|
||||
|
||||
@@ -12,7 +12,7 @@ import { validateEmail } from '../../validators/email-validator';
|
||||
import { genderLastNameValidator } from '../../validators/gender-b2b-validator';
|
||||
import { camelCase } from 'lodash';
|
||||
import { CustomerSearchStore } from '../store';
|
||||
import { CustomerSearchNavigation, NavigationRoute } from '@shared/services';
|
||||
import { CustomerSearchNavigation, GenderSettingsService, NavigationRoute } from '@shared/services';
|
||||
|
||||
@Component({ template: '' })
|
||||
export abstract class CustomerDataEditComponent implements OnInit {
|
||||
@@ -41,7 +41,8 @@ export abstract class CustomerDataEditComponent implements OnInit {
|
||||
private cdr: ChangeDetectorRef,
|
||||
private location: Location,
|
||||
private _store: CustomerSearchStore,
|
||||
private _navigation: CustomerSearchNavigation
|
||||
private _navigation: CustomerSearchNavigation,
|
||||
public genderSettings: GenderSettingsService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -90,7 +91,7 @@ export abstract class CustomerDataEditComponent implements OnInit {
|
||||
|
||||
this.control = fb.group(
|
||||
{
|
||||
gender: fb.control(customerDTO?.gender, [isBranch ? Validators.min(1) : () => null, isBranch ? Validators.required : () => null]),
|
||||
gender: fb.control(customerDTO?.gender, [isBranch ? Validators.required : () => null]),
|
||||
title: fb.control(customerDTO?.title),
|
||||
lastName: fb.control(customerDTO?.lastName, [Validators.required]),
|
||||
firstName: fb.control(customerDTO?.firstName, [Validators.required]),
|
||||
|
||||
@@ -27,8 +27,7 @@
|
||||
|
||||
<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-option *ngFor="let gender of genderSettings.genders" [value]="gender.value">{{ gender.label }}</shared-select-option>
|
||||
</shared-select>
|
||||
</shared-form-control>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { map, switchMap, 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 '@shared/services';
|
||||
import { CustomerSearchNavigation, GenderSettingsService } from '@shared/services';
|
||||
import { Subject, combineLatest } from 'rxjs';
|
||||
import { IconComponent } from '@shared/components/icon';
|
||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
||||
@@ -50,7 +50,7 @@ export class EditShippingAddressMainViewComponent extends ComponentStore<EditShi
|
||||
);
|
||||
|
||||
formGroup = new FormGroup({
|
||||
gender: new FormControl<Gender>(0, [Validators.required, Validators.min(1)]),
|
||||
gender: new FormControl<Gender>(undefined, [Validators.required]),
|
||||
title: new FormControl<string>(undefined),
|
||||
firstName: new FormControl<string>(undefined, [Validators.required]),
|
||||
lastName: new FormControl<string>(undefined, [Validators.required]),
|
||||
@@ -83,7 +83,8 @@ export class EditShippingAddressMainViewComponent extends ComponentStore<EditShi
|
||||
private _customerService: CrmCustomerService,
|
||||
private _addressSelection: AddressSelectionModalService,
|
||||
private _store: CustomerSearchStore,
|
||||
private _navigation: CustomerSearchNavigation
|
||||
private _navigation: CustomerSearchNavigation,
|
||||
public genderSettings: GenderSettingsService
|
||||
) {
|
||||
super({ shippingAddress: undefined });
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import { CrmCustomerService } from '@domain/crm';
|
||||
import { Result } from '@domain/defs';
|
||||
import { CustomerDTO, ListResponseArgsOfCustomerInfoDTO, QuerySettingsDTO } from '@swagger/crm';
|
||||
import { Filter } from '@shared/components/filter';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { DomainOmsService } from '@domain/oms';
|
||||
import { OrderDTO, OrderListItemDTO } from '@swagger/oms';
|
||||
import { hash } from '@utils/common';
|
||||
@@ -304,7 +303,10 @@ export class CustomerSearchStore extends ComponentStore<CustomerSearchState> imp
|
||||
),
|
||||
withLatestFrom(this.filter$, this.processId$),
|
||||
map(([a1, a2, a3]) => {
|
||||
this.patchState({ fetchingCustomerList: true, customerList: [], customerListCount: 0, message: '' });
|
||||
// #4564 Setze "customer" undefined immer wenn neu gesucht wird,
|
||||
// da sonst Änderungen einer zweiten ISA am Kunden, selbst nach erneuter Suche, nicht geupdated werden,
|
||||
// da noch der alte Kundendatensatz im Store gespeichert ist
|
||||
this.patchState({ fetchingCustomerList: true, customerList: [], customer: undefined, customerListCount: 0, message: '' });
|
||||
|
||||
let retored = false;
|
||||
if (a1.ignoreRestore) {
|
||||
|
||||
@@ -5,8 +5,8 @@ export function genderLastNameValidator(isB2b: boolean): ValidatorFn | null {
|
||||
return (control: UntypedFormGroup): ValidationErrors | null => {
|
||||
const gender = control.get('gender').value;
|
||||
const lastName = control.get('lastName').value;
|
||||
if (!!lastName && gender === 0) {
|
||||
control.get('gender').setValidators([Validators.required, Validators.min(1)]);
|
||||
if (!!lastName) {
|
||||
control.get('gender').setValidators([Validators.required]);
|
||||
return { genderNotSet: true };
|
||||
} else {
|
||||
control.get('gender').setValidators(null);
|
||||
|
||||
@@ -16,7 +16,7 @@ export function organisationB2bDeliveryValidator(): ValidatorFn | null {
|
||||
lastName = control.get('shippingAddress').get('lastName');
|
||||
organisation = control.get('shippingAddress').get('organisation').get('name');
|
||||
isOrganisationSet = !!organisation.value;
|
||||
isNameSet = gender.value !== 0 && !!firstName.value && !!lastName.value;
|
||||
isNameSet = !!firstName.value && !!lastName.value;
|
||||
|
||||
if (control.get('differentShippingAddress').value === true) {
|
||||
return validate(gender, firstName, lastName, organisation, isOrganisationSet, isNameSet);
|
||||
@@ -28,14 +28,14 @@ export function organisationB2bDeliveryValidator(): ValidatorFn | null {
|
||||
lastName = control.get('lastName');
|
||||
organisation = control.get('organisation').get('name');
|
||||
isOrganisationSet = !!organisation.value;
|
||||
isNameSet = gender.value !== 0 && !!firstName.value && !!lastName.value;
|
||||
isNameSet = !!firstName.value && !!lastName.value;
|
||||
return validate(gender, firstName, lastName, organisation, isOrganisationSet, isNameSet);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function setNameValidation(gender: AbstractControl, firstName: AbstractControl, lastName: AbstractControl) {
|
||||
gender.setValidators([Validators.required, Validators.min(1)]);
|
||||
gender.setValidators([Validators.required]);
|
||||
firstName.setValidators([Validators.required]);
|
||||
lastName.setValidators([Validators.required]);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
ui-slider {
|
||||
img {
|
||||
@apply rounded cursor-pointer;
|
||||
height: 160px;
|
||||
max-height: 160px;
|
||||
|
||||
// max-width: aut;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
}
|
||||
|
||||
.package-details-list-item__product-image {
|
||||
@apply w-12 h-auto shadow;
|
||||
@apply w-12 shadow max-h-full;
|
||||
}
|
||||
|
||||
@screen desktop {
|
||||
@@ -20,7 +20,7 @@
|
||||
}
|
||||
|
||||
.package-details-list-item__product-image {
|
||||
@apply w-auto h-full shadow mx-auto;
|
||||
@apply w-auto max-h-full shadow mx-auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,13 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Breadcrumb, BreadcrumbService } from '@core/breadcrumb';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { NavigationRoute } from '@shared/services';
|
||||
import { DBHOrderItemListItemDTO, KeyValueDTOOfStringAndString } from '@swagger/oms';
|
||||
import { DBHOrderItemListItemDTO, KeyValueDTOOfStringAndString, ListResponseArgsOfDBHOrderItemListItemDTO } from '@swagger/oms';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { Observable } from 'rxjs';
|
||||
import { RunCheckTrigger } from './trigger';
|
||||
import { OrderItemsContext } from '@domain/oms';
|
||||
import { ActionHandlerService } from './services/action-handler.service';
|
||||
import { Config } from '@core/config';
|
||||
import { debounce } from '@utils/common';
|
||||
|
||||
export type GetNameForBreadcrumbData = {
|
||||
processId: number;
|
||||
@@ -125,13 +124,13 @@ export abstract class PickupShelfBaseComponent implements OnInit {
|
||||
const filterQueryParams = this.listStore.filter.getQueryParams();
|
||||
|
||||
// Only Update QueryParams if the user is already on the details, edit or history page
|
||||
const view: string = this.activatedRoute.snapshot.data.view;
|
||||
if (['filter', 'details', 'edit', 'history'].includes(view)) {
|
||||
await this.router.navigate([], { queryParams: { ...queryParams, ...filterQueryParams }, skipLocationChange: true });
|
||||
return;
|
||||
}
|
||||
// const view: string = this.activatedRoute.snapshot.data.view;
|
||||
// if (['filter', 'details', 'edit', 'history'].includes(view)) {
|
||||
// await this.router.navigate([], { queryParams: { ...queryParams, ...filterQueryParams }, skipLocationChange: true });
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (response.hits === 1) {
|
||||
if (response.hits === 1 || this._hasSameOrderNumber(response)) {
|
||||
const detailsPath = await this.getPathForDetail(response.result[0]).pipe(take(1)).toPromise();
|
||||
await this.router.navigate(detailsPath.path, { queryParams: { ...queryParams, ...filterQueryParams, ...detailsPath.queryParams } });
|
||||
} else if (response.hits > 1) {
|
||||
@@ -143,6 +142,13 @@ export abstract class PickupShelfBaseComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
// Fix Ticket #4684 Navigate on Details if items contain same OrderNumber
|
||||
private _hasSameOrderNumber(response: ListResponseArgsOfDBHOrderItemListItemDTO) {
|
||||
if (response.hits === 0) return false;
|
||||
const orderNumbers = new Set(response.result.map((item) => item.orderNumber));
|
||||
return orderNumbers.size === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sucht die Breadcrumb anhand des Tags.
|
||||
* @param tag Der gesuchte Tag
|
||||
|
||||
@@ -43,6 +43,7 @@ export abstract class PickupShelfDetailsBaseComponent {
|
||||
this.store.resetCoverItems();
|
||||
}
|
||||
this.store.fetchOrder({ orderId: Number(params.orderId) });
|
||||
|
||||
this.store.fetchOrderItems({
|
||||
orderNumber: params.orderNumber ? decodeURIComponent(params.orderNumber) : undefined,
|
||||
compartmentCode: params.compartmentCode ? decodeURIComponent(params.compartmentCode) : undefined,
|
||||
@@ -124,6 +125,7 @@ export abstract class PickupShelfDetailsBaseComponent {
|
||||
processingStatus: updatedItem.processingStatus,
|
||||
compartmentCode: updatedItem.compartmentCode,
|
||||
compartmentInfo: updatedItem.compartmentInfo,
|
||||
quantity: updatedItem.quantity,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,13 +10,14 @@ import { UiSpinnerModule } from '@ui/spinner';
|
||||
import { OnInitDirective } from '@shared/directives/element-lifecycle';
|
||||
import { PickupShelfInNavigationService } from '@shared/services';
|
||||
import { BehaviorSubject, asapScheduler, combineLatest } from 'rxjs';
|
||||
import { map, shareReplay } from 'rxjs/operators';
|
||||
import { distinctUntilChanged, map, shareReplay } from 'rxjs/operators';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { DBHOrderItemListItemDTO, KeyValueDTOOfStringAndString } from '@swagger/oms';
|
||||
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { RunCheckTrigger } from '../../trigger';
|
||||
import { PickUpShelfDetailsItemsGroupComponent } from '../../shared/pickup-shelf-details-items-group/pickup-shelf-details-items-group.component';
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
@Component({
|
||||
selector: 'page-pickup-shelf-in-details',
|
||||
@@ -49,7 +50,7 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
|
||||
|
||||
order$ = this.store.order$;
|
||||
|
||||
orderItems$ = this.store.orderItems$.pipe(shareReplay());
|
||||
orderItems$ = this.store.orderItems$.pipe(shareReplay(1));
|
||||
|
||||
noOrderItemsFound$ = this.store.noOrderItemsFound$;
|
||||
|
||||
@@ -102,7 +103,7 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
combineLatest([this._activatedRoute.params, this.orderItems$])
|
||||
combineLatest([this._activatedRoute.params.pipe(distinctUntilChanged(isEqual)), this.orderItems$.pipe(distinctUntilChanged(isEqual))])
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe(([params, items]) => {
|
||||
const orderItemSubsetId = +params?.orderItemSubsetId;
|
||||
@@ -141,11 +142,14 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
|
||||
try {
|
||||
this.changeActionLoader$.next(action.command);
|
||||
this.store.setDisableHeaderStatusDropdown(true);
|
||||
|
||||
const context = await this.execAction({ action, latestCompartmentCode, latestCompartmentInfo });
|
||||
|
||||
if (!!context) {
|
||||
if (action.command.includes('ARRIVED') || action.command.includes('PRINT_PRICEDIFFQRCODELABEL')) {
|
||||
if (
|
||||
action.command.includes('ARRIVED') ||
|
||||
action.command.includes('PRINT_PRICEDIFFQRCODELABEL') ||
|
||||
action.command.includes('BACKTOSTOCK')
|
||||
) {
|
||||
asapScheduler.schedule(async () => {
|
||||
await this.navigateBasedOnCurrentView();
|
||||
}, 100);
|
||||
@@ -210,17 +214,17 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
|
||||
updateDate({ date, type }: { date: Date; type?: 'delivery' | 'pickup' | 'preferred' }) {
|
||||
switch (type) {
|
||||
case 'delivery':
|
||||
this.store.orderItems.forEach((item) =>
|
||||
this.store.selectedOrderItems.forEach((item) =>
|
||||
this.store.patchOrderItemSubset({ item, changes: { estimatedShippingDate: date.toISOString() } })
|
||||
);
|
||||
break;
|
||||
case 'pickup':
|
||||
this.store.orderItems.forEach((item) =>
|
||||
this.store.selectedOrderItems.forEach((item) =>
|
||||
this.store.patchOrderItemSubset({ item, changes: { compartmentStop: date.toISOString() } })
|
||||
);
|
||||
break;
|
||||
case 'preferred':
|
||||
this.store.orderItems.forEach((item) =>
|
||||
this.store.selectedOrderItems.forEach((item) =>
|
||||
this.store.patchOrderItemSubset({ item, changes: { preferredPickUpDate: date.toISOString() } })
|
||||
);
|
||||
break;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<shared-goods-in-out-order-edit
|
||||
*ngIf="store.orderItems$ | async; let items"
|
||||
(navigation)="navigateToShelfInDetailsPage($event)"
|
||||
[items]="items"
|
||||
></shared-goods-in-out-order-edit>
|
||||
<ng-container *ngIf="store.selectedOrderItem$ | async; let item">
|
||||
<shared-goods-in-out-order-edit
|
||||
*ngIf="item"
|
||||
(navigation)="navigateToShelfInDetailsPage($event)"
|
||||
[items]="[item]"
|
||||
></shared-goods-in-out-order-edit>
|
||||
</ng-container>
|
||||
|
||||
@@ -20,15 +20,23 @@ export class PickupShelfInEditComponent extends PickupShelfDetailsBaseComponent
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.listStore;
|
||||
}
|
||||
|
||||
async navigateToShelfInDetailsPage(changes?: Partial<DBHOrderItemListItemDTO>) {
|
||||
const orderId = (await this.store.orderItems$.pipe(first()).toPromise())?.find((_) => true)?.orderId;
|
||||
const orderNumber = this.activatedRoute?.snapshot?.params?.orderNumber;
|
||||
const compartmentCode = changes?.compartmentCode ?? this.activatedRoute?.snapshot?.params?.compartmentCode;
|
||||
const orderNumber = decodeURIComponent(this.activatedRoute?.snapshot?.params?.orderNumber);
|
||||
let compartmentCode = changes?.compartmentCode ?? this.activatedRoute?.snapshot?.params?.compartmentCode;
|
||||
const processingStatus = changes?.processingStatus ?? this.activatedRoute.snapshot.params.orderItemProcessingStatus;
|
||||
const compartmentInfo = changes?.compartmentInfo ?? this.activatedRoute.snapshot.params.compartmentInfo;
|
||||
let compartmentInfo = changes?.compartmentInfo ?? this.activatedRoute.snapshot.params.compartmentInfo;
|
||||
const item = this.store?.selectedOrderItem;
|
||||
|
||||
if (compartmentCode) {
|
||||
compartmentCode = decodeURIComponent(compartmentCode);
|
||||
}
|
||||
|
||||
if (compartmentInfo) {
|
||||
compartmentInfo = decodeURIComponent(compartmentInfo);
|
||||
}
|
||||
|
||||
await this.router.navigate(
|
||||
this.shelfInNavigation.detailRoute({
|
||||
@@ -38,7 +46,7 @@ export class PickupShelfInEditComponent extends PickupShelfDetailsBaseComponent
|
||||
compartmentCode,
|
||||
processingStatus,
|
||||
compartmentInfo,
|
||||
orderItemSubsetId: this.store?.selectPreviousSelectedOrderItemSubsetId,
|
||||
orderItemSubsetId: item?.orderItemSubsetId,
|
||||
},
|
||||
side: this.side,
|
||||
}).path,
|
||||
|
||||
@@ -79,7 +79,7 @@ export class PickUpShelfInListComponent implements OnInit, AfterViewInit {
|
||||
})
|
||||
);
|
||||
|
||||
fetching$: Observable<boolean> = this.store.fetching$;
|
||||
fetching$: Observable<boolean> = this.store.fetchingList$;
|
||||
|
||||
searchboxHint$ = this.store.searchboxHint$;
|
||||
|
||||
@@ -126,7 +126,7 @@ export class PickUpShelfInListComponent implements OnInit, AfterViewInit {
|
||||
.subscribe(([_, queryParams]) => {
|
||||
if (!this.store.list.length || !isEqual(queryParams, this.cleanupQueryParams(this.store.filter.getQueryParams()))) {
|
||||
this.store.setQueryParams(queryParams);
|
||||
this.store.fetchList();
|
||||
this.store.fetchList({ emitFetchListResponse: false });
|
||||
}
|
||||
|
||||
const scrollPos = this._getScrollPositionFromCache();
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<div class="flex flex-row px-12 justify-center desktop-large:px-0">
|
||||
<shared-filter-input-group-main
|
||||
class="block w-full mr-3 desktop-large:mx-auto"
|
||||
*ngIf="filter$ | async; let filter"
|
||||
[inputGroup]="filter?.input | group: 'main'"
|
||||
[hint]="searchboxHint$ | async"
|
||||
[loading]="fetching$ | async"
|
||||
|
||||
@@ -38,7 +38,7 @@ export class PickUpShelfInMainSideViewComponent implements OnInit {
|
||||
})
|
||||
);
|
||||
|
||||
fetching$: Observable<boolean> = this.store.fetching$;
|
||||
fetching$: Observable<boolean> = this.store.fetchingList$;
|
||||
|
||||
searchboxHint$ = this.store.searchboxHint$;
|
||||
|
||||
|
||||
@@ -105,7 +105,11 @@ export class PickupShelfOutDetailsComponent extends PickupShelfDetailsBaseCompon
|
||||
const context = await this.execAction({ action });
|
||||
|
||||
if (!!context) {
|
||||
if (action.command.includes('ARRIVED') || action.command.includes('PRINT_PRICEDIFFQRCODELABEL')) {
|
||||
if (
|
||||
action.command.includes('ARRIVED') ||
|
||||
action.command.includes('PRINT_PRICEDIFFQRCODELABEL') ||
|
||||
action.command.includes('BACKTOSTOCK')
|
||||
) {
|
||||
const nav = this._pickupShelfOutNavigationService.defaultRoute({ processId: this.processId });
|
||||
await this.router.navigate(nav.path, { queryParams: nav.queryParams, queryParamsHandling: 'preserve' });
|
||||
} else {
|
||||
|
||||
@@ -26,10 +26,18 @@ export class PickupShelfOutEditComponent extends PickupShelfDetailsBaseComponent
|
||||
|
||||
async navigateToShelfOutDetailsPage(changes: Partial<DBHOrderItemListItemDTO>) {
|
||||
const orderId = (await this.store.orderItems$.pipe(first()).toPromise())?.find((_) => true)?.orderId;
|
||||
const orderNumber = this.activatedRoute?.snapshot?.params?.orderNumber;
|
||||
const compartmentCode = changes?.compartmentCode ?? this.activatedRoute?.snapshot?.params?.compartmentCode;
|
||||
const orderNumber = decodeURIComponent(this.activatedRoute?.snapshot?.params?.orderNumber);
|
||||
let compartmentCode = changes?.compartmentCode ?? this.activatedRoute?.snapshot?.params?.compartmentCode;
|
||||
const processingStatus = changes?.processingStatus ?? this.activatedRoute.snapshot.params.orderItemProcessingStatus;
|
||||
const compartmentInfo = changes?.compartmentInfo ?? this.activatedRoute.snapshot.params.compartmentInfo;
|
||||
let compartmentInfo = changes?.compartmentInfo ?? this.activatedRoute.snapshot.params.compartmentInfo;
|
||||
|
||||
if (compartmentCode) {
|
||||
compartmentCode = decodeURIComponent(compartmentCode);
|
||||
}
|
||||
|
||||
if (compartmentInfo) {
|
||||
compartmentInfo = decodeURIComponent(compartmentInfo);
|
||||
}
|
||||
|
||||
await this.router.navigate(
|
||||
this.shelfOutNavigation.detailRoute({
|
||||
|
||||
@@ -83,7 +83,7 @@ export class PickupShelfOutListComponent implements OnInit, AfterViewInit {
|
||||
})
|
||||
);
|
||||
|
||||
fetching$: Observable<boolean> = this.store.fetching$;
|
||||
fetching$: Observable<boolean> = this.store.fetchingList$;
|
||||
|
||||
searchboxHint$ = this.store.searchboxHint$;
|
||||
|
||||
@@ -245,7 +245,7 @@ export class PickupShelfOutListComponent implements OnInit, AfterViewInit {
|
||||
action,
|
||||
items: selectedItems,
|
||||
});
|
||||
this.store.fetchList();
|
||||
this.store.fetchList({ emitFetchListResponse: false });
|
||||
this.store.resetSelectedListItems();
|
||||
this.loadingFetchedActionButton$.next(false);
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
<div class="flex flex-row px-12 justify-center desktop-large:px-0">
|
||||
<shared-filter-input-group-main
|
||||
class="block w-full mr-3 desktop-large:mx-auto"
|
||||
*ngIf="filter$ | async; let filter"
|
||||
[inputGroup]="filter?.input | group: 'main'"
|
||||
[hint]="searchboxHint$ | async"
|
||||
[loading]="fetching$ | async"
|
||||
|
||||
@@ -38,7 +38,7 @@ export class PickupShelfOutMainSideViewComponent implements OnInit {
|
||||
})
|
||||
);
|
||||
|
||||
fetching$: Observable<boolean> = this.store.fetching$;
|
||||
fetching$: Observable<boolean> = this.store.fetchingList$;
|
||||
|
||||
searchboxHint$ = this.store.searchboxHint$;
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ ui-slider {
|
||||
@apply mr-5;
|
||||
|
||||
.image {
|
||||
@apply relative border-none outline-none bg-transparent;
|
||||
@apply relative border-none outline-none bg-transparent flex;
|
||||
width: 53px;
|
||||
height: 85px;
|
||||
}
|
||||
@@ -27,7 +27,7 @@ ui-slider {
|
||||
|
||||
.thumbnail {
|
||||
@apply rounded-md shadow-lg;
|
||||
height: 85px;
|
||||
max-height: 5.3125rem;
|
||||
}
|
||||
|
||||
.faded {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<button
|
||||
type="button"
|
||||
class="px-2 py-3 bg-[#C6CBD0] rounded flex flex-row items-center open:bg-[#596470] open:text-white z-dropdown"
|
||||
[disabled]="!(customer$ | async)"
|
||||
class="page-pickup-shelf-details-header-nav-menu__nav-button px-2 py-3 bg-[#C6CBD0] rounded flex flex-row items-center open:bg-[#596470] open:text-white z-dropdown"
|
||||
[cdkMenuTriggerFor]="navMenu"
|
||||
#menuTrigger="cdkMenuTriggerFor"
|
||||
[class.open]="menuTrigger.isOpen()"
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
:host {
|
||||
@apply inline-block;
|
||||
}
|
||||
|
||||
.page-pickup-shelf-details-header-nav-menu__nav-button:disabled {
|
||||
@apply cursor-not-allowed text-white;
|
||||
}
|
||||
|
||||
@@ -7,11 +7,12 @@ import { ComponentStore } from '@ngrx/component-store';
|
||||
import { IconComponent } from '@shared/components/icon';
|
||||
import { SharedMenuModule } from '@shared/components/menu';
|
||||
import { CustomerSearchNavigation } from '@shared/services';
|
||||
import { CustomerInfoDTO } from '@swagger/crm';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
export interface PickUpShelfDetailsHeaderNavMenuComponentState {
|
||||
customerId?: number;
|
||||
customer?: CustomerInfoDTO;
|
||||
showCustomerDetails: boolean;
|
||||
}
|
||||
|
||||
@@ -25,26 +26,26 @@ export interface PickUpShelfDetailsHeaderNavMenuComponentState {
|
||||
imports: [CdkMenuModule, SharedMenuModule, IconComponent, RouterLink, NgIf, AsyncPipe],
|
||||
})
|
||||
export class PickUpShelfDetailsHeaderNavMenuComponent extends ComponentStore<PickUpShelfDetailsHeaderNavMenuComponentState> {
|
||||
@Input() set customerId(value: NumberInput) {
|
||||
this.patchState({ customerId: coerceNumberProperty(value) });
|
||||
@Input() set customer(value: CustomerInfoDTO) {
|
||||
this.patchState({ customer: value });
|
||||
}
|
||||
|
||||
@Input() set showCustomerDetails(value: BooleanInput) {
|
||||
this.patchState({ showCustomerDetails: coerceBooleanProperty(value) });
|
||||
}
|
||||
|
||||
readonly customerId$ = this.select((state) => state.customerId);
|
||||
readonly customer$ = this.select((state) => state.customer);
|
||||
|
||||
readonly showCustomerDetails$ = this.select((state) => state.showCustomerDetails);
|
||||
|
||||
ordersRoute$ = this.customerId$.pipe(
|
||||
map((customerId) => customerId && this._navigation.ordersRoute({ processId: Date.now(), customerId }))
|
||||
ordersRoute$ = this.customer$.pipe(
|
||||
map((customer) => !!customer && this._navigation.ordersRoute({ processId: Date.now(), customerId: customer?.id, customer }))
|
||||
);
|
||||
|
||||
customerDetailsRoute$ = combineLatest([this.showCustomerDetails$, this.customerId$]).pipe(
|
||||
customerDetailsRoute$ = combineLatest([this.showCustomerDetails$, this.customer$]).pipe(
|
||||
map(
|
||||
([showCustomerDetails, customerId]) =>
|
||||
showCustomerDetails && customerId && this._navigation.detailsRoute({ processId: Date.now(), customerId })
|
||||
([showCustomerDetails, customer]) =>
|
||||
showCustomerDetails && !!customer && this._navigation.detailsRoute({ processId: Date.now(), customerId: customer?.id, customer })
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -20,10 +20,7 @@
|
||||
|
||||
<div class="page-pickup-shelf-details-header__details bg-white px-4 pt-4 pb-5">
|
||||
<div class="flex flex-row items-center" [class.mb-8]="!orderItem?.features?.paid && !isKulturpass">
|
||||
<page-pickup-shelf-details-header-nav-menu
|
||||
class="mr-2"
|
||||
[customerId]="customerId$ | async"
|
||||
></page-pickup-shelf-details-header-nav-menu>
|
||||
<page-pickup-shelf-details-header-nav-menu class="mr-2" [customer]="customer$ | async"></page-pickup-shelf-details-header-nav-menu>
|
||||
<h2 class="page-pickup-shelf-details-header__details-header items-center">
|
||||
<div class="text-h2">
|
||||
{{ orderItem?.organisation }}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { AsyncPipe, DatePipe, NgFor, NgIf, NgSwitch, NgSwitchCase, NgTemplateOut
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output, inject } from '@angular/core';
|
||||
import { DBHOrderItemListItemDTO, KeyValueDTOOfStringAndString, NotificationChannel, OrderDTO } from '@swagger/oms';
|
||||
import { PickupShelfDetailsStore } from '../../store';
|
||||
import { map, shareReplay, withLatestFrom } from 'rxjs/operators';
|
||||
import { map, shareReplay, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { BehaviorSubject, Observable, combineLatest } from 'rxjs';
|
||||
import { DateAdapter, UiCommonModule } from '@ui/common';
|
||||
import { IconModule } from '@shared/components/icon';
|
||||
@@ -92,7 +92,11 @@ export class PickUpShelfDetailsHeaderComponent {
|
||||
minDateDatepicker = this.dateAdapter.addCalendarDays(this.dateAdapter.today(), -1);
|
||||
today = this.dateAdapter.today();
|
||||
|
||||
orderItem$ = this._store.orderItems$.pipe(map((orderItems) => orderItems?.find((_) => true)));
|
||||
// Daten die im Header Angezeigt werden sollen
|
||||
orderItem$ = combineLatest([
|
||||
this._store.selectedOrderItem$, // Wenn man im Abholfach ist muss das ausgewählte OrderItem genommen werden
|
||||
this._store.selectedOrderItems$.pipe(map((orderItems) => orderItems?.find((_) => true))), // Wenn man in der Warenausgabe ist muss man das erste OrderItem nehmen
|
||||
]).pipe(map(([selectedOrderItem, selectedOrderItems]) => selectedOrderItem || selectedOrderItems));
|
||||
|
||||
changeDateLoader$ = new BehaviorSubject<boolean>(false);
|
||||
changePreferredDateLoader$ = new BehaviorSubject<boolean>(false);
|
||||
@@ -101,9 +105,9 @@ export class PickUpShelfDetailsHeaderComponent {
|
||||
|
||||
changeDateDisabled$ = this.changeStatusDisabled$;
|
||||
|
||||
customerId$ = this._store.customer$.pipe(map((customer) => customer?.id));
|
||||
customer$ = this._store.customer$;
|
||||
|
||||
features$ = this._store.customer$.pipe(
|
||||
features$ = this.customer$.pipe(
|
||||
map((customer) => customer?.features || []),
|
||||
map((features) => features.filter((f) => f.enabled && !!f.description)),
|
||||
shareReplay()
|
||||
|
||||
@@ -22,7 +22,7 @@ button {
|
||||
|
||||
.page-pickup-shelf-details-item__thumbnail {
|
||||
img {
|
||||
@apply rounded shadow-cta w-[3.625rem] h-[5.9375rem];
|
||||
@apply rounded shadow-cta w-[3.625rem] max-h-[5.9375rem];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,10 @@ export class PickUpShelfDetailsItemComponent extends ComponentStore<PickUpShelfD
|
||||
set orderItem(orderItem: DBHOrderItemListItemDTO) {
|
||||
if (!isEqual(this.orderItem, orderItem)) {
|
||||
// Remove Prev OrderItem from selected list
|
||||
this._store.selectOrderItem(this.orderItem, false);
|
||||
if (this.orderItem?.orderItemSubsetId !== orderItem?.orderItemSubsetId) {
|
||||
this._store.selectOrderItem(this.orderItem, false);
|
||||
}
|
||||
|
||||
this.patchState({ orderItem, quantity: orderItem?.quantity, more: false });
|
||||
this.specialCommentControl.reset(orderItem?.specialComment);
|
||||
// Add New OrderItem to selected list if selected was set to true by its input
|
||||
|
||||
@@ -33,7 +33,7 @@ export class PickupShelfFilterComponent {
|
||||
return this._activatedRoute?.parent?.children?.find((childRoute) => childRoute?.outlet === 'primary')?.snapshot?.routeConfig?.path;
|
||||
}
|
||||
|
||||
fetching$: Observable<boolean> = this.store.fetching$;
|
||||
fetching$: Observable<boolean> = this.store.fetchingList$;
|
||||
|
||||
searchboxHint$ = this.store.searchboxHint$;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
>
|
||||
<div class="page-pickup-shelf-list-item__item-thumbnail text-center w-[3.125rem] h-[4.9375rem]">
|
||||
<img
|
||||
class="page-pickup-shelf-list-item__item-image w-[3.125rem] h-[4.9375rem]"
|
||||
class="page-pickup-shelf-list-item__item-image w-[3.125rem] max-h-[4.9375rem]"
|
||||
loading="lazy"
|
||||
*ngIf="item?.product?.ean | productImage; let productImage"
|
||||
[src]="productImage"
|
||||
|
||||
@@ -100,9 +100,9 @@ export const selectedOrderItems = (s: PickupShelfDetailsState) => {
|
||||
|
||||
export const selectedOrderItem = (s: PickupShelfDetailsState) => {
|
||||
const orderItems = selectOrderItems(s);
|
||||
const selectedOrderItemId = selectPreviousSelectedOrderItemSubsetId(s);
|
||||
const displayedOrderItemSubsetId = selectDisplayedOrderItemSubsetId(s);
|
||||
|
||||
return orderItems?.find((oi) => oi?.orderItemSubsetId === selectedOrderItemId);
|
||||
return orderItems?.find((oi) => oi?.orderItemSubsetId === displayedOrderItemSubsetId);
|
||||
};
|
||||
|
||||
export const selectSelectedOrderItemQuantity = (s: PickupShelfDetailsState) => {
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
} from '@swagger/oms';
|
||||
import { PickupShelfIOService, PickupShelfService } from '@domain/pickup-shelf';
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { delayWhen, filter, mergeMap, switchMap, take, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { debounceTime, delayWhen, distinctUntilChanged, filter, mergeMap, switchMap, take, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
import * as Selectors from './pickup-shelf-details.selectors';
|
||||
@@ -27,6 +27,7 @@ import { CacheService } from '@core/cache';
|
||||
import { RunCheckTrigger } from '../trigger';
|
||||
import { DomainReceiptService } from '@domain/oms';
|
||||
import { PickupShelfStore } from './pickup-shelf.store';
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
@Injectable()
|
||||
export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsState> {
|
||||
@@ -332,7 +333,6 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
|
||||
|
||||
fetchOrder = this.effect((trigger$: Observable<{ orderId: number }>) =>
|
||||
trigger$.pipe(
|
||||
filter(({ orderId }) => this.order?.id !== orderId),
|
||||
tap(({ orderId }) => this.beforeFetchOrder(orderId)),
|
||||
switchMap(({ orderId }) =>
|
||||
this._pickupShelfService.getOrderByOrderId(orderId).pipe(tapResponse(this.fetchOrderSuccess, this.fetchOrderFailed))
|
||||
@@ -491,13 +491,15 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
|
||||
};
|
||||
|
||||
fetchCustomerSuccess = (res: ListResponseArgsOfCustomerInfoDTO) => {
|
||||
const customers = res.result?.filter((res) => res.customerNumber === this.order.buyer.buyerNumber);
|
||||
|
||||
// check if response contains exactly one customer
|
||||
if (res.result.length > 1) {
|
||||
if (customers.length > 1) {
|
||||
this._modal.error('Fehler beim Laden des Kunden', new Error('Es wurde mehr als ein Kunde gefunden.'));
|
||||
return;
|
||||
}
|
||||
|
||||
const customer = res.result[0];
|
||||
const customer = customers[0];
|
||||
|
||||
if (!customer) {
|
||||
this.patchState({ fetchingCustomer: false });
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
import { ComponentStore, tapResponse, OnStoreInit } from '@ngrx/component-store';
|
||||
import { PickupShelfState } from './pickup-shelf.state';
|
||||
import { PickupShelfIOService } from '@domain/pickup-shelf';
|
||||
import { delayWhen, filter, map, skipWhile, switchMap, take, takeUntil, tap, throttleTime, withLatestFrom } from 'rxjs/operators';
|
||||
import {
|
||||
debounceTime,
|
||||
delayWhen,
|
||||
filter,
|
||||
map,
|
||||
skipWhile,
|
||||
switchMap,
|
||||
take,
|
||||
takeUntil,
|
||||
tap,
|
||||
throttleTime,
|
||||
withLatestFrom,
|
||||
} from 'rxjs/operators';
|
||||
import {
|
||||
DBHOrderItemListItemDTO,
|
||||
ListResponseArgsOfDBHOrderItemListItemDTO,
|
||||
@@ -13,7 +25,7 @@ import { ToasterService } from '@shared/shell';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
|
||||
import * as Selectors from './pickup-shelf.selectors';
|
||||
import { Subject, combineLatest } from 'rxjs';
|
||||
import { Observable, Subject, combineLatest } from 'rxjs';
|
||||
import { CacheService } from '@core/cache';
|
||||
import { Filter } from '@shared/components/filter';
|
||||
|
||||
@@ -71,22 +83,21 @@ export class PickupShelfStore extends ComponentStore<PickupShelfState> implement
|
||||
|
||||
readonly listHits$ = this.select(Selectors.selectListHits);
|
||||
|
||||
readonly fetching$ = this.select(Selectors.selectFetchingList);
|
||||
|
||||
get listHits() {
|
||||
return this.get(Selectors.selectListHits);
|
||||
}
|
||||
|
||||
searchboxHint$ = combineLatest([this.fetching$, this.fetchListResponse$]).pipe(
|
||||
map(([fetching, response]) => (response?.response?.hits === 0 && !fetching ? 'Keine Suchergebnisse' : ''))
|
||||
);
|
||||
|
||||
readonly fetchingList$ = this.select(Selectors.selectFetchingList);
|
||||
|
||||
get fetchingList() {
|
||||
return this.get(Selectors.selectFetchingList);
|
||||
}
|
||||
|
||||
searchboxHint$ = combineLatest([this.fetchingList$, this.fetchListResponse$]).pipe(
|
||||
debounceTime(100),
|
||||
map(([fetching, response]) => (response?.response?.hits === 0 && !fetching ? 'Keine Suchergebnisse' : ''))
|
||||
);
|
||||
|
||||
readonly selectedListItems$ = this.select(Selectors.selectSelectedListItems);
|
||||
|
||||
get selectedListItems() {
|
||||
@@ -100,6 +111,7 @@ export class PickupShelfStore extends ComponentStore<PickupShelfState> implement
|
||||
this._destronyRef.onDestroy(() => {
|
||||
this.cancelListRequests();
|
||||
this._fetchListResponse.complete();
|
||||
this.patchState({ fetchingList: false });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -124,7 +136,6 @@ export class PickupShelfStore extends ComponentStore<PickupShelfState> implement
|
||||
|
||||
cancelListRequests() {
|
||||
this._cancelListRequests.next();
|
||||
this.patchState({ fetchingList: false });
|
||||
}
|
||||
|
||||
addSelectedListItem = this.updater((state, listItem: DBHOrderItemListItemDTO) => ({
|
||||
@@ -193,19 +204,21 @@ export class PickupShelfStore extends ComponentStore<PickupShelfState> implement
|
||||
this.patchState({ fetchingQuerySettings: false });
|
||||
};
|
||||
|
||||
delayWhenFilterIsNotReady = delayWhen(() =>
|
||||
delayWhenFilterIsNotReady = delayWhen((value: { emitFetchListResponse: boolean } | void) =>
|
||||
this.filter$.pipe(
|
||||
filter((filter) => !!filter),
|
||||
take(1)
|
||||
)
|
||||
);
|
||||
|
||||
fetchList = this.effect((trigger$) =>
|
||||
fetchList = this.effect((trigger$: Observable<{ emitFetchListResponse: boolean } | void>) =>
|
||||
trigger$.pipe(
|
||||
this.delayWhenFilterIsNotReady,
|
||||
withLatestFrom(this.filter$, this.processId$),
|
||||
map(([_, filter, processId]) => this.beforeFetchList(filter, processId)),
|
||||
switchMap(({ filter, processId, list }) =>
|
||||
map(([{ emitFetchListResponse } = { emitFetchListResponse: true }, filter, processId]) =>
|
||||
this.beforeFetchList(emitFetchListResponse, filter, processId)
|
||||
),
|
||||
switchMap(({ emitFetchListResponse, filter, processId, list }) =>
|
||||
this._pickupShelfIOService
|
||||
.search({
|
||||
...filter.getQueryToken(),
|
||||
@@ -214,7 +227,7 @@ export class PickupShelfStore extends ComponentStore<PickupShelfState> implement
|
||||
.pipe(
|
||||
takeUntil(this._cancelListRequests),
|
||||
tapResponse(
|
||||
(res) => this.fetchListDone({ processId, queryParams: filter.getQueryParams() })(res),
|
||||
(res) => this.fetchListDone({ processId, queryParams: filter.getQueryParams(), emitFetchListResponse })(res),
|
||||
(err) => this.fetchListError(err)
|
||||
)
|
||||
)
|
||||
@@ -222,28 +235,38 @@ export class PickupShelfStore extends ComponentStore<PickupShelfState> implement
|
||||
)
|
||||
);
|
||||
|
||||
private beforeFetchList = (filter: Filter, processId: number) => {
|
||||
private beforeFetchList = (emitFetchListResponse: boolean, filter: Filter, processId: number) => {
|
||||
this.cancelListRequests();
|
||||
this.patchState({ fetchingList: true });
|
||||
const queryToken = filter.getQueryParams();
|
||||
const cachedListResponse = this._cacheService.get<ListResponseArgsOfDBHOrderItemListItemDTO>({ processId, queryToken });
|
||||
|
||||
let list: DBHOrderItemListItemDTO[] = [];
|
||||
|
||||
if (!!cachedListResponse) {
|
||||
this.patchState({ fetchingList: false, list: cachedListResponse.result, listHits: cachedListResponse.hits });
|
||||
this.patchState({ list: cachedListResponse.result, listHits: cachedListResponse.hits });
|
||||
list = cachedListResponse.result;
|
||||
} else {
|
||||
this.patchState({ fetchingList: true, list: [], listHits: 0 });
|
||||
this.patchState({ list: [], listHits: 0 });
|
||||
}
|
||||
|
||||
return { filter, processId, list };
|
||||
return { emitFetchListResponse, filter, processId, list };
|
||||
};
|
||||
|
||||
private fetchListDone = ({ processId, queryParams }: { processId: number; queryParams: Record<string, string> }) => (
|
||||
response: ListResponseArgsOfDBHOrderItemListItemDTO
|
||||
) => {
|
||||
private fetchListDone = ({
|
||||
processId,
|
||||
queryParams,
|
||||
emitFetchListResponse,
|
||||
}: {
|
||||
processId: number;
|
||||
queryParams: Record<string, string>;
|
||||
emitFetchListResponse: boolean;
|
||||
}) => (response: ListResponseArgsOfDBHOrderItemListItemDTO) => {
|
||||
this.patchState({ fetchingList: false, list: response.result, listHits: response.hits });
|
||||
this._fetchListResponse.next({ processId, response, queryParams });
|
||||
if (emitFetchListResponse) {
|
||||
this._fetchListResponse.next({ processId, response, queryParams });
|
||||
}
|
||||
|
||||
this._cacheService.set<ListResponseArgsOfDBHOrderItemListItemDTO>({ processId, queryToken: queryParams }, response, { persist: true });
|
||||
};
|
||||
|
||||
|
||||
@@ -31,6 +31,6 @@ export class RemissionFilterComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
resetFilter() {
|
||||
this.store.loadFilter();
|
||||
this.store.loadFilter({ loadDefault: true });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,12 +12,6 @@
|
||||
>
|
||||
{{ item.title }}
|
||||
</h3>
|
||||
<span class="product-group block text-right whitespace-nowrap text-active-branch"
|
||||
>{{ item.productGroup }}:{{ item.productGroup | productGroup }}</span
|
||||
>
|
||||
<div class="department block text-right text-inactive-branch overflow-hidden overflow-ellipsis whitespace-nowrap">
|
||||
{{ item.department }}
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="showImpediment" class="grid grid-flow-col items-start text-p2 font-bold text-dark-goldenrod">
|
||||
<span
|
||||
@@ -79,6 +73,15 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-flow-row-dense text-active-branch text-right">
|
||||
<div>
|
||||
{{ item?.dto?.department }}
|
||||
<span *ngIf="item?.dto?.department && item?.dto?.shelfLabel">/</span>
|
||||
{{ item?.dto?.shelfLabel }}
|
||||
</div>
|
||||
<div>{{ item.productGroup }}:{{ item.productGroup | productGroup }}</div>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="!!returnDto; else removeItem">
|
||||
<div class="grid grid-flow-col justify-self-end gap-2 items-center">
|
||||
<button
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
:host {
|
||||
@apply grid grid-flow-row gap-2 p-4 bg-white rounded w-full;
|
||||
height: 368px;
|
||||
max-height: 368px;
|
||||
height: 23rem;
|
||||
max-height: 23rem;
|
||||
}
|
||||
|
||||
.item-header-details {
|
||||
@@ -51,5 +51,7 @@
|
||||
}
|
||||
|
||||
.product-data-grid {
|
||||
grid-template-columns: 90px 190px auto;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
grid-template-columns: 5.625rem 11.875rem 1fr;
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
combineLatest([this.selectedSource$, this.selectedSupplier$])
|
||||
.pipe(takeUntil(this._onDestroy$))
|
||||
.subscribe(() => {
|
||||
this.loadFilter();
|
||||
this.loadFilter({});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -227,12 +227,12 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
)
|
||||
);
|
||||
|
||||
loadFilter = this.effect(($) =>
|
||||
$.pipe(
|
||||
loadFilter = this.effect((options$: Observable<{ loadDefault?: boolean }>) =>
|
||||
options$.pipe(
|
||||
// tap((_) => (this.getCachedData()?.hits === 0 ? this.setFetching(true) : null)),
|
||||
withLatestFrom(this.selectedSupplier$, this.selectedSource$, this._activatedRoute.queryParams),
|
||||
filter(([, selectedSupplier, selectedSource]) => !!selectedSupplier?.id && !!selectedSource),
|
||||
switchMap(([, selectedSupplier, selectedSource, queryParams]) =>
|
||||
filter(([loadDefault, selectedSupplier, selectedSource]) => !!selectedSupplier?.id && !!selectedSource),
|
||||
switchMap(([loadDefault, selectedSupplier, selectedSource, queryParams]) =>
|
||||
this._domainRemissionService
|
||||
.getQuerySettings({
|
||||
supplierId: selectedSupplier.id,
|
||||
@@ -245,7 +245,8 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
|
||||
settings?.filter?.forEach((filter) => (filter.input = filter.input?.filter((input) => input.options?.values?.length > 0)));
|
||||
|
||||
const filter = UiFilter.create(settings);
|
||||
if (!!queryParams) {
|
||||
|
||||
if (!!queryParams && !loadDefault) {
|
||||
filter?.fromQueryParams(queryParams);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<cdk-virtual-scroll-viewport
|
||||
#scrollContainer
|
||||
class="remission-list"
|
||||
[itemSize]="368"
|
||||
[itemSize]="368 * shellService.scale"
|
||||
minBufferPx="1200"
|
||||
maxBufferPx="1200"
|
||||
(scrolledIndexChange)="scrolledIndexChange($event)"
|
||||
@@ -97,10 +97,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="h-px-100"></div>
|
||||
<div class="h-24"></div>
|
||||
</cdk-virtual-scroll-viewport>
|
||||
|
||||
<div class="actions flex items-center justify-center bottom-40 sticky gap-7">
|
||||
<div class="actions flex items-center justify-center bottom-12 sticky gap-7">
|
||||
<ng-container>
|
||||
<a
|
||||
*ngIf="showStartRemissionAction$ | async"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
:host {
|
||||
@apply flex flex-col w-full box-content relative;
|
||||
max-height: calc(100vh - 284px);
|
||||
max-height: calc(100vh - 10.25rem);
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
.remission-list-result {
|
||||
@apply list-none bg-white rounded mb-2;
|
||||
height: 368px;
|
||||
max-height: 368px;
|
||||
}
|
||||
|
||||
.filter {
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, ViewChild, ViewChildren, QueryList, TrackByFunction } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
ChangeDetectionStrategy,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
ViewChild,
|
||||
ViewChildren,
|
||||
QueryList,
|
||||
TrackByFunction,
|
||||
inject,
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
@@ -11,6 +21,7 @@ import { debounceTime, first, map, shareReplay, takeUntil, withLatestFrom } from
|
||||
import { RemissionListItemComponent } from './remission-list-item';
|
||||
import { RemissionListComponentStore } from './remission-list.component-store';
|
||||
import { RemissionComponentStore } from './remission.component-store';
|
||||
import { ShellService } from '@shared/shell';
|
||||
|
||||
@Component({
|
||||
selector: 'page-remission-list',
|
||||
@@ -20,6 +31,8 @@ import { RemissionComponentStore } from './remission.component-store';
|
||||
providers: [RemissionComponentStore],
|
||||
})
|
||||
export class RemissionListComponent implements OnInit, OnDestroy {
|
||||
shellService = inject(ShellService);
|
||||
|
||||
@ViewChildren(RemissionListItemComponent) listItems: QueryList<RemissionListItemComponent>;
|
||||
@ViewChild('scrollContainer', { static: true })
|
||||
scrollContainer: CdkVirtualScrollViewport;
|
||||
|
||||
@@ -13,7 +13,7 @@ h1 {
|
||||
img {
|
||||
@apply rounded-customerCard;
|
||||
width: 190px;
|
||||
height: 310px;
|
||||
max-height: 310px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
<ng-container *ngIf="expanded[i]">
|
||||
<ui-form-control label="Abholfachnummer" [clearable]="true" variant="inline">
|
||||
<input uiInput formControlName="compartmentCode" />
|
||||
<input pattern="^\d{3,4}_\d{4}_\d{1,5}$" uiInput formControlName="compartmentCode" />
|
||||
</ui-form-control>
|
||||
|
||||
<shared-goods-in-out-order-details-tags
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user