mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
Compare commits
10 Commits
2.3-202306
...
feature/ku
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
330c59f7e9 | ||
|
|
0c65e9dace | ||
|
|
9b8ea11866 | ||
|
|
17aed38316 | ||
|
|
48a7cc4dd4 | ||
|
|
4417fd9f0d | ||
|
|
3e429cb261 | ||
|
|
48e30e795f | ||
|
|
953e528298 | ||
|
|
4276f427b9 |
@@ -11,13 +11,9 @@ export class DevScanAdapter implements ScanAdapter {
|
||||
constructor(private _modal: UiModalService, private _environmentService: EnvironmentService) {}
|
||||
|
||||
async init(): Promise<boolean> {
|
||||
if (this._environmentService.isTablet()) {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(isDevMode());
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(isDevMode());
|
||||
});
|
||||
}
|
||||
|
||||
scan(): Observable<string> {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { CommandService } from './command.service';
|
||||
|
||||
export abstract class ActionHandler<T = any> {
|
||||
constructor(readonly action: string) {}
|
||||
abstract handler(data: T): Promise<T>;
|
||||
abstract handler(data: T, service?: CommandService): Promise<T>;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { ModuleWithProviders, NgModule, Type } from '@angular/core';
|
||||
import { ModuleWithProviders, NgModule, Provider, Type } from '@angular/core';
|
||||
import { ActionHandler } from './action-handler.interface';
|
||||
import { CommandService } from './command.service';
|
||||
import { FEATURE_ACTION_HANDLERS, ROOT_ACTION_HANDLERS } from './tokens';
|
||||
|
||||
export function provideActionHandlers(actionHandlers: Type<ActionHandler>[]): Provider[] {
|
||||
return [CommandService, actionHandlers.map((handler) => ({ provide: FEATURE_ACTION_HANDLERS, useClass: handler, multi: true }))];
|
||||
}
|
||||
|
||||
@NgModule({})
|
||||
export class CoreCommandModule {
|
||||
static forRoot(actionHandlers: Type<ActionHandler>[]): ModuleWithProviders<CoreCommandModule> {
|
||||
|
||||
@@ -16,7 +16,7 @@ export class CommandService {
|
||||
throw new Error('Action Handler does not exist');
|
||||
}
|
||||
|
||||
data = await handler.handler(data);
|
||||
data = await handler.handler(data, this);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,13 @@ import {
|
||||
StoreCheckoutBranchService,
|
||||
ItemsResult,
|
||||
} from '@swagger/checkout';
|
||||
import { DisplayOrderDTO, DisplayOrderItemDTO, OrderCheckoutService, ReorderValues } from '@swagger/oms';
|
||||
import {
|
||||
DisplayOrderDTO,
|
||||
DisplayOrderItemDTO,
|
||||
OrderCheckoutService,
|
||||
ReorderValues,
|
||||
ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString,
|
||||
} from '@swagger/oms';
|
||||
import { isNullOrUndefined, memorize } from '@utils/common';
|
||||
import { combineLatest, Observable, of, concat, isObservable, throwError } from 'rxjs';
|
||||
import { bufferCount, catchError, filter, first, map, mergeMap, shareReplay, switchMap, tap, withLatestFrom } from 'rxjs/operators';
|
||||
@@ -372,8 +378,9 @@ export class DomainCheckoutService {
|
||||
_setBuyer({ processId, buyer }: { processId: number; buyer: BuyerDTO }): Observable<CheckoutDTO> {
|
||||
return this.getCheckout({ processId }).pipe(
|
||||
first(),
|
||||
mergeMap((checkout) =>
|
||||
this._buyerService
|
||||
mergeMap((checkout) => {
|
||||
console.log('checkout', checkout, processId);
|
||||
return this._buyerService
|
||||
.StoreCheckoutBuyerSetBuyerPOST({
|
||||
checkoutId: checkout?.id,
|
||||
buyerDTO: buyer,
|
||||
@@ -381,8 +388,8 @@ export class DomainCheckoutService {
|
||||
.pipe(
|
||||
map((response) => response.result),
|
||||
tap((checkout) => this.store.dispatch(DomainCheckoutActions.setCheckout({ processId, checkout })))
|
||||
)
|
||||
)
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -710,6 +717,47 @@ export class DomainCheckoutService {
|
||||
.pipe(mergeMap((_) => completeOrder$.pipe(tap(console.log.bind(window, 'completeOrder$')))));
|
||||
}
|
||||
|
||||
completeKulturpassOrder({
|
||||
processId,
|
||||
orderItemSubsetId,
|
||||
}: {
|
||||
processId: number;
|
||||
orderItemSubsetId: number;
|
||||
}): Observable<ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString> {
|
||||
const refreshShoppingCart$ = this.getShoppingCart({ processId, latest: true }).pipe(first());
|
||||
const refreshCheckout$ = this.getCheckout({ processId, refresh: true }).pipe(first());
|
||||
|
||||
const setBuyer$ = this.getBuyer({ processId }).pipe(
|
||||
first(),
|
||||
mergeMap((buyer) => this._setBuyer({ processId, buyer }))
|
||||
);
|
||||
|
||||
const setPayer$ = this.getPayer({ processId }).pipe(
|
||||
first(),
|
||||
mergeMap((payer) => this._setPayer({ processId, payer }))
|
||||
);
|
||||
|
||||
const checkAvailabilities$ = this.checkAvailabilities({ processId });
|
||||
|
||||
const updateAvailabilities$ = this.updateAvailabilities({ processId });
|
||||
|
||||
return refreshShoppingCart$.pipe(
|
||||
mergeMap((_) => refreshCheckout$),
|
||||
mergeMap((_) => checkAvailabilities$),
|
||||
mergeMap((_) => updateAvailabilities$),
|
||||
mergeMap((_) => setBuyer$),
|
||||
mergeMap((_) => setPayer$),
|
||||
mergeMap((checkout) =>
|
||||
this.orderCheckoutService.OrderCheckoutCreateKulturPassOrder({
|
||||
payload: {
|
||||
checkoutId: checkout.id,
|
||||
orderItemSubsetId: String(orderItemSubsetId),
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
updateDestination({
|
||||
processId,
|
||||
destinationId,
|
||||
|
||||
@@ -38,4 +38,5 @@ export * from './requested.action-handler';
|
||||
export * from './reserved.action-handler';
|
||||
export * from './returned-by-buyer.action-handler';
|
||||
export * from './shipping-note.action-handler';
|
||||
export * from './shop-with-kulturpass.action-handler';
|
||||
export * from './supplier-temporarily-out-of-stock.action-handler copy';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { OrderItemListItemDTO, ReceiptDTO } from '@swagger/oms';
|
||||
import { OrderItemListItemDTO, ReceiptDTO, OrderDTO } from '@swagger/oms';
|
||||
|
||||
export interface OrderItemsContext {
|
||||
items: OrderItemListItemDTO[];
|
||||
@@ -12,4 +12,6 @@ export interface OrderItemsContext {
|
||||
receipts?: ReceiptDTO[];
|
||||
|
||||
shippingDelayComment?: string;
|
||||
|
||||
order?: OrderDTO;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { OrderItemsContext } from './order-items.context';
|
||||
import { ActionHandler, CommandService } from '@core/command';
|
||||
import { KulturpassOrderModalService } from '@shared/modals/kulturpass-order-modal';
|
||||
import { DisplayOrderItemSubsetDTO, OrderItemListItemDTO, ReceiptDTO } from '@swagger/oms';
|
||||
import { DomainReceiptService } from '../receipt.service';
|
||||
import { DomainGoodsService } from '../goods.service';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
export class ShopWithKulturpassActionHandler extends ActionHandler<OrderItemsContext> {
|
||||
constructor(
|
||||
private _modal: KulturpassOrderModalService,
|
||||
private _receiptService: DomainReceiptService,
|
||||
private _goodsService: DomainGoodsService
|
||||
) {
|
||||
super('SHOP_WITH_KULTURPASS');
|
||||
}
|
||||
|
||||
async handler(data: OrderItemsContext, service: CommandService): Promise<OrderItemsContext> {
|
||||
const items: OrderItemListItemDTO[] = [];
|
||||
const receipts: ReceiptDTO[] = [];
|
||||
|
||||
let command: string;
|
||||
for (const item of data.items) {
|
||||
const result = await this._modal.open({ orderItemListItem: item, order: data.order }).afterClosed$.toPromise();
|
||||
|
||||
const displayOrder = result.data[0];
|
||||
command = result.data[1];
|
||||
|
||||
if (displayOrder) {
|
||||
const subsetItems = displayOrder.items.reduce((acc, item) => [...acc, ...item.subsetItems], [] as DisplayOrderItemSubsetDTO[]);
|
||||
|
||||
const orderItems = await this.getItems(displayOrder.orderNumber);
|
||||
|
||||
items.push(...orderItems);
|
||||
|
||||
const subsetItemIds = subsetItems.map((item) => item.id);
|
||||
|
||||
const r = await this.getReceipts(subsetItemIds);
|
||||
|
||||
receipts.push(...r);
|
||||
}
|
||||
}
|
||||
|
||||
if (!command) {
|
||||
return {
|
||||
...data,
|
||||
items,
|
||||
receipts,
|
||||
};
|
||||
} else {
|
||||
return service.handleCommand(command, {
|
||||
...data,
|
||||
items,
|
||||
receipts,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getReceipts(ids: number[]) {
|
||||
return this._receiptService
|
||||
.getReceipts({
|
||||
receiptType: 128,
|
||||
eagerLoading: 1,
|
||||
ids,
|
||||
})
|
||||
.pipe(map((res) => res.result.map((data) => data.item3.data).filter((data) => !!data)))
|
||||
.toPromise();
|
||||
}
|
||||
|
||||
getItems(orderNumber: string) {
|
||||
return this._goodsService
|
||||
.getWarenausgabeItemByOrderNumber(orderNumber, false)
|
||||
.pipe(map((res) => res.result))
|
||||
.toPromise();
|
||||
}
|
||||
}
|
||||
@@ -70,5 +70,8 @@
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "AQZyKCc+BEkNL00Y3h3FjawGLF+INUj7cVb0My91hl8ffiW873T8FTV1k4TIZJx5RwcJlYxhgsxHVcnM4AJgSwJhbAfxJmP/3XGijLlLp3XUIRjQwFtf7UlZAFZ7Vrt1/WSf7kxxrFQ2SE2AQwLqPg9DL+hHEfd4xT/15n8p2q7qUlCKLsV6jF12Pd7koFNSWNL3ZIkRtd1ma99/321dnwAJHFGXqWg5nprJ7sYtqUqNQ8Er9SlvKbhnw3AipHzKpz0O3oNfUsr6NlZivRBhMhCZLo5WpXo1m9uIU8zLEWMNDJ+wGUctcGxE3eCptP2zLXUgxxjB+0EXOUtT/GWUc/Ip61CMiyUf7Paz026E2eYil2yWgfkTP5CUgDMNGZFuAA1T5PhB9FRW51CjAIvwOKVMCvfixJiVoUsXHnWH2ZnXqtbDR/uEZBE7OKoBlaPL4G3Lvgdqym5EjROAztUXb6wOmVDiGzzqgizyZnIcxFBSKJAownGj9Vh4/Y/Ag1xzGzNtjz3ngSRfMfIIq/q2Q51uiLiv7mBVliPvPWMUTfTjnqnK/OSBlR2ID+COJqnUKpQMedPyOT3IMznmM6gQCmyYO5KE0MkfhFh6+pdNi6oJM2iZsxK1Z1V+GRSOIwrJEoajjDJkh439XjXk8NExFvplrLjK/oL/dsHIZiG6U5GVWW92kGkuXkJCeUz1CET3paxbGqwrd53r5d6gFABbC12CtcP2JeH4YYCpHYyPQacf0prj9Hdq3wDztShC9tH+4UQS/GbaDHKcS1ANIyPuTxHmBFtPuCJ9Uagy5QBEc8eAz2nfsbfaUxYzco6u/zhNsFbqp6zgQIxs5OcqDQ=="
|
||||
},
|
||||
"kulturpass": {
|
||||
"wertcodes": ["4035511298765", "4035511298697", "4035511298703", "4035511298710", "4035511298727", "4035511298598", "4035511298604", "4035511298611", "4035511298628", "4035511298734", "4035511298741", "4035511298758"]
|
||||
}
|
||||
}
|
||||
@@ -69,5 +69,8 @@
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "AQZyKCc+BEkNL00Y3h3FjawGLF+INUj7cVb0My91hl8ffiW873T8FTV1k4TIZJx5RwcJlYxhgsxHVcnM4AJgSwJhbAfxJmP/3XGijLlLp3XUIRjQwFtf7UlZAFZ7Vrt1/WSf7kxxrFQ2SE2AQwLqPg9DL+hHEfd4xT/15n8p2q7qUlCKLsV6jF12Pd7koFNSWNL3ZIkRtd1ma99/321dnwAJHFGXqWg5nprJ7sYtqUqNQ8Er9SlvKbhnw3AipHzKpz0O3oNfUsr6NlZivRBhMhCZLo5WpXo1m9uIU8zLEWMNDJ+wGUctcGxE3eCptP2zLXUgxxjB+0EXOUtT/GWUc/Ip61CMiyUf7Paz026E2eYil2yWgfkTP5CUgDMNGZFuAA1T5PhB9FRW51CjAIvwOKVMCvfixJiVoUsXHnWH2ZnXqtbDR/uEZBE7OKoBlaPL4G3Lvgdqym5EjROAztUXb6wOmVDiGzzqgizyZnIcxFBSKJAownGj9Vh4/Y/Ag1xzGzNtjz3ngSRfMfIIq/q2Q51uiLiv7mBVliPvPWMUTfTjnqnK/OSBlR2ID+COJqnUKpQMedPyOT3IMznmM6gQCmyYO5KE0MkfhFh6+pdNi6oJM2iZsxK1Z1V+GRSOIwrJEoajjDJkh439XjXk8NExFvplrLjK/oL/dsHIZiG6U5GVWW92kGkuXkJCeUz1CET3paxbGqwrd53r5d6gFABbC12CtcP2JeH4YYCpHYyPQacf0prj9Hdq3wDztShC9tH+4UQS/GbaDHKcS1ANIyPuTxHmBFtPuCJ9Uagy5QBEc8eAz2nfsbfaUxYzco6u/zhNsFbqp6zgQIxs5OcqDQ=="
|
||||
}
|
||||
},
|
||||
"kulturpass": {
|
||||
"wertcodes": ["4035511298765", "4035511298697", "4035511298703", "4035511298710", "4035511298727", "4035511298598", "4035511298604", "4035511298611", "4035511298628", "4035511298734", "4035511298741", "4035511298758"]
|
||||
}
|
||||
}
|
||||
@@ -71,5 +71,8 @@
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "AQZyKCc+BEkNL00Y3h3FjawGLF+INUj7cVb0My91hl8ffiW873T8FTV1k4TIZJx5RwcJlYxhgsxHVcnM4AJgSwJhbAfxJmP/3XGijLlLp3XUIRjQwFtf7UlZAFZ7Vrt1/WSf7kxxrFQ2SE2AQwLqPg9DL+hHEfd4xT/15n8p2q7qUlCKLsV6jF12Pd7koFNSWNL3ZIkRtd1ma99/321dnwAJHFGXqWg5nprJ7sYtqUqNQ8Er9SlvKbhnw3AipHzKpz0O3oNfUsr6NlZivRBhMhCZLo5WpXo1m9uIU8zLEWMNDJ+wGUctcGxE3eCptP2zLXUgxxjB+0EXOUtT/GWUc/Ip61CMiyUf7Paz026E2eYil2yWgfkTP5CUgDMNGZFuAA1T5PhB9FRW51CjAIvwOKVMCvfixJiVoUsXHnWH2ZnXqtbDR/uEZBE7OKoBlaPL4G3Lvgdqym5EjROAztUXb6wOmVDiGzzqgizyZnIcxFBSKJAownGj9Vh4/Y/Ag1xzGzNtjz3ngSRfMfIIq/q2Q51uiLiv7mBVliPvPWMUTfTjnqnK/OSBlR2ID+COJqnUKpQMedPyOT3IMznmM6gQCmyYO5KE0MkfhFh6+pdNi6oJM2iZsxK1Z1V+GRSOIwrJEoajjDJkh439XjXk8NExFvplrLjK/oL/dsHIZiG6U5GVWW92kGkuXkJCeUz1CET3paxbGqwrd53r5d6gFABbC12CtcP2JeH4YYCpHYyPQacf0prj9Hdq3wDztShC9tH+4UQS/GbaDHKcS1ANIyPuTxHmBFtPuCJ9Uagy5QBEc8eAz2nfsbfaUxYzco6u/zhNsFbqp6zgQIxs5OcqDQ=="
|
||||
},
|
||||
"kulturpass": {
|
||||
"wertcodes": ["4035511298765", "4035511298697", "4035511298703", "4035511298710", "4035511298727", "4035511298598", "4035511298604", "4035511298611", "4035511298628", "4035511298734", "4035511298741", "4035511298758"]
|
||||
}
|
||||
}
|
||||
@@ -70,5 +70,8 @@
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "AfHi/mY+RbwJD5nC7SuWn3I14pFUOfSbQ2QG//4aV3zWQjwix30kHqsqraA8ZiipDBql8YlwIyV6VPBMUiAX4s9YHDxHHsWwq2BUB3ImzDEcU1jmMH/5yakGUYpCQ68D0iZ8SG9sS0QBb3iFdCHc1r9DFr1cMTxM7zOvb/AUoIVmieHZXnx9ioUgCvczsLiuX3hwvTW3lhbvJ4uUyqTWK4sWFVwoY4AIWSFrPwwrkV2DksMKT5fMJT3GWgPypvTIGwWvpRfLWwKlc1Z3ckyb84khsnaWD2wr+hdgu/K8YIMmgGszm5KIZ/G05YfDNZtQ4jby+5RZvQwWR8rxM35rJgf73OkMSpuL9jw3T0TTAlvpkGRLzVVuCw9VjlBLqfPNEZ6VsEwFuAla9IYUvFHCsjypg2J6UpxHXrTYmbsSu5Jm8frVfS5znPPTO9D/4rF6ZVv2PxY9PgUgJUvwMa/VMc/nse3RRRf8RGT4rUItfJDFO8pujD76vVEWq/KixQRoMdLgDLyxhsFVftkxqhZhyEfFZzsEy49LSojJ28vpHpBWLeCQBmnZ7JZ4C5yOQiqSQV/assBq2zJN2q+vCDp8qy5j1rED1SX5Ec7JpgpgnU4chLIf5Zn7bP/hNGT3pEYBuXeDXXN8ke1pcc3fc3m0FysDG0o56XVCUqImZ8Ezi8eujZciKDrWbtljhKTj7cnfuJx0sVHF6Bh5i4YfgA/Z+NL+MtH2EVIF67e6hEz6PWYTcoh3ybBaJfxb2FNvGJutNKg04GwMhYq6K2IddBt0fDiBt0SGM0oSBlUP3DKCUmXcf2a6ASbrcqv6Wz1jHt0pY4U8bEpg7qSbW3VDyvdPgyQ="
|
||||
}
|
||||
},
|
||||
"kulturpass": {
|
||||
"wertcodes": ["4035511298765", "4035511298697", "4035511298703", "4035511298710", "4035511298727", "4035511298598", "4035511298604", "4035511298611", "4035511298628", "4035511298734", "4035511298741", "4035511298758"]
|
||||
}
|
||||
}
|
||||
@@ -70,5 +70,8 @@
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "AfHi/mY+RbwJD5nC7SuWn3I14pFUOfSbQ2QG//4aV3zWQjwix30kHqsqraA8ZiipDBql8YlwIyV6VPBMUiAX4s9YHDxHHsWwq2BUB3ImzDEcU1jmMH/5yakGUYpCQ68D0iZ8SG9sS0QBb3iFdCHc1r9DFr1cMTxM7zOvb/AUoIVmieHZXnx9ioUgCvczsLiuX3hwvTW3lhbvJ4uUyqTWK4sWFVwoY4AIWSFrPwwrkV2DksMKT5fMJT3GWgPypvTIGwWvpRfLWwKlc1Z3ckyb84khsnaWD2wr+hdgu/K8YIMmgGszm5KIZ/G05YfDNZtQ4jby+5RZvQwWR8rxM35rJgf73OkMSpuL9jw3T0TTAlvpkGRLzVVuCw9VjlBLqfPNEZ6VsEwFuAla9IYUvFHCsjypg2J6UpxHXrTYmbsSu5Jm8frVfS5znPPTO9D/4rF6ZVv2PxY9PgUgJUvwMa/VMc/nse3RRRf8RGT4rUItfJDFO8pujD76vVEWq/KixQRoMdLgDLyxhsFVftkxqhZhyEfFZzsEy49LSojJ28vpHpBWLeCQBmnZ7JZ4C5yOQiqSQV/assBq2zJN2q+vCDp8qy5j1rED1SX5Ec7JpgpgnU4chLIf5Zn7bP/hNGT3pEYBuXeDXXN8ke1pcc3fc3m0FysDG0o56XVCUqImZ8Ezi8eujZciKDrWbtljhKTj7cnfuJx0sVHF6Bh5i4YfgA/Z+NL+MtH2EVIF67e6hEz6PWYTcoh3ybBaJfxb2FNvGJutNKg04GwMhYq6K2IddBt0fDiBt0SGM0oSBlUP3DKCUmXcf2a6ASbrcqv6Wz1jHt0pY4U8bEpg7qSbW3VDyvdPgyQ="
|
||||
}
|
||||
},
|
||||
"kulturpass": {
|
||||
"wertcodes": ["4035511298765", "4035511298697", "4035511298703", "4035511298710", "4035511298727", "4035511298598", "4035511298604", "4035511298611", "4035511298628", "4035511298734", "4035511298741", "4035511298758"]
|
||||
}
|
||||
}
|
||||
@@ -71,5 +71,8 @@
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "AQZyKCc+BEkNL00Y3h3FjawGLF+INUj7cVb0My91hl8ffiW873T8FTV1k4TIZJx5RwcJlYxhgsxHVcnM4AJgSwJhbAfxJmP/3XGijLlLp3XUIRjQwFtf7UlZAFZ7Vrt1/WSf7kxxrFQ2SE2AQwLqPg9DL+hHEfd4xT/15n8p2q7qUlCKLsV6jF12Pd7koFNSWNL3ZIkRtd1ma99/321dnwAJHFGXqWg5nprJ7sYtqUqNQ8Er9SlvKbhnw3AipHzKpz0O3oNfUsr6NlZivRBhMhCZLo5WpXo1m9uIU8zLEWMNDJ+wGUctcGxE3eCptP2zLXUgxxjB+0EXOUtT/GWUc/Ip61CMiyUf7Paz026E2eYil2yWgfkTP5CUgDMNGZFuAA1T5PhB9FRW51CjAIvwOKVMCvfixJiVoUsXHnWH2ZnXqtbDR/uEZBE7OKoBlaPL4G3Lvgdqym5EjROAztUXb6wOmVDiGzzqgizyZnIcxFBSKJAownGj9Vh4/Y/Ag1xzGzNtjz3ngSRfMfIIq/q2Q51uiLiv7mBVliPvPWMUTfTjnqnK/OSBlR2ID+COJqnUKpQMedPyOT3IMznmM6gQCmyYO5KE0MkfhFh6+pdNi6oJM2iZsxK1Z1V+GRSOIwrJEoajjDJkh439XjXk8NExFvplrLjK/oL/dsHIZiG6U5GVWW92kGkuXkJCeUz1CET3paxbGqwrd53r5d6gFABbC12CtcP2JeH4YYCpHYyPQacf0prj9Hdq3wDztShC9tH+4UQS/GbaDHKcS1ANIyPuTxHmBFtPuCJ9Uagy5QBEc8eAz2nfsbfaUxYzco6u/zhNsFbqp6zgQIxs5OcqDQ=="
|
||||
},
|
||||
"kulturpass": {
|
||||
"wertcodes": ["4035511298765", "4035511298697", "4035511298703", "4035511298710", "4035511298727", "4035511298598", "4035511298604", "4035511298611", "4035511298628", "4035511298734", "4035511298741", "4035511298758"]
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,7 @@ import {
|
||||
PrintPriceDiffQrCodeLabelActionHandler,
|
||||
CollectWithSmallAmountinvoiceActionHandler,
|
||||
PrintSmallamountinvoiceActionHandler,
|
||||
ShopWithKulturpassActionHandler,
|
||||
} from '@domain/oms';
|
||||
import { CoreCommandModule } from '@core/command';
|
||||
import { CustomerOrderRoutingModule } from './customer-order-routing.module';
|
||||
@@ -93,6 +94,7 @@ import { BreadcrumbModule } from '@shared/components/breadcrumb';
|
||||
PrintPriceDiffQrCodeLabelActionHandler,
|
||||
CollectWithSmallAmountinvoiceActionHandler,
|
||||
PrintSmallamountinvoiceActionHandler,
|
||||
ShopWithKulturpassActionHandler,
|
||||
]),
|
||||
],
|
||||
exports: [CustomerOrderComponent],
|
||||
|
||||
@@ -43,6 +43,7 @@ import {
|
||||
PrintPriceDiffQrCodeLabelActionHandler,
|
||||
CollectWithSmallAmountinvoiceActionHandler,
|
||||
PrintSmallamountinvoiceActionHandler,
|
||||
ShopWithKulturpassActionHandler,
|
||||
} from '@domain/oms';
|
||||
@NgModule({
|
||||
declarations: [GoodsInComponent],
|
||||
@@ -89,6 +90,7 @@ import {
|
||||
PrintPriceDiffQrCodeLabelActionHandler,
|
||||
CollectWithSmallAmountinvoiceActionHandler,
|
||||
PrintSmallamountinvoiceActionHandler,
|
||||
ShopWithKulturpassActionHandler,
|
||||
]),
|
||||
],
|
||||
exports: [GoodsInComponent],
|
||||
|
||||
@@ -41,6 +41,7 @@ import {
|
||||
PrintPriceDiffQrCodeLabelActionHandler,
|
||||
CollectWithSmallAmountinvoiceActionHandler,
|
||||
PrintSmallamountinvoiceActionHandler,
|
||||
ShopWithKulturpassActionHandler,
|
||||
} from '@domain/oms';
|
||||
import { CoreCommandModule } from '@core/command';
|
||||
import { ShellBreadcrumbModule } from '@shell/breadcrumb';
|
||||
@@ -91,6 +92,7 @@ import { GoodsInRoutingModule } from './good-out-routing.module';
|
||||
PrintPriceDiffQrCodeLabelActionHandler,
|
||||
CollectWithSmallAmountinvoiceActionHandler,
|
||||
PrintSmallamountinvoiceActionHandler,
|
||||
ShopWithKulturpassActionHandler,
|
||||
]),
|
||||
],
|
||||
exports: [GoodsOutComponent],
|
||||
|
||||
@@ -288,7 +288,7 @@
|
||||
<button
|
||||
[uiOverlayTrigger]="preferredPickUpDatePicker"
|
||||
#preferredPickUpDatePickerTrigger="uiOverlayTrigger"
|
||||
[disabled]="(!isKulturpass && !!orderItem?.features?.paid) || (changeDateDisabled$ | async)"
|
||||
[disabled]="preferredPickUpDateDisabled$ | async"
|
||||
class="cta-pickup-preferred"
|
||||
>
|
||||
<strong *ngIf="preferredPickUpDate$ | async; let pickUpDate; else: selectTemplate">
|
||||
@@ -319,7 +319,7 @@
|
||||
<div *ngIf="!(changeDateLoader$ | async)" class="value">
|
||||
<button
|
||||
class="cta-datepicker"
|
||||
[disabled]="changeDateDisabled$ | async"
|
||||
[disabled]="vslLieferdatumDisabled$ | async"
|
||||
[uiOverlayTrigger]="uiDatepicker"
|
||||
#datepicker="uiOverlayTrigger"
|
||||
>
|
||||
|
||||
@@ -18,6 +18,8 @@ import { cloneDeep } from 'lodash';
|
||||
import { BehaviorSubject, combineLatest } from 'rxjs';
|
||||
import { filter, first, map, shareReplay, switchMap } from 'rxjs/operators';
|
||||
import { SharedGoodsInOutOrderDetailsComponent } from '../goods-in-out-order-details.component';
|
||||
import { Config } from '@core/config';
|
||||
import { coerceArray } from '@angular/cdk/coercion';
|
||||
|
||||
@Component({
|
||||
selector: 'shared-goods-in-out-order-details-header',
|
||||
@@ -100,12 +102,41 @@ export class SharedGoodsInOutOrderDetailsHeaderComponent implements OnChanges {
|
||||
return !!this.order?.features && !!this.order?.features?.orderType;
|
||||
}
|
||||
|
||||
get kulturpassWertcodes() {
|
||||
return coerceArray(this.config.get('kulturpass.wertcodes'));
|
||||
}
|
||||
|
||||
preferredPickUpDateDisabled$ = combineLatest([this.changeDateDisabled$, this.orderItem$]).pipe(
|
||||
map(([changeDateDisabled, orderItem]) => {
|
||||
if (changeDateDisabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.kulturpassWertcodes.includes(orderItem?.product?.ean)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !this.isKulturpass && !!orderItem?.features?.paid;
|
||||
})
|
||||
);
|
||||
|
||||
vslLieferdatumDisabled$ = combineLatest([this.changeDateDisabled$, this.orderItem$]).pipe(
|
||||
map(([changeDateDisabled, orderItem]) => {
|
||||
if (changeDateDisabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.kulturpassWertcodes.includes(orderItem?.product?.ean);
|
||||
})
|
||||
);
|
||||
|
||||
constructor(
|
||||
@Host() private host: SharedGoodsInOutOrderDetailsComponent,
|
||||
private customerService: CrmCustomerService,
|
||||
private dateAdapter: DateAdapter,
|
||||
private omsService: DomainOmsService,
|
||||
private cdr: ChangeDetectorRef
|
||||
private cdr: ChangeDetectorRef,
|
||||
private config: Config
|
||||
) {}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { SharedGoodsInOutOrderDetailsCoversComponent } from './goods-in-out-orde
|
||||
import { SharedGoodsInOutOrderDetailsItemComponent } from './goods-in-out-order-details-item';
|
||||
import { SharedGoodsInOutOrderDetailsTagsComponent } from './goods-in-out-order-details-tags';
|
||||
import { SharedGoodsInOutOrderDetailsStore } from './goods-in-out-order-details.store';
|
||||
import { SharedGoodsInOutOrderDetailsHeaderComponent } from './goods-in-out-order-details-header';
|
||||
|
||||
@Component({
|
||||
selector: 'shared-goods-in-out-order-details',
|
||||
@@ -26,6 +27,9 @@ import { SharedGoodsInOutOrderDetailsStore } from './goods-in-out-order-details.
|
||||
],
|
||||
})
|
||||
export class SharedGoodsInOutOrderDetailsComponent extends SharedGoodsInOutOrderDetailsStore implements AfterContentInit, OnDestroy {
|
||||
@ContentChild(SharedGoodsInOutOrderDetailsHeaderComponent)
|
||||
orderDetailsHeaderComponent: SharedGoodsInOutOrderDetailsHeaderComponent;
|
||||
|
||||
@ContentChildren(SharedGoodsInOutOrderDetailsItemComponent)
|
||||
orderDetailsItemComponents: QueryList<SharedGoodsInOutOrderDetailsItemComponent>;
|
||||
|
||||
@@ -205,6 +209,7 @@ export class SharedGoodsInOutOrderDetailsComponent extends SharedGoodsInOutOrder
|
||||
action.command.includes('PRINT_PRICEDIFFQRCODELABEL') && !compartmentCode ? this.orderItems[0]?.compartmentCode : compartmentCode,
|
||||
itemQuantity: this.getItemQuantityMap(),
|
||||
receipts,
|
||||
order: this.orderDetailsHeaderComponent?.order,
|
||||
};
|
||||
try {
|
||||
commandData = await this.commandService.handleCommand(command, commandData);
|
||||
|
||||
6
apps/shared/components/loader/ng-package.json
Normal file
6
apps/shared/components/loader/ng-package.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "../../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
11
apps/shared/components/loader/src/lib/loader.component.css
Normal file
11
apps/shared/components/loader/src/lib/loader.component.css
Normal file
@@ -0,0 +1,11 @@
|
||||
.shared-loader {
|
||||
@apply relative block h-full;
|
||||
}
|
||||
|
||||
.shared-loader__spinner {
|
||||
@apply absolute inset-0 flex items-center justify-center;
|
||||
}
|
||||
|
||||
.shared-loader__background {
|
||||
@apply bg-white bg-opacity-75;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<div class="shared-loader__spinner" *ngIf="showLoader" [class.shared-loader__background]="showBackground">
|
||||
<ui-icon class="animate-spin" icon="spinner" [size]="spinnerSizeInRem"></ui-icon>
|
||||
</div>
|
||||
<div [class.invisible]="showLoader && contentHidden">
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
43
apps/shared/components/loader/src/lib/loader.component.ts
Normal file
43
apps/shared/components/loader/src/lib/loader.component.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { BooleanInput, NumberInput, coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
|
||||
import { NgIf } from '@angular/common';
|
||||
import { Component, ChangeDetectionStrategy, ViewEncapsulation, Input } from '@angular/core';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
|
||||
@Component({
|
||||
selector: 'shared-loader',
|
||||
templateUrl: 'loader.component.html',
|
||||
styleUrls: ['loader.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: { class: 'shared-loader' },
|
||||
standalone: true,
|
||||
imports: [NgIf, UiIconModule],
|
||||
})
|
||||
export class LoaderComponent {
|
||||
@Input() loading: BooleanInput;
|
||||
|
||||
@Input() background: BooleanInput;
|
||||
|
||||
@Input() spinnerSize: NumberInput = 24;
|
||||
|
||||
@Input() hideContent: BooleanInput;
|
||||
|
||||
get showLoader() {
|
||||
console.log('showLoader', this.loading);
|
||||
return coerceBooleanProperty(this.loading);
|
||||
}
|
||||
|
||||
get showBackground() {
|
||||
return coerceBooleanProperty(this.background);
|
||||
}
|
||||
|
||||
get spinnerSizeInRem() {
|
||||
return coerceNumberProperty(this.spinnerSize) / 16 + 'rem';
|
||||
}
|
||||
|
||||
get contentHidden() {
|
||||
return coerceBooleanProperty(this.hideContent);
|
||||
}
|
||||
|
||||
constructor() {}
|
||||
}
|
||||
9
apps/shared/components/loader/src/lib/loader.module.ts
Normal file
9
apps/shared/components/loader/src/lib/loader.module.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { LoaderComponent } from './loader.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [LoaderComponent],
|
||||
exports: [LoaderComponent],
|
||||
})
|
||||
export class LoaderModule {}
|
||||
2
apps/shared/components/loader/src/public-api.ts
Normal file
2
apps/shared/components/loader/src/public-api.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './lib/loader.component';
|
||||
export * from './lib/loader.module';
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "../../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
:host {
|
||||
@apply grid px-4 py-2 gap-4;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<div class="img-wrapper">
|
||||
<img class="rounded shadow w-20" [src]="item?.product?.ean | productImage" [alt]="item?.product?.name" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-sm">{{ item?.product?.contributors }}</div>
|
||||
<div class="font-bold">{{ item?.product?.name }}</div>
|
||||
<div class="font-bold mt-4 flex flex-row items-center">
|
||||
<img class="h-5 mr-2" [src]="iconSrc" [alt]="item?.product?.formatDetail" />
|
||||
<span>{{ item?.product?.formatDetail }}</span>
|
||||
</div>
|
||||
<div class="text-sm">{{ item?.product?.manufacturer }} | {{ item?.product?.ean }}</div>
|
||||
<div class="text-sm">{{ item?.product?.volume }} | {{ item?.product?.publicationDate | date }}</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="font-bold text-xl mt-4">{{ item?.unitPrice?.value?.value | currency: 'EUR' }}</div>
|
||||
<div class="font-bold">
|
||||
<ui-quantity-dropdown
|
||||
[quantity]="itemQuantity$ | async"
|
||||
[minQuantity]="availableQuantity$ | async"
|
||||
(quantityChange)="onQuantityChange($event)"
|
||||
></ui-quantity-dropdown>
|
||||
</div>
|
||||
<div *ngIf="maxQuantityHint" class="text-warning font-bold text-sm">
|
||||
Es sind maximal <br />
|
||||
{{ availableQuantity$ | async }} Exemplare verfügbar
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,62 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, ChangeDetectionStrategy, Output, Input, EventEmitter } from '@angular/core';
|
||||
import { ProductImageModule } from '@cdn/product-image';
|
||||
import { provideComponentStore } from '@ngrx/component-store';
|
||||
import { ShoppingCartItemDTO } from '@swagger/checkout';
|
||||
import { UiQuantityDropdownModule } from '@ui/quantity-dropdown';
|
||||
import { KulturpassOrderItemStore } from './kulturpass-order-item.store';
|
||||
|
||||
@Component({
|
||||
selector: 'shared-kulturpass-order-item',
|
||||
templateUrl: 'kulturpass-order-item.component.html',
|
||||
styleUrls: ['kulturpass-order-item.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: { class: 'shared-kulturpass-order-item' },
|
||||
standalone: true,
|
||||
imports: [ProductImageModule, CommonModule, UiQuantityDropdownModule],
|
||||
providers: [provideComponentStore(KulturpassOrderItemStore)],
|
||||
})
|
||||
export class KulturpassOrderItemComponent {
|
||||
@Input()
|
||||
set item(item: ShoppingCartItemDTO) {
|
||||
this._store.updateItem(item);
|
||||
this._store.fetchAvailability(item);
|
||||
}
|
||||
get item() {
|
||||
return this._store.item;
|
||||
}
|
||||
|
||||
@Output() quantityChange = new EventEmitter<ShoppingCartItemDTO>();
|
||||
|
||||
itemQuantity$ = this._store.itemQuantity$;
|
||||
|
||||
get iconSrc() {
|
||||
return `/assets/images/Icon_${this.item?.product?.format}.svg`;
|
||||
}
|
||||
|
||||
availableQuantity$ = this._store.availableQuantity$;
|
||||
|
||||
maxQuantityHint = false;
|
||||
|
||||
constructor(private _store: KulturpassOrderItemStore) {}
|
||||
|
||||
onQuantityChange(quantity: number) {
|
||||
const initialQuantity = this.item.quantity;
|
||||
this._store.updateItem({ ...this.item, quantity });
|
||||
|
||||
if (this._store.availableQuantity < quantity) {
|
||||
quantity = this._store.availableQuantity;
|
||||
this.maxQuantityHint = true;
|
||||
} else {
|
||||
this.maxQuantityHint = false;
|
||||
}
|
||||
|
||||
if (initialQuantity !== quantity) {
|
||||
this.quantityChange.emit({ ...this.item, quantity });
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this._store.updateItem({ ...this.item, quantity });
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { ComponentStore, tapResponse } from '@ngrx/component-store';
|
||||
import { ShoppingCartItemDTO, AvailabilityDTO } from '@swagger/checkout';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { Observable } from 'rxjs';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
export interface KulturpassOrderItemState {
|
||||
item: ShoppingCartItemDTO;
|
||||
availability?: AvailabilityDTO;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class KulturpassOrderItemStore extends ComponentStore<KulturpassOrderItemState> {
|
||||
get item() {
|
||||
return this.get((s) => s.item);
|
||||
}
|
||||
|
||||
get availability() {
|
||||
return this.get((s) => s.availability);
|
||||
}
|
||||
|
||||
get availableQuantity() {
|
||||
return this.get((s) => s.availability?.inStock ?? s.item?.quantity ?? 0);
|
||||
}
|
||||
|
||||
constructor(private _availabilityService: DomainAvailabilityService) {
|
||||
super({ item: null });
|
||||
}
|
||||
|
||||
readonly item$ = this.select((state) => state.item);
|
||||
|
||||
readonly updateItem = this.updater((state, item: ShoppingCartItemDTO) => ({ ...state, item }));
|
||||
|
||||
readonly itemQuantity$ = this.select((state) => state.item?.quantity ?? 0);
|
||||
|
||||
readonly availability$ = this.select((state) => state.availability);
|
||||
|
||||
readonly updateAvailability = this.updater((state, availability: AvailabilityDTO) => ({ ...state, availability }));
|
||||
|
||||
readonly availableQuantity$ = this.select((state) => state.availability?.inStock ?? state.item?.quantity ?? 0);
|
||||
|
||||
fetchAvailability = this.effect((item$: Observable<ShoppingCartItemDTO>) =>
|
||||
item$.pipe(
|
||||
switchMap((item) =>
|
||||
this._availabilityService
|
||||
.getTakeAwayAvailability({
|
||||
item: {
|
||||
ean: item.product.ean,
|
||||
itemId: Number(item.product.catalogProductNumber),
|
||||
price: item.unitPrice,
|
||||
},
|
||||
quantity: item.quantity,
|
||||
})
|
||||
.pipe(tapResponse(this.handleAvailabilityResponse, this.handleAvailabilityError))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
handleAvailabilityResponse = (res: AvailabilityDTO) => {
|
||||
this.updateAvailability(res);
|
||||
};
|
||||
|
||||
handleAvailabilityError = (err) => {
|
||||
console.log(err);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
:host {
|
||||
@apply block;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
@apply grid max-h-[calc(100vh-8rem)] h-[calc(100vh-8rem)];
|
||||
grid-template-rows: repeat(4, auto) 1fr auto;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<shared-loader [loading]="fetchShoppingCart$ | async" background="true" spinnerSize="36">
|
||||
<div class="wrapper">
|
||||
<div>
|
||||
<h1 class="text-center text-2xl font-bold">Kulturpass Warenkorb</h1>
|
||||
<p class="text-center text-lg">Bitte scannen Sie Artikel, um den Code einzulösen.</p>
|
||||
</div>
|
||||
<div>
|
||||
<shared-kulturpass-order-searchbox (addToShoppingCart)="addToShoppingCart($event)"></shared-kulturpass-order-searchbox>
|
||||
</div>
|
||||
<div class="border-y border-solid border-[#EFF1F5] py-3 px-4 -mx-4 flex flex-row items-center">
|
||||
<div class="w-[6.875rem]">
|
||||
Wertgutschein
|
||||
</div>
|
||||
<div class="ml-4 font-bold">
|
||||
{{ kulturpassCode$ | async }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-b border-solid border-[#EFF1F5] py-3 px-4 -mx-4 flex flex-row items-center">
|
||||
<div class="w-[6.875rem]">
|
||||
Filiale
|
||||
</div>
|
||||
<div class="ml-4 font-bold">
|
||||
{{ branch$ | async | branchName: 'name-address' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-y-auto -mx-4 scroll-bar">
|
||||
<div *ngIf="emptyShoppingCart$ | async" class="h-full grid items-center justify-center">
|
||||
<h3 class="text-xl font-bold text-center text-gray-500">
|
||||
Warenkorb ist leer, bitte suchen oder scannen <br />
|
||||
Sie Artikel um den Warenkob zu füllen.
|
||||
</h3>
|
||||
</div>
|
||||
<shared-kulturpass-order-item
|
||||
class="border-b border-solid border-[#EFF1F5]"
|
||||
*ngFor="let item of items$ | async; trackBy: trackItemById"
|
||||
[item]="item"
|
||||
(quantityChange)="quantityChange($event)"
|
||||
>
|
||||
</shared-kulturpass-order-item>
|
||||
</div>
|
||||
<div class="flex flex-row justify-evenly items-stretch border-t border-solid border-[#EFF1F5] py-3 px-4 -mx-4">
|
||||
<div class="grid grid-flow-row text-sm">
|
||||
<div class="grid grid-cols-2 gap-5">
|
||||
<div>Guthaben</div>
|
||||
<div class="font-bold text-right">{{ credit$ | async | currency: 'EUR' }}</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-5">
|
||||
<div>Summe</div>
|
||||
<div class="font-bold text-right">{{ total$ | async | currency: 'EUR' }}</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-5">
|
||||
<div>Restbetrag</div>
|
||||
<div class="font-bold text-right" [class.text-brand]="negativeBalance$ | async">{{ balance$ | async | currency: 'EUR' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid items-end justify-end">
|
||||
<button
|
||||
type="button"
|
||||
class="bg-brand text-white px-6 py-3 font-bold rounded-full disabled:bg-disabled-branch disabled:text-active-branch"
|
||||
[disabled]="orderButtonDisabled$ | async"
|
||||
(click)="order()"
|
||||
>
|
||||
<shared-loader [loading]="ordering$ | async" hideContent="true">
|
||||
Kauf abschließen und Rechnung drucken
|
||||
</shared-loader>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</shared-loader>
|
||||
@@ -0,0 +1,78 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core';
|
||||
import { KulturpassOrderSearchboxComponent } from './kulturpass-order-searchbox/kulturpass-order-searchbox.component';
|
||||
import { provideComponentStore } from '@ngrx/component-store';
|
||||
import { KulturpassOrderModalStore } from './kulturpass-order-modal.store';
|
||||
import { UiModalRef } from '@ui/modal';
|
||||
import { KulturpassOrderModalData } from './kulturpass-order-modal.data';
|
||||
import { AddToShoppingCartDTO, ShoppingCartItemDTO } from '@swagger/checkout';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { BranchNamePipe } from '@shared/pipes/branch';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { KulturpassOrderItemComponent } from './kulturpass-order-item/kulturpass-order-item.component';
|
||||
import { LoaderComponent } from '@shared/components/loader';
|
||||
import { DisplayOrderDTO, KeyValueDTOOfStringAndString } from '@swagger/oms';
|
||||
@Component({
|
||||
selector: 'shared-kulturpass-order-modal',
|
||||
templateUrl: 'kulturpass-order-modal.component.html',
|
||||
styleUrls: ['kulturpass-order-modal.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: { class: 'shared-kulturpass-order-modal' },
|
||||
standalone: true,
|
||||
imports: [KulturpassOrderSearchboxComponent, CommonModule, BranchNamePipe, KulturpassOrderItemComponent, LoaderComponent],
|
||||
providers: [provideComponentStore(KulturpassOrderModalStore)],
|
||||
})
|
||||
export class KulturpassOrderModalComponent implements OnInit {
|
||||
branch$ = this._store.branch$;
|
||||
|
||||
fetchShoppingCart$ = this._store.fetchShoppingCart$;
|
||||
|
||||
items$ = this._store.shoppingCart$.pipe(map((shoppingCart) => shoppingCart?.items?.map((item) => item.data) ?? []));
|
||||
|
||||
trackItemById = (index: number, item: ShoppingCartItemDTO) => item.id;
|
||||
|
||||
kulturpassCode$ = this._store.orderItemListItem$.pipe(map((orderItemListItem) => orderItemListItem.buyerNumber));
|
||||
|
||||
credit$ = this._store.orderItemListItem$.pipe(map((orderItemListItem) => orderItemListItem?.retailPrice?.value?.value ?? 0));
|
||||
|
||||
total$ = this._store.shoppingCart$.pipe(map((shoppingCart) => shoppingCart?.total?.value ?? 0));
|
||||
|
||||
balance$ = combineLatest([this.credit$, this.total$]).pipe(map(([credit, total]) => credit - total));
|
||||
|
||||
negativeBalance$ = this.balance$.pipe(map((balance) => balance < 0));
|
||||
|
||||
emptyShoppingCart$ = this.items$.pipe(map((items) => items.length === 0));
|
||||
|
||||
ordering$ = this._store.ordering$;
|
||||
|
||||
orderButtonDisabled$ = combineLatest([this.emptyShoppingCart$, this.negativeBalance$, this.ordering$]).pipe(
|
||||
map(([emptyShoppingCart, negativeBalance, ordering]) => emptyShoppingCart || negativeBalance || ordering)
|
||||
);
|
||||
|
||||
constructor(
|
||||
private _modalRef: UiModalRef<[DisplayOrderDTO, string], KulturpassOrderModalData>,
|
||||
private _store: KulturpassOrderModalStore
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this._store.updateOrder(this._modalRef.data.order);
|
||||
this._store.createShoppingCart(this._modalRef.data.orderItemListItem);
|
||||
}
|
||||
|
||||
addToShoppingCart(addToShoppingCart: AddToShoppingCartDTO) {
|
||||
this._store.addItem(addToShoppingCart);
|
||||
}
|
||||
|
||||
quantityChange(shoppingCartItem: ShoppingCartItemDTO) {
|
||||
this._store.quantityChange(shoppingCartItem);
|
||||
}
|
||||
|
||||
order() {
|
||||
this._store.onOrderSuccess = async (displayOrder: DisplayOrderDTO, action: KeyValueDTOOfStringAndString[]) => {
|
||||
const command = action.map((action) => action.command).join('|');
|
||||
|
||||
this._modalRef.close([displayOrder, command]);
|
||||
};
|
||||
this._store.orderItems();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { OrderItemListItemDTO, OrderDTO } from '@swagger/oms';
|
||||
|
||||
export interface KulturpassOrderModalData {
|
||||
/**
|
||||
* Guthaben des Kulturpasses
|
||||
*/
|
||||
orderItemListItem: OrderItemListItemDTO;
|
||||
|
||||
order: OrderDTO;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { KulturpassOrderModalComponent } from './kulturpass-order-modal.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [KulturpassOrderModalComponent],
|
||||
exports: [KulturpassOrderModalComponent],
|
||||
})
|
||||
export class KulturpassOrderModalModule {}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { UiModalRef, UiModalService } from '@ui/modal';
|
||||
import { KulturpassOrderModalData } from './kulturpass-order-modal.data';
|
||||
import { KulturpassOrderModalComponent } from './kulturpass-order-modal.component';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DisplayOrderDTO } from '@swagger/oms';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class KulturpassOrderModalService {
|
||||
constructor(private modal: UiModalService) {}
|
||||
|
||||
open(data: KulturpassOrderModalData): UiModalRef<[DisplayOrderDTO, string], KulturpassOrderModalData> {
|
||||
return this.modal.open<[DisplayOrderDTO, string], KulturpassOrderModalData>({
|
||||
content: KulturpassOrderModalComponent,
|
||||
data,
|
||||
config: {
|
||||
backdropClose: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ComponentStore, OnStoreInit, tapResponse } from '@ngrx/component-store';
|
||||
import { AddToShoppingCartDTO, BranchDTO, CheckoutDTO, ShoppingCartDTO, ShoppingCartItemDTO } from '@swagger/checkout';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { switchMap, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import {
|
||||
BranchService,
|
||||
DisplayOrderDTO,
|
||||
KeyValueDTOOfStringAndString,
|
||||
OrderDTO,
|
||||
OrderItemListItemDTO,
|
||||
ResponseArgsOfIEnumerableOfBranchDTO,
|
||||
ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString,
|
||||
} from '@swagger/oms';
|
||||
import { Observable } from 'rxjs';
|
||||
import { AuthService } from '@core/auth';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
|
||||
export interface KulturpassOrderModalState {
|
||||
orderItemListItem?: OrderItemListItemDTO;
|
||||
shoppingCart?: ShoppingCartDTO;
|
||||
fetchShoppingCart?: boolean;
|
||||
branch?: BranchDTO;
|
||||
order?: OrderDTO;
|
||||
ordering?: boolean;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class KulturpassOrderModalStore extends ComponentStore<KulturpassOrderModalState> implements OnStoreInit {
|
||||
readonly processId = Date.now();
|
||||
|
||||
get orderItemListItem() {
|
||||
return this.get((s) => s.orderItemListItem);
|
||||
}
|
||||
|
||||
get shoppingCart() {
|
||||
return this.get((s) => s.shoppingCart);
|
||||
}
|
||||
|
||||
get branch() {
|
||||
return this.get((s) => s.branch);
|
||||
}
|
||||
|
||||
get order() {
|
||||
return this.get((s) => s.order);
|
||||
}
|
||||
|
||||
get fetchShoppingCart() {
|
||||
return this.get((s) => s.fetchShoppingCart);
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _checkoutService: DomainCheckoutService,
|
||||
private _branchService: BranchService,
|
||||
private _authService: AuthService,
|
||||
private _modal: UiModalService
|
||||
) {
|
||||
super({});
|
||||
}
|
||||
|
||||
ngrxOnStoreInit = () => {
|
||||
this.loadBranch();
|
||||
};
|
||||
|
||||
readonly orderItemListItem$ = this.select((state) => state.orderItemListItem);
|
||||
|
||||
readonly shoppingCart$ = this.select((state) => state.shoppingCart);
|
||||
|
||||
readonly branch$ = this.select((state) => state.branch);
|
||||
|
||||
readonly order$ = this.select((state) => state.order);
|
||||
|
||||
readonly updateCheckout = this.updater((state, checkout: CheckoutDTO) => ({ ...state, checkout }));
|
||||
|
||||
readonly updateOrder = this.updater((state, order: OrderDTO) => ({ ...state, order }));
|
||||
|
||||
readonly fetchShoppingCart$ = this.select((state) => state.fetchShoppingCart);
|
||||
|
||||
readonly updateFetchShoppingCart = this.updater((state, fetchShoppingCart: boolean) => ({ ...state, fetchShoppingCart }));
|
||||
|
||||
readonly ordering$ = this.select((state) => state.ordering);
|
||||
|
||||
loadBranch = this.effect(($) =>
|
||||
$.pipe(switchMap(() => this._branchService.BranchGetBranches({}).pipe(tapResponse(this.handleBranchResponse, this.handleBranchError))))
|
||||
);
|
||||
|
||||
handleBranchResponse = (res: ResponseArgsOfIEnumerableOfBranchDTO) => {
|
||||
const branchNumber = this._authService.getClaimByKey('branch_no');
|
||||
|
||||
this.patchState({ branch: res.result.find((b) => b.branchNumber === branchNumber) });
|
||||
};
|
||||
|
||||
handleBranchError = (err) => {
|
||||
this._modal.error('Fehler beim Laden der Filiale', err);
|
||||
};
|
||||
|
||||
createShoppingCart = this.effect((orderItemListItem$: Observable<OrderItemListItemDTO>) =>
|
||||
orderItemListItem$.pipe(
|
||||
tap((orderItemListItem) => {
|
||||
this.patchState({ orderItemListItem });
|
||||
this.updateFetchShoppingCart(true);
|
||||
}),
|
||||
switchMap((orderItemListItem) =>
|
||||
this._checkoutService
|
||||
.getShoppingCart({ processId: this.processId })
|
||||
.pipe(tapResponse(this.handleCreateShoppingCartResponse, this.handleCreateShoppingCartError))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
handleCreateShoppingCartResponse = (res: ShoppingCartDTO) => {
|
||||
this.patchState({ shoppingCart: res });
|
||||
this._checkoutService.setBuyer({ processId: this.processId, buyer: this.order.buyer });
|
||||
this._checkoutService.setPayer({ processId: this.processId, payer: this.order.billing?.data });
|
||||
|
||||
this.updateFetchShoppingCart(false);
|
||||
};
|
||||
|
||||
handleCreateShoppingCartError = (err: any) => {
|
||||
this._modal.error('Fehler beim Laden des Warenkorbs', err);
|
||||
|
||||
this.updateFetchShoppingCart(false);
|
||||
};
|
||||
|
||||
addItem = this.effect((add$: Observable<AddToShoppingCartDTO>) =>
|
||||
add$.pipe(
|
||||
withLatestFrom(this.orderItemListItem$),
|
||||
switchMap(([add, orderItemListItem]) =>
|
||||
this._checkoutService
|
||||
.addItemToShoppingCart({
|
||||
processId: this.processId,
|
||||
items: [add],
|
||||
})
|
||||
.pipe(tapResponse(this.handleAddItemResponse, this.handleAddItemError))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
handleAddItemResponse = (res: ShoppingCartDTO) => {};
|
||||
|
||||
handleAddItemError = (err: any) => {
|
||||
this._modal.error('Fehler beim Hinzufügen des Artikels', err);
|
||||
};
|
||||
|
||||
quantityChange = this.effect((change$: Observable<ShoppingCartItemDTO>) =>
|
||||
change$.pipe(
|
||||
withLatestFrom(this.orderItemListItem$),
|
||||
switchMap(([change, orderItemListItem]) =>
|
||||
this._checkoutService
|
||||
.updateItemInShoppingCart({
|
||||
processId: this.processId,
|
||||
shoppingCartItemId: change.id,
|
||||
update: { quantity: change.quantity },
|
||||
})
|
||||
.pipe(tapResponse(this.handleQuantityChangeResponse, this.handleQuantityChangeError))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
handleQuantityChangeResponse = (res: ShoppingCartDTO) => {};
|
||||
|
||||
handleQuantityChangeError = (err: any) => {
|
||||
this._modal.error('Fehler beim Ändern der Menge', err);
|
||||
};
|
||||
|
||||
orderItems = this.effect(($: Observable<void>) =>
|
||||
$.pipe(
|
||||
tap(() => this.patchState({ ordering: true })),
|
||||
withLatestFrom(this.orderItemListItem$),
|
||||
switchMap(([_, orderItemListItem]) =>
|
||||
this._checkoutService
|
||||
.completeKulturpassOrder({
|
||||
processId: this.processId,
|
||||
orderItemSubsetId: orderItemListItem.orderItemSubsetId,
|
||||
})
|
||||
.pipe(tapResponse(this.handleOrderResponse, this.handleOrderError))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
handleOrderResponse = (res: ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString) => {
|
||||
this.onOrderSuccess(res.result.item1[0], res.result.item2);
|
||||
};
|
||||
|
||||
onOrderSuccess = (displayOrder: DisplayOrderDTO, action: KeyValueDTOOfStringAndString[]) => {};
|
||||
|
||||
handleOrderError = (err: any) => {
|
||||
this._modal.error('Fehler beim Bestellen', err);
|
||||
this.patchState({ ordering: false });
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<ui-searchbox
|
||||
class="max-w-lg mx-auto my-6"
|
||||
placeholder="EAN / ISBN"
|
||||
[formControl]="queryControl"
|
||||
[scanner]="true"
|
||||
[focusAfterViewInit]="true"
|
||||
[loading]="fetching$ | async"
|
||||
(search)="search($event)"
|
||||
(scan)="search($event)"
|
||||
[hint]="hint$ | async"
|
||||
>
|
||||
</ui-searchbox>
|
||||
@@ -0,0 +1,59 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, Output, EventEmitter, ChangeDetectorRef } from '@angular/core';
|
||||
import { UiSearchboxNextModule } from '@ui/searchbox';
|
||||
import { KulturpassOrderSearchboxStore } from './kulturpass-order-searchbox.store';
|
||||
import { provideComponentStore } from '@ngrx/component-store';
|
||||
import { Subject } from 'rxjs';
|
||||
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { AddToShoppingCartDTO } from '@swagger/checkout';
|
||||
|
||||
@Component({
|
||||
selector: 'shared-kulturpass-order-searchbox',
|
||||
templateUrl: 'kulturpass-order-searchbox.component.html',
|
||||
styleUrls: ['kulturpass-order-searchbox.component.css'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: { class: 'shared-kulturpass-order-searchbox' },
|
||||
standalone: true,
|
||||
imports: [UiSearchboxNextModule, ReactiveFormsModule, CommonModule],
|
||||
providers: [provideComponentStore(KulturpassOrderSearchboxStore)],
|
||||
})
|
||||
export class KulturpassOrderSearchboxComponent implements OnInit, OnDestroy {
|
||||
private _onDestroy$ = new Subject<void>();
|
||||
|
||||
queryControl = new FormControl(this._store.query);
|
||||
|
||||
fetching$ = this._store.fetching$;
|
||||
|
||||
@Output()
|
||||
addToShoppingCart = new EventEmitter<AddToShoppingCartDTO>();
|
||||
|
||||
hint$ = this._store.hint$;
|
||||
|
||||
constructor(private _store: KulturpassOrderSearchboxStore, private _cdr: ChangeDetectorRef) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this._store.query$.pipe(takeUntil(this._onDestroy$)).subscribe((query) => {
|
||||
if (this.queryControl.value === query) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.queryControl.setValue(query);
|
||||
this._cdr.markForCheck();
|
||||
});
|
||||
|
||||
this._store.addToShoppingCart$.pipe(takeUntil(this._onDestroy$)).subscribe((addToShoppingCart) => {
|
||||
this.addToShoppingCart.emit(addToShoppingCart);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this._onDestroy$.next();
|
||||
this._onDestroy$.complete();
|
||||
}
|
||||
|
||||
search(query: string) {
|
||||
this._store.updateQuery(query);
|
||||
this._store.search();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ComponentStore, OnStoreInit, tapResponse } from '@ngrx/component-store';
|
||||
import { ItemDTO, ResponseArgsOfItemDTO } from '@swagger/cat';
|
||||
import { switchMap, withLatestFrom } from 'rxjs/operators';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { DomainCatalogService } from '@domain/catalog';
|
||||
import { AddToShoppingCartDTO, AvailabilityDTO, BranchDTO } from '@swagger/checkout';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
|
||||
export interface KulturpassOrderSearchboxState {
|
||||
query: string;
|
||||
fetching: boolean;
|
||||
branch?: BranchDTO;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class KulturpassOrderSearchboxStore extends ComponentStore<KulturpassOrderSearchboxState> implements OnStoreInit {
|
||||
get query() {
|
||||
return this.get((s) => s.query);
|
||||
}
|
||||
|
||||
get fetching() {
|
||||
return this.get((s) => s.fetching);
|
||||
}
|
||||
|
||||
get branch() {
|
||||
return this.get((s) => s.branch);
|
||||
}
|
||||
|
||||
addToShoppingCart$ = new Subject<AddToShoppingCartDTO>();
|
||||
|
||||
hint$ = new Subject<string>();
|
||||
|
||||
constructor(
|
||||
private _catalogService: DomainCatalogService,
|
||||
private _availabilityService: DomainAvailabilityService,
|
||||
private _modal: UiModalService
|
||||
) {
|
||||
super({ query: '', fetching: false });
|
||||
}
|
||||
|
||||
readonly query$ = this.select((state) => state.query);
|
||||
|
||||
readonly updateQuery = this.updater((state, query: string) => ({ ...state, query }));
|
||||
|
||||
readonly fetching$ = this.select((state) => state.fetching);
|
||||
|
||||
readonly updateFetching = this.updater((state, fetching: boolean) => ({ ...state, fetching }));
|
||||
|
||||
readonly branch$ = this.select((state) => state.branch);
|
||||
|
||||
readonly updateBranch = this.updater((state, branch: BranchDTO) => ({ ...state, branch }));
|
||||
|
||||
ngrxOnStoreInit = () => {
|
||||
this.loadBranch();
|
||||
};
|
||||
|
||||
loadBranch = this.effect(($) =>
|
||||
$.pipe(
|
||||
switchMap(() => this._availabilityService.getDefaultBranch().pipe(tapResponse(this.handleBranchResponse, this.handleBranchError)))
|
||||
)
|
||||
);
|
||||
|
||||
handleBranchResponse = (res: BranchDTO) => {
|
||||
this.patchState({ branch: res });
|
||||
};
|
||||
|
||||
handleBranchError = (err) => {
|
||||
this._modal.error('Fehler beim Laden der Filiale', err);
|
||||
};
|
||||
|
||||
readonly search = this.effect(($) =>
|
||||
$.pipe(
|
||||
tap(() => this.patchState({ fetching: true })),
|
||||
withLatestFrom(this.query$),
|
||||
switchMap(([_, query]) =>
|
||||
this._catalogService.getDetailsByEan({ ean: query }).pipe(tapResponse(this.handleSearchResponse, this.handleSearchError))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
handleSearchResponse = (res: ResponseArgsOfItemDTO) => {
|
||||
if (!res.result) {
|
||||
this.hint$.next('Artikel nicht gefunden');
|
||||
this.patchState({ query: '' });
|
||||
return;
|
||||
}
|
||||
|
||||
this.fetchAvailability(res.result);
|
||||
};
|
||||
|
||||
handleSearchError = (err) => {
|
||||
this.hint$.next('Artikel nicht gefunden');
|
||||
this.patchState({ query: '', fetching: false });
|
||||
};
|
||||
|
||||
fetchAvailability = this.effect((item$: Observable<ItemDTO>) =>
|
||||
item$.pipe(
|
||||
switchMap((item) =>
|
||||
this._availabilityService
|
||||
.getTakeAwayAvailability({
|
||||
item: {
|
||||
ean: item.product.ean,
|
||||
itemId: item.id,
|
||||
price: item.catalogAvailability.price,
|
||||
},
|
||||
quantity: 1,
|
||||
})
|
||||
.pipe(tapResponse(this.handleAvailabilityResponse(item), this.handleAvailabilityError))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
handleAvailabilityResponse = (item: ItemDTO) => (availability: AvailabilityDTO) => {
|
||||
if (!this._availabilityService.isAvailable({ availability }) || availability.inStock < 1) {
|
||||
this.hint$.next('Artikel nicht vorrätig');
|
||||
this.patchState({ query: '', fetching: false });
|
||||
return;
|
||||
}
|
||||
|
||||
const addToShoppingCartDTO: AddToShoppingCartDTO = {
|
||||
quantity: 1,
|
||||
availability: availability,
|
||||
destination: {
|
||||
data: {
|
||||
target: 1,
|
||||
targetBranch: { id: this.branch.id },
|
||||
},
|
||||
},
|
||||
promotion: {
|
||||
points: 0,
|
||||
},
|
||||
itemType: item.type,
|
||||
product: { catalogProductNumber: String(item.id), ...item.product },
|
||||
};
|
||||
|
||||
this.addToShoppingCart$.next(addToShoppingCartDTO);
|
||||
|
||||
this.patchState({ query: '', fetching: false });
|
||||
};
|
||||
|
||||
handleAvailabilityError = (err) => {
|
||||
this._modal.error('Fehler beim Laden der Verfügbarkeit', err);
|
||||
this.patchState({ query: '', fetching: false });
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from './lib/kulturpass-order-modal.component';
|
||||
export * from './lib/kulturpass-order-modal.module';
|
||||
export * from './lib/kulturpass-order-modal.data';
|
||||
export * from './lib/kulturpass-order-modal.service';
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { BranchDTO } from '@swagger/checkout';
|
||||
|
||||
export type BranchNameFormat = 'key' | 'name' | 'key-name';
|
||||
export type BranchNameFormat = 'key' | 'name' | 'key-name' | 'name-address';
|
||||
|
||||
@Pipe({
|
||||
name: 'branchName',
|
||||
@@ -24,6 +24,10 @@ export class BranchNamePipe implements PipeTransform {
|
||||
return value.key;
|
||||
}
|
||||
|
||||
if (format === 'name-address') {
|
||||
return `${value.name} | ${value.address?.street} ${value.address?.streetNumber}, ${value.address?.zipCode} ${value.address?.city}`;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,8 @@ export { ResponseArgsOfIEnumerableOfLogisticianDTO } from './models/response-arg
|
||||
export { LogisticianDTO } from './models/logistician-dto';
|
||||
export { EntityDTOBaseOfLogisticianDTOAndILogistician } from './models/entity-dtobase-of-logistician-dtoand-ilogistician';
|
||||
export { ResponseArgsOfLogisticianDTO } from './models/response-args-of-logistician-dto';
|
||||
export { ResponseArgsOfIEnumerableOfDisplayOrderDTO } from './models/response-args-of-ienumerable-of-display-order-dto';
|
||||
export { ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString } from './models/response-args-of-value-tuple-of-ienumerable-of-display-order-dtoand-ienumerable-of-key-value-dtoof-string-and-string';
|
||||
export { ValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString } from './models/value-tuple-of-ienumerable-of-display-order-dtoand-ienumerable-of-key-value-dtoof-string-and-string';
|
||||
export { DisplayOrderDTO } from './models/display-order-dto';
|
||||
export { DisplayBranchDTO } from './models/display-branch-dto';
|
||||
export { CommunicationDetailsDTO } from './models/communication-details-dto';
|
||||
@@ -81,7 +82,10 @@ export { TermsOfDeliveryDTO } from './models/terms-of-delivery-dto';
|
||||
export { TypeOfDelivery } from './models/type-of-delivery';
|
||||
export { ShippingType } from './models/shipping-type';
|
||||
export { NotificationChannel } from './models/notification-channel';
|
||||
export { LinkedRecordDTO } from './models/linked-record-dto';
|
||||
export { EntityDTOBaseOfDisplayOrderDTOAndIOrder } from './models/entity-dtobase-of-display-order-dtoand-iorder';
|
||||
export { KulturPassOrderValues } from './models/kultur-pass-order-values';
|
||||
export { ResponseArgsOfIEnumerableOfDisplayOrderDTO } from './models/response-args-of-ienumerable-of-display-order-dto';
|
||||
export { ResponseArgsOfValueTupleOfOrderItemSubsetDTOAndOrderItemSubsetDTO } from './models/response-args-of-value-tuple-of-order-item-subset-dtoand-order-item-subset-dto';
|
||||
export { ValueTupleOfOrderItemSubsetDTOAndOrderItemSubsetDTO } from './models/value-tuple-of-order-item-subset-dtoand-order-item-subset-dto';
|
||||
export { OrderItemSubsetDTO } from './models/order-item-subset-dto';
|
||||
@@ -109,7 +113,6 @@ export { PaymentDTO } from './models/payment-dto';
|
||||
export { EntityDTOBaseOfPaymentDTOAndIReadOnlyPayment } from './models/entity-dtobase-of-payment-dtoand-iread-only-payment';
|
||||
export { ValidationStatus } from './models/validation-status';
|
||||
export { PackagingInstructions } from './models/packaging-instructions';
|
||||
export { LinkedRecordDTO } from './models/linked-record-dto';
|
||||
export { EntityDTOBaseOfOrderDTOAndIOrder } from './models/entity-dtobase-of-order-dtoand-iorder';
|
||||
export { OrderItemType } from './models/order-item-type';
|
||||
export { EntityDTOContainerOfOrderItemSubsetDTO } from './models/entity-dtocontainer-of-order-item-subset-dto';
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
/* tslint:disable */
|
||||
import { EntityDTOBaseOfDisplayOrderDTOAndIOrder } from './entity-dtobase-of-display-order-dtoand-iorder';
|
||||
import { KeyValueDTOOfStringAndString } from './key-value-dtoof-string-and-string';
|
||||
import { DisplayAddresseeDTO } from './display-addressee-dto';
|
||||
import { BuyerType } from './buyer-type';
|
||||
import { EnvironmentChannel } from './environment-channel';
|
||||
import { DisplayOrderItemDTO } from './display-order-item-dto';
|
||||
import { LinkedRecordDTO } from './linked-record-dto';
|
||||
import { DisplayLogisticianDTO } from './display-logistician-dto';
|
||||
import { NotificationChannel } from './notification-channel';
|
||||
import { DisplayBranchDTO } from './display-branch-dto';
|
||||
@@ -11,6 +13,7 @@ import { OrderType } from './order-type';
|
||||
import { DisplayOrderPaymentDTO } from './display-order-payment-dto';
|
||||
import { TermsOfDeliveryDTO } from './terms-of-delivery-dto';
|
||||
export interface DisplayOrderDTO extends EntityDTOBaseOfDisplayOrderDTOAndIOrder{
|
||||
actions?: Array<KeyValueDTOOfStringAndString>;
|
||||
buyer?: DisplayAddresseeDTO;
|
||||
buyerComment?: string;
|
||||
buyerIsGuestAccount?: boolean;
|
||||
@@ -21,6 +24,7 @@ export interface DisplayOrderDTO extends EntityDTOBaseOfDisplayOrderDTOAndIOrder
|
||||
features?: {[key: string]: string};
|
||||
items?: Array<DisplayOrderItemDTO>;
|
||||
itemsCount?: number;
|
||||
linkedRecords?: Array<LinkedRecordDTO>;
|
||||
logistician?: DisplayLogisticianDTO;
|
||||
notificationChannels?: NotificationChannel;
|
||||
orderBranch?: DisplayBranchDTO;
|
||||
|
||||
13
apps/swagger/oms/src/lib/models/kultur-pass-order-values.ts
Normal file
13
apps/swagger/oms/src/lib/models/kultur-pass-order-values.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
/* tslint:disable */
|
||||
export interface KulturPassOrderValues {
|
||||
|
||||
/**
|
||||
* Checkout PK
|
||||
*/
|
||||
checkoutId: number;
|
||||
|
||||
/**
|
||||
* PK des KulturPass-Einlösecode-Postens
|
||||
*/
|
||||
orderItemSubsetId?: string;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/* tslint:disable */
|
||||
import { ResponseArgs } from './response-args';
|
||||
import { ValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString } from './value-tuple-of-ienumerable-of-display-order-dtoand-ienumerable-of-key-value-dtoof-string-and-string';
|
||||
export interface ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString extends ResponseArgs{
|
||||
result: ValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
/* tslint:disable */
|
||||
import { DisplayOrderDTO } from './display-order-dto';
|
||||
import { KeyValueDTOOfStringAndString } from './key-value-dtoof-string-and-string';
|
||||
export interface ValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString {
|
||||
item1: Array<DisplayOrderDTO>;
|
||||
item2: Array<KeyValueDTOOfStringAndString>;
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import { StrictHttpResponse as __StrictHttpResponse } from '../strict-http-respo
|
||||
import { Observable as __Observable } from 'rxjs';
|
||||
import { map as __map, filter as __filter } from 'rxjs/operators';
|
||||
|
||||
import { ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString } from '../models/response-args-of-value-tuple-of-ienumerable-of-display-order-dtoand-ienumerable-of-key-value-dtoof-string-and-string';
|
||||
import { KulturPassOrderValues } from '../models/kultur-pass-order-values';
|
||||
import { ResponseArgsOfIEnumerableOfDisplayOrderDTO } from '../models/response-args-of-ienumerable-of-display-order-dto';
|
||||
import { ResponseArgsOfValueTupleOfOrderItemSubsetDTOAndOrderItemSubsetDTO } from '../models/response-args-of-value-tuple-of-order-item-subset-dtoand-order-item-subset-dto';
|
||||
import { ReorderValues } from '../models/reorder-values';
|
||||
@@ -16,6 +18,7 @@ import { ResponseArgsOfSupplierOrderResult } from '../models/response-args-of-su
|
||||
providedIn: 'root',
|
||||
})
|
||||
class OrderCheckoutService extends __BaseService {
|
||||
static readonly OrderCheckoutCreateKulturPassOrderPath = '/order/kulturpass';
|
||||
static readonly OrderCheckoutCreateOrderPOSTPath = '/order/checkout/{checkoutId}';
|
||||
static readonly OrderCheckoutCreateOrderPUTPath = '/order/checkout/{checkoutId}';
|
||||
static readonly OrderCheckoutReorderPath = '/order/{orderId}/orderitem/{orderItemId}/orderitemsubset/{orderItemSubsetId}/reorder';
|
||||
@@ -30,6 +33,55 @@ class OrderCheckoutService extends __BaseService {
|
||||
super(config, http);
|
||||
}
|
||||
|
||||
/**
|
||||
* KulturPass-Filialentnahme
|
||||
* @param params The `OrderCheckoutService.OrderCheckoutCreateKulturPassOrderParams` containing the following parameters:
|
||||
*
|
||||
* - `payload`:
|
||||
*
|
||||
* - `locale`:
|
||||
*
|
||||
* @return or
|
||||
*/
|
||||
OrderCheckoutCreateKulturPassOrderResponse(params: OrderCheckoutService.OrderCheckoutCreateKulturPassOrderParams): __Observable<__StrictHttpResponse<ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString | ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString>> {
|
||||
let __params = this.newParams();
|
||||
let __headers = new HttpHeaders();
|
||||
let __body: any = null;
|
||||
__body = params.payload;
|
||||
if (params.locale != null) __params = __params.set('locale', params.locale.toString());
|
||||
let req = new HttpRequest<any>(
|
||||
'POST',
|
||||
this.rootUrl + `/order/kulturpass`,
|
||||
__body,
|
||||
{
|
||||
headers: __headers,
|
||||
params: __params,
|
||||
responseType: 'json'
|
||||
});
|
||||
|
||||
return this.http.request<any>(req).pipe(
|
||||
__filter(_r => _r instanceof HttpResponse),
|
||||
__map((_r) => {
|
||||
return _r as __StrictHttpResponse<ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString | ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString>;
|
||||
})
|
||||
);
|
||||
}
|
||||
/**
|
||||
* KulturPass-Filialentnahme
|
||||
* @param params The `OrderCheckoutService.OrderCheckoutCreateKulturPassOrderParams` containing the following parameters:
|
||||
*
|
||||
* - `payload`:
|
||||
*
|
||||
* - `locale`:
|
||||
*
|
||||
* @return or
|
||||
*/
|
||||
OrderCheckoutCreateKulturPassOrder(params: OrderCheckoutService.OrderCheckoutCreateKulturPassOrderParams): __Observable<ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString | ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString> {
|
||||
return this.OrderCheckoutCreateKulturPassOrderResponse(params).pipe(
|
||||
__map(_r => _r.body as ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString | ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param params The `OrderCheckoutService.OrderCheckoutCreateOrderPOSTParams` containing the following parameters:
|
||||
*
|
||||
@@ -312,6 +364,14 @@ class OrderCheckoutService extends __BaseService {
|
||||
|
||||
module OrderCheckoutService {
|
||||
|
||||
/**
|
||||
* Parameters for OrderCheckoutCreateKulturPassOrder
|
||||
*/
|
||||
export interface OrderCheckoutCreateKulturPassOrderParams {
|
||||
payload: KulturPassOrderValues;
|
||||
locale?: null | string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for OrderCheckoutCreateOrderPOST
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,8 @@ import {
|
||||
forwardRef,
|
||||
ChangeDetectorRef,
|
||||
HostListener,
|
||||
Output,
|
||||
EventEmitter,
|
||||
} from '@angular/core';
|
||||
import { ControlValueAccessor } from '@angular/forms';
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
@@ -25,6 +27,9 @@ export class QuantityDropdownComponent implements ControlValueAccessor {
|
||||
@Input()
|
||||
quantity: number;
|
||||
|
||||
@Output()
|
||||
quantityChange = new EventEmitter<number>();
|
||||
|
||||
@Input()
|
||||
suffix: string = 'x';
|
||||
|
||||
@@ -75,6 +80,7 @@ export class QuantityDropdownComponent implements ControlValueAccessor {
|
||||
|
||||
this.quantity = quantity;
|
||||
this.onChange(quantity);
|
||||
this.quantityChange.emit(quantity);
|
||||
this.showDropdown = false;
|
||||
this.customInput = false;
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ export class UiSearchboxNextComponent extends UiFormControlDirective<any>
|
||||
startScan() {
|
||||
if (!!this.scanAdapterService?.isReady()) {
|
||||
this.subscriptions.add(
|
||||
this.scanAdapterService.scan().subscribe((result) => {
|
||||
this.scanAdapterService.scan({ include: ['Dev'] }).subscribe((result) => {
|
||||
this.scan.emit(result);
|
||||
this.setQuery(result);
|
||||
this.autocomplete?.close();
|
||||
|
||||
Reference in New Issue
Block a user