Skip to content

v1.18.0: backorders, notifications, dispatcher reliability

Choose a tag to compare

@mhightower932 mhightower932 released this 18 Jun 15:54
260b350

Backorders, notifications, and dispatcher reliability

Three threads. A partial-fulfillment workflow lets an operator ship what's pickable and spin the shortfall into a backorder that waits for stock and rejoins the picking queue on its own when a receipt makes it whole. Per-warehouse Microsoft Teams notifications fire on the backorder lifecycle so the floor hears about shorts and restocks without watching a screen. And the outbound webhook dispatcher is hardened against the failure mode where one stuck delivery silently blocks an entire subscription.

Mobile. Zero mobile/ diffs. The v1.14.0 build (versionCode 8) remains current; no new APK.

Added

  • Partial-fulfillment + backorders (#384): POST /admin/sales-orders/<id>/partial-fulfill shorts the unshippable lines and creates a backorder SO (order_type='backorder', status=WAITING_STOCK, parent_so_id back-pointer, full address copy, NULL totals); the original continues through pack/ship, and a SHORT inventory adjustment is written when on-hand stock exists for a shorted line. BO chaining is capped at one level; refund SOs are rejected. POST .../cancel-backorder cancels a BO with a reason; the shared cancel service gained a parent-cancel cascade. The receiving loop matches WAITING_STOCK backorders on every receipt and flips a fully-satisfiable one to OPEN. A /backorders dashboard (Waiting / Ready-to-ship) and a "Partially Fulfill" sub-modal front the workflow, gated by a new backorders page key. Events backorder.opened / backorder.fulfillable / backorder.cancelled register at v1.
  • Teams notification webhooks (#385): per-warehouse Microsoft Teams destinations for the backorder.* family. A MessageCard builder (one variant per event, with an "Open in Sentry" deep-link), an SSRF-guarded sender, admin CRUD (list / create / PATCH / rotate-url / delete / test-send) gated by a new notifications page key, and a /notifications admin page. URLs are Fernet-encrypted at rest and never returned in plaintext. Each emit dispatches its card after commit on a daemon thread; failures are isolated per-webhook and the outbox row persists for replay. Cards carry item names alongside SKUs.

Fixed

  • Webhook dispatcher reliability (#386): four hardening fixes against silent head-of-line blocking. (1) Dispatch-time DNS resolution moved inside the wall-clock watchdog so a hung getaddrinfo fails as a timeout instead of wedging a delivery in_flight forever. (2) A heartbeat-driven reaper reclaims rows stuck in_flight past DISPATCHER_INFLIGHT_RECLAIM_S (default 120s), not just at boot. (3) Permanent failures (4xx except 408/429, ssrf_rejected) fast-DLQ on attempt 1 instead of burning the full ~15-hour retry schedule; transient failures keep the schedule. (4) A dispatcher self-monitor posts straight to Teams when a delivery stalls, the DLQ grows, a subscription lags, or an auto-pause fires; opt-in, de-spammed by transition + cooldown. New DISPATCHER_INFLIGHT_RECLAIM_S and DISPATCHER_HEALTH_* env vars.

Migrations

  • 067 -- sales_orders gains backorder_opened_at, backorder_fulfillable_at, cancellation_reason; order_type CHECK adds 'backorder'; WAITING_STOCK status + SHORT adjustment reason documented (app-enforced, no DB CHECK); ix_sales_orders_waiting_stock partial index.
  • 068 -- notification_webhooks table: per-warehouse Teams destinations with a Fernet-encrypted URL.

Upgrade notes

  • Apply migrations 067 and 068.
  • New optional dispatcher env vars (DISPATCHER_INFLIGHT_RECLAIM_S, DISPATCHER_HEALTH_*) have safe defaults; see .env.example. The self-monitor is inert until a dispatcher.* Teams channel is configured.