From 7c1d10005e93c535589557032a9bbab1426e9c26 Mon Sep 17 00:00:00 2001 From: OneTwo3D IMS Date: Sun, 21 Jun 2026 16:49:39 +0000 Subject: [PATCH 1/2] fix(ci): repair qty-precision migration trigger dependency + regenerate stale workflow docs Two pre-existing CI blockers (red on every PR; not introduced by recent work): 1. Migration 20260619120000_cost_layer_qty_precision_14_6 alters stock_movements.qty to numeric(14,6), but the stock_movements_reporting_evidence_guard constraint trigger (20260602103000) lists qty in its 'UPDATE OF ... qty ...' column set, so Postgres refuses: 'cannot alter type of a column used in a trigger definition' (P3018). prisma migrate deploy failed on a fresh DB, blocking the e2e-select, invariant-preflight, and schema-guardrails(fresh-db-drift) jobs entirely. Drop the trigger around the column rewrite and recreate it identically (the trigger function is unchanged). Only stock_movements.qty had a column-scoped trigger; the other widened columns have none. 2. docs/workflows.md was out of date, failing the docs-workflows check. Regenerated via npm run docs:workflows. NOTE: editing an in-sequence migration changes its checksum. This migration has been red in CI since it merged, so it has almost certainly never applied cleanly via migrate deploy anywhere; on any environment that did record it applied, run 'prisma migrate resolve' before the next deploy. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/workflows.md | 26 ------------------- .../migration.sql | 16 ++++++++++++ 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/docs/workflows.md b/docs/workflows.md index 0455ac8e..9ead2474 100644 --- a/docs/workflows.md +++ b/docs/workflows.md @@ -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 | diff --git a/prisma/migrations/20260619120000_cost_layer_qty_precision_14_6/migration.sql b/prisma/migrations/20260619120000_cost_layer_qty_precision_14_6/migration.sql index 1f9f8e65..82d84f7d 100644 --- a/prisma/migrations/20260619120000_cost_layer_qty_precision_14_6/migration.sql +++ b/prisma/migrations/20260619120000_cost_layer_qty_precision_14_6/migration.sql @@ -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 +-- 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. From 317b110b9ae5ea320966c6bd5585c0b288d8a825 Mon Sep 17 00:00:00 2001 From: OneTwo3D IMS Date: Sun, 21 Jun 2026 17:05:41 +0000 Subject: [PATCH 2/2] fix(invariants): cast thresholdDays bind param in stranded-transfer SQL (42P18) The inventory invariant SQL collector passed STRANDED_TRANSFER_DAYS into a jsonb_build_object value position without a type cast, so Postgres could not determine the bind parameter's type ('could not determine data type of parameter $42') and the whole inventory invariant report failed at runtime. This surfaced only now that the migration fix lets invariant-preflight reach the report on a fresh DB (unit tests use mocked clients, so the raw query never ran). Cast it ::int, matching the same constant's already-cast use in the WHERE clause. Co-Authored-By: Claude Opus 4.8 (1M context) --- lib/domain/inventory/invariants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/domain/inventory/invariants.ts b/lib/domain/inventory/invariants.ts index abf421f7..71288a87 100644 --- a/lib/domain/inventory/invariants.ts +++ b/lib/domain/inventory/invariants.ts @@ -1710,7 +1710,7 @@ function buildSqlInventoryInvariantQuery(options: Required