Merged PR 2077: fix(checkout-data-access, checkout-reward-shopping-cart, checkout-reward-sele...

fix(checkout-data-access, checkout-reward-shopping-cart, checkout-reward-selection-dialog): Show Low Stock message inside Dialog, Adjusted Item Identifyer so that mergedItems inside reward-selection-dialog service works properly, Adjusted Error Message Logic and Quantity Select Logic based on purchasing Options for Abholung

Ref: #5523
This commit is contained in:
Nino Righi
2025-12-10 17:12:47 +00:00
committed by Lorenz Hilpert
parent 964a6026a0
commit de3edaa0f9
9 changed files with 83 additions and 24 deletions

View File

@@ -4,12 +4,13 @@ import {
} from '@isa/checkout/data-access'; } from '@isa/checkout/data-access';
/** /**
* Creates a unique key for an item based on EAN, destination, and orderItemType. * Creates a unique key for an item based on EAN, targetBranchId, and orderItemType.
* Items are only considered identical if all three match. * Items are only considered identical if all three match.
*/ */
export const getItemKey = (item: ShoppingCartItem): string => { export const getItemKey = (item: ShoppingCartItem): string => {
const ean = item.product.ean ?? 'no-ean'; const ean = item.product.ean ?? 'no-ean';
const destinationId = item.destination?.data?.id ?? 'no-destination'; const targetBranchId =
item.destination?.data?.targetBranch?.id ?? 'no-target-branch-id';
const orderType = getOrderTypeFeature(item.features) ?? 'no-orderType'; const orderType = getOrderTypeFeature(item.features) ?? 'no-orderType';
return `${ean}|${destinationId}|${orderType}`; return `${ean}|${targetBranchId}|${orderType}`;
}; };

View File

@@ -66,7 +66,8 @@ export class RewardShoppingCartItemQuantityControlComponent {
if ( if (
orderType === OrderTypeFeature.Delivery || orderType === OrderTypeFeature.Delivery ||
orderType === OrderTypeFeature.DigitalShipping || orderType === OrderTypeFeature.DigitalShipping ||
orderType === OrderTypeFeature.B2BShipping orderType === OrderTypeFeature.B2BShipping ||
orderType === OrderTypeFeature.Pickup
) { ) {
return 999; return 999;
} }

View File

@@ -37,11 +37,20 @@
</div> </div>
</div> </div>
@if (quantityControl.maxQuantity() < 2 && !isDownload()) { @if (!isDownload()) {
<div @if (showLowStockMessage()) {
class="text-isa-accent-red isa-text-body-2-bold flex flex-row items-center gap-2" <div
> class="text-isa-accent-red isa-text-body-2-bold flex flex-row items-center gap-2"
<ng-icon name="isaOtherInfo" size="1.5rem"></ng-icon> >
<div>Geringer Bestand - Artikel holen vor Abschluss</div> <ng-icon name="isaOtherInfo" size="1.5rem"></ng-icon>
</div> <div>{{ inStock() }} Exemplare sofort lieferbar</div>
</div>
} @else if (quantityControl.maxQuantity() < 2) {
<div
class="text-isa-accent-red isa-text-body-2-bold flex flex-row items-center gap-2"
>
<ng-icon name="isaOtherInfo" size="1.5rem"></ng-icon>
<div>Geringer Bestand - Artikel holen vor Abschluss</div>
</div>
}
} }

View File

@@ -72,6 +72,16 @@ export class RewardShoppingCartItemComponent {
hasOrderTypeFeature(this.item().features, ['Download']), hasOrderTypeFeature(this.item().features, ['Download']),
); );
isAbholung = computed(() =>
hasOrderTypeFeature(this.item().features, ['Abholung']),
);
inStock = computed(() => this.item().availability?.inStock ?? 0);
showLowStockMessage = computed(() => {
return this.isAbholung() && this.inStock() < 2;
});
async updatePurchaseOption() { async updatePurchaseOption() {
const shoppingCartItemId = this.itemId(); const shoppingCartItemId = this.itemId();
const shoppingCartId = this.shoppingCartId(); const shoppingCartId = this.shoppingCartId();

View File

@@ -1,3 +1,3 @@
:host { :host {
@apply text-isa-accent-red isa-text-body-2-bold flex flex-row gap-2 items-center; @apply text-isa-accent-red isa-text-body-2-bold flex flex-col gap-2 items-start;
} }

View File

@@ -1,8 +1,10 @@
@if (store.totalLoyaltyPointsNeeded() > store.customerRewardPoints()) { @if (store.totalLoyaltyPointsNeeded() > store.customerRewardPoints()) {
<ng-icon <div class="flex flex-row gap-2 items-center">
class="w-6 h-6 inline-flex items-center justify-center" <ng-icon
size="1.5rem" class="w-6 h-6 inline-flex items-center justify-center"
name="isaOtherInfo" size="1.5rem"
></ng-icon> name="isaOtherInfo"
<span>Lesepunkte reichen nicht für alle Artikel</span> ></ng-icon>
<span>Lesepunkte reichen nicht für alle Artikel</span>
</div>
} }

View File

@@ -41,10 +41,7 @@ export class RewardSelectionInputsComponent {
hasCorrectOrderType = computed(() => { hasCorrectOrderType = computed(() => {
const item = this.rewardSelectionItem().item; const item = this.rewardSelectionItem().item;
return hasOrderTypeFeature(item.features, [ return hasOrderTypeFeature(item.features, [OrderTypeFeature.InStore]);
OrderTypeFeature.InStore,
OrderTypeFeature.Pickup,
]);
}); });
hasStock = computed(() => { hasStock = computed(() => {

View File

@@ -27,3 +27,16 @@
<lib-reward-selection-inputs></lib-reward-selection-inputs> <lib-reward-selection-inputs></lib-reward-selection-inputs>
</div> </div>
@if (showLowStockMessage()) {
<div
class="flex flex-row gap-2 items-center text-isa-accent-red isa-text-body-2-bold"
>
<ng-icon
class="w-6 h-6 inline-flex items-center justify-center"
size="1.5rem"
name="isaOtherInfo"
></ng-icon>
<span>{{ inStock() }} Exemplare sofort lieferbar</span>
</div>
}

View File

@@ -1,8 +1,18 @@
import { ChangeDetectionStrategy, Component, input } from '@angular/core'; import {
ChangeDetectionStrategy,
Component,
computed,
input,
} from '@angular/core';
import { ProductImageDirective } from '@isa/shared/product-image'; import { ProductImageDirective } from '@isa/shared/product-image';
import { ProductRouterLinkDirective } from '@isa/shared/product-router-link'; import { ProductRouterLinkDirective } from '@isa/shared/product-router-link';
import { RewardSelectionInputsComponent } from './reward-selection-inputs/reward-selection-inputs.component'; import { RewardSelectionInputsComponent } from './reward-selection-inputs/reward-selection-inputs.component';
import { RewardSelectionItem } from '@isa/checkout/data-access'; import {
hasOrderTypeFeature,
RewardSelectionItem,
} from '@isa/checkout/data-access';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { isaOtherInfo } from '@isa/icons';
@Component({ @Component({
selector: 'lib-reward-selection-item', selector: 'lib-reward-selection-item',
@@ -13,8 +23,24 @@ import { RewardSelectionItem } from '@isa/checkout/data-access';
ProductImageDirective, ProductImageDirective,
ProductRouterLinkDirective, ProductRouterLinkDirective,
RewardSelectionInputsComponent, RewardSelectionInputsComponent,
NgIcon,
], ],
providers: [provideIcons({ isaOtherInfo })],
}) })
export class RewardSelectionItemComponent { export class RewardSelectionItemComponent {
rewardSelectionItem = input.required<RewardSelectionItem>(); rewardSelectionItem = input.required<RewardSelectionItem>();
inStock = computed(
() => this.rewardSelectionItem().item?.availability?.inStock ?? 0,
);
isAbholung = computed(() =>
hasOrderTypeFeature(this.rewardSelectionItem()?.item?.features, [
'Abholung',
]),
);
showLowStockMessage = computed(() => {
return this.isAbholung() && this.inStock() < 2;
});
} }