Preparation & delivery
Preparation with picking list up to ready, shipping with own fleet or carrier and tracking number, proof of delivery, carriers, the V2 carrier API and the delivery-fee policy.
This area covers what happens between the back-office confirmation of an order and its delivery (cahier §3, §4.4, §11, §14.2, reference screen 5): preparation, shipping, proof of delivery, the carriers HOCO works with, and the delivery fee charged at checkout. It is run by the Responsable livraison in the back-office (BO); resellers follow it in their apps (RA, RW) through the order tracker. The server's fulfillment module owns Delivery and Carrier; the order moves through admin.orders.transition and admin.deliveries.* (API › Orders & delivery); statuses on Lifecycles › Delivery.
| ID | Requirement | Release | Priority | Source | Apps |
|---|---|---|---|---|---|
DLV-01 | Preparation workflow (picking list) up to 'ready' | V1 | MUST | §3, §4.4 | API · BO |
DLV-02 | Shipping: carrier assignment (own fleet or company), tracking number | V1 | MUST | §4.4 | API · BO |
DLV-03 | Delivery confirmation with proof (photo, recipient name) | V1 | MUST | §3, §4.4 | API · BO |
DLV-04 | Carrier list management (API-capable vs manual) | V1 | SHOULD | §11 | API · BO |
DLV-05 | Carrier API integration (shipment creation, tracking webhooks) | V2 | SHOULD | §11, §14.2 | API |
DLV-06 | Delivery-fee policy (free threshold, per wilaya) | V1 | SHOULD | Reference screen 5 | API · BO |
Settings used in this area
| Setting | Default | Meaning |
|---|---|---|
delivery.feePolicy | FREE | FREE: no fee once the minimum is reached (« Offerts »); WILAYA_TABLE: fee per wilaya (D-20). |
delivery.feeByWilaya | — | WILAYA_TABLE: fee HT per wilaya code, plus a default fee. |
delivery.freeThresholdTtc | — | WILAYA_TABLE: merchandise total TTC from which delivery is free. |
delivery.proofPhotoRequired | true | A proof photo (or signature) is required to mark an order delivered. |
stock.deductOn · billing.invoiceOn | SHIPPED · SHIPPED | Stock deduction and invoice at shipping (STK-03, FIN-01). |
Requirements
DLV-01 — Preparation workflow up to ready
Statement — The system shall manage the preparation of every confirmed order — delivery board, picking list, picking and packing — until it is ready to leave.
Rules
- Confirmation (ORD-14) creates a
DeliveryinTO_PREPAREwith a proposed mode from the address. The delivery board (BO-42,admin.deliveries.list,delivery.view) shows one column per status — À préparer, En préparation, Prête, Expédiée, Livrée, Échec de livraison — or the same records as a list, with filters by wilaya, mode, carrier and date, and late orders highlighted. - « Commencer la préparation » moves the order
VALIDATED → PREPARING(admin.orders.transition,orders.updateordelivery.update); the user becomes the picker. - The picking list (
admin.deliveries.pickingList, JSON or A4 PDF) shows the order number with its barcode, the reseller, the address and landmark, the notes, the warehouse and per line brand, product, variant, SKU, barcode and quantity — sorted by brand then SKU, no prices. - A picking shortage is handled before packing by a controlled modification that decreases or removes the line, with a reason the reseller sees (ORD-05); quantities can never be increased while
PREPARING. - « Prête » moves
PREPARING → READYwith the number of parcels (≥ 1,400 VALIDATION_FAILEDotherwise); the delivery noteBL-YYYY-NNNNNNis allocated and its PDF generated (ORD-12). - The
Deliverymirrors the order in the same transaction; each move is journaled and pushed live to the reseller (ORD-15).
Acceptance criteria
- Confirming an order adds a card under À préparer on BO-42 without reload.
- The picking list PDF of
CMD-2026-000158lists its lines by brand with SKU, barcode and quantity and no price. - Marking an order Prête without parcels returns
400 VALIDATION_FAILED; with 2 parcels it allocatesBL-2026-000123and the delivery note can be downloaded. - A delivery manager without
orders.updatecan move orders through preparation (holdsdelivery.update) but cannot cancel them.
Data — Delivery, Order, OrderStatusChange, OrderChange, File (picking list, delivery note), NumberSequence.
Interfaces
- Screens: BO-42 Delivery board
- API:
admin.orders.transitionPOST /admin/orders/{orderId}/transitions·admin.deliveries.listGET /admin/deliveries·admin.deliveries.pickingListGET /admin/deliveries/{deliveryId}/picking-list
DLV-02 — Shipping with carrier or own fleet and tracking number
Statement — The system shall record how each order is delivered — HOCO's own drivers, a delivery company or pickup at the depot — with the carrier, tracking number or driver, and mark it shipped.
Rules
- Delivery data (
admin.deliveries.update,delivery.update): mode (DeliveryMode:OWN_FLEET,CARRIER,PICKUP, changeable until shipping), carrier, tracking number (3–60 characters), driver name and phone (E.164), planned date, parcels, note. - Shipping guard (
READY → SHIPPED):OWN_FLEETneeds a driver name and phone;CARRIERneeds an active carrier covering the delivery wilaya and a tracking number when the carrier requires one (422 DELIVERY_INFO_REQUIREDwithdetails.missing;422 CARRIER_INACTIVE); aPICKUPorder does not ship — it goes fromREADYtoDELIVEREDat handover (DLV-03). - Shipping deducts stock (
SHIPMENTmovements) and issues the invoice with the defaults (STK-03, FIN-01); the tracking link is built from the carrier's template (https://…/{tracking}). - Failed attempt: on a shipped order,
attempt(reason required, next attempt date) sets the deliveryFAILEDwhile the order staysSHIPPED;reattemptputs it back toSHIPPED; after the last failure the goods come back withSHIPPED → RETURNED(refused at the door), which creates a return in transit whose reception re-enters the stock automatically (ORD-13). - A delivered, returned or cancelled delivery cannot be edited (
409 DELIVERY_NOT_EDITABLE). - Notifications to the reseller: shipped (with carrier and tracking link), failed attempt (« Livraison non aboutie — nouvelle tentative le … »), returned — push, inbox and live.
Acceptance criteria
- Shipping a
CARRIERorder without tracking number for a carrier that requires one returns422 DELIVERY_INFO_REQUIREDwithmissing: ["trackingNumber"]. - Shipping with carrier Yalidine and tracking
YAL-58219004moves the order toSHIPPED, posts the stock deduction, issues the invoice and sends the reseller a push with the tracking link. - A failed attempt keeps the order
SHIPPED, shows Échec de livraison on BO-42 and notifies the reseller with the next attempt date. - Editing a delivered delivery returns
409 DELIVERY_NOT_EDITABLE.
Data — Delivery, Carrier, Order, StockMovement, Invoice.
Interfaces
- Screens: BO-42 Delivery board
- API:
admin.deliveries.listGET /admin/deliveries·admin.deliveries.updatePATCH /admin/deliveries/{deliveryId}
DLV-03 — Proof of delivery
Statement — The system shall record a proof of delivery — recipient name, time and a photo or signature — before marking an order delivered, and record the cash collected on cash-on-delivery orders.
Rules
admin.deliveries.proof(delivery.update): recipient name (2–120), delivery time (after shipping, at most 5 minutes in the future), aDELIVERY_PROOFphoto or signature (required whiledelivery.proofPhotoRequiredis true —422 DELIVERY_PROOF_REQUIRED), optional note.- Allowed on a
SHIPPEDorder, orREADYwith modePICKUP(handover at the depot); otherwise409 ORDER_TRANSITION_NOT_ALLOWED. The order and delivery becomeDELIVERED; a move toDELIVEREDthrough the generic transition is refused (422 DELIVERY_PROOF_REQUIRED). - Cash collected on a
CASH_ON_DELIVERYorder creates aPayment(PAY-…, statusPENDING_VERIFICATION) linked to the order and its invoice; finance confirms it (FIN-03) — delivery staff never confirm money. - Delivery starts the return and after-sales windows, makes the reseller
ACTIVEafter a first order (CRM-04) and notifies the reseller (« Commande livrée »). - In V1 proofs are entered in the back-office from what the driver or carrier reports; a driver app is not in scope. Proof photos are private files served by signed URLs.
Acceptance criteria
- Recording the proof of a shipped order with recipient Hichem Bouzid and a photo marks it
DELIVERED; RA-22 shows Livrée live. - Without photo while the setting is on, the API returns
422 DELIVERY_PROOF_REQUIRED. - Recording 10 234,00 DA collected creates
PAY-2026-000081PENDING_VERIFICATIONvisible to finance in BO-45. - A proof on a
VALIDATEDorder returns409 ORDER_TRANSITION_NOT_ALLOWED.
Data — Delivery (proof), File (DELIVERY_PROOF), Order, Payment.
Interfaces
- Screens: BO-42 Delivery board
- API:
admin.deliveries.proofPOST /admin/deliveries/{deliveryId}/proof
DLV-04 — Carrier list management
Statement — The system should let the back-office maintain the list of carriers — HOCO's own fleet and delivery companies — with their coverage, tracking link template and whether they offer an API.
Rules
- A
Carrierhas a unique name (2–80,409 DUPLICATE_VALUE), a mode (OWN_FLEET,CARRIER), a phone, a tracking URL template containing{tracking}(https only), whether a tracking number is required, the wilayas covered (empty = all), an API-capable flag (informative in V1, used by V2 integration) and an active flag. - Managed in BO-43 (
admin.carriers.crud): read withdelivery.view(so the board can offer the picker), write withdelivery.administer. - A carrier used by deliveries is deactivated, never deleted; an inactive or non-covering carrier cannot be chosen for a delivery (
422 CARRIER_INACTIVE).
Acceptance criteria
- Creating a carrier with a template lacking
{tracking}returns400 VALIDATION_FAILED. - A carrier covering wilayas 31, 46 and 29 is not offered for a delivery to wilaya 16.
- Deactivating Yalidine removes it from the picker and keeps it on past deliveries.
Data — Carrier, Delivery.
Interfaces
- Screens: BO-43 Carriers
- API:
admin.carriers.crudGET · POST · PATCH /admin/carriers[/{carrierId}]
Notes / open points — Which carriers HOCO uses is D-08.
DLV-05 — Carrier API integration
| Release | Priority | Source | Apps | Owner tasks |
|---|---|---|---|---|
| V2 | SHOULD | cahier §11, §14.2 | API | SRV-34 |
Statement — The system should, in V2, create shipments and follow their tracking through the API of the carriers that offer one.
Rules
- For an API-capable carrier, shipping creates the shipment through its API (parcels, address, cash to collect) and stores the carrier's tracking number and label PDF.
- The carrier's tracking webhooks (signature verified, processed idempotently) update the delivery: in transit, delivered (with the carrier's proof), failed attempt, returned to sender — mapped to the same transitions as manual entry.
- When the API is down, the delivery falls back to manual entry without blocking the order.
Acceptance criteria
- A shipment created for an API-capable carrier stores the carrier's tracking number; its delivered webhook marks the order
DELIVERED. - The same webhook received twice changes nothing the second time.
Data — Carrier, Delivery, integration logs.
Interfaces
- Screens: none dedicated
- API: no dedicated operation
Notes / open points — V2 (SRV-34), depends on D-08.
DLV-06 — Delivery-fee policy
Statement — The system should compute the delivery fee of an order from a configurable policy — free, or per wilaya with a free-delivery threshold — and show it before checkout.
Rules
delivery.feePolicy = FREE(default): every order that reaches the minimum amount is delivered free; the cart shows « Frais de livraison : Offerts » (reference screen 5).WILAYA_TABLE: the fee is the amount HT ofdelivery.feeByWilayafor the delivery address's wilaya (or the table's default); it is waived when the merchandise total TTC after promotions reachesdelivery.freeThresholdTtc, or when aFREE_DELIVERYpromotion applies (PRM-01);PICKUPis always free.- The fee is HT with VAT at 19 % added to the totals (PRC-04); the cart computes it for the default address,
cart.checkoutOptionsfor each address, and checkout freezes it on the order — a later policy change never alters an order. - A changed fee between display and checkout makes the checkout answer
409 CART_CHANGED(PRC-05). - The policy and table are business settings (ADM-03), changed by
settings.administerand journaled.
Acceptance criteria
- With the default policy, a cart above the minimum shows Offerts and
deliveryFee: 0. - With
WILAYA_TABLE, a fee of 50 000 HT for wilaya 31 and a threshold of 5 000 000 TTC: a cart of 4 200 000 TTC delivered in Oran gets 50 000 HT (59 500 TTC) of fee; a cart of 5 100 000 TTC gets 0. - A
FREE_DELIVERYpromotion targeted at the reseller sets the fee to 0 whatever the table.
Data — Setting, Order (frozen fee), Cart, Promotion.
Interfaces
- Screens: RA-18 Checkout
- API:
cart.checkoutOptionsGET /cart/checkout-options
Notes / open points — Free delivery or a fee table is D-20 (default: free).
Error codes
| Code | HTTP | Raised when |
|---|---|---|
ORDER_TRANSITION_NOT_ALLOWED | 409 | A move or proof not allowed from the order's status |
DELIVERY_NOT_EDITABLE | 409 | Editing a delivered, returned or cancelled delivery, or an attempt in the wrong state |
DUPLICATE_VALUE | 409 | Carrier name already used |
DELIVERY_INFO_REQUIRED | 422 | Shipping without driver or tracking data |
CARRIER_INACTIVE | 422 | Inactive carrier or one not covering the wilaya |
DELIVERY_PROOF_REQUIRED | 422 | Delivered without proof photo, or through the generic transition |
REASON_REQUIRED | 422 | Failed attempt or door refusal without reason |
DOCUMENT_NOT_AVAILABLE | 409 | Picking list of a cancelled delivery |
Cart & orders
The server-side cart and its rules, checkout, the eleven-status order lifecycle with back-office confirmation of every order, processing, history, live tracking, assisted orders, first orders, cancellation, phone orders, documents and returns.
Invoicing, payments & credit
Invoices with legal mentions and statuses, payment methods, payments recorded and declared, allocation, credit control at checkout, credit notes and receipts, the reseller finance view, and the V2 detailed credit, reminders and accounting exports.