v1.13.0: SO status revert + editing refinements
"SO status revert and editing refinements" release. The admin sales-order surface gains a status-revert flow that demotes a PICKED / PACKED / SHIPPED order to any earlier status -- releasing picked inventory back to source bins, unpacking, and unshipping under one transaction and one audit shape -- plus a free-text order_origin label, tracking-number and inline address editing in the main edit modal, and a .modal-scoped type-scale pass. Cancel-batch now does the same full revert across PENDING / PICKED / SHORT.
Mobile. Zero mobile/ diffs on this release. v1.10.3 mobile source (versionCode 7) remains current; no new APK build for v1.13.0.
Added
- SO status-revert flow + Release Picked Quantities (#361):
POST /admin/sales-orders/<id>/revert-statusdemotes an SO from PICKED/PACKED/SHIPPED to any earlier status, composing the unwind per effect -- a per-pick_task release restoresquantity_pickedto the source bin viaadd_inventory(), decrementssales_order_lines.quantity_pickedandquantity_allocated, and marks the task RELEASED (the new terminal pick_task status); unpack zerosquantity_packedand clearspacked_at; unship clearstracking_number/carrier/shipped_at. A guard rejects withpicked_qty_remaining(409) when a sub-PICKED target would strand picked units.new_status == currentis a release-only mode that releases picks without flipping status. The edit modal intercepts backward transitions and opens a per-pick_task checkbox modal (release vs keep), andGET /admin/sales-orders/<id>returns apick_tasksarray so the modal renders without a second round-trip. New audit actions SO_STATUS_REVERTED / SO_PICK_RELEASED / SO_UNPACKED / SO_UNSHIPPED. Cancel-batch routes through a sharedfull_revert_batchhelper that unwinds PENDING reservations, PICKED moves, and SHORT residue so a cancelled batch leaves the SO indistinguishable from "never started picking". - Free-text order_origin label (#361):
sales_orders.order_originVARCHAR(64) (migration 063), a free-text upstream-origin / channel label populated by the inbound payload (no FK / enum, so any connector value lands without a deploy), surfaced read/write across the SO modals and the GET/PUT/POST surface. Distinct fromsource_system(which connector pushed the order) andorder_source(the web/pos enum); the inbound mapping template gains an annotated example. - Tracking number + inline address editing in the SO modal (#361):
tracking_numberjoins the view + edit modals (GET now returnscarrier+tracking_number), and address editing moves out of its standalone modal into the main edit form so header + addresses save under one click (PUT, then a conditional PATCH/address) with a client-sideaddressEditablegate mirroring the backend status rule. - Modal text scale + line-items polish (#361): a
.modal-scoped type-scale bump (labels, inputs, section/card titles step up one size inside popups), the line-items item-name column reverts from muted grey to default text, and the view-modal Order Total / Shipping Paid render with a$prefix.
Security
- Dependency audit catch-up (#361):
cryptography46.0.7 -> 48.0.1 (GHSA-537c-gmf6-5ccf) and transitive npm lockfile bumps clearing the HIGH advisories (viteserver.fs.denybypass, ws memory exhaustion, node-tar file smuggling, form-data CRLF) raised by advisories published 2026-06-15. Lockfile-only, no direct-dependency version moves; the remaining mobile moderate-tier advisories sit below the--audit-level=highgate.
Migrations
- 063 (#361) --
sales_orders.order_originfree-text upstream-origin column.
See CHANGELOG.md for the full notes.