From 8a91a862ca78cee6d4793f503d77318b6dc533da Mon Sep 17 00:00:00 2001 From: sdarbinyan Date: Thu, 13 Aug 2026 07:42:55 +0400 Subject: [PATCH] fix: order status dropdown could bypass confirm-gated cancel/refund The status - @for (status of statuses; track status) { +
- {{ 'adminOrders.requestRefund' | translate }} - {{ 'adminOrders.cancelOrder' | translate }} + {{ 'adminOrders.requestRefund' | translate }} + {{ 'adminOrders.cancelOrder' | translate }}
diff --git a/src/app/features/admin/orders/pages/admin-order-detail-page.component.ts b/src/app/features/admin/orders/pages/admin-order-detail-page.component.ts index 7435150..27d78b7 100644 --- a/src/app/features/admin/orders/pages/admin-order-detail-page.component.ts +++ b/src/app/features/admin/orders/pages/admin-order-detail-page.component.ts @@ -30,6 +30,8 @@ export class AdminOrderDetailPageComponent { private readonly translate = inject(TranslateService); readonly statuses: AdminOrderStatus[] = ['pending', 'processing', 'shipped', 'delivered', 'cancelled', 'refunded']; + /** Terminal statuses are only reachable via the confirm-gated cancel()/requestRefund(), never the raw dropdown. */ + readonly selectableStatuses: AdminOrderStatus[] = this.statuses.filter(status => !TERMINAL_STATUSES.includes(status)); readonly workflowSteps = WORKFLOW_STEPS; readonly noteDraft = signal(''); readonly internalNoteDraft = signal(''); @@ -74,6 +76,11 @@ export class AdminOrderDetailPageComponent { } setStatus(id: string, status: AdminOrderStatus): void { + if (TERMINAL_STATUSES.includes(status)) { + // Unreachable from the dropdown (options are filtered), but guard anyway + // since terminal transitions must always go through the confirm dialog. + return; + } this.facade.setStatus(id, status); } diff --git a/src/app/features/admin/orders/pages/admin-orders-list-page.component.html b/src/app/features/admin/orders/pages/admin-orders-list-page.component.html index fce1a75..321d71d 100644 --- a/src/app/features/admin/orders/pages/admin-orders-list-page.component.html +++ b/src/app/features/admin/orders/pages/admin-orders-list-page.component.html @@ -37,8 +37,8 @@
{{ facade.selectedIds().length }} {{ 'adminProducts.selectedCount' | translate }} {{ 'adminOrders.applyStatus' | translate }} diff --git a/src/app/features/admin/orders/pages/admin-orders-list-page.component.ts b/src/app/features/admin/orders/pages/admin-orders-list-page.component.ts index 9c1d430..a8e36f8 100644 --- a/src/app/features/admin/orders/pages/admin-orders-list-page.component.ts +++ b/src/app/features/admin/orders/pages/admin-orders-list-page.component.ts @@ -30,6 +30,8 @@ export class AdminOrdersListPageComponent { private readonly languageService = inject(LanguageService); readonly statuses = ['all', 'pending', 'processing', 'shipped', 'delivered', 'cancelled', 'refunded'] as const; + /** Bulk status change excludes terminal statuses - cancel/refund must go through the confirm-gated single-order flow. */ + readonly bulkSelectableStatuses: AdminOrderStatus[] = ['pending', 'processing', 'shipped', 'delivered']; readonly allColumns = ALL_ORDER_COLUMNS; protected readonly columnsPanelOpen = signal(false); protected readonly bulkStatusValue = signal('pending');