Shipped by the supplier, not yet received · GIT_INBOUND stock type held against the destination location · 2,336 units, AED 512K owned and afloat · this is the balance that neither i2 nor INV1 ever represented at all
Customs hold · day 6 of demurrage. Container MSCU7719 (INB-2026-0702-001, CIC Lulwa, 96 units) arrived Jebel Ali 17-07, 5 free days expired 22-07. Accruing AED 640/day, total AED 3,840, already booked as an estimated demurrage cost component so the broker invoice will be a small revision rather than a surprise.Open PO →
1 shipment silent 14 days.INB-2026-0715-010 · AWB DHL 4429117001 returns 404 from both the unified Tracking API and MyDHL Express. Marked state=exception and permanently removed from the poll queue rather than retried forever. 24 units still sitting in GIT_INBOUND pending a manual decision.Open case →
GIT_INBOUND waterfall · July
Every movement into and out of the transit balance for the month, ending at the balance the ledger holds right now
closes at 2,336
Opening 01-07ShippedReceivedShortClosing 29-07
BalanceInto transitOut to receiptWritten off short1,504 + 4,220 - 3,228 - 160 = 2,336
Customs hold aging and demurrage risk
Band width is AED of goods at risk · the black mark is median age in the bucket · demurrage starts when free days expire, not when the hold opens
AED 640/day accruing
MSCU7719
AED 3,840
SDEC-2026-0726
AED 0
SDEC-2026-0712 closed
AED 0
Sea freight has no tracking adapter anywhere in the estate. ops2 registers SEAFREIGHT as a courier with source "manual" and no poller, so a container ETA is a human-typed date nobody revises. i3 therefore derives the demurrage clock from the customs entry (arrived_on + free_days) rather than from carrier events, and books the projected accrual as an estimated cost component the moment a hold opens.
DHL polling policy. Open shipments are polled every 30 minutes against the unified Tracking API, which is cheap. The side panel and the carton-to-piece match use MyDHL Express with levelOfDetail=all for per-piece weights and dimensions. A transient failure backs off exponentially; a 404 is terminal and sets state=exception so a dead AWB is never polled forever. That distinction between DHLError and DHLNotFoundError is ported directly from ops2 iwms/dhl.py. Accounts are Minimalist 454655276 and Lulwa 454850095, both on API profile apF0jS2iQ2hB7y; account numbers are settings, the API keys are Fly secrets.
Shipped-to-received reconciliation
one row per closed shipment line · this is the gap that becomes either a claim or an excess12 rows · 2 open claims
Excess never posts to STOCK. Atelier Rossi delivered 752 units against 740 shipped. Those 12 units have no purchase price, so admitting them to sellable stock would create units at cost 0, which is exactly the i2 failure this whole module exists to close. They post to QUARANTINE and wait for a commercial decision (accept and invoice, or return). Short units go the other way: they are written off GIT_INBOUND to LOST_IN_TRANSIT so the transit balance closes cleanly, and the money sits on a supplier claim rather than on a stock valuation.