From 6e614683c55954c505aefc3620419373845c263b Mon Sep 17 00:00:00 2001 From: Nino Righi Date: Fri, 24 Oct 2025 16:35:20 +0000 Subject: [PATCH] Merged PR 1984: fix(reward-confirmation): improve action card visibility and status messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix(reward-confirmation): improve action card visibility and status messages Refactor confirmation action card to only display for items with 'Rücklage' feature. Replace boolean completion check with state-based system using ProcessingStatusState enum (Cancelled, NotFound, Collected). Add specific completion messages for each state to provide clearer user feedback. Changes: - Add displayActionCard computed signal to check for 'Rücklage' feature - Replace getProcessingStatusCompleted with getProcessingStatusState helper - Add ProcessingStatusState enum with three states (Cancelled, NotFound, Collected) - Update completion messages in template to use @switch based on processingStatus - Wrap entire action card in @if block checking displayActionCard - Add proper test coverage for new helper function - Update component spec to provide required dependencies Ref: #5391, #5404, #5406 --- ...ation-list-item-action-card.component.html | 134 ++++++++++-------- ...rmation-list-item-action-card.component.ts | 18 ++- ...r-confirmation-item-list-item.component.ts | 12 +- ...processing-status-completed.helper.spec.ts | 97 ------------- .../get-processing-status-completed.helper.ts | 18 --- ...get-processing-status-state.helper.spec.ts | 92 ++++++++++++ .../get-processing-status-state.helper.ts | 55 +++++++ .../src/lib/helpers/reward/index.ts | 2 +- libs/oms/data-access/src/lib/models/index.ts | 1 + .../src/lib/models/processing-status-state.ts | 14 ++ 10 files changed, 259 insertions(+), 184 deletions(-) delete mode 100644 libs/oms/data-access/src/lib/helpers/reward/get-processing-status-completed.helper.spec.ts delete mode 100644 libs/oms/data-access/src/lib/helpers/reward/get-processing-status-completed.helper.ts create mode 100644 libs/oms/data-access/src/lib/helpers/reward/get-processing-status-state.helper.spec.ts create mode 100644 libs/oms/data-access/src/lib/helpers/reward/get-processing-status-state.helper.ts create mode 100644 libs/oms/data-access/src/lib/models/processing-status-state.ts diff --git a/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list-item/confirmation-list-item-action-card/confirmation-list-item-action-card.component.html b/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list-item/confirmation-list-item-action-card/confirmation-list-item-action-card.component.html index 1e7cc2dca..203e957fc 100644 --- a/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list-item/confirmation-list-item-action-card/confirmation-list-item-action-card.component.html +++ b/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list-item/confirmation-list-item-action-card/confirmation-list-item-action-card.component.html @@ -1,64 +1,78 @@ -
- @if (!isComplete()) { -
- Bitte buchen Sie die Prämie aus dem Abholfach aus oder wählen Sie eine - andere Aktion. -
- -
- + @if (!isComplete()) { +
- Prämie ausbuchen - Nicht gefunden - Stornieren - + Bitte buchen Sie die Prämie aus dem Abholfach aus oder wählen Sie eine + andere Aktion. +
- +
+ } @else { +
- - Abschließen - -
- } @else { -
- Artikel wurde Storniert und Lesepunkte gut geschrieben. -
+ @switch (processingStatus()) { + @case (ProcessingStatusState.Cancelled) { + Artikel wurde storniert und die Lesepunkte wieder gutgeschrieben. + } + @case (ProcessingStatusState.NotFound) { + Die Prämienbestellung wurde storniert und die Lesepunkte wieder + gutgeschrieben. Bitte korrigieren Sie bei Bedarf den Filialbestand. + } + @case (ProcessingStatusState.Collected) { + Der Artikel wurde aus dem Bestand ausgebucht und kann dem Kunden + mitgegeben werden. + } + } +
- - - Abgeschlossen - - } - + + + Abgeschlossen + + } + +} diff --git a/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list-item/confirmation-list-item-action-card/confirmation-list-item-action-card.component.ts b/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list-item/confirmation-list-item-action-card/confirmation-list-item-action-card.component.ts index b27b26b47..42a41ce10 100644 --- a/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list-item/confirmation-list-item-action-card/confirmation-list-item-action-card.component.ts +++ b/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list-item/confirmation-list-item-action-card/confirmation-list-item-action-card.component.ts @@ -13,7 +13,8 @@ import { OrderRewardCollectFacade, LoyaltyCollectType, OrderItemSubsetResource, - getProcessingStatusCompleted, + getProcessingStatusState, + ProcessingStatusState, } from '@isa/oms/data-access'; import { ButtonComponent } from '@isa/ui/buttons'; import { NgIcon } from '@ng-icons/core'; @@ -23,6 +24,7 @@ import { DropdownButtonComponent, DropdownOptionComponent, } from '@isa/ui/input-controls'; +import { hasOrderTypeFeature } from '@isa/checkout/data-access'; @Component({ selector: 'checkout-confirmation-list-item-action-card', @@ -39,6 +41,7 @@ import { }) export class ConfirmationListItemActionCardComponent { LoyaltyCollectType = LoyaltyCollectType; + ProcessingStatusState = ProcessingStatusState; #orderRewardCollectFacade = inject(OrderRewardCollectFacade); #store = inject(OrderConfiramtionStore); #orderItemSubsetResource = inject(OrderItemSubsetResource); @@ -61,13 +64,22 @@ export class ConfirmationListItemActionCardComponent { orderItemSubsets = this.#orderItemSubsetResource.orderItemSubsets; selectedAction = signal(LoyaltyCollectType.Collect); - isComplete = computed(() => { + + processingStatus = computed(() => { const subsets = this.orderItemSubsets(); const statuses = subsets?.map((subset) => subset.processingStatus); - return getProcessingStatusCompleted(statuses); + return getProcessingStatusState(statuses); }); isLoading = signal(false); + isComplete = computed(() => { + return this.processingStatus() !== undefined; + }); + + displayActionCard = computed(() => + hasOrderTypeFeature(this.item().features, ['Rücklage']), + ); + constructor() { effect(() => { const item = this.item(); diff --git a/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list-item/order-confirmation-item-list-item.component.ts b/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list-item/order-confirmation-item-list-item.component.ts index 29557d304..756facb94 100644 --- a/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list-item/order-confirmation-item-list-item.component.ts +++ b/libs/checkout/feature/reward-order-confirmation/src/lib/order-confirmation-item-list/order-confirmation-item-list-item/order-confirmation-item-list-item.component.ts @@ -77,10 +77,12 @@ export class OrderConfirmationItemListItemComponent { )?.data; // Fallback: use DisplayOrderItem features if not found in cart - return foundItem ?? { - features: item.features, - availability: undefined, - destination: undefined, - }; + return ( + foundItem ?? { + features: item.features, + availability: undefined, + destination: undefined, + } + ); }); } diff --git a/libs/oms/data-access/src/lib/helpers/reward/get-processing-status-completed.helper.spec.ts b/libs/oms/data-access/src/lib/helpers/reward/get-processing-status-completed.helper.spec.ts deleted file mode 100644 index 9687ca0de..000000000 --- a/libs/oms/data-access/src/lib/helpers/reward/get-processing-status-completed.helper.spec.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { OrderItemProcessingStatusValue } from '../../schemas'; -import { getProcessingStatusCompleted } from './get-processing-status-completed.helper'; - -describe('getProcessingStatusCompleted', () => { - it('should return true when all statuses are different from Bestellt (16)', () => { - // Arrange - const statuses = [ - OrderItemProcessingStatusValue.Versendet, // 64 - OrderItemProcessingStatusValue.Eingetroffen, // 128 - OrderItemProcessingStatusValue.Abgeholt, // 256 - ]; - - // Act - const result = getProcessingStatusCompleted(statuses); - - // Assert - expect(result).toBe(true); - }); - - it('should return true when statuses include various completed states', () => { - // Arrange - const statuses = [ - OrderItemProcessingStatusValue.Zugestellt, // 4194304 - OrderItemProcessingStatusValue.Abgeholt, // 256 - OrderItemProcessingStatusValue.Versendet, // 64 - ]; - - // Act - const result = getProcessingStatusCompleted(statuses); - - // Assert - expect(result).toBe(true); - }); - - it('should return false when at least one status is Bestellt (16)', () => { - // Arrange - const statuses = [ - OrderItemProcessingStatusValue.Versendet, // 64 - OrderItemProcessingStatusValue.Bestellt, // 16 - OrderItemProcessingStatusValue.Abgeholt, // 256 - ]; - - // Act - const result = getProcessingStatusCompleted(statuses); - - // Assert - expect(result).toBe(false); - }); - - it('should return false when all statuses are Bestellt (16)', () => { - // Arrange - const statuses = [ - OrderItemProcessingStatusValue.Bestellt, // 16 - OrderItemProcessingStatusValue.Bestellt, // 16 - OrderItemProcessingStatusValue.Bestellt, // 16 - ]; - - // Act - const result = getProcessingStatusCompleted(statuses); - - // Assert - expect(result).toBe(false); - }); - - it('should return false when array is empty', () => { - // Arrange - const statuses: number[] = []; - - // Act - const result = getProcessingStatusCompleted(statuses); - - // Assert - expect(result).toBe(false); - }); - - it('should return false when statuses is undefined', () => { - // Arrange - const statuses = undefined; - - // Act - const result = getProcessingStatusCompleted(statuses); - - // Assert - expect(result).toBe(false); - }); - - it('should return true with single status different from Bestellt', () => { - // Arrange - const statuses = [OrderItemProcessingStatusValue.Abgeholt]; // 256 - - // Act - const result = getProcessingStatusCompleted(statuses); - - // Assert - expect(result).toBe(true); - }); -}); diff --git a/libs/oms/data-access/src/lib/helpers/reward/get-processing-status-completed.helper.ts b/libs/oms/data-access/src/lib/helpers/reward/get-processing-status-completed.helper.ts deleted file mode 100644 index d6b2b17ba..000000000 --- a/libs/oms/data-access/src/lib/helpers/reward/get-processing-status-completed.helper.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { OrderItemProcessingStatusValue } from '../../schemas'; - -/** - * Checks if all processing statuses are completed (not in "Bestellt" state). - * Returns true if all statuses are different from "Bestellt" (16). - * Returns false if any status is still "Bestellt" (16) or if the array is empty/undefined. - */ -export const getProcessingStatusCompleted = ( - statuses: number[] | undefined, -): boolean => { - if (!statuses || statuses.length === 0) { - return false; - } - - return statuses.every( - (status) => status !== OrderItemProcessingStatusValue.Bestellt, - ); -}; diff --git a/libs/oms/data-access/src/lib/helpers/reward/get-processing-status-state.helper.spec.ts b/libs/oms/data-access/src/lib/helpers/reward/get-processing-status-state.helper.spec.ts new file mode 100644 index 000000000..461797aa9 --- /dev/null +++ b/libs/oms/data-access/src/lib/helpers/reward/get-processing-status-state.helper.spec.ts @@ -0,0 +1,92 @@ +import { OrderItemProcessingStatusValue } from '../../schemas'; +import { ProcessingStatusState } from '../../models'; +import { getProcessingStatusState } from './get-processing-status-state.helper'; + +describe('getProcessingStatusState', () => { + describe('Cancelled status', () => { + it('should return Cancelled when all items are cancelled', () => { + // Arrange + const statuses = [ + OrderItemProcessingStatusValue.StorniertKunde, // 512 + OrderItemProcessingStatusValue.Storniert, // 1024 + OrderItemProcessingStatusValue.StorniertLieferant, // 2048 + ]; + + // Act + const result = getProcessingStatusState(statuses); + + // Assert + expect(result).toBe(ProcessingStatusState.Cancelled); + }); + }); + + describe('NotFound status', () => { + it('should return NotFound when all items are NichtLieferbar', () => { + // Arrange + const statuses = [ + OrderItemProcessingStatusValue.NichtLieferbar, // 4096 + OrderItemProcessingStatusValue.NichtLieferbar, // 4096 + ]; + + // Act + const result = getProcessingStatusState(statuses); + + // Assert + expect(result).toBe(ProcessingStatusState.NotFound); + }); + }); + + describe('Collected status', () => { + it('should return Collected when all items are Abgeholt', () => { + // Arrange + const statuses = [ + OrderItemProcessingStatusValue.Abgeholt, // 256 + OrderItemProcessingStatusValue.Abgeholt, // 256 + ]; + + // Act + const result = getProcessingStatusState(statuses); + + // Assert + expect(result).toBe(ProcessingStatusState.Collected); + }); + }); + + describe('Undefined cases', () => { + it('should return undefined when array is empty', () => { + // Arrange + const statuses: number[] = []; + + // Act + const result = getProcessingStatusState(statuses); + + // Assert + expect(result).toBeUndefined(); + }); + + it('should return undefined when statuses is undefined', () => { + // Arrange + const statuses = undefined; + + // Act + const result = getProcessingStatusState(statuses); + + // Assert + expect(result).toBeUndefined(); + }); + + it('should return undefined when items have mixed statuses', () => { + // Arrange + const statuses = [ + OrderItemProcessingStatusValue.StorniertKunde, // 512 + OrderItemProcessingStatusValue.Abgeholt, // 256 + ]; + + // Act + const result = getProcessingStatusState(statuses); + + // Assert + expect(result).toBeUndefined(); + }); + }); +}); diff --git a/libs/oms/data-access/src/lib/helpers/reward/get-processing-status-state.helper.ts b/libs/oms/data-access/src/lib/helpers/reward/get-processing-status-state.helper.ts new file mode 100644 index 000000000..98d8c1958 --- /dev/null +++ b/libs/oms/data-access/src/lib/helpers/reward/get-processing-status-state.helper.ts @@ -0,0 +1,55 @@ +import { OrderItemProcessingStatusValue } from '../../schemas'; +import { ProcessingStatusState } from '../../models'; + +/** + * Determines the completion status of order items based on their processing statuses. + * + * @param statuses - Array of processing status values to evaluate + * @returns The processing status state: + * - `ProcessingStatusState.Cancelled` if all items are cancelled + * - `ProcessingStatusState.NotFound` if all items are marked as not available + * - `ProcessingStatusState.Collected` if all items are collected + * - `undefined` if statuses don't match any completion state + * + * @example + * ```ts + * const statuses = [512, 1024]; // StorniertKunde, Storniert + * getProcessingStatusState(statuses); // ProcessingStatusState.Cancelled + * ``` + */ +export const getProcessingStatusState = ( + statuses: number[] | undefined, +): ProcessingStatusState | undefined => { + if (!statuses || statuses.length === 0) { + return undefined; + } + + // Check if all statuses are cancelled + const allCancelled = statuses.every( + (status) => + status === OrderItemProcessingStatusValue.StorniertKunde || + status === OrderItemProcessingStatusValue.Storniert || + status === OrderItemProcessingStatusValue.StorniertLieferant, + ); + if (allCancelled) { + return ProcessingStatusState.Cancelled; + } + + // Check if all statuses are not available + const allNotFound = statuses.every( + (status) => status === OrderItemProcessingStatusValue.NichtLieferbar, + ); + if (allNotFound) { + return ProcessingStatusState.NotFound; + } + + // Check if all statuses are collected + const allCollected = statuses.every( + (status) => status === OrderItemProcessingStatusValue.Abgeholt, + ); + if (allCollected) { + return ProcessingStatusState.Collected; + } + + return undefined; +}; diff --git a/libs/oms/data-access/src/lib/helpers/reward/index.ts b/libs/oms/data-access/src/lib/helpers/reward/index.ts index 5e7ab59e6..3a0e4a34e 100644 --- a/libs/oms/data-access/src/lib/helpers/reward/index.ts +++ b/libs/oms/data-access/src/lib/helpers/reward/index.ts @@ -1 +1 @@ -export * from './get-processing-status-completed.helper'; +export * from './get-processing-status-state.helper'; diff --git a/libs/oms/data-access/src/lib/models/index.ts b/libs/oms/data-access/src/lib/models/index.ts index 310a98693..9f186556e 100644 --- a/libs/oms/data-access/src/lib/models/index.ts +++ b/libs/oms/data-access/src/lib/models/index.ts @@ -5,6 +5,7 @@ export * from './eligible-for-return'; export * from './gender'; export * from './logistician'; export * from './order'; +export * from './processing-status-state'; export * from './quantity'; export * from './receipt-item-list-item'; export * from './receipt-item-task-list-item'; diff --git a/libs/oms/data-access/src/lib/models/processing-status-state.ts b/libs/oms/data-access/src/lib/models/processing-status-state.ts new file mode 100644 index 000000000..92c546621 --- /dev/null +++ b/libs/oms/data-access/src/lib/models/processing-status-state.ts @@ -0,0 +1,14 @@ +/** + * Processing status state types for order items + */ +export const ProcessingStatusState = { + /** Item was cancelled by customer, merchant, or supplier */ + Cancelled: 'cancelled', + /** Item was not found / not available */ + NotFound: 'not-found', + /** Item was successfully collected */ + Collected: 'collected', +} as const; + +export type ProcessingStatusState = + (typeof ProcessingStatusState)[keyof typeof ProcessingStatusState];