shippingservice/documentation/pickup_scheduling_architecture.md
vignesh b8ba39c3f8
All checks were successful
Deploy Beta (NATIVE) / deploy (push) Successful in 39s
feat: implement shipping views, carrier allocation, models, and pickup scheduling architecture
2026-10-13 19:23:16 +05:30

10 KiB
Raw Blame History

Tradhox Multi-Carrier Pickup Scheduling Architecture & Logistics Guide

This document defines the complete architecture, carrier rules, multi-seller scenarios, multi-location logistics, and data audit structures for scheduling courier pickups across Delhivery, Ekart Logistics, and Shadowfax.


1. Carrier Capabilities & Pickup Workflow

Carrier Date Selection Time Slot Selection Minimum Wallet Balance Pickup Mechanism
Delhivery Logistics Yes (YYYY-MM-DD) Yes (10:00:00, 14:00:00, 17:00:00) ₹500.00 (Strict Floor) Live First-Mile API (POST /fm/request/new/). Dispatches executive to seller warehouse.
Ekart Logistics Yes (YYYY-MM-DD) Daily Hub Sweep (Morning & Evening) Positive freight balance Sets preferred dispatchDate (POST /data/shipment/dispatch-date). Hub sweeps run twice daily.
Shadowfax Logistics SLA Scheduled Automated Cut-Off Sweep Positive freight balance Automated route sweeps based on seller warehouse dispatch cutoff times (e.g. 2:00 PM / 4:00 PM).

2. Delhivery One Special Rules & Error Handling

2.1. Strict Minimum Wallet Reserve (₹500.00 Floor)

  • Delhivery One enforces a minimum wallet balance floor of ₹500.00 before accepting any First Mile pickup dispatch:
    HTTP 400 Bad Request
    { "prepaid": "Client wallet balance is 454.32 which is less than 500.0" }
    
  • Rationale: Delhivery holds a security reserve against potential weight discrepancies, volumetric adjustments, fuel surcharges, and RTO risk.
  • Resolution: The seller must top up their Delhivery One wallet (via one.delhivery.com \rightarrow Finances \rightarrow Wallet) so the balance crosses ₹500.00.

2.2. Single Pickup Request Per Warehouse / Slot (Code 669)

  • Delhivery allows only ONE active Pickup Request per warehouse per date & slot.
  • When a pickup is already booked for warehouse SAM on that date/slot and another request is sent, Delhivery returns:
    {
      "status": true,
      "success": false,
      "pr_exist": true,
      "pickup_id": 328094672,
      "error": {
        "code": 669,
        "message": "A Pickup Request 328094672 for this Pickup Location Already Exist for 13 Oct in slot 14:00 - 18:00"
      }
    }
    
  • Tradhox Implementation:
    • Code 669 is not an error; it confirms that Delhivery already has an active pickup assigned to that location.
    • The backend catches pr_exist = true, extracts pickup_id = 328094672, records it on the order, and presents a green confirmation banner to the seller.

3. Multi-Seller Scenarios

Scenario A: Distinct Store / Workshop Names (Default)

  • Even if multiple sellers share the same neighborhood or pincode (641301):
    • Seller 1: Warehouse name = SAM
    • Seller 2: Warehouse name = KUMAR-CRAFTS
  • Delhivery evaluates pickup requests strictly by Warehouse Name, not pincode.
  • Seller 1 receives their own Pickup ID (PUR-1), and Seller 2 receives their own Pickup ID (PUR-2).
  • Delhivery dispatches independent field executive visits.

Scenario B: Shared Artisan Cluster / Consolidation Hub

  • If multiple artisans bring their finished crafts to a shared guild center registered under warehouse SAM:
    • Seller A books a pickup for 13 Oct (2 PM – 5 PM) \rightarrow creates Delhivery Pickup Request #328094672.
    • Seller B at the same hub later reschedules their order for the same date/slot.
    • Delhivery returns code 669 (pr_exist = true).
    • Tradhox automatically attaches Seller B's order to Pickup Request #328094672.
    • When the Delhivery pickup van arrives at hub SAM, the driver scans all packages waiting at SAM in one consolidated visit.

4. Multi-Order & Multi-Location Logistics

Scenario 1: One Seller Warehouse \rightarrow Multiple Delivery Destinations

  • Origin: Warehouse SAM (Coimbatore / Mettupalayam).
  • Destinations: Order 1 (Chennai), Order 2 (Bengaluru), Order 3 (Mumbai).
  • Logistics Flow:
    1. Only 1 Pickup Request is created for warehouse SAM.
    2. Delhivery dispatches one pickup executive to SAM.
    3. The executive scans all packages into their handheld device and loads them into the local van.
    4. At the central Delhivery sorting hub, Delhivery's sorting automated line splits the packages onto their respective linehaul trucks and airport cargo containers according to destination sort codes (CHE/GUU, BLR/SRA, BOM/AND).

Scenario 2: One Seller with Multiple Origin Workshops

  • Workshop 1: SAM-Coimbatore (Coimbatore).
  • Workshop 2: SAM-Salem (Salem).
  • Logistics Flow:
    1. Each workshop is registered as an independent pickup warehouse in Delhivery.
    2. Orders dispatched from Workshop 1 create a Coimbatore pickup assignment.
    3. Orders dispatched from Workshop 2 create a Salem pickup assignment.
    4. Both pickups execute concurrently without interference.

5. Database Schema & Audit Logging

seller_central_backend (Order Model)

class Order(models.Model):
    ...
    eta = models.CharField(max_length=50, default='N/A')
    pickup_id = models.CharField(max_length=100, blank=True, null=True, help_text='Carrier Pickup Reference ID')
    pickup_payload = models.JSONField(default=dict, blank=True, null=True, help_text='Carrier Pickup Scheduling Response & Audit Details')

Stored pickup_payload JSON Structure

{
  "latest_status": "success",
  "last_scheduled_at": "2026-10-12T13:39:37Z",
  "pickup_id": "328094672",
  "pickup_date": "2026-10-13",
  "pickup_time": "14:00:00",
  "carrier": "Delhivery Logistics",
  "history": [
    {
      "scheduled_at": "2026-10-12T13:39:37Z",
      "status": "success",
      "pickup_id": "328094672",
      "pickup_date": "2026-10-13",
      "pickup_time": "14:00:00",
      "carrier": "Delhivery Logistics",
      "message": "Pickup request #328094672 is already confirmed with Delhivery for 2026-10-13",
      "raw_response": { ... }
    }
  ]
}

Microservice Audit Tables (shippingservice)

  • Delhivery: DelhiveryActivityLog (records every HTTP status, endpoint, request headers/payload, and response).
  • Ekart: EkartActivityLog (records all token, dispatch-date, and tracking calls).
  • Shadowfax: ActivityLog (records forward/reverse order dispatch and tracking calls).

6. Delhivery One Web Portal ("Add to Pickup") vs. REST API Workflow

6.1. Why Orders in the Web Portal Show "Add to Pickup"

  • In the Delhivery One Web Dashboard (one.delhivery.com/orders/forward/ready-to-ship), manifested orders display an "Add to Pickup" button.
  • The web portal has its own internal UI workflow:
    1. A dashboard user selects orders and clicks "Add to Pickup".
    2. The portal prompts for date, time slot, and warehouse, and generates a Pickup Request (PUR).
    3. Once submitted through the web UI, the portal UI groups those orders and displays them under the "Ready For Pickup" tab.

6.2. How the REST API Operates

  • In Delhivery's official developer API, order creation and pickup requests are decoupled:
    1. Order Manifestation API (POST /api/cmu/create.json):
      • Registers the consignment, creates the AWB, and maps it to the warehouse (SAM).
    2. Pickup Request Creation API (POST /fm/request/new/):
      • Dispatches a field executive to the warehouse (SAM) with pickup_date, pickup_time, and expected_package_count.
      • The REST API does not accept a list of waybills/orders. It books the executive visit for the entire warehouse.
  • Physical Scan & Handoff:
    • The Delhivery delivery executive arrives at the warehouse holding the active Pickup Request ID (e.g. #328095871).
    • The driver scans the physical barcode/AWB label on each package using their handheld scanner.
    • The scan links the package to the pickup run and immediately transitions the order status from manifested directly to "In Transit" / "Picked Up".
  • Tradhox User Experience:
    • In Tradhox Supplier Central, once an order is manifested and scheduled, Tradhox surfaces the active Pickup Request ID (PR #328095871) and PICKUP SCHEDULED badge.
    • Merchants do not need to manually click "Add to Pickup" inside the Delhivery One portal; the courier executive will collect all ready packages for warehouse SAM.

7. Check Pickup Schedule by Tracking ID (AWB) Specification

7.1. REST Endpoints

Clients can query the pickup schedule using either endpoint:

  • Primary Route: GET /api/v1/carrier/pickup-schedule/?tracking_id=<AWB>
  • Unified Alias: GET /api/v1/carrier/schedule-pickup/?tracking_id=<AWB>
  • POST Route: POST /api/v1/carrier/pickup-schedule/ with JSON {"tracking_id": "<AWB>"}

Supported Query Parameters

  • tracking_id / awb / tracking / waybill: The carrier waybill or client order ID (e.g. 69873010000232).

7.2. Response Schema

{
  "status": "success",
  "tracking_id": "69873010000232",
  "order_id": "32-18",
  "carrier": "DELHIVERY",
  "carrier_display": "Delhivery Logistics",
  "pickup_scheduled": true,
  "pickup_id": "328095871",
  "pickup_date": "2026-10-14",
  "pickup_time": "10:00:00",
  "pickup_slot": "Morning Slot (10:00 AM – 1:00 PM)",
  "pickup_location": "SAM",
  "shipment_status": "Manifested",
  "pickup_status": "CONFIRMED",
  "status_display": "Pickup Confirmed with Delhivery Logistics (PR #328095871) for 2026-10-14 (Morning Slot (10:00 AM – 1:00 PM))",
  "destination": {
    "city": "Kanchipuram",
    "pincode": 600059
  },
  "consignee": {
    "name": "Vignesh Krishnasamy",
    "city": "Kanchipuram",
    "state": "Tamil Nadu",
    "pincode": 600059
  },
  "scans": [
    {
      "scan": "Manifested",
      "instructions": "Manifest uploaded",
      "location": "Mettupalayam_IshwaryNgr_D (Tamil Nadu)",
      "timestamp": "2026-10-12T19:04:35.275"
    }
  ],
  "details": {
    "expected_package_count": 1,
    "manifest_date": "2026-10-12T19:04:35.245",
    "picked_up_date": null
  }
}

7.3. Resolution Hierarchy

  1. shipping_pickupschedule Table: Checks if a local record exists.
  2. Live Carrier Tracking API:
    • For Delhivery, calls /api/v1/packages/json/?waybill={trk}, extracting origin warehouse, consignee address, and shipment status.
    • Cross-checks with active warehouse pickup requests.
  3. Cross-Database Order Lookup:
    • Queries api_order in customerprofile_beta to correlate pickup_id and ETA slot.
  4. Auto-Caching: Updates the PickupSchedule model so subsequent lookups are instant.