mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
Merged PR 1104: #2662 Listenbestellung Download OLA im Warenkorb bei Bestellen Klick
#2662 Listenbestellung Download OLA im Warenkorb bei Bestellen Klick Related work items: #2662
This commit is contained in:
committed by
Lorenz Hilpert
parent
92958f4b22
commit
12fe8b46c3
@@ -24,7 +24,7 @@ import {
|
||||
import { DisplayOrderDTO, OrderCheckoutService, ReorderValues } 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, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { bufferCount, catchError, filter, first, map, mergeMap, shareReplay, switchMap, tap, withLatestFrom } from 'rxjs/operators';
|
||||
|
||||
import * as DomainCheckoutSelectors from './store/domain-checkout.selectors';
|
||||
import * as DomainCheckoutActions from './store/domain-checkout.actions';
|
||||
@@ -217,6 +217,22 @@ export class DomainCheckoutService {
|
||||
);
|
||||
}
|
||||
|
||||
updateShoppingCartItemAvailability({
|
||||
shoppingCartId,
|
||||
shoppingCartItemId,
|
||||
availability,
|
||||
}: {
|
||||
shoppingCartId: number;
|
||||
shoppingCartItemId: number;
|
||||
availability: AvailabilityDTO;
|
||||
}) {
|
||||
return this.storeCheckoutService.StoreCheckoutUpdateShoppingCartItemAvailability({
|
||||
shoppingCartId,
|
||||
shoppingCartItemId,
|
||||
availability,
|
||||
});
|
||||
}
|
||||
|
||||
updateItemInShoppingCart({
|
||||
processId,
|
||||
shoppingCartItemId,
|
||||
@@ -314,6 +330,10 @@ export class DomainCheckoutService {
|
||||
);
|
||||
}
|
||||
|
||||
getOlaErrors({ processId }: { processId: number }): Observable<number[]> {
|
||||
return this.store.select(DomainCheckoutSelectors.selectOlaErrorsByProcessId, { processId });
|
||||
}
|
||||
|
||||
setPayment({ processId, paymentType }: { processId: number; paymentType: PaymentType }): Observable<CheckoutDTO> {
|
||||
return this.getCheckout({ processId }).pipe(
|
||||
first(),
|
||||
@@ -383,6 +403,53 @@ export class DomainCheckoutService {
|
||||
);
|
||||
}
|
||||
|
||||
checkAvailabilities({ processId }: { processId: number }): Observable<any> {
|
||||
const shoppingCart$ = this.getShoppingCart({ processId }).pipe(first());
|
||||
const itemsToCheck$ = shoppingCart$.pipe(
|
||||
map((cart) => cart?.items?.filter((item) => item?.data?.features?.orderType === 'Download' && !item.data.availability.lastRequest))
|
||||
);
|
||||
|
||||
return itemsToCheck$.pipe(
|
||||
withLatestFrom(shoppingCart$),
|
||||
switchMap(async ([items, cart]) => {
|
||||
const errorIds = [];
|
||||
|
||||
for (const item of items) {
|
||||
const availability = await this.availabilityService
|
||||
.getDownloadAvailability({
|
||||
item: {
|
||||
ean: item.data.product.ean,
|
||||
itemId: Number(item.data.product.catalogProductNumber),
|
||||
price: item.data.availability.price,
|
||||
},
|
||||
})
|
||||
.toPromise();
|
||||
|
||||
if (!availability || !this.availabilityService.isAvailable({ availability })) {
|
||||
errorIds.push(item.id);
|
||||
} else {
|
||||
await this.updateShoppingCartItemAvailability({
|
||||
shoppingCartId: cart.id,
|
||||
shoppingCartItemId: item.id,
|
||||
availability: {
|
||||
...availability,
|
||||
lastRequest: new Date().toISOString(),
|
||||
},
|
||||
}).toPromise();
|
||||
}
|
||||
}
|
||||
|
||||
this.setOlaErrors({ processId, errorIds });
|
||||
|
||||
if (errorIds.length > 0) {
|
||||
throw throwError(new Error(`Artikel nicht verfügbar`));
|
||||
} else {
|
||||
return of(undefined);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
updateAvailabilities({ processId }: { processId: number }): Observable<any> {
|
||||
const shoppingCart$ = this.getShoppingCart({ processId }).pipe(first());
|
||||
const itemsToUpdate$ = shoppingCart$.pipe(
|
||||
@@ -545,6 +612,8 @@ export class DomainCheckoutService {
|
||||
})
|
||||
);
|
||||
|
||||
const checkAvailabilities$ = this.checkAvailabilities({ processId });
|
||||
|
||||
const updateAvailabilities$ = this.updateAvailabilities({ processId });
|
||||
|
||||
const setPaymentType$ = itemOrderOptions$.pipe(
|
||||
@@ -610,6 +679,7 @@ export class DomainCheckoutService {
|
||||
mergeMap((_) => refreshShoppingCart$.pipe(tap(console.log.bind(window, 'refreshShoppingCart$')))),
|
||||
mergeMap((_) => setSpecialComment$.pipe(tap(console.log.bind(window, 'setSpecialComment$')))),
|
||||
mergeMap((_) => refreshCheckout$.pipe(tap(console.log.bind(window, 'refreshCheckout$')))),
|
||||
mergeMap((_) => checkAvailabilities$.pipe(tap(console.log.bind(window, 'checkAvailabilities$')))),
|
||||
mergeMap((_) => updateAvailabilities$.pipe(tap(console.log.bind(window, 'updateAvailabilities$')))),
|
||||
mergeMap((_) => setBuyer$.pipe(tap(console.log.bind(window, 'setBuyer$')))),
|
||||
mergeMap((_) => setNotificationChannels$.pipe(tap(console.log.bind(window, 'setNotificationChannels$')))),
|
||||
@@ -765,6 +835,15 @@ export class DomainCheckoutService {
|
||||
this.store.dispatch(DomainCheckoutActions.setCustomerFeatures({ processId, customerFeatures }));
|
||||
}
|
||||
|
||||
setOlaErrors({ processId, errorIds }: { processId: number; errorIds: number[] }) {
|
||||
this.store.dispatch(
|
||||
DomainCheckoutActions.setOlaError({
|
||||
processId,
|
||||
olaErrorIds: errorIds,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
getCustomerFeatures({ processId }: { processId: number }): Observable<{ [key: string]: string }> {
|
||||
return this.store.select(DomainCheckoutSelectors.selectCustomerFeaturesByProcessId, { processId });
|
||||
}
|
||||
|
||||
@@ -12,4 +12,5 @@ export interface CheckoutEntity {
|
||||
orders: DisplayOrderDTO[];
|
||||
specialComment: string;
|
||||
notificationChannels: NotificationChannel;
|
||||
olaErrorIds: number[];
|
||||
}
|
||||
|
||||
@@ -57,3 +57,5 @@ export const setBuyer = createAction(`${prefix} Set Buyer`, props<{ processId: n
|
||||
export const setPayer = createAction(`${prefix} Set Payer`, props<{ processId: number; payer: PayerDTO }>());
|
||||
|
||||
export const setSpecialComment = createAction(`${prefix} Set Agent Comment`, props<{ processId: number; agentComment: string }>());
|
||||
|
||||
export const setOlaError = createAction(`${prefix} Set Ola Error`, props<{ processId: number; olaErrorIds: number[] }>());
|
||||
|
||||
@@ -72,7 +72,12 @@ const _domainCheckoutReducer = createReducer(
|
||||
return storeCheckoutAdapter.setOne(entity, s);
|
||||
}),
|
||||
on(DomainCheckoutActions.removeProcess, (s, { processId }) => storeCheckoutAdapter.removeOne(processId, s)),
|
||||
on(DomainCheckoutActions.setOrders, (s, { orders }) => ({ ...s, orders }))
|
||||
on(DomainCheckoutActions.setOrders, (s, { orders }) => ({ ...s, orders })),
|
||||
on(DomainCheckoutActions.setOlaError, (s, { processId, olaErrorIds }) => {
|
||||
const entity = getOrCreateCheckoutEntity({ processId, entities: s.entities });
|
||||
entity.olaErrorIds = olaErrorIds;
|
||||
return storeCheckoutAdapter.setOne(entity, s);
|
||||
})
|
||||
);
|
||||
|
||||
export function domainCheckoutReducer(state, action) {
|
||||
@@ -94,6 +99,7 @@ function getOrCreateCheckoutEntity({ entities, processId }: { entities: Dictiona
|
||||
buyer: undefined,
|
||||
specialComment: '',
|
||||
notificationChannels: 0,
|
||||
olaErrorIds: [],
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -56,3 +56,8 @@ export const selectBuyerCommunicationDetails = createSelector(
|
||||
);
|
||||
|
||||
export const selectOrders = createSelector(storeFeatureSelector, (s) => s.orders);
|
||||
|
||||
export const selectOlaErrorsByProcessId = createSelector(
|
||||
selectEntities,
|
||||
(entities: Dictionary<CheckoutEntity>, { processId }: { processId: number }) => entities[processId]?.olaErrorIds
|
||||
);
|
||||
|
||||
@@ -244,6 +244,7 @@ export class ArticleSearchResultsComponent implements OnInit, OnDestroy {
|
||||
availability: {
|
||||
availabilityType: item?.catalogAvailability?.status,
|
||||
price: item?.catalogAvailability?.price,
|
||||
supplierProductNumber: item?.ids?.dig ? String(item.ids?.dig) : item?.product?.supplierProductNumber,
|
||||
},
|
||||
product: {
|
||||
catalogProductNumber: String(item?.id),
|
||||
|
||||
@@ -166,7 +166,7 @@
|
||||
</strong>
|
||||
<span class="shipping-cost-info">ohne Versandkosten</span>
|
||||
</div>
|
||||
<button class="cta-primary" (click)="order()" [disabled]="primaryCtaDisabled$ | async">
|
||||
<button class="cta-primary" (click)="order()" [disabled]="showOrderButtonSpinner">
|
||||
<ui-spinner [show]="showOrderButtonSpinner">
|
||||
{{ primaryCtaLabel$ | async }}
|
||||
</ui-spinner>
|
||||
|
||||
@@ -19,6 +19,7 @@ import { ResponseArgsOfItemDTO } from '@swagger/cat';
|
||||
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 { time } from 'console';
|
||||
|
||||
export interface CheckoutReviewComponentState {
|
||||
shoppingCart: ShoppingCartDTO;
|
||||
|
||||
@@ -39,6 +39,10 @@
|
||||
{{ 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 }}
|
||||
|
||||
<div class="item-availability-message" *ngIf="olaError$ | async">
|
||||
Artikel nicht verfügbar
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item-price-stock">
|
||||
|
||||
@@ -103,6 +103,10 @@
|
||||
|
||||
.item-info {
|
||||
grid-area: item-info;
|
||||
|
||||
.item-availability-message {
|
||||
@apply text-dark-goldenrod font-bold text-sm whitespace-nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.item-availability {
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { DomainAvailabilityService } from '@domain/availability';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { ComponentStore } from '@ngrx/component-store';
|
||||
import { ShoppingCartItemDTO } from '@swagger/checkout';
|
||||
import { first, map, shareReplay } from 'rxjs/operators';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { filter, first, map, shareReplay, switchMap } from 'rxjs/operators';
|
||||
|
||||
export interface ShoppingCartItemComponentState {
|
||||
item: ShoppingCartItemDTO;
|
||||
@@ -79,7 +83,25 @@ export class ShoppingCartItemComponent extends ComponentStore<ShoppingCartItemCo
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
constructor() {
|
||||
isDownloadAvailable$ = combineLatest([this.item$, this.orderType$]).pipe(
|
||||
filter(([_, orderType]) => orderType === 'Download'),
|
||||
switchMap(([item]) =>
|
||||
this.availabilityService.getDownloadAvailability({
|
||||
item: { ean: item.product.ean, price: item.availability.price, itemId: +item.product.catalogProductNumber },
|
||||
})
|
||||
),
|
||||
map((availability) => availability && this.availabilityService.isAvailable({ availability }))
|
||||
);
|
||||
|
||||
olaError$ = this.checkoutService
|
||||
.getOlaErrors({ processId: this.application.activatedProcessId })
|
||||
.pipe(map((ids) => ids?.find((id) => id === this.item.id)));
|
||||
|
||||
constructor(
|
||||
private availabilityService: DomainAvailabilityService,
|
||||
private checkoutService: DomainCheckoutService,
|
||||
private application: ApplicationService
|
||||
) {
|
||||
super({ item: undefined, orderType: '' });
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user