Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 0 additions & 26 deletions docs/workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,32 +31,6 @@ rules.
| `REFUNDED` | None | Terminal. |
| `SHIPPED` | `COMPLETED`, `DELIVERED`, `PARTIALLY_REFUNDED`, `REFUNDED` | - |

The `DELIVERED` transition can be driven automatically by delivery-tracking
polling (TrackShip or the active shopping connector, via `/api/cron/delivery-status`).
That cron path runs the **same** transition guard and side effects as a manual
delivery — it does not write the status directly. Because the cron has no user
session it skips only the permission check (not the state-machine guard, unlike
the WooCommerce status-sync path), so if an order has moved out of a deliverable
state (e.g. cancelled or refunded after dispatch) between the poll's SHIPPED
query and the under-lock write, the guard rejects the change and the cron logs a
`delivery_status_skipped` warning instead of forcing it.

**`COMPLETED` vs `DELIVERED`.** Both are manual, operator-set terminal-ish
statuses reached from `SHIPPED` (and `COMPLETED → DELIVERED`). `DELIVERED` means
the carrier confirmed delivery and can be set automatically by the delivery-status
cron; `COMPLETED` is a manual "this order is done from our side" marker for
businesses that don't track delivery (no automatic trigger sets it). Neither is
forced by any sync; both still allow `PARTIALLY_REFUNDED`/`REFUNDED` afterwards.
Use `DELIVERED` when delivery tracking is in play, `COMPLETED` otherwise.

Manual status edits are rejected on **archived** orders (unarchive first);
automated pushes (WooCommerce force-sync, the delivery-status cron) still apply.
Deleting a payment that takes an already-paid order in an advanced status
(`SHIPPED`/`COMPLETED`/`DELIVERED`/`PARTIALLY_REFUNDED`) back below fully-paid
does not auto-revert the status but raises a `payment_status_mismatch` warning
activity log so the operator can decide (it fires only on a genuine paid→unpaid
transition, not for orders that were never fully paid, e.g. credit terms).

### Shipments

| Status | Allowed next statuses | Notes |
Expand Down
2 changes: 1 addition & 1 deletion lib/domain/inventory/invariants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1710,7 +1710,7 @@ function buildSqlInventoryInvariantQuery(options: Required<Pick<InventoryInvaria
'fromWarehouseId', st."fromWarehouseId",
'dispatchedAt', st."dispatchedAt",
'qty', stl.qty::float8,
'thresholdDays', ${STRANDED_TRANSFER_DAYS}
'thresholdDays', ${STRANDED_TRANSFER_DAYS}::int
) AS details
FROM "stock_transfers" st
INNER JOIN "stock_transfer_lines" stl ON stl."transferId" = st.id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,25 @@ ALTER TABLE "stock_levels"
ALTER COLUMN "quantity" TYPE numeric(14,6),
ALTER COLUMN "reservedQty" TYPE numeric(14,6);

-- The stock_movements_reporting_evidence_guard constraint trigger (migration

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add the schema-scope marker so migration-scope passes

On a PR this still trips the schema guard before the fresh-db job: .github/workflows/schema-guardrails.yml runs node scripts/check-prisma-schema-scope.mjs "origin/${{ github.base_ref }}" HEAD, and that script fails any changed prisma/migrations/**/migration.sql without a matching prisma/schema.prisma change unless the migration file contains an exact -- prisma-schema-scope-ok: db-native... comment. I reproduced node scripts/check-prisma-schema-scope.mjs e510de09f37f7ae09e2174cb2ec030d62b947d43^ e510de09f37f7ae09e2174cb2ec030d62b947d43, and this migration is reported as unchecked, so the CI blocker remains for any PR carrying this trigger-only edit.

Useful? React with 👍 / 👎.

-- 20260602103000) lists qty in its "UPDATE OF ... qty ..." column set, so Postgres
-- refuses to alter qty's type while it exists ("cannot alter type of a column used
-- in a trigger definition"). Drop the trigger, rewrite the column, then recreate it
-- identically — the trigger FUNCTION (assert_stock_movement_reporting_evidence) is
-- unchanged, so only the trigger binding is recreated.
-- prisma-schema-scope-ok: db-native constraint trigger drop/recreate around the qty column rewrite; constraint triggers are not modeled in prisma/schema.prisma, so there is no matching schema change
DROP TRIGGER IF EXISTS stock_movements_reporting_evidence_guard ON "stock_movements";

ALTER TABLE "stock_movements"
ALTER COLUMN "qty" TYPE numeric(14,6);

CREATE CONSTRAINT TRIGGER stock_movements_reporting_evidence_guard
AFTER INSERT OR UPDATE OF type, "productId", "fromWarehouseId", "toWarehouseId", qty, "referenceType", "referenceId"
ON "stock_movements"
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW
EXECUTE FUNCTION assert_stock_movement_reporting_evidence();

-- Persisted daily snapshots and reservation snapshots derive from the live
-- quantities above; widen them (and roundQty now persists 6dp) so as-of/turnover
-- reports don't disagree with live stock at the 5th/6th dp.
Expand Down
Loading