Dingoo Barcode Format
Barcodes (order IDs) generated by the invoice flow follow an 18-character format. They serve both as a unique shipment identifier and as a scannable barcode on the physical label.
Structure
| Field | Length | Description |
|---|---|---|
country |
2 chars | ISO country code (e.g. PT) |
zone |
4 digits | Distribution zone code (zero-padded) |
size |
1 digit | Package size code (1–5, or 0 if unknown) |
serial |
8 digits | Sequential number fetched from MongoDB (zero-padded) |
volume |
2 digits | Parcel index within the invoice (1 to 99, zero-padded) |
checkdigit |
1 digit | Integrity check digit |
Example: PT9876100000123018
- country =
PT - zone =
9876 - size =
1 - serial =
00000123 - volume =
01(first parcel of the invoice) - check digit =
8
Barcode Generation per Invoice
When an invoice with N parcels is imported:
- A unique serial is fetched from MongoDB for each parcel (via an atomic counter).
- The volume number is assigned sequentially: parcel 1 gets
01, parcel 2 gets02, etc. - The size code comes from the
sizefield of eachInvoiceOrderItem(1–5). - The check digit is computed from the 15 numeric characters that make up the barcode body.
Check Digit Algorithm
The check digit protects against transcription errors. It is computed from the 15 numeric characters that sit between the 2-char country code and the check digit itself.
P T 9 8 7 6 1 0 0 0 0 0 1 2 3 0 1 ?
└──┘ └─────────────────────────────────────────┘ └┘
country numeric part (15 digits) cd
The numeric part is the direct concatenation of the four inner fields:
numeric_part = zone(4) + size(1) + serial(8) + volume(2)
= "9876" + "1" + "00000123" + "01"
= "987610000012301" (15 digits)
Steps
- Reverse the 15-digit numeric part.
- For each digit at position
i(starting at 0), assign weight 3 ifiis even, 1 ifiis odd. - Sum all
digit × weightproducts. - Check digit =
(10 − (sum mod 10)) mod 10.
Worked Example — PT9876100000123018
Numeric part: 987610000012301
Reversed: 103210000016789
| i | Digit | Weight | Product |
|---|---|---|---|
| 0 | 1 | 3 | 3 |
| 1 | 0 | 1 | 0 |
| 2 | 3 | 3 | 9 |
| 3 | 2 | 1 | 2 |
| 4 | 1 | 3 | 3 |
| 5 | 0 | 1 | 0 |
| 6 | 0 | 3 | 0 |
| 7 | 0 | 1 | 0 |
| 8 | 0 | 3 | 0 |
| 9 | 0 | 1 | 0 |
| 10 | 1 | 3 | 3 |
| 11 | 6 | 1 | 6 |
| 12 | 7 | 3 | 21 |
| 13 | 8 | 1 | 8 |
| 14 | 9 | 3 | 27 |
Sum = 3 + 9 + 2 + 3 + 3 + 6 + 21 + 8 + 27 = 82
Check digit = (10 − (82 mod 10)) mod 10 = (10 − 2) mod 10 = 8 ✓
The last character of PT9876100000123018 is indeed 8.
Python Reference
def _check_digit(numeric_part: str) -> int:
digits = list(map(int, numeric_part[::-1]))
total = sum(d * (3 if i % 2 == 0 else 1) for i, d in enumerate(digits))
return (10 - (total % 10)) % 10
Size Codes
| Code | Description |
|---|---|
1 |
Extra Small |
2 |
Small |
3 |
Medium |
4 |
Large |
5 |
Extra Large |
Relabeling: orderId vs confirmedBarcode
orderId is generated once, when the parcel is first created, using the invoice's parcel count and position at that moment (e.g. the 4th parcel of a 4-parcel invoice gets volume 04). It never changes afterwards — it's the stable internal key used for every API call, DB lookup and status history (GET /orders/{order_id}, PUT /cancel_order, orderFlows, etc.).
That volume number embedded in orderId can become stale: if parcels of the same invoice are later cancelled or added (e.g. via PUT /cancel_order or POST /update_invoice_orders), the parcel's position among the currently active parcels of the invoice changes, but orderId doesn't reflect that anymore.
To keep printed labels correct without renaming orderId, the orders collection has a separate confirmedBarcode field:
- Whenever the active-parcel numbering of an invoice is recalculated (cancel, uncancel, or add), each active parcel gets a new barcode value written to
confirmedBarcode— samecountry/zone/size/serialas the original, onlyvolume(renumbered 1..N among the active parcels) and the check digit change. Seerefresh_invoice_label_numberinginexternal-api/src/utils/databases_util.py. orderIditself is never modified by this process.- The label generator (
generateOrderLabel.jsin the BO) prints and encodesconfirmedBarcodewhen present, falling back toorderIdotherwise — so the printed number and the scanned barcode always match each other, even though they may no longer match the volume digits insideorderId. - Scanning already resolves by priority
confirmedBarcode→possibleBarcodes→orderId(seefindOrderByBarcodeindingoo-api/app/bo/routes/v1/orders.js), so a relabeled parcel still scans correctly.
In short: orderId is "when/how this parcel was first created." confirmedBarcode (when set) is "what's actually printed and scanned right now." They can legitimately differ after cancellations.