Cartons, zones and picking

The physical layer i3 absorbs out of ops2 at Phase 5 · master and sub cartons, carton to zone assignment, partial split with relabel, carton-level EPC association, picking replenishment, damage matching inside 48 hours

Opening a carton debits its lines and credits picking stock in the same transaction. The pair nets to zero, so a carton and the picking area can never both count the same unit. ops2 credits picking and leaves the carton at full quantity, which double counts the contents of all 38 opened cartons here. The reconciler at T-04.16 finds and fixes those on import. Bridge state →

Carton state by zone

412 master cartons at HQ_319 and HQ_325 · a voided carton contributes nothing to the reconciliation identity

stacked
319_A1 · 106 sealed 319_A1 · 10 opened 319_A1 · 2 depleted 319_A2 · 95 sealed 319_A2 · 8 opened 319_A2 · 1 depleted 319_A3 · 116 sealed 319_A3 · 11 opened 319_A3 · 4 depleted 319_A4 · 86 sealed 319_A4 · 5 opened 319_A4 · 1 depleted 319_A5 · 55 sealed 319_A5 · 4 opened 319_A5 · 2 depleted RECEIVING · 26 sealed, awaiting put-away QC_HOLD · 9 sealed, QC pending RTS_STAGING · 2 sealed, RTS-0022 HQ_325 · 51 sealed HQ_325 · 4 opened HQ_325 · 5 depleted HQ_325 · 4 voided, excluded from the identity
319_A1319_A2319_A3319_A4319_A5RECEIVINGQC_HOLDRTS_STGHQ_325
Sealed 351Opened 38Depleted 19QC pending 9Voided 4

Where cartons come from

Provenance of the 412 live cartons · cartons.source

412
Inbound GRN · 61% · 251 cartons Split · 16% · 66 cartons Repack · 12% · 49 cartons Transfer in · 7% · 29 cartons Supplier pre-packed and manual · 4% · 17 cartons cartons 412
  • Inbound GRN61%
  • Split16%
  • Repack12%
  • Transfer in7%
  • Pre-packed, manual4%
Multi-SKU parents
47 · avg 2.7 children
Parent total check
47 of 47 balanced
Cartons per PO, avg
14.2
Oldest sealed carton
MC-3812 · 214d in 319_A5
Cartons with no bin
6 · put-away queue

Carton register

Master, sub and retail cartons · contents live in carton_lines, never on the carton row · click a row to expand its lines

1 split awaiting label1 damage match pending
CartonKindZone · binPO or inflowContentsUnitsSubsEPCsOpenedLast eventState
MC-4471master319_A3 · B12PO-2026-116 MSR31-07 ×18 of 2418124 29-07 13:4113:41 openopened · picking
MC-4470master319_A3 · B12PO-2026-116 MSR31-08 ×3030130 -27-07 09:12 movesealed
MC-4462master · multi319_A2 · C04PO-2026-115 3 SKUs · mixed30330 -29-07 10:40 split_outsplit 20 u out
Contents · carton_lines for MC-4462
SKUTitleStock typeOriginalCurrentUnit costValue AED
5DQR7Quartz Dial · Rose 38mmSTOCK4020184.003,680
5DQR13Quartz Dial · Silver 38mmSTOCK1010184.001,840
XTRA-STRAPLeather strap · spare, tanSTOCK0042.000
Parent total, must equal the sum of children50305,520
ops2 stores a single sku plus a total on master_cartons, so a mixed carton loses its composition and a partial move cannot say which SKU left. carton_lines is the fix, and the parent-total invariant is a trigger, not application code.
Sub-cartons
BarcodeSKUQtyState
MC-4462-A5DQR720sealed
MC-4462-B5DQR1310sealed
MC-4462-CXTRA-STRAP0depleted
Children total30matches parent
Carton-level EPC association
E280 6894 0000 4021 8F3C · 5DQR7
E280 6894 0000 4021 8F3D · 5DQR7
E280 6894 0000 4021 8F3E · 5DQR13
+ 27 more · serial range MIN-000412 to MIN-000441
MC-4462-Asub319_A2 · C04PO-2026-115 5DQR7 ×2020·20 -29-07 10:40 split_outsealed
MC-4462-Bsub319_A2 · C04PO-2026-115 5DQR13 ×1010·10 -24-07 16:02 createdsealed
MC-4491master319_A3 · B02PO-2026-115 5DQR7 ×2020120 -29-07 10:40 split_innew · from split
MC-4455master · multiRECEIVINGINF-2319 2 SKUs · PP02 ×484830 -29-07 13:58 createdawaiting QC
MC-4448master · multiQC_HOLDINF-2318 4 SKUs · mixed2420 -26-07 11:20 qc_queuedRNI 74h · SLA breach
MC-4433master319_A1 · A03PO-2026-114 FYN01 ×60 of 120601120 26-07 08:1029-07 12:05 remove_to_pickingopened · picking
MC-4412master319_A2 · C11PO-2026-114 LBA01 ×3636136 -21-07 14:44 movesealed
MC-4401master · multi319_A1 · A08PO-2026-113 XTRA-STRAP ×20020040 -18-07 10:12 createdsealed
MC-4390masterRTS_STAGINGPO-2026-113 XTRA-STRAP ×12012020 -26-07 09:30 rts_stageRTS-0022 staged 3d
MC-4377masterDAMAGEPO-2026-112 PP02 ×6616 27-07 15:2227-07 15:40 qc_reject_localdamage unmatched 49h
MC-4355retail319_PICKINGRPK-318 FYB01 ×1212·12 28-07 11:0528-07 11:05 repack_inrepack output
MC-3812master319_A5 · E22PO-2025-088 TNS01 ×484810 -28-12-2025 createdaged 214d
MC-4218masterHQ_325PO-2026-109 CDW01 ×0010 14-07 09:0019-07 16:10 voidvoided · excluded
412 master · 1,108 sub · 15 shown · contributing to the identity: 389 cartons (sealed and opened), excluded: 23 (voided, archived) · carton units 29,637 + picking loose 2,205 = 31,842 = ledger STOCK at HQ_319

Partial split with relabel

Peel n pieces off a carton into a new standalone carton at another zone. Both labels reprint. Idempotent on the split key, so a retried scan returns the original result instead of creating a second carton.

MC-4462
40 → 20
5DQR7 · 319_A2 · C04
relabelled 10:41
→
MC-4491
+20
5DQR7 · 319_A3 · B02
relabelled 10:41
Idempotency key
iwms:split:MC-4462:0007
Ledger rows written: 0 · both cartons are at HQ_319 under STOCK, so location and stock type are unchanged and the split is a registry event only.
SplitSourceNewQtyTo zoneLabelsLedger
SPL-0212MC-4462MC-449120319_A3both printedregistry only
SPL-0211MC-4433MC-448960319_PICKINGboth printedregistry only
SPL-0210MC-4401MC-448880HQ_3251 of 2 · 34m2 rows · cross-location
SPL-0209MC-4390MC-4487120RTS_STAGINGboth printed2 rows · STOCK to RTS_PENDING
SPL-0208MC-4412MC-448612319_A2both printedregistry only
SPL-0207MC-4455MC-448524QC_HOLDboth printed2 rows · RNI to QUARANTINE
SPL-0210 has been half-labelled for 34 minutes. A split is not physically complete until both labels are printed; after 30 minutes it lands on the exceptions queue, because a carton on a shelf with the old label and the new quantity is exactly how a count goes wrong.

Picking replenishment

Loose pieces in 319_PICKING, each traceable to the carton it came out of. Opening a carton debits its lines by exactly what the picking row is credited.

SKUSource cartonLooseCarton leftDebitedOpenedAge
MSR31-07MC-4471618629-07 13:411h
FYN01MC-443360606026-07 08:103d
LBA01MC-440918141825-07 09:224d
PP02MC-439822262224-07 15:405d
JRY01MC-43864004022-07 10:057d
FYB01MC-435593928-07 11:051d
CDW01MC-43411281221-07 08:558d
JAE17MC-43302842820-07 14:129d
TNS01MC-4318711719-07 09:4010d
MSR31-08MC-430516141618-07 16:3011d
XTRA-STRAPMC-429144564417-07 11:1812d
5DQR7MC-42773193116-07 13:0213d
38 open picking rows · loose 2,205 u · debited from cartons 2,205 u · the pair nets to 0, which is the invariant. Where the debit column disagrees with the loose column, the row is a drift case, not a rounding difference.

Carton-level damage matching

48-hour window Damage queue ↗
DamageSourceCartonUnit / EPCCarton eventGapQtyMatch
DMG-0421IWMS QCMC-4448-qc_reject_local 26-07 11:200h4matched on carton
DMG-0420ops2 returnsMC-4471E280…8F3Copen 29-07 13:412h1matched on unit
DMG-0419CSD intakeMC-4433E280…7A11remove_to_picking 29-07 12:056h1matched on unit
DMG-0418IWMS QCMC-4377-qc_reject_local 27-07 15:4049h6outside window · needs a human link
DMG-0417RFIDMC-4355E280…9C04repack_in 28-07 11:053h1matched on unit
DMG-0416ops2 dispatchMC-4412-move 21-07 14:4418h2matched on carton
DMG-0415IWMS QCMC-4401-qc_repair_local 18-07 12:022h3matched on carton
DMG-0414CSD intake-E280…4B77no carton event found-1unmatched incident
A damage report matches a carton event when it shares a carton id or a unit id and falls inside 48 hours of that event. Outside the window it becomes an unmatched incident that a human must link, because an automatic match on a stale event is how a damage gets charged to the wrong PO and the wrong supplier.

Universal QR scan

One resolver, four outcomes. Scanning any code returns its kind and the actions permitted for it right now:

MC-4471 → carton → Receive · Count · QC · Move · Split · Open
MC-4462-A → sub-carton → Count · QC · Move · Split
319_A3_B12 → bin → Put-away here · Count this bin
319_PICKING → zone → Replenish · Count zone
E280 6894… → EPC → Unit timeline · Zone change

A carton scan followed by a bin scan inside 60 seconds executes the move without a confirm step. That pairing slot is one row per operator, so scanning a second carton safely replaces the pending pair.

Why a carton event is never audit-only

In ops2, remove_pieces_to_picking calls record_movement(event_type="remove_to_picking"). That type is not in the valid-event set, so the call raises, and the caller swallows the exception with a comment saying movement logging is audit-only.

The result is that the carton is debited, the picking row is credited, and no movement row and therefore no ledger row is ever written. Every partial replenishment since that feature shipped is invisible to the ledger.

In i3 there is no audit-only path. carton_events.event_type is a foreign key to the event registry, so an unregistered type is a constraint violation at insert. The carton event and its ledger row are written in one transaction or neither is written. Nothing can swallow it into silence.

Sub-carton invariant

A multi-SKU parent's quantity is always the sum of its children, enforced by trigger. A parent contributes nothing to the reconciliation identity; only its children do.

Limits carried over from ops2: at most 20 distinct SKUs and 100 children per parent. A merge exists as the inverse of a split, for when the packing-list parser over-splits a mixed carton that arrived as one box.

Connected to

Locations → HQ_319 floor → IWMS events → GRN and QC → POs and PI → Transfers → Return to supplier → Damages → Stock count → RFID gates → 3-way reconcile → Drift → SKU detail →