Module: Courier / Delivery Partner (courier / logistics)
Status: ๐ก Backend Only (6 real carrier adapters; near-zero stored credentials) ยท Last validated: 2026-09-06 ยท Priority: P1
Multi-carrier shipping integration for merchant parcels. Validated against classs/DeliveryPartnerCourierModule.php + classs/courier_providers/ + schema.
A. Purpose
Merchants ship orders via aggregated carriers (Shiprocket, Delhivery, DTDC, Shadowfax, Xpressbees, Shree Maruti) โ real cURL adapters in classs/courier_providers/. Revenue: per-shipment fee possible, none defined.
B. Actors
Merchant (shipper); carrier (external); admin. Enrollment logistics.
C. Entry points
/courier_intro.php, /courier_dashboard.php; merchant delivery_partner_shipments.php. External API: api/developer/shipping.php (scopes shipping.write :124, tracking.read :66). (corrected 2026-09-06: doc previously said shipping.manage; the scope literally required by devapi_require_scope() in that file is shipping.write.)
E. Feature registry (prefix CUR-)
| ID | Feature | Actor | Method | Tables | Status |
|---|---|---|---|---|---|
| CUR-001 | List supported vendors | merchant | listSupportedVendors :734 | โ | ๐ข |
| CUR-002 | Save vendor credentials | merchant | setVendorCredentials :894, getVendorCredentials :960 | credential store | ๐ก (mostly unset) |
| CUR-003 | Company shipping settings | merchant | getCompanySettings :809, saveCompanySettings :828 | settings | ๐ข |
| CUR-004 | Pick vendor for payload | system | pickVendorForPayload :175 | โ | ๐ข |
| CUR-005 | Generate label | merchant | getLabel(companyId, shipmentUid) :749 | courier_shipments | ๐ก |
| CUR-006 | Inbound webhook (status) | carrier | generateWebhookSecret :864 + webhook | courier_shipments | ๐ก |
G. Data model (2026-09-06)
courier_partners 9 (api_credentials_json NULL on all) ยท courier_shipments 4.
H. Financial impact
Shipping charges pass through to the order; no platform courier commission defined.
K. State machine (courier_shipments)
draft โ booked โ picked_up โ in_transit โ out_for_delivery โ delivered / booking_failed / ndr_pending / rto_initiated/rto_delivered / cancelled (carrier webhook updates status). (corrected 2026-09-06: doc previously said created โ label_generated โ ... โ rto. Code shows otherwise โ createShipmentDraft() (classs/DeliveryPartnerCourierModule.php:1018) defaults initialStatus to draft; getLabel() moves it straight to booked in the same update that writes awb_number/label_url (:1276-1286, on success) or to booking_failed (:1266, on failure) โ there is no separate label_generated state. Webhook status mapping (:419-425) emits picked_up/in_transit/out_for_delivery/delivered/rto_initiated/ cancelled, and :1801 also references a ndr_pending status; the exact string is rto_initiated/ rto_delivered, not bare rto.)
L / M / N
Errors: CUR-E001 code labels the active path "simulated" โ carriers won't actually ship until setVendorCredentials stores real keys (all courier_partners.api_credentials_json are NULL). Depends on the order module, external carrier APIs. Change-impact: storing credentials flips this from simulated to live โ re-test label generation + tracking webhook per carrier.