mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
Compare commits
150 Commits
split-scre
...
fix/4397-R
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d223e064c2 | ||
|
|
ecb5a77fdd | ||
|
|
6652c2f97e | ||
|
|
e9f16f72cb | ||
|
|
a687b1771f | ||
|
|
af10e66b1a | ||
|
|
2d8a0f514d | ||
|
|
02ade0a377 | ||
|
|
c2943037d9 | ||
|
|
c30d8fa5fd | ||
|
|
4fd10bc8a4 | ||
|
|
1d25fec9ff | ||
|
|
6f77527d59 | ||
|
|
7a2cd5cef8 | ||
|
|
d1de4d96d8 | ||
|
|
dd1652c3a6 | ||
|
|
66fd2eed81 | ||
|
|
f5d90f97e8 | ||
|
|
ade3800568 | ||
|
|
4d669731fb | ||
|
|
5bc81f7048 | ||
|
|
6cf6dec001 | ||
|
|
526d82752c | ||
|
|
7565b2bb54 | ||
|
|
692a32f4d7 | ||
|
|
4039ffdf20 | ||
|
|
cb39b3b79b | ||
|
|
fe3dfd00ab | ||
|
|
08a4b5a2ca | ||
|
|
e8a036b6df | ||
|
|
ff698ec6b2 | ||
|
|
8644ea515b | ||
|
|
10a77c25e9 | ||
|
|
25d3adc28c | ||
|
|
5cdbbb995f | ||
|
|
01a26ef57a | ||
|
|
3b337ea127 | ||
|
|
c66ef5ba91 | ||
|
|
b2edcf8a20 | ||
|
|
06af33e37e | ||
|
|
1a217d0870 | ||
|
|
d6c52baf53 | ||
|
|
f923fdefa4 | ||
|
|
bd674a0e14 | ||
|
|
bd3f8af924 | ||
|
|
5e720876ac | ||
|
|
8543db465b | ||
|
|
ec4951d8dd | ||
|
|
17f1846c69 | ||
|
|
6b71a544fe | ||
|
|
7f1f097179 | ||
|
|
a7003b84bf | ||
|
|
8a84e69ce3 | ||
|
|
3ebd50a8c1 | ||
|
|
1f7a952c91 | ||
|
|
560ef57915 | ||
|
|
4fb81526ae | ||
|
|
4bee8117ee | ||
|
|
66991684d2 | ||
|
|
06abcbff51 | ||
|
|
17197461f7 | ||
|
|
f036190019 | ||
|
|
e68975b0f7 | ||
|
|
692c1cb596 | ||
|
|
7ace3b7685 | ||
|
|
6d6077c54f | ||
|
|
b60913de3c | ||
|
|
357b89f1ea | ||
|
|
c37b05d4b8 | ||
|
|
94fe011d49 | ||
|
|
0e458e81d8 | ||
|
|
efbdb134a9 | ||
|
|
a97d87ed7b | ||
|
|
cb56cfcb00 | ||
|
|
d13cf0ef8d | ||
|
|
e6afd6887a | ||
|
|
7378b7db53 | ||
|
|
70f9bb0f73 | ||
|
|
2fa7451716 | ||
|
|
871aeaed1f | ||
|
|
09f0337489 | ||
|
|
51f36de7dd | ||
|
|
0999e1ea51 | ||
|
|
d079b276cf | ||
|
|
e1bd87418c | ||
|
|
d06af28e11 | ||
|
|
c123a29b1d | ||
|
|
1398a3bdee | ||
|
|
340e866aed | ||
|
|
9338162906 | ||
|
|
23d61bfa60 | ||
|
|
7409053cef | ||
|
|
0c372b0245 | ||
|
|
dd68405522 | ||
|
|
69e792ae41 | ||
|
|
02b507aca9 | ||
|
|
05f94c65fc | ||
|
|
8b6ebd1820 | ||
|
|
45cb411e17 | ||
|
|
dec66de61d | ||
|
|
e9a490d7f3 | ||
|
|
280b28a474 | ||
|
|
cfba5f34d4 | ||
|
|
582e2d988c | ||
|
|
4c627986d1 | ||
|
|
299dab43b9 | ||
|
|
ce0823a6fd | ||
|
|
e0963e9b65 | ||
|
|
a88552f975 | ||
|
|
66a7bab287 | ||
|
|
088d9e1b6f | ||
|
|
29619b2fec | ||
|
|
a5effc89a7 | ||
|
|
e7fe2a2676 | ||
|
|
53bb01db2d | ||
|
|
003d0cbcb2 | ||
|
|
a71c627a30 | ||
|
|
261c851514 | ||
|
|
58cfcba738 | ||
|
|
50dac899c9 | ||
|
|
9fe25f0f73 | ||
|
|
678c961ea9 | ||
|
|
f6b4633ac4 | ||
|
|
0ecd2916a2 | ||
|
|
e786b60bfc | ||
|
|
8c079e9064 | ||
|
|
3b08fe438b | ||
|
|
fedbdcc35c | ||
|
|
ac656ddc04 | ||
|
|
85d8d75da8 | ||
|
|
e6d389d848 | ||
|
|
664053f231 | ||
|
|
18b2230dd7 | ||
|
|
0876ed3acc | ||
|
|
7b4edbee8b | ||
|
|
05ef1edfeb | ||
|
|
fb8db78bbd | ||
|
|
aecc4a477f | ||
|
|
fd63ce8b3c | ||
|
|
423cd498cf | ||
|
|
b421c8b08c | ||
|
|
4304286f48 | ||
|
|
df308c98ff | ||
|
|
1d1221e8c5 | ||
|
|
e2a6eac0a2 | ||
|
|
4e54baf9fb | ||
|
|
7593e420de | ||
|
|
84ca80a1c9 | ||
|
|
7265f4d4ce | ||
|
|
fca1eacc6e |
@@ -86,6 +86,28 @@ export class ApplicationService {
|
||||
return this.getProcessById$(processId).pipe(map((process) => process?.data?.selectedBranch));
|
||||
}
|
||||
|
||||
readonly REGEX_PROCESS_NAME = /^Vorgang \d+$/;
|
||||
|
||||
async createCustomerProcess(processId?: number): Promise<ApplicationProcess> {
|
||||
const processes = await this.getProcesses$('customer').pipe(first()).toPromise();
|
||||
|
||||
const processIds = processes.filter((x) => this.REGEX_PROCESS_NAME.test(x.name)).map((x) => +x.name.split(' ')[1]);
|
||||
|
||||
const maxId = processIds.length > 0 ? Math.max(...processIds) : 0;
|
||||
|
||||
const process: ApplicationProcess = {
|
||||
id: processId ?? Date.now(),
|
||||
type: 'cart',
|
||||
name: `Vorgang ${maxId + 1}`,
|
||||
section: 'customer',
|
||||
closeable: true,
|
||||
};
|
||||
|
||||
await this.createProcess(process);
|
||||
|
||||
return process;
|
||||
}
|
||||
|
||||
async createProcess(process: ApplicationProcess) {
|
||||
const existingProcess = await this.getProcessById$(process?.id).pipe(first()).toPromise();
|
||||
if (existingProcess?.id === process?.id) {
|
||||
|
||||
44
apps/core/cache/src/lib/cache.service.ts
vendored
44
apps/core/cache/src/lib/cache.service.ts
vendored
@@ -1,14 +1,24 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CacheOptions } from './cache-options';
|
||||
import { Cached } from './cached';
|
||||
import { interval } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class CacheService {
|
||||
constructor() {}
|
||||
constructor() {
|
||||
this._registerCleanupTask();
|
||||
}
|
||||
|
||||
set(token: Object, data: any, options?: CacheOptions) {
|
||||
_registerCleanupTask() {
|
||||
this.cleanup();
|
||||
interval(1000 * 60).subscribe(() => {
|
||||
this.cleanup();
|
||||
});
|
||||
}
|
||||
|
||||
set<T>(token: Object, data: T, options?: CacheOptions) {
|
||||
const persist = options?.persist;
|
||||
const ttl = options?.ttl;
|
||||
const cached: Cached = {
|
||||
@@ -17,6 +27,8 @@ export class CacheService {
|
||||
|
||||
if (ttl) {
|
||||
cached.until = Date.now() + ttl;
|
||||
} else {
|
||||
cached.until = Date.now() + 1000 * 60 * 60 * 12;
|
||||
}
|
||||
|
||||
if (persist) {
|
||||
@@ -29,13 +41,15 @@ export class CacheService {
|
||||
return cached;
|
||||
}
|
||||
|
||||
get<T = any>(token: Object, from: 'session' | 'persist' = 'session'): T {
|
||||
get<T = any>(token: Object, from?: 'session' | 'persist'): T {
|
||||
let cached: Cached;
|
||||
|
||||
if (from === 'session') {
|
||||
cached = this.deserialize(sessionStorage.getItem(this.getKey(token)));
|
||||
} else if (from === 'persist') {
|
||||
cached = this.deserialize(localStorage.getItem(this.getKey(token)));
|
||||
} else {
|
||||
cached = this.deserialize(sessionStorage.getItem(this.getKey(token))) || this.deserialize(localStorage.getItem(this.getKey(token)));
|
||||
}
|
||||
|
||||
if (!cached) {
|
||||
@@ -59,7 +73,8 @@ export class CacheService {
|
||||
}
|
||||
|
||||
private getKey(token: Object) {
|
||||
return this.hash(JSON.stringify(token));
|
||||
const key = `CacheService_` + this.hash(JSON.stringify(token));
|
||||
return key;
|
||||
}
|
||||
|
||||
private hash(data: string): string {
|
||||
@@ -77,4 +92,25 @@ export class CacheService {
|
||||
private deserialize(data: string): Cached {
|
||||
return JSON.parse(data);
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
// get all keys created by this service by looking for the service name and remove the entries
|
||||
// that ttl is expired
|
||||
let localStorageKeys = Object.keys(localStorage).filter((key) => key.startsWith('CacheService_'));
|
||||
let seesionStorageKeys = Object.keys(sessionStorage).filter((key) => key.startsWith('CacheService_'));
|
||||
|
||||
localStorageKeys.forEach((key) => {
|
||||
const cached = this.deserialize(localStorage.getItem(key));
|
||||
if (cached.until < Date.now()) {
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
});
|
||||
|
||||
seesionStorageKeys.forEach((key) => {
|
||||
const cached = this.deserialize(sessionStorage.getItem(key));
|
||||
if (cached.until < Date.now()) {
|
||||
sessionStorage.removeItem(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { map } from 'rxjs/operators';
|
||||
|
||||
const MATCH_TABLET = '(max-width: 1023px)';
|
||||
|
||||
const MATCH_DESKTOP_SMALL = '(min-width: 1024px) and (max-width: 1439px)';
|
||||
const MATCH_DESKTOP_SMALL = '(min-width: 1024px) and (max-width: 1279px)';
|
||||
|
||||
const MATCH_DESKTOP = '(min-width: 1280px)';
|
||||
|
||||
|
||||
@@ -27,7 +27,9 @@ import {
|
||||
StoreCheckoutPayerService,
|
||||
StoreCheckoutBranchService,
|
||||
ItemsResult,
|
||||
ShoppingCartItemDTO,
|
||||
KulturPassService,
|
||||
ProductDTO,
|
||||
KulturPassResult,
|
||||
} from '@swagger/checkout';
|
||||
import {
|
||||
DisplayOrderDTO,
|
||||
@@ -37,22 +39,20 @@ import {
|
||||
ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString,
|
||||
} from '@swagger/oms';
|
||||
import { isNullOrUndefined, memorize } from '@utils/common';
|
||||
import { combineLatest, Observable, of, concat, isObservable, throwError, interval, zip, EMPTY, Subscription } from 'rxjs';
|
||||
import { combineLatest, Observable, of, concat, isObservable, throwError, interval as rxjsInterval } from 'rxjs';
|
||||
import {
|
||||
bufferCount,
|
||||
catchError,
|
||||
debounceTime,
|
||||
distinctUntilChanged,
|
||||
filter,
|
||||
first,
|
||||
map,
|
||||
mergeMap,
|
||||
share,
|
||||
shareReplay,
|
||||
switchMap,
|
||||
take,
|
||||
tap,
|
||||
withLatestFrom,
|
||||
startWith,
|
||||
} from 'rxjs/operators';
|
||||
|
||||
import * as DomainCheckoutSelectors from './store/domain-checkout.selectors';
|
||||
@@ -63,8 +63,6 @@ import { ApplicationService } from '@core/application';
|
||||
import { CustomerDTO } from '@swagger/crm';
|
||||
import { Config } from '@core/config';
|
||||
import parseDuration from 'parse-duration';
|
||||
import { CheckoutEntity } from './store/defs/checkout.entity';
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
@Injectable()
|
||||
export class DomainCheckoutService {
|
||||
@@ -84,7 +82,8 @@ export class DomainCheckoutService {
|
||||
private _paymentService: StoreCheckoutPaymentService,
|
||||
private _buyerService: StoreCheckoutBuyerService,
|
||||
private _payerService: StoreCheckoutPayerService,
|
||||
private _branchService: StoreCheckoutBranchService
|
||||
private _branchService: StoreCheckoutBranchService,
|
||||
private _kulturpassService: KulturPassService
|
||||
) {}
|
||||
|
||||
//#region shoppingcart
|
||||
@@ -231,6 +230,10 @@ export class DomainCheckoutService {
|
||||
);
|
||||
}
|
||||
|
||||
canAddItemsKulturpass(payload: ProductDTO[]): Observable<KulturPassResult[]> {
|
||||
return this._kulturpassService.KulturPassCanAddForKulturPass({ payload }).pipe(map((response) => response?.result));
|
||||
}
|
||||
|
||||
canAddItems({
|
||||
processId,
|
||||
payload,
|
||||
@@ -701,57 +704,60 @@ export class DomainCheckoutService {
|
||||
* @returns true if the availability of all items is valid
|
||||
*/
|
||||
validateOlaStatus({ processId, interval }: { processId: number; interval?: number }): Observable<boolean> {
|
||||
return new Observable<boolean>((observer) => {
|
||||
const enity$ = this.store.select(DomainCheckoutSelectors.selectCheckoutEntityByProcessId, { processId });
|
||||
return rxjsInterval(interval ?? this.olaExpiration / 10).pipe(
|
||||
startWith(0),
|
||||
switchMap(() =>
|
||||
this.store.select(DomainCheckoutSelectors.selectCheckoutEntityByProcessId, { processId }).pipe(
|
||||
map((entity) => {
|
||||
const now = Date.now();
|
||||
if (!entity || !entity.shoppingCart || !entity.shoppingCart.items) {
|
||||
return;
|
||||
}
|
||||
|
||||
const olaExpiration = this.olaExpiration;
|
||||
const itemAvailabilityTimestamp = entity.itemAvailabilityTimestamp ?? {};
|
||||
const shoppingCart = entity.shoppingCart;
|
||||
|
||||
let timeout: any;
|
||||
const timestamps = shoppingCart.items
|
||||
?.map((i) => i.data)
|
||||
?.filter((item) => !!item?.features?.orderType)
|
||||
?.map((item) => {
|
||||
const orderType = item.features.orderType;
|
||||
|
||||
let subscription: Subscription;
|
||||
let timestamp = itemAvailabilityTimestamp[`${item.id}_${orderType}`];
|
||||
|
||||
function check() {
|
||||
const now = Date.now();
|
||||
if (timestamp) {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
subscription?.unsubscribe();
|
||||
subscription = enity$.pipe(take(1)).subscribe((entity) => {
|
||||
if (!entity || !entity.shoppingCart || !entity.shoppingCart.items) {
|
||||
return;
|
||||
}
|
||||
if (orderType.endsWith('Versand')) {
|
||||
timestamp =
|
||||
itemAvailabilityTimestamp[`${item.id}_Versand`] ??
|
||||
itemAvailabilityTimestamp[`${item.id}_DIG-Versand`] ??
|
||||
itemAvailabilityTimestamp[`${item.id}_B2B-Versand`];
|
||||
}
|
||||
|
||||
const itemAvailabilityTimestamp = entity.itemAvailabilityTimestamp ?? {};
|
||||
const shoppingCart = entity.shoppingCart;
|
||||
return timestamp;
|
||||
})
|
||||
?.filter((timestamp) => !!timestamp);
|
||||
|
||||
const timestamps = shoppingCart.items
|
||||
?.map((i) => i.data)
|
||||
?.filter((item) => !!item?.features?.orderType)
|
||||
?.map((item) => itemAvailabilityTimestamp[`${item.id}_${item.features.orderType}`]);
|
||||
if (timestamps?.length > 0) {
|
||||
const oldestTimestamp = Math.min(...timestamps);
|
||||
const expirationTimestamp = oldestTimestamp + this.olaExpiration;
|
||||
return expirationTimestamp > now;
|
||||
}
|
||||
|
||||
if (timestamps?.length > 0) {
|
||||
const oldestTimestamp = Math.min(...timestamps);
|
||||
observer.next(now - oldestTimestamp < olaExpiration);
|
||||
}
|
||||
|
||||
timeout = setTimeout(() => {
|
||||
check.call(this);
|
||||
}, interval ?? olaExpiration / 10);
|
||||
});
|
||||
}
|
||||
|
||||
check.call(this);
|
||||
|
||||
return () => {
|
||||
subscription?.unsubscribe();
|
||||
clearTimeout(timeout);
|
||||
};
|
||||
}).pipe(distinctUntilChanged());
|
||||
return false;
|
||||
})
|
||||
)
|
||||
),
|
||||
distinctUntilChanged()
|
||||
);
|
||||
}
|
||||
|
||||
validateAvailabilities({ processId }: { processId: number }): Observable<boolean> {
|
||||
return this.getShoppingCart({ processId }).pipe(
|
||||
map((shoppingCart) => {
|
||||
const items = shoppingCart?.items?.map((item) => item.data) || [];
|
||||
|
||||
return items.every((i) => this.availabilityService.isAvailable({ availability: i.availability }));
|
||||
})
|
||||
);
|
||||
@@ -1015,6 +1021,7 @@ export class DomainCheckoutService {
|
||||
|
||||
//#region Common
|
||||
|
||||
@memorize()
|
||||
canSetCustomer({
|
||||
processId,
|
||||
customerFeatures,
|
||||
@@ -1022,24 +1029,26 @@ export class DomainCheckoutService {
|
||||
processId: number;
|
||||
customerFeatures?: { [key: string]: string };
|
||||
}): Observable<{ ok?: boolean; filter?: { [key: string]: string }; message?: string; create?: InputDTO }> {
|
||||
return this.getShoppingCart({ processId }).pipe(
|
||||
first(),
|
||||
mergeMap((shoppingCart) =>
|
||||
this._shoppingCartService
|
||||
.StoreCheckoutShoppingCartCanAddBuyer({
|
||||
shoppingCartId: shoppingCart.id,
|
||||
payload: { customerFeatures },
|
||||
})
|
||||
.pipe(
|
||||
map((response) => ({
|
||||
ok: response.result.ok,
|
||||
filter: response.result.queryToken?.filter || {},
|
||||
message: response.message,
|
||||
create: response.result.create,
|
||||
}))
|
||||
)
|
||||
return this.getShoppingCart({ processId })
|
||||
.pipe(
|
||||
first(),
|
||||
mergeMap((shoppingCart) =>
|
||||
this._shoppingCartService
|
||||
.StoreCheckoutShoppingCartCanAddBuyer({
|
||||
shoppingCartId: shoppingCart.id,
|
||||
payload: { customerFeatures },
|
||||
})
|
||||
.pipe(
|
||||
map((response) => ({
|
||||
ok: response.result.ok,
|
||||
filter: response.result.queryToken?.filter || {},
|
||||
message: response.message,
|
||||
create: response.result.create,
|
||||
}))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
.pipe(shareReplay(1));
|
||||
}
|
||||
|
||||
setNotificationChannels({ processId, notificationChannels }: { processId: number; notificationChannels: NotificationChannel }): void {
|
||||
|
||||
@@ -22,5 +22,5 @@ export interface CheckoutEntity {
|
||||
specialComment: string;
|
||||
notificationChannels: NotificationChannel;
|
||||
olaErrorIds: number[];
|
||||
itemAvailabilityTimestamp: Record<string, number>;
|
||||
itemAvailabilityTimestamp: Record<string, number | undefined>;
|
||||
}
|
||||
|
||||
88
apps/domain/oms/src/lib/action-handler-services.ts
Normal file
88
apps/domain/oms/src/lib/action-handler-services.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { ActionHandler } from '@core/command';
|
||||
import {
|
||||
AcceptedActionHandler,
|
||||
ArrivedActionHandler,
|
||||
AssembledActionHandler,
|
||||
AvailableForDownloadActionHandler,
|
||||
BackToStockActionHandler,
|
||||
CanceledByBuyerActionHandler,
|
||||
CanceledByRetailerActionHandler,
|
||||
CanceledBySupplierActionHandler,
|
||||
CreateShippingNoteActionHandler,
|
||||
DeliveredActionHandler,
|
||||
DetermineSupplierActionHandler,
|
||||
DispatchedActionHandler,
|
||||
DownloadedActionHandler,
|
||||
FetchedActionHandler,
|
||||
InProcessActionHandler,
|
||||
NotAvailableActionHandler,
|
||||
NotFetchedActionHandler,
|
||||
OrderAtSupplierActionHandler,
|
||||
OrderingActionHandler,
|
||||
OverdueActionHandler,
|
||||
PackedActionHandler,
|
||||
ParkedActionHandler,
|
||||
PlacedActionHandler,
|
||||
PreparationForShippingActionHandler,
|
||||
PrintCompartmentLabelActionHandler,
|
||||
PrintShippingNoteActionHandler,
|
||||
ReOrderActionHandler,
|
||||
RedirectedInternaqllyActionHandler,
|
||||
RequestedActionHandler,
|
||||
ReserverdActionHandler,
|
||||
ReturnedByBuyerActionHandler,
|
||||
ShippingNoteActionHandler,
|
||||
SupplierTemporarilyOutOfStockActionHandler,
|
||||
ReOrderedActionHandler,
|
||||
CollectOnDeliveryNoteActionHandler,
|
||||
PrintPriceDiffQrCodeLabelActionHandler,
|
||||
CollectWithSmallAmountinvoiceActionHandler,
|
||||
PrintSmallamountinvoiceActionHandler,
|
||||
ShopWithKulturpassActionHandler,
|
||||
ChangeOrderItemStatusBaseActionHandler,
|
||||
CreateReturnItemActionHandler,
|
||||
} from './action-handlers';
|
||||
import { Type } from '@angular/core';
|
||||
|
||||
export const ActionHandlerServices: Type<ActionHandler>[] = [
|
||||
AcceptedActionHandler,
|
||||
ArrivedActionHandler,
|
||||
AssembledActionHandler,
|
||||
AvailableForDownloadActionHandler,
|
||||
BackToStockActionHandler,
|
||||
CanceledByBuyerActionHandler,
|
||||
CanceledByRetailerActionHandler,
|
||||
CanceledBySupplierActionHandler,
|
||||
CreateShippingNoteActionHandler,
|
||||
DeliveredActionHandler,
|
||||
DetermineSupplierActionHandler,
|
||||
DispatchedActionHandler,
|
||||
DownloadedActionHandler,
|
||||
FetchedActionHandler,
|
||||
InProcessActionHandler,
|
||||
NotAvailableActionHandler,
|
||||
NotFetchedActionHandler,
|
||||
OrderAtSupplierActionHandler,
|
||||
OrderingActionHandler,
|
||||
OverdueActionHandler,
|
||||
PackedActionHandler,
|
||||
ParkedActionHandler,
|
||||
PlacedActionHandler,
|
||||
PreparationForShippingActionHandler,
|
||||
PrintCompartmentLabelActionHandler,
|
||||
PrintShippingNoteActionHandler,
|
||||
ReOrderActionHandler,
|
||||
RedirectedInternaqllyActionHandler,
|
||||
RequestedActionHandler,
|
||||
ReserverdActionHandler,
|
||||
ReturnedByBuyerActionHandler,
|
||||
ShippingNoteActionHandler,
|
||||
SupplierTemporarilyOutOfStockActionHandler,
|
||||
ReOrderedActionHandler,
|
||||
CollectOnDeliveryNoteActionHandler,
|
||||
PrintPriceDiffQrCodeLabelActionHandler,
|
||||
CollectWithSmallAmountinvoiceActionHandler,
|
||||
PrintSmallamountinvoiceActionHandler,
|
||||
ShopWithKulturpassActionHandler,
|
||||
CreateReturnItemActionHandler,
|
||||
];
|
||||
@@ -2,6 +2,7 @@
|
||||
* Public API Surface of oms
|
||||
*/
|
||||
|
||||
export * from './lib/action-handler-services';
|
||||
export * from './lib/goods.service';
|
||||
export * from './lib/receipt.service';
|
||||
export * from './lib/oms.service';
|
||||
|
||||
51
apps/domain/pickup-shelf/src/lib/pickup-shelf-in.service.ts
Normal file
51
apps/domain/pickup-shelf/src/lib/pickup-shelf-in.service.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { AbholfachService, AutocompleteTokenDTO, ListResponseArgsOfDBHOrderItemListItemDTO, QueryTokenDTO } from '@swagger/oms';
|
||||
import { PickupShelfIOService } from './pickup-shelf-io.service';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class PickupShelfInService extends PickupShelfIOService {
|
||||
private _abholfachService = inject(AbholfachService);
|
||||
|
||||
getQuerySettings() {
|
||||
return this._abholfachService.AbholfachWareneingangQuerySettings();
|
||||
}
|
||||
|
||||
search(queryToken: QueryTokenDTO) {
|
||||
return this._abholfachService.AbholfachWareneingang(queryToken);
|
||||
}
|
||||
|
||||
complete(autocompleteToken: AutocompleteTokenDTO) {
|
||||
return this._abholfachService.AbholfachWareneingangAutocomplete(autocompleteToken);
|
||||
}
|
||||
|
||||
getOrderItemsByOrderNumberOrCompartmentCode(args: {
|
||||
orderNumber?: string;
|
||||
compartmentCode?: string;
|
||||
}): Observable<ListResponseArgsOfDBHOrderItemListItemDTO> {
|
||||
if (!args.orderNumber && !args.compartmentCode) {
|
||||
return throwError(
|
||||
'PickupShelfInService.getOrderItemsByOrderNumberOrCompartmentCode(): Either orderNumber or compartmentCode must be provided.'
|
||||
);
|
||||
}
|
||||
|
||||
return this._abholfachService.AbholfachWareneingang({
|
||||
input: {
|
||||
qs: args.compartmentCode ?? args.orderNumber,
|
||||
},
|
||||
filter: {
|
||||
all_branches: String(true),
|
||||
archive: String(false),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getOrderItemsByCustomerNumber(args: { customerNumber: string }): Observable<ListResponseArgsOfDBHOrderItemListItemDTO> {
|
||||
return this._abholfachService.AbholfachWareneingang({
|
||||
filter: { orderitemprocessingstatus: '16;128;8192;1048576' },
|
||||
input: {
|
||||
customer_name: args.customerNumber,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
25
apps/domain/pickup-shelf/src/lib/pickup-shelf-io.service.ts
Normal file
25
apps/domain/pickup-shelf/src/lib/pickup-shelf-io.service.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
AutocompleteTokenDTO,
|
||||
ListResponseArgsOfDBHOrderItemListItemDTO,
|
||||
QueryTokenDTO,
|
||||
ResponseArgsOfIEnumerableOfAutocompleteDTO,
|
||||
ResponseArgsOfQuerySettingsDTO,
|
||||
} from '@swagger/oms';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export abstract class PickupShelfIOService {
|
||||
abstract getQuerySettings(): Observable<ResponseArgsOfQuerySettingsDTO>;
|
||||
|
||||
abstract search(queryToken: QueryTokenDTO): Observable<ListResponseArgsOfDBHOrderItemListItemDTO>;
|
||||
|
||||
abstract complete(autocompleteToken: AutocompleteTokenDTO): Observable<ResponseArgsOfIEnumerableOfAutocompleteDTO>;
|
||||
|
||||
abstract getOrderItemsByOrderNumberOrCompartmentCode(args: {
|
||||
orderNumber?: string;
|
||||
compartmentCode?: string;
|
||||
}): Observable<ListResponseArgsOfDBHOrderItemListItemDTO>;
|
||||
|
||||
abstract getOrderItemsByCustomerNumber(args: { customerNumber: string }): Observable<ListResponseArgsOfDBHOrderItemListItemDTO>;
|
||||
}
|
||||
46
apps/domain/pickup-shelf/src/lib/pickup-shelf-out.service.ts
Normal file
46
apps/domain/pickup-shelf/src/lib/pickup-shelf-out.service.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { AbholfachService, AutocompleteTokenDTO, ListResponseArgsOfDBHOrderItemListItemDTO, QueryTokenDTO } from '@swagger/oms';
|
||||
import { PickupShelfIOService } from './pickup-shelf-io.service';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class PickupShelfOutService extends PickupShelfIOService {
|
||||
private _abholfachService = inject(AbholfachService);
|
||||
|
||||
getQuerySettings() {
|
||||
return this._abholfachService.AbholfachWarenausgabeQuerySettings();
|
||||
}
|
||||
|
||||
search(queryToken: QueryTokenDTO) {
|
||||
return this._abholfachService.AbholfachWarenausgabe(queryToken);
|
||||
}
|
||||
|
||||
complete(autocompleteToken: AutocompleteTokenDTO) {
|
||||
return this._abholfachService.AbholfachWarenausgabeAutocomplete(autocompleteToken);
|
||||
}
|
||||
|
||||
getOrderItemsByOrderNumberOrCompartmentCode(args: {
|
||||
orderNumber?: string;
|
||||
compartmentCode?: string;
|
||||
}): Observable<ListResponseArgsOfDBHOrderItemListItemDTO> {
|
||||
if (!args.orderNumber && !args.compartmentCode) {
|
||||
return throwError(
|
||||
'PickupShelfOutService.getOrderItemsByOrderNumberOrCompartmentCode(): Either orderNumber or compartmentCode must be provided.'
|
||||
);
|
||||
}
|
||||
|
||||
return this._abholfachService.AbholfachWarenausgabe({
|
||||
input: {
|
||||
qs: args.compartmentCode ?? args.orderNumber,
|
||||
},
|
||||
filter: {
|
||||
all_branches: String(true),
|
||||
archive: String(false),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getOrderItemsByCustomerNumber(args: { customerNumber: string }): Observable<ListResponseArgsOfDBHOrderItemListItemDTO> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
27
apps/domain/pickup-shelf/src/lib/pickup-shelf.service.ts
Normal file
27
apps/domain/pickup-shelf/src/lib/pickup-shelf.service.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { DBHOrderItemListItemDTO, OrderItemDTO, OrderItemSubsetDTO, OrderService } from '@swagger/oms';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class PickupShelfService {
|
||||
private _orderService = inject(OrderService);
|
||||
|
||||
getOrderByOrderId(orderId: number) {
|
||||
return this._orderService.OrderGetOrder(orderId);
|
||||
}
|
||||
patchOrderItemSubset(item: DBHOrderItemListItemDTO, changes: Partial<OrderItemSubsetDTO>) {
|
||||
return this._orderService.OrderPatchOrderItemSubset({
|
||||
orderId: item.orderId,
|
||||
orderItemId: item.orderItemId,
|
||||
orderItemSubsetId: item.orderItemSubsetId,
|
||||
orderItemSubset: changes,
|
||||
});
|
||||
}
|
||||
|
||||
getOrderItemSubsetTasks(item: DBHOrderItemListItemDTO) {
|
||||
return this._orderService.OrderGetOrderItemSubsetTasks({
|
||||
orderId: item.orderId,
|
||||
orderItemId: item.orderItemId,
|
||||
orderItemSubsetId: item.orderItemSubsetId,
|
||||
});
|
||||
}
|
||||
}
|
||||
4
apps/domain/pickup-shelf/src/public-api.ts
Normal file
4
apps/domain/pickup-shelf/src/public-api.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from './lib/pickup-shelf-in.service';
|
||||
export * from './lib/pickup-shelf-io.service';
|
||||
export * from './lib/pickup-shelf-out.service';
|
||||
export * from './lib/pickup-shelf.service';
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isDevMode, NgModule } from '@angular/core';
|
||||
import { inject, isDevMode, NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import {
|
||||
CanActivateCartGuard,
|
||||
@@ -22,6 +22,9 @@ import { MainComponent } from './main.component';
|
||||
import { PreviewComponent } from './preview';
|
||||
import { BranchSectionResolver, CustomerSectionResolver, ProcessIdResolver } from './resolvers';
|
||||
import { TokenLoginComponent, TokenLoginModule } from './token-login';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { ProcessIdGuard } from './guards/process-id.guard';
|
||||
import { ActivateProcessIdGuard, ActivateProcessIdWithConfigKeyGuard } from './guards/activate-process-id.guard';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@@ -36,111 +39,111 @@ const routes: Routes = [
|
||||
canActivate: [IsAuthenticatedGuard],
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
canActivate: [],
|
||||
path: 'kunde',
|
||||
component: MainComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'kunde',
|
||||
component: MainComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'dashboard',
|
||||
loadChildren: () => import('@page/dashboard').then((m) => m.DashboardModule),
|
||||
},
|
||||
{
|
||||
path: 'product',
|
||||
loadChildren: () => import('@page/catalog').then((m) => m.PageCatalogModule),
|
||||
canActivate: [CanActivateProductGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/product',
|
||||
loadChildren: () => import('@page/catalog').then((m) => m.PageCatalogModule),
|
||||
canActivate: [CanActivateProductWithProcessIdGuard],
|
||||
resolve: { processId: ProcessIdResolver },
|
||||
},
|
||||
{
|
||||
path: 'order',
|
||||
loadChildren: () => import('@page/customer-order').then((m) => m.CustomerOrderModule),
|
||||
canActivate: [CanActivateCustomerOrdersGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/order',
|
||||
loadChildren: () => import('@page/customer-order').then((m) => m.CustomerOrderModule),
|
||||
canActivate: [CanActivateCustomerOrdersWithProcessIdGuard],
|
||||
resolve: { processId: ProcessIdResolver },
|
||||
},
|
||||
{
|
||||
path: 'customer',
|
||||
loadChildren: () => import('@page/customer').then((m) => m.CustomerModule),
|
||||
canActivate: [CanActivateCustomerGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/customer',
|
||||
loadChildren: () => import('@page/customer').then((m) => m.CustomerModule),
|
||||
canActivate: [CanActivateCustomerWithProcessIdGuard],
|
||||
resolve: { processId: ProcessIdResolver },
|
||||
},
|
||||
{
|
||||
path: 'cart',
|
||||
loadChildren: () => import('@page/checkout').then((m) => m.PageCheckoutModule),
|
||||
canActivate: [CanActivateCartGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/cart',
|
||||
loadChildren: () => import('@page/checkout').then((m) => m.PageCheckoutModule),
|
||||
canActivate: [CanActivateCartWithProcessIdGuard],
|
||||
},
|
||||
{
|
||||
path: 'goods/out',
|
||||
loadChildren: () => import('@page/goods-out').then((m) => m.GoodsOutModule),
|
||||
canActivate: [CanActivateGoodsOutGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/goods/out',
|
||||
loadChildren: () => import('@page/goods-out').then((m) => m.GoodsOutModule),
|
||||
canActivate: [CanActivateGoodsOutWithProcessIdGuard],
|
||||
resolve: { processId: ProcessIdResolver },
|
||||
},
|
||||
{ path: '**', redirectTo: 'dashboard', pathMatch: 'full' },
|
||||
],
|
||||
resolve: { section: CustomerSectionResolver },
|
||||
path: 'dashboard',
|
||||
loadChildren: () => import('@page/dashboard').then((m) => m.DashboardModule),
|
||||
},
|
||||
{
|
||||
path: 'filiale',
|
||||
component: MainComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'task-calendar',
|
||||
loadChildren: () => import('@page/task-calendar').then((m) => m.PageTaskCalendarModule),
|
||||
canActivate: [CanActivateTaskCalendarGuard],
|
||||
},
|
||||
{
|
||||
path: 'goods/in',
|
||||
loadChildren: () => import('@page/goods-in').then((m) => m.GoodsInModule),
|
||||
canActivate: [CanActivateGoodsInGuard],
|
||||
},
|
||||
{
|
||||
path: 'remission',
|
||||
loadChildren: () => import('@page/remission').then((m) => m.PageRemissionModule),
|
||||
canActivate: [CanActivateRemissionGuard],
|
||||
},
|
||||
{
|
||||
path: 'package-inspection',
|
||||
loadChildren: () => import('@page/package-inspection').then((m) => m.PackageInspectionModule),
|
||||
canActivate: [CanActivatePackageInspectionGuard],
|
||||
},
|
||||
{
|
||||
path: 'assortment',
|
||||
loadChildren: () => import('@page/assortment').then((m) => m.AssortmentModule),
|
||||
canActivate: [CanActivateAssortmentGuard],
|
||||
},
|
||||
{ path: '**', redirectTo: 'task-calendar', pathMatch: 'full' },
|
||||
],
|
||||
resolve: { section: BranchSectionResolver },
|
||||
path: 'product',
|
||||
loadChildren: () => import('@page/catalog').then((m) => m.PageCatalogModule),
|
||||
canActivate: [CanActivateProductGuard],
|
||||
},
|
||||
{ path: '**', redirectTo: 'kunde', pathMatch: 'full' },
|
||||
{
|
||||
path: ':processId/product',
|
||||
loadChildren: () => import('@page/catalog').then((m) => m.PageCatalogModule),
|
||||
canActivate: [CanActivateProductWithProcessIdGuard],
|
||||
resolve: { processId: ProcessIdResolver },
|
||||
},
|
||||
{
|
||||
path: 'order',
|
||||
loadChildren: () => import('@page/customer-order').then((m) => m.CustomerOrderModule),
|
||||
canActivate: [CanActivateCustomerOrdersGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/order',
|
||||
loadChildren: () => import('@page/customer-order').then((m) => m.CustomerOrderModule),
|
||||
canActivate: [CanActivateCustomerOrdersWithProcessIdGuard],
|
||||
resolve: { processId: ProcessIdResolver },
|
||||
},
|
||||
{
|
||||
path: 'customer',
|
||||
loadChildren: () => import('@page/customer').then((m) => m.CustomerModule),
|
||||
canActivate: [CanActivateCustomerGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/customer',
|
||||
loadChildren: () => import('@page/customer').then((m) => m.CustomerModule),
|
||||
canActivate: [CanActivateCustomerWithProcessIdGuard],
|
||||
resolve: { processId: ProcessIdResolver },
|
||||
},
|
||||
{
|
||||
path: 'cart',
|
||||
loadChildren: () => import('@page/checkout').then((m) => m.PageCheckoutModule),
|
||||
canActivate: [CanActivateCartGuard],
|
||||
},
|
||||
{
|
||||
path: ':processId/cart',
|
||||
loadChildren: () => import('@page/checkout').then((m) => m.PageCheckoutModule),
|
||||
canActivate: [CanActivateCartWithProcessIdGuard],
|
||||
},
|
||||
{
|
||||
path: 'pickup-shelf',
|
||||
canActivate: [ProcessIdGuard],
|
||||
// NOTE: This is a workaround for the canActivate guard not being called
|
||||
loadChildren: () => import('@page/pickup-shelf').then((m) => m.PickupShelfOutModule),
|
||||
},
|
||||
{
|
||||
path: ':processId/pickup-shelf',
|
||||
canActivate: [ActivateProcessIdGuard],
|
||||
loadChildren: () => import('@page/pickup-shelf').then((m) => m.PickupShelfOutModule),
|
||||
},
|
||||
{ path: '**', redirectTo: 'dashboard', pathMatch: 'full' },
|
||||
],
|
||||
resolve: { section: CustomerSectionResolver },
|
||||
},
|
||||
{
|
||||
path: 'filiale',
|
||||
component: MainComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'task-calendar',
|
||||
loadChildren: () => import('@page/task-calendar').then((m) => m.PageTaskCalendarModule),
|
||||
canActivate: [CanActivateTaskCalendarGuard],
|
||||
},
|
||||
{
|
||||
path: 'pickup-shelf',
|
||||
canActivate: [ActivateProcessIdWithConfigKeyGuard('pickupShelf')],
|
||||
// NOTE: This is a workaround for the canActivate guard not being called
|
||||
loadChildren: () => import('@page/pickup-shelf').then((m) => m.PickupShelfInModule),
|
||||
},
|
||||
{
|
||||
path: 'goods/in',
|
||||
loadChildren: () => import('@page/goods-in').then((m) => m.GoodsInModule),
|
||||
canActivate: [CanActivateGoodsInGuard],
|
||||
},
|
||||
{
|
||||
path: 'remission',
|
||||
loadChildren: () => import('@page/remission').then((m) => m.PageRemissionModule),
|
||||
canActivate: [CanActivateRemissionGuard],
|
||||
},
|
||||
{
|
||||
path: 'package-inspection',
|
||||
loadChildren: () => import('@page/package-inspection').then((m) => m.PackageInspectionModule),
|
||||
canActivate: [CanActivatePackageInspectionGuard],
|
||||
},
|
||||
{
|
||||
path: 'assortment',
|
||||
loadChildren: () => import('@page/assortment').then((m) => m.AssortmentModule),
|
||||
canActivate: [CanActivateAssortmentGuard],
|
||||
},
|
||||
{ path: '**', redirectTo: 'task-calendar', pathMatch: 'full' },
|
||||
],
|
||||
resolve: { section: BranchSectionResolver },
|
||||
},
|
||||
{ path: '**', redirectTo: 'kunde', pathMatch: 'full' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
46
apps/isa-app/src/app/guards/activate-process-id.guard.ts
Normal file
46
apps/isa-app/src/app/guards/activate-process-id.guard.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { inject } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivateFn, RouterStateSnapshot } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { Config } from '@core/config';
|
||||
import { take } from 'rxjs/operators';
|
||||
|
||||
export const ActivateProcessIdGuard: CanActivateFn = async (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
|
||||
const application = inject(ApplicationService);
|
||||
|
||||
const processIdStr = route.params.processId;
|
||||
|
||||
if (!processIdStr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const processId = Number(processIdStr);
|
||||
|
||||
// Check if Process already exists
|
||||
const process = await application.getProcessById$(processId).pipe(take(1)).toPromise();
|
||||
|
||||
if (!process) {
|
||||
application.createCustomerProcess(processId);
|
||||
}
|
||||
|
||||
application.activateProcess(processId);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
export const ActivateProcessIdWithConfigKeyGuard: (key: string) => CanActivateFn = (key) => async (
|
||||
route: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot
|
||||
) => {
|
||||
const application = inject(ApplicationService);
|
||||
const config = inject(Config);
|
||||
|
||||
const processId = config.get(`process.ids.${key}`);
|
||||
|
||||
if (isNaN(processId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
application.activateProcess(processId);
|
||||
|
||||
return true;
|
||||
};
|
||||
@@ -2,6 +2,7 @@ import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { ApplicationProcess, ApplicationService } from '@core/application';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { CustomerSearchNavigation } from '@shared/services';
|
||||
import { first } from 'rxjs/operators';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
@@ -9,7 +10,8 @@ export class CanActivateCustomerGuard {
|
||||
constructor(
|
||||
private readonly _applicationService: ApplicationService,
|
||||
private readonly _checkoutService: DomainCheckoutService,
|
||||
private readonly _router: Router
|
||||
private readonly _router: Router,
|
||||
private readonly _navigation: CustomerSearchNavigation
|
||||
) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
@@ -41,11 +43,17 @@ export class CanActivateCustomerGuard {
|
||||
await this.fromCartProcess(processes);
|
||||
return false;
|
||||
} else {
|
||||
await this._router.navigate(['/kunde', String(lastActivatedProcessId), 'customer']);
|
||||
await this.navigateToDefaultRoute(lastActivatedProcessId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async navigateToDefaultRoute(processId: number) {
|
||||
const route = this._navigation.defaultRoute({ processId });
|
||||
|
||||
await this._router.navigate(route.path, { queryParams: route.queryParams });
|
||||
}
|
||||
|
||||
// Bei offener Artikelsuche/Kundensuche und Klick auf Footer Kundensuche
|
||||
async fromCartProcess(processes: ApplicationProcess[]) {
|
||||
const newProcessId = Date.now();
|
||||
@@ -56,7 +64,7 @@ export class CanActivateCustomerGuard {
|
||||
name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === 'cart'))}`,
|
||||
});
|
||||
|
||||
await this._router.navigate(['/kunde', String(newProcessId), 'customer']);
|
||||
await this.navigateToDefaultRoute(newProcessId);
|
||||
}
|
||||
|
||||
// Bei offener Bestellbestätigung und Klick auf Footer Kundensuche
|
||||
@@ -74,7 +82,7 @@ export class CanActivateCustomerGuard {
|
||||
});
|
||||
|
||||
// Navigation
|
||||
await this._router.navigate(['/kunde', String(processId), 'customer']);
|
||||
await this.navigateToDefaultRoute(processId);
|
||||
}
|
||||
|
||||
// Bei offener Warenausgabe und Klick auf Footer Kundensuche
|
||||
@@ -98,7 +106,7 @@ export class CanActivateCustomerGuard {
|
||||
});
|
||||
|
||||
// Navigation
|
||||
await this._router.navigate(['/kunde', String(processId), 'customer']);
|
||||
await this.navigateToDefaultRoute(processId);
|
||||
}
|
||||
|
||||
processNumber(processes: ApplicationProcess[]) {
|
||||
|
||||
33
apps/isa-app/src/app/guards/process-id.guard.ts
Normal file
33
apps/isa-app/src/app/guards/process-id.guard.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { inject } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivateFn, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { take } from 'rxjs/operators';
|
||||
|
||||
export const ProcessIdGuard: CanActivateFn = async (
|
||||
route: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot
|
||||
): Promise<boolean | UrlTree> => {
|
||||
const application = inject(ApplicationService);
|
||||
const router = inject(Router);
|
||||
|
||||
const process = await application.getLastActivatedProcessWithSection$('customer').pipe(take(1)).toPromise();
|
||||
|
||||
const processId = process?.id ?? Date.now();
|
||||
|
||||
const originalUrl = state.url?.split('?')[0] ?? '';
|
||||
|
||||
let url: string = '';
|
||||
|
||||
if (originalUrl.startsWith('/kunde')) {
|
||||
url = originalUrl.replace('/kunde', `/kunde/${processId}`);
|
||||
} else {
|
||||
url = originalUrl;
|
||||
}
|
||||
|
||||
if (originalUrl === url) {
|
||||
return true;
|
||||
}
|
||||
|
||||
await router.navigateByUrl(url);
|
||||
return false;
|
||||
};
|
||||
@@ -6,6 +6,10 @@
|
||||
"name": "account",
|
||||
"data": "M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z"
|
||||
},
|
||||
{
|
||||
"name": "account-circle",
|
||||
"data": "M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M7.07,18.28C7.5,17.38 10.12,16.5 12,16.5C13.88,16.5 16.5,17.38 16.93,18.28C15.57,19.36 13.86,20 12,20C10.14,20 8.43,19.36 7.07,18.28M18.36,16.83C16.93,15.09 13.46,14.5 12,14.5C10.54,14.5 7.07,15.09 5.64,16.83C4.62,15.5 4,13.82 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,13.82 19.38,15.5 18.36,16.83M12,6C10.06,6 8.5,7.56 8.5,9.5C8.5,11.44 10.06,13 12,13C13.94,13 15.5,11.44 15.5,9.5C15.5,7.56 13.94,6 12,6M12,11A1.5,1.5 0 0,1 10.5,9.5A1.5,1.5 0 0,1 12,8A1.5,1.5 0 0,1 13.5,9.5A1.5,1.5 0 0,1 12,11Z"
|
||||
},
|
||||
{
|
||||
"name": "package-variant-closed",
|
||||
"data": "M21,16.5C21,16.88 20.79,17.21 20.47,17.38L12.57,21.82C12.41,21.94 12.21,22 12,22C11.79,22 11.59,21.94 11.43,21.82L3.53,17.38C3.21,17.21 3,16.88 3,16.5V7.5C3,7.12 3.21,6.79 3.53,6.62L11.43,2.18C11.59,2.06 11.79,2 12,2C12.21,2 12.41,2.06 12.57,2.18L20.47,6.62C20.79,6.79 21,7.12 21,7.5V16.5M12,4.15L10.11,5.22L16,8.61L17.96,7.5L12,4.15M6.04,7.5L12,10.85L13.96,9.75L8.08,6.35L6.04,7.5M5,15.91L11,19.29V12.58L5,9.21V15.91M19,15.91V9.21L13,12.58V19.29L19,15.91Z"
|
||||
|
||||
@@ -67,12 +67,13 @@
|
||||
"taskCalendar": 3000,
|
||||
"remission": 4000,
|
||||
"packageInspection": 5000,
|
||||
"assortment": 6000
|
||||
"assortment": 6000,
|
||||
"pickupShelf": 7000
|
||||
}
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
|
||||
"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=="
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
|
||||
|
||||
@@ -66,12 +66,13 @@
|
||||
"taskCalendar": 3000,
|
||||
"remission": 4000,
|
||||
"packageInspection": 5000,
|
||||
"assortment": 6000
|
||||
"assortment": 6000,
|
||||
"pickupShelf": 7000
|
||||
}
|
||||
},
|
||||
"checkForUpdates": 900000,
|
||||
"licence": {
|
||||
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
|
||||
"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=="
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
@@ -48,7 +48,7 @@
|
||||
"rootUrl": "https://isa-test.paragon-data.net/wws/v1"
|
||||
},
|
||||
"@domain/checkout": {
|
||||
"olaExpiration": "30s"
|
||||
"olaExpiration": "5m"
|
||||
},
|
||||
"hubs": {
|
||||
"notifications": {
|
||||
@@ -68,12 +68,13 @@
|
||||
"taskCalendar": 3000,
|
||||
"remission": 4000,
|
||||
"packageInspection": 5000,
|
||||
"assortment": 6000
|
||||
"assortment": 6000,
|
||||
"pickupShelf": 7000
|
||||
}
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
|
||||
"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=="
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
@@ -67,12 +67,13 @@
|
||||
"taskCalendar": 3000,
|
||||
"remission": 4000,
|
||||
"packageInspection": 5000,
|
||||
"assortment": 6000
|
||||
"assortment": 6000,
|
||||
"pickupShelf": 7000
|
||||
}
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "AZZzfQ+eLFl3Dzf1QSBag1lDibIoOPh4W33erRIRe3SDUMkHDX8eczEjd2TnfRMWoE5lXOBGtESCWICN9EbrmI1S9Lu5APsvvEOD+K54ADwIVawx0HNZRAc8/+9Vf/izcEGOFQFGBQJyR6vzdzFv5HcjznhxI9E3LiF+uVQPtCqsVYzpkMWIrC5VCg2uwNrj9Bw6f8zYi/lZPrDMS5yVKVcajeK7sh9QAq17dR0opjIIuP5t5nDEJ7hnITwtTR5HaM6cX/KhKpTILOgKexvLYqrK6QJWpU85sDwqwn6T7av4V68qL3XrUo60dScop4QsvraQe1HkRsffl6DkAEoX0RNMS5qVWjGerW7lvA/DQd9hsAO3jWFDR9hVDyt2VvmzzFKnHYqTYxC5qG4bCEJ0RJjy6tEP5Q7vL5SxWygVadmjPv+TwDOCS7DxzxIjcO+BXQY7gW6qn0hx9fXzyvO3avrGWqyImMlgEApZq+36ANqtRcPD/stEe4i0N9dSPhYoHPcc/9/9jpts43FozlgfY4wY8Wt5ybB3X0caISMmB/klFIJKKN7num439z3+Xk7ENB/Xvb0XAtnOt/cuxQYsGQ7fb62GOO/7Va5fdE9ZfaIJsS5ToE6oIbV04pLUssJf9cUMsyPFVELYSJmyGPQQFRz0TTxxRvPapIWrfa2x5x3hYUpNTAdY3v0fN9l/1ZqNSBmIBLH/LoXaVJQ2DydGD1/QFZ2Z/S7zTYKg5/cSEpUgiYtbwutNZSjRH29ucSizC524k+Zst95T8G7LJaWCT8SQAcKXqCnjpiEGWzD++h0jXjn6BWjUnIHi0te+27vF/z6UQL00sWco5hUIqF66EiU="
|
||||
"scandit": "AVljxT/dG+TAIDDL2jTxm843juR2OtZ6lHLxRpYR7x9uYiSvY2IAHdRx8tjsf9KU7wK0F5cAeb/nLMHF6Vor9ps79wvuBQw6G3N0IW978b78ZUgPOFzxHUAMuD8dbkDZlX8r9y1cOd9sT3UNEwGrQ4siUt2oCkigyTxJAgYs1ijnjQid7q42hHk3tMXywrAYeu5MhF0TV1H77DRDMxPHD/xiR0zhFQRB2Dtnm1+e3LHKCyQjZ/zknEpQB6HS7UbCBoEDj4tohb83E6oqmQFWwt85/Jk9f49gxXakIcNODnQI5H63kSqpEmV9Al1a5L+WGZ6Bq1gwBbnD8FBXlVqxoooiFXW7jzzBa9LNmQiQ5J8yEkIsPeyOHec7F4ERvVONSMYwWyH39ZweSiRsZRM1UsFPhN96bCT5MEwkjPFn4gji6TPGEceJZvV3HwsiCT5Bgjla4bvDsZ2jYvAr9tSij8kIii9dHvsWlrimt+szHJLSz+8uNI6jAvXyr2f3oRxZD/F9osZHVWkgtAc+vVWqkxVJCqmpmoHOXI6TFSqSjYHddhZyU5r2lgQt0+NI6k/bV3iN7Le1RJCP/wuSDCTZjzsU1igB7UnIN2Y70CqCjIeVH9qlxaI1YAC9lwFv1FZvsiueYeJP1n39mmXCSELVtzxgIBEX5yaIHNbbGXd+e8JUgcO8vJ2JA2kJudaU+xfYR5SY//+J1kPsNSbnBnM25LL+LjeRB3QTfqV5sFq8ORWcIMITvkEaRfP3PVcOzb+hO4Ren4ezhJuyADulmvG8a9Kxxk6ymzBbE7a93SGVbxp7OQNEmvTn5+B9wJ7/l1mtvZL2TilrDZBQVMYWrGuUGpA="
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
@@ -67,12 +67,13 @@
|
||||
"taskCalendar": 3000,
|
||||
"remission": 4000,
|
||||
"packageInspection": 5000,
|
||||
"assortment": 6000
|
||||
"assortment": 6000,
|
||||
"pickupShelf": 7000
|
||||
}
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "AZZzfQ+eLFl3Dzf1QSBag1lDibIoOPh4W33erRIRe3SDUMkHDX8eczEjd2TnfRMWoE5lXOBGtESCWICN9EbrmI1S9Lu5APsvvEOD+K54ADwIVawx0HNZRAc8/+9Vf/izcEGOFQFGBQJyR6vzdzFv5HcjznhxI9E3LiF+uVQPtCqsVYzpkMWIrC5VCg2uwNrj9Bw6f8zYi/lZPrDMS5yVKVcajeK7sh9QAq17dR0opjIIuP5t5nDEJ7hnITwtTR5HaM6cX/KhKpTILOgKexvLYqrK6QJWpU85sDwqwn6T7av4V68qL3XrUo60dScop4QsvraQe1HkRsffl6DkAEoX0RNMS5qVWjGerW7lvA/DQd9hsAO3jWFDR9hVDyt2VvmzzFKnHYqTYxC5qG4bCEJ0RJjy6tEP5Q7vL5SxWygVadmjPv+TwDOCS7DxzxIjcO+BXQY7gW6qn0hx9fXzyvO3avrGWqyImMlgEApZq+36ANqtRcPD/stEe4i0N9dSPhYoHPcc/9/9jpts43FozlgfY4wY8Wt5ybB3X0caISMmB/klFIJKKN7num439z3+Xk7ENB/Xvb0XAtnOt/cuxQYsGQ7fb62GOO/7Va5fdE9ZfaIJsS5ToE6oIbV04pLUssJf9cUMsyPFVELYSJmyGPQQFRz0TTxxRvPapIWrfa2x5x3hYUpNTAdY3v0fN9l/1ZqNSBmIBLH/LoXaVJQ2DydGD1/QFZ2Z/S7zTYKg5/cSEpUgiYtbwutNZSjRH29ucSizC524k+Zst95T8G7LJaWCT8SQAcKXqCnjpiEGWzD++h0jXjn6BWjUnIHi0te+27vF/z6UQL00sWco5hUIqF66EiU="
|
||||
"scandit": "AVljxT/dG+TAIDDL2jTxm843juR2OtZ6lHLxRpYR7x9uYiSvY2IAHdRx8tjsf9KU7wK0F5cAeb/nLMHF6Vor9ps79wvuBQw6G3N0IW978b78ZUgPOFzxHUAMuD8dbkDZlX8r9y1cOd9sT3UNEwGrQ4siUt2oCkigyTxJAgYs1ijnjQid7q42hHk3tMXywrAYeu5MhF0TV1H77DRDMxPHD/xiR0zhFQRB2Dtnm1+e3LHKCyQjZ/zknEpQB6HS7UbCBoEDj4tohb83E6oqmQFWwt85/Jk9f49gxXakIcNODnQI5H63kSqpEmV9Al1a5L+WGZ6Bq1gwBbnD8FBXlVqxoooiFXW7jzzBa9LNmQiQ5J8yEkIsPeyOHec7F4ERvVONSMYwWyH39ZweSiRsZRM1UsFPhN96bCT5MEwkjPFn4gji6TPGEceJZvV3HwsiCT5Bgjla4bvDsZ2jYvAr9tSij8kIii9dHvsWlrimt+szHJLSz+8uNI6jAvXyr2f3oRxZD/F9osZHVWkgtAc+vVWqkxVJCqmpmoHOXI6TFSqSjYHddhZyU5r2lgQt0+NI6k/bV3iN7Le1RJCP/wuSDCTZjzsU1igB7UnIN2Y70CqCjIeVH9qlxaI1YAC9lwFv1FZvsiueYeJP1n39mmXCSELVtzxgIBEX5yaIHNbbGXd+e8JUgcO8vJ2JA2kJudaU+xfYR5SY//+J1kPsNSbnBnM25LL+LjeRB3QTfqV5sFq8ORWcIMITvkEaRfP3PVcOzb+hO4Ren4ezhJuyADulmvG8a9Kxxk6ymzBbE7a93SGVbxp7OQNEmvTn5+B9wJ7/l1mtvZL2TilrDZBQVMYWrGuUGpA="
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
@@ -68,12 +68,13 @@
|
||||
"taskCalendar": 3000,
|
||||
"remission": 4000,
|
||||
"packageInspection": 5000,
|
||||
"assortment": 6000
|
||||
"assortment": 6000,
|
||||
"pickupShelf": 7000
|
||||
}
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
|
||||
"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=="
|
||||
},
|
||||
"@shared/icon": "/assets/icons.json"
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, inject } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { PickupShelfInNavigationService } from '@shared/services';
|
||||
import { UiFilter } from '@ui/filter';
|
||||
import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
|
||||
|
||||
@@ -9,6 +10,8 @@ import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ModalNotificationsRemissionGroupComponent {
|
||||
private _pickupShelfInNavigationService = inject(PickupShelfInNavigationService);
|
||||
|
||||
@Input()
|
||||
notifications: MessageBoardItemDTO[];
|
||||
|
||||
@@ -18,8 +21,14 @@ export class ModalNotificationsRemissionGroupComponent {
|
||||
constructor(private _router: Router) {}
|
||||
|
||||
itemSelected(item: MessageBoardItemDTO) {
|
||||
const defaultNav = this._pickupShelfInNavigationService.listRoute();
|
||||
const queryParams = UiFilter.getQueryParamsFromQueryTokenDTO(item.queryToken);
|
||||
this._router.navigate(['/filiale/goods/in/results'], { queryParams });
|
||||
this._router.navigate(defaultNav.path, {
|
||||
queryParams: {
|
||||
...defaultNav.queryParams,
|
||||
...queryParams,
|
||||
},
|
||||
});
|
||||
this.navigated.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, inject } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { PickupShelfInNavigationService } from '@shared/services';
|
||||
import { UiFilter } from '@ui/filter';
|
||||
import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
|
||||
|
||||
@@ -9,6 +10,7 @@ import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ModalNotificationsReservationGroupComponent {
|
||||
private _pickupShelfInNavigationService = inject(PickupShelfInNavigationService);
|
||||
@Input()
|
||||
notifications: MessageBoardItemDTO[];
|
||||
|
||||
@@ -18,8 +20,14 @@ export class ModalNotificationsReservationGroupComponent {
|
||||
constructor(private _router: Router) {}
|
||||
|
||||
itemSelected(item: MessageBoardItemDTO) {
|
||||
const defaultNav = this._pickupShelfInNavigationService.listRoute();
|
||||
const queryParams = UiFilter.getQueryParamsFromQueryTokenDTO(item.queryToken);
|
||||
this._router.navigate(['/filiale/goods/in/results'], { queryParams });
|
||||
this._router.navigate(defaultNav.path, {
|
||||
queryParams: {
|
||||
...defaultNav.queryParams,
|
||||
...queryParams,
|
||||
},
|
||||
});
|
||||
this.navigated.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, inject } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { PickupShelfInNavigationService } from '@shared/services';
|
||||
import { UiFilter } from '@ui/filter';
|
||||
import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
|
||||
|
||||
@@ -9,6 +10,8 @@ import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ModalNotificationsTaskCalendarGroupComponent {
|
||||
private _pickupShelfInNavigationService = inject(PickupShelfInNavigationService);
|
||||
|
||||
@Input()
|
||||
notifications: MessageBoardItemDTO[];
|
||||
|
||||
@@ -18,8 +21,14 @@ export class ModalNotificationsTaskCalendarGroupComponent {
|
||||
constructor(private _router: Router) {}
|
||||
|
||||
itemSelected(item: MessageBoardItemDTO) {
|
||||
const defaultNav = this._pickupShelfInNavigationService.listRoute();
|
||||
const queryParams = UiFilter.getQueryParamsFromQueryTokenDTO(item.queryToken);
|
||||
this._router.navigate(['/filiale/goods/in/results'], { queryParams });
|
||||
this._router.navigate(defaultNav.path, {
|
||||
queryParams: {
|
||||
...defaultNav.queryParams,
|
||||
...queryParams,
|
||||
},
|
||||
});
|
||||
this.navigated.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ export class ModalNotificationsComponent extends ComponentStore<ModalNotificatio
|
||||
|
||||
private _categorySelector = (state: ModalNotificationComponentState) => {
|
||||
const selectedArea = this._selectedAreaSelector(state);
|
||||
console.log('_categorySelector', state.notifications[selectedArea]?.[0]?.category);
|
||||
|
||||
return state.notifications[selectedArea]?.[0]?.category;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<shared-breadcrumb class="my-4" [key]="breadcrumbKey"></shared-breadcrumb>
|
||||
<shared-breadcrumb [key]="breadcrumbKey"></shared-breadcrumb>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="page-article-details__product-details mb-3">
|
||||
<div class="page-article-details__product-bookmark 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-px-5">
|
||||
<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" />
|
||||
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #archivTooltip [closeable]="true">
|
||||
<ng-container *ngIf="isAvailable$ | async; else notAvailable">
|
||||
@@ -17,7 +17,10 @@
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="showSubscriptionBadge$ | async">
|
||||
<button [uiOverlayTrigger]="subscribtionTooltip" class="p-0 m-0 outline-none border-none bg-transparent relative -top-px-5">
|
||||
<button
|
||||
[uiOverlayTrigger]="subscribtionTooltip"
|
||||
class="p-0 m-0 outline-none border-none bg-transparent relative -top-[0.3125rem]"
|
||||
>
|
||||
<img src="/assets/images/bookmark_subscription.svg" alt="Fortsetzungsartikel Badge" />
|
||||
</button>
|
||||
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #subscribtionTooltip [closeable]="true"
|
||||
@@ -27,7 +30,7 @@
|
||||
</ui-tooltip>
|
||||
</div>
|
||||
<div *ngIf="showPromotionBadge$ | async" class="promotion-badge">
|
||||
<button [uiOverlayTrigger]="promotionTooltip" class="p-0 m-0 outline-none border-none bg-transparent relative -top-px-5">
|
||||
<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>
|
||||
<ui-tooltip yPosition="above" xPosition="after" [yOffset]="-11" [xOffset]="-8" #promotionTooltip [closeable]="true">
|
||||
Dieser Artikel befindet sich im Prämienkatalog.
|
||||
@@ -46,7 +49,7 @@
|
||||
alt="product image"
|
||||
/>
|
||||
<ui-icon
|
||||
class="absolute text-[#A7B9CB] inline-block bottom-[14px] right-[18px]"
|
||||
class="absolute text-[#A7B9CB] inline-block bottom-[0.875rem] right-[1.125rem]"
|
||||
*ngIf="imageLoaded$ | async"
|
||||
icon="search_add"
|
||||
size="25px"
|
||||
@@ -196,7 +199,7 @@
|
||||
*ngIf="showDeliveryTruck$ | async"
|
||||
class="w-[2.25rem] h-[2.25rem] bg-[#D8DFE5] rounded-[5px_5px_0px_5px] flex items-center justify-center ml-3"
|
||||
>
|
||||
<ui-icon class="-mb-px-5 -mt-px-5 mx-1" icon="truck" size="30px"></ui-icon>
|
||||
<ui-icon class="-mb-[0.3125rem] -mt-[0.3125rem] mx-1" icon="truck" size="30px"></ui-icon>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
@@ -209,7 +212,7 @@
|
||||
*ngIf="showDeliveryB2BTruck$ | async"
|
||||
class="w-[2.25rem] h-[2.25rem] bg-[#D8DFE5] rounded-[5px_5px_0px_5px] flex items-center justify-center ml-3"
|
||||
>
|
||||
<ui-icon class="-mb-px-10 -mt-px-10 mx-1" icon="truck_b2b" size="30px"> </ui-icon>
|
||||
<ui-icon class="-mb-[0.625rem] -mt-[0.625rem] mx-1" icon="truck_b2b" size="30px"> </ui-icon>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
@@ -222,7 +225,7 @@
|
||||
|
||||
<div class="page-article-details__shelf-ssc">
|
||||
<div class="page-article-details__ssc flex justify-end my-2 font-bold text-lg">
|
||||
<div class="w-52 h-px-20 bg-[#e6eff9] animate-[load_0.75s_linear_infinite]" *ngIf="fetchingAvailabilities$ | async"></div>
|
||||
<div class="w-52 h-5 bg-[#e6eff9] animate-[load_0.75s_linear_infinite]" *ngIf="fetchingAvailabilities$ | async"></div>
|
||||
<ng-container *ngIf="!(fetchingAvailabilities$ | async)">
|
||||
<div class="text-right" *ngIf="store.sscText$ | async; let sscText">
|
||||
{{ sscText }}
|
||||
@@ -294,7 +297,7 @@
|
||||
class="mr-4 text-[#0556B4] font-bold no-underline px-2"
|
||||
*ngFor="let format of item.family"
|
||||
[routerLink]="getDetailsPath(format.product.ean)"
|
||||
[queryParamsHandling]="!(isTablet$ | async) ? 'preserve' : ''"
|
||||
queryParamsHandling="preserve"
|
||||
>
|
||||
<span class="flex items-center">
|
||||
<img
|
||||
@@ -350,7 +353,7 @@
|
||||
>
|
||||
<button
|
||||
*ngIf="!(store.isDownload$ | async)"
|
||||
class="text-brand border-2 border-brand bg-white font-bold text-lg px-[1.375rem] py-4 rounded-full mr-px-30"
|
||||
class="text-brand border-2 border-brand bg-white font-bold text-lg px-[1.375rem] py-4 rounded-full mr-[1.875rem]"
|
||||
(click)="showAvailabilities()"
|
||||
>
|
||||
Bestände in anderen Filialen
|
||||
|
||||
@@ -84,12 +84,10 @@
|
||||
}
|
||||
|
||||
.page-article-details__scroll-top-cta {
|
||||
@apply flex items-center justify-center self-end border-none outline-none bg-white relative rounded p-0 mt-8 mr-4;
|
||||
@apply w-[3.625rem] h-[3.625rem] flex items-center justify-center self-end border-none outline-none bg-white relative rounded p-0 mt-8 mr-4;
|
||||
box-shadow: 0px 0px 20px 0px rgba(89, 100, 112, 0.5);
|
||||
transform: rotate(-90deg);
|
||||
border-radius: 100%;
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
}
|
||||
|
||||
.page-article-details__actions {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, ElementRef, ViewChild } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, ElementRef, ViewChild, inject } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { DomainPrinterService } from '@domain/printer';
|
||||
@@ -20,7 +20,7 @@ import { DateAdapter } from '@ui/common';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { PurchaseOptionsModalService } from '@shared/modals/purchase-options-modal';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { CheckoutNavigationService, ProductCatalogNavigationService } from '@shared/services';
|
||||
import { CheckoutNavigationService, ProductCatalogNavigationService, CustomerSearchNavigation } from '@shared/services';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
@@ -33,6 +33,8 @@ import { Store } from '@ngrx/store';
|
||||
animations: [slideYAnimation],
|
||||
})
|
||||
export class ArticleDetailsComponent implements OnInit, OnDestroy {
|
||||
private _customerSearchNavigation = inject(CustomerSearchNavigation);
|
||||
|
||||
private readonly subscriptions = new Subscription();
|
||||
showRecommendations: boolean;
|
||||
|
||||
@@ -411,6 +413,7 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
async navigateToCustomerSearch() {
|
||||
const nav = this._customerSearchNavigation.defaultRoute({ processId: this.applicationService.activatedProcessId });
|
||||
try {
|
||||
const response = await this.customerFeatures$
|
||||
.pipe(
|
||||
@@ -420,11 +423,11 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
|
||||
})
|
||||
)
|
||||
.toPromise();
|
||||
this._router.navigate(['/kunde', this.applicationService.activatedProcessId, 'customer', 'search'], {
|
||||
this._router.navigate(nav.path, {
|
||||
queryParams: { filter_customertype: response.filter.customertype },
|
||||
});
|
||||
} catch (error) {
|
||||
this._router.navigate(['/kunde', this.applicationService.activatedProcessId, 'customer', 'search']);
|
||||
this._router.navigate(nav.path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import { ArticleSearchService } from './article-search.store';
|
||||
import { FocusSearchboxEvent } from './focus-searchbox.event';
|
||||
import { ArticleSearchMainAutocompleteProvider } from './providers';
|
||||
import { ProductCatalogNavigationService } from '@shared/services';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { FilterAutocompleteProvider } from '@shared/components/filter';
|
||||
|
||||
@Component({
|
||||
@@ -28,16 +27,11 @@ export class ArticleSearchComponent implements OnInit, OnDestroy {
|
||||
private _onDestroy$ = new Subject();
|
||||
private _processId$: Observable<number>;
|
||||
|
||||
get isTablet() {
|
||||
return this._environmentService.matchTablet();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _breadcrumb: BreadcrumbService,
|
||||
private _articleSearch: ArticleSearchService,
|
||||
private _activatedRoute: ActivatedRoute,
|
||||
private _navigationService: ProductCatalogNavigationService,
|
||||
private _environmentService: EnvironmentService
|
||||
private _navigationService: ProductCatalogNavigationService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -61,7 +55,7 @@ export class ArticleSearchComponent implements OnInit, OnDestroy {
|
||||
.getArticleDetailsPath({
|
||||
processId,
|
||||
itemId: item.id,
|
||||
extras: { queryParams: this.isTablet ? undefined : params },
|
||||
extras: { queryParams: params },
|
||||
})
|
||||
.navigate();
|
||||
} else {
|
||||
|
||||
@@ -73,6 +73,7 @@ export class ArticleSearchFilterComponent implements OnInit, OnDestroy {
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.showFilter = this.sideOutlet !== 'search';
|
||||
this._activatedRoute.queryParams
|
||||
.pipe(takeUntil(this._onDestroy$))
|
||||
.subscribe(async (queryParams) => await this.articleSearch.setDefaultFilter(queryParams));
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
[class.page-search-result-item__item-card-primary]="primaryOutletActive"
|
||||
[routerLink]="detailsPath"
|
||||
[routerLinkActive]="!isTablet && !primaryOutletActive ? 'active' : ''"
|
||||
[queryParamsHandling]="!isTablet ? 'preserve' : ''"
|
||||
(click)="isDesktop ? scrollIntoView() : ''"
|
||||
queryParamsHandling="preserve"
|
||||
(click)="isDesktopLarge ? scrollIntoView() : ''"
|
||||
>
|
||||
<div class="page-search-result-item__item-thumbnail text-center mr-4 w-[50px] h-[79px]">
|
||||
<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-[50px] h-[79px]"
|
||||
class="page-search-result-item__item-image w-[3.125rem] h-[4.9375rem]"
|
||||
loading="lazy"
|
||||
*ngIf="item?.imageId | thumbnailUrl; let thumbnailUrl"
|
||||
[src]="thumbnailUrl"
|
||||
|
||||
@@ -78,8 +78,8 @@ export class SearchResultItemComponent extends ComponentStore<SearchResultItemCo
|
||||
return this._environment.matchTablet();
|
||||
}
|
||||
|
||||
get isDesktop() {
|
||||
return this._environment.matchDesktop();
|
||||
get isDesktopLarge() {
|
||||
return this._environment.matchDesktopLarge();
|
||||
}
|
||||
|
||||
get detailsPath() {
|
||||
@@ -157,11 +157,6 @@ export class SearchResultItemComponent extends ComponentStore<SearchResultItemCo
|
||||
setSelected() {
|
||||
const isSelected = this._articleSearchService.selectedItemIds.includes(this.item?.id);
|
||||
this._articleSearchService.setSelected({ selected: !isSelected, itemId: this.item?.id });
|
||||
|
||||
// #4135 Code auskommentiert bis zur Klärung
|
||||
// if (!this.isTablet) {
|
||||
// this.selectedChange.emit(this.item);
|
||||
// }
|
||||
}
|
||||
|
||||
async showTooltip() {
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
[class.pb-4]="!(primaryOutletActive$ | async)"
|
||||
[class.flex-col]="!(primaryOutletActive$ | async)"
|
||||
>
|
||||
<div class="flex flex-row w-full desktop-small:w-min" [class.desktop-large:w-full]="!(primaryOutletActive$ | async)">
|
||||
<div class="flex flex-row w-full desktop:w-min" [class.desktop-large:w-full]="!(primaryOutletActive$ | async)">
|
||||
<shared-filter-input-group-main
|
||||
*ngIf="filter$ | async; let filter"
|
||||
class="block mr-3 w-full desktop-small:w-[23.5rem]"
|
||||
class="block mr-3 w-full desktop:w-[23.5rem]"
|
||||
[class.desktop-large:w-full]="!(primaryOutletActive$ | async)"
|
||||
[hint]="searchboxHint$ | async"
|
||||
[loading]="fetching$ | async"
|
||||
@@ -38,7 +38,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-search-results__order-by" [class.page-search-results__order-by-primary]="primaryOutletActive$ | async">
|
||||
<div class="page-search-results__order-by mb-[0.125rem]" [class.page-search-results__order-by-primary]="primaryOutletActive$ | async">
|
||||
<shared-order-by-filter
|
||||
[orderBy]="(filter$ | async)?.orderBy"
|
||||
(selectedOrderByChange)="search({ clear: true, orderBy: true }); updateBreadcrumbs()"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
}
|
||||
|
||||
.product-list {
|
||||
@apply m-0 p-0 mt-px-2;
|
||||
@apply m-0 p-0;
|
||||
}
|
||||
|
||||
.page-search-results__result-item {
|
||||
@@ -12,7 +12,7 @@
|
||||
}
|
||||
|
||||
.page-search-results__result-item-primary {
|
||||
@apply mb-[5px];
|
||||
@apply mb-[0.3125rem];
|
||||
}
|
||||
|
||||
.page-search-results__order-by {
|
||||
|
||||
@@ -69,8 +69,8 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
|
||||
return this._environment.matchTablet();
|
||||
}
|
||||
|
||||
get isDesktop() {
|
||||
return this._environment.matchDesktop();
|
||||
get isDesktopLarge() {
|
||||
return this._environment.matchDesktopLarge();
|
||||
}
|
||||
|
||||
hasFilter$ = combineLatest([this.searchService.filter$, this.searchService.defaultSettings$]).pipe(
|
||||
@@ -89,7 +89,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
|
||||
}
|
||||
|
||||
get primaryOutletActive$() {
|
||||
return this._environment.matchTablet$.pipe(map((matches) => !matches && this.route.outlet === 'primary'));
|
||||
return this._environment.matchDesktop$.pipe(map((matches) => matches && this.route.outlet === 'primary'));
|
||||
}
|
||||
|
||||
// Ticket #4169 Splitscreen
|
||||
@@ -174,7 +174,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
|
||||
) {
|
||||
this.search({ clear: true });
|
||||
} else {
|
||||
if (!this.isDesktop || this.route.outlet === 'primary') {
|
||||
if (!this.isDesktopLarge || this.route.outlet === 'primary') {
|
||||
this.scrollTop(Number(queryParams.scroll_position ?? 0));
|
||||
} else {
|
||||
this.scrollItemIntoView();
|
||||
@@ -194,7 +194,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
|
||||
await this.createBreadcrumb(processId, queryParams);
|
||||
}
|
||||
|
||||
if (!this.isDesktop || this.route?.outlet === 'primary') {
|
||||
if (this.route?.outlet === 'primary') {
|
||||
await this.removeDetailsBreadcrumb(processId);
|
||||
}
|
||||
})
|
||||
@@ -224,7 +224,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
|
||||
.getArticleDetailsPathByEan({
|
||||
processId,
|
||||
ean,
|
||||
extras: { queryParams: this.isTablet ? undefined : params },
|
||||
extras: { queryParams: params },
|
||||
})
|
||||
.navigate();
|
||||
} else {
|
||||
@@ -232,11 +232,11 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
|
||||
.getArticleDetailsPath({
|
||||
processId,
|
||||
itemId,
|
||||
extras: { queryParams: this.isTablet ? undefined : params },
|
||||
extras: { queryParams: params },
|
||||
})
|
||||
.navigate();
|
||||
}
|
||||
} else if ((searchCompleted?.clear || this.route.outlet === 'primary') && !this.isTablet) {
|
||||
} else if ((searchCompleted?.clear || this.route.outlet === 'primary') && this.isDesktopLarge) {
|
||||
await this._navigationService.getArticleSearchResultsPath(processId, { queryParams: params }).navigate();
|
||||
}
|
||||
}
|
||||
@@ -312,7 +312,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy, AfterVi
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.isDesktop || this.route.outlet === 'primary') {
|
||||
if (this.route.outlet === 'primary') {
|
||||
this.searchService.setScrollPosition(this.scrollContainer.measureScrollOffset('top'));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<shared-breadcrumb class="mb-5 desktop-small:mb-9" [key]="activatedProcessId$ | async" [tags]="['catalog']">
|
||||
<shared-breadcrumb [key]="activatedProcessId$ | async" [tags]="['catalog']">
|
||||
<shared-branch-selector
|
||||
[uiOverlayTrigger]="tooltip"
|
||||
[overlayTriggerDisabled]="stockTooltipDisabled"
|
||||
|
||||
@@ -31,7 +31,7 @@ shared-branch-selector.shared-branch-selector-opend {
|
||||
shared-branch-selector.shared-branch-selector-opend
|
||||
.shared-branch-selector-input-container
|
||||
.shared-branch-selector-input-icon {
|
||||
@apply pl-0 border-l-0;
|
||||
@apply border-l-0;
|
||||
}
|
||||
|
||||
::ng-deep .tablet page-catalog shared-breadcrumb:focus-within .shared-breadcrumb__suffix {
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<page-checkout-review-details></page-checkout-review-details>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngFor="let group of groupedItems$ | async; let lastGroup = last">
|
||||
<ng-container *ngFor="let group of groupedItems$ | async; let lastGroup = last; trackBy: trackByGroupedItems">
|
||||
<ng-container *ngIf="group?.orderType !== undefined">
|
||||
<hr />
|
||||
<div class="row item-group-header bg-[#F5F7FA]">
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
QueryList,
|
||||
AfterViewInit,
|
||||
TrackByFunction,
|
||||
inject,
|
||||
} from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
@@ -16,7 +17,7 @@ import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { AvailabilityDTO, DestinationDTO, ShoppingCartItemDTO } from '@swagger/checkout';
|
||||
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
|
||||
import { PrintModalData, PrintModalComponent } from '@modal/printer';
|
||||
import { delay, first, map, switchMap, takeUntil } from 'rxjs/operators';
|
||||
import { delay, first, map, switchMap, takeUntil, tap } from 'rxjs/operators';
|
||||
import { Subject, NEVER, combineLatest, BehaviorSubject, Subscription } from 'rxjs';
|
||||
import { DomainCatalogService } from '@domain/catalog';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
@@ -29,6 +30,7 @@ import { EnvironmentService } from '@core/environment';
|
||||
import { CheckoutReviewStore } from './checkout-review.store';
|
||||
import { ToasterService } from '@shared/shell';
|
||||
import { ShoppingCartItemComponent } from './shopping-cart-item/shopping-cart-item.component';
|
||||
import { CustomerSearchNavigation } from '@shared/services';
|
||||
|
||||
@Component({
|
||||
selector: 'page-checkout-review',
|
||||
@@ -37,6 +39,9 @@ import { ShoppingCartItemComponent } from './shopping-cart-item/shopping-cart-it
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class CheckoutReviewComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
private _onDestroy$ = new Subject<void>();
|
||||
|
||||
private _customerSearchNavigation = inject(CustomerSearchNavigation);
|
||||
checkingOla$ = new BehaviorSubject<boolean>(false);
|
||||
|
||||
payer$ = this._store.payer$;
|
||||
@@ -54,6 +59,9 @@ export class CheckoutReviewComponent implements OnInit, OnDestroy, AfterViewInit
|
||||
map((items) => items?.filter((item) => item?.features?.orderType === undefined))
|
||||
);
|
||||
|
||||
trackByGroupedItems: TrackByFunction<{ orderType: string; destination: DestinationDTO; items: ShoppingCartItemDTO[] }> = (_, item) =>
|
||||
item?.orderType + item?.destination?.id;
|
||||
|
||||
groupedItems$ = this._store.shoppingCartItems$.pipe(
|
||||
takeUntil(this._store.orderCompleted),
|
||||
map((items) =>
|
||||
@@ -164,6 +172,7 @@ export class CheckoutReviewComponent implements OnInit, OnDestroy, AfterViewInit
|
||||
showOrderButtonSpinner: boolean;
|
||||
|
||||
checkoutIsInValid$ = this.applicationService.activatedProcessId$.pipe(
|
||||
takeUntil(this._onDestroy$),
|
||||
switchMap((processId) => this.domainCheckoutService.checkoutIsValid({ processId })),
|
||||
map((valid) => !valid)
|
||||
);
|
||||
@@ -176,8 +185,6 @@ export class CheckoutReviewComponent implements OnInit, OnDestroy, AfterViewInit
|
||||
return this._environmentService.matchDesktopLarge$;
|
||||
}
|
||||
|
||||
private _onDestroy$ = new Subject<void>();
|
||||
|
||||
@ViewChildren(ShoppingCartItemComponent)
|
||||
private _shoppingCartItems: QueryList<ShoppingCartItemComponent>;
|
||||
|
||||
@@ -224,13 +231,15 @@ export class CheckoutReviewComponent implements OnInit, OnDestroy, AfterViewInit
|
||||
this.resetControl();
|
||||
this._onDestroy$.next();
|
||||
this._onDestroy$.complete();
|
||||
this.checkingOla$.complete();
|
||||
this.quantityError$.complete();
|
||||
this.olaCheckSubscription?.unsubscribe();
|
||||
}
|
||||
|
||||
registerOlaCechk() {
|
||||
this.olaCheckSubscription?.unsubscribe();
|
||||
this.olaCheckSubscription = this.applicationService.activatedProcessId$
|
||||
.pipe(
|
||||
takeUntil(this._onDestroy$),
|
||||
delay(250),
|
||||
switchMap((processId) =>
|
||||
this.domainCheckoutService.validateOlaStatus({
|
||||
@@ -250,7 +259,7 @@ export class CheckoutReviewComponent implements OnInit, OnDestroy, AfterViewInit
|
||||
|
||||
for (let itemComp of this._shoppingCartItems.toArray()) {
|
||||
await itemComp.refreshAvailability();
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
}
|
||||
this.checkingOla$.next(false);
|
||||
}
|
||||
@@ -467,6 +476,8 @@ export class CheckoutReviewComponent implements OnInit, OnDestroy, AfterViewInit
|
||||
}
|
||||
|
||||
async navigateToCustomerSearch(processId: number) {
|
||||
const nav = this._customerSearchNavigation.defaultRoute({ processId });
|
||||
|
||||
try {
|
||||
const response = await this.customerFeatures$
|
||||
.pipe(
|
||||
@@ -477,11 +488,11 @@ export class CheckoutReviewComponent implements OnInit, OnDestroy, AfterViewInit
|
||||
)
|
||||
.toPromise();
|
||||
|
||||
this.router.navigate(['/kunde', this.applicationService.activatedProcessId, 'customer', 'search'], {
|
||||
this.router.navigate(nav.path, {
|
||||
queryParams: { filter_customertype: response.filter.customertype },
|
||||
});
|
||||
} catch (error) {
|
||||
this.router.navigate(['/kunde', this.applicationService.activatedProcessId, 'customer', 'search']);
|
||||
this.router.navigate(nav.path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,7 +512,8 @@ export class CheckoutReviewComponent implements OnInit, OnDestroy, AfterViewInit
|
||||
return;
|
||||
}
|
||||
const customerId = customer.source;
|
||||
this.router.navigate(['/kunde', this.applicationService.activatedProcessId, 'customer', `${customerId}`]);
|
||||
const nav = this._customerSearchNavigation.detailsRoute({ processId, customerId });
|
||||
this.router.navigate(nav.path);
|
||||
}
|
||||
|
||||
async order() {
|
||||
|
||||
@@ -20,7 +20,7 @@ import { CheckoutReviewDetailsComponent } from './details/checkout-review-detail
|
||||
import { CheckoutReviewStore } from './checkout-review.store';
|
||||
import { IconModule } from '@shared/components/icon';
|
||||
import { TextFieldModule } from '@angular/cdk/text-field';
|
||||
import { LoaderComponent } from '@shared/components/loader';
|
||||
import { LoaderComponent, SkeletonLoaderComponent } from '@shared/components/loader';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -41,6 +41,7 @@ import { LoaderComponent } from '@shared/components/loader';
|
||||
SharedNotificationChannelControlModule,
|
||||
TextFieldModule,
|
||||
LoaderComponent,
|
||||
SkeletonLoaderComponent,
|
||||
],
|
||||
exports: [CheckoutReviewComponent, CheckoutReviewDetailsComponent],
|
||||
declarations: [CheckoutReviewComponent, SpecialCommentComponent, ShoppingCartItemComponent, CheckoutReviewDetailsComponent],
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
<ng-container *ngIf="payer$ | async; let payer">
|
||||
<div *ngIf="showAddresses$ | async" class="flex flex-row items-start justify-between p-5 pt-0">
|
||||
<div class="flex flex-row flex-wrap pr-4">
|
||||
<div class="flex flex-row flex-wrap pr-4" data-address-type="Rechnungsadresse">
|
||||
<div class="mr-3">Rechnungsadresse</div>
|
||||
<div class="font-bold">
|
||||
{{ payer | payerAddress }}
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
<ng-container *ngIf="payer$ | async; let payer">
|
||||
<div *ngIf="showAddresses$ | async" class="flex flex-row items-start justify-between px-5">
|
||||
<div class="flex flex-row flex-wrap pr-4">
|
||||
<div class="flex flex-row flex-wrap pr-4" data-address-type="Lieferadresse">
|
||||
<div class="mr-3">Lieferadresse</div>
|
||||
<div class="font-bold">
|
||||
{{ shippingAddress$ | async | shippingAddress }}
|
||||
|
||||
@@ -43,13 +43,16 @@
|
||||
<div *ngIf="notAvailable$ | async">
|
||||
<span class="text-brand item-date">Nicht verfügbar</span>
|
||||
</div>
|
||||
<ui-spinner class="ava-loader" [show]="refreshingAvailabilit$ | async">
|
||||
<div class="item-date" [class.ssc-changed]="sscChanged$ | async" *ngIf="orderType === 'Abholung'">
|
||||
|
||||
<shared-skeleton-loader class="w-40" *ngIf="refreshingAvailabilit$ | async; else avaTmplt"> </shared-skeleton-loader>
|
||||
|
||||
<ng-template #avaTmplt>
|
||||
<div class="item-date" [class.availability-changed]="estimatedShippingDateChanged$ | async" *ngIf="orderType === 'Abholung'">
|
||||
Abholung ab {{ item?.availability?.estimatedShippingDate | date }}
|
||||
</div>
|
||||
<div
|
||||
class="item-date"
|
||||
[class.ssc-changed]="sscChanged$ | async"
|
||||
[class.availability-changed]="estimatedShippingDateChanged$ | async"
|
||||
*ngIf="orderType === 'Versand' || orderType === 'B2B-Versand' || orderType === 'DIG-Versand'"
|
||||
>
|
||||
<ng-container *ngIf="item?.availability?.estimatedDelivery; else estimatedShippingDate">
|
||||
@@ -59,7 +62,7 @@
|
||||
</ng-container>
|
||||
<ng-template #estimatedShippingDate> Versand {{ item?.availability?.estimatedShippingDate | date }} </ng-template>
|
||||
</div>
|
||||
</ui-spinner>
|
||||
</ng-template>
|
||||
|
||||
<div class="item-availability-message" *ngIf="olaError$ | async">
|
||||
Artikel nicht verfügbar
|
||||
|
||||
@@ -101,7 +101,7 @@ button {
|
||||
}
|
||||
}
|
||||
|
||||
.ssc-changed {
|
||||
.availability-changed {
|
||||
@apply text-dark-goldenrod;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import { ComponentStore } from '@ngrx/component-store';
|
||||
import { ProductCatalogNavigationService } from '@shared/services';
|
||||
import { ItemType, ShoppingCartItemDTO } from '@swagger/checkout';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { filter, first, map, shareReplay, switchMap } from 'rxjs/operators';
|
||||
|
||||
@@ -18,6 +19,7 @@ export interface ShoppingCartItemComponentState {
|
||||
refreshingAvailability: boolean;
|
||||
sscChanged: boolean;
|
||||
sscTextChanged: boolean;
|
||||
estimatedShippingDateChanged: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
@@ -137,6 +139,8 @@ export class ShoppingCartItemComponent extends ComponentStore<ShoppingCartItemCo
|
||||
|
||||
sscChanged$ = this.select((s) => s.sscChanged || s.sscTextChanged);
|
||||
|
||||
estimatedShippingDateChanged$ = this.select((s) => s.estimatedShippingDateChanged);
|
||||
|
||||
notAvailable$ = this.item$.pipe(
|
||||
map((item) => {
|
||||
const availability = item?.availability;
|
||||
@@ -161,7 +165,14 @@ export class ShoppingCartItemComponent extends ComponentStore<ShoppingCartItemCo
|
||||
private _environment: EnvironmentService,
|
||||
private _cdr: ChangeDetectorRef
|
||||
) {
|
||||
super({ item: undefined, orderType: '', refreshingAvailability: false, sscChanged: false, sscTextChanged: false });
|
||||
super({
|
||||
item: undefined,
|
||||
orderType: '',
|
||||
refreshingAvailability: false,
|
||||
sscChanged: false,
|
||||
sscTextChanged: false,
|
||||
estimatedShippingDateChanged: false,
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {}
|
||||
@@ -192,6 +203,11 @@ export class ShoppingCartItemComponent extends ComponentStore<ShoppingCartItemCo
|
||||
if (currentAvailability.sscText !== availability.sscText) {
|
||||
this.ssctextChanged();
|
||||
}
|
||||
if (
|
||||
moment(currentAvailability.estimatedShippingDate).startOf('day').diff(moment(availability.estimatedShippingDate).startOf('day'))
|
||||
) {
|
||||
this.estimatedShippingDateChanged();
|
||||
}
|
||||
} catch (error) {}
|
||||
|
||||
this.patchRefreshingAvailability(false);
|
||||
@@ -206,16 +222,17 @@ export class ShoppingCartItemComponent extends ComponentStore<ShoppingCartItemCo
|
||||
}
|
||||
|
||||
ssctextChanged() {
|
||||
this._zone.run(() => {
|
||||
this.patchState({ sscTextChanged: true });
|
||||
this._cdr.markForCheck();
|
||||
});
|
||||
this.patchState({ sscTextChanged: true });
|
||||
this._cdr.markForCheck();
|
||||
}
|
||||
|
||||
sscChanged() {
|
||||
this._zone.run(() => {
|
||||
this.patchState({ sscChanged: true });
|
||||
this._cdr.markForCheck();
|
||||
});
|
||||
this.patchState({ sscChanged: true });
|
||||
this._cdr.markForCheck();
|
||||
}
|
||||
|
||||
estimatedShippingDateChanged() {
|
||||
this.patchState({ estimatedShippingDateChanged: true });
|
||||
this._cdr.markForCheck();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,202 +1,201 @@
|
||||
<div class="flex flex-col bg-white rounded pt-10">
|
||||
<div class="rounded-[50%] bg-[#26830C] w-8 h-8 flex items-center justify-center self-center">
|
||||
<shared-icon class="text-white" icon="done" [size]="24"></shared-icon>
|
||||
</div>
|
||||
<div class="summary-wrapper">
|
||||
<div class="flex flex-col bg-white rounded pt-10 mb-24">
|
||||
<div class="rounded-[50%] bg-[#26830C] w-8 h-8 flex items-center justify-center self-center">
|
||||
<shared-icon class="text-white" icon="done" [size]="24"></shared-icon>
|
||||
</div>
|
||||
|
||||
<h1 class="text-center text-h2 my-1 font-bold">Bestellbestätigung</h1>
|
||||
<p class="text-center text-p1 mb-10">
|
||||
Nachfolgend erhalten Sie die Übersicht Ihrer Bestellung.
|
||||
</p>
|
||||
<h1 class="text-center text-h2 my-1 font-bold">Bestellbestätigung</h1>
|
||||
<p class="text-center text-p1 mb-10">
|
||||
Nachfolgend erhalten Sie die Übersicht Ihrer Bestellung.
|
||||
</p>
|
||||
|
||||
<ng-container *ngFor="let displayOrder of displayOrders$ | async; let i = index; let orderLast = last">
|
||||
<ng-container *ngIf="i === 0">
|
||||
<div class="flex flex-row items-center bg-white shadow-card min-h-[3.3125rem]">
|
||||
<div class="text-h3 font-bold px-5 py-[0.875rem]">
|
||||
{{ displayOrder?.buyer | buyerName }}
|
||||
<ng-container *ngFor="let displayOrder of displayOrders$ | async; let i = index; let orderLast = last">
|
||||
<ng-container *ngIf="i === 0">
|
||||
<div class="flex flex-row items-center bg-white shadow-card min-h-[3.3125rem]">
|
||||
<div class="text-h3 font-bold px-5 py-[0.875rem]">
|
||||
{{ displayOrder?.buyer | buyerName }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
</ng-container>
|
||||
|
||||
<div class="flex flex-row items-center bg-[#F5F7FA] min-h-[3.3125rem]">
|
||||
<div class="flex flex-row items-center justify-center px-5 py-[0.875rem]">
|
||||
<shared-icon
|
||||
*ngIf="(displayOrder?.items)[0]?.features?.orderType !== 'Dummy'"
|
||||
class="mr-2"
|
||||
[size]="(displayOrder?.items)[0]?.features?.orderType === 'B2B-Versand' ? 36 : 24"
|
||||
[icon]="(displayOrder?.items)[0]?.features?.orderType"
|
||||
></shared-icon>
|
||||
<p class="text-p1 font-bold mr-3">{{ (displayOrder?.items)[0]?.features?.orderType }}</p>
|
||||
<div
|
||||
*ngIf="
|
||||
(displayOrder?.items)[0]?.features?.orderType === 'Abholung' || (displayOrder?.items)[0]?.features?.orderType === 'Rücklage';
|
||||
else shippingAddress
|
||||
"
|
||||
>
|
||||
{{ displayOrder.targetBranch?.name }}, {{ displayOrder.targetBranch | branchAddress }}
|
||||
</div>
|
||||
<ng-template #shippingAddress>
|
||||
{{ displayOrder.shippingAddress | branchAddress }}
|
||||
</ng-template>
|
||||
<div *ngIf="(displayOrder?.items)[0]?.features?.orderType === 'Download'">
|
||||
| {{ displayOrder.buyer?.communicationDetails?.email }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
</ng-container>
|
||||
|
||||
<div class="flex flex-row items-center bg-[#F5F7FA] min-h-[3.3125rem]">
|
||||
<div class="flex flex-row items-center justify-center px-5 py-[0.875rem]">
|
||||
<shared-icon
|
||||
*ngIf="(displayOrder?.items)[0]?.features?.orderType !== 'Dummy'"
|
||||
class="mr-2"
|
||||
[size]="(displayOrder?.items)[0]?.features?.orderType === 'B2B-Versand' ? 36 : 24"
|
||||
[icon]="(displayOrder?.items)[0]?.features?.orderType"
|
||||
></shared-icon>
|
||||
<p class="text-p1 font-bold mr-3">{{ (displayOrder?.items)[0]?.features?.orderType }}</p>
|
||||
<div
|
||||
*ngIf="
|
||||
(displayOrder?.items)[0]?.features?.orderType === 'Abholung' || (displayOrder?.items)[0]?.features?.orderType === 'Rücklage';
|
||||
else shippingAddress
|
||||
"
|
||||
>
|
||||
{{ displayOrder.targetBranch?.name }}, {{ displayOrder.targetBranch | branchAddress }}
|
||||
</div>
|
||||
<ng-template #shippingAddress>
|
||||
{{ displayOrder.shippingAddress | branchAddress }}
|
||||
</ng-template>
|
||||
<div *ngIf="(displayOrder?.items)[0]?.features?.orderType === 'Download'">
|
||||
| {{ displayOrder.buyer?.communicationDetails?.email }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="flex flex-col px-5 pt-7 pb-[1.875rem] bg-white">
|
||||
<div class="flex flex-row justify-between items-center mb-[0.375rem]">
|
||||
<div class="flex flex-row">
|
||||
<span class="w-32">Vorgangs-ID</span>
|
||||
<ng-container *ngIf="customer$ | async; let customer">
|
||||
<a
|
||||
*ngIf="customer$ | async; let customer"
|
||||
class="font-bold text-[#0556B4] no-underline"
|
||||
[routerLink]="['/kunde', processId, 'customer', 'search', customer?.id, 'orders', displayOrder.id]"
|
||||
[queryParams]="{ main_qs: customer?.customerNumber, filter_customertype: '' }"
|
||||
>{{ displayOrder.orderNumber }}</a
|
||||
>
|
||||
</ng-container>
|
||||
<ui-spinner class="text-[#0556B4] h-4 w-4" [show]="!(customer$ | async)"> </ui-spinner>
|
||||
</div>
|
||||
<button
|
||||
*ifRole="'Store'"
|
||||
type="button"
|
||||
class="cta-print bg-transparent text-brand font-bold text-p1 outline-none border-none pr-0"
|
||||
(click)="openPrintModal(displayOrder.id)"
|
||||
>
|
||||
Drucken
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row justify-between items-center">
|
||||
<div class="flex flex-row">
|
||||
<span class="w-32">Bestelldatum</span>
|
||||
<strong>{{ displayOrder.orderDate | date }}</strong>
|
||||
<div class="flex flex-col px-5 py-4 bg-white" [attr.data-order-type]="(displayOrder?.items)[0]?.features?.orderType">
|
||||
<div class="flex flex-row justify-between items-center mb-[0.375rem]">
|
||||
<div class="flex flex-row">
|
||||
<span class="w-32">Vorgangs-ID</span>
|
||||
<ng-container *ngIf="customer$ | async; let customer">
|
||||
<a
|
||||
*ngIf="customer$ | async; let customer"
|
||||
class="font-bold text-[#0556B4] no-underline"
|
||||
[routerLink]="['/kunde', processId, 'customer', 'search', customer?.id, 'orders', displayOrder.id]"
|
||||
[queryParams]="{ main_qs: customer?.customerNumber, filter_customertype: '' }"
|
||||
>{{ displayOrder.orderNumber }}</a
|
||||
>
|
||||
</ng-container>
|
||||
<ui-spinner class="text-[#0556B4] h-4 w-4" [show]="!(customer$ | async)"> </ui-spinner>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row justify-between items-center">
|
||||
<div class="flex flex-row">
|
||||
<span class="w-32">Bestelldatum</span>
|
||||
<strong>{{ displayOrder.orderDate | date }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mr-4">
|
||||
<button
|
||||
(click)="expanded[i] = !expanded[i]"
|
||||
type="button"
|
||||
class="text-[#0556B4] font-bold flex flex-row items-center justify-center"
|
||||
[class.flex-row-reverse]="!expanded[i]"
|
||||
>
|
||||
<shared-icon
|
||||
class="mr-1"
|
||||
icon="arrow-back"
|
||||
[size]="20"
|
||||
[class.ml-1]="!expanded[i]"
|
||||
[class.rotate-180]="!expanded[i]"
|
||||
></shared-icon>
|
||||
{{ expanded[i] ? 'Weniger' : 'Mehr' }}
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
(click)="expanded[i] = !expanded[i]"
|
||||
type="button"
|
||||
class="text-[#0556B4] font-bold flex flex-row items-center justify-center"
|
||||
[class.flex-row-reverse]="!expanded[i]"
|
||||
>
|
||||
<shared-icon
|
||||
class="mr-1"
|
||||
icon="arrow-back"
|
||||
[size]="20"
|
||||
[class.ml-1]="!expanded[i]"
|
||||
[class.rotate-180]="!expanded[i]"
|
||||
></shared-icon>
|
||||
{{ expanded[i] ? 'Weniger' : 'Mehr' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-container *ngFor="let order of displayOrder.items; let last = last">
|
||||
<ng-container *ngIf="expanded[i]">
|
||||
<div
|
||||
class="page-checkout-summary__items-tablet px-5 pb-[1.875rem] bg-white"
|
||||
[class.page-checkout-summary__items]="isDesktop$ | async"
|
||||
[class.last]="last"
|
||||
>
|
||||
<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" />
|
||||
</a>
|
||||
</div>
|
||||
<ng-container *ngFor="let order of displayOrder.items; let last = last">
|
||||
<ng-container *ngIf="expanded[i]">
|
||||
<div
|
||||
class="page-checkout-summary__items-tablet px-5 pb-[1.875rem] bg-white"
|
||||
[class.page-checkout-summary__items]="isDesktop$ | async"
|
||||
[class.last]="last"
|
||||
>
|
||||
<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" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="page-checkout-summary__items-title whitespace-nowrap overflow-ellipsis overflow-hidden">
|
||||
<a
|
||||
class="font-bold no-underline text-[#0556B4]"
|
||||
[routerLink]="getProductSearchDetailsPath(order?.product?.ean)"
|
||||
[queryParams]="getProductSearchDetailsQueryParams(order)"
|
||||
>{{ order?.product?.name }}</a
|
||||
>
|
||||
</div>
|
||||
<div class="page-checkout-summary__items-title whitespace-nowrap overflow-ellipsis overflow-hidden">
|
||||
<a
|
||||
class="font-bold no-underline text-[#0556B4]"
|
||||
[routerLink]="getProductSearchDetailsPath(order?.product?.ean)"
|
||||
[queryParams]="getProductSearchDetailsQueryParams(order)"
|
||||
>{{ order?.product?.name }}</a
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="page-checkout-summary__items-ssc" *ngIf="(order?.subsetItems)[0]; let subsetItem">
|
||||
<span class="mr-2">{{ subsetItem.supplierName }}</span>
|
||||
<span *ngIf="subsetItem?.ssc && subsetItem?.sscText" class="font-bold border-l border-black pl-2"
|
||||
>{{ subsetItem.ssc }} - {{ subsetItem.sscText }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="page-checkout-summary__items-ssc" *ngIf="(order?.subsetItems)[0]; let subsetItem">
|
||||
<span class="mr-2">{{ subsetItem.supplierName }}</span>
|
||||
<span *ngIf="subsetItem?.ssc && subsetItem?.sscText" class="font-bold border-l border-black pl-2"
|
||||
>{{ subsetItem.ssc }} - {{ subsetItem.sscText }}</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="page-checkout-summary__items-quantity font-bold justify-self-end">
|
||||
<span> {{ order.quantity }}x </span>
|
||||
</div>
|
||||
<div class="page-checkout-summary__items-quantity font-bold justify-self-end">
|
||||
<span> {{ order.quantity }}x </span>
|
||||
</div>
|
||||
|
||||
<div class="page-checkout-summary__items-price font-bold justify-self-end">
|
||||
<span> {{ order.price?.value?.value | currency: ' ' }} {{ order.price?.value?.currency }} </span>
|
||||
</div>
|
||||
<div class="page-checkout-summary__items-price font-bold justify-self-end">
|
||||
<span> {{ order.price?.value?.value | currency: ' ' }} {{ order.price?.value?.currency }} </span>
|
||||
</div>
|
||||
|
||||
<div class="page-checkout-summary__items-delivery product-details">
|
||||
<div class="delivery-row" [ngSwitch]="order?.features?.orderType">
|
||||
<ng-container *ngSwitchCase="'Abholung'">
|
||||
<span class="order-type"
|
||||
>Abholung ab {{ (order?.subsetItems)[0]?.estimatedShippingDate | date }}
|
||||
<ng-container [ngTemplateOutlet]="abholfrist" [ngTemplateOutletContext]="{ order: order }"> </ng-container>
|
||||
</span>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="'Rücklage'">
|
||||
<span class="order-type"
|
||||
>{{ order?.features?.orderType }}
|
||||
<ng-container [ngTemplateOutlet]="abholfrist" [ngTemplateOutletContext]="{ order: order }"> </ng-container>
|
||||
</span>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="['Versand', 'B2B-Versand', 'DIG-Versand'].indexOf(order?.features?.orderType) > -1">
|
||||
<ng-container *ngIf="(order?.subsetItems)[0]?.estimatedDelivery; else estimatedShippingDate">
|
||||
<div class="page-checkout-summary__items-delivery product-details">
|
||||
<div class="delivery-row" [ngSwitch]="order?.features?.orderType">
|
||||
<ng-container *ngSwitchCase="'Abholung'">
|
||||
<span class="order-type"
|
||||
>Zustellung zwischen
|
||||
{{ ((order?.subsetItems)[0]?.estimatedDelivery?.start | date: 'EEE, dd.MM.')?.replace('.', '') }} und
|
||||
{{ ((order?.subsetItems)[0]?.estimatedDelivery?.stop | date: 'EEE, dd.MM.')?.replace('.', '') }}</span
|
||||
>
|
||||
>Abholung ab {{ (order?.subsetItems)[0]?.estimatedShippingDate | date }}
|
||||
<ng-container [ngTemplateOutlet]="abholfrist" [ngTemplateOutletContext]="{ order: order }"> </ng-container>
|
||||
</span>
|
||||
</ng-container>
|
||||
<ng-template #estimatedShippingDate>
|
||||
<span class="order-type">Versanddatum {{ (order?.subsetItems)[0]?.estimatedShippingDate | date }}</span>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchDefault>
|
||||
<span class="order-type">{{ order?.features?.orderType }}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="'Rücklage'">
|
||||
<span class="order-type"
|
||||
>{{ order?.features?.orderType }}
|
||||
<ng-container [ngTemplateOutlet]="abholfrist" [ngTemplateOutletContext]="{ order: order }"> </ng-container>
|
||||
</span>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="['Versand', 'B2B-Versand', 'DIG-Versand'].indexOf(order?.features?.orderType) > -1">
|
||||
<ng-container *ngIf="(order?.subsetItems)[0]?.estimatedDelivery; else estimatedShippingDate">
|
||||
<span class="order-type"
|
||||
>Zustellung zwischen
|
||||
{{ ((order?.subsetItems)[0]?.estimatedDelivery?.start | date: 'EEE, dd.MM.')?.replace('.', '') }} und
|
||||
{{ ((order?.subsetItems)[0]?.estimatedDelivery?.stop | date: 'EEE, dd.MM.')?.replace('.', '') }}</span
|
||||
>
|
||||
</ng-container>
|
||||
<ng-template #estimatedShippingDate>
|
||||
<span class="order-type">Versanddatum {{ (order?.subsetItems)[0]?.estimatedShippingDate | date }}</span>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchDefault>
|
||||
<span class="order-type">{{ order?.features?.orderType }}</span>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<hr *ngIf="last" />
|
||||
</ng-container>
|
||||
<ng-container *ngIf="orderLast">
|
||||
<div class="flex flex-row justify-between items-center min-h-[3.3125rem] bg-white px-5 py-4 rounded-b">
|
||||
<span *ngIf="totalReadingPoints$ | async; let totalReadingPoints" class="text-p2 font-bold"
|
||||
>{{ totalItemCount$ | async }} Artikel | {{ totalReadingPoints }} Lesepunkte</span
|
||||
>
|
||||
|
||||
<div class="flex flex-row items-center justify-center">
|
||||
<div class="text-p1 font-bold flex flex-row items-center">
|
||||
<div class="mr-1">Gesamtsumme {{ totalPrice$ | async | currency: ' ' }} {{ totalPriceCurrency$ | async }}</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="bg-brand text-white font-bold text-p1 outline-none border-none rounded-full px-6 py-3 ml-2"
|
||||
*ngIf="(takeNowOrders$ | async)?.length === 1 && (isB2BCustomer$ | async)"
|
||||
>
|
||||
<button class="cta-goods-out" (click)="navigateToShelfOut()">Zur Warenausgabe</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<hr *ngIf="last" />
|
||||
</ng-container>
|
||||
<ng-container *ngIf="orderLast">
|
||||
<div class="flex flex-row justify-between items-center min-h-[3.3125rem] bg-white px-5 py-4 rounded-b">
|
||||
<span *ngIf="totalReadingPoints$ | async; let totalReadingPoints" class="text-p2 font-bold"
|
||||
>{{ totalItemCount$ | async }} Artikel | {{ totalReadingPoints }} Lesepunkte</span
|
||||
>
|
||||
|
||||
<div class="flex flex-row items-center justify-center">
|
||||
<div class="text-p1 font-bold flex flex-row items-center">
|
||||
<div class="mr-1">Gesamtsumme {{ totalPrice$ | async | currency: ' ' }} {{ totalPriceCurrency$ | async }}</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="bg-brand text-white font-bold text-p1 outline-none border-none rounded-full px-6 py-3 ml-2"
|
||||
*ngIf="(takeNowOrders$ | async)?.length === 1 && (isB2BCustomer$ | async)"
|
||||
>
|
||||
<button class="cta-goods-out" (click)="navigateToGoodsOut()">Zur Warenausgabe</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #abholfrist let-order="order">
|
||||
<div *ngIf="!(updatingPreferredPickUpDate$ | async)[(order?.subsetItems)[0].id]" class="inline-flex">
|
||||
<button [uiOverlayTrigger]="deadlineDatepicker" #deadlineDatepickerTrigger="uiOverlayTrigger" class="flex flex-row items-center">
|
||||
<span class="mx-[0.625rem] font-normal">bis</span>
|
||||
<strong class="border-r border-[#AEB7C1] pr-4 text-[#AEB7C1]">
|
||||
{{ ((order?.subsetItems)[0]?.preferredPickUpDate | date: 'dd.MM.yy') || 'Auswählen' }}
|
||||
<strong class="border-r border-[#AEB7C1] pr-4">
|
||||
{{ ((order?.subsetItems)[0]?.preferredPickUpDate | date: 'dd.MM.yy') || 'TT.MM.JJJJ' }}
|
||||
</strong>
|
||||
|
||||
<shared-icon class="text-[#596470] ml-4" [size]="24" icon="isa-calendar"></shared-icon>
|
||||
@@ -222,3 +221,23 @@
|
||||
</div>
|
||||
<div class="fetching" *ngIf="!!(updatingPreferredPickUpDate$ | async)[(order?.subsetItems)[0].id]"></div>
|
||||
</ng-template>
|
||||
|
||||
<div class="absolute left-1/2 bottom-10 transform -translate-x-1/2 inline-grid grid-flow-col gap-4">
|
||||
<button
|
||||
*ifRole="'Store'"
|
||||
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"
|
||||
(click)="printOrderConfirmation()"
|
||||
>
|
||||
Bestellbestätigung drucken
|
||||
</button>
|
||||
|
||||
<button
|
||||
*ngIf="hasAbholung$ | 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"
|
||||
(click)="sendOrderConfirmation()"
|
||||
>
|
||||
Bestellbestätigung senden
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
:host {
|
||||
@apply box-border bg-transparent rounded overflow-scroll h-split-screen-tablet desktop-small:h-split-screen-desktop flex flex-col justify-between;
|
||||
@apply box-border bg-transparent relative;
|
||||
}
|
||||
|
||||
.summary-wrapper {
|
||||
@apply rounded overflow-scroll h-split-screen-tablet desktop-small:h-split-screen-desktop flex flex-col justify-between;
|
||||
}
|
||||
|
||||
.fetching {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Injector, OnDestroy, OnInit, inject } from '@angular/core';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
|
||||
import { PrintModalComponent, PrintModalData } from '@modal/printer';
|
||||
@@ -13,8 +13,11 @@ import { ApplicationService } from '@core/application';
|
||||
import { DomainPrinterService } from '@domain/printer';
|
||||
import { BehaviorSubject, combineLatest, NEVER, Subject } from 'rxjs';
|
||||
import { DateAdapter } from '@ui/common';
|
||||
import { CheckoutNavigationService, ProductCatalogNavigationService } from '@shared/services';
|
||||
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({
|
||||
selector: 'page-checkout-summary',
|
||||
@@ -23,6 +26,14 @@ import { EnvironmentService } from '@core/environment';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class CheckoutSummaryComponent implements OnInit, OnDestroy {
|
||||
private _injector = inject(Injector);
|
||||
|
||||
get sendOrderConfirmationModalService() {
|
||||
return this._injector.get(SendOrderConfirmationModalService);
|
||||
}
|
||||
|
||||
private _toaster = inject(ToasterService);
|
||||
|
||||
private _onDestroy$ = new Subject();
|
||||
processId = Date.now();
|
||||
selectedDate = this.dateAdapter.today();
|
||||
@@ -54,11 +65,16 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
|
||||
const itemsWithDifferentOrderFeature = orderWithMultipleFeatures.items.filter(
|
||||
(item) => item.features.orderType !== orderWithMultipleFeatures.features.orderType
|
||||
);
|
||||
filteredOrders = [
|
||||
...filteredOrders.filter((order) => order.id !== orderWithMultipleFeatures.id),
|
||||
{ ...orderWithMultipleFeatures, items: itemsWithOrderFeature },
|
||||
{ ...orderWithMultipleFeatures, items: itemsWithDifferentOrderFeature },
|
||||
];
|
||||
|
||||
filteredOrders = [...filteredOrders.filter((order) => order.id !== orderWithMultipleFeatures.id)];
|
||||
|
||||
if (itemsWithOrderFeature?.length > 0) {
|
||||
filteredOrders = [...filteredOrders, { ...orderWithMultipleFeatures, items: itemsWithOrderFeature }];
|
||||
}
|
||||
|
||||
if (itemsWithDifferentOrderFeature?.length > 0) {
|
||||
filteredOrders = [...filteredOrders, { ...orderWithMultipleFeatures, items: itemsWithDifferentOrderFeature }];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,6 +89,10 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
hasAbholung$ = this.displayOrders$.pipe(
|
||||
map((displayOrders) => displayOrders.filter((order) => order.features?.orderType === 'Abholung')?.length > 0)
|
||||
);
|
||||
|
||||
totalItemCount$ = this.displayOrders$.pipe(
|
||||
map((displayOrders) =>
|
||||
displayOrders.reduce(
|
||||
@@ -157,6 +177,7 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
|
||||
private dateAdapter: DateAdapter,
|
||||
private _navigation: CheckoutNavigationService,
|
||||
private _productNavigationService: ProductCatalogNavigationService,
|
||||
private _shelfOutNavigationService: PickUpShelfOutNavigationService,
|
||||
private _environmentService: EnvironmentService,
|
||||
private _cdr: ChangeDetectorRef
|
||||
) {
|
||||
@@ -216,20 +237,6 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
|
||||
return { main_qs: item?.product?.ean, filter_format: item?.features?.orderType === 'Download' ? 'eb;dl' : undefined };
|
||||
}
|
||||
|
||||
openPrintModal(id: number) {
|
||||
this.uiModal.open({
|
||||
content: PrintModalComponent,
|
||||
data: {
|
||||
printerType: 'Label',
|
||||
print: (printer) => this.domainPrinterService.printOrder({ orderIds: [id], printer }).toPromise(),
|
||||
} as PrintModalData,
|
||||
config: {
|
||||
panelClass: [],
|
||||
showScrollbarY: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async updatePreferredPickUpDate(item: DisplayOrderItemDTO, date: Date) {
|
||||
const data: Record<string, string> = {};
|
||||
|
||||
@@ -279,7 +286,7 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
|
||||
this.domainCheckoutService.updateOrderItem(item);
|
||||
}
|
||||
|
||||
async navigateToGoodsOut() {
|
||||
async navigateToShelfOut() {
|
||||
let takeNowOrders = await this.takeNowOrders$.pipe(first()).toPromise();
|
||||
if (takeNowOrders.length != 1) return;
|
||||
|
||||
@@ -294,9 +301,45 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
this.router.navigate(['/kunde', 'goods', 'out', 'details', 'order', takeNowOrders[0].orderNumber, 128]);
|
||||
await this.router.navigate(
|
||||
this._shelfOutNavigationService.detailRoute({
|
||||
processId: Date.now(),
|
||||
item: { orderId: takeNowOrders[0].id, orderNumber: takeNowOrders[0].orderNumber, processingStatus: 128 },
|
||||
}).path
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
async sendOrderConfirmation() {
|
||||
const orders = await this.displayOrders$.pipe(first()).toPromise();
|
||||
|
||||
await this.sendOrderConfirmationModalService.open(orders);
|
||||
}
|
||||
|
||||
async printOrderConfirmation() {
|
||||
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' });
|
||||
}
|
||||
},
|
||||
} as PrintModalData,
|
||||
config: {
|
||||
panelClass: [],
|
||||
showScrollbarY: false,
|
||||
},
|
||||
})
|
||||
.afterClosed$.toPromise();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<shared-breadcrumb class="mb-5 desktop-small:mb-9" [key]="breadcrumbKey$ | async" [tags]="['checkout']"></shared-breadcrumb>
|
||||
<shared-breadcrumb [key]="breadcrumbKey$ | async" [tags]="['checkout']"></shared-breadcrumb>
|
||||
|
||||
<shared-splitscreen></shared-splitscreen>
|
||||
|
||||
@@ -295,7 +295,7 @@
|
||||
[disabled]="(!isKulturpass && !!orderItem?.features?.paid) || (changeDateDisabled$ | async)"
|
||||
class="cta-pickup-preferred"
|
||||
>
|
||||
<strong *ngIf="preferredPickUpDate$ | async; let pickUpDate; else: selectTemplate">
|
||||
<strong class="border-r border-[#AEB7C1] pr-4" *ngIf="preferredPickUpDate$ | async; let pickUpDate; else: selectTemplate">
|
||||
{{ pickUpDate | date: 'dd.MM.yy' }}
|
||||
</strong>
|
||||
<ng-template #selectTemplate>
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
import { ChangeDetectionStrategy, Component, ContentChildren, OnDestroy, OnInit, QueryList } from '@angular/core';
|
||||
import {
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
ContentChild,
|
||||
ContentChildren,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
QueryList,
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
@@ -13,6 +22,7 @@ import { CustomerOrderDetailsStore } from './customer-order-details.store';
|
||||
import { CustomerOrderDetailsItemComponent } from './customer-order-details-item';
|
||||
import { unionBy } from 'lodash';
|
||||
import { CommandService } from '@core/command';
|
||||
import { CustomerOrderDetailsTagsComponent } from './customer-order-details-tags';
|
||||
|
||||
@Component({
|
||||
selector: 'page-customer-order-details',
|
||||
@@ -21,10 +31,13 @@ import { CommandService } from '@core/command';
|
||||
providers: [provideComponentStore(CustomerOrderDetailsStore)],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class CustomerOrderDetailsComponent implements OnInit, OnDestroy {
|
||||
export class CustomerOrderDetailsComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
@ContentChildren(CustomerOrderDetailsItemComponent)
|
||||
customerOrderDetailsItemComponents: QueryList<CustomerOrderDetailsItemComponent>;
|
||||
|
||||
@ContentChild(CustomerOrderDetailsTagsComponent, { static: false })
|
||||
customerOrderDetailsTags: CustomerOrderDetailsTagsComponent;
|
||||
|
||||
buyerNumber$ = this._store.buyerNumber$;
|
||||
|
||||
compartmentCode$ = this._store.compartmentCode$;
|
||||
@@ -146,10 +159,23 @@ export class CustomerOrderDetailsComponent implements OnInit, OnDestroy {
|
||||
this.removeBreadcrumbs();
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this._registerCustomerOrderDetailsTagsComponentChanges();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.subscriptions.unsubscribe();
|
||||
}
|
||||
|
||||
private _registerCustomerOrderDetailsTagsComponentChanges() {
|
||||
this.subscriptions.add(
|
||||
this.items$.subscribe((_) => {
|
||||
this.customerOrderDetailsTags?.writeValue(this.compartmentInfo);
|
||||
this.customerOrderDetailsTags?.registerOnChange((compartmentInfo) => (this._store.compartmentInfo = compartmentInfo));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
itemsSelectable(items: OrderItemListItemDTO[]) {
|
||||
this._store.patchState({
|
||||
itemsSelectable: items?.some((item) => !!item?.actions && item?.actions?.length > 0),
|
||||
|
||||
@@ -4,7 +4,7 @@ import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { DomainCustomerOrderService, DomainGoodsService, DomainOmsService } from '@domain/oms';
|
||||
import { CustomerOrdersNavigationService } from '@shared/services';
|
||||
import { OrderItemListItemDTO } from '@swagger/oms';
|
||||
import { DBHOrderItemListItemDTO, OrderItemListItemDTO } from '@swagger/oms';
|
||||
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
|
||||
import { combineLatest, Observable } from 'rxjs';
|
||||
import { map, shareReplay, switchMap, tap, withLatestFrom } from 'rxjs/operators';
|
||||
@@ -87,10 +87,10 @@ export class CustomerOrderEditComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
async navigateToDetailsPage({ options }: { options?: { processingStatus?: number } }) {
|
||||
async navigateToDetailsPage(changes?: Partial<DBHOrderItemListItemDTO>) {
|
||||
const orderId = this._activatedRoute.snapshot.params.orderId;
|
||||
const compartmentCode = this._activatedRoute.snapshot.params.compartmentCode;
|
||||
const processingStatus = options?.processingStatus ? options.processingStatus : this._activatedRoute.snapshot.params.processingStatus;
|
||||
const processingStatus = changes?.processingStatus ? changes.processingStatus : this._activatedRoute.snapshot.params.processingStatus;
|
||||
|
||||
await this._navigation
|
||||
.getCustomerOrdersDetailsPath({
|
||||
|
||||
@@ -83,6 +83,7 @@ export class CustomerOrderSearchFilterComponent implements OnInit, OnDestroy {
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.showFilter = this.sideOutlet !== 'search';
|
||||
this._activatedRoute.queryParams.pipe(takeUntil(this._onDestroy$)).subscribe((queryParams) => {
|
||||
this._customerOrdersSearchStore.setQueryParams(queryParams);
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[routerLink]="detailsLink"
|
||||
[routerLinkActive]="!isTablet && !primaryOutletActive ? 'active' : ''"
|
||||
[queryParams]="queryParams"
|
||||
(click)="isDesktop ? scrollIntoView() : ''"
|
||||
(click)="isDesktopLarge ? scrollIntoView() : ''"
|
||||
>
|
||||
<div
|
||||
class="page-customer-order-item__item-grid-container"
|
||||
|
||||
@@ -74,6 +74,10 @@
|
||||
grid-area: ordernumber;
|
||||
}
|
||||
|
||||
.page-customer-order-item__item-special-comment {
|
||||
grid-area: comment;
|
||||
}
|
||||
|
||||
.page-customer-order-item__item-order-number-main {
|
||||
@apply justify-self-start self-center;
|
||||
}
|
||||
@@ -82,25 +86,7 @@
|
||||
grid-area: status;
|
||||
}
|
||||
|
||||
.page-customer-order-item__item-select-bullet {
|
||||
grid-area: select;
|
||||
}
|
||||
|
||||
.active,
|
||||
.hover:hover {
|
||||
@apply bg-[#D8DFE5] border border-solid border-[#0556B4];
|
||||
|
||||
.page-customer-order-item__item-select-bullet {
|
||||
.isa-select-bullet::before {
|
||||
@apply bg-[#fff];
|
||||
}
|
||||
|
||||
.isa-select-bullet:checked:before {
|
||||
@apply bg-[#596470];
|
||||
}
|
||||
|
||||
.isa-select-bullet:hover::before {
|
||||
@apply bg-[#778490];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, ElementRef } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, Input, ElementRef } from '@angular/core';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { ComponentStore } from '@ngrx/component-store';
|
||||
@@ -10,8 +10,6 @@ import { map } from 'rxjs/operators';
|
||||
|
||||
export interface CustomerOrderItemComponentState {
|
||||
item?: OrderItemListItemDTO;
|
||||
selected: boolean;
|
||||
selectable: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
@@ -33,30 +31,12 @@ export class CustomerOrderItemComponent extends ComponentStore<CustomerOrderItem
|
||||
|
||||
readonly item$ = this.select((s) => s.item);
|
||||
|
||||
@Input()
|
||||
selected: boolean;
|
||||
|
||||
selected$ = this.select((s) => s.selected);
|
||||
|
||||
@Input()
|
||||
get selectable() {
|
||||
return this.get((s) => s.selectable);
|
||||
}
|
||||
set selectable(selectable: boolean) {
|
||||
if (this.selectable !== selectable) {
|
||||
this.patchState({ selectable });
|
||||
}
|
||||
}
|
||||
|
||||
@Output()
|
||||
selectedChange = new EventEmitter<boolean>();
|
||||
|
||||
get isTablet() {
|
||||
return this._environment.matchTablet();
|
||||
}
|
||||
|
||||
get isDesktop() {
|
||||
return this._environment.matchDesktop();
|
||||
get isDesktopLarge() {
|
||||
return this._environment.matchDesktopLarge();
|
||||
}
|
||||
|
||||
get queryParams() {
|
||||
@@ -98,7 +78,7 @@ export class CustomerOrderItemComponent extends ComponentStore<CustomerOrderItem
|
||||
private _applicationService: ApplicationService,
|
||||
private _elRef: ElementRef
|
||||
) {
|
||||
super({ selected: false, selectable: false });
|
||||
super({});
|
||||
}
|
||||
|
||||
scrollIntoView() {
|
||||
|
||||
@@ -72,10 +72,7 @@
|
||||
*ngFor="let item of compartmentCodeGroup.items; let firstItem = first; trackBy: trackByFn"
|
||||
class="page-customer-orders-results__result-item mb-[0.625rem]"
|
||||
[class.page-customer-orders-results__result-item-main]="primaryOutletActive$ | async"
|
||||
[selectable]="item | goodsOutItemSelectable: selectionRules:selectedItems"
|
||||
[selected]="item | goodsOutItemSelected: selectedOrderItemSubsetIds"
|
||||
[item]="item"
|
||||
(selectedChange)="setSelectedItem(item, $event)"
|
||||
[primaryOutletActive]="primaryOutletActive$ | async"
|
||||
></page-customer-order-item>
|
||||
</ng-container>
|
||||
|
||||
@@ -112,18 +112,10 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
|
||||
return this._environment.matchTablet$;
|
||||
}
|
||||
|
||||
get isTablet() {
|
||||
return this._environment.matchTablet();
|
||||
}
|
||||
|
||||
get isDesktopLarge() {
|
||||
return this._environment.matchDesktopLarge();
|
||||
}
|
||||
|
||||
get rightOutletParams(): Params {
|
||||
return this._activatedRoute?.parent?.children?.find((childRoute) => childRoute?.outlet === 'right')?.snapshot?.params;
|
||||
}
|
||||
|
||||
get filterRoute() {
|
||||
const compartmentCode = this._activatedRoute?.snapshot?.params?.compartmentCode;
|
||||
const orderId = this._activatedRoute?.snapshot?.params?.orderId;
|
||||
@@ -230,7 +222,7 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
|
||||
await this.createBreadcrumb(processId, params);
|
||||
}
|
||||
|
||||
if (!this.isDesktopLarge || this._activatedRoute?.outlet === 'main') {
|
||||
if (this._activatedRoute?.outlet === 'primary') {
|
||||
await this.removeDetailsBreadcrumb(processId);
|
||||
}
|
||||
})
|
||||
@@ -253,7 +245,7 @@ export class CustomerOrderSearchResultsComponent extends ComponentStore<Customer
|
||||
result?.results?.result?.find((_) => true),
|
||||
queryParams
|
||||
);
|
||||
} else if ((!!result?.clear || this._activatedRoute.outlet === 'primary') && !this.isTablet) {
|
||||
} else if ((!!result?.clear || this._activatedRoute.outlet === 'primary') && this.isDesktopLarge) {
|
||||
await this._navigationService.getCustomerOrdersResultsPath(processId, { queryParams }).navigate();
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<shared-breadcrumb class="mb-5 desktop-small:mb-9" [key]="processId$ | async" [tags]="['customer-order']">
|
||||
<shared-breadcrumb [key]="processId$ | async" [tags]="['customer-order']">
|
||||
<shared-branch-selector [branchType]="1" [value]="selectedBranch$ | async" (valueChange)="patchProcessData($event)">
|
||||
</shared-branch-selector>
|
||||
</shared-breadcrumb>
|
||||
|
||||
@@ -31,7 +31,7 @@ shared-branch-selector.shared-branch-selector-opend {
|
||||
shared-branch-selector.shared-branch-selector-opend
|
||||
.shared-branch-selector-input-container
|
||||
.shared-branch-selector-input-icon {
|
||||
@apply pl-0 border-l-0;
|
||||
@apply border-l-0;
|
||||
}
|
||||
|
||||
::ng-deep .tablet page-customer-order shared-breadcrumb:focus-within .shared-breadcrumb__suffix {
|
||||
|
||||
@@ -85,7 +85,9 @@
|
||||
</app-deviating-address-form-block>
|
||||
|
||||
<div class="spacer"></div>
|
||||
<button class="cta-submit" type="button" (click)="save()" [disabled]="form.invalid || form.pending">
|
||||
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
|
||||
</button>
|
||||
<div class="sticky w-full flex items-center justify-center">
|
||||
<button class="cta-submit" type="button" (click)="save()" [disabled]="form.invalid || form.pending">
|
||||
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -19,7 +19,7 @@ form {
|
||||
}
|
||||
|
||||
button.cta-submit {
|
||||
@apply sticky left-1/2 bottom-8 text-center bg-brand text-lg text-white font-bold px-7 py-3 rounded-full transform -translate-x-1/2 transition-all duration-200 ease-in-out;
|
||||
@apply fixed bottom-16 desktop-small:bottom-8 text-center bg-brand text-lg text-white font-bold px-7 py-3 rounded-full transform transition-all duration-200 ease-in-out;
|
||||
|
||||
&:disabled {
|
||||
@apply bg-active-branch cursor-not-allowed;
|
||||
|
||||
@@ -98,7 +98,9 @@
|
||||
</app-deviating-address-form-block>
|
||||
|
||||
<div class="spacer"></div>
|
||||
<button class="cta-submit" type="button" (click)="save()" [disabled]="form.invalid || form.pending">
|
||||
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
|
||||
</button>
|
||||
<div class="sticky w-full flex items-center justify-center">
|
||||
<button class="cta-submit" type="button" (click)="save()" [disabled]="form.invalid || form.pending">
|
||||
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -143,7 +143,9 @@
|
||||
|
||||
<div class="spacer"></div>
|
||||
|
||||
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
|
||||
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
|
||||
</button>
|
||||
<div class="sticky w-full flex items-center justify-center">
|
||||
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
|
||||
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -84,9 +84,12 @@
|
||||
</app-deviating-address-form-block>
|
||||
|
||||
<div class="spacer"></div>
|
||||
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
|
||||
<ui-spinner [show]="busy$ | async">
|
||||
Speichern
|
||||
</ui-spinner>
|
||||
</button>
|
||||
|
||||
<div class="sticky w-full flex items-center justify-center">
|
||||
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
|
||||
<ui-spinner [show]="busy$ | async">
|
||||
Speichern
|
||||
</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -98,7 +98,9 @@
|
||||
</app-deviating-address-form-block>
|
||||
|
||||
<div class="spacer"></div>
|
||||
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
|
||||
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
|
||||
</button>
|
||||
<div class="sticky w-full flex items-center justify-center">
|
||||
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
|
||||
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
<a
|
||||
*ngIf="customerSearchNavigation$ | async; let customerSearchNavigation"
|
||||
[routerLink]="customerSearchNavigation.path"
|
||||
[queryParams]="customerSearchNavigation.queryParams"
|
||||
class="text-[1.375rem] font-bold text-[#596470] text-center py-4"
|
||||
>Kundensuche</a
|
||||
>
|
||||
<div class="text-center pt-10 px-8 rounded-card side-view-shadow grow">
|
||||
<h1 class="text-[1.625rem] font-bold">Kundendaten erfassen</h1>
|
||||
<p class="text-lg mt-2">
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, ChangeDetectionStrategy, Input } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { CustomerSearchNavigation } from '@shared/services';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'page-customer-create-side-view',
|
||||
@@ -14,9 +11,5 @@ import { map } from 'rxjs/operators';
|
||||
imports: [CommonModule, RouterModule],
|
||||
})
|
||||
export class CustomerCreateSideViewComponent {
|
||||
customerSearchNavigation$ = this._applicationService.activatedProcessId$.pipe(
|
||||
map((processId) => this.searchNavigation.defaultRoute({ processId }))
|
||||
);
|
||||
|
||||
constructor(public readonly searchNavigation: CustomerSearchNavigation, private _applicationService: ApplicationService) {}
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
@@ -113,7 +113,9 @@
|
||||
|
||||
<div class="spacer"></div>
|
||||
|
||||
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
|
||||
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
|
||||
</button>
|
||||
<div class="sticky w-full flex items-center justify-center">
|
||||
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
|
||||
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<shared-breadcrumb [key]="processId$ | async" [tags]="['customer']" class="mb-5 desktop-small:mb-9"></shared-breadcrumb>
|
||||
<shared-breadcrumb [key]="processId$ | async" [tags]="['customer']"></shared-breadcrumb>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
</shared-form-control>
|
||||
|
||||
<div class="text-center col-span-2">
|
||||
<shared-checkbox>Diese Rechnungsadresse als Standard Adresse festlegen</shared-checkbox>
|
||||
<shared-checkbox formControlName="isDefault">Diese Rechnungsadresse als Standard Adresse festlegen</shared-checkbox>
|
||||
</div>
|
||||
<div class="mt-6 text-center col-span-2">
|
||||
<button
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
</shared-form-control>
|
||||
|
||||
<div class="text-center col-span-2">
|
||||
<shared-checkbox>Diese Lieferadresse als Standard Adresse festlegen</shared-checkbox>
|
||||
<shared-checkbox formControlName="isDefault">Diese Lieferadresse als Standard Adresse festlegen</shared-checkbox>
|
||||
</div>
|
||||
<div class="mt-6 text-center col-span-2">
|
||||
<button
|
||||
|
||||
@@ -30,7 +30,7 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
|
||||
breadcrumb = this.snapshot.data?.breadcrumb;
|
||||
|
||||
if (!breadcrumb) {
|
||||
breadcrumb = this.firstChildSnapshot.data?.breadcrumb;
|
||||
breadcrumb = this.firstChildSnapshot?.data?.breadcrumb;
|
||||
}
|
||||
|
||||
return breadcrumb;
|
||||
@@ -145,7 +145,6 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
|
||||
let processId: number;
|
||||
|
||||
processId = this.snapshot.data?.processId;
|
||||
|
||||
if (!processId) {
|
||||
processId = this.parentSnapshot?.data?.processId;
|
||||
}
|
||||
@@ -168,7 +167,7 @@ export class CustomerSearchComponent implements OnInit, OnDestroy {
|
||||
side = this.snapshot.data?.side;
|
||||
|
||||
if (!side) {
|
||||
side = this.firstChildSnapshot.data?.side;
|
||||
side = this.firstChildSnapshot?.data?.side;
|
||||
}
|
||||
|
||||
if (side !== this.side) {
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
[checked]="!(selectedPayer$ | async)"
|
||||
(change)="selectCustomerAddress()"
|
||||
/>
|
||||
<div class="ml-2 flex flex-row justify-between items-center grow">
|
||||
<span class="truncate">
|
||||
<div class="ml-2 flex flex-row justify-between items-start grow">
|
||||
<span class="mr-4">
|
||||
{{ customer$ | async | address }}
|
||||
</span>
|
||||
<a
|
||||
@@ -51,8 +51,8 @@
|
||||
[checked]="(selectedPayer$ | async)?.payer.id === assignedPayer.payer.id"
|
||||
(change)="selectPayer(assignedPayer)"
|
||||
/>
|
||||
<div class="flex flex-row justify-between items-center grow">
|
||||
<span class="ml-2">
|
||||
<div class="flex flex-row justify-between items-start grow">
|
||||
<span class="mr-4">
|
||||
{{ assignedPayer.payer.data | address }}
|
||||
</span>
|
||||
<ng-container *ngIf="canEditAddress$ | async">
|
||||
|
||||
@@ -157,16 +157,19 @@ export class DetailsMainViewBillingAddressesComponent extends ComponentStore<Det
|
||||
);
|
||||
|
||||
handleLoadAssignedPayersResponse = (response: ListResponseArgsOfAssignedPayerDTO) => {
|
||||
const selectedPayer = response.result.reduce<AssignedPayerDTO>((selected, payer) => {
|
||||
if (!selected) {
|
||||
return payer;
|
||||
const selectedPayer = response.result.reduce<AssignedPayerDTO>((prev, curr) => {
|
||||
if (!prev) {
|
||||
return curr;
|
||||
}
|
||||
|
||||
if (new Date(selected.isDefault).getTime() < new Date(payer.isDefault).getTime()) {
|
||||
return payer;
|
||||
const prevDate = new Date(prev?.isDefault ?? 0);
|
||||
const currDate = new Date(curr?.isDefault ?? 0);
|
||||
|
||||
if (prevDate > currDate) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
return selected;
|
||||
return curr;
|
||||
}, undefined);
|
||||
|
||||
this.patchState({
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
*ngIf="showCustomerAddress$ | async"
|
||||
>
|
||||
<input name="shipping-address" type="radio" [checked]="!(selectedShippingAddress$ | async)" (change)="selectCustomerAddress()" />
|
||||
<div class="ml-2 flex flex-row justify-between items-center grow">
|
||||
<span class="truncate">
|
||||
<div class="ml-2 flex flex-row justify-between items-start grow">
|
||||
<span class="mr-4">
|
||||
{{ customer$ | async | address }}
|
||||
</span>
|
||||
<a
|
||||
@@ -45,11 +45,18 @@
|
||||
[checked]="(selectedShippingAddress$ | async)?.id === shippingAddress.id"
|
||||
(change)="selectShippingAddress(shippingAddress)"
|
||||
/>
|
||||
<div class="ml-2 flex flex-row justify-between items-center grow">
|
||||
<span class="ml-2">
|
||||
<div class="ml-2 flex flex-row justify-between items-start grow">
|
||||
<span class="mr-4">
|
||||
{{ shippingAddress | address }}
|
||||
</span>
|
||||
<a *ngIf="canEditAddress$ | async" class="text-brand font-bold" type="button">
|
||||
<a
|
||||
*ngIf="editShippingAddressRoute$(shippingAddress.id) | async; let route"
|
||||
class="text-brand font-bold"
|
||||
type="button"
|
||||
[routerLink]="route?.path"
|
||||
[queryParams]="route?.queryParams"
|
||||
[queryParamsHandling]="'merge'"
|
||||
>
|
||||
Bearbeiten
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -71,6 +71,16 @@ export class DetailsMainViewDeliveryAddressesComponent extends ComponentStore<De
|
||||
)
|
||||
);
|
||||
|
||||
editShippingAddressRoute$ = (shippingAddressId: number) =>
|
||||
combineLatest([this.canEditAddress$, this._store.processId$, this._store.customerId$]).pipe(
|
||||
map(([canEditAddress, processId, customerId]) => {
|
||||
if (canEditAddress) {
|
||||
return this._navigation.editShippingAddressRoute({ processId, customerId, shippingAddressId });
|
||||
}
|
||||
return undefined;
|
||||
})
|
||||
);
|
||||
|
||||
canEditAddress$ = combineLatest([this._store.isKundenkarte$, this._store.isBusinessKonto$, this._store.isMitarbeiter$]).pipe(
|
||||
map(([isKundenkarte, isBusinessKonto, isMitarbeiter]) => isKundenkarte || isBusinessKonto || isMitarbeiter)
|
||||
);
|
||||
@@ -150,16 +160,19 @@ export class DetailsMainViewDeliveryAddressesComponent extends ComponentStore<De
|
||||
);
|
||||
|
||||
handleLoadShippingAddressesResponse = (response: ListResponseArgsOfAssignedPayerDTO) => {
|
||||
const selectedShippingAddress = response.result.reduce<ShippingAddressDTO>((selected, shipping) => {
|
||||
if (!this.showCustomerAddress && !selected) {
|
||||
return shipping;
|
||||
const selectedShippingAddress = response.result.reduce<ShippingAddressDTO>((prev, curr) => {
|
||||
if (!this.showCustomerAddress && !prev) {
|
||||
return curr;
|
||||
}
|
||||
|
||||
if (selected && shipping && new Date(selected.isDefault).getTime() < new Date(shipping.isDefault).getTime()) {
|
||||
return shipping;
|
||||
const prevDate = new Date(prev?.isDefault ?? 0);
|
||||
const currDate = new Date(curr?.isDefault ?? 0);
|
||||
|
||||
if (prevDate > currDate) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
return selected;
|
||||
return curr;
|
||||
}, undefined);
|
||||
|
||||
this.patchState({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy } from '@angular/core';
|
||||
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';
|
||||
@@ -12,6 +12,7 @@ import { ApplicationService } from '@core/application';
|
||||
import { CheckoutNavigationService, ProductCatalogNavigationService } from '@shared/services';
|
||||
import { Router } from '@angular/router';
|
||||
import { log, logAsync } from '@utils/common';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
|
||||
const GENDER_MAP = {
|
||||
2: 'Herr',
|
||||
@@ -34,6 +35,8 @@ export interface CustomerDetailsViewMainState {
|
||||
export class CustomerDetailsViewMainComponent extends ComponentStore<CustomerDetailsViewMainState> implements OnInit, OnDestroy {
|
||||
private _onDestroy$ = new Subject();
|
||||
|
||||
customerService = inject(CrmCustomerService);
|
||||
|
||||
fetching$ = this._store.fetchingCustomer$;
|
||||
|
||||
isBusy$ = this.select((s) => s.isBusy);
|
||||
@@ -230,15 +233,21 @@ export class CustomerDetailsViewMainComponent extends ComponentStore<CustomerDet
|
||||
if (this.isBusy) return;
|
||||
this.setIsBusy(true);
|
||||
|
||||
if (this.shoppingCartHasItems && !(await this._canAddCustomerAsync())) {
|
||||
const canAddCustomer = await this._canAddCustomerAsync();
|
||||
if (this.shoppingCartHasItems && !canAddCustomer) {
|
||||
this.setIsBusy(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.shippingAddress && !this._canAddShippingAddressAsync()) {
|
||||
const canAddShippingAddress = await this._canAddShippingAddressAsync();
|
||||
if (this.shippingAddress && !canAddShippingAddress) {
|
||||
this.setIsBusy(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(await this._updateDestinationAsync())) {
|
||||
const destinationUpdated = await this._updateDestinationAsync();
|
||||
if (!destinationUpdated) {
|
||||
this.setIsBusy(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -300,13 +309,15 @@ export class CustomerDetailsViewMainComponent extends ComponentStore<CustomerDet
|
||||
return true;
|
||||
}
|
||||
|
||||
const required = await this.customerService.canUpgrade(this.customer.id).toPromise();
|
||||
|
||||
const upgradeableTo = res.create;
|
||||
const data: CantAddCustomerToCartData = {
|
||||
message: res.message,
|
||||
upgradeableTo,
|
||||
customer: this.customer,
|
||||
attributes: this.customer.attributes.map((a) => a.data),
|
||||
required: res.create,
|
||||
required,
|
||||
};
|
||||
|
||||
await this._modalService
|
||||
|
||||
@@ -70,13 +70,13 @@
|
||||
</shared-form-control>
|
||||
|
||||
<div class="text-center col-span-2">
|
||||
<shared-checkbox>Diese Rechnungsadresse als Standard Adresse festlegen</shared-checkbox>
|
||||
<shared-checkbox formControlName="isDefault">Diese Rechnungsadresse als Standard Adresse festlegen</shared-checkbox>
|
||||
</div>
|
||||
<div class="mt-6 text-center col-span-2">
|
||||
<button
|
||||
[disabled]="formGroup.invalid || formGroup.disabled"
|
||||
type="submit"
|
||||
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white"
|
||||
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white disabled:bg-gray-400 disabled:cursor-not-allowed"
|
||||
>
|
||||
Speichern
|
||||
</button>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, ChangeDetectorRef, inject } from '@angular/core';
|
||||
import { CheckboxComponent } from '@shared/components/checkbox';
|
||||
import { FormControl, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
||||
import { SelectModule } from '@shared/components/select';
|
||||
@@ -36,6 +36,8 @@ export class EditBillingAddressMainViewComponent extends ComponentStore<EditBill
|
||||
map(([processId, customerId]) => this._navigation.detailsRoute({ processId, customerId }))
|
||||
);
|
||||
|
||||
private _cdr = inject(ChangeDetectorRef);
|
||||
|
||||
formGroup = new FormGroup({
|
||||
gender: new FormControl<Gender>(0, [Validators.required, Validators.min(1)]),
|
||||
title: new FormControl<string>(undefined),
|
||||
@@ -103,6 +105,10 @@ export class EditBillingAddressMainViewComponent extends ComponentStore<EditBill
|
||||
country: payer.address.country,
|
||||
info: payer.address.info,
|
||||
});
|
||||
|
||||
this.formGroup.markAllAsTouched();
|
||||
this.formGroup.updateValueAndValidity();
|
||||
this._cdr.markForCheck();
|
||||
}
|
||||
|
||||
async save() {
|
||||
|
||||
@@ -86,13 +86,13 @@
|
||||
</shared-form-control>
|
||||
|
||||
<div class="text-center col-span-2">
|
||||
<shared-checkbox>Diese Lieferadresse als Standard Adresse festlegen</shared-checkbox>
|
||||
<shared-checkbox formControlName="isDefault">Diese Lieferadresse als Standard Adresse festlegen</shared-checkbox>
|
||||
</div>
|
||||
<div class="mt-6 text-center col-span-2">
|
||||
<button
|
||||
[disabled]="formGroup.invalid || formGroup.disabled"
|
||||
type="submit"
|
||||
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white"
|
||||
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white disabled:bg-gray-400 disabled:cursor-not-allowed"
|
||||
tabindex="15"
|
||||
>
|
||||
Speichern
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, inject, ChangeDetectorRef } from '@angular/core';
|
||||
import { CheckboxComponent } from '@shared/components/checkbox';
|
||||
import { FormControl, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
||||
import { SelectModule } from '@shared/components/select';
|
||||
import { FormControlComponent } from '@shared/components/form-control';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
import { AddressDTO, Gender, ShippingAddressDTO } from '@swagger/crm';
|
||||
import { map, takeUntil } from 'rxjs/operators';
|
||||
import { 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 { Subject, combineLatest } from 'rxjs';
|
||||
import { IconComponent } from '@shared/components/icon';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
||||
import { ComponentStore } from '@ngrx/component-store';
|
||||
|
||||
export interface EditShippingAddressMainViewState {
|
||||
shippingAddress?: ShippingAddressDTO;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'page-edit-shipping-address-main-view',
|
||||
@@ -33,9 +38,13 @@ import { RouterLink } from '@angular/router';
|
||||
CheckboxComponent,
|
||||
],
|
||||
})
|
||||
export class EditShippingAddressMainViewComponent implements OnInit, OnDestroy {
|
||||
export class EditShippingAddressMainViewComponent extends ComponentStore<EditShippingAddressMainViewState> implements OnInit, OnDestroy {
|
||||
private _activatedRoute = inject(ActivatedRoute);
|
||||
|
||||
private _onDestroy = new Subject<void>();
|
||||
|
||||
private _cdr = inject(ChangeDetectorRef);
|
||||
|
||||
detailsRoute$ = combineLatest([this._store.processId$, this._store.customerId$]).pipe(
|
||||
map(([processId, customerId]) => this._navigation.detailsRoute({ processId, customerId }))
|
||||
);
|
||||
@@ -61,14 +70,30 @@ export class EditShippingAddressMainViewComponent implements OnInit, OnDestroy {
|
||||
|
||||
isBusinessKonto$ = this._store.isBusinessKonto$;
|
||||
|
||||
shippingAddressId$ = this._activatedRoute.params.pipe(
|
||||
map((params) => params.shippingAddressId),
|
||||
switchMap((shippingAddressId) => this._customerService.getShippingAddress(shippingAddressId).pipe(map((res) => res.result)))
|
||||
);
|
||||
|
||||
get shippingAddressId() {
|
||||
return this.get((s) => s.shippingAddress?.id);
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _customerService: CrmCustomerService,
|
||||
private _addressSelection: AddressSelectionModalService,
|
||||
private _store: CustomerSearchStore,
|
||||
private _navigation: CustomerSearchNavigation
|
||||
) {}
|
||||
) {
|
||||
super({ shippingAddress: undefined });
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.shippingAddressId$.pipe(takeUntil(this._onDestroy)).subscribe((shippingAddress) => {
|
||||
this.patchState({ shippingAddress });
|
||||
this.patchFormGroup(shippingAddress);
|
||||
});
|
||||
|
||||
this._store.customer$.pipe(takeUntil(this._onDestroy)).subscribe(() => {
|
||||
if (this._store.isBusinessKonto) {
|
||||
this.formGroup.controls.organisation.setValidators([Validators.required]);
|
||||
@@ -78,6 +103,26 @@ export class EditShippingAddressMainViewComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
patchFormGroup(shipping: ShippingAddressDTO) {
|
||||
this.formGroup.patchValue({
|
||||
gender: shipping.gender ?? 0,
|
||||
title: shipping.title,
|
||||
lastName: shipping.lastName,
|
||||
firstName: shipping.firstName,
|
||||
organisation: shipping.organisation?.name,
|
||||
street: shipping.address.street,
|
||||
streetNumber: shipping.address.streetNumber,
|
||||
zipCode: shipping.address.zipCode,
|
||||
city: shipping.address.city,
|
||||
country: shipping.address.country,
|
||||
info: shipping.address.info,
|
||||
});
|
||||
|
||||
this.formGroup.markAllAsTouched();
|
||||
this.formGroup.updateValueAndValidity();
|
||||
this._cdr.markForCheck();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this._onDestroy.next();
|
||||
this._onDestroy.complete();
|
||||
@@ -127,7 +172,12 @@ export class EditShippingAddressMainViewComponent implements OnInit, OnDestroy {
|
||||
address: addressValidationResult,
|
||||
};
|
||||
|
||||
const result = await this._customerService.createShippingAddress(this._store.customerId, shippingAddress, formData.isDefault);
|
||||
const result = await this._customerService.updateShippingAddress(
|
||||
this._store.customerId,
|
||||
this.shippingAddressId,
|
||||
shippingAddress,
|
||||
formData.isDefault
|
||||
);
|
||||
|
||||
this._navigation.navigateToDetails({ processId: this._store.processId, customerId: this._store.customerId });
|
||||
} catch (error) {
|
||||
|
||||
@@ -14,7 +14,13 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-3 bg-surface text-surface-content">
|
||||
<shared-filter [filter]="filter" [loading]="fetching$ | async" (search)="search(filter)" [hint]="message$ | async"></shared-filter>
|
||||
<shared-filter
|
||||
[filter]="filter"
|
||||
[loading]="fetching$ | async"
|
||||
(search)="search(filter)"
|
||||
[hint]="message$ | async"
|
||||
[scanner]="true"
|
||||
></shared-filter>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-flow-col gap-6 items-center justify-center mt-6">
|
||||
|
||||
@@ -39,9 +39,7 @@ export class CustomerFilterMainViewComponent {
|
||||
private _location: Location,
|
||||
private _router: Router,
|
||||
private _customerSearchNavigation: CustomerSearchNavigation
|
||||
) {
|
||||
console.log(this.isOnMainRoute);
|
||||
}
|
||||
) {}
|
||||
|
||||
search(filter: Filter) {
|
||||
this._store.setFilter(filter);
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
<a
|
||||
*ngIf="customerCreateNavigation$ | async; let customerCreateNavigation"
|
||||
[routerLink]="customerCreateNavigation.path"
|
||||
[queryParams]="customerCreateNavigation.queryParams"
|
||||
class="text-[1.375rem] font-bold text-[#596470] text-center py-4"
|
||||
>Kundendaten erfassen</a
|
||||
>
|
||||
<div class="text-center pt-10 px-8 rounded-card side-view-shadow grow">
|
||||
<h1 class="text-[1.625rem] font-bold">Kundensuche</h1>
|
||||
<p class="text-lg mt-2 mb-6">
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { AsyncPipe, CommonModule, NgIf } from '@angular/common';
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { CustomerCreateNavigation } from '@shared/services';
|
||||
import { Filter, FilterModule } from '@shared/components/filter';
|
||||
import { CustomerSearchStore } from '../store';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'page-customer-main-side-view',
|
||||
@@ -15,15 +13,13 @@ import { map } from 'rxjs/operators';
|
||||
imports: [CommonModule, RouterModule, FilterModule, AsyncPipe, NgIf],
|
||||
})
|
||||
export class MainSideViewComponent {
|
||||
customerCreateNavigation$ = this._store.processId$.pipe(map((processId) => this._navigation.defaultRoute({ processId })));
|
||||
|
||||
message$ = this._store.message$;
|
||||
|
||||
filter$ = this._store.filter$;
|
||||
|
||||
fetching$ = this._store.fetchingCustomerList$;
|
||||
|
||||
constructor(private _navigation: CustomerCreateNavigation, private _store: CustomerSearchStore) {}
|
||||
constructor(private _store: CustomerSearchStore) {}
|
||||
|
||||
search(filter: Filter) {
|
||||
this._store.setFilter(filter);
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
<div class="desktop-large:hidden">
|
||||
<a
|
||||
*ngIf="customerCreateNavigation$ | async; let customerCreateNavigation"
|
||||
[routerLink]="customerCreateNavigation.path"
|
||||
[queryParams]="customerCreateNavigation.queryParams"
|
||||
class="block text-[1.375rem] font-bold text-[#596470] text-center py-4"
|
||||
>Kundendaten erfassen</a
|
||||
>
|
||||
<div class="text-center pt-10 px-8 rounded-card side-view-shadow grow">
|
||||
<h1 class="text-[1.625rem] font-bold">Kundensuche</h1>
|
||||
<p class="text-lg mt-2 mb-6">
|
||||
@@ -19,6 +12,7 @@
|
||||
(search)="search(filter)"
|
||||
[loading]="fetching$ | async"
|
||||
[hint]="message$ | async"
|
||||
[scanner]="true"
|
||||
></shared-filter-input-group-main>
|
||||
<a
|
||||
*ngIf="filterRoute$ | async; let filterRoute"
|
||||
|
||||
@@ -6,7 +6,7 @@ import { AsyncPipe, NgIf } from '@angular/common';
|
||||
import { Router, RouterLink } from '@angular/router';
|
||||
import { IconComponent } from '@shared/components/icon';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { CustomerCreateNavigation, CustomerSearchNavigation } from '@shared/services';
|
||||
import { CustomerSearchNavigation } from '@shared/services';
|
||||
import { CustomerFilterMainViewModule } from '../filter-main-view/filter-main-view.module';
|
||||
import { isEmpty } from 'lodash';
|
||||
|
||||
@@ -20,8 +20,6 @@ import { isEmpty } from 'lodash';
|
||||
imports: [AsyncPipe, RouterLink, FilterModule, NgIf, IconComponent, CustomerFilterMainViewModule],
|
||||
})
|
||||
export class CustomerMainViewComponent {
|
||||
customerCreateNavigation$ = this._store.processId$.pipe(map((processId) => this._createNavigation.defaultRoute({ processId })));
|
||||
|
||||
filterRoute$ = combineLatest([this._store.processId$, this._store.filter$]).pipe(
|
||||
map(([processId, filter]) => {
|
||||
const route = this._searchNavigation.filterRoute({ processId, comingFrom: this._router.url?.split('?')[0] });
|
||||
@@ -45,12 +43,7 @@ export class CustomerMainViewComponent {
|
||||
|
||||
message$ = this._store.message$;
|
||||
|
||||
constructor(
|
||||
private _createNavigation: CustomerCreateNavigation,
|
||||
private _searchNavigation: CustomerSearchNavigation,
|
||||
private _store: CustomerSearchStore,
|
||||
private _router: Router
|
||||
) {}
|
||||
constructor(private _searchNavigation: CustomerSearchNavigation, private _store: CustomerSearchStore, private _router: Router) {}
|
||||
|
||||
search(filter: Filter) {
|
||||
this._store.setFilter(filter);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
(search)="search(filter)"
|
||||
[hint]="message$ | async"
|
||||
[loading]="fetching$ | async"
|
||||
[scanner]="true"
|
||||
></shared-filter-input-group-main>
|
||||
<a
|
||||
class="btn btn-light h-14 font-bold"
|
||||
@@ -25,7 +26,7 @@
|
||||
<span class="mr-5 self-end text-sm"> {{ hits$ | async }} Treffer </span>
|
||||
</div>
|
||||
<page-customer-result-list
|
||||
[compact]="isTablet$ | async"
|
||||
[compact]="(isTablet$ | async) || (isDesktopSmall$ | async)"
|
||||
[processId]="processId$ | async"
|
||||
[customers]="customers$ | async"
|
||||
[hits]="hits$ | async"
|
||||
|
||||
@@ -63,6 +63,8 @@ export class CustomerResultsMainViewComponent implements OnInit, OnDestroy, Afte
|
||||
|
||||
isTablet$ = this._environment.matchTablet$;
|
||||
|
||||
isDesktopSmall$ = this._environment.matchDesktopSmall$;
|
||||
|
||||
message$ = this._store.message$;
|
||||
|
||||
private _onDestroy$ = new Subject<void>();
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
(search)="search(filter)"
|
||||
[hint]="message$ | async"
|
||||
[loading]="fetching$ | async"
|
||||
[scanner]="true"
|
||||
></shared-filter-input-group-main>
|
||||
<a
|
||||
class="btn btn-light h-14 font-bold"
|
||||
|
||||
@@ -2,12 +2,15 @@ import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { AddressDTO } from '@swagger/crm';
|
||||
import { UiModalRef } from '@ui/modal';
|
||||
|
||||
/**
|
||||
* @deprecated Use `AddressSelectionModalComponent` in @shared/modal instead.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'page-address-selection-modal',
|
||||
selector: 'page-deprecated-address-selection-modal',
|
||||
templateUrl: 'address-selection-modal.component.html',
|
||||
styleUrls: ['address-selection-modal.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class AddressSelectionModalComponent {
|
||||
export class DeprecatedAddressSelectionModalComponent {
|
||||
constructor(public ref: UiModalRef<AddressDTO[] | string>) {}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { AddressSelectionModalComponent } from './address-selection-modal.component';
|
||||
import { DeprecatedAddressSelectionModalComponent } from './address-selection-modal.component';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiIconModule],
|
||||
exports: [AddressSelectionModalComponent],
|
||||
declarations: [AddressSelectionModalComponent],
|
||||
exports: [DeprecatedAddressSelectionModalComponent],
|
||||
declarations: [DeprecatedAddressSelectionModalComponent],
|
||||
})
|
||||
export class AddressSelectionModalModule {}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { CrmCustomerService } from '@domain/crm';
|
||||
import { AddressDTO } from '@swagger/crm';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { AddressSelectionModalComponent } from './address-selection-modal.component';
|
||||
import { DeprecatedAddressSelectionModalComponent } from './address-selection-modal.component';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddressSelectionModalService {
|
||||
@@ -25,7 +25,9 @@ export class AddressSelectionModalService {
|
||||
.toPromise();
|
||||
|
||||
if (addresses?.length > 0) {
|
||||
const modalResult = await this.modal.open({ content: AddressSelectionModalComponent, data: addresses }).afterClosed$.toPromise();
|
||||
const modalResult = await this.modal
|
||||
.open({ content: DeprecatedAddressSelectionModalComponent, data: addresses })
|
||||
.afterClosed$.toPromise();
|
||||
if (modalResult?.data) {
|
||||
return modalResult.data;
|
||||
}
|
||||
|
||||
@@ -6,13 +6,7 @@
|
||||
</p>
|
||||
|
||||
<div class="cta-wrapper">
|
||||
<a
|
||||
class="search-btn"
|
||||
[routerLink]="['/kunde', applicationService.activatedProcessId, 'customer', 'search']"
|
||||
[queryParams]="queryParams"
|
||||
(click)="ref.close()"
|
||||
>Zur Kundensuche</a
|
||||
>
|
||||
<a class="search-btn" [routerLink]="customerSearchNav.path" [queryParams]="queryParams" (click)="ref.close()">Zur Kundensuche</a>
|
||||
<button class="create-btn" (click)="upgradeCustomer()">Kundendaten erfassen</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, inject } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { UiModalRef } from '@ui/modal';
|
||||
import { isBoolean } from '@utils/common';
|
||||
import { encodeFormData, mapCustomerDtoToCustomerCreateFormData } from '../../create-customer/customer-create-form-data';
|
||||
import { CantAddCustomerToCartData } from './cant-add-customer-to-cart.data';
|
||||
import { CustomerCreateNavigation } from '@shared/services';
|
||||
|
||||
@Component({
|
||||
selector: 'pages-cant-add-customer-to-cart-modal',
|
||||
@@ -13,6 +14,12 @@ import { CantAddCustomerToCartData } from './cant-add-customer-to-cart.data';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class CantAddCustomerToCartModalComponent {
|
||||
customerCreateNavigation = inject(CustomerCreateNavigation);
|
||||
|
||||
customerSearchNav = this.customerCreateNavigation.defaultRoute({
|
||||
processId: this.applicationService.activatedProcessId,
|
||||
});
|
||||
|
||||
get upgradable(): boolean {
|
||||
return typeof this.option?.value === 'string';
|
||||
}
|
||||
@@ -50,12 +57,21 @@ export class CantAddCustomerToCartModalComponent {
|
||||
}
|
||||
|
||||
if (option === 'webshop' && attributes.some((a) => a.key === 'p4mUser')) {
|
||||
this.router.navigate(['/kunde', this.applicationService.activatedProcessId, 'customer', 'create', 'webshop-p4m'], {
|
||||
queryParams,
|
||||
const nav = this.customerCreateNavigation.createCustomerRoute({
|
||||
processId: this.applicationService.activatedProcessId,
|
||||
customerType: 'webshop-p4m',
|
||||
});
|
||||
this.router.navigate(nav.path, {
|
||||
queryParams: { ...nav.queryParams, ...queryParams },
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(['/kunde', this.applicationService.activatedProcessId, 'customer', 'create', option], {
|
||||
queryParams,
|
||||
const nav = this.customerCreateNavigation.createCustomerRoute({
|
||||
processId: this.applicationService.activatedProcessId,
|
||||
customerType: option as any,
|
||||
});
|
||||
|
||||
this.router.navigate(nav.path, {
|
||||
queryParams: { ...nav.queryParams, ...queryParams },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,11 @@
|
||||
>
|
||||
<a
|
||||
class="create-btn"
|
||||
[routerLink]="['/kunde', applicationService.activatedProcessId, 'customer', 'create', 'guest']"
|
||||
*ngIf="customerCreatePath(); let nav"
|
||||
[routerLink]="nav.path"
|
||||
(click)="ref.close()"
|
||||
[queryParams]="createCustomerDataQuery(ref?.data)"
|
||||
[queryParamsHandling]="'merge'"
|
||||
>Kundendaten erfassen</a
|
||||
>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, inject } from '@angular/core';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { CustomerDTO } from '@swagger/crm';
|
||||
import { UiModalRef } from '@ui/modal';
|
||||
import { encodeFormData, mapCustomerDtoToCustomerCreateFormData } from '../../create-customer';
|
||||
import { CustomerCreateNavigation } from '@shared/services';
|
||||
|
||||
@Component({
|
||||
selector: 'page-cant-select-guest-modal',
|
||||
@@ -11,8 +12,17 @@ import { encodeFormData, mapCustomerDtoToCustomerCreateFormData } from '../../cr
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class CantSelectGuestModalComponent {
|
||||
customerCreateNavigation = inject(CustomerCreateNavigation);
|
||||
|
||||
constructor(public ref: UiModalRef<any, CustomerDTO>, public readonly applicationService: ApplicationService) {}
|
||||
|
||||
customerCreatePath() {
|
||||
return this.customerCreateNavigation.createCustomerRoute({
|
||||
processId: this.applicationService.activatedProcessId,
|
||||
customerType: 'guest',
|
||||
});
|
||||
}
|
||||
|
||||
createCustomerDataQuery(customer: CustomerDTO): { [key: string]: string } {
|
||||
const formData = encodeFormData(mapCustomerDtoToCustomerCreateFormData(customer));
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user