Merged PR 1833: fix(oms-data-access, oms-return-details): remove obsolete 'Software' product...

fix(oms-data-access, oms-return-details): remove obsolete 'Software' product category and related logic

- Removed the 'Software' entry from the ProductCategory constant and its type in `constants.ts`.
- Removed all references to ProductCategory.Software in the category-question registry and eligibility logic.
- Updated the return-details-order-group-item-controls component template to ensure the product category dropdown and checkbox are only rendered when the item is returnable, improving UI consistency and preventing controls from appearing for non-returnable items.
- Added/extended unit tests to verify correct rendering and logic for canReturnReceiptItem and selectability.

This change ensures that only supported product categories are handled in the return process and that UI controls are displayed appropriately based on item eligibility.

Ref: #5100
This commit is contained in:
Nino Righi
2025-05-26 08:53:33 +00:00
committed by Lorenz Hilpert
parent 1ad6c41c25
commit 1ddc0a2767
6 changed files with 80 additions and 37 deletions

View File

@@ -11,7 +11,6 @@ export const ProductCategory = {
SonstigesNonbook: 'Sonstiges und Non-Book',
ElektronischeGeraete: 'Andere Elektronische Geräte',
Tolino: 'Tolino',
Software: 'Software',
} as const;
export type ProductCategoryKey = keyof typeof ProductCategory;

View File

@@ -26,5 +26,4 @@ export const CategoryQuestions: Record<
[ProductCategory.SonstigesNonbook]: nonbookQuestions,
[ProductCategory.ElektronischeGeraete]: elektronischeGeraeteQuestions,
[ProductCategory.Tolino]: tolinoQuestions,
[ProductCategory.Software]: tonDatentraegerQuestions,
};

View File

@@ -172,7 +172,6 @@ export class ReturnProcessService {
returnProcess,
questions,
);
case ProductCategory.Software:
case ProductCategory.TonDatentraeger:
return isTonDatentraegerEligibleForReturn(returnProcess, questions);
case ProductCategory.Tolino:

View File

@@ -1,37 +1,43 @@
@if (quantityDropdownValues().length > 1) {
@if (canReturnReceiptItem()) {
@if (quantityDropdownValues().length > 1) {
<ui-dropdown
[value]="quantity()"
(valueChange)="changeProductQuantity($event)"
>
@for (quantity of quantityDropdownValues(); track quantity) {
<ui-dropdown-option [value]="quantity">{{
quantity
}}</ui-dropdown-option>
}
</ui-dropdown>
}
<ui-dropdown
[value]="quantity()"
(valueChange)="changeProductQuantity($event)"
label="Produktart"
[value]="getProductCategory()"
(valueChange)="setProductCategory($event)"
>
@for (quantity of quantityDropdownValues(); track quantity) {
<ui-dropdown-option [value]="quantity">{{ quantity }}</ui-dropdown-option>
@for (kv of availableCategories; track kv.key) {
<ui-dropdown-option [value]="kv.key">{{ kv.value }}</ui-dropdown-option>
}
</ui-dropdown>
}
<ui-dropdown
label="Produktart"
[value]="getProductCategory()"
(valueChange)="setProductCategory($event)"
>
@for (kv of availableCategories; track kv.key) {
<ui-dropdown-option [value]="kv.key">{{ kv.value }}</ui-dropdown-option>
@if (selectable()) {
<ui-checkbox appearance="bullet">
<input
type="checkbox"
[checked]="selected()"
(click)="selected.set(!selected())"
data-what="return-item-checkbox"
[attr.data-which]="item().product.ean"
/>
</ui-checkbox>
} @else if (showProductCategoryDropdownLoading()) {
<ui-icon-button
[pending]="true"
[color]="'tertiary'"
data-what="load-spinner"
data-which="can-return"
></ui-icon-button>
}
</ui-dropdown>
@if (selectable()) {
<ui-checkbox appearance="bullet">
<input
type="checkbox"
[checked]="selected()"
(click)="selected.set(!selected())"
data-what="return-item-checkbox"
[attr.data-which]="item().product.ean"
/>
</ui-checkbox>
} @else if (showProductCategoryDropdownLoading()) {
<ui-icon-button
[pending]="true"
[color]="'tertiary'"
data-what="load-spinner"
data-which="can-return"
></ui-icon-button>
}

View File

@@ -147,4 +147,40 @@ describe('ReturnDetailsOrderGroupItemControlsComponent', () => {
// With Spectator we can use toHaveProperty for HTML elements
expect(checkbox).toHaveProperty('checked', true);
});
it('should be true when actions include canReturn with truthy value', () => {
// Arrange
const item = createMockItem('0001', true);
spectator.setInput('item', item);
// Act
spectator.detectChanges();
// Assert
expect(spectator.component.canReturnReceiptItem()).toBe(true);
});
it('should be false when no canReturn action is present', () => {
// Arrange
const item = { ...createMockItem('0001', true), actions: [] };
spectator.setInput('item', item as any);
// Act
spectator.detectChanges();
// Assert
expect(spectator.component.canReturnReceiptItem()).toBe(false);
});
it('should be false when canReturn action has falsy value', () => {
// Arrange
const item = createMockItem('0001', false);
spectator.setInput('item', item);
// Act
spectator.detectChanges();
// Assert
expect(spectator.component.canReturnReceiptItem()).toBe(false);
});
});

View File

@@ -74,6 +74,12 @@ export class ReturnDetailsOrderGroupItemControlsComponent {
canReturn = output<CanReturn | undefined>();
canReturnReceiptItem = computed(() =>
this.item()?.actions?.some(
(a) => a.key === 'canReturn' && coerceBooleanProperty(a.value),
),
);
constructor() {
effect(() => {
const quantityDropdown = this.quantityDropdownValues();
@@ -89,9 +95,7 @@ export class ReturnDetailsOrderGroupItemControlsComponent {
effect(() => {
const productCategory = this.getProductCategory();
const canReturnReceiptItem = this.item()?.actions?.some(
(a) => a.key === 'canReturn' && coerceBooleanProperty(a.value),
);
const canReturnReceiptItem = this.canReturnReceiptItem();
const isSelectable =
canReturnReceiptItem && productCategory !== 'unknown';