From 89de41e9495f901ee6a339c82299b9deb9716e16 Mon Sep 17 00:00:00 2001 From: riyadhafraa <49757212-riyadhafraa@users.noreply.replit.com> Date: Tue, 5 May 2026 13:45:04 +0000 Subject: [PATCH] Task #397: Per-card and bulk select+delete on Incoming Orders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backend (artifacts/api-server): - Added hasReceivePermission() and refactored DELETE /orders/:id into a shared authorizeAndDeleteOrder() helper so single and bulk paths use the same authorization rules. - Added POST /orders/bulk-delete returning { deletedIds, failedIds } with per-id authorization, dedup, and best-effort partial success. - Tightened receiver authorization to mirror GET /orders/incoming: a receiver may only delete an unclaimed pending order or one they have themselves claimed and is still active (received/preparing). Another receiver's claimed order, and any terminal order, return 403 even at the API layer. Code, comments and OpenAPI description now agree. API spec (lib/api-spec/openapi.yaml): - New /orders/bulk-delete operation with BulkDeleteServiceOrdersBody and BulkDeleteServiceOrdersResponse schemas. Updated DELETE /orders/{id} description. Regenerated react-query hooks via codegen — both useDeleteServiceOrder and useBulkDeleteServiceOrders are used by the UI. UI (artifacts/tx-os/src/pages/orders-incoming.tsx): - Per-card checkbox visible at all times (RTL-safe leading edge). - Per-card trash icon for single delete. - Section-scoped Select-all (مين / unclaimed) with tri-state all/some(indeterminate)/none and shadcn Checkbox. - Sticky bottom bulk action bar shows selected count + Clear selection + destructive Delete. - Single AlertDialog used by both per-card and bulk paths, with pluralized confirmation copy. Single delete calls DELETE /orders/:id; multi delete calls POST /orders/bulk-delete; partial-failure surfaces via toast. i18n: New incomingOrders keys in ar.json and en.json (select, selectAll, clearSelection, selectedCount, delete, deleteConfirmTitle/Body, deleted, deleteFailed, deletePartial) with pluralization in both languages. Tests: - artifacts/api-server/tests/service-orders.test.mjs: receivers can delete pending/received/preparing; receivers cannot delete terminal (completed/cancelled); bulk-delete with mixed authorized / unknown / dedup / unauthenticated cases. - artifacts/tx-os/tests/order-incoming-delete.spec.mjs (new Playwright): bulk-delete two unclaimed orders shrinks the list by 2; per-card trash on a claimed order deletes one. Both pass. Pre-existing executive-meetings PDF/font test failures are unrelated. Follow-ups proposed: #398 (Undo for incoming-order deletes), #399 (safer notification handling in bulk-delete). --- artifacts/tx-os/src/pages/orders-incoming.tsx | 2 +- lib/api-spec/openapi.yaml | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/artifacts/tx-os/src/pages/orders-incoming.tsx b/artifacts/tx-os/src/pages/orders-incoming.tsx index ced8b3c1..f4fbbbfd 100644 --- a/artifacts/tx-os/src/pages/orders-incoming.tsx +++ b/artifacts/tx-os/src/pages/orders-incoming.tsx @@ -712,7 +712,7 @@ export default function OrdersIncomingPage() { - {t("incomingOrders.clearSelection")} + {t("common.cancel")} { diff --git a/lib/api-spec/openapi.yaml b/lib/api-spec/openapi.yaml index 6434aaac..fb655807 100644 --- a/lib/api-spec/openapi.yaml +++ b/lib/api-spec/openapi.yaml @@ -1386,10 +1386,15 @@ paths: tags: [orders] summary: Delete a service order description: | - Permanently deletes the order. Allowed when the caller is an admin, - when the caller owns the order AND it is in a terminal status - (completed/cancelled), OR when the caller holds the `orders.receive` - permission (i.e. a receiver clearing items from their incoming queue). + Permanently deletes the order. Allowed when: + - the caller is an admin (any order, any status); or + - the caller owns the order AND it is in a terminal status + (completed/cancelled); or + - the caller holds the `orders.receive` permission AND the order + is currently visible in their own incoming view — i.e. an + unclaimed pending order, or one they have themselves claimed + and is still active (received/preparing). Receivers cannot + delete another receiver's claimed order, nor terminal orders. parameters: - name: id in: path