mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Compare commits
153 Commits
2.2
...
4323-WBS-F
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02b507aca9 | ||
|
|
05f94c65fc | ||
|
|
85d8d75da8 | ||
|
|
423cd498cf | ||
|
|
df308c98ff | ||
|
|
f4df6e8799 | ||
|
|
e9a63fd553 | ||
|
|
23b77c7e48 | ||
|
|
8b6188a6b5 | ||
|
|
822625a1c2 | ||
|
|
819827cc4c | ||
|
|
d09b5b1ce7 | ||
|
|
180e93a7da | ||
|
|
9671683a93 | ||
|
|
d909d6e804 | ||
|
|
15c50779b4 | ||
|
|
5bdfec7c3f | ||
|
|
810653c4d1 | ||
|
|
eddff0d93f | ||
|
|
44b406fad4 | ||
|
|
8416028113 | ||
|
|
44b33c1e4c | ||
|
|
6fb72e4b2f | ||
|
|
fce50daff6 | ||
|
|
b954947bb7 | ||
|
|
ddd5d50c5d | ||
|
|
215d7ca341 | ||
|
|
1255df10e0 | ||
|
|
ac35cc237e | ||
|
|
4fe5034e1c | ||
|
|
eec1cb5666 | ||
|
|
b62e6e8e35 | ||
|
|
b845147050 | ||
|
|
6bc265a358 | ||
|
|
98e963d782 | ||
|
|
90268b4ec1 | ||
|
|
034693df98 | ||
|
|
5b31661f8d | ||
|
|
d48b59b374 | ||
|
|
7d72fc56db | ||
|
|
90edb7dd7e | ||
|
|
7ee0c4d145 | ||
|
|
67f2ff54be | ||
|
|
f0470d3faa | ||
|
|
fb97db99b0 | ||
|
|
92aad95603 | ||
|
|
513cef2a66 | ||
|
|
bdf3bbc530 | ||
|
|
47baf2fa89 | ||
|
|
57bfc523ab | ||
|
|
23edea5fa4 | ||
|
|
330c59f7e9 | ||
|
|
0c65e9dace | ||
|
|
9b8ea11866 | ||
|
|
17aed38316 | ||
|
|
48a7cc4dd4 | ||
|
|
4417fd9f0d | ||
|
|
3e429cb261 | ||
|
|
48e30e795f | ||
|
|
953e528298 | ||
|
|
4276f427b9 | ||
|
|
264d914044 | ||
|
|
12f1e7c3af | ||
|
|
9eb4fbab65 | ||
|
|
8d1a63e47f | ||
|
|
e449e612c1 | ||
|
|
6ba65f031b | ||
|
|
f31ac4c2e3 | ||
|
|
f980f5aaf9 | ||
|
|
87a1e8a2c4 | ||
|
|
5bb9ebd6ec | ||
|
|
45ab1e9cc5 | ||
|
|
8d2685a8c3 | ||
|
|
d38c41a99d | ||
|
|
ff3dacde39 | ||
|
|
90b752e185 | ||
|
|
3ed9227508 | ||
|
|
9cfe8176d4 | ||
|
|
3999b8f623 | ||
|
|
c8f54b8be5 | ||
|
|
413d2f5178 | ||
|
|
35c2a6a046 | ||
|
|
1df201525c | ||
|
|
ef72dcf554 | ||
|
|
c228147c00 | ||
|
|
4b56b973c8 | ||
|
|
28a00b9f22 | ||
|
|
b1fe692de5 | ||
|
|
08b2f6cbc9 | ||
|
|
10e1db388f | ||
|
|
cd7f71b968 | ||
|
|
9361a631dd | ||
|
|
59c5abfd93 | ||
|
|
633c23a6f0 | ||
|
|
779e7323e2 | ||
|
|
6e7fbd940b | ||
|
|
6878b608fc | ||
|
|
a4fab8b64e | ||
|
|
21c0cc8794 | ||
|
|
7ea11ea0c4 | ||
|
|
778343f636 | ||
|
|
d2fb3b6c85 | ||
|
|
4c7b5eec38 | ||
|
|
35068e23cd | ||
|
|
bc30b86cce | ||
|
|
461f166e33 | ||
|
|
ad95faffa7 | ||
|
|
a0eb3c0459 | ||
|
|
fea435a6d2 | ||
|
|
ea9920c4d5 | ||
|
|
259d0f1648 | ||
|
|
872d3ff383 | ||
|
|
d68055f8a9 | ||
|
|
8d98dcf7e7 | ||
|
|
6311ebe467 | ||
|
|
f8a5ceed97 | ||
|
|
0420bda5da | ||
|
|
6dc532f40e | ||
|
|
0560d01f30 | ||
|
|
8aa870dddd | ||
|
|
26a3c76d5f | ||
|
|
bba50ccbcc | ||
|
|
88a06628e3 | ||
|
|
37ceb30ffb | ||
|
|
ece5d0fa0d | ||
|
|
6be214c6cd | ||
|
|
c470453ea4 | ||
|
|
27961bb4e5 | ||
|
|
74e4016625 | ||
|
|
c389008811 | ||
|
|
d067f925b9 | ||
|
|
dd04a1f2af | ||
|
|
9caabb6cc0 | ||
|
|
33b28d5f41 | ||
|
|
475f9b5e34 | ||
|
|
447456d7a6 | ||
|
|
241a34d7a8 | ||
|
|
8bc2ea8373 | ||
|
|
e066da3762 | ||
|
|
ad96278956 | ||
|
|
83406277ad | ||
|
|
9e89348381 | ||
|
|
0fb7419598 | ||
|
|
1790298cb4 | ||
|
|
ffe8e39c85 | ||
|
|
67e0f4bd46 | ||
|
|
e7b3a58da3 | ||
|
|
598f9f3777 | ||
|
|
4b342778df | ||
|
|
10e8fd904a | ||
|
|
1de342fd3b | ||
|
|
f4c1c3dd7f | ||
|
|
80bfc59356 |
@@ -1635,5 +1635,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": false
|
||||
}
|
||||
}
|
||||
@@ -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> {
|
||||
|
||||
@@ -14,7 +14,6 @@ export class ScanAdapterService {
|
||||
async init(): Promise<void> {
|
||||
for (const adapter of this.scanAdapters) {
|
||||
const isReady = await adapter.init();
|
||||
console.log('ScanAdapterService.init', adapter.name, isReady);
|
||||
this._readyAdapters[adapter.name] = isReady;
|
||||
}
|
||||
}
|
||||
@@ -24,42 +23,30 @@ export class ScanAdapterService {
|
||||
}
|
||||
|
||||
getAdapter(name: string): ScanAdapter | undefined {
|
||||
return this.scanAdapters.find((adapter) => adapter.name === name);
|
||||
return this._readyAdapters[name] && this.scanAdapters.find((adapter) => adapter.name === name);
|
||||
}
|
||||
|
||||
// return true if at least one adapter is ready
|
||||
isReady(): boolean {
|
||||
return Object.values(this._readyAdapters).some((ready) => ready);
|
||||
}
|
||||
|
||||
scan(ops: { use?: string; include?: string[]; exclude?: string[] } = { exclude: ['Dev'] }): Observable<string> {
|
||||
scan(): Observable<string> {
|
||||
const adapterOrder = ['Native', 'Scandit', 'Dev'];
|
||||
|
||||
let adapter: ScanAdapter;
|
||||
|
||||
if (ops.use == undefined) {
|
||||
// get the first adapter that is ready to use
|
||||
adapter = this.scanAdapters
|
||||
.filter((adapter) => {
|
||||
if (ops.include?.length) {
|
||||
return ops.include.includes(adapter.name);
|
||||
} else if (ops.exclude?.length) {
|
||||
return !ops.exclude.includes(adapter.name);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
})
|
||||
.find((adapter) => this._readyAdapters[adapter.name]);
|
||||
} else {
|
||||
adapter = this.getAdapter(ops.use);
|
||||
for (const name of adapterOrder) {
|
||||
adapter = this.getAdapter(name);
|
||||
|
||||
if (adapter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!adapter) {
|
||||
return throwError('No adapter found');
|
||||
}
|
||||
|
||||
if (this._readyAdapters[adapter.name] == false) {
|
||||
return throwError('Adapter is not ready');
|
||||
}
|
||||
|
||||
return adapter.scan();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import { ResponseArgsOfIEnumerableOfStockInfoDTO, StockDTO, StockInfoDTO, StockS
|
||||
import { PriceDTO } from '@swagger/availability';
|
||||
import { AvailabilityByBranchDTO, ItemData } from './defs';
|
||||
import { Availability } from './defs/availability';
|
||||
import { isEmpty } from 'lodash';
|
||||
|
||||
@Injectable()
|
||||
export class DomainAvailabilityService {
|
||||
@@ -34,6 +35,11 @@ export class DomainAvailabilityService {
|
||||
private _branchService: StoreCheckoutBranchService
|
||||
) {}
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
memorizedAvailabilityShippingAvailability(request: Array<AvailabilityRequestDTO>) {
|
||||
return this._availabilityService.AvailabilityShippingAvailability(request).pipe(shareReplay(1));
|
||||
}
|
||||
|
||||
@memorize()
|
||||
getSuppliers(): Observable<SupplierDTO[]> {
|
||||
return this._supplierService.StoreCheckoutSupplierGetSuppliers({}).pipe(
|
||||
@@ -140,6 +146,7 @@ export class DomainAvailabilityService {
|
||||
);
|
||||
}
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getTakeAwayAvailability({
|
||||
item,
|
||||
quantity,
|
||||
@@ -160,7 +167,7 @@ export class DomainAvailabilityService {
|
||||
),
|
||||
map(([response, supplier, defaultBranch]) => {
|
||||
const price = item?.price;
|
||||
return this._mapToTakeAwayAvailability({ response, supplier, branchId: branch.id ?? defaultBranch.id, quantity, price });
|
||||
return this._mapToTakeAwayAvailability({ response, supplier, branchId: branch?.id ?? defaultBranch?.id, quantity, price });
|
||||
}),
|
||||
shareReplay(1)
|
||||
);
|
||||
@@ -249,57 +256,53 @@ export class DomainAvailabilityService {
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getDeliveryAvailability({ item, quantity }: { item: ItemData; quantity: number }): Observable<AvailabilityDTO> {
|
||||
return this._availabilityService
|
||||
.AvailabilityShippingAvailability([
|
||||
{
|
||||
ean: item?.ean,
|
||||
itemId: item?.itemId ? String(item?.itemId) : null,
|
||||
price: item?.price,
|
||||
qty: quantity,
|
||||
},
|
||||
])
|
||||
.pipe(
|
||||
timeout(5000),
|
||||
map((r) => this._mapToShippingAvailability(r.result)?.find((_) => true)),
|
||||
shareReplay(1)
|
||||
);
|
||||
return this.memorizedAvailabilityShippingAvailability([
|
||||
{
|
||||
ean: item?.ean,
|
||||
itemId: item?.itemId ? String(item?.itemId) : null,
|
||||
price: item?.price,
|
||||
qty: quantity,
|
||||
},
|
||||
]).pipe(
|
||||
timeout(5000),
|
||||
map((r) => this._mapToShippingAvailability(r.result)?.find((_) => true)),
|
||||
shareReplay(1)
|
||||
);
|
||||
}
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getDigDeliveryAvailability({ item, quantity }: { item: ItemData; quantity: number }): Observable<AvailabilityDTO> {
|
||||
return this._availabilityService
|
||||
.AvailabilityShippingAvailability([
|
||||
{
|
||||
qty: quantity,
|
||||
ean: item?.ean,
|
||||
itemId: item?.itemId ? String(item?.itemId) : null,
|
||||
price: item?.price,
|
||||
},
|
||||
])
|
||||
.pipe(
|
||||
timeout(5000),
|
||||
map((r) => {
|
||||
const availabilities = r.result;
|
||||
const preferred = availabilities?.find((f) => f.preferred === 1);
|
||||
return this.memorizedAvailabilityShippingAvailability([
|
||||
{
|
||||
qty: quantity,
|
||||
ean: item?.ean,
|
||||
itemId: item?.itemId ? String(item?.itemId) : null,
|
||||
price: item?.price,
|
||||
},
|
||||
]).pipe(
|
||||
timeout(5000),
|
||||
map((r) => {
|
||||
const availabilities = r.result;
|
||||
const preferred = availabilities?.find((f) => f.preferred === 1);
|
||||
|
||||
const availability: AvailabilityDTO = {
|
||||
availabilityType: preferred?.status,
|
||||
ssc: preferred?.ssc,
|
||||
sscText: preferred?.sscText,
|
||||
supplier: { id: preferred?.supplierId },
|
||||
isPrebooked: preferred?.isPrebooked,
|
||||
estimatedShippingDate: preferred?.requestStatusCode === '32' ? preferred?.altAt : preferred?.at,
|
||||
estimatedDelivery: preferred?.estimatedDelivery,
|
||||
price: preferred?.price,
|
||||
logistician: { id: preferred?.logisticianId },
|
||||
supplierProductNumber: preferred?.supplierProductNumber,
|
||||
supplierInfo: preferred?.requestStatusCode,
|
||||
lastRequest: preferred?.requested,
|
||||
};
|
||||
return availability;
|
||||
}),
|
||||
shareReplay(1)
|
||||
);
|
||||
const availability: AvailabilityDTO = {
|
||||
availabilityType: preferred?.status,
|
||||
ssc: preferred?.ssc,
|
||||
sscText: preferred?.sscText,
|
||||
supplier: { id: preferred?.supplierId },
|
||||
isPrebooked: preferred?.isPrebooked,
|
||||
estimatedShippingDate: preferred?.requestStatusCode === '32' ? preferred?.altAt : preferred?.at,
|
||||
estimatedDelivery: preferred?.estimatedDelivery,
|
||||
price: preferred?.price,
|
||||
logistician: { id: preferred?.logisticianId },
|
||||
supplierProductNumber: preferred?.supplierProductNumber,
|
||||
supplierInfo: preferred?.requestStatusCode,
|
||||
lastRequest: preferred?.requested,
|
||||
};
|
||||
return availability;
|
||||
}),
|
||||
shareReplay(1)
|
||||
);
|
||||
}
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
@@ -333,37 +336,35 @@ export class DomainAvailabilityService {
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getDownloadAvailability({ item }: { item: ItemData }): Observable<AvailabilityDTO> {
|
||||
return this._availabilityService
|
||||
.AvailabilityShippingAvailability([
|
||||
{
|
||||
ean: item?.ean,
|
||||
itemId: item?.itemId ? String(item?.itemId) : null,
|
||||
price: item?.price,
|
||||
qty: 1,
|
||||
},
|
||||
])
|
||||
.pipe(
|
||||
map((r) => {
|
||||
const availabilities = r.result;
|
||||
const preferred = availabilities?.find((f) => f.preferred === 1);
|
||||
return this.memorizedAvailabilityShippingAvailability([
|
||||
{
|
||||
ean: item?.ean,
|
||||
itemId: item?.itemId ? String(item?.itemId) : null,
|
||||
price: item?.price,
|
||||
qty: 1,
|
||||
},
|
||||
]).pipe(
|
||||
map((r) => {
|
||||
const availabilities = r.result;
|
||||
const preferred = availabilities?.find((f) => f.preferred === 1);
|
||||
|
||||
const availability: AvailabilityDTO = {
|
||||
availabilityType: preferred?.status,
|
||||
ssc: preferred?.ssc,
|
||||
sscText: preferred?.sscText,
|
||||
supplier: { id: preferred?.supplierId },
|
||||
isPrebooked: preferred?.isPrebooked,
|
||||
estimatedShippingDate: preferred?.requestStatusCode === '32' ? preferred?.altAt : preferred?.at,
|
||||
price: preferred?.price,
|
||||
supplierProductNumber: preferred?.supplierProductNumber,
|
||||
logistician: { id: preferred?.logisticianId },
|
||||
supplierInfo: preferred?.requestStatusCode,
|
||||
lastRequest: preferred?.requested,
|
||||
};
|
||||
return availability;
|
||||
}),
|
||||
shareReplay(1)
|
||||
);
|
||||
const availability: AvailabilityDTO = {
|
||||
availabilityType: preferred?.status,
|
||||
ssc: preferred?.ssc,
|
||||
sscText: preferred?.sscText,
|
||||
supplier: { id: preferred?.supplierId },
|
||||
isPrebooked: preferred?.isPrebooked,
|
||||
estimatedShippingDate: preferred?.requestStatusCode === '32' ? preferred?.altAt : preferred?.at,
|
||||
price: preferred?.price,
|
||||
supplierProductNumber: preferred?.supplierProductNumber,
|
||||
logistician: { id: preferred?.logisticianId },
|
||||
supplierInfo: preferred?.requestStatusCode,
|
||||
lastRequest: preferred?.requested,
|
||||
};
|
||||
return availability;
|
||||
}),
|
||||
shareReplay(1)
|
||||
);
|
||||
}
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
@@ -401,7 +402,7 @@ export class DomainAvailabilityService {
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getDeliveryAvailabilities(payload: AvailabilityRequestDTO[]) {
|
||||
return this._availabilityService.AvailabilityShippingAvailability(payload).pipe(
|
||||
return this.memorizedAvailabilityShippingAvailability(payload).pipe(
|
||||
timeout(20000),
|
||||
map((response) => this._mapToShippingAvailability(response.result))
|
||||
);
|
||||
@@ -409,7 +410,7 @@ export class DomainAvailabilityService {
|
||||
|
||||
@memorize({ ttl: 10000 })
|
||||
getDigDeliveryAvailabilities(payload: AvailabilityRequestDTO[]) {
|
||||
return this._availabilityService.AvailabilityShippingAvailability(payload).pipe(
|
||||
return this.memorizedAvailabilityShippingAvailability(payload).pipe(
|
||||
timeout(20000),
|
||||
map((response) => this._mapToShippingAvailability(response.result))
|
||||
);
|
||||
@@ -447,6 +448,9 @@ export class DomainAvailabilityService {
|
||||
}
|
||||
|
||||
isAvailable({ availability }: { availability: AvailabilityDTO }) {
|
||||
if (availability?.supplier?.id === 16 && availability?.inStock == 0) {
|
||||
return false;
|
||||
}
|
||||
return [2, 32, 256, 1024, 2048, 4096].some((code) => availability?.availabilityType === code);
|
||||
}
|
||||
|
||||
@@ -476,6 +480,10 @@ export class DomainAvailabilityService {
|
||||
};
|
||||
}
|
||||
|
||||
private _priceIsEmpty(price: PriceDTO) {
|
||||
return isEmpty(price?.value) || isEmpty(price?.vat);
|
||||
}
|
||||
|
||||
private _mapToTakeAwayAvailability({
|
||||
response,
|
||||
supplier,
|
||||
@@ -496,7 +504,7 @@ export class DomainAvailabilityService {
|
||||
inStock: inStock,
|
||||
supplierSSC: quantity <= inStock ? '999' : '',
|
||||
supplierSSCText: quantity <= inStock ? 'Filialentnahme' : '',
|
||||
price: price ?? stockInfo?.retailPrice,
|
||||
price: this._priceIsEmpty(price) ? stockInfo?.retailPrice : price,
|
||||
supplier: { id: supplier?.id },
|
||||
// TODO: Change after API Update
|
||||
// LH: 2021-03-09 preis Property hat nun ein Fallback auf retailPrice
|
||||
@@ -538,6 +546,7 @@ export class DomainAvailabilityService {
|
||||
return preferred.map((p) => {
|
||||
return [
|
||||
{
|
||||
orderDeadline: p?.orderDeadline,
|
||||
availabilityType: p?.status,
|
||||
ssc: p?.ssc,
|
||||
sscText: p?.sscText,
|
||||
@@ -559,7 +568,6 @@ export class DomainAvailabilityService {
|
||||
|
||||
private _mapToShippingAvailability(availabilities: SwaggerAvailabilityDTO[]) {
|
||||
const preferred = availabilities.filter((f) => f.preferred === 1);
|
||||
|
||||
return preferred.map((p) => {
|
||||
return {
|
||||
availabilityType: p?.status,
|
||||
@@ -573,6 +581,7 @@ export class DomainAvailabilityService {
|
||||
supplierInfo: p?.requestStatusCode,
|
||||
lastRequest: p?.requested,
|
||||
itemId: p.itemId,
|
||||
priceMaintained: p.priceMaintained,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -26,8 +26,18 @@ import {
|
||||
StoreCheckoutBuyerService,
|
||||
StoreCheckoutPayerService,
|
||||
StoreCheckoutBranchService,
|
||||
ItemsResult,
|
||||
KulturPassService,
|
||||
ProductDTO,
|
||||
KulturPassResult,
|
||||
} 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';
|
||||
@@ -37,7 +47,7 @@ import * as DomainCheckoutActions from './store/domain-checkout.actions';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { CustomerDTO, EntityDTOContainerOfAttributeDTO } from '@swagger/crm';
|
||||
import { CustomerDTO } from '@swagger/crm';
|
||||
|
||||
@Injectable()
|
||||
export class DomainCheckoutService {
|
||||
@@ -51,7 +61,8 @@ export class DomainCheckoutService {
|
||||
private _paymentService: StoreCheckoutPaymentService,
|
||||
private _buyerService: StoreCheckoutBuyerService,
|
||||
private _payerService: StoreCheckoutPayerService,
|
||||
private _branchService: StoreCheckoutBranchService
|
||||
private _branchService: StoreCheckoutBranchService,
|
||||
private _kulturpassService: KulturPassService
|
||||
) {}
|
||||
|
||||
//#region shoppingcart
|
||||
@@ -198,7 +209,19 @@ export class DomainCheckoutService {
|
||||
);
|
||||
}
|
||||
|
||||
canAddItems({ processId, payload, orderType }: { processId: number; payload: ItemPayload[]; orderType: string }) {
|
||||
canAddItemsKulturpass(payload: ProductDTO[]): Observable<KulturPassResult[]> {
|
||||
return this._kulturpassService.KulturPassCanAddForKulturPass({ payload }).pipe(map((response) => response?.result));
|
||||
}
|
||||
|
||||
canAddItems({
|
||||
processId,
|
||||
payload,
|
||||
orderType,
|
||||
}: {
|
||||
processId: number;
|
||||
payload: ItemPayload[];
|
||||
orderType: string;
|
||||
}): Observable<ItemsResult[]> {
|
||||
return this.getShoppingCart({ processId }).pipe(
|
||||
first(),
|
||||
withLatestFrom(this.store.select(DomainCheckoutSelectors.selectCustomerFeaturesByProcessId, { processId })),
|
||||
@@ -217,7 +240,8 @@ export class DomainCheckoutService {
|
||||
})
|
||||
.pipe(
|
||||
map((response) => {
|
||||
return response.result;
|
||||
// TODO: remove this when the API is fixed
|
||||
return (response.result as unknown) as ItemsResult[];
|
||||
})
|
||||
);
|
||||
})
|
||||
@@ -362,8 +386,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,
|
||||
@@ -371,8 +396,8 @@ export class DomainCheckoutService {
|
||||
.pipe(
|
||||
map((response) => response.result),
|
||||
tap((checkout) => this.store.dispatch(DomainCheckoutActions.setCheckout({ processId, checkout })))
|
||||
)
|
||||
)
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -700,6 +725,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,
|
||||
|
||||
@@ -21,6 +21,7 @@ export class CollectOnDeliveryNoteActionHandler extends ActionHandler<OrderItems
|
||||
const response = await this.orderService
|
||||
.OrderCollectOnDeliveryNote({
|
||||
data,
|
||||
eagerLoading: 1,
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
@@ -29,7 +30,7 @@ export class CollectOnDeliveryNoteActionHandler extends ActionHandler<OrderItems
|
||||
|
||||
return {
|
||||
...context,
|
||||
receipts: response.result,
|
||||
receipts: response.result.map((r) => r.data),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActionHandler } from '@core/command';
|
||||
import { OrderService } from '@swagger/oms';
|
||||
import { OrderItemsContext } from './order-items.context';
|
||||
|
||||
@Injectable()
|
||||
export class CollectWithSmallAmountinvoiceActionHandler extends ActionHandler<OrderItemsContext> {
|
||||
constructor(private orderService: OrderService) {
|
||||
super('COLLECT_WITH_SMALLAMOUNTINVOICE');
|
||||
}
|
||||
|
||||
async handler(context: OrderItemsContext): Promise<OrderItemsContext> {
|
||||
const data: Record<number, number> = {};
|
||||
|
||||
context.items.forEach((orderItemSubsetId) => {
|
||||
data[orderItemSubsetId.orderItemSubsetId] =
|
||||
context.itemQuantity?.get(orderItemSubsetId.orderItemSubsetId) ?? orderItemSubsetId.quantity;
|
||||
});
|
||||
|
||||
const response = await this.orderService
|
||||
.OrderCollectWithSmallAmountInvoice({
|
||||
data,
|
||||
eagerLoading: 1,
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
// Für korrekte Navigation nach Aufruf, da ProcessingStatus Serverseitig auf abgeholt gesetzt wird
|
||||
context.items?.forEach((i) => (i.processingStatus = 256));
|
||||
|
||||
return {
|
||||
...context,
|
||||
receipts: response.result.map((r) => r.data),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
// start:ng42.barrel
|
||||
export * from './accepted.action-handler';
|
||||
export * from './arrived.action-handler';
|
||||
export * from './assembled.action-handler';
|
||||
@@ -7,6 +6,10 @@ export * from './back-to-stock.action-handler';
|
||||
export * from './canceled-by-buyer.action-handler';
|
||||
export * from './canceled-by-retailer.action-handler';
|
||||
export * from './canceled-by-supplier.action-handler';
|
||||
export * from './change-order-item-status-base.action-handler';
|
||||
export * from './collect-on-deliverynote.action-handler';
|
||||
export * from './collect-with-smallamountinvoice.action-handler';
|
||||
export * from './create-returnitem.action-handler';
|
||||
export * from './create-shipping-note.action-handler';
|
||||
export * from './delivered.action-handler';
|
||||
export * from './determine-supplier.action-handler';
|
||||
@@ -25,16 +28,15 @@ export * from './parked.action-handler';
|
||||
export * from './placed.action-handler';
|
||||
export * from './preperation-for-shipping.action-handler';
|
||||
export * from './print-compartment-label.action-handler';
|
||||
export * from './print-pricediffqrcodelabel.action-handler';
|
||||
export * from './print-shipping-note.action-handler';
|
||||
export * from './re-ordered.action-handler';
|
||||
export * from './print-smallamountinvoice.action-handler';
|
||||
export * from './re-order.action-handler';
|
||||
export * from './re-ordered.action-handler';
|
||||
export * from './redirected-internally.action-handler';
|
||||
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';
|
||||
export * from './collect-on-deliverynote.action-handler';
|
||||
export * from './create-returnitem.action-handler';
|
||||
export * from './print-pricediffqrcodelabel.action-handler';
|
||||
// end:ng42.barrel
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ export class PrintShippingNoteActionHandler extends ActionHandler<OrderItemsCont
|
||||
printerType: 'Label',
|
||||
print: async (printer) => {
|
||||
try {
|
||||
for (const group of groupBy(data?.receipts, (receipt) => receipt?.buyer?.buyerNumber)) {
|
||||
const receipts = data?.receipts?.filter((r) => r?.receiptType & 1);
|
||||
for (const group of groupBy(receipts, (receipt) => receipt?.buyer?.buyerNumber)) {
|
||||
await this.domainPrinterService.printShippingNote({ printer, receipts: group?.items?.map((r) => r?.id) }).toPromise();
|
||||
}
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActionHandler } from '@core/command';
|
||||
import { OrderItemsContext } from './order-items.context';
|
||||
import { OMSPrintService } from '@swagger/print';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { PrintModalComponent, PrintModalData } from '@modal/printer';
|
||||
import { NativeContainerService } from 'native-container';
|
||||
import { groupBy } from '@ui/common';
|
||||
|
||||
@Injectable()
|
||||
export class PrintSmallamountinvoiceActionHandler extends ActionHandler<OrderItemsContext> {
|
||||
constructor(
|
||||
private uiModal: UiModalService,
|
||||
private omsPrintService: OMSPrintService,
|
||||
private nativeContainerService: NativeContainerService
|
||||
) {
|
||||
super('PRINT_SMALLAMOUNTINVOICE');
|
||||
}
|
||||
|
||||
async handler(data: OrderItemsContext): Promise<OrderItemsContext> {
|
||||
await this.uiModal
|
||||
.open({
|
||||
content: PrintModalComponent,
|
||||
config: { showScrollbarY: false },
|
||||
data: {
|
||||
printImmediately: !this.nativeContainerService.isNative,
|
||||
printerType: 'Label',
|
||||
print: async (printer) => {
|
||||
try {
|
||||
const receipts = data?.receipts?.filter((r) => r?.receiptType & 128);
|
||||
for (const group of groupBy(receipts, (receipt) => receipt?.buyer?.buyerNumber)) {
|
||||
await this.omsPrintService
|
||||
.OMSPrintKleinbetragsrechnung({
|
||||
data: group?.items?.map((r) => r?.id),
|
||||
printer,
|
||||
})
|
||||
.toPromise();
|
||||
}
|
||||
return {
|
||||
error: false,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return {
|
||||
error: true,
|
||||
message: error?.message || error,
|
||||
};
|
||||
}
|
||||
},
|
||||
} as PrintModalData,
|
||||
})
|
||||
.afterClosed$.toPromise();
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
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();
|
||||
|
||||
if (result.data == null) {
|
||||
return data;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
AutocompleteTokenDTO,
|
||||
BranchService,
|
||||
ChangeStockStatusCodeValues,
|
||||
HistoryDTO,
|
||||
@@ -11,9 +10,7 @@ import {
|
||||
OrderItemSubsetDTO,
|
||||
OrderListItemDTO,
|
||||
OrderService,
|
||||
QueryTokenDTO,
|
||||
ReceiptService,
|
||||
ResponseArgsOfIEnumerableOfHistoryDTO,
|
||||
StatusValues,
|
||||
StockStatusCodeService,
|
||||
ValueTupleOfLongAndReceiptTypeAndEntityDTOContainerOfReceiptDTO,
|
||||
@@ -22,7 +19,7 @@ import {
|
||||
} from '@swagger/oms';
|
||||
import { memorize } from '@utils/common';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, mergeMap, shareReplay } from 'rxjs/operators';
|
||||
import { map, shareReplay } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
export class DomainOmsService {
|
||||
@@ -191,6 +188,10 @@ export class DomainOmsService {
|
||||
);
|
||||
}
|
||||
|
||||
getOrderSource(orderId: number): Observable<string> {
|
||||
return this.getOrder(orderId).pipe(map((order) => order?.features?.orderSource));
|
||||
}
|
||||
|
||||
updateNotifications(orderId: number, changes: { selected: NotificationChannel; email: string; mobile: string }) {
|
||||
const communicationDetails = {
|
||||
email: changes.email,
|
||||
|
||||
11
apps/domain/package-inspection/src/lib/events.ts
Normal file
11
apps/domain/package-inspection/src/lib/events.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { PackageArrivalStatusDTO } from '@swagger/wws';
|
||||
|
||||
export abstract class PackageInspectionEvent {
|
||||
constructor(public readonly type: string) {}
|
||||
}
|
||||
|
||||
export class PackageStatusChangedEvent extends PackageInspectionEvent {
|
||||
constructor(public readonly packageId: string, public readonly status: PackageArrivalStatusDTO) {
|
||||
super('PackageStatusChangedEvent');
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
ListResponseArgsOfPackageDTO,
|
||||
ListResponseArgsOfPackageDTO2,
|
||||
PackageArrivalStatusDTO,
|
||||
PackageDetailResponseDTO,
|
||||
PackageDTO,
|
||||
PackageDTO2,
|
||||
QuerySettingsDTO,
|
||||
QueryTokenDTO,
|
||||
@@ -13,13 +11,18 @@ import {
|
||||
ResponseArgsOfQuerySettingsDTO,
|
||||
WareneingangService,
|
||||
} from '@swagger/wws';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { map, tap } from 'rxjs/operators';
|
||||
import { PackageInspectionEvent, PackageStatusChangedEvent } from './events';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class DomainPackageInspectionService {
|
||||
private _events = new Subject<PackageInspectionEvent>();
|
||||
|
||||
events = this._events.asObservable();
|
||||
|
||||
constructor(private _wareneingang: WareneingangService) {}
|
||||
|
||||
getQuerySettingsResponse(): Observable<ResponseArgsOfQuerySettingsDTO> {
|
||||
@@ -47,23 +50,26 @@ export class DomainPackageInspectionService {
|
||||
}
|
||||
|
||||
changePackageStatusResponse(pkg: PackageDTO2, modifier: string): Observable<ResponseArgsOfPackageArrivalStatusDTO> {
|
||||
return this._wareneingang.WareneingangChangePackageStatus({
|
||||
packageId: pkg.id,
|
||||
payload: {
|
||||
id: pkg.id,
|
||||
annotation: pkg.annotation,
|
||||
area: pkg.area,
|
||||
arrivalChecked: pkg.arrivalChecked,
|
||||
arrivalStatus: pkg.arrivalStatus,
|
||||
deliveryNoteNumber: pkg.deliveryNoteNumber,
|
||||
deliveryTarget: pkg.deliveryTarget,
|
||||
estimatedDeliveryDate: pkg.estimatedDeliveryDate,
|
||||
packageNumber: pkg.packageNumber,
|
||||
supplier: pkg.supplier,
|
||||
trackingNumber: pkg.trackingNumber,
|
||||
},
|
||||
modifier,
|
||||
});
|
||||
return this._wareneingang
|
||||
.WareneingangChangePackageStatus({
|
||||
packageId: pkg.id,
|
||||
payload: {
|
||||
id: pkg.id,
|
||||
annotation: pkg.annotation,
|
||||
area: pkg.area,
|
||||
arrivalChecked: pkg.arrivalChecked,
|
||||
arrivalStatus: pkg.arrivalStatus,
|
||||
deliveryNoteNumber: pkg.deliveryNoteNumber,
|
||||
deliveryTarget: pkg.deliveryTarget,
|
||||
estimatedDeliveryDate: pkg.estimatedDeliveryDate,
|
||||
packageNumber: pkg.packageNumber,
|
||||
supplier: pkg.supplier,
|
||||
trackingNumber: pkg.trackingNumber,
|
||||
scanId: pkg.scanId,
|
||||
},
|
||||
modifier,
|
||||
})
|
||||
.pipe(tap((res) => this._events.next(new PackageStatusChangedEvent(pkg.id, res.result))));
|
||||
}
|
||||
|
||||
changePackageStatus(pkg: PackageDTO2, modifier: string): Observable<PackageArrivalStatusDTO> {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Public API Surface of package-inspection
|
||||
*/
|
||||
|
||||
export * from './lib/events';
|
||||
export * from './lib/package-inspection.service';
|
||||
export * from './lib/package-inspection.module';
|
||||
|
||||
@@ -447,7 +447,7 @@ export class DomainRemissionService {
|
||||
* Create a new receipt for the given return/remission
|
||||
* @param returnId Return ID
|
||||
* @param receiptNumber Receipt number
|
||||
* @returns ReturnDTO - ShippingDocument
|
||||
* @returns ReceiptDTO
|
||||
*/
|
||||
async createReceipt(returnDTO: ReturnDTO, receiptNumber?: string): Promise<ReceiptDTO> {
|
||||
const stock = await this._getStock();
|
||||
@@ -471,14 +471,41 @@ export class DomainRemissionService {
|
||||
return receipt;
|
||||
}
|
||||
|
||||
async completeReceipt(returnId: number, receiptId: number, packageCode: string): Promise<ReceiptDTO> {
|
||||
/**
|
||||
* Create a new Package and assign it to a receipt
|
||||
* @param returnId Return ID
|
||||
* @param receiptId Receipt ID
|
||||
* @param packageNumber Packagenumber
|
||||
* @returns ReceiptDTO
|
||||
*/
|
||||
async createReceiptAndAssignPackage({
|
||||
returnId,
|
||||
receiptId,
|
||||
packageNumber,
|
||||
}: {
|
||||
returnId: number;
|
||||
receiptId: number;
|
||||
packageNumber: string;
|
||||
}): Promise<ReceiptDTO> {
|
||||
const response = await this._returnService
|
||||
.ReturnCreateAndAssignPackage({
|
||||
returnId,
|
||||
receiptId,
|
||||
data: {
|
||||
packageNumber,
|
||||
},
|
||||
})
|
||||
.toPromise();
|
||||
const receipt: ReceiptDTO = response.result;
|
||||
return receipt;
|
||||
}
|
||||
|
||||
async completeReceipt(returnId: number, receiptId: number): Promise<ReceiptDTO> {
|
||||
const res = await this._returnService
|
||||
.ReturnFinalizeReceipt({
|
||||
returnId,
|
||||
receiptId,
|
||||
data: {
|
||||
packageCode,
|
||||
},
|
||||
data: {},
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
|
||||
@@ -4,61 +4,118 @@ import { SignalrHub, SignalRHubOptions } from '@core/signalr';
|
||||
import { BehaviorSubject, merge, of } from 'rxjs';
|
||||
import { filter, map, shareReplay, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { EnvelopeDTO, MessageBoardItemDTO } from './defs';
|
||||
import { cloneDeep } from 'lodash';
|
||||
|
||||
export const NOTIFICATIONS_HUB_OPTIONS = new InjectionToken<SignalRHubOptions>('hub.notifications.options');
|
||||
|
||||
@Injectable()
|
||||
export class NotificationsHub extends SignalrHub {
|
||||
updateNotification$ = new BehaviorSubject<MessageBoardItemDTO>(undefined);
|
||||
|
||||
get branchNo() {
|
||||
return String(this._auth.getClaimByKey('branch_no') || this._auth.getClaimByKey('sub'));
|
||||
}
|
||||
|
||||
// get sessionStoragesessionStorageKey() {
|
||||
// return `NOTIFICATIONS_BOARD_${this.branchNo}`;
|
||||
// }
|
||||
|
||||
get sessionStoragesessionStorageKey() {
|
||||
return `NOTIFICATIONS_BOARD_${this.branchNo}`;
|
||||
return `NOTIFICATIONS_BOARD_AREA_${this.branchNo}`;
|
||||
}
|
||||
|
||||
messageBoardItems$ = new BehaviorSubject<Record<string, MessageBoardItemDTO[]>>({});
|
||||
|
||||
constructor(@Inject(NOTIFICATIONS_HUB_OPTIONS) options: SignalRHubOptions, private _auth: AuthService) {
|
||||
super(options);
|
||||
|
||||
this.messageBoardItems$.next(this._getNotifications());
|
||||
|
||||
this.messageBoardItems$.subscribe((data) => {
|
||||
this._storeNotifactions(data);
|
||||
});
|
||||
|
||||
this.listen<EnvelopeDTO<MessageBoardItemDTO[]>>('messageBoard').subscribe((envelope) => {
|
||||
if (envelope.action === 'refresh') {
|
||||
this.refreshMessageBoardItems(envelope.target.area, envelope.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
notifications$ = merge(
|
||||
of(this._getNotifications()).pipe(filter((f) => !!f)),
|
||||
this.listen<EnvelopeDTO<MessageBoardItemDTO[]>>('messageBoard')
|
||||
).pipe(
|
||||
withLatestFrom(this.updateNotification$),
|
||||
map(([d, update]) => {
|
||||
const data = d;
|
||||
if (update && !!data && !data?.data?.find((message) => message?.category === 'ISA-Update')) {
|
||||
data.data.push(update);
|
||||
refreshMessageBoardItems(targetArea: string, messages: MessageBoardItemDTO[]) {
|
||||
const current = cloneDeep(this.messageBoardItems$.value);
|
||||
|
||||
current[targetArea] = messages ?? [];
|
||||
|
||||
this.messageBoardItems$.next(current);
|
||||
}
|
||||
|
||||
notifications$ = this.messageBoardItems$.asObservable().pipe(
|
||||
map((data) => {
|
||||
const messages = { ...data };
|
||||
const keys = Object.keys(data);
|
||||
for (let key of keys) {
|
||||
if (data[key].length === 0 || data[key] === undefined) {
|
||||
delete messages[key];
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}),
|
||||
tap((data) => this._storeNotifactions(data)),
|
||||
shareReplay(1)
|
||||
|
||||
return messages;
|
||||
})
|
||||
);
|
||||
|
||||
private _storeNotifactions(data: EnvelopeDTO<MessageBoardItemDTO[]>) {
|
||||
if (data) {
|
||||
sessionStorage.setItem(this.sessionStoragesessionStorageKey, JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
// notifications$ = merge(
|
||||
// of(this._getNotifications()).pipe(filter((f) => !!f)),
|
||||
// this.listen<EnvelopeDTO<MessageBoardItemDTO[]>>('messageBoard')
|
||||
// ).pipe(
|
||||
// withLatestFrom(this.updateNotification$),
|
||||
// map(([d, update]) => {
|
||||
// console.log('notifications$', d, update);
|
||||
// const data = d;
|
||||
// if (update && !!data && !data?.data?.find((message) => message?.category === 'ISA-Update')) {
|
||||
// data.data.push(update);
|
||||
// }
|
||||
// return data;
|
||||
// }),
|
||||
// tap((data) => this._storeNotifactions(data)),
|
||||
// shareReplay(1)
|
||||
// );
|
||||
|
||||
private _getNotifications(): EnvelopeDTO<MessageBoardItemDTO[]> {
|
||||
// private _storeNotifactions(data: EnvelopeDTO<MessageBoardItemDTO[]>) {
|
||||
// if (data) {
|
||||
// sessionStorage.setItem(this.sessionStoragesessionStorageKey, JSON.stringify(data));
|
||||
// }
|
||||
// }
|
||||
|
||||
// private _getNotifications(): EnvelopeDTO<MessageBoardItemDTO[]> {
|
||||
// const stringData = sessionStorage.getItem(this.sessionStoragesessionStorageKey);
|
||||
// if (stringData) {
|
||||
// return JSON.parse(stringData);
|
||||
// }
|
||||
// return undefined;
|
||||
// }
|
||||
|
||||
private _getNotifications(): Record<string, MessageBoardItemDTO[]> {
|
||||
const stringData = sessionStorage.getItem(this.sessionStoragesessionStorageKey);
|
||||
if (stringData) {
|
||||
return JSON.parse(stringData);
|
||||
}
|
||||
return undefined;
|
||||
return {};
|
||||
}
|
||||
|
||||
private _storeNotifactions(data: Record<string, MessageBoardItemDTO[]>) {
|
||||
if (data) {
|
||||
delete data['messageBoard/isa-update'];
|
||||
sessionStorage.setItem(this.sessionStoragesessionStorageKey, JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
|
||||
updateNotification() {
|
||||
this.updateNotification$.next({
|
||||
category: 'ISA-Update',
|
||||
type: 'update',
|
||||
headline: 'Update Benachrichtigung',
|
||||
text: 'Es steht eine aktuellere Version der ISA bereit. Bitte aktualisieren Sie die Anwendung.',
|
||||
});
|
||||
this.refreshMessageBoardItems('messageBoard/isa-update', [
|
||||
{
|
||||
category: 'ISA-Update',
|
||||
type: 'update',
|
||||
headline: 'Update Benachrichtigung',
|
||||
text: 'Es steht eine aktuellere Version der ISA bereit. Bitte aktualisieren Sie die Anwendung.',
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +107,25 @@ export function _notificationsHubOptionsFactory(config: Config, auth: AuthServic
|
||||
aliases: [
|
||||
{ alias: 'd-account', name: 'account' },
|
||||
{ alias: 'd-no-account', name: 'package-variant-closed' },
|
||||
{ name: 'isa-audio', alias: 'AU' },
|
||||
{ name: 'isa-audio', alias: 'CAS' },
|
||||
{ name: 'isa-audio', alias: 'DL' },
|
||||
{ name: 'isa-audio', alias: 'KAS' },
|
||||
{ name: 'isa-hard-cover', alias: 'BUCH' },
|
||||
{ name: 'isa-hard-cover', alias: 'GEB' },
|
||||
{ name: 'isa-hard-cover', alias: 'HC' },
|
||||
{ name: 'isa-hard-cover', alias: 'KT' },
|
||||
{ name: 'isa-ebook', alias: 'EB' },
|
||||
{ name: 'isa-non-book', alias: 'GLO' },
|
||||
{ name: 'isa-non-book', alias: 'HDL' },
|
||||
{ name: 'isa-non-book', alias: 'NB' },
|
||||
{ name: 'isa-non-book', alias: 'SPL' },
|
||||
{ name: 'isa-calendar', alias: 'KA' },
|
||||
{ name: 'isa-scroll', alias: 'MA' },
|
||||
{ name: 'isa-software', alias: 'SW' },
|
||||
{ name: 'isa-soft-cover', alias: 'TB' },
|
||||
{ name: 'isa-video', alias: 'VI' },
|
||||
{ name: 'isa-news-paper', alias: 'ZS' },
|
||||
],
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -52,11 +52,7 @@ export class IsAuthenticatedGuard implements CanActivate {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const result = await this._scanService
|
||||
.scan({
|
||||
exclude: ['Dev'],
|
||||
})
|
||||
?.toPromise();
|
||||
const result = await this._scanService.scan()?.toPromise();
|
||||
|
||||
if (typeof result === 'string') {
|
||||
try {
|
||||
|
||||
@@ -73,10 +73,10 @@
|
||||
<ui-icon icon="documents_refresh" size="24px"></ui-icon>
|
||||
Remission
|
||||
</a>
|
||||
<!-- <a [routerLink]="['/filiale/package-inspection']" routerLinkActive="active" (click)="fetchAndOpenPackages()">
|
||||
<a [routerLink]="['/filiale/package-inspection']" routerLinkActive="active" (click)="fetchAndOpenPackages()">
|
||||
<ui-svg-icon icon="clipboard-check-outline" [size]="24"></ui-svg-icon>
|
||||
Wareneingang
|
||||
</a> -->
|
||||
</a>
|
||||
</ng-container>
|
||||
</shell-footer>
|
||||
</div>
|
||||
|
||||
@@ -29,7 +29,9 @@ export class ShellComponent {
|
||||
|
||||
notifications$ = this._notificationsHub.notifications$;
|
||||
|
||||
notificationCount$ = this.notifications$.pipe(map((message) => message?.data?.length));
|
||||
notificationCount$ = this.notifications$.pipe(
|
||||
map((notifications) => Object.values(notifications).reduce((acc, val) => acc + val?.length ?? 0, 0))
|
||||
);
|
||||
|
||||
get activatedProcessId$() {
|
||||
return this._appService.getActivatedProcessId$().pipe(
|
||||
|
||||
405
apps/isa-app/src/assets/icons.json
Normal file
405
apps/isa-app/src/assets/icons.json
Normal file
File diff suppressed because one or more lines are too long
11
apps/isa-app/src/assets/images/Icon_DR.svg
Normal file
11
apps/isa-app/src/assets/images/Icon_DR.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="22px" height="18px" viewBox="0 0 22 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 52.2 (67145) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Icon_HC</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Hugendubel_Icons" transform="translate(-29.000000, -177.000000)" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.3">
|
||||
<path d="M32.725699,178.000628 C32.7430505,177.999791 32.7604307,177.999791 32.7777823,178.000628 L37.5260449,178.000628 C38.53109,178.000628 39.44018,178.547926 40.0000026,179.340692 C40.5598253,178.547926 41.4689153,178.000628 42.4739603,178.000628 L47.222223,178.000628 C47.529035,178.00066 47.7777477,178.256627 47.7777784,178.572389 L47.7777784,179.71591 L49.4444446,179.71591 C49.7512567,179.715942 49.9999694,179.971909 50,180.287671 L50,192.008763 C49.9999694,192.324524 49.7512567,192.580492 49.4444446,192.580523 L42.4739603,192.580523 C41.4766486,192.580523 40.8524541,192.949423 40.4947942,193.688309 C40.3998428,193.879608 40.208727,194 40.0000026,194 C39.7912783,194 39.6001624,193.879608 39.5052111,193.688309 C39.1475512,192.949423 38.5233566,192.580523 37.5260449,192.580523 L30.5555607,192.580523 C30.2487486,192.580492 30.0000359,192.324524 30.0000053,192.008763 L30.0000053,180.287671 C29.9987652,179.991708 30.2171687,179.743681 30.5034773,179.71591 C30.5208289,179.715072 30.5382091,179.715072 30.5555607,179.71591 L32.2222269,179.71591 L32.2222269,178.572389 C32.2209869,178.276426 32.4393904,178.028399 32.725699,178.000628 Z M33.3333377,179.14415 L33.3333377,189.43584 L36.6232674,189.43584 C37.6190746,189.43584 38.5547188,189.729711 39.2621556,190.356017 C39.3270606,190.413476 39.3849347,190.480265 39.4444472,190.543626 L39.4444472,180.957703 C39.4433388,180.936873 39.4433388,180.915996 39.4444472,180.895166 C39.4444472,180.068361 38.4768339,179.14415 37.5260449,179.14415 L33.3333377,179.14415 Z M42.4739603,179.14415 C41.5231714,179.14415 40.555558,180.068361 40.555558,180.895166 C40.5555806,180.898144 40.5555806,180.901122 40.555558,180.9041 L40.555558,190.543626 C40.6150705,190.480265 40.6729447,190.413476 40.7378497,190.356017 C41.4452864,189.729711 42.3809306,189.43584 43.3767379,189.43584 L46.6666675,189.43584 L46.6666675,179.14415 L42.4739603,179.14415 Z M31.1111161,180.859431 L31.1111161,191.437002 L37.5260449,191.437002 C38.0365968,191.437002 38.5189494,191.531483 38.9496557,191.713949 C38.8273679,191.527334 38.6888269,191.36055 38.5329891,191.222592 C38.0547048,190.799175 37.405738,190.579361 36.6232674,190.579361 L32.7777823,190.579361 C32.4709702,190.57933 32.2222575,190.323362 32.2222269,190.007601 L32.2222269,180.859431 L31.1111161,180.859431 Z M47.7777784,180.859431 L47.7777784,190.007601 C47.7777477,190.323362 47.529035,190.57933 47.222223,190.579361 L43.3767379,190.579361 C42.5942672,190.579361 41.9453004,190.799175 41.4670161,191.222592 C41.3107359,191.360944 41.1725734,191.526903 41.0503496,191.713949 C41.4810558,191.531483 41.9634085,191.437002 42.4739603,191.437002 L48.8888892,191.437002 L48.8888892,180.859431 L47.7777784,180.859431 Z M35.5,182.116677 L37.5,182.116677 C37.7761424,182.116677 38,182.340535 38,182.616677 L38,182.645847 C38,182.921989 37.7761424,183.145847 37.5,183.145847 L35.5,183.145847 C35.2238576,183.145847 35,182.921989 35,182.645847 L35,182.616677 C35,182.340535 35.2238576,182.116677 35.5,182.116677 Z M35.5,184.175016 L37.5,184.175016 C37.7761424,184.175016 38,184.398874 38,184.675016 L38,184.704185 C38,184.980328 37.7761424,185.204185 37.5,185.204185 L35.5,185.204185 C35.2238576,185.204185 35,184.980328 35,184.704185 L35,184.675016 C35,184.398874 35.2238576,184.175016 35.5,184.175016 Z M35.5,186.233355 L37.5,186.233355 C37.7761424,186.233355 38,186.457212 38,186.733355 L38,186.762524 C38,187.038666 37.7761424,187.262524 37.5,187.262524 L35.5,187.262524 C35.2238576,187.262524 35,187.038666 35,186.762524 L35,186.733355 C35,186.457212 35.2238576,186.233355 35.5,186.233355 Z M42.5,182.116677 L44.5,182.116677 C44.7761424,182.116677 45,182.340535 45,182.616677 L45,182.645847 C45,182.921989 44.7761424,183.145847 44.5,183.145847 L42.5,183.145847 C42.2238576,183.145847 42,182.921989 42,182.645847 L42,182.616677 C42,182.340535 42.2238576,182.116677 42.5,182.116677 Z M42.5,184.175016 L44.5,184.175016 C44.7761424,184.175016 45,184.398874 45,184.675016 L45,184.704185 C45,184.980328 44.7761424,185.204185 44.5,185.204185 L42.5,185.204185 C42.2238576,185.204185 42,184.980328 42,184.704185 L42,184.675016 C42,184.398874 42.2238576,184.175016 42.5,184.175016 Z M42.5,186.233355 L44.5,186.233355 C44.7761424,186.233355 45,186.457212 45,186.733355 L45,186.762524 C45,187.038666 44.7761424,187.262524 44.5,187.262524 L42.5,187.262524 C42.2238576,187.262524 42,187.038666 42,186.762524 L42,186.733355 C42,186.457212 42.2238576,186.233355 42.5,186.233355 Z" id="Icon_HC"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.0 KiB |
11
apps/isa-app/src/assets/images/Icon_GEH.svg
Normal file
11
apps/isa-app/src/assets/images/Icon_GEH.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="22px" height="18px" viewBox="0 0 22 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 52.2 (67145) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Icon_HC</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Hugendubel_Icons" transform="translate(-29.000000, -177.000000)" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.3">
|
||||
<path d="M32.725699,178.000628 C32.7430505,177.999791 32.7604307,177.999791 32.7777823,178.000628 L37.5260449,178.000628 C38.53109,178.000628 39.44018,178.547926 40.0000026,179.340692 C40.5598253,178.547926 41.4689153,178.000628 42.4739603,178.000628 L47.222223,178.000628 C47.529035,178.00066 47.7777477,178.256627 47.7777784,178.572389 L47.7777784,179.71591 L49.4444446,179.71591 C49.7512567,179.715942 49.9999694,179.971909 50,180.287671 L50,192.008763 C49.9999694,192.324524 49.7512567,192.580492 49.4444446,192.580523 L42.4739603,192.580523 C41.4766486,192.580523 40.8524541,192.949423 40.4947942,193.688309 C40.3998428,193.879608 40.208727,194 40.0000026,194 C39.7912783,194 39.6001624,193.879608 39.5052111,193.688309 C39.1475512,192.949423 38.5233566,192.580523 37.5260449,192.580523 L30.5555607,192.580523 C30.2487486,192.580492 30.0000359,192.324524 30.0000053,192.008763 L30.0000053,180.287671 C29.9987652,179.991708 30.2171687,179.743681 30.5034773,179.71591 C30.5208289,179.715072 30.5382091,179.715072 30.5555607,179.71591 L32.2222269,179.71591 L32.2222269,178.572389 C32.2209869,178.276426 32.4393904,178.028399 32.725699,178.000628 Z M33.3333377,179.14415 L33.3333377,189.43584 L36.6232674,189.43584 C37.6190746,189.43584 38.5547188,189.729711 39.2621556,190.356017 C39.3270606,190.413476 39.3849347,190.480265 39.4444472,190.543626 L39.4444472,180.957703 C39.4433388,180.936873 39.4433388,180.915996 39.4444472,180.895166 C39.4444472,180.068361 38.4768339,179.14415 37.5260449,179.14415 L33.3333377,179.14415 Z M42.4739603,179.14415 C41.5231714,179.14415 40.555558,180.068361 40.555558,180.895166 C40.5555806,180.898144 40.5555806,180.901122 40.555558,180.9041 L40.555558,190.543626 C40.6150705,190.480265 40.6729447,190.413476 40.7378497,190.356017 C41.4452864,189.729711 42.3809306,189.43584 43.3767379,189.43584 L46.6666675,189.43584 L46.6666675,179.14415 L42.4739603,179.14415 Z M31.1111161,180.859431 L31.1111161,191.437002 L37.5260449,191.437002 C38.0365968,191.437002 38.5189494,191.531483 38.9496557,191.713949 C38.8273679,191.527334 38.6888269,191.36055 38.5329891,191.222592 C38.0547048,190.799175 37.405738,190.579361 36.6232674,190.579361 L32.7777823,190.579361 C32.4709702,190.57933 32.2222575,190.323362 32.2222269,190.007601 L32.2222269,180.859431 L31.1111161,180.859431 Z M47.7777784,180.859431 L47.7777784,190.007601 C47.7777477,190.323362 47.529035,190.57933 47.222223,190.579361 L43.3767379,190.579361 C42.5942672,190.579361 41.9453004,190.799175 41.4670161,191.222592 C41.3107359,191.360944 41.1725734,191.526903 41.0503496,191.713949 C41.4810558,191.531483 41.9634085,191.437002 42.4739603,191.437002 L48.8888892,191.437002 L48.8888892,180.859431 L47.7777784,180.859431 Z M35.5,182.116677 L37.5,182.116677 C37.7761424,182.116677 38,182.340535 38,182.616677 L38,182.645847 C38,182.921989 37.7761424,183.145847 37.5,183.145847 L35.5,183.145847 C35.2238576,183.145847 35,182.921989 35,182.645847 L35,182.616677 C35,182.340535 35.2238576,182.116677 35.5,182.116677 Z M35.5,184.175016 L37.5,184.175016 C37.7761424,184.175016 38,184.398874 38,184.675016 L38,184.704185 C38,184.980328 37.7761424,185.204185 37.5,185.204185 L35.5,185.204185 C35.2238576,185.204185 35,184.980328 35,184.704185 L35,184.675016 C35,184.398874 35.2238576,184.175016 35.5,184.175016 Z M35.5,186.233355 L37.5,186.233355 C37.7761424,186.233355 38,186.457212 38,186.733355 L38,186.762524 C38,187.038666 37.7761424,187.262524 37.5,187.262524 L35.5,187.262524 C35.2238576,187.262524 35,187.038666 35,186.762524 L35,186.733355 C35,186.457212 35.2238576,186.233355 35.5,186.233355 Z M42.5,182.116677 L44.5,182.116677 C44.7761424,182.116677 45,182.340535 45,182.616677 L45,182.645847 C45,182.921989 44.7761424,183.145847 44.5,183.145847 L42.5,183.145847 C42.2238576,183.145847 42,182.921989 42,182.645847 L42,182.616677 C42,182.340535 42.2238576,182.116677 42.5,182.116677 Z M42.5,184.175016 L44.5,184.175016 C44.7761424,184.175016 45,184.398874 45,184.675016 L45,184.704185 C45,184.980328 44.7761424,185.204185 44.5,185.204185 L42.5,185.204185 C42.2238576,185.204185 42,184.980328 42,184.704185 L42,184.675016 C42,184.398874 42.2238576,184.175016 42.5,184.175016 Z M42.5,186.233355 L44.5,186.233355 C44.7761424,186.233355 45,186.457212 45,186.733355 L45,186.762524 C45,187.038666 44.7761424,187.262524 44.5,187.262524 L42.5,187.262524 C42.2238576,187.262524 42,187.038666 42,186.762524 L42,186.733355 C42,186.457212 42.2238576,186.233355 42.5,186.233355 Z" id="Icon_HC"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.0 KiB |
11
apps/isa-app/src/assets/images/Icon_PP.svg
Normal file
11
apps/isa-app/src/assets/images/Icon_PP.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="22px" height="18px" viewBox="0 0 22 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 52.2 (67145) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Icon_HC</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Hugendubel_Icons" transform="translate(-29.000000, -177.000000)" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.3">
|
||||
<path d="M32.725699,178.000628 C32.7430505,177.999791 32.7604307,177.999791 32.7777823,178.000628 L37.5260449,178.000628 C38.53109,178.000628 39.44018,178.547926 40.0000026,179.340692 C40.5598253,178.547926 41.4689153,178.000628 42.4739603,178.000628 L47.222223,178.000628 C47.529035,178.00066 47.7777477,178.256627 47.7777784,178.572389 L47.7777784,179.71591 L49.4444446,179.71591 C49.7512567,179.715942 49.9999694,179.971909 50,180.287671 L50,192.008763 C49.9999694,192.324524 49.7512567,192.580492 49.4444446,192.580523 L42.4739603,192.580523 C41.4766486,192.580523 40.8524541,192.949423 40.4947942,193.688309 C40.3998428,193.879608 40.208727,194 40.0000026,194 C39.7912783,194 39.6001624,193.879608 39.5052111,193.688309 C39.1475512,192.949423 38.5233566,192.580523 37.5260449,192.580523 L30.5555607,192.580523 C30.2487486,192.580492 30.0000359,192.324524 30.0000053,192.008763 L30.0000053,180.287671 C29.9987652,179.991708 30.2171687,179.743681 30.5034773,179.71591 C30.5208289,179.715072 30.5382091,179.715072 30.5555607,179.71591 L32.2222269,179.71591 L32.2222269,178.572389 C32.2209869,178.276426 32.4393904,178.028399 32.725699,178.000628 Z M33.3333377,179.14415 L33.3333377,189.43584 L36.6232674,189.43584 C37.6190746,189.43584 38.5547188,189.729711 39.2621556,190.356017 C39.3270606,190.413476 39.3849347,190.480265 39.4444472,190.543626 L39.4444472,180.957703 C39.4433388,180.936873 39.4433388,180.915996 39.4444472,180.895166 C39.4444472,180.068361 38.4768339,179.14415 37.5260449,179.14415 L33.3333377,179.14415 Z M42.4739603,179.14415 C41.5231714,179.14415 40.555558,180.068361 40.555558,180.895166 C40.5555806,180.898144 40.5555806,180.901122 40.555558,180.9041 L40.555558,190.543626 C40.6150705,190.480265 40.6729447,190.413476 40.7378497,190.356017 C41.4452864,189.729711 42.3809306,189.43584 43.3767379,189.43584 L46.6666675,189.43584 L46.6666675,179.14415 L42.4739603,179.14415 Z M31.1111161,180.859431 L31.1111161,191.437002 L37.5260449,191.437002 C38.0365968,191.437002 38.5189494,191.531483 38.9496557,191.713949 C38.8273679,191.527334 38.6888269,191.36055 38.5329891,191.222592 C38.0547048,190.799175 37.405738,190.579361 36.6232674,190.579361 L32.7777823,190.579361 C32.4709702,190.57933 32.2222575,190.323362 32.2222269,190.007601 L32.2222269,180.859431 L31.1111161,180.859431 Z M47.7777784,180.859431 L47.7777784,190.007601 C47.7777477,190.323362 47.529035,190.57933 47.222223,190.579361 L43.3767379,190.579361 C42.5942672,190.579361 41.9453004,190.799175 41.4670161,191.222592 C41.3107359,191.360944 41.1725734,191.526903 41.0503496,191.713949 C41.4810558,191.531483 41.9634085,191.437002 42.4739603,191.437002 L48.8888892,191.437002 L48.8888892,180.859431 L47.7777784,180.859431 Z M35.5,182.116677 L37.5,182.116677 C37.7761424,182.116677 38,182.340535 38,182.616677 L38,182.645847 C38,182.921989 37.7761424,183.145847 37.5,183.145847 L35.5,183.145847 C35.2238576,183.145847 35,182.921989 35,182.645847 L35,182.616677 C35,182.340535 35.2238576,182.116677 35.5,182.116677 Z M35.5,184.175016 L37.5,184.175016 C37.7761424,184.175016 38,184.398874 38,184.675016 L38,184.704185 C38,184.980328 37.7761424,185.204185 37.5,185.204185 L35.5,185.204185 C35.2238576,185.204185 35,184.980328 35,184.704185 L35,184.675016 C35,184.398874 35.2238576,184.175016 35.5,184.175016 Z M35.5,186.233355 L37.5,186.233355 C37.7761424,186.233355 38,186.457212 38,186.733355 L38,186.762524 C38,187.038666 37.7761424,187.262524 37.5,187.262524 L35.5,187.262524 C35.2238576,187.262524 35,187.038666 35,186.762524 L35,186.733355 C35,186.457212 35.2238576,186.233355 35.5,186.233355 Z M42.5,182.116677 L44.5,182.116677 C44.7761424,182.116677 45,182.340535 45,182.616677 L45,182.645847 C45,182.921989 44.7761424,183.145847 44.5,183.145847 L42.5,183.145847 C42.2238576,183.145847 42,182.921989 42,182.645847 L42,182.616677 C42,182.340535 42.2238576,182.116677 42.5,182.116677 Z M42.5,184.175016 L44.5,184.175016 C44.7761424,184.175016 45,184.398874 45,184.675016 L45,184.704185 C45,184.980328 44.7761424,185.204185 44.5,185.204185 L42.5,185.204185 C42.2238576,185.204185 42,184.980328 42,184.704185 L42,184.675016 C42,184.398874 42.2238576,184.175016 42.5,184.175016 Z M42.5,186.233355 L44.5,186.233355 C44.7761424,186.233355 45,186.457212 45,186.733355 L45,186.762524 C45,187.038666 44.7761424,187.262524 44.5,187.262524 L42.5,187.262524 C42.2238576,187.262524 42,187.038666 42,186.762524 L42,186.733355 C42,186.457212 42.2238576,186.233355 42.5,186.233355 Z" id="Icon_HC"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.0 KiB |
@@ -41,7 +41,7 @@
|
||||
"rootUrl": "https://filialinformationsystem-test.paragon-systems.de/eiswebapi/v1"
|
||||
},
|
||||
"@swagger/remi": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/inv/v1"
|
||||
"rootUrl": "https://isa-test.paragon-data.net/inv/v6"
|
||||
},
|
||||
"@swagger/wws": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/wws/v1"
|
||||
@@ -69,6 +69,6 @@
|
||||
},
|
||||
"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=="
|
||||
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@
|
||||
"rootUrl": "https://filialinformationsystem-integration.paragon-systems.de/eiswebapi/v1"
|
||||
},
|
||||
"@swagger/remi": {
|
||||
"rootUrl": "https://isa-integration.paragon-data.net/inv/v1"
|
||||
"rootUrl": "https://isa-integration.paragon-data.net/inv/v6"
|
||||
},
|
||||
"@swagger/wws": {
|
||||
"rootUrl": "https://isa-integration.paragon-data.net/wws/v1"
|
||||
@@ -68,6 +68,6 @@
|
||||
},
|
||||
"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=="
|
||||
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@
|
||||
"rootUrl": "https://filialinformationsystem-test.paragon-systems.de/eiswebapi/v1"
|
||||
},
|
||||
"@swagger/remi": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/inv/v1"
|
||||
"rootUrl": "https://isa-test.paragon-data.net/inv/v6"
|
||||
},
|
||||
"@swagger/wws": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/wws/v1"
|
||||
@@ -70,6 +70,6 @@
|
||||
},
|
||||
"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=="
|
||||
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@
|
||||
"rootUrl": "https://filialinformationsystem.paragon-systems.de/eiswebapi/v1"
|
||||
},
|
||||
"@swagger/remi": {
|
||||
"rootUrl": "https://isa.paragon-systems.de/inv/v1"
|
||||
"rootUrl": "https://isa.paragon-systems.de/inv/v6"
|
||||
},
|
||||
"@swagger/wws": {
|
||||
"rootUrl": "https://isa.paragon-systems.de/wws/v1"
|
||||
@@ -69,6 +69,6 @@
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "AfHi/mY+RbwJD5nC7SuWn3I14pFUOfSbQ2QG//4aV3zWQjwix30kHqsqraA8ZiipDBql8YlwIyV6VPBMUiAX4s9YHDxHHsWwq2BUB3ImzDEcU1jmMH/5yakGUYpCQ68D0iZ8SG9sS0QBb3iFdCHc1r9DFr1cMTxM7zOvb/AUoIVmieHZXnx9ioUgCvczsLiuX3hwvTW3lhbvJ4uUyqTWK4sWFVwoY4AIWSFrPwwrkV2DksMKT5fMJT3GWgPypvTIGwWvpRfLWwKlc1Z3ckyb84khsnaWD2wr+hdgu/K8YIMmgGszm5KIZ/G05YfDNZtQ4jby+5RZvQwWR8rxM35rJgf73OkMSpuL9jw3T0TTAlvpkGRLzVVuCw9VjlBLqfPNEZ6VsEwFuAla9IYUvFHCsjypg2J6UpxHXrTYmbsSu5Jm8frVfS5znPPTO9D/4rF6ZVv2PxY9PgUgJUvwMa/VMc/nse3RRRf8RGT4rUItfJDFO8pujD76vVEWq/KixQRoMdLgDLyxhsFVftkxqhZhyEfFZzsEy49LSojJ28vpHpBWLeCQBmnZ7JZ4C5yOQiqSQV/assBq2zJN2q+vCDp8qy5j1rED1SX5Ec7JpgpgnU4chLIf5Zn7bP/hNGT3pEYBuXeDXXN8ke1pcc3fc3m0FysDG0o56XVCUqImZ8Ezi8eujZciKDrWbtljhKTj7cnfuJx0sVHF6Bh5i4YfgA/Z+NL+MtH2EVIF67e6hEz6PWYTcoh3ybBaJfxb2FNvGJutNKg04GwMhYq6K2IddBt0fDiBt0SGM0oSBlUP3DKCUmXcf2a6ASbrcqv6Wz1jHt0pY4U8bEpg7qSbW3VDyvdPgyQ="
|
||||
"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="
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@
|
||||
"rootUrl": "https://filialinformationsystem-staging.paragon-systems.de/eiswebapi/v1"
|
||||
},
|
||||
"@swagger/remi": {
|
||||
"rootUrl": "https://isa-staging.paragon-systems.de/inv/v1"
|
||||
"rootUrl": "https://isa-staging.paragon-systems.de/inv/v6"
|
||||
},
|
||||
"@swagger/wws": {
|
||||
"rootUrl": "https://isa-staging.paragon-systems.de/wws/v1"
|
||||
@@ -69,6 +69,6 @@
|
||||
},
|
||||
"checkForUpdates": 3600000,
|
||||
"licence": {
|
||||
"scandit": "AfHi/mY+RbwJD5nC7SuWn3I14pFUOfSbQ2QG//4aV3zWQjwix30kHqsqraA8ZiipDBql8YlwIyV6VPBMUiAX4s9YHDxHHsWwq2BUB3ImzDEcU1jmMH/5yakGUYpCQ68D0iZ8SG9sS0QBb3iFdCHc1r9DFr1cMTxM7zOvb/AUoIVmieHZXnx9ioUgCvczsLiuX3hwvTW3lhbvJ4uUyqTWK4sWFVwoY4AIWSFrPwwrkV2DksMKT5fMJT3GWgPypvTIGwWvpRfLWwKlc1Z3ckyb84khsnaWD2wr+hdgu/K8YIMmgGszm5KIZ/G05YfDNZtQ4jby+5RZvQwWR8rxM35rJgf73OkMSpuL9jw3T0TTAlvpkGRLzVVuCw9VjlBLqfPNEZ6VsEwFuAla9IYUvFHCsjypg2J6UpxHXrTYmbsSu5Jm8frVfS5znPPTO9D/4rF6ZVv2PxY9PgUgJUvwMa/VMc/nse3RRRf8RGT4rUItfJDFO8pujD76vVEWq/KixQRoMdLgDLyxhsFVftkxqhZhyEfFZzsEy49LSojJ28vpHpBWLeCQBmnZ7JZ4C5yOQiqSQV/assBq2zJN2q+vCDp8qy5j1rED1SX5Ec7JpgpgnU4chLIf5Zn7bP/hNGT3pEYBuXeDXXN8ke1pcc3fc3m0FysDG0o56XVCUqImZ8Ezi8eujZciKDrWbtljhKTj7cnfuJx0sVHF6Bh5i4YfgA/Z+NL+MtH2EVIF67e6hEz6PWYTcoh3ybBaJfxb2FNvGJutNKg04GwMhYq6K2IddBt0fDiBt0SGM0oSBlUP3DKCUmXcf2a6ASbrcqv6Wz1jHt0pY4U8bEpg7qSbW3VDyvdPgyQ="
|
||||
"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="
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@
|
||||
"rootUrl": "https://filialinformationsystem-test.paragon-systems.de/eiswebapi/v1"
|
||||
},
|
||||
"@swagger/remi": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/inv/v1"
|
||||
"rootUrl": "https://isa-test.paragon-data.net/inv/v6"
|
||||
},
|
||||
"@swagger/wws": {
|
||||
"rootUrl": "https://isa-test.paragon-data.net/wws/v1"
|
||||
@@ -70,6 +70,6 @@
|
||||
},
|
||||
"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=="
|
||||
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
<div class="notification-headline">
|
||||
<h1>{{ item.headline }}</h1>
|
||||
<button class="notification-edit-cta" (click)="itemSelected.emit(item)">
|
||||
Bearbeiten
|
||||
</button>
|
||||
<div class="grid grid-cols-[1fr_auto] items-center gap-4">
|
||||
<div class="grid grid-flow-row gap-4">
|
||||
<h1 class="text-left font-bold text-lg">{{ item.headline }}</h1>
|
||||
<div class="notification-text">{{ item.text }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<button *ngIf="editButton" class="notification-edit-cta text-brand font-bold text-lg px-4 py-3" (click)="itemSelected.emit(item)">
|
||||
{{ editButtonLabel }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="notification-text">{{ item.text }}</div>
|
||||
|
||||
@@ -13,5 +13,11 @@ export class ModalNotificationsListItemComponent {
|
||||
@Output()
|
||||
itemSelected = new EventEmitter<MessageBoardItemDTO>();
|
||||
|
||||
@Input()
|
||||
editButton = true;
|
||||
|
||||
@Input()
|
||||
editButtonLabel = 'Bearbeiten';
|
||||
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<div class="notification-list scroll-bar">
|
||||
<ng-container *ngFor="let notification of notifications">
|
||||
<modal-notifications-list-item
|
||||
(click)="itemSelected(notification)"
|
||||
[editButtonLabel]="'Packstück-Prüfung'"
|
||||
[item]="notification"
|
||||
(itemSelected)="itemSelected($event)"
|
||||
></modal-notifications-list-item>
|
||||
<hr />
|
||||
</ng-container>
|
||||
</div>
|
||||
@@ -0,0 +1,101 @@
|
||||
import { createComponentFactory, Spectator, SpyObject } from '@ngneat/spectator';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { Router } from '@angular/router';
|
||||
import { UiFilter } from '@ui/filter';
|
||||
import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
|
||||
import { Component } from '@angular/core';
|
||||
import { ModalNotificationsListItemComponent } from '../notifications-list-item/notifications-list-item.component';
|
||||
import { ModalNotificationsRemissionGroupComponent } from './notifications-remission-group.component';
|
||||
|
||||
// DummyComponent Class
|
||||
@Component({
|
||||
selector: 'dummy-component',
|
||||
template: '<div></div>',
|
||||
})
|
||||
class DummyComponent {
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
describe('ModalNotificationsRemissionGroupComponent', () => {
|
||||
let spectator: Spectator<ModalNotificationsRemissionGroupComponent>;
|
||||
let uiFilterMock: SpyObject<UiFilter>;
|
||||
let router: Router;
|
||||
|
||||
const createComponent = createComponentFactory({
|
||||
component: ModalNotificationsRemissionGroupComponent,
|
||||
declarations: [ModalNotificationsListItemComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterTestingModule.withRoutes([
|
||||
{ path: 'filiale/goods/in/results', component: DummyComponent },
|
||||
{ path: 'filiale/remission/create', component: DummyComponent },
|
||||
]),
|
||||
UiIconModule,
|
||||
],
|
||||
providers: [],
|
||||
mocks: [UiFilter],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
spectator = createComponent({ props: { notifications: [] } });
|
||||
router = spectator.inject(Router);
|
||||
uiFilterMock = spectator.inject(UiFilter);
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(spectator.component).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('notifications input', () => {
|
||||
it('should display the right notification-counter value based on the length of the input array', () => {
|
||||
spectator.setInput({ notifications: [{}, {}, {}] });
|
||||
expect(spectator.query('.notification-counter')).toHaveText('3');
|
||||
});
|
||||
|
||||
it('should not display notification-counter if input array has length 0', () => {
|
||||
spectator.setInput({ notifications: [] });
|
||||
expect(spectator.query('.notification-counter')).toHaveText('');
|
||||
});
|
||||
|
||||
it('should render modal-notifications-list-item based on the input array', () => {
|
||||
const notifications = [{}, {}];
|
||||
spectator.setInput({ notifications });
|
||||
spectator.detectComponentChanges();
|
||||
expect(spectator.queryAll('modal-notifications-list-item')).toHaveLength(notifications.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe('itemSelected()', () => {
|
||||
it('should navigate to results with queryParams from UiFilter.getQueryParamsFromQueryTokenDTO()', () => {
|
||||
const item: MessageBoardItemDTO = { queryToken: { input: { main_qs: 'test' } } };
|
||||
spyOn(UiFilter, 'getQueryParamsFromQueryTokenDTO').and.returnValue(item.queryToken.input);
|
||||
spyOn(router, 'navigate');
|
||||
spectator.component.itemSelected(item);
|
||||
expect(router.navigate).toHaveBeenCalledWith(['/filiale/goods/in/results'], { queryParams: item.queryToken.input });
|
||||
});
|
||||
|
||||
it('should emit the navigated event after select item', () => {
|
||||
const item: MessageBoardItemDTO = { queryToken: { input: { main_qs: 'test' } } };
|
||||
spyOn(spectator.component.navigated, 'emit');
|
||||
spectator.component.itemSelected(item);
|
||||
expect(spectator.component.navigated.emit).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('actions CTA', () => {
|
||||
it('should navigate to remission page after clicking the CTA', () => {
|
||||
const cta = spectator.query('.cta-primary');
|
||||
expect(cta).toHaveText('Zur Remission');
|
||||
expect(cta).toHaveAttribute('href', '/filiale/remission/create');
|
||||
});
|
||||
|
||||
it('should emit the navigated event after clicking the CTA', () => {
|
||||
const cta = spectator.query('.cta-primary') as HTMLAnchorElement;
|
||||
spyOn(spectator.component.navigated, 'emit');
|
||||
spectator.click(cta);
|
||||
expect(spectator.component.navigated.emit).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
|
||||
|
||||
@Component({
|
||||
selector: 'modal-notifications-package-inspection-group',
|
||||
templateUrl: 'notifications-package-inspection-group.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ModalNotificationsPackageInspectionGroupComponent {
|
||||
@Input()
|
||||
notifications: MessageBoardItemDTO[];
|
||||
|
||||
@Output()
|
||||
navigated = new EventEmitter<void>();
|
||||
|
||||
constructor(private _router: Router) {}
|
||||
|
||||
itemSelected(item: MessageBoardItemDTO) {
|
||||
this._router.navigate(['/filiale/package-inspection/packages']);
|
||||
this.navigated.emit();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,3 @@
|
||||
<div class="header">
|
||||
<div class="notification-icon">
|
||||
<span class="notification-counter">{{ notifications.length }}</span>
|
||||
<ui-icon icon="notification" size="26px"></ui-icon>
|
||||
</div>
|
||||
|
||||
<h2>Remission</h2>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<div class="notification-list scroll-bar">
|
||||
<ng-container *ngFor="let notification of notifications">
|
||||
<modal-notifications-list-item [item]="notification" (itemSelected)="itemSelected($event)"></modal-notifications-list-item>
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
<div class="header">
|
||||
<div class="notification-icon">
|
||||
<div class="notification-counter">{{ notifications.length }}</div>
|
||||
<ui-icon icon="notification" size="26px"></ui-icon>
|
||||
</div>
|
||||
|
||||
<h2>Reservierungsanfragen</h2>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<div class="notification-list scroll-bar">
|
||||
<ng-container *ngFor="let notification of notifications">
|
||||
<modal-notifications-list-item [item]="notification" (itemSelected)="itemSelected($event)"></modal-notifications-list-item>
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
<div class="header">
|
||||
<div class="notification-icon">
|
||||
<span class="notification-counter">{{ notifications.length }}</span>
|
||||
<ui-icon icon="notification" size="26px"></ui-icon>
|
||||
</div>
|
||||
|
||||
<h2>Tätigkeitskalender</h2>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<div class="notification-list scroll-bar">
|
||||
<ng-container *ngFor="let notification of notifications">
|
||||
<modal-notifications-list-item [item]="notification" (itemSelected)="itemSelected($event)"></modal-notifications-list-item>
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
<div class="header">
|
||||
<div class="notification-icon">
|
||||
<span class="notification-counter">{{ notifications.length }}</span>
|
||||
<ui-icon icon="notification" size="26px"></ui-icon>
|
||||
</div>
|
||||
|
||||
<h2>ISA-Update</h2>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<div class="notification-list scroll-bar">
|
||||
<ng-container *ngFor="let notification of notifications">
|
||||
<div class="notification-headline">
|
||||
|
||||
@@ -1,34 +1,39 @@
|
||||
<h1>Sie haben neue Nachrichten</h1>
|
||||
|
||||
<ng-container *ngFor="let notification of groupedNotifications$ | async">
|
||||
<button
|
||||
*ngIf="notification.group !== (activeCard$ | async)"
|
||||
type="button"
|
||||
class="notification-card"
|
||||
(click)="activeCard = notification.group"
|
||||
>
|
||||
{{ notification.group }}
|
||||
<ng-container *ngFor="let notification of notifications$ | async | keyvalue">
|
||||
<button type="button" class="notification-card" (click)="selectArea(notification.key)">
|
||||
<div class="notification-icon">
|
||||
<div class="notification-counter">{{ notification.value?.length }}</div>
|
||||
<ui-icon icon="notification" size="26px"></ui-icon>
|
||||
</div>
|
||||
<span>{{ notification.value?.[0]?.category }}</span>
|
||||
</button>
|
||||
</ng-container>
|
||||
|
||||
<ng-container [ngSwitch]="activeCard$ | async">
|
||||
<modal-notifications-update-group
|
||||
*ngSwitchCase="'ISA-Update'"
|
||||
[notifications]="activeNotifications$ | async"
|
||||
></modal-notifications-update-group>
|
||||
<modal-notifications-reservation-group
|
||||
*ngSwitchCase="'Reservierungsanfragen'"
|
||||
[notifications]="activeNotifications$ | async"
|
||||
(navigated)="close()"
|
||||
></modal-notifications-reservation-group>
|
||||
<modal-notifications-remission-group
|
||||
*ngSwitchCase="'Remission'"
|
||||
[notifications]="activeNotifications$ | async"
|
||||
(navigated)="close()"
|
||||
></modal-notifications-remission-group>
|
||||
<modal-notifications-task-calendar-group
|
||||
*ngSwitchCase="'Tätigkeitskalender'"
|
||||
[notifications]="activeNotifications$ | async"
|
||||
(navigated)="close()"
|
||||
></modal-notifications-task-calendar-group>
|
||||
<hr class="-mx-4" />
|
||||
<ng-container *ngIf="notification.key === selectedArea" [ngSwitch]="notification.value?.[0]?.category">
|
||||
<modal-notifications-update-group
|
||||
*ngSwitchCase="'ISA-Update'"
|
||||
[notifications]="notifications[selectedArea]"
|
||||
></modal-notifications-update-group>
|
||||
<modal-notifications-reservation-group
|
||||
*ngSwitchCase="'Reservierungsanfragen'"
|
||||
[notifications]="notifications[selectedArea]"
|
||||
(navigated)="close()"
|
||||
></modal-notifications-reservation-group>
|
||||
<modal-notifications-remission-group
|
||||
*ngSwitchCase="'Remission'"
|
||||
[notifications]="notifications[selectedArea]"
|
||||
(navigated)="close()"
|
||||
></modal-notifications-remission-group>
|
||||
<modal-notifications-task-calendar-group
|
||||
*ngSwitchCase="'Tätigkeitskalender'"
|
||||
[notifications]="notifications[selectedArea]"
|
||||
(navigated)="close()"
|
||||
></modal-notifications-task-calendar-group>
|
||||
<modal-notifications-package-inspection-group
|
||||
*ngSwitchCase="'Wareneingang Lagerware'"
|
||||
[notifications]="notifications[selectedArea]"
|
||||
(navigated)="close()"
|
||||
>
|
||||
</modal-notifications-package-inspection-group>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
@@ -2,46 +2,44 @@ modal-notifications {
|
||||
@apply flex flex-col relative h-full;
|
||||
|
||||
h1 {
|
||||
@apply text-xl font-bold text-center mb-10;
|
||||
@apply text-xl font-bold text-center;
|
||||
}
|
||||
|
||||
// .notification-card {
|
||||
// @apply text-center text-xl text-inactive-branch block bg-white rounded-t-card font-bold no-underline py-4 border-none outline-none shadow-card -ml-4;
|
||||
// width: calc(100% + 2rem);
|
||||
// }
|
||||
|
||||
.notification-card {
|
||||
@apply text-center text-xl text-inactive-branch block bg-white rounded-t-card font-bold no-underline py-4 border-none outline-none shadow-card -ml-4;
|
||||
width: calc(100% + 2rem);
|
||||
@apply grid grid-flow-col items-center justify-center gap-4;
|
||||
@apply text-inactive-branch bg-white;
|
||||
@apply font-bold text-xl -mx-4 py-4;
|
||||
|
||||
.notification-icon {
|
||||
@apply relative;
|
||||
|
||||
.notification-counter {
|
||||
@apply absolute font-normal text-base -top-2 -right-1 bg-brand text-white rounded-full w-5 h-5 flex items-center justify-center;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
ui-icon {
|
||||
@apply text-inactive-branch;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply font-bold text-2xl ml-4;
|
||||
}
|
||||
}
|
||||
|
||||
modal-notifications-remission-group,
|
||||
modal-notifications-reservation-group,
|
||||
modal-notifications-task-calendar-group,
|
||||
modal-notifications-update-group {
|
||||
modal-notifications-update-group,
|
||||
modal-notifications-package-inspection-group {
|
||||
@apply flex flex-col relative pb-2;
|
||||
|
||||
.header {
|
||||
@apply flex flex-row justify-center items-center mt-5;
|
||||
|
||||
.notification-icon {
|
||||
@apply relative;
|
||||
|
||||
.notification-counter {
|
||||
@apply absolute -top-2 -right-1 bg-brand text-white rounded-full w-5 h-5 flex items-center justify-center;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
ui-icon {
|
||||
@apply text-inactive-branch;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply font-bold text-2xl ml-4;
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
@apply bg-disabled-branch h-px-2 -ml-4 my-4;
|
||||
width: calc(100% + 2rem);
|
||||
}
|
||||
|
||||
.notification-list {
|
||||
@apply overflow-y-scroll -ml-4;
|
||||
max-height: calc(100vh - 450px);
|
||||
@@ -60,7 +58,7 @@ modal-notifications {
|
||||
|
||||
modal-notifications-list-item,
|
||||
modal-notifications-update-group {
|
||||
@apply flex flex-col relative py-1 px-4;
|
||||
@apply flex flex-col relative p-4;
|
||||
|
||||
.notification-headline {
|
||||
@apply flex flex-row justify-between items-start;
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ComponentStore } from '@ngrx/component-store';
|
||||
import { Group, groupBy } from '@ui/common';
|
||||
import { UiModalRef } from '@ui/modal';
|
||||
import { EnvelopeDTO, MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
|
||||
|
||||
interface ModalNotificationComponentState {
|
||||
activeCard: string;
|
||||
groupedNotifications: Group<string, MessageBoardItemDTO>[];
|
||||
selectedArea: string;
|
||||
notifications: Record<string, MessageBoardItemDTO[]>;
|
||||
}
|
||||
|
||||
@Component({
|
||||
@@ -18,44 +15,61 @@ interface ModalNotificationComponentState {
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class ModalNotificationsComponent extends ComponentStore<ModalNotificationComponentState> implements OnInit {
|
||||
set activeCard(activeCard: string) {
|
||||
if (this.activeCard !== activeCard) {
|
||||
this.patchState({ activeCard });
|
||||
export class ModalNotificationsComponent extends ComponentStore<ModalNotificationComponentState> {
|
||||
private _selectedAreaSelector = (state: ModalNotificationComponentState) => {
|
||||
if (state.selectedArea) {
|
||||
return state.selectedArea;
|
||||
}
|
||||
|
||||
const keys = Object.keys(state.notifications);
|
||||
|
||||
for (const key of keys) {
|
||||
if (state.notifications[key]?.length > 0) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
get selectedArea() {
|
||||
return this.get(this._selectedAreaSelector);
|
||||
}
|
||||
|
||||
activeCard$ = this.select((s) => s.activeCard);
|
||||
selectedArea$ = this.select(this._selectedAreaSelector);
|
||||
|
||||
get activeCard() {
|
||||
return this.get((s) => s.activeCard);
|
||||
private _categorySelector = (state: ModalNotificationComponentState) => {
|
||||
const selectedArea = this._selectedAreaSelector(state);
|
||||
console.log('_categorySelector', state.notifications[selectedArea]?.[0]?.category);
|
||||
return state.notifications[selectedArea]?.[0]?.category;
|
||||
};
|
||||
|
||||
get category() {
|
||||
return this.get(this._categorySelector);
|
||||
}
|
||||
|
||||
get groupedNotifications() {
|
||||
return this.get((s) => s.groupedNotifications);
|
||||
}
|
||||
groupedNotifications$ = this.select((s) => s.groupedNotifications);
|
||||
category$ = this.select(this._categorySelector);
|
||||
|
||||
set groupedNotifications(groupedNotifications: Group<string, MessageBoardItemDTO>[]) {
|
||||
this.patchState({ groupedNotifications });
|
||||
get notifications() {
|
||||
return this.get((s) => s.notifications);
|
||||
}
|
||||
|
||||
activeNotifications$ = combineLatest([this.activeCard$, this.groupedNotifications$]).pipe(
|
||||
map(([activeCard, notifications]) => notifications.find((n) => n.group === activeCard)?.items)
|
||||
);
|
||||
notifications$ = this.select((s) => s.notifications);
|
||||
|
||||
constructor(private _modalRef: UiModalRef<any, EnvelopeDTO<MessageBoardItemDTO[]>>) {
|
||||
constructor(private _modalRef: UiModalRef<any, Record<string, MessageBoardItemDTO[]>>) {
|
||||
super({
|
||||
activeCard: undefined,
|
||||
groupedNotifications: groupBy(_modalRef.data.data, (item: MessageBoardItemDTO) => item.category),
|
||||
selectedArea: undefined,
|
||||
notifications: _modalRef.data,
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.patchState({ activeCard: this.groupedNotifications?.find((_) => true)?.group });
|
||||
}
|
||||
|
||||
close() {
|
||||
this._modalRef.close();
|
||||
}
|
||||
|
||||
selectArea(area: string) {
|
||||
this.patchState({
|
||||
selectedArea: area,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { ModalNotificationsReservationGroupComponent } from './notifications-res
|
||||
import { ModalNotificationsTaskCalendarGroupComponent } from './notifications-task-calendar-group/notifications-task-calendar-group.component';
|
||||
import { ModalNotificationsUpdateGroupComponent } from './notifications-update-group/notifications-update-group.component';
|
||||
import { ModalNotificationsComponent } from './notifications.component';
|
||||
import { ModalNotificationsPackageInspectionGroupComponent } from './notifications-package-inspection-group/notifications-package-inspection-group.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiCommonModule, UiIconModule, RouterModule],
|
||||
@@ -19,6 +20,7 @@ import { ModalNotificationsComponent } from './notifications.component';
|
||||
ModalNotificationsTaskCalendarGroupComponent,
|
||||
ModalNotificationsUpdateGroupComponent,
|
||||
ModalNotificationsListItemComponent,
|
||||
ModalNotificationsPackageInspectionGroupComponent,
|
||||
],
|
||||
exports: [
|
||||
ModalNotificationsComponent,
|
||||
@@ -27,6 +29,7 @@ import { ModalNotificationsComponent } from './notifications.component';
|
||||
ModalNotificationsTaskCalendarGroupComponent,
|
||||
ModalNotificationsUpdateGroupComponent,
|
||||
ModalNotificationsListItemComponent,
|
||||
ModalNotificationsPackageInspectionGroupComponent,
|
||||
],
|
||||
})
|
||||
export class ModalNotificationsModule {}
|
||||
|
||||
@@ -54,21 +54,12 @@ export class PriceUpdateItemComponent {
|
||||
inStock$ = combineLatest([this.defaultBranch$, this._item$]).pipe(
|
||||
debounceTime(100),
|
||||
filter(([defaultBranch, item]) => !!defaultBranch && !!item),
|
||||
switchMap(
|
||||
([defaultBranch, item]) =>
|
||||
this._stockService.getInStock$({
|
||||
itemId: Number(item?.product?.catalogProductNumber),
|
||||
branchId: defaultBranch?.id,
|
||||
})
|
||||
// TODO: Bugfixing INSTOCK
|
||||
// .pipe(
|
||||
// map((instock) => {
|
||||
// this.item.product.ean === '9783551775559' ? console.log({ item: this.item, instock }) : '';
|
||||
// return instock;
|
||||
// })
|
||||
// )
|
||||
),
|
||||
shareReplay(1)
|
||||
switchMap(([defaultBranch, item]) =>
|
||||
this._stockService.getInStock$({
|
||||
itemId: Number(item?.product?.catalogProductNumber),
|
||||
branchId: defaultBranch?.id,
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
constructor(
|
||||
|
||||
@@ -51,16 +51,9 @@
|
||||
</div>
|
||||
|
||||
<div class="right">
|
||||
<div class="price" *ngIf="item.catalogAvailability?.price?.value?.value; else retailPrice">
|
||||
{{ item.catalogAvailability?.price?.value?.value | currency: item.catalogAvailability?.price?.value?.currency:'code' }}
|
||||
<div class="price" *ngIf="price$ | async; let price">
|
||||
{{ price?.value?.value | currency: price?.value?.currency:'code' }}
|
||||
</div>
|
||||
<ng-template #retailPrice>
|
||||
<div class="price" *ngIf="store.takeAwayAvailability$ | async; let takeAwayAvailability">
|
||||
{{
|
||||
takeAwayAvailability?.retailPrice?.value?.value | currency: takeAwayAvailability?.retailPrice?.value?.currency:'code'
|
||||
}}
|
||||
</div>
|
||||
</ng-template>
|
||||
<div *ngIf="store.promotionPoints$ | async; let promotionPoints">{{ promotionPoints }} Lesepunkte</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -94,7 +87,24 @@
|
||||
|
||||
<div class="fetching xsmall" *ngIf="store.fetchingPickUpAvailability$ | async; else showAvailabilityPickUpIcon"></div>
|
||||
<ng-template #showAvailabilityPickUpIcon>
|
||||
<ui-icon *ngIf="store.isPickUpAvailabilityAvailable$ | async" icon="box_out" size="18px"></ui-icon>
|
||||
<ui-icon
|
||||
[uiOverlayTrigger]="orderDeadlineTooltip"
|
||||
*ngIf="store.isPickUpAvailabilityAvailable$ | async"
|
||||
icon="box_out"
|
||||
size="18px"
|
||||
></ui-icon>
|
||||
|
||||
<ui-tooltip
|
||||
[warning]="true"
|
||||
yPosition="above"
|
||||
xPosition="after"
|
||||
[yOffset]="-11"
|
||||
[xOffset]="8"
|
||||
#orderDeadlineTooltip
|
||||
[closeable]="true"
|
||||
>
|
||||
<b>{{ (store.pickUpAvailability$ | async)?.orderDeadline | orderDeadline }}</b>
|
||||
</ui-tooltip>
|
||||
</ng-template>
|
||||
|
||||
<div class="fetching xsmall" *ngIf="store.fetchingDeliveryAvailability$ | async; else showAvailabilityDeliveryIcon"></div>
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, ElementRef } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { DomainPrinterService } from '@domain/printer';
|
||||
import { ItemDTO as PrinterItemDTO } from '@swagger/print';
|
||||
import { PrintModalComponent, PrintModalData } from '@modal/printer';
|
||||
import { AvailabilityDTO, BranchDTO } from '@swagger/checkout';
|
||||
import { BranchDTO } from '@swagger/checkout';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { ModalReviewsComponent } from '@modal/reviews';
|
||||
import { PurchasingOptionsModalComponent, PurchasingOptionsModalData } from 'apps/page/checkout/src/lib/modals/purchasing-options-modal';
|
||||
import { PurchasingOptions } from 'apps/page/checkout/src/lib/modals/purchasing-options-modal/purchasing-options-modal.store';
|
||||
import { BehaviorSubject, combineLatest, Subscription } from 'rxjs';
|
||||
import { debounceTime, filter, first, map, shareReplay, switchMap } from 'rxjs/operators';
|
||||
import { ArticleDetailsStore } from './article-details.store';
|
||||
@@ -20,7 +18,9 @@ import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { ItemDTO } from '@swagger/cat';
|
||||
import { DateAdapter } from '@ui/common';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { PurchaseOptionsModalService } from '@shared/modals/purchase-options-modal';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
|
||||
@Component({
|
||||
selector: 'page-article-details',
|
||||
@@ -66,6 +66,10 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
|
||||
this.store.isDeliveryB2BAvailabilityAvailable$,
|
||||
]).pipe(map(([digDelivery, b2bDelivery]) => b2bDelivery && !digDelivery));
|
||||
|
||||
customerFeatures$ = this.applicationService.activatedProcessId$.pipe(
|
||||
switchMap((processId) => this._domainCheckoutService.getCustomerFeatures({ processId }))
|
||||
);
|
||||
|
||||
showSubscriptionBadge$ = this.store.item$.pipe(map((item) => item?.features?.find((i) => i.key === 'PFO')));
|
||||
|
||||
showPromotionBadge$ = this.store.item$.pipe(map((item) => item?.features?.find((i) => i.key === 'Promotion')));
|
||||
@@ -114,6 +118,38 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
price$ = combineLatest([
|
||||
this.store.item$,
|
||||
this.store.takeAwayAvailability$,
|
||||
this.store.deliveryAvailability$,
|
||||
this.store.deliveryDigAvailability$,
|
||||
this.store.deliveryB2BAvailability$,
|
||||
]).pipe(
|
||||
map(([item, takeAway, delivery, deliveryDig, deliveryB2B]) => {
|
||||
if (item?.catalogAvailability?.price?.value?.value) {
|
||||
return item?.catalogAvailability?.price;
|
||||
}
|
||||
|
||||
if (takeAway?.price?.value?.value) {
|
||||
return takeAway.price;
|
||||
}
|
||||
|
||||
if (delivery?.price?.value?.value) {
|
||||
return delivery.price;
|
||||
}
|
||||
|
||||
if (deliveryDig?.price?.value?.value) {
|
||||
return deliveryDig.price;
|
||||
}
|
||||
|
||||
if (deliveryB2B?.price?.value?.value) {
|
||||
return deliveryB2B.price;
|
||||
}
|
||||
|
||||
return null;
|
||||
})
|
||||
);
|
||||
|
||||
constructor(
|
||||
public readonly applicationService: ApplicationService,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
@@ -125,7 +161,10 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
|
||||
private _dateAdapter: DateAdapter,
|
||||
private _datePipe: DatePipe,
|
||||
public elementRef: ElementRef,
|
||||
private _availability: DomainAvailabilityService
|
||||
private _purchaseOptionsModalService: PurchaseOptionsModalService,
|
||||
private _availability: DomainAvailabilityService,
|
||||
private _router: Router,
|
||||
private _domainCheckoutService: DomainCheckoutService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -262,59 +301,70 @@ export class ArticleDetailsComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
async showPurchasingModal(selectedBranch?: BranchDTO) {
|
||||
let availableOptions: PurchasingOptions[] = [];
|
||||
const availabilities: { [key: string]: AvailabilityDTO } = {};
|
||||
const item = await this.store.item$.pipe(first()).toPromise();
|
||||
|
||||
const takeNow = await this.store.isTakeAwayAvailabilityAvailable$.pipe(first()).toPromise();
|
||||
if (takeNow) {
|
||||
availableOptions.push('take-away');
|
||||
availabilities['take-away'] = await this.store.takeAwayAvailability$.pipe(first()).toPromise();
|
||||
}
|
||||
|
||||
const download = await this.store.isDownloadAvailabilityAvailable$.pipe(first()).toPromise();
|
||||
if (download) {
|
||||
availableOptions.push('download');
|
||||
availabilities['download'] = await this.store.downloadAvailability$.pipe(first()).toPromise();
|
||||
}
|
||||
|
||||
const pickup = await this.store.isPickUpAvailabilityAvailable$.pipe(first()).toPromise();
|
||||
if (pickup) {
|
||||
availableOptions.push('pick-up');
|
||||
availabilities['pick-up'] = await this.store.pickUpAvailability$.pipe(first()).toPromise();
|
||||
}
|
||||
|
||||
const digDelivery = await this.store.isDeliveryDigAvailabilityAvailable$.pipe(first()).toPromise();
|
||||
if (digDelivery) {
|
||||
availableOptions.push('dig-delivery');
|
||||
availabilities['dig-delivery'] = await this.store.deliveryDigAvailability$.pipe(first()).toPromise();
|
||||
}
|
||||
|
||||
const b2b = await this.store.isDeliveryB2BAvailabilityAvailable$.pipe(first()).toPromise();
|
||||
|
||||
if (b2b) {
|
||||
availableOptions.push('b2b-delivery');
|
||||
availabilities['b2b-delivery'] = await this.store.deliveryB2BAvailability$.pipe(first()).toPromise();
|
||||
}
|
||||
|
||||
if (availableOptions.includes('dig-delivery') && availableOptions.includes('b2b-delivery')) {
|
||||
availableOptions.push('delivery');
|
||||
availabilities['delivery'] = await this.store.deliveryAvailability$.pipe(first()).toPromise();
|
||||
availableOptions = availableOptions.filter((option) => !(option === 'dig-delivery' || option === 'b2b-delivery'));
|
||||
}
|
||||
|
||||
const branch = selectedBranch || (await this.store.branch$.pipe(first()).toPromise());
|
||||
|
||||
this.uiModal.open({
|
||||
content: PurchasingOptionsModalComponent,
|
||||
data: {
|
||||
availableOptions,
|
||||
option: selectedBranch ? 'take-away' : undefined,
|
||||
item: await this.store.item$.pipe(first()).toPromise(),
|
||||
branchId: branch?.id,
|
||||
this._purchaseOptionsModalService
|
||||
.open({
|
||||
type: 'add',
|
||||
processId: this.applicationService.activatedProcessId,
|
||||
availabilities,
|
||||
} as PurchasingOptionsModalData,
|
||||
});
|
||||
items: [item],
|
||||
pickupBranch: selectedBranch,
|
||||
inStoreBranch: selectedBranch,
|
||||
preSelectOption: !!selectedBranch ? { option: 'in-store', showOptionOnly: true } : undefined,
|
||||
})
|
||||
.afterClosed$.subscribe(async (result) => {
|
||||
if (result?.data === 'continue') {
|
||||
const customer = await this._domainCheckoutService
|
||||
.getBuyer({ processId: this.applicationService.activatedProcessId })
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
if (customer) {
|
||||
this.navigateToShoppingCart();
|
||||
} else {
|
||||
this.navigateToCustomerSearch();
|
||||
}
|
||||
} else if (result?.data === 'continue-shopping') {
|
||||
this.navigateToResultList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
navigateToShoppingCart() {
|
||||
this._router.navigate([`/kunde/${this.applicationService.activatedProcessId}/cart/review`]);
|
||||
}
|
||||
|
||||
async navigateToCustomerSearch() {
|
||||
try {
|
||||
const response = await this.customerFeatures$
|
||||
.pipe(
|
||||
first(),
|
||||
switchMap((customerFeatures) => {
|
||||
return this._domainCheckoutService.canSetCustomer({ processId: this.applicationService.activatedProcessId, customerFeatures });
|
||||
})
|
||||
)
|
||||
.toPromise();
|
||||
this._router.navigate(['/kunde', this.applicationService.activatedProcessId, 'customer', 'search'], {
|
||||
queryParams: { filter_customertype: response.filter.customertype },
|
||||
});
|
||||
} catch (error) {
|
||||
this._router.navigate(['/kunde', this.applicationService.activatedProcessId, 'customer', 'search']);
|
||||
}
|
||||
}
|
||||
|
||||
async navigateToResultList() {
|
||||
let crumbs = await this.breadcrumb
|
||||
.getBreadcrumbsByKeyAndTags$(this.applicationService.activatedProcessId, ['catalog'])
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
crumbs = crumbs.filter((crumb) => !crumb.tags?.includes('details'));
|
||||
|
||||
const crumb = crumbs[crumbs.length - 1];
|
||||
if (crumb) {
|
||||
this._router.navigate([crumb.path], { queryParams: crumb.params });
|
||||
} else {
|
||||
this._router.navigate([`/kunde/${this.applicationService.activatedProcessId}/product`]);
|
||||
}
|
||||
}
|
||||
|
||||
scrollTop() {
|
||||
|
||||
@@ -10,6 +10,7 @@ import { ArticleRecommendationsComponent } from './recommendations/article-recom
|
||||
import { PipesModule } from '../shared/pipes/pipes.module';
|
||||
import { UiTooltipModule } from '@ui/tooltip';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { OrderDeadlinePipeModule } from '@shared/pipes/order-deadline';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -22,6 +23,7 @@ import { UiCommonModule } from '@ui/common';
|
||||
UiCommonModule,
|
||||
UiTooltipModule,
|
||||
PipesModule,
|
||||
OrderDeadlinePipeModule,
|
||||
],
|
||||
exports: [ArticleDetailsComponent, ArticleRecommendationsComponent],
|
||||
declarations: [ArticleDetailsComponent, ArticleRecommendationsComponent],
|
||||
|
||||
@@ -129,7 +129,11 @@ export class ArticleDetailsStore extends ComponentStore<ArticleDetailsState> {
|
||||
|
||||
//#region Abholung
|
||||
readonly fetchingPickUpAvailability$ = this.select((s) => s.fetchingPickUpAvailability);
|
||||
readonly pickUpAvailability$: Observable<AvailabilityDTO> = combineLatest([this.itemData$, this.branch$, this.isDownload$]).pipe(
|
||||
readonly pickUpAvailability$: Observable<AvailabilityDTO & { orderDeadline?: string }> = combineLatest([
|
||||
this.itemData$,
|
||||
this.branch$,
|
||||
this.isDownload$,
|
||||
]).pipe(
|
||||
tap(() => this.patchState({ fetchingPickUpAvailability: true, fetchingPickUpAvailabilityError: undefined })),
|
||||
switchMap(([item, branch, isDownload]) =>
|
||||
!!item && !!branch && !isDownload
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
<ng-container *ngIf="filter$ | async; let filter">
|
||||
<div class="catalog-search-filter-content">
|
||||
<button class="btn-close" type="button" (click)="close.emit()">
|
||||
<ui-icon icon="close" size="20px"></ui-icon>
|
||||
</button>
|
||||
<div class="w-full flex flex-row justify-end items-center">
|
||||
<button (click)="clearFilter(filter)" class="text-[#0556B4] mr-[0.8125rem]">Alle Filter entfernen</button>
|
||||
<button class="text-cool-grey p-4 outline-none border-none bg-transparent" type="button" (click)="close.emit()">
|
||||
<ui-icon icon="close" size="20px"></ui-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="catalog-search-filter-content-main">
|
||||
<div class="catalog-search-filter-content-main -mt-8">
|
||||
<h1 class="text-3xl font-bold text-center py-4">Filter</h1>
|
||||
<ui-filter
|
||||
[filter]="filter"
|
||||
|
||||
@@ -6,10 +6,6 @@
|
||||
@apply relative mx-auto p-4;
|
||||
}
|
||||
|
||||
.btn-close {
|
||||
@apply absolute text-cool-grey top-3 p-4 right-4 outline-none border-none bg-transparent;
|
||||
}
|
||||
|
||||
.catalog-search-filter-content-main {
|
||||
h1.title {
|
||||
@apply text-center;
|
||||
|
||||
@@ -58,4 +58,8 @@ export class ArticleSearchFilterComponent implements OnInit {
|
||||
const queryParams = { main_qs: value?.getQueryParams()?.main_qs || '' };
|
||||
this.articleSearch.setDefaultFilter(queryParams);
|
||||
}
|
||||
|
||||
clearFilter(value: UiFilter) {
|
||||
value.unselectAll();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { ItemDTO } from '@swagger/cat';
|
||||
import { DateAdapter } from '@ui/common';
|
||||
import { isEqual } from 'lodash';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { debounceTime, switchMap, map, tap, shareReplay } from 'rxjs/operators';
|
||||
import { debounceTime, switchMap, map, shareReplay, filter } from 'rxjs/operators';
|
||||
import { ArticleSearchService } from '../article-search.store';
|
||||
|
||||
export interface SearchResultItemComponentState {
|
||||
@@ -87,8 +87,7 @@ export class SearchResultItemComponent extends ComponentStore<SearchResultItemCo
|
||||
map(([defaultBranch, selectedBranch]) => {
|
||||
const branch = selectedBranch ?? defaultBranch;
|
||||
return branch.branchType !== 4;
|
||||
}),
|
||||
shareReplay(1)
|
||||
})
|
||||
);
|
||||
|
||||
stockTooltipText$ = combineLatest([this.defaultBranch$, this.selectedBranchId$]).pipe(
|
||||
@@ -104,12 +103,12 @@ export class SearchResultItemComponent extends ComponentStore<SearchResultItemCo
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}),
|
||||
shareReplay(1)
|
||||
})
|
||||
);
|
||||
|
||||
inStock$ = combineLatest([this.item$, this.selectedBranchId$, this.defaultBranch$]).pipe(
|
||||
debounceTime(100),
|
||||
filter(([item, branch, defaultBranch]) => !!item && !!defaultBranch),
|
||||
switchMap(([item, branch, defaultBranch]) =>
|
||||
this._stockService.getInStock$({ itemId: item.id, branchId: branch?.id ?? defaultBranch?.id })
|
||||
)
|
||||
|
||||
@@ -15,6 +15,7 @@ import { debounceTime, first, map, switchMap } from 'rxjs/operators';
|
||||
import { ArticleSearchService } from '../article-search.store';
|
||||
import { AddedToCartModalComponent } from './added-to-cart-modal/added-to-cart-modal.component';
|
||||
import { SearchResultItemComponent } from './search-result-item.component';
|
||||
import { DomainAvailabilityService, ItemData } from '@domain/availability';
|
||||
|
||||
@Component({
|
||||
selector: 'page-search-results',
|
||||
@@ -54,7 +55,8 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
|
||||
private breadcrumb: BreadcrumbService,
|
||||
private cache: CacheService,
|
||||
private _uiModal: UiModalService,
|
||||
private _checkoutService: DomainCheckoutService
|
||||
private _checkoutService: DomainCheckoutService,
|
||||
private _availability: DomainAvailabilityService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -241,6 +243,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
|
||||
// Zeige Select Radio Button nicht an wenn Item Archivartikel oder Fortsetzungsartikel ist
|
||||
const isArchiv = item?.catalogAvailability?.status === 1;
|
||||
const isFortsetzung = item?.features?.find((i) => i?.key === 'PFO');
|
||||
|
||||
return !(isArchiv || isFortsetzung);
|
||||
}
|
||||
|
||||
@@ -257,11 +260,12 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
|
||||
|
||||
for (const item of selectedItems) {
|
||||
const isDownload = item?.product?.format === 'EB' || item?.product?.format === 'DL';
|
||||
const price = item?.catalogAvailability?.price;
|
||||
const shoppingCartItem: AddToShoppingCartDTO = {
|
||||
quantity: 1,
|
||||
availability: {
|
||||
availabilityType: item?.catalogAvailability?.status,
|
||||
price: item?.catalogAvailability?.price,
|
||||
price,
|
||||
supplierProductNumber: item?.ids?.dig ? String(item.ids?.dig) : item?.product?.supplierProductNumber,
|
||||
},
|
||||
product: {
|
||||
@@ -273,7 +277,13 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
|
||||
};
|
||||
|
||||
if (isDownload) {
|
||||
shoppingCartItem.destination = { data: { target: 16 } };
|
||||
const itemId = item?.id;
|
||||
const ean = item?.product?.ean;
|
||||
const downloadItem: ItemData = { ean, itemId, price };
|
||||
|
||||
// #4180 Für Download Artikel muss hier immer zwingend der logistician gesetzt werden, da diese Artikel direkt zugeordnet dem Warenkorb hinzugefügt werden
|
||||
const downloadAvailability = await this._availability.getDownloadAvailability({ item: downloadItem }).pipe(first()).toPromise();
|
||||
shoppingCartItem.destination = { data: { target: 16, logistician: downloadAvailability?.logistician } };
|
||||
canAddItemsPayload.push({
|
||||
availabilities: [{ ...item.catalogAvailability, format: 'DL' }],
|
||||
id: item.product.catalogProductNumber,
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
<shared-breadcrumb class="my-4" [key]="activatedProcessId$ | async" [tags]="['catalog']">
|
||||
<shared-branch-selector [branchType]="1" [value]="selectedBranch$ | async" (valueChange)="patchProcessData($event)">
|
||||
<shared-branch-selector
|
||||
[filterCurrentBranch]="!!auth.hasRole('Store')"
|
||||
[orderBy]="auth.hasRole('Store') ? 'distance' : 'name'"
|
||||
[branchType]="1"
|
||||
[value]="selectedBranch$ | async"
|
||||
(valueChange)="patchProcessData($event)"
|
||||
>
|
||||
</shared-branch-selector>
|
||||
</shared-breadcrumb>
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { AuthService } from '@core/auth';
|
||||
import { EnvironmentService } from '@core/environment';
|
||||
import { BranchSelectorComponent } from '@shared/components/branch-selector';
|
||||
import { BreadcrumbComponent } from '@shared/components/breadcrumb';
|
||||
@@ -30,11 +31,13 @@ export class PageCatalogComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
constructor(
|
||||
public application: ApplicationService,
|
||||
private _uiModal: UiModalService,
|
||||
public auth: AuthService,
|
||||
private _environmentService: EnvironmentService,
|
||||
private _renderer: Renderer2
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
// this.auth.getClaims();
|
||||
this.activatedProcessId$ = this.application.activatedProcessId$.pipe(map((processId) => String(processId)));
|
||||
|
||||
this.selectedBranch$ = this.activatedProcessId$.pipe(switchMap((processId) => this.application.getSelectedBranch$(Number(processId))));
|
||||
|
||||
@@ -6,8 +6,6 @@ import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { AvailabilityDTO, DestinationDTO, NotificationChannel, ShoppingCartItemDTO, ShoppingCartDTO } from '@swagger/checkout';
|
||||
import { UiErrorModalComponent, UiMessageModalComponent, UiModalService } from '@ui/modal';
|
||||
import { PrintModalData, PrintModalComponent } from '@modal/printer';
|
||||
import { PurchasingOptionsModalComponent, PurchasingOptionsModalData } from '../modals/purchasing-options-modal';
|
||||
import { PurchasingOptions } from '../modals/purchasing-options-modal/purchasing-options-modal.store';
|
||||
import { AuthService } from '@core/auth';
|
||||
import { first, map, shareReplay, switchMap, take, takeUntil, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { Subject, NEVER, combineLatest, BehaviorSubject } from 'rxjs';
|
||||
@@ -15,13 +13,11 @@ import { DomainCatalogService } from '@domain/catalog';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { DomainPrinterService } from '@domain/printer';
|
||||
import { CheckoutDummyComponent } from '../checkout-dummy/checkout-dummy.component';
|
||||
import { ResponseArgsOfItemDTO } from '@swagger/cat';
|
||||
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { emailNotificationValidator, mobileNotificationValidator } from '@shared/components/notification-channel-control';
|
||||
import { PurchasingOptionsListModalComponent } from '../modals/purchasing-options-list-modal';
|
||||
import { PurchasingOptionsListModalData } from '../modals/purchasing-options-list-modal/purchasing-options-list-modal.data';
|
||||
import { ComponentStore, tapResponse } from '@ngrx/component-store';
|
||||
import { CheckoutDummyData } from '../checkout-dummy/checkout-dummy-data';
|
||||
import { PurchaseOptionsModalService } from '@shared/modals/purchase-options-modal';
|
||||
|
||||
export interface CheckoutReviewComponentState {
|
||||
shoppingCart: ShoppingCartDTO;
|
||||
@@ -242,7 +238,8 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
|
||||
private domainCatalogService: DomainCatalogService,
|
||||
private breadcrumb: BreadcrumbService,
|
||||
private domainPrinterService: DomainPrinterService,
|
||||
private _fb: UntypedFormBuilder
|
||||
private _fb: UntypedFormBuilder,
|
||||
private _purchaseOptionsModalService: PurchaseOptionsModalService
|
||||
) {
|
||||
super({
|
||||
shoppingCart: undefined,
|
||||
@@ -274,7 +271,7 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
|
||||
shoppingCart,
|
||||
shoppingCartItems,
|
||||
});
|
||||
this.checkQuantityErrors(shoppingCartItems);
|
||||
// this.checkQuantityErrors(shoppingCartItems);
|
||||
},
|
||||
(err) => {},
|
||||
() => {}
|
||||
@@ -285,15 +282,15 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
|
||||
)
|
||||
);
|
||||
|
||||
checkQuantityErrors(shoppingCartItems: ShoppingCartItemDTO[]) {
|
||||
shoppingCartItems.forEach((item) => {
|
||||
if (item.features?.orderType === 'Rücklage') {
|
||||
this.setQuantityError(item, item.availability, item.quantity > item.availability?.inStock);
|
||||
} else {
|
||||
this.setQuantityError(item, item.availability, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
// checkQuantityErrors(shoppingCartItems: ShoppingCartItemDTO[]) {
|
||||
// shoppingCartItems.forEach((item) => {
|
||||
// if (item.features?.orderType === 'Abholung') {
|
||||
// this.setQuantityError(item, item.availability, item.quantity > item.availability?.inStock);
|
||||
// } else {
|
||||
// this.setQuantityError(item, item.availability, false);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
async updateBreadcrumb() {
|
||||
await this.breadcrumb.addOrUpdateBreadcrumbIfNotExists({
|
||||
@@ -434,171 +431,10 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
|
||||
}
|
||||
|
||||
async changeItem({ shoppingCartItem }: { shoppingCartItem: ShoppingCartItemDTO }) {
|
||||
this.loadingOnItemChangeById$.next(shoppingCartItem.id);
|
||||
|
||||
const quantity = shoppingCartItem.quantity;
|
||||
|
||||
const branchNo = this.auth.getClaimByKey('branch_no');
|
||||
const branchId = shoppingCartItem?.destination?.data?.targetBranch?.id;
|
||||
|
||||
const customerFeatures = await this.customerFeatures$.pipe(first()).toPromise();
|
||||
|
||||
let branch = await this.domainCheckoutService
|
||||
.getBranches()
|
||||
.pipe(map((branches) => branches.find((branch) => (branchId ? branch.id === branchId : branch.branchNumber === branchNo))))
|
||||
.toPromise();
|
||||
|
||||
if (!branch) {
|
||||
branch = await this.applicationService.getSelectedBranch$().pipe(take(1)).toPromise();
|
||||
}
|
||||
|
||||
let catalogItem: ResponseArgsOfItemDTO;
|
||||
if (Number.isInteger(shoppingCartItem?.product?.catalogProductNumber)) {
|
||||
catalogItem = await this.domainCatalogService
|
||||
.getDetailsById({ id: Number(shoppingCartItem.product.catalogProductNumber) })
|
||||
.toPromise();
|
||||
} else if (shoppingCartItem?.product?.ean) {
|
||||
catalogItem = await this.domainCatalogService.getDetailsByEan({ ean: shoppingCartItem.product.ean }).toPromise();
|
||||
}
|
||||
|
||||
let takeAwayAvailability: AvailabilityDTO;
|
||||
if (!!catalogItem?.result?.product) {
|
||||
takeAwayAvailability = await this.availabilityService
|
||||
.getTakeAwayAvailability({
|
||||
item: {
|
||||
itemId: catalogItem.result.id,
|
||||
ean: catalogItem.result.product.ean,
|
||||
price: catalogItem.result.catalogAvailability?.price,
|
||||
},
|
||||
quantity,
|
||||
})
|
||||
.toPromise();
|
||||
}
|
||||
|
||||
const pickupAvailability = await this.availabilityService
|
||||
.getPickUpAvailability({
|
||||
item: {
|
||||
itemId: Number(shoppingCartItem.product.catalogProductNumber),
|
||||
ean: shoppingCartItem.product.ean,
|
||||
price: shoppingCartItem.availability.price,
|
||||
},
|
||||
branch,
|
||||
quantity,
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
const digAvailability = await this.availabilityService
|
||||
.getDigDeliveryAvailability({
|
||||
item: {
|
||||
itemId: Number(shoppingCartItem.product.catalogProductNumber),
|
||||
ean: shoppingCartItem.product.ean,
|
||||
price: shoppingCartItem.availability.price,
|
||||
},
|
||||
quantity,
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
const b2bAvailability = await this.availabilityService
|
||||
.getB2bDeliveryAvailability({
|
||||
item: {
|
||||
itemId: Number(shoppingCartItem.product.catalogProductNumber),
|
||||
ean: shoppingCartItem.product.ean,
|
||||
price: shoppingCartItem.availability.price,
|
||||
},
|
||||
quantity,
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
const downloadAvailability = await this.availabilityService
|
||||
.getDownloadAvailability({
|
||||
item: {
|
||||
itemId: Number(shoppingCartItem.product.catalogProductNumber),
|
||||
ean: shoppingCartItem.product.ean,
|
||||
price: shoppingCartItem.availability.price,
|
||||
},
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
let availableOptions: PurchasingOptions[] = [];
|
||||
const availabilities: { [key: string]: AvailabilityDTO } = {};
|
||||
|
||||
if (takeAwayAvailability && this.availabilityService.isAvailable({ availability: takeAwayAvailability })) {
|
||||
availableOptions.push('take-away');
|
||||
availabilities['take-away'] = takeAwayAvailability;
|
||||
}
|
||||
|
||||
if (downloadAvailability && this.availabilityService.isAvailable({ availability: downloadAvailability })) {
|
||||
availableOptions.push('download');
|
||||
availabilities['download'] = downloadAvailability;
|
||||
}
|
||||
|
||||
if (pickupAvailability && this.availabilityService.isAvailable({ availability: pickupAvailability[0] })) {
|
||||
if (pickupAvailability[1].availableFor) {
|
||||
if ((pickupAvailability[1].availableFor & 2) === 2) {
|
||||
availableOptions.push('pick-up');
|
||||
availabilities['pick-up'] = pickupAvailability[0];
|
||||
}
|
||||
} else {
|
||||
availableOptions.push('pick-up');
|
||||
availabilities['pick-up'] = pickupAvailability[0];
|
||||
}
|
||||
|
||||
if (!customerFeatures?.webshop && this.availabilityService.isAvailable({ availability: b2bAvailability })) {
|
||||
availableOptions.push('b2b-delivery');
|
||||
availabilities['b2b-delivery'] = b2bAvailability;
|
||||
}
|
||||
}
|
||||
|
||||
if (digAvailability && this.availabilityService.isAvailable({ availability: digAvailability }) && !customerFeatures?.b2b) {
|
||||
availableOptions.push('dig-delivery');
|
||||
availabilities['dig-delivery'] = digAvailability;
|
||||
}
|
||||
|
||||
if (availableOptions.includes('dig-delivery') && availableOptions.includes('b2b-delivery')) {
|
||||
let shippingAvailability = await this.availabilityService
|
||||
.getDeliveryAvailability({
|
||||
item: {
|
||||
itemId: Number(shoppingCartItem.product.catalogProductNumber),
|
||||
ean: shoppingCartItem.product.ean,
|
||||
price: shoppingCartItem.availability.price,
|
||||
},
|
||||
quantity,
|
||||
})
|
||||
.toPromise();
|
||||
if (shippingAvailability && this.availabilityService.isAvailable({ availability: shippingAvailability })) {
|
||||
availableOptions.push('delivery');
|
||||
availabilities['delivery'] = shippingAvailability;
|
||||
availableOptions = availableOptions.filter((option) => !(option === 'dig-delivery' || option === 'b2b-delivery'));
|
||||
}
|
||||
}
|
||||
|
||||
this.loadingOnItemChangeById$.next(undefined);
|
||||
this.cdr.markForCheck();
|
||||
|
||||
const itemId = Number(shoppingCartItem.product.catalogProductNumber);
|
||||
const modal = this.uiModal.open({
|
||||
content: PurchasingOptionsModalComponent,
|
||||
data: {
|
||||
availableOptions,
|
||||
item: {
|
||||
id: itemId,
|
||||
itemId: itemId,
|
||||
product: shoppingCartItem.product,
|
||||
price: shoppingCartItem.availability.price,
|
||||
catalogAvailability: {
|
||||
status: shoppingCartItem.availability.availabilityType,
|
||||
price: shoppingCartItem.availability.price,
|
||||
},
|
||||
},
|
||||
shoppingCartItem,
|
||||
branchId: branch?.id,
|
||||
processId: this.applicationService.activatedProcessId,
|
||||
availabilities,
|
||||
} as PurchasingOptionsModalData,
|
||||
});
|
||||
|
||||
modal.afterClosed$.pipe(takeUntil(this._orderCompleted)).subscribe(() => {
|
||||
this.setQuantityError(shoppingCartItem, undefined, false);
|
||||
this._purchaseOptionsModalService.open({
|
||||
processId: this.applicationService.activatedProcessId,
|
||||
items: [shoppingCartItem],
|
||||
type: 'update',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -649,7 +485,7 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
this.setQuantityError(shoppingCartItem, availability, availability?.inStock < quantity);
|
||||
// this.setQuantityError(shoppingCartItem, availability, availability?.inStock < quantity);
|
||||
break;
|
||||
case 'Abholung':
|
||||
availability = await this.availabilityService
|
||||
@@ -727,7 +563,7 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
|
||||
},
|
||||
})
|
||||
.toPromise();
|
||||
this.setQuantityError(shoppingCartItem, availability, false);
|
||||
// this.setQuantityError(shoppingCartItem, availability, false);
|
||||
} else if (availability) {
|
||||
// Wenn das Ergebnis der Availability Abfrage keinen Preis zurückliefert (z.B. HFI Geschenkkarte), wird der Preis aus der
|
||||
// Availability vor der Abfrage verwendet
|
||||
@@ -758,16 +594,16 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
|
||||
this.loadingOnQuantityChangeById$.next(undefined);
|
||||
}
|
||||
|
||||
setQuantityError(item: ShoppingCartItemDTO, availability: AvailabilityDTO, error: boolean) {
|
||||
const quantityErrors: { [key: string]: string } = this.quantityError$.value;
|
||||
if (error) {
|
||||
quantityErrors[item.product.catalogProductNumber] = `${availability.inStock} Exemplar(e) sofort lieferbar`;
|
||||
this.quantityError$.next({ ...quantityErrors });
|
||||
} else {
|
||||
delete quantityErrors[item.product.catalogProductNumber];
|
||||
this.quantityError$.next({ ...quantityErrors });
|
||||
}
|
||||
}
|
||||
// setQuantityError(item: ShoppingCartItemDTO, availability: AvailabilityDTO, error: boolean) {
|
||||
// const quantityErrors: { [key: string]: string } = this.quantityError$.value;
|
||||
// if (error) {
|
||||
// quantityErrors[item.product.catalogProductNumber] = `${availability.inStock} Exemplar(e) sofort lieferbar`;
|
||||
// this.quantityError$.next({ ...quantityErrors });
|
||||
// } else {
|
||||
// delete quantityErrors[item.product.catalogProductNumber];
|
||||
// this.quantityError$.next({ ...quantityErrors });
|
||||
// }
|
||||
// }
|
||||
|
||||
// Bei unbekannten Kunden und DIG Bestellung findet ein Vergleich der Preise statt
|
||||
compareDeliveryAndCatalogPrice(availability: AvailabilityDTO, orderType: string, shoppingCartItemPrice: number) {
|
||||
@@ -807,6 +643,7 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
|
||||
})
|
||||
)
|
||||
.toPromise();
|
||||
|
||||
this.router.navigate(['/kunde', this.applicationService.activatedProcessId, 'customer', 'search'], {
|
||||
queryParams: { filter_customertype: response.filter.customertype },
|
||||
});
|
||||
@@ -816,16 +653,10 @@ export class CheckoutReviewComponent extends ComponentStore<CheckoutReviewCompon
|
||||
}
|
||||
|
||||
async showPurchasingListModal(shoppingCartItems: ShoppingCartItemDTO[]) {
|
||||
const customerFeatures = await this.customerFeatures$.pipe(first()).toPromise();
|
||||
this.uiModal.open({
|
||||
content: PurchasingOptionsListModalComponent,
|
||||
title: 'Wie möchten Sie die Artikel erhalten?',
|
||||
config: { showScrollbarY: false },
|
||||
data: {
|
||||
processId: this.applicationService.activatedProcessId,
|
||||
shoppingCartItems: shoppingCartItems,
|
||||
customerFeatures,
|
||||
} as PurchasingOptionsListModalData,
|
||||
this._purchaseOptionsModalService.open({
|
||||
processId: this.applicationService.activatedProcessId,
|
||||
items: shoppingCartItems,
|
||||
type: 'update',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// start:ng42.barrel
|
||||
export * from './page-checkout.module';
|
||||
export * from './page-checkout-modals.module';
|
||||
// end:ng42.barrel
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<div class="option-icon">
|
||||
<ui-icon size="50px" icon="truck"></ui-icon>
|
||||
</div>
|
||||
<button
|
||||
class="option-chip"
|
||||
[disabled]="optionChipDisabled$ | async"
|
||||
(click)="optionChange('delivery')"
|
||||
[class.selected]="(selectedOption$ | async) === 'delivery'"
|
||||
>
|
||||
Versand
|
||||
</button>
|
||||
<p>Möchten Sie die Artikel<br />geliefert bekommen?</p>
|
||||
<p>Versandkostenfrei</p>
|
||||
@@ -1,23 +0,0 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { PurchasingOptionsListModalStore } from '../purchasing-options-list-modal.store';
|
||||
|
||||
@Component({
|
||||
selector: 'page-delivery-option-list',
|
||||
templateUrl: 'delivery-option-list.component.html',
|
||||
styleUrls: ['../list-options.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class DeliveryOptionListComponent {
|
||||
selectedOption$ = this._store.selectedFilterOption$;
|
||||
optionChipDisabled$ = this._store.fetchingAvailabilities$;
|
||||
|
||||
constructor(private _store: PurchasingOptionsListModalStore) {}
|
||||
|
||||
optionChange(option: string) {
|
||||
if (this._store.selectedFilterOption === option) {
|
||||
this._store.selectedFilterOption = undefined;
|
||||
} else {
|
||||
this._store.selectedFilterOption = option;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
// start:ng42.barrel
|
||||
export * from './delivery-option-list.component';
|
||||
// end:ng42.barrel
|
||||
@@ -1,7 +0,0 @@
|
||||
// start:ng42.barrel
|
||||
export * from './delivery-option';
|
||||
export * from './pick-up-option';
|
||||
export * from './take-away-option';
|
||||
export * from './purchasing-options-list-modal.component';
|
||||
export * from './purchasing-options-list-modal.module';
|
||||
// end:ng42.barrel
|
||||
@@ -1,44 +0,0 @@
|
||||
:host {
|
||||
@apply block w-72;
|
||||
}
|
||||
|
||||
.option-icon {
|
||||
@apply text-ucla-blue mx-auto;
|
||||
width: 40px;
|
||||
|
||||
.truck-b2b {
|
||||
margin-top: -21px;
|
||||
margin-bottom: -12px;
|
||||
width: 70px;
|
||||
}
|
||||
}
|
||||
|
||||
.option-chip {
|
||||
@apply rounded-full text-base px-4 py-3 bg-glitter text-inactive-customer border-none font-bold;
|
||||
|
||||
&.selected {
|
||||
@apply bg-active-customer text-white;
|
||||
}
|
||||
}
|
||||
|
||||
.option-description {
|
||||
@apply my-2;
|
||||
}
|
||||
|
||||
.option-select {
|
||||
@apply mt-4 mb-4 border-2 border-solid border-brand text-brand text-cta-l font-bold bg-white rounded-full py-3 px-6;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply my-4;
|
||||
}
|
||||
|
||||
::ng-deep page-purchasing-options-list-modal ui-branch-dropdown .wrapper {
|
||||
@apply mx-auto;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
::ng-deep page-pick-up-option-list .option-chip:disabled,
|
||||
::ng-deep page-take-away-option-list .option-chip:disabled {
|
||||
@apply bg-disabled-branch border-disabled-branch text-white;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
// start:ng42.barrel
|
||||
export * from './pick-up-option-list.component';
|
||||
// end:ng42.barrel
|
||||
@@ -1,18 +0,0 @@
|
||||
<div class="option-icon">
|
||||
<ui-icon size="50px" icon="box_out"></ui-icon>
|
||||
</div>
|
||||
<button
|
||||
class="option-chip"
|
||||
[disabled]="optionChipDisabled$ | async"
|
||||
(click)="optionChange('pick-up')"
|
||||
[class.selected]="(selectedOption$ | async) === 'pick-up'"
|
||||
>
|
||||
Abholung
|
||||
</button>
|
||||
<p>Möchten Sie die Artikel<br />in einer unserer Filialen<br />abholen?</p>
|
||||
|
||||
<ui-branch-dropdown
|
||||
[branches]="branches$ | async"
|
||||
[selected]="selectedBranch$ | async"
|
||||
(selectBranch)="selectBranch($event)"
|
||||
></ui-branch-dropdown>
|
||||
@@ -1,48 +0,0 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { BranchDTO } from '@swagger/checkout';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { first, map } from 'rxjs/operators';
|
||||
import { PurchasingOptionsListModalStore } from '../purchasing-options-list-modal.store';
|
||||
|
||||
@Component({
|
||||
selector: 'page-pick-up-option-list',
|
||||
templateUrl: 'pick-up-option-list.component.html',
|
||||
styleUrls: ['../list-options.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PickUpOptionListComponent {
|
||||
branches$ = this._store.branches$;
|
||||
selectedBranch$ = this._store.selectedPickUpBranch$.pipe(
|
||||
map((branch) => {
|
||||
// Determins if branch is targetBranch
|
||||
if (branch?.branchType === 1) {
|
||||
return branch.name;
|
||||
}
|
||||
})
|
||||
);
|
||||
selectedOption$ = this._store.selectedFilterOption$;
|
||||
optionChipDisabled$ = combineLatest([this._store.fetchingAvailabilities$, this.selectedBranch$]).pipe(
|
||||
map(([fetching, selectedBranch]) => {
|
||||
return fetching || !selectedBranch;
|
||||
})
|
||||
);
|
||||
|
||||
constructor(private _store: PurchasingOptionsListModalStore) {}
|
||||
|
||||
optionChange(option: string) {
|
||||
if (this._store.selectedFilterOption === option) {
|
||||
this._store.selectedFilterOption = undefined;
|
||||
} else {
|
||||
this._store.selectedFilterOption = option;
|
||||
}
|
||||
}
|
||||
|
||||
async selectBranch(branch: BranchDTO) {
|
||||
this._store.lastSelectedFilterOption$.next(undefined);
|
||||
|
||||
this._store.selectedPickUpBranch = branch;
|
||||
|
||||
const shoppingCartItems = await this._store.shoppingCartItems$.pipe(first()).toPromise();
|
||||
shoppingCartItems.forEach((item) => this._store.loadPickUpAvailability({ item }));
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
<div class="item-thumbnail">
|
||||
<img loading="lazy" *ngIf="item?.product?.ean | productImage; let thumbnailUrl" [src]="thumbnailUrl" [alt]="item?.product?.name" />
|
||||
</div>
|
||||
|
||||
<div class="item-contributors">
|
||||
{{ item.product.contributors }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="item-title"
|
||||
[class.xl]="item?.product?.name?.length >= 35"
|
||||
[class.lg]="item?.product?.name?.length >= 40"
|
||||
[class.md]="item?.product?.name?.length >= 50"
|
||||
[class.sm]="item?.product?.name?.length >= 60"
|
||||
[class.xs]="item?.product?.name?.length >= 100"
|
||||
>
|
||||
{{ item?.product?.name }}
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="canAdd$ | async; let canAdd">
|
||||
<div class="item-can-add" *ngIf="canAdd !== true">
|
||||
{{ canAdd }}
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div class="item-format" *ngIf="item?.product?.format && item?.product?.formatDetail">
|
||||
<img
|
||||
*ngIf="item?.product?.format !== '--'"
|
||||
src="assets/images/Icon_{{ item?.product?.format }}.svg"
|
||||
[alt]="item?.product?.formatDetail"
|
||||
/>
|
||||
{{ item?.product?.formatDetail }}
|
||||
</div>
|
||||
|
||||
<div class="item-info">
|
||||
{{ item?.product?.manufacturer | substr: 18 }} | {{ item?.product?.ean }} <br />
|
||||
{{ item?.product?.volume }} <span *ngIf="item?.product?.volume && item?.product?.publicationDate">|</span>
|
||||
{{ item?.product?.publicationDate | date: 'dd. MMMM yyyy' }}
|
||||
</div>
|
||||
|
||||
<div class="item-price-stock">
|
||||
<div class="price">
|
||||
<ng-container *ngIf="showTooltip$ | async">
|
||||
<button [uiOverlayTrigger]="tooltipContent" #tooltip="uiOverlayTrigger" class="info-tooltip-button" type="button">
|
||||
i
|
||||
</button>
|
||||
<ui-tooltip #tooltipContent yPosition="above" xPosition="after" [yOffset]="-16">
|
||||
Günstigerer Preis aus Hugendubel Katalog wird übernommen
|
||||
</ui-tooltip>
|
||||
</ng-container>
|
||||
|
||||
<div *ngIf="price$ | async; let price">{{ price?.value?.value | currency: price?.value?.currency:'code' }}</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<ui-quantity-dropdown
|
||||
[disabled]="fetchingAvailabilities$ | async"
|
||||
[ngModel]="item.quantity"
|
||||
(ngModelChange)="changeQuantity($event)"
|
||||
[range]="quantityRange$ | async"
|
||||
>
|
||||
</ui-quantity-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item-select">
|
||||
<ui-select-bullet
|
||||
*ngIf="selectVisible$ | async"
|
||||
[disabled]="selectDisabled$ | async"
|
||||
[ngModel]="isSelected$ | async"
|
||||
(ngModelChange)="selected($event)"
|
||||
></ui-select-bullet>
|
||||
</div>
|
||||
|
||||
<div class="item-availability">
|
||||
<div class="fetching" *ngIf="fetchingAvailabilities$ | async; else availabilities"></div>
|
||||
<ng-template #availabilities>
|
||||
<ng-container *ngIf="notAvailable$ | async; else available">
|
||||
<span class="hint">Derzeit nicht bestellbar</span>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #available>
|
||||
<span>Verfügbar als</span>
|
||||
<div *ngIf="takeAwayAvailabilities$ | async; let takeAwayAvailabilites">
|
||||
<ui-icon icon="shopping_bag" size="18px"></ui-icon>
|
||||
<span class="instock">{{ takeAwayAvailabilites?.inStock }}x</span> ab sofort
|
||||
</div>
|
||||
|
||||
<div *ngIf="!!(pickUpAvailabilities$ | async)">
|
||||
<ui-icon icon="box_out" size="18px"></ui-icon>
|
||||
{{ (pickUpAvailabilities$ | async)?.estimatedShippingDate | date: 'dd. MMMM yyyy' }}
|
||||
</div>
|
||||
|
||||
<div *ngIf="!!(deliveryDigAvailabilities$ | async); else b2b">
|
||||
<ui-icon class="truck" icon="truck" size="30px"></ui-icon>
|
||||
<ng-container *ngIf="deliveryDigAvailabilities$ | async; let deliveryDigAvailabilities">
|
||||
<ng-container *ngIf="deliveryDigAvailabilities?.estimatedDelivery; else estimatedShippingDate">
|
||||
{{ (deliveryDigAvailabilities?.estimatedDelivery?.start | date: 'EEE, dd.MM.')?.replace('.', '') }} -
|
||||
{{ (deliveryDigAvailabilities?.estimatedDelivery?.stop | date: 'EEE, dd.MM.')?.replace('.', '') }}
|
||||
</ng-container>
|
||||
<ng-template #estimatedShippingDate>
|
||||
{{ deliveryDigAvailabilities.estimatedShippingDate | date: 'dd. MMMM yyyy' }}
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<ng-template #b2b>
|
||||
<div *ngIf="!!(deliveryB2bAvailabilities$ | async)">
|
||||
<ui-icon class="truck-b2b" icon="truck_b2b" size="40px"></ui-icon>
|
||||
{{ (deliveryB2bAvailabilities$ | async)?.estimatedShippingDate | date: 'dd. MMMM yyyy' }}
|
||||
</div>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</div>
|
||||
@@ -1,180 +0,0 @@
|
||||
:host {
|
||||
@apply text-black no-underline grid py-4;
|
||||
grid-template-columns: 102px 60% auto;
|
||||
grid-template-rows: auto;
|
||||
grid-template-areas:
|
||||
'item-thumbnail item-contributors item-contributors'
|
||||
'item-thumbnail item-title item-price-stock'
|
||||
'item-thumbnail item-can-add item-price-stock'
|
||||
'item-thumbnail item-format item-price-stock'
|
||||
'item-thumbnail item-info item-select'
|
||||
'item-thumbnail item-date item-select'
|
||||
'item-thumbnail item-ssc item-select'
|
||||
'item-thumbnail item-availability item-select';
|
||||
}
|
||||
|
||||
.item-thumbnail {
|
||||
grid-area: item-thumbnail;
|
||||
width: 70px;
|
||||
@apply mr-8;
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 150px;
|
||||
@apply rounded-card shadow-cta;
|
||||
}
|
||||
}
|
||||
|
||||
.item-contributors {
|
||||
@apply font-bold no-underline;
|
||||
grid-area: item-contributors;
|
||||
height: 22px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
max-width: 600px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
grid-area: item-title;
|
||||
@apply font-bold text-lg mb-4;
|
||||
max-height: 64px;
|
||||
}
|
||||
|
||||
.item-title.xl {
|
||||
@apply font-bold text-xl;
|
||||
}
|
||||
|
||||
.item-title.lg {
|
||||
@apply font-bold text-lg;
|
||||
}
|
||||
|
||||
.item-title.md {
|
||||
@apply font-bold text-base;
|
||||
}
|
||||
|
||||
.item-title.sm {
|
||||
@apply font-bold text-sm;
|
||||
}
|
||||
|
||||
.item-title.xs {
|
||||
@apply font-bold text-xs;
|
||||
}
|
||||
|
||||
.item-format {
|
||||
grid-area: item-format;
|
||||
@apply flex flex-row items-center font-bold text-lg whitespace-nowrap;
|
||||
|
||||
img {
|
||||
@apply mr-2;
|
||||
}
|
||||
}
|
||||
|
||||
.item-price-stock {
|
||||
grid-area: item-price-stock;
|
||||
@apply font-bold text-xl text-right;
|
||||
|
||||
.price {
|
||||
@apply flex flex-row justify-end items-center;
|
||||
}
|
||||
|
||||
.info-tooltip-button {
|
||||
@apply border-font-customer border-solid border-2 bg-white rounded-full text-base font-bold mr-3;
|
||||
border-style: outset;
|
||||
width: 31px;
|
||||
height: 31px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.quantity-btn {
|
||||
@apply flex flex-row items-center p-0 w-full text-right outline-none border-none bg-transparent text-lg;
|
||||
}
|
||||
|
||||
.quantity-btn-icon {
|
||||
@apply inline-flex ml-2;
|
||||
transition: transform 200ms ease-in-out;
|
||||
}
|
||||
|
||||
ui-quantity-dropdown {
|
||||
@apply flex justify-end mt-2;
|
||||
|
||||
&.disabled {
|
||||
@apply cursor-not-allowed bg-inactive-branch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-stock {
|
||||
grid-area: item-stock;
|
||||
@apply flex flex-row justify-end items-baseline font-bold text-lg;
|
||||
|
||||
ui-icon {
|
||||
@apply text-active-customer mr-2;
|
||||
}
|
||||
}
|
||||
|
||||
.item-info {
|
||||
grid-area: item-info;
|
||||
}
|
||||
|
||||
.item-availability {
|
||||
@apply flex flex-row items-center mt-4 whitespace-nowrap text-sm;
|
||||
grid-area: item-availability;
|
||||
|
||||
.fetching {
|
||||
@apply w-52 h-px-20;
|
||||
background-color: #e6eff9;
|
||||
animation: load 0.75s linear infinite;
|
||||
}
|
||||
|
||||
span {
|
||||
@apply mr-4;
|
||||
}
|
||||
|
||||
.instock {
|
||||
@apply mr-2 font-bold;
|
||||
}
|
||||
|
||||
ui-icon {
|
||||
@apply text-dark-cerulean mx-2;
|
||||
}
|
||||
|
||||
div {
|
||||
@apply mr-4 flex items-center;
|
||||
}
|
||||
|
||||
.truck {
|
||||
@apply -mb-px-5 -mt-px-5;
|
||||
}
|
||||
|
||||
.truck-b2b {
|
||||
@apply -mb-px-10 -mt-px-10;
|
||||
}
|
||||
}
|
||||
|
||||
.item-can-add {
|
||||
@apply text-xl text-dark-goldenrod font-semibold;
|
||||
grid-area: item-can-add;
|
||||
}
|
||||
|
||||
.item-select {
|
||||
@apply flex items-center justify-end;
|
||||
grid-area: item-select;
|
||||
|
||||
ui-select-bullet {
|
||||
@apply cursor-pointer p-4 -m-4 z-dropdown;
|
||||
|
||||
&.disabled {
|
||||
@apply cursor-not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hint {
|
||||
@apply text-xl text-dark-goldenrod font-semibold;
|
||||
}
|
||||
|
||||
@screen desktop {
|
||||
.item-availability {
|
||||
@apply text-base;
|
||||
}
|
||||
}
|
||||
@@ -1,250 +0,0 @@
|
||||
import { Component, ChangeDetectionStrategy, Input } from '@angular/core';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { AvailabilityDTO, ShoppingCartItemDTO } from '@swagger/checkout';
|
||||
import { combineLatest, Observable } from 'rxjs';
|
||||
import { filter, map, shareReplay, withLatestFrom } from 'rxjs/operators';
|
||||
import { PurchasingOptionsListModalStore } from '../purchasing-options-list-modal.store';
|
||||
|
||||
@Component({
|
||||
selector: 'page-purchasing-options-list-item',
|
||||
templateUrl: 'purchasing-options-list-item.component.html',
|
||||
styleUrls: ['purchasing-options-list-item.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PurchasingOptionsListItemComponent {
|
||||
@Input()
|
||||
item: ShoppingCartItemDTO;
|
||||
|
||||
isSelected$ = this._store.selectedShoppingCartItems$.pipe(
|
||||
map((selectedShoppingCartItems) => !!selectedShoppingCartItems?.find((item) => item.id === this.item.id))
|
||||
);
|
||||
|
||||
fetchingAvailabilities$ = combineLatest([
|
||||
this._store.takeAwayAvailabilities$,
|
||||
this._store.pickUpAvailabilities$,
|
||||
this._store.deliveryAvailabilities$,
|
||||
this._store.deliveryDigAvailabilities$,
|
||||
this._store.deliveryB2bAvailabilities$,
|
||||
]).pipe(
|
||||
map(
|
||||
([takeAway, pickUp, delivery, digDelivery, b2bDelivery]) =>
|
||||
!takeAway ||
|
||||
takeAway[this.item.product.catalogProductNumber] === true ||
|
||||
!pickUp ||
|
||||
pickUp[this.item.product.catalogProductNumber] === true ||
|
||||
!delivery ||
|
||||
delivery[this.item.product.catalogProductNumber] === true ||
|
||||
!digDelivery ||
|
||||
digDelivery[this.item.product.catalogProductNumber] === true ||
|
||||
!b2bDelivery ||
|
||||
b2bDelivery[this.item.product.catalogProductNumber] === true
|
||||
)
|
||||
);
|
||||
|
||||
takeAwayAvailabilities$ = this._store.takeAwayAvailabilities$.pipe(
|
||||
map((takeAwayAvailabilities) => {
|
||||
if (takeAwayAvailabilities) {
|
||||
const availability = takeAwayAvailabilities[this.item.product?.catalogProductNumber];
|
||||
|
||||
if (typeof availability === 'boolean') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return availability;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
pickUpAvailabilities$: Observable<AvailabilityDTO> = this._store.pickUpAvailabilities$.pipe(
|
||||
map((pickUpAvailabilities) => {
|
||||
if (pickUpAvailabilities) {
|
||||
const availability = pickUpAvailabilities[this.item.product?.catalogProductNumber];
|
||||
|
||||
if (typeof availability === 'boolean') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return availability;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
deliveryAvailabilities$ = this._store.deliveryAvailabilities$.pipe(
|
||||
map((shippingAvailabilities) => (!!shippingAvailabilities ? shippingAvailabilities[this.item.product?.catalogProductNumber] : [])),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
deliveryDigAvailabilities$: Observable<AvailabilityDTO> = this._store.deliveryDigAvailabilities$.pipe(
|
||||
map((shippingAvailabilities) => {
|
||||
if (shippingAvailabilities) {
|
||||
const availability = shippingAvailabilities[this.item.product?.catalogProductNumber];
|
||||
|
||||
if (typeof availability === 'boolean') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return availability;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
deliveryB2bAvailabilities$ = this._store.deliveryB2bAvailabilities$.pipe(
|
||||
map((shippingAvailabilities) => {
|
||||
if (shippingAvailabilities) {
|
||||
const availability = shippingAvailabilities[this.item.product?.catalogProductNumber];
|
||||
|
||||
if (typeof availability === 'boolean') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return availability;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
notAvailable$ = combineLatest([
|
||||
this.fetchingAvailabilities$,
|
||||
this.takeAwayAvailabilities$,
|
||||
this.pickUpAvailabilities$,
|
||||
this.deliveryAvailabilities$,
|
||||
this.deliveryDigAvailabilities$,
|
||||
this.deliveryB2bAvailabilities$,
|
||||
]).pipe(
|
||||
map(
|
||||
([fetching, takeAway, store, delivery, deliveryDig, deliveryB2b]) =>
|
||||
!fetching && !takeAway && !store && !delivery && !deliveryDig && !deliveryB2b
|
||||
)
|
||||
);
|
||||
|
||||
showTooltip$ = this._store.selectedFilterOption$.pipe(
|
||||
withLatestFrom(this.deliveryAvailabilities$, this.deliveryDigAvailabilities$),
|
||||
map(([option, delivery, deliveryDig]) => {
|
||||
if (option === 'delivery') {
|
||||
const deliveryAvailability = (deliveryDig as AvailabilityDTO) || (delivery as AvailabilityDTO);
|
||||
|
||||
const shippingPrice = deliveryAvailability?.price?.value?.value;
|
||||
const catalogPrice = this.item?.availability?.price?.value?.value;
|
||||
return catalogPrice < shippingPrice;
|
||||
}
|
||||
return false;
|
||||
})
|
||||
);
|
||||
|
||||
price$ = combineLatest([this.fetchingAvailabilities$, this._store.selectedFilterOption$]).pipe(
|
||||
filter(([fetching]) => !fetching),
|
||||
withLatestFrom(
|
||||
this.takeAwayAvailabilities$,
|
||||
this.pickUpAvailabilities$,
|
||||
this.deliveryAvailabilities$,
|
||||
this.deliveryDigAvailabilities$,
|
||||
this.deliveryB2bAvailabilities$
|
||||
),
|
||||
map(([[_, option], takeAway, pickUp, delivery, deliveryDig, deliveryB2b]) => {
|
||||
let availability;
|
||||
|
||||
switch (option) {
|
||||
case 'take-away':
|
||||
availability = takeAway;
|
||||
break;
|
||||
case 'pick-up':
|
||||
availability = pickUp;
|
||||
break;
|
||||
case 'delivery':
|
||||
if (deliveryDig || delivery) {
|
||||
availability = deliveryDig || delivery;
|
||||
} else {
|
||||
availability = deliveryB2b;
|
||||
option = 'b2b-delivery';
|
||||
availability.p;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return this.item.availability?.price ?? this.item.unitPrice;
|
||||
}
|
||||
|
||||
return this._availabilityService.getPriceForAvailability(option, this.item.availability, availability) ?? this.item.unitPrice;
|
||||
})
|
||||
);
|
||||
|
||||
selectDisabled$ = this._store.selectedFilterOption$.pipe(map((selectedFilterOption) => !selectedFilterOption));
|
||||
|
||||
selectVisible$ = combineLatest([this._store.canAdd$, this._store.selectedShoppingCartItems$]).pipe(
|
||||
withLatestFrom(
|
||||
this._store.selectedFilterOption$,
|
||||
this._store.deliveryAvailabilities$,
|
||||
this._store.deliveryDigAvailabilities$,
|
||||
this._store.deliveryB2bAvailabilities$,
|
||||
this._store.fetchingAvailabilities$
|
||||
),
|
||||
map(([[canAdd, items], option, delivery, deliveryDig, deliveryB2b, fetching]) => {
|
||||
if (!option || fetching) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Select immer sichtbar bei ausgewählten Items
|
||||
if (items?.find((item) => item.product?.catalogProductNumber === this.item.product?.catalogProductNumber)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Select nur anzeigen, wenn ein anderes ausgewähltes Item die gleiche Verfügbarkeit hat (B2B Versand z.B.)
|
||||
if (items?.length > 0 && option === 'delivery' && canAdd[this.item.product.catalogProductNumber]?.status < 2) {
|
||||
if (items.every((item) => delivery[item.product?.catalogProductNumber]) && delivery[this.item.product?.catalogProductNumber]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
items.every((item) => deliveryDig[item.product?.catalogProductNumber]) &&
|
||||
deliveryDig[this.item.product?.catalogProductNumber]
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
items.every((item) => deliveryB2b[item.product?.catalogProductNumber]) &&
|
||||
deliveryB2b[this.item.product?.catalogProductNumber]
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return canAdd && canAdd[this.item.product.catalogProductNumber]?.status < 2;
|
||||
})
|
||||
);
|
||||
|
||||
canAdd$ = this._store.canAdd$.pipe(
|
||||
filter((canAdd) => !!this.item && !!canAdd),
|
||||
map((canAdd) => !!canAdd[this.item.product.catalogProductNumber]?.message)
|
||||
);
|
||||
|
||||
quantityRange$ = combineLatest([this._store.selectedFilterOption$, this.takeAwayAvailabilities$]).pipe(
|
||||
map(([option, availability]) => (option === 'take-away' ? (availability as AvailabilityDTO)?.inStock : 999))
|
||||
);
|
||||
|
||||
constructor(private _store: PurchasingOptionsListModalStore, private _availabilityService: DomainAvailabilityService) {}
|
||||
|
||||
selected(value: boolean) {
|
||||
this._store.selectShoppingCartItem([this.item], value);
|
||||
}
|
||||
|
||||
changeQuantity(quantity: number) {
|
||||
if (quantity === 0) {
|
||||
this._store.removeShoppingCartItem(this.item);
|
||||
} else {
|
||||
this._store.updateItemQuantity({ itemId: this.item.id, quantity });
|
||||
this._store.loadAvailabilities({ items: [{ ...this.item, quantity }] });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
<div class="options">
|
||||
<page-take-away-option-list></page-take-away-option-list>
|
||||
<page-pick-up-option-list></page-pick-up-option-list>
|
||||
<page-delivery-option-list></page-delivery-option-list>
|
||||
</div>
|
||||
|
||||
<div class="items" *ngIf="shoppingCartItems$ | async; let shoppingCartItems">
|
||||
<div class="item-actions">
|
||||
<ng-container>
|
||||
<button
|
||||
*ngIf="!(allShoppingCartItemsSelected$ | async); else unselectAll"
|
||||
class="cta-select-all"
|
||||
[disabled]="selectAllCtaDisabled$ | async"
|
||||
(click)="selectAll(shoppingCartItems, true)"
|
||||
>
|
||||
Alle auswählen
|
||||
</button>
|
||||
|
||||
<ng-template #unselectAll>
|
||||
<button class="cta-select-all" [disabled]="selectAllCtaDisabled$ | async" (click)="selectAll(shoppingCartItems, false)">
|
||||
Alle abwählen
|
||||
</button>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
||||
<br />
|
||||
{{ (selectedShoppingCartItems$ | async)?.length || 0 }} von {{ shoppingCartItems?.length || 0 }} Artikeln
|
||||
</div>
|
||||
|
||||
<div class="item-list scroll-bar" *ngIf="shoppingCartItems?.length > 0; else emptyMessage">
|
||||
<hr />
|
||||
<ng-container *ngFor="let item of shoppingCartItems">
|
||||
<page-purchasing-options-list-item [item]="item"></page-purchasing-options-list-item>
|
||||
<hr />
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<ng-template #emptyMessage>
|
||||
<div class="empty-message">Keine Artikel für die ausgewählte Kaufoption verfügbar</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button class="cta-apply" [disabled]="applyCtaDisabled$ | async" (click)="apply()">
|
||||
<ui-spinner [show]="addItemsLoader$ | async">
|
||||
Übernehmen
|
||||
</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
@@ -1,49 +0,0 @@
|
||||
:host {
|
||||
@apply block box-border;
|
||||
}
|
||||
|
||||
.options {
|
||||
@apply flex flex-row box-border text-center justify-center mt-4;
|
||||
}
|
||||
|
||||
.items {
|
||||
min-height: 440px;
|
||||
|
||||
.item-actions {
|
||||
@apply text-right;
|
||||
|
||||
.cta-select-all {
|
||||
@apply text-brand bg-transparent text-base font-bold outline-none border-none px-4 py-4 -mr-4;
|
||||
|
||||
&:disabled {
|
||||
@apply text-inactive-branch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-list {
|
||||
@apply overflow-y-scroll overflow-x-hidden -ml-4;
|
||||
max-height: calc(100vh - 580px);
|
||||
width: calc(100% + 2rem);
|
||||
|
||||
page-purchasing-options-list-item {
|
||||
@apply px-4;
|
||||
}
|
||||
}
|
||||
|
||||
.empty-message {
|
||||
@apply text-inactive-branch my-8 text-center font-bold;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
@apply flex justify-center mt-8;
|
||||
|
||||
.cta-apply {
|
||||
@apply text-white border-2 border-solid border-brand bg-brand font-bold text-lg px-4 py-2 rounded-full;
|
||||
|
||||
&:disabled {
|
||||
@apply bg-inactive-branch border-inactive-branch;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { ShoppingCartItemDTO, UpdateShoppingCartItemDTO } from '@swagger/checkout';
|
||||
import { UiErrorModalComponent, UiModalRef, UiModalService } from '@ui/modal';
|
||||
import { BehaviorSubject, combineLatest, Subject } from 'rxjs';
|
||||
import { debounceTime, filter, first, map, shareReplay, takeUntil, withLatestFrom } from 'rxjs/operators';
|
||||
import { PurchasingOptionsListModalData } from './purchasing-options-list-modal.data';
|
||||
import { PurchasingOptionsListModalStore } from './purchasing-options-list-modal.store';
|
||||
|
||||
@Component({
|
||||
selector: 'page-purchasing-options-list-modal',
|
||||
templateUrl: 'purchasing-options-list-modal.component.html',
|
||||
styleUrls: ['purchasing-options-list-modal.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [PurchasingOptionsListModalStore],
|
||||
})
|
||||
export class PurchasingOptionsListModalComponent implements OnInit {
|
||||
private _onDestroy$ = new Subject();
|
||||
|
||||
addItemsLoader$ = new BehaviorSubject<boolean>(false);
|
||||
|
||||
shoppingCartItems$ = combineLatest([
|
||||
this._store.fetchingAvailabilities$,
|
||||
this._store.selectedFilterOption$,
|
||||
this._store.shoppingCartItems$,
|
||||
]).pipe(
|
||||
withLatestFrom(
|
||||
this._store.takeAwayAvailabilities$,
|
||||
this._store.pickUpAvailabilities$,
|
||||
this._store.deliveryAvailabilities$,
|
||||
this._store.deliveryDigAvailabilities$,
|
||||
this._store.deliveryB2bAvailabilities$
|
||||
),
|
||||
map(
|
||||
([
|
||||
[_, selectedFilterOption, shoppingCartItems],
|
||||
takeAwayAvailability,
|
||||
pickUpAvailability,
|
||||
deliveryAvailability,
|
||||
deliveryDigAvailability,
|
||||
deliveryB2bAvailability,
|
||||
]) => {
|
||||
if (!!takeAwayAvailability && !!pickUpAvailability && !!deliveryAvailability) {
|
||||
switch (selectedFilterOption) {
|
||||
case 'take-away':
|
||||
return shoppingCartItems.filter((item) => !!takeAwayAvailability[item.product?.catalogProductNumber]);
|
||||
case 'pick-up':
|
||||
return shoppingCartItems.filter((item) => !!pickUpAvailability[item.product?.catalogProductNumber]);
|
||||
case 'delivery':
|
||||
return shoppingCartItems.filter(
|
||||
(item) =>
|
||||
!!deliveryAvailability[item.product?.catalogProductNumber] ||
|
||||
!!deliveryDigAvailability[item.product?.catalogProductNumber] ||
|
||||
!!deliveryB2bAvailability[item.product?.catalogProductNumber]
|
||||
);
|
||||
}
|
||||
}
|
||||
return shoppingCartItems;
|
||||
}
|
||||
),
|
||||
map((shoppingCartItems) => shoppingCartItems?.sort((a, b) => a.product?.name.localeCompare(b.product?.name))),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
selectedShoppingCartItems$ = this._store.selectedShoppingCartItems$;
|
||||
|
||||
allShoppingCartItemsSelected$ = combineLatest([this.shoppingCartItems$, this.selectedShoppingCartItems$]).pipe(
|
||||
map(
|
||||
([shoppingCartItems, selectedShoppingCartItems]) =>
|
||||
shoppingCartItems.every((item) => selectedShoppingCartItems.find((i) => item.id === i.id)) && shoppingCartItems?.length > 0
|
||||
)
|
||||
);
|
||||
|
||||
canAddItems$ = this._store.canAdd$.pipe(
|
||||
map((canAdd) => {
|
||||
for (const key in canAdd) {
|
||||
if (Object.prototype.hasOwnProperty.call(canAdd, key)) {
|
||||
if (!!canAdd[key]?.message) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
selectAllCtaDisabled$ = combineLatest([this._store.selectedFilterOption$, this.canAddItems$]).pipe(
|
||||
withLatestFrom(this.shoppingCartItems$),
|
||||
map(([[selectedFilterOption, canAddItems], items]) => !selectedFilterOption || items?.length === 0 || !canAddItems)
|
||||
);
|
||||
|
||||
applyCtaDisabled$ = combineLatest([this.addItemsLoader$, this._store.selectedFilterOption$, this._store.selectedShoppingCartItems$]).pipe(
|
||||
withLatestFrom(this.shoppingCartItems$),
|
||||
map(
|
||||
([[addItemsLoader, selectedFilterOption, selectedShoppingCartItems], shoppingCartItems]) =>
|
||||
addItemsLoader || !selectedFilterOption || shoppingCartItems?.length === 0 || selectedShoppingCartItems?.length === 0
|
||||
)
|
||||
);
|
||||
|
||||
constructor(
|
||||
private _modalRef: UiModalRef<any, PurchasingOptionsListModalData>,
|
||||
private _modal: UiModalService,
|
||||
private _store: PurchasingOptionsListModalStore,
|
||||
private _availability: DomainAvailabilityService,
|
||||
private _checkout: DomainCheckoutService
|
||||
) {
|
||||
this._store.shoppingCartItems = _modalRef.data.shoppingCartItems;
|
||||
this._store.customerFeatures = _modalRef.data.customerFeatures;
|
||||
this._store.processId = _modalRef.data.processId;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this._store.loadBranches();
|
||||
|
||||
// Beim Wechsel der ausgewählten Filteroption oder der Branches die Auswahl leeren
|
||||
combineLatest([this._store.selectedFilterOption$, this._store.selectedTakeAwayBranch$, this._store.selectedPickUpBranch$])
|
||||
.pipe(takeUntil(this._onDestroy$))
|
||||
.subscribe(() => this._store.clearSelectedShoppingCartItems());
|
||||
|
||||
this._store.selectedFilterOption$
|
||||
.pipe(takeUntil(this._onDestroy$), withLatestFrom(this.shoppingCartItems$))
|
||||
.subscribe(([option, items]) => this.checkCanAdd(option, items));
|
||||
|
||||
this._store.fetchingAvailabilities$
|
||||
.pipe(
|
||||
takeUntil(this._onDestroy$),
|
||||
debounceTime(250),
|
||||
filter((fetching) => !fetching),
|
||||
withLatestFrom(this.shoppingCartItems$, this._store.selectedFilterOption$)
|
||||
)
|
||||
.subscribe(([_, items, option]) => this.checkCanAdd(option, items));
|
||||
|
||||
this.canAddItems$
|
||||
.pipe(takeUntil(this._onDestroy$), withLatestFrom(this.shoppingCartItems$, this._store.selectedFilterOption$))
|
||||
.subscribe(([showSelectAll, items, option]) => {
|
||||
if (items?.length > 0 && this._store.lastSelectedFilterOption$.value !== option) {
|
||||
this.selectAll(items, showSelectAll && !!option);
|
||||
}
|
||||
|
||||
// Nach dem Übernehmen von Items wird eine neue CanAdd Abfrage ausgeführt, in diesem Fall soll aber nicht alles ausgewählt werden
|
||||
this._store.lastSelectedFilterOption$.next(option);
|
||||
});
|
||||
}
|
||||
|
||||
checkCanAdd(selectedFilterOption: string, items: ShoppingCartItemDTO[]) {
|
||||
if (!!selectedFilterOption && items?.length > 0) {
|
||||
this._store.checkCanAddItems(items);
|
||||
} else {
|
||||
this._store.patchState({ canAdd: {} });
|
||||
}
|
||||
}
|
||||
|
||||
async selectAll(items: ShoppingCartItemDTO[], value: boolean) {
|
||||
this._store.selectShoppingCartItem(items, value);
|
||||
}
|
||||
|
||||
async apply() {
|
||||
this.addItemsLoader$.next(true);
|
||||
|
||||
try {
|
||||
const shoppingCartItems = await this._store.shoppingCartItems$.pipe(first()).toPromise();
|
||||
const items = await this._store.selectedShoppingCartItems$.pipe(first()).toPromise();
|
||||
const takeAwayAvailabilities = await this._store.takeAwayAvailabilities$.pipe(first()).toPromise();
|
||||
const pickupAvailabilities = await this._store.pickUpAvailabilities$.pipe(first()).toPromise();
|
||||
const deliveryAvailabilities = await this._store.deliveryAvailabilities$.pipe(first()).toPromise();
|
||||
const deliveryB2bAvailabilities = await this._store.deliveryB2bAvailabilities$.pipe(first()).toPromise();
|
||||
const deliveryDigAvailabilities = await this._store.deliveryDigAvailabilities$.pipe(first()).toPromise();
|
||||
const selectedTakeAwayBranch = await this._store.selectedTakeAwayBranch$.pipe(first()).toPromise();
|
||||
const selectedPickUpBranch = await this._store.selectedPickUpBranch$.pipe(first()).toPromise();
|
||||
let option = this._store.selectedFilterOption;
|
||||
|
||||
for (const item of items) {
|
||||
let availability;
|
||||
switch (this._store.selectedFilterOption) {
|
||||
case 'take-away':
|
||||
availability = takeAwayAvailabilities[item.product.catalogProductNumber];
|
||||
break;
|
||||
case 'pick-up':
|
||||
availability = pickupAvailabilities[item.product.catalogProductNumber];
|
||||
break;
|
||||
case 'delivery':
|
||||
if (
|
||||
deliveryDigAvailabilities[item.product.catalogProductNumber] &&
|
||||
deliveryB2bAvailabilities[item.product.catalogProductNumber] &&
|
||||
deliveryAvailabilities[item.product.catalogProductNumber]
|
||||
) {
|
||||
availability = deliveryAvailabilities[item.product.catalogProductNumber];
|
||||
} else if (deliveryDigAvailabilities[item.product.catalogProductNumber]) {
|
||||
availability = deliveryDigAvailabilities[item.product.catalogProductNumber];
|
||||
} else if (deliveryB2bAvailabilities[item.product.catalogProductNumber]) {
|
||||
availability = deliveryB2bAvailabilities[item.product.catalogProductNumber];
|
||||
option = 'b2b-delivery';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
const price = this._availability.getPriceForAvailability(option, item.availability, availability);
|
||||
|
||||
// Negative Preise und nicht vorhandene Availability ignorieren
|
||||
if (price?.value?.value < 0 || !availability) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const updateItem: UpdateShoppingCartItemDTO = {
|
||||
quantity: item.quantity,
|
||||
availability: {
|
||||
...availability,
|
||||
price: price ? price : item.unitPrice,
|
||||
},
|
||||
promotion: item?.promotion?.points ? { points: item.promotion.points } : undefined,
|
||||
};
|
||||
|
||||
switch (this._store.selectedFilterOption) {
|
||||
case 'take-away':
|
||||
updateItem.destination = {
|
||||
data: { target: 1, targetBranch: { id: selectedTakeAwayBranch.id } },
|
||||
};
|
||||
break;
|
||||
case 'pick-up':
|
||||
updateItem.destination = {
|
||||
data: { target: 1, targetBranch: { id: selectedPickUpBranch.id } },
|
||||
};
|
||||
break;
|
||||
case 'delivery':
|
||||
case 'dig-delivery':
|
||||
case 'b2b-delivery':
|
||||
updateItem.destination = {
|
||||
data: { target: 2, logistician: availability?.logistician },
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
await this._checkout
|
||||
.updateItemInShoppingCart({
|
||||
processId: this._modalRef.data.processId,
|
||||
shoppingCartItemId: item.id,
|
||||
update: {
|
||||
...updateItem,
|
||||
},
|
||||
})
|
||||
.toPromise();
|
||||
}
|
||||
|
||||
const remainingItems = shoppingCartItems.filter((i) => !items.find((j) => i.id === j.id));
|
||||
this._store.shoppingCartItems = [...remainingItems];
|
||||
|
||||
this._store.clearSelectedShoppingCartItems();
|
||||
|
||||
if (remainingItems?.length === 0) {
|
||||
this._modalRef.close();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this._modal.open({ content: UiErrorModalComponent, data: error, title: 'Fehler beim Hinzufügen zum Warenkorb' });
|
||||
} finally {
|
||||
this.addItemsLoader$.next(false);
|
||||
}
|
||||
|
||||
const shoppingCartItems = await this.shoppingCartItems$.pipe(first()).toPromise();
|
||||
if (shoppingCartItems?.length > 0) {
|
||||
this._store.checkCanAddItems(shoppingCartItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import { ShoppingCartItemDTO } from '@swagger/checkout';
|
||||
|
||||
export interface PurchasingOptionsListModalData {
|
||||
processId: number;
|
||||
shoppingCartItems?: ShoppingCartItemDTO[];
|
||||
customerFeatures: { [key: string]: string };
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { PurchasingOptionsListModalComponent } from './purchasing-options-list-modal.component';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { ProductImageModule } from '@cdn/product-image';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { UiSelectBulletModule } from '@ui/select-bullet';
|
||||
import { UiQuantityDropdownModule } from '@ui/quantity-dropdown';
|
||||
import { PickUpOptionListComponent } from './pick-up-option/pick-up-option-list.component';
|
||||
import { TakeAwayOptionListComponent } from './take-away-option/take-away-option-list.component';
|
||||
import { DeliveryOptionListComponent } from './delivery-option/delivery-option-list.component';
|
||||
import { PurchasingOptionsListItemComponent } from './purchasing-options-list-item/purchasing-options-list-item.component';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { UiBranchDropdownModule } from '@ui/branch-dropdown';
|
||||
import { UiTooltipModule } from '@ui/tooltip';
|
||||
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
UiCommonModule,
|
||||
UiIconModule,
|
||||
UiSelectBulletModule,
|
||||
UiQuantityDropdownModule,
|
||||
ProductImageModule,
|
||||
UiBranchDropdownModule,
|
||||
UiTooltipModule,
|
||||
UiSpinnerModule,
|
||||
],
|
||||
exports: [PurchasingOptionsListModalComponent],
|
||||
declarations: [
|
||||
PurchasingOptionsListModalComponent,
|
||||
PurchasingOptionsListItemComponent,
|
||||
PickUpOptionListComponent,
|
||||
TakeAwayOptionListComponent,
|
||||
DeliveryOptionListComponent,
|
||||
],
|
||||
})
|
||||
export class PurchasingOptionsListModalModule {}
|
||||
@@ -1,598 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ComponentStore, tapResponse } from '@ngrx/component-store';
|
||||
import { AvailabilityDTO, BranchDTO, ShoppingCartItemDTO } from '@swagger/checkout';
|
||||
import { map, mergeMap, switchMap, withLatestFrom } from 'rxjs/operators';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { ApplicationService } from '@core/application';
|
||||
|
||||
interface PurchasingOptionsListModalState {
|
||||
processId: number;
|
||||
shoppingCartItems: ShoppingCartItemDTO[];
|
||||
selectedFilterOption: string;
|
||||
takeAwayAvailabilities: { [key: string]: AvailabilityDTO | true };
|
||||
pickUpAvailabilities: { [key: string]: AvailabilityDTO | true };
|
||||
deliveryAvailabilities: { [key: string]: AvailabilityDTO | true };
|
||||
deliveryB2bAvailabilities: { [key: string]: AvailabilityDTO | true };
|
||||
deliveryDigAvailabilities: { [key: string]: AvailabilityDTO | true };
|
||||
customerFeatures: { [key: string]: string };
|
||||
canAdd: { [key: string]: { message: string; status: number } };
|
||||
selectedShoppingCartItems: ShoppingCartItemDTO[];
|
||||
branches: BranchDTO[];
|
||||
currentBranch: BranchDTO;
|
||||
selectedTakeAwayBranch: BranchDTO;
|
||||
selectedPickUpBranch: BranchDTO;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class PurchasingOptionsListModalStore extends ComponentStore<PurchasingOptionsListModalState> {
|
||||
lastSelectedFilterOption$ = new BehaviorSubject<string>(undefined);
|
||||
|
||||
branches$ = this.select((s) => s.branches);
|
||||
currentBranch$ = this.select((s) => s.currentBranch);
|
||||
takeAwayAvailabilities$ = this.select((s) => s.takeAwayAvailabilities);
|
||||
pickUpAvailabilities$ = this.select((s) => s.pickUpAvailabilities);
|
||||
deliveryAvailabilities$ = this.select((s) => s.deliveryAvailabilities);
|
||||
deliveryB2bAvailabilities$ = this.select((s) => s.deliveryB2bAvailabilities);
|
||||
canAdd$ = this.select((s) => s.canAdd);
|
||||
deliveryDigAvailabilities$ = this.select((s) => s.deliveryDigAvailabilities);
|
||||
|
||||
shoppingCartItems$ = this.select((s) => s.shoppingCartItems);
|
||||
|
||||
set shoppingCartItems(shoppingCartItems: ShoppingCartItemDTO[]) {
|
||||
shoppingCartItems = shoppingCartItems.sort((a, b) => a.product?.name.localeCompare(b.product.name));
|
||||
this.patchState({ shoppingCartItems });
|
||||
}
|
||||
|
||||
processId$ = this.select((s) => s.processId);
|
||||
|
||||
set processId(processId: number) {
|
||||
this.patchState({ processId });
|
||||
}
|
||||
|
||||
customerFeatures$ = this.select((s) => s.customerFeatures);
|
||||
|
||||
set customerFeatures(customerFeatures: { [key: string]: string }) {
|
||||
this.patchState({ customerFeatures });
|
||||
}
|
||||
|
||||
selectedFilterOption$ = this.select((s) => s.selectedFilterOption);
|
||||
|
||||
set selectedFilterOption(selectedFilterOption: string) {
|
||||
this.patchState({ selectedFilterOption });
|
||||
}
|
||||
|
||||
get selectedFilterOption() {
|
||||
return this.get((s) => s.selectedFilterOption);
|
||||
}
|
||||
|
||||
selectedShoppingCartItems$ = this.select((s) => s.selectedShoppingCartItems);
|
||||
|
||||
get selectedShoppingCartItems() {
|
||||
return this.get((s) => s.selectedShoppingCartItems);
|
||||
}
|
||||
|
||||
selectedTakeAwayBranch$ = this.select((s) => s.selectedTakeAwayBranch);
|
||||
|
||||
set selectedTakeAwayBranch(selectedTakeAwayBranch: BranchDTO) {
|
||||
this.patchState({ selectedTakeAwayBranch });
|
||||
}
|
||||
|
||||
selectedPickUpBranch$ = this.select((s) => s.selectedPickUpBranch);
|
||||
|
||||
set selectedPickUpBranch(selectedPickUpBranch: BranchDTO) {
|
||||
this.patchState({ selectedPickUpBranch });
|
||||
}
|
||||
|
||||
fetchingAvailabilities$ = combineLatest([this.takeAwayAvailabilities$, this.pickUpAvailabilities$, this.deliveryAvailabilities$]).pipe(
|
||||
map(([takeAway, pickUp, delivery]) => {
|
||||
const fetchingCheck = (obj) => {
|
||||
for (const key in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
const element = obj[key];
|
||||
if (typeof element === 'boolean') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
return !takeAway || fetchingCheck(takeAway) || !pickUp || fetchingCheck(pickUp) || !delivery || fetchingCheck(delivery);
|
||||
})
|
||||
);
|
||||
|
||||
constructor(
|
||||
private _availabilityService: DomainAvailabilityService,
|
||||
private _checkoutService: DomainCheckoutService,
|
||||
private _application: ApplicationService
|
||||
) {
|
||||
super({
|
||||
processId: undefined,
|
||||
shoppingCartItems: [],
|
||||
selectedFilterOption: undefined,
|
||||
pickUpAvailabilities: undefined,
|
||||
deliveryAvailabilities: undefined,
|
||||
takeAwayAvailabilities: undefined,
|
||||
deliveryB2bAvailabilities: undefined,
|
||||
deliveryDigAvailabilities: undefined,
|
||||
selectedShoppingCartItems: [],
|
||||
branches: [],
|
||||
currentBranch: undefined,
|
||||
selectedTakeAwayBranch: undefined,
|
||||
selectedPickUpBranch: undefined,
|
||||
customerFeatures: undefined,
|
||||
canAdd: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
loadAvailabilities(options: { items?: ShoppingCartItemDTO[] }) {
|
||||
const shoppingCartItems = options.items ?? this.get((s) => s.shoppingCartItems);
|
||||
|
||||
for (const item of shoppingCartItems) {
|
||||
this.loadTakeAwayAvailability({ item });
|
||||
this.loadPickUpAvailability({ item });
|
||||
this.loadDeliveryAvailability({ item });
|
||||
this.loadDeliveryB2bAvailability({ item });
|
||||
this.loadDeliveryDigAvailability({ item });
|
||||
}
|
||||
}
|
||||
|
||||
readonly setAvailabilityFetching = this.updater((state, { name, id, fetching }: { name: string; id: string; fetching?: boolean }) => {
|
||||
const availability = { ...state[name] };
|
||||
|
||||
if (fetching) {
|
||||
availability[id] = fetching;
|
||||
} else {
|
||||
delete availability[id];
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
[name]: {
|
||||
...availability,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
readonly setAvailability = this.updater((state, { name, availability }: { name: string; availability: any }) => {
|
||||
const av = { ...state[name] };
|
||||
|
||||
if (this._availabilityService.isAvailable({ availability })) {
|
||||
av[availability.itemId] = availability;
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
[name]: av,
|
||||
};
|
||||
});
|
||||
|
||||
loadPickUpAvailability = this.effect((options$: Observable<{ item?: ShoppingCartItemDTO }>) =>
|
||||
options$.pipe(
|
||||
withLatestFrom(this.selectedPickUpBranch$),
|
||||
mergeMap(([options, branch]) => {
|
||||
this.setAvailabilityFetching({
|
||||
name: 'pickUpAvailabilities',
|
||||
id: options.item.product.catalogProductNumber,
|
||||
fetching: true,
|
||||
});
|
||||
|
||||
return this._availabilityService
|
||||
.getPickUpAvailability({
|
||||
item: {
|
||||
itemId: +options.item.product.catalogProductNumber,
|
||||
ean: options.item.product.ean,
|
||||
price: options.item.availability.price,
|
||||
},
|
||||
branch,
|
||||
quantity: options.item.quantity,
|
||||
})
|
||||
.pipe(
|
||||
map((av) => {
|
||||
if (av?.length > 0) {
|
||||
if (av[1].availableFor) {
|
||||
if ((av[1].availableFor & 2) === 2) {
|
||||
return av[0];
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
} else {
|
||||
return av[0];
|
||||
}
|
||||
}
|
||||
}),
|
||||
tapResponse(
|
||||
(availability) => {
|
||||
this.setAvailabilityFetching({
|
||||
name: 'pickUpAvailabilities',
|
||||
id: options.item.product.catalogProductNumber,
|
||||
});
|
||||
this.setAvailability({
|
||||
name: 'pickUpAvailabilities',
|
||||
availability: { ...availability, itemId: options.item.product.catalogProductNumber },
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setAvailabilityFetching({
|
||||
name: 'pickUpAvailabilities',
|
||||
id: options.item.product.catalogProductNumber,
|
||||
fetching: false,
|
||||
});
|
||||
this.setAvailability({ name: 'pickUpAvailabilities', availability: {} });
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
loadDeliveryAvailability = this.effect((options$: Observable<{ item?: ShoppingCartItemDTO }>) =>
|
||||
options$.pipe(
|
||||
mergeMap((options) => {
|
||||
this.setAvailabilityFetching({
|
||||
name: 'deliveryAvailabilities',
|
||||
id: options.item.product.catalogProductNumber,
|
||||
fetching: true,
|
||||
});
|
||||
|
||||
return this._availabilityService
|
||||
.getDeliveryAvailability({
|
||||
item: {
|
||||
itemId: +options.item.product.catalogProductNumber,
|
||||
ean: options.item.product.ean,
|
||||
price: options.item.availability.price,
|
||||
},
|
||||
quantity: options.item.quantity,
|
||||
})
|
||||
.pipe(
|
||||
tapResponse(
|
||||
(availability) => {
|
||||
this.setAvailabilityFetching({
|
||||
name: 'deliveryAvailabilities',
|
||||
id: options.item.product.catalogProductNumber,
|
||||
});
|
||||
this.setAvailability({
|
||||
name: 'deliveryAvailabilities',
|
||||
availability: { ...availability, itemId: options.item.product.catalogProductNumber },
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setAvailabilityFetching({
|
||||
name: 'deliveryAvailabilities',
|
||||
id: options.item.product.catalogProductNumber,
|
||||
fetching: false,
|
||||
});
|
||||
this.setAvailability({ name: 'deliveryAvailabilities', availability: {} });
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
loadDeliveryB2bAvailability = this.effect((options$: Observable<{ item?: ShoppingCartItemDTO }>) =>
|
||||
options$.pipe(
|
||||
mergeMap((options) => {
|
||||
this.setAvailabilityFetching({
|
||||
name: 'deliveryB2bAvailabilities',
|
||||
id: options.item.product.catalogProductNumber,
|
||||
fetching: true,
|
||||
});
|
||||
|
||||
return this._availabilityService
|
||||
.getB2bDeliveryAvailability({
|
||||
item: {
|
||||
itemId: +options.item.product.catalogProductNumber,
|
||||
ean: options.item.product.ean,
|
||||
price: options.item.availability.price,
|
||||
},
|
||||
quantity: options.item.quantity,
|
||||
})
|
||||
.pipe(
|
||||
tapResponse(
|
||||
(availability) => {
|
||||
this.setAvailabilityFetching({
|
||||
name: 'deliveryB2bAvailabilities',
|
||||
id: options.item.product.catalogProductNumber,
|
||||
});
|
||||
|
||||
this.setAvailability({
|
||||
name: 'deliveryB2bAvailabilities',
|
||||
availability: { ...availability, itemId: options.item.product.catalogProductNumber },
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setAvailabilityFetching({
|
||||
name: 'deliveryB2bAvailabilities',
|
||||
id: options.item.product.catalogProductNumber,
|
||||
fetching: false,
|
||||
});
|
||||
this.setAvailability({ name: 'deliveryB2bAvailabilities', availability: {} });
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
loadDeliveryDigAvailability = this.effect((options$: Observable<{ item?: ShoppingCartItemDTO }>) =>
|
||||
options$.pipe(
|
||||
mergeMap((options) => {
|
||||
this.setAvailabilityFetching({
|
||||
name: 'deliveryDigAvailabilities',
|
||||
id: options.item.product.catalogProductNumber,
|
||||
fetching: true,
|
||||
});
|
||||
|
||||
return this._availabilityService
|
||||
.getDigDeliveryAvailability({
|
||||
item: {
|
||||
itemId: +options.item.product.catalogProductNumber,
|
||||
ean: options.item.product.ean,
|
||||
price: options.item.availability.price,
|
||||
},
|
||||
quantity: options.item.quantity,
|
||||
})
|
||||
.pipe(
|
||||
tapResponse(
|
||||
(availability) => {
|
||||
this.setAvailabilityFetching({
|
||||
name: 'deliveryDigAvailabilities',
|
||||
id: options.item.product.catalogProductNumber,
|
||||
});
|
||||
this.setAvailability({
|
||||
name: 'deliveryDigAvailabilities',
|
||||
availability: { ...availability, itemId: options.item.product.catalogProductNumber },
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setAvailabilityFetching({
|
||||
name: 'deliveryDigAvailabilities',
|
||||
id: options.item.product.catalogProductNumber,
|
||||
fetching: false,
|
||||
});
|
||||
this.setAvailability({ name: 'deliveryDigAvailabilities', availability: {} });
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
loadTakeAwayAvailability = this.effect((options$: Observable<{ item?: ShoppingCartItemDTO }>) =>
|
||||
options$.pipe(
|
||||
withLatestFrom(this.selectedTakeAwayBranch$),
|
||||
mergeMap(([options, branch]) => {
|
||||
this.setAvailabilityFetching({
|
||||
name: 'takeAwayAvailabilities',
|
||||
id: options.item.product.catalogProductNumber,
|
||||
fetching: true,
|
||||
});
|
||||
|
||||
return this._availabilityService
|
||||
.getTakeAwayAvailabilityByBranch({
|
||||
itemId: +options.item.product.catalogProductNumber,
|
||||
price: options.item.availability.price,
|
||||
quantity: options.item.quantity,
|
||||
branch,
|
||||
})
|
||||
.pipe(
|
||||
tapResponse(
|
||||
(availability) => {
|
||||
this.setAvailabilityFetching({
|
||||
name: 'takeAwayAvailabilities',
|
||||
id: options.item.product.catalogProductNumber,
|
||||
});
|
||||
this.setAvailability({
|
||||
name: 'takeAwayAvailabilities',
|
||||
availability: { ...availability, itemId: options.item.product.catalogProductNumber },
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setAvailabilityFetching({
|
||||
name: 'takeAwayAvailabilities',
|
||||
id: options.item.product.catalogProductNumber,
|
||||
fetching: false,
|
||||
});
|
||||
this.setAvailability({ name: 'takeAwayAvailabilities', availability: {} });
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
getCurrentBranch() {
|
||||
return combineLatest([this._application.getSelectedBranch$(), this._availabilityService.getDefaultBranch()]).pipe(
|
||||
map(([selectedBranch, defaultBranch]) => selectedBranch || defaultBranch)
|
||||
);
|
||||
}
|
||||
|
||||
loadBranches = this.effect(($) =>
|
||||
$.pipe(
|
||||
switchMap(() =>
|
||||
this._availabilityService.getBranches().pipe(
|
||||
map((branches) =>
|
||||
branches.filter(
|
||||
(branch) => branch.status === 1 && branch.branchType === 1 && branch.isOnline === true && branch.isShippingEnabled === true
|
||||
)
|
||||
),
|
||||
withLatestFrom(this.getCurrentBranch()),
|
||||
tapResponse(
|
||||
([branches, currentBranch]) => {
|
||||
this.patchState({
|
||||
branches,
|
||||
selectedTakeAwayBranch: currentBranch,
|
||||
selectedPickUpBranch: currentBranch,
|
||||
currentBranch,
|
||||
});
|
||||
this.loadAvailabilities({});
|
||||
},
|
||||
() =>
|
||||
this.patchState({
|
||||
branches: [],
|
||||
selectedTakeAwayBranch: undefined,
|
||||
selectedPickUpBranch: undefined,
|
||||
currentBranch: undefined,
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
checkCanAddItems = this.effect((items$: Observable<ShoppingCartItemDTO[]>) =>
|
||||
items$.pipe(
|
||||
withLatestFrom(
|
||||
this.processId$,
|
||||
this.selectedFilterOption$,
|
||||
this.takeAwayAvailabilities$,
|
||||
this.pickUpAvailabilities$,
|
||||
this.deliveryAvailabilities$,
|
||||
this.deliveryB2bAvailabilities$,
|
||||
this.deliveryDigAvailabilities$
|
||||
),
|
||||
mergeMap(([items, processId, selectedOption, takeAway, pickUp, delivery, deliveryB2b, deliveryDig]) => {
|
||||
let orderType: string;
|
||||
const payload = items.map((item) => {
|
||||
switch (selectedOption) {
|
||||
case 'take-away':
|
||||
orderType = 'Rücklage';
|
||||
return {
|
||||
availabilities: [this.getOlaAvailability(takeAway[item.product.catalogProductNumber], item)],
|
||||
id: item.product.catalogProductNumber,
|
||||
};
|
||||
case 'pick-up':
|
||||
orderType = 'Abholung';
|
||||
return {
|
||||
availabilities: [this.getOlaAvailability(pickUp[item.product.catalogProductNumber], item)],
|
||||
id: item.product.catalogProductNumber,
|
||||
};
|
||||
case 'delivery':
|
||||
orderType = 'Versand';
|
||||
if (
|
||||
deliveryDig[item.product.catalogProductNumber] &&
|
||||
deliveryB2b[item.product.catalogProductNumber] &&
|
||||
delivery[item.product.catalogProductNumber]
|
||||
) {
|
||||
return {
|
||||
availabilities: [this.getOlaAvailability(delivery[item.product.catalogProductNumber], item)],
|
||||
id: item.product.catalogProductNumber,
|
||||
};
|
||||
} else if (deliveryDig[item.product.catalogProductNumber]) {
|
||||
return {
|
||||
availabilities: [this.getOlaAvailability(deliveryDig[item.product.catalogProductNumber], item)],
|
||||
id: item.product.catalogProductNumber,
|
||||
};
|
||||
} else if (deliveryB2b[item.product.catalogProductNumber]) {
|
||||
return {
|
||||
availabilities: [this.getOlaAvailability(deliveryB2b[item.product.catalogProductNumber], item)],
|
||||
id: item.product.catalogProductNumber,
|
||||
};
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return this._checkoutService.canAddItems({ processId, payload, orderType }).pipe(
|
||||
tapResponse(
|
||||
(result: any) => {
|
||||
const canAdd = {};
|
||||
|
||||
result?.forEach((r) => {
|
||||
canAdd[r.id] = { message: r.message, status: r.status };
|
||||
});
|
||||
|
||||
this.patchState({ canAdd });
|
||||
},
|
||||
(error: Error) => {
|
||||
const canAdd = {};
|
||||
|
||||
items?.forEach((i) => {
|
||||
canAdd[i.product?.catalogProductNumber] = { message: error?.message };
|
||||
});
|
||||
|
||||
this.patchState({ canAdd });
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
getOlaAvailability(availability: AvailabilityDTO, item: ShoppingCartItemDTO) {
|
||||
return {
|
||||
qty: item.quantity,
|
||||
ean: item.product.ean,
|
||||
itemId: item.product.catalogProductNumber,
|
||||
format: item.product.format,
|
||||
at: availability?.estimatedShippingDate,
|
||||
isPrebooked: availability?.isPrebooked,
|
||||
status: availability?.availabilityType,
|
||||
logisticianId: availability?.logistician?.id,
|
||||
price: availability?.price,
|
||||
ssc: availability?.ssc,
|
||||
sscText: availability?.sscText,
|
||||
supplierId: availability?.supplier?.id,
|
||||
};
|
||||
}
|
||||
|
||||
readonly updateItemQuantity = this.updater((state, value: { itemId: number; quantity: number }) => {
|
||||
const itemToUpdate = state.shoppingCartItems.find((item) => item.id === value.itemId);
|
||||
const otherItems = state.shoppingCartItems.filter((item) => item.id !== value.itemId);
|
||||
const updatedItem = { ...itemToUpdate, quantity: value.quantity };
|
||||
const shoppingCartItems = [...otherItems, updatedItem].sort((a, b) => a.product?.name.localeCompare(b.product.name));
|
||||
|
||||
// Ausgewählte Items auch aktualisieren
|
||||
let selectedShoppingCartItems = state.selectedShoppingCartItems;
|
||||
if (state.selectedShoppingCartItems.find((item) => item.id === value.itemId)) {
|
||||
const selectedItems = state.selectedShoppingCartItems.filter((item) => item.id !== value.itemId);
|
||||
selectedShoppingCartItems = [...selectedItems, updatedItem].sort((a, b) => a.product?.name.localeCompare(b.product.name));
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
shoppingCartItems,
|
||||
selectedShoppingCartItems,
|
||||
};
|
||||
});
|
||||
|
||||
async removeShoppingCartItem(item: ShoppingCartItemDTO) {
|
||||
const items = this.get((s) => s.shoppingCartItems);
|
||||
const processId = this.get((s) => s.processId);
|
||||
|
||||
await this._checkoutService
|
||||
.updateItemInShoppingCart({
|
||||
processId,
|
||||
shoppingCartItemId: item.id,
|
||||
update: {
|
||||
quantity: 0,
|
||||
availability: null,
|
||||
},
|
||||
})
|
||||
.toPromise();
|
||||
this.selectShoppingCartItem([item], false);
|
||||
const shoppingCartItems = items.filter((i) => i.id !== item.id);
|
||||
this.patchState({ shoppingCartItems });
|
||||
}
|
||||
|
||||
selectShoppingCartItem(shoppingCartItems: ShoppingCartItemDTO[], selected: boolean) {
|
||||
if (selected) {
|
||||
this.patchState({
|
||||
selectedShoppingCartItems: [
|
||||
...this.selectedShoppingCartItems.filter((item) => !shoppingCartItems.find((i) => item.id === i.id)),
|
||||
...shoppingCartItems,
|
||||
],
|
||||
});
|
||||
} else {
|
||||
this.patchState({
|
||||
selectedShoppingCartItems: this.selectedShoppingCartItems.filter((item) => !shoppingCartItems.find((i) => item.id === i.id)),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
clearSelectedShoppingCartItems() {
|
||||
this.patchState({ selectedShoppingCartItems: [] });
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
// start:ng42.barrel
|
||||
export * from './take-away-option-list.component';
|
||||
// end:ng42.barrel
|
||||
@@ -1,18 +0,0 @@
|
||||
<div class="option-icon">
|
||||
<ui-icon size="50px" icon="shopping_bag"></ui-icon>
|
||||
</div>
|
||||
<button
|
||||
class="option-chip"
|
||||
[disabled]="optionChipDisabled$ | async"
|
||||
(click)="optionChange('take-away')"
|
||||
[class.selected]="(selectedOption$ | async) === 'take-away'"
|
||||
>
|
||||
Rücklage
|
||||
</button>
|
||||
<p>Möchten Sie die Artikel<br />zurücklegen lassen oder<br />sofort mitnehmen?</p>
|
||||
|
||||
<ui-branch-dropdown
|
||||
[branches]="branches$ | async"
|
||||
[selected]="selectedBranch$ | async"
|
||||
(selectBranch)="selectBranch($event)"
|
||||
></ui-branch-dropdown>
|
||||
@@ -1,48 +0,0 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { BranchDTO } from '@swagger/checkout';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { first, map } from 'rxjs/operators';
|
||||
import { PurchasingOptionsListModalStore } from '../purchasing-options-list-modal.store';
|
||||
|
||||
@Component({
|
||||
selector: 'page-take-away-option-list',
|
||||
templateUrl: 'take-away-option-list.component.html',
|
||||
styleUrls: ['../list-options.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class TakeAwayOptionListComponent {
|
||||
branches$ = this._store.branches$;
|
||||
selectedBranch$ = this._store.selectedTakeAwayBranch$.pipe(
|
||||
map((branch) => {
|
||||
// Determins if branch is targetBranch
|
||||
if (branch?.branchType === 1) {
|
||||
return branch.name;
|
||||
}
|
||||
})
|
||||
);
|
||||
selectedOption$ = this._store.selectedFilterOption$;
|
||||
optionChipDisabled$ = combineLatest([this._store.fetchingAvailabilities$, this.selectedBranch$]).pipe(
|
||||
map(([fetching, selectedBranch]) => {
|
||||
return fetching || !selectedBranch;
|
||||
})
|
||||
);
|
||||
|
||||
constructor(private _store: PurchasingOptionsListModalStore) {}
|
||||
|
||||
optionChange(option: string) {
|
||||
if (this._store.selectedFilterOption === option) {
|
||||
this._store.selectedFilterOption = undefined;
|
||||
} else {
|
||||
this._store.selectedFilterOption = option;
|
||||
}
|
||||
}
|
||||
|
||||
async selectBranch(branch: BranchDTO) {
|
||||
this._store.lastSelectedFilterOption$.next(undefined);
|
||||
|
||||
this._store.selectedTakeAwayBranch = branch;
|
||||
|
||||
const shoppingCartItems = await this._store.shoppingCartItems$.pipe(first()).toPromise();
|
||||
shoppingCartItems.forEach((item) => this._store.loadTakeAwayAvailability({ item }));
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
<ng-container *ngIf="item$ | async; let item">
|
||||
<ng-container *ngIf="availability$ | async; let availability">
|
||||
<div class="option-icon">
|
||||
<ui-icon size="80px" icon="truck_b2b"></ui-icon>
|
||||
</div>
|
||||
|
||||
<h4>B2B Versand</h4>
|
||||
<p>
|
||||
Als B2B Kunde können wir Ihnen den Artikel auch liefern.
|
||||
</p>
|
||||
<span class="price" *ngIf="price$ | async; let price">{{ price?.value?.value | currency: price?.value?.currency:'code' }}</span>
|
||||
<div class="grow"></div>
|
||||
<span class="delivery">Versandkostenfrei</span>
|
||||
<span class="date"
|
||||
>Versanddatum <strong>{{ availability?.estimatedShippingDate | date: 'shortDate' }}</strong></span
|
||||
>
|
||||
<div>
|
||||
<button [disabled]="availability.price?.value?.value < 0" type="button" class="select-option" (click)="select()">
|
||||
Auswählen
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
@@ -1,9 +0,0 @@
|
||||
.option-icon {
|
||||
margin-top: -12px;
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
@apply font-bold;
|
||||
margin-top: -2px;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { PurchasingOptionsModalStore } from '../purchasing-options-modal.store';
|
||||
|
||||
@Component({
|
||||
selector: 'page-b2b-delivery-option',
|
||||
templateUrl: 'b2b-delivery-option.component.html',
|
||||
styleUrls: ['../option.scss', 'b2b-delivery-option.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class B2BDeliveryOptionComponent {
|
||||
readonly item$ = this._purchasingOptionsModalStore.selectItem;
|
||||
|
||||
readonly availability$ = this._purchasingOptionsModalStore.selectAvailabilities.pipe(map((ava) => ava['b2b-delivery']));
|
||||
|
||||
readonly price$ = combineLatest([this.availability$, this.item$]).pipe(
|
||||
map(([availability, item]) => this._availabilityService.getPriceForAvailability('b2b-delivery', item.catalogAvailability, availability))
|
||||
);
|
||||
|
||||
constructor(private _purchasingOptionsModalStore: PurchasingOptionsModalStore, private _availabilityService: DomainAvailabilityService) {}
|
||||
|
||||
select() {
|
||||
this._purchasingOptionsModalStore.setOption('b2b-delivery');
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
// start:ng42.barrel
|
||||
export * from './b2b-delivery-option.component';
|
||||
// end:ng42.barrel
|
||||
@@ -1,41 +0,0 @@
|
||||
<ng-container *ngIf="item$ | async; let item">
|
||||
<ng-container *ngIf="availability$ | async; let availability">
|
||||
<div class="option-icon">
|
||||
<ui-icon size="50px" icon="truck"></ui-icon>
|
||||
</div>
|
||||
<h4>Versand</h4>
|
||||
<p>
|
||||
Möchten Sie den Artikel geliefert bekommen?
|
||||
</p>
|
||||
<div class="price-wrapper">
|
||||
<span class="price" *ngIf="price$ | async; let price">{{ price?.value?.value | currency: price?.value?.currency:'code' }}</span>
|
||||
<ng-container *ngIf="showTooltip$ | async">
|
||||
<button [uiOverlayTrigger]="tooltipContent" #tooltip="uiOverlayTrigger" class="info-tooltip-button" type="button">
|
||||
i
|
||||
</button>
|
||||
<ui-tooltip #tooltipContent yPosition="above" xPosition="after" [yOffset]="-16">
|
||||
Günstigerer Preis aus Hugendubel Katalog wird übernommen
|
||||
</ui-tooltip>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="grow"></div>
|
||||
<span class="delivery">Versandkostenfrei</span>
|
||||
<span *ngIf="availability?.estimatedDelivery; else estimatedShippingDateTmpl" class="date">
|
||||
Zustellung zwischen <br />
|
||||
<strong
|
||||
>{{ (availability?.estimatedDelivery?.start | date: 'EEE, dd.MM.')?.replace('.', '') }} und
|
||||
{{ (availability?.estimatedDelivery?.stop | date: 'EEE, dd.MM.')?.replace('.', '') }}</strong
|
||||
>
|
||||
</span>
|
||||
<ng-template #estimatedShippingDateTmpl>
|
||||
<span class="date">
|
||||
Versanddatum <strong>{{ availability?.estimatedShippingDate | date }}</strong>
|
||||
</span>
|
||||
</ng-template>
|
||||
<div>
|
||||
<button [disabled]="availability.price?.value?.value < 0" type="button" class="select-option" (click)="select()">
|
||||
Auswählen
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
@@ -1,15 +0,0 @@
|
||||
.price-wrapper {
|
||||
@apply mt-2;
|
||||
}
|
||||
|
||||
.info-tooltip-button {
|
||||
@apply border-font-customer border-solid border-2 bg-white rounded-full text-base font-bold;
|
||||
border-style: outset;
|
||||
width: 31px;
|
||||
height: 31px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
@apply font-bold;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { PurchasingOptionsModalStore } from '../purchasing-options-modal.store';
|
||||
|
||||
@Component({
|
||||
selector: 'page-delivery-option',
|
||||
templateUrl: 'delivery-option.component.html',
|
||||
styleUrls: ['../option.scss', 'delivery-option.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class DeliveryOptionComponent {
|
||||
readonly item$ = this._purchasingOptionsModalStore.selectItem;
|
||||
|
||||
readonly availability$ = this._purchasingOptionsModalStore.selectAvailabilities.pipe(map((ava) => ava['delivery']));
|
||||
|
||||
readonly showTooltip$ = combineLatest([this.availability$, this.item$]).pipe(
|
||||
map(([availability, item]) => {
|
||||
const shippingPrice = availability?.price?.value?.value;
|
||||
const catalogPrice = item?.catalogAvailability?.price?.value?.value;
|
||||
return catalogPrice < shippingPrice;
|
||||
})
|
||||
);
|
||||
|
||||
readonly price$ = combineLatest([this.availability$, this.item$]).pipe(
|
||||
map(([availability, item]) => this._availabilityService.getPriceForAvailability('delivery', item.catalogAvailability, availability))
|
||||
);
|
||||
|
||||
constructor(private _purchasingOptionsModalStore: PurchasingOptionsModalStore, private _availabilityService: DomainAvailabilityService) {}
|
||||
|
||||
select() {
|
||||
this._purchasingOptionsModalStore.setOption('delivery');
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
// start:ng42.barrel
|
||||
export * from './delivery-option.component';
|
||||
// end:ng42.barrel
|
||||
@@ -1,40 +0,0 @@
|
||||
<ng-container *ngIf="item$ | async; let item">
|
||||
<ng-container *ngIf="availability$ | async; let availability">
|
||||
<div class="option-icon">
|
||||
<ui-icon size="50px" icon="truck"></ui-icon>
|
||||
</div>
|
||||
<h4>DIG Versand</h4>
|
||||
<p>Möchten Sie den Artikel geliefert bekommen?</p>
|
||||
<div class="price-wrapper">
|
||||
<span class="price" *ngIf="price$ | async; let price">{{ price?.value?.value | currency: price?.value?.currency:'code' }}</span>
|
||||
<ng-container *ngIf="showTooltip$ | async">
|
||||
<button [uiOverlayTrigger]="tooltipContent" #tooltip="uiOverlayTrigger" class="info-tooltip-button" type="button">
|
||||
i
|
||||
</button>
|
||||
<ui-tooltip #tooltipContent yPosition="above" xPosition="after" [yOffset]="-16">
|
||||
Günstigerer Preis aus Hugendubel Katalog wird übernommen
|
||||
</ui-tooltip>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="grow"></div>
|
||||
<span class="delivery">Versandkostenfrei</span>
|
||||
<span *ngIf="availability?.estimatedDelivery; else estimatedShippingDateTmpl" class="date">
|
||||
Zustellung zwischen <br />
|
||||
<strong
|
||||
>{{ (availability?.estimatedDelivery?.start | date: 'EEE, dd.MM.')?.replace('.', '') }} und
|
||||
{{ (availability?.estimatedDelivery?.stop | date: 'EEE, dd.MM.')?.replace('.', '') }}</strong
|
||||
>
|
||||
</span>
|
||||
<ng-template #estimatedShippingDateTmpl>
|
||||
<span class="date">
|
||||
Versanddatum <strong>{{ availability?.estimatedShippingDate | date }}</strong>
|
||||
</span>
|
||||
</ng-template>
|
||||
|
||||
<div>
|
||||
<button [disabled]="availability.price?.value?.value < 0" type="button" class="select-option" (click)="select()">
|
||||
Auswählen
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
@@ -1,15 +0,0 @@
|
||||
.price-wrapper {
|
||||
@apply mt-2;
|
||||
}
|
||||
|
||||
.info-tooltip-button {
|
||||
@apply border-font-customer bg-white rounded-full text-base font-bold;
|
||||
border-style: outset;
|
||||
width: 31px;
|
||||
height: 31px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
@apply font-bold;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { PurchasingOptionsModalStore } from '../purchasing-options-modal.store';
|
||||
|
||||
@Component({
|
||||
selector: 'page-dig-delivery-option',
|
||||
templateUrl: 'dig-delivery-option.component.html',
|
||||
styleUrls: ['../option.scss', 'dig-delivery-option.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class DigDeliveryOptionComponent {
|
||||
readonly item$ = this._purchasingOptionsModalStore.selectItem;
|
||||
|
||||
readonly availability$ = this._purchasingOptionsModalStore.selectAvailabilities.pipe(map((ava) => ava['dig-delivery']));
|
||||
|
||||
readonly showTooltip$ = combineLatest([this.availability$, this.item$]).pipe(
|
||||
map(([availability, item]) => {
|
||||
const shippingPrice = availability?.price?.value?.value;
|
||||
const catalogPrice = item?.catalogAvailability?.price?.value?.value;
|
||||
return catalogPrice < shippingPrice;
|
||||
})
|
||||
);
|
||||
|
||||
readonly price$ = combineLatest([this.availability$, this.item$]).pipe(
|
||||
map(([availability, item]) => this._availabilityService.getPriceForAvailability('dig-delivery', item.catalogAvailability, availability))
|
||||
);
|
||||
|
||||
constructor(private _purchasingOptionsModalStore: PurchasingOptionsModalStore, private _availabilityService: DomainAvailabilityService) {}
|
||||
|
||||
select() {
|
||||
this._purchasingOptionsModalStore.setOption('dig-delivery');
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
// start:ng42.barrel
|
||||
export * from './dig-delivery-option.component';
|
||||
// end:ng42.barrel
|
||||
@@ -1,6 +0,0 @@
|
||||
// start:ng42.barrel
|
||||
export * from './options';
|
||||
export * from './purchasing-options-modal.component';
|
||||
export * from './purchasing-options-modal.data';
|
||||
export * from './purchasing-options-modal.module';
|
||||
// end:ng42.barrel
|
||||
@@ -1,41 +0,0 @@
|
||||
:host {
|
||||
@apply flex flex-col box-border text-center;
|
||||
width: 202px;
|
||||
}
|
||||
|
||||
.option-icon {
|
||||
@apply text-ucla-blue mx-auto;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
@apply text-2xl mt-4 mb-0;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply my-2;
|
||||
}
|
||||
|
||||
.price {
|
||||
@apply font-bold my-2;
|
||||
}
|
||||
|
||||
.delivery {
|
||||
@apply text-regular mb-px-5;
|
||||
}
|
||||
|
||||
.date {
|
||||
@apply text-cta-l whitespace-nowrap;
|
||||
}
|
||||
|
||||
.grow {
|
||||
@apply flex-grow;
|
||||
}
|
||||
|
||||
.select-option {
|
||||
@apply mt-4 mb-4 border-2 border-solid border-brand text-brand text-cta-l font-bold bg-white rounded-full py-3 px-6;
|
||||
}
|
||||
|
||||
.select-option:disabled {
|
||||
@apply bg-disabled-branch border-disabled-branch text-white;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// start:ng42.barrel
|
||||
export * from './b2b-delivery-option';
|
||||
export * from './delivery-option';
|
||||
export * from './dig-delivery-option';
|
||||
export * from './pick-up-option';
|
||||
export * from './take-away-option';
|
||||
// end:ng42.barrel
|
||||
@@ -1,3 +0,0 @@
|
||||
// start:ng42.barrel
|
||||
export * from './pick-up-option.component';
|
||||
// end:ng42.barrel
|
||||
@@ -1,32 +0,0 @@
|
||||
<ng-container *ngIf="item$ | async; let item">
|
||||
<ng-container *ngIf="availability$ | async; let availability">
|
||||
<div class="option-icon">
|
||||
<ui-icon size="50px" icon="box_out"></ui-icon>
|
||||
</div>
|
||||
<h4>Abholung</h4>
|
||||
<p>
|
||||
Möchten Sie den Artikel in einer unserer Filialen abholen?
|
||||
</p>
|
||||
<span class="price" *ngIf="price$ | async; let price">{{ price?.value?.value | currency: price?.value?.currency:'code' }}</span>
|
||||
<ui-branch-dropdown
|
||||
class="min-h-[38px]"
|
||||
[branches]="branches$ | async"
|
||||
[selected]="selected$ | async"
|
||||
(selectBranch)="selectBranch($event)"
|
||||
></ui-branch-dropdown>
|
||||
<span class="date"
|
||||
>Abholung ab <strong>{{ (availability$ | async)?.estimatedShippingDate | date: 'shortDate' }}</strong></span
|
||||
>
|
||||
<div class="grow"></div>
|
||||
<div>
|
||||
<button
|
||||
[disabled]="availability.price?.value?.value < 0 || !(selected$ | async)"
|
||||
type="button"
|
||||
class="select-option"
|
||||
(click)="select()"
|
||||
>
|
||||
Auswählen
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
@@ -1,3 +0,0 @@
|
||||
h4 {
|
||||
@apply font-bold;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user