Skip to content

Dispatch & Delivery

Book: Sales & Revenue  |  Module: Dispatch & Delivery Scope: How a confirmed order/invoice physically gets loaded from the store, dispatched out the gate, delivered to the customer, and confirmed delivered. Nav home: Sidebar → Sales & Receivables → Dispatch & Delivery (resources/views/admin/includes/sidebar_includes/sales_and_receivables.blade.php:1690).


1. Purpose

Once a customer's order has been taken and turned into an invoice/requisition (that happens in the Order Taking & Sales Invoicing chapter), the goods still have to physically leave the warehouse and reach the shop. This module covers that whole physical journey:

  1. Loading sheet dispatch — a store keeper picks the goods for a route/delivery off the shelf and stages them at a loading bay, then a second person validates (double-counts) them, then they get loaded onto a vehicle. Any shortfall becomes a return.
  2. Delivery schedules — the loaded goods become a delivery (a trip). The system tracks the vehicle, driver, turnboy/operator, the customers to visit, tonnage, and route stops. Deliveries can be merged (combine trips) or split (break one trip into two), including across branches.
  3. Gate pass / gateman verification — before a loaded truck leaves the yard, a gate pass is issued and a gateman at the gate verifies the driver's identity (with a photo), scans the gate-pass code, and checks the truck is leaving within an allowed time window.
  4. Delivery confirmation — out on the route, the driver/delivery man marks each customer delivered on the mobile app, usually confirmed by a one-time code (OTP) sent to the customer. Deliveries that cannot be completed are logged as delivery failures for back-office review.

The guiding idea is a chain of custody: every hand-off (picked → staged → validated → loaded → out the gate → delivered) is recorded with who did it and when, and most hand-offs enforce that a different person does the next step (segregation of duties).

What this chapter does NOT cover (handed off elsewhere): - Creating the order/invoice → Order Taking & Sales Invoicing. - Vehicle/fleet master data, fuel, tyres, garage management → Fleet & Logistics. - Inbound goods coming IN from suppliers → Logistics & Inbound Deliveries. (This chapter is strictly outbound to customers.) - Route definitions themselves → Route Management.


2. Users & roles

Access is gated two ways in the code: - Backoffice (web): Controller::mypermissionsforAModule() returns the literal string 'superadmin' when role_id == 1, otherwise the user's permission array (app/Http/Controllers/Controller.php:1115). Menu items and actions check isset($my_permissions['<model>___<action>']) or the can('<action>','<model>') helper. - Mobile (Flutter app bizwizorderanddelivery): role determines the home screen (gateman, delivery man/driver, POS dispatcher, salesman/route roles) — lib/app/app.router.dart.

Role / actor Where Does what Key permissions (slugs)
Store keeper / dispatcher Web + POS dispatcher mobile Picks & stages loading-sheet items to the bay; scoped to their own bin (wa_unit_of_measures_id) store-loading-sheet___view, store-loading-sheet___view-undispatched, store-loading-sheet___validate, loading-sheet___preparation
Validator Web Double-counts staged items before loading; must not be the same person who prepared store-loading-sheet___validate, loading-sheet___validation
Loader Web Assigns vehicle & completes loading (3‑stage flow) loading-sheet___loading
Delivery man / Driver Mobile Drives the trip, marks each customer delivered (OTP), reports failures (route middleware; mobile role config('app.delivery_role', 184))
Turnboy / Operator Mobile Assists driver; an operator can be assigned exclusive app control of a delivery delivery-schedule___...
Gateman Mobile Verifies driver identity + photo at the gate, scans gate pass, enforces time window (gate flows; see gateman_verified_by)
Dispatch/Delivery supervisor Web Views schedules, merges/splits, reviews delivery failures, issues standalone gate passes, clears reports dispatch-and-delivery___view, delivery-schedule___view, delivery-schedule___clear-delivery-report, delivery-schedule___view-action-log, delivery-merging-and-splitting___view/add/reverse, cross-branch-delivery-merging___view/add/reverse, delivery-failures___view, standalone-gate-passes___view/add/edit/delete, dispatched-loading-sheets___view, dispatched-loading-sheets___view-all, shift_delivery_report___view, pending-returns-allocation___view, interbranch-loading-sheets___view/dispatch, credit-sales___dispatch

The whole menu block is wrapped in dispatch-and-delivery___view OR superadmin (sales_and_receivables.blade.php:1690).

Menu → destination map (sales_and_receivables.blade.php:1713–1839):

Menu label Route name Controller
Dispatch Loading Sheet store-loading-sheets.index ParkingListController@index
Pending Returns Allocation pending-returns.index PendingReturnsController@index
User Activity user-activity.index UserActivityController@index
Dispatched Loading Sheets store-loading-sheets.dispatched ParkingListController@getDispatched
Interbranch Loading Sheets interbranch-loading-sheets.index InterbranchLoadingSheetController@index
Deliveries delivery-schedules.index DeliveryScheduleController@index
Merging & Splitting delivery-merging-splitting.index DeliverySplittingAndMergingController@index
Cross-Branch Merging cross-branch-delivery-merging.index CrossBranchDeliveryMergingController@index
Delivery Failures deliveries.failures.index DeliveryFailureController@index
Shift Delivery Report dispatch-reports.shift-delivery-report DeliveryReportController@index
POS Dispatch / POS Dispatch Log / POS Cash Sales Returns pos-cash-sales.dispatch etc. PosCashSalesController (POS cash-sale dispatch — light touch here)
Credit Sales Dispatch credit-sales-dispatch CreditSalesController@dispatchScreen
Delivery Action Logs delivery-schedules.logs DeliveryScheduleController@logs
Gate Passes standalone-gate-passes.index GatePassController@index

Routes live in routes/web.php:5175–5279 (web) and routes/modules/api.php:493–506 + routes/api.php:661–765 (mobile). Interbranch is in routes/modules/logistics.php:181–184.


3. Processes

There are two loading-sheet dispatch flows in the code, selected by a global setting: - Sales-order flow (identify-sales-orders-from-normal-orders setting = 1): a strict 3-stage state machine (prepare → validate → load). - Legacy "normal" flow (setting off): a simpler path using just a dispatched boolean, or the two-step bay/validate flow.

3.1 Loading sheet dispatch — the 3-stage state machine (sales-order flow)

The core record is SalesmanShiftStoreDispatch (SSSD) with child SalesmanShiftStoreDispatchItem (SSSDI). Its status column drives everything. All state names, stage numbers, and access rules are defined in app/SalesmanShiftStoreDispatch.php (getCurrentStageNumber() :233, canUserAccessStage() :288).

stateDiagram-v2
    [*] --> pending: sheet created (from order/invoice)
    pending --> preparing: startPreparation (Stage 1)
    preparing --> prepared: completePreparation (all items picked)
    prepared --> validating: startValidation (Stage 2, must be a DIFFERENT user)
    validating --> validated: completeValidationStage (all counted, returns allocated)
    validated --> loading: startLoading (Stage 3)
    loading --> dispatched: completeLoading (vehicle assigned, goods on truck)
    dispatched --> [*]

    note right of preparing
      Stage 1: Preparation
      perm loading-sheet___preparation
      writes SSSDI.dispatched_quantity, is_dispatched
    end note
    note right of validating
      Stage 2: Validation
      perm loading-sheet___validation
      cannot be preparation_completed_by
      writes SSSDI.validated_quantity, variance_quantity, is_validated
    end note
    note right of loading
      Stage 3: Loading
      perm loading-sheet___loading
      assignVehicle -> DeliverySchedule.vehicle_id
    end note

Each transition is also mirrored onto the linked SalesOrderLoadingSheet rows (updateLinkedSalesOrderLoadingSheets(['status' => ...])) and, at completion, onto DeliverySchedule.status.

Stage-by-stage (all in app/Http/Controllers/StoreKeeper/ParkingListController.php):

  • Stage 1 – Preparation (pick from shelf to bay):
  • startPreparation :2212 — requires pending, perm loading-sheet___preparation; sets status='preparing', preparation_started_at/_by.
  • prepareItemWorkflow :2717 — per item: dispatched_quantity, is_dispatched=true.
  • completePreparation :2275 — requires all items prepared; sets status='prepared', preparation_completed_at/_by.
  • Stage 2 – Validation (independent recount):
  • startValidation :2341 — requires prepared, perm loading-sheet___validation; blocks if caller == preparation_completed_by (:2367); sets status='validating'.
  • validateItemWorkflow :2771 — per item: validated_quantity, variance_quantity = max(0, dispatched − validated), is_validated=true, returns_allocated = !hasVariance.
  • completeValidationStage :2409 — requires all validated; if SalesmanShiftStoreDispatch::requiresReturnsAllocation() (a hard-coded model toggle, currently true, :27) then all variances must have returns allocated; sets status='validated', validator_id, validated_at.
  • Stage 3 – Loading (onto vehicle):
  • startLoading :2486 — requires validated, perm loading-sheet___loading; sets status='loading'.
  • assignVehicle :2549 — writes DeliverySchedule.vehicle_id; updates linked SO sheets.
  • completeLoading :2598 — requires vehicle set; sets this sheet status='dispatched' + dispatched=true, bulk-updates sibling SSSD rows for the same delivery to dispatched (:2655), sets DeliverySchedule.status='consolidated' (:2698), and rolls the shift's deliveries consolidating → consolidated when nothing is left.

Audit & locking: every stage writes UserActivityLog::logCompletion(...) and toggles UserActivityStatus busy/idle so two users can't edit the same sheet at once (returns HTTP 423 if locked). Cross-branch merges gate each transition through CrossBranchLoadStopService::assertDispatchWorkAllowed().

3.2 Loading sheet dispatch — two-step web flow & legacy

An alternative simpler path (also ParkingListController, and the mobile equivalents) uses statuses pending → dispatched_to_bay → validated:

stateDiagram-v2
    [*] --> pending
    pending --> dispatched_to_bay: dispatchToBay / completeDispatchToBay
    dispatched_to_bay --> validated: processValidation / completeDispatch (dispatched=true)
    validated --> [*]
  • Web: dispatchToBayView :757, dispatchItem :817, completeDispatchToBay :881 (→ dispatched_to_bay); validateLoadingSheet :1000, validateItem :1397, processValidationWeb :1238 / completeDispatch :1465 (→ validated).
  • Mobile: POST store-loading-sheets/dispatch-to-bay → dispatchToBay; POST store-loading-sheets/validate → processValidation; single-step POST store-loading-sheets/dispatch → processDispatch (sets dispatched=true directly).
  • Returns: shortfalls found at validation are turned into WaInventoryLocationItemReturn rows with approval_status='pending_approval', is_auto_return=true (via createReturnsFromUserSelections(), ParkingListController.php:1327). These flow to the returns/approvals module and surface under Pending Returns Allocation.
  • Legacy "normal" flow: uses only the dispatched boolean on SSSD (no status enum). Listing filters on where('dispatched', false/true).

3.3 Delivery schedule lifecycle & gate pass

Once loading completes, the DeliverySchedule carries the trip. Its status progresses (string literals — no PHP constants; comment on delivery_schedules migration: "consolidating, consolidated, loaded, in_progress, finished"):

flowchart TD
    A["consolidating / consolidated<br/>(loading in store)"] --> B["loaded<br/>(all cross-branch stops done)"]
    B --> C["Gate pass initiated<br/>gate_pass_status = initiated"]
    C --> D["Gateman verifies driver + scans code<br/>gateman_verification_status: pending -> approved<br/>gate_pass_status: initiated -> verified"]
    D --> E["in_progress<br/>(truck on route, driver delivering)"]
    E --> F["finished<br/>(shift ended, report generated)"]
    E -.->|per customer fails| G["Delivery Failure logged<br/>status = pending"]
    A -.->|merge/split| A2["merged / reversed<br/>+ is_merge_result / is_split_result flags"]

Two parallel state columns ride alongside status: - gate_pass_status: pending → initiated → verified (default pending; migration 2024_04_18_114904). - gateman_verification_status: pending → approved | rejected (migration 2026_01_19_154148; also stores gateman_rejection_reason, gateman_verified_at, gateman_verified_by, driver_verification_image).

Gate pass issuance (web): - DeliveryScheduleController@createGatePass (:3680, primary path) sets gate_pass_status='initiated', gate_pass_initiated_at/_by, and when a valid date is given gateman_verification_status='pending'; it blocks issuance if the vehicle still has an uncleared finished report (sales-order flow). initiateGatePass (:3663) and downloadGatePass (:3647) set the issued_gate_pass/has_gatepass boolean flags. Clearing a stale report: clearDeliveryReport (:2827) sets report_cleared_at/_by (perm delivery-schedule___clear-delivery-report). - Standalone gate passes (not tied to a delivery) are created via GatePassController@store (:300) with status='initiated'.

Gate verification (mobile gateman):

sequenceDiagram
    participant G as Gateman (mobile)
    participant API as DeliveryScheduleController (API)
    participant DB as delivery_schedules / gate_passes
    G->>API: GET /gateManTrips (getPendingGatePassVerifications :4052)
    API-->>G: trips where gate_pass_status=initiated, gateman_verification_status in (pending,approved)
    G->>API: POST /gatemanVerification (approve/reject + driver photo) :4313
    API->>DB: gateman_verification_status = approved|rejected, driver_verification_image, gateman_verified_by/_at
    G->>API: POST /gatePassValidate (scan code) :4184
    API->>API: match code "{delivery_number}-{routes}" + time window 04:50-18:00
    API->>DB: gate_pass_status = verified, record shift-start mileage
    API-->>G: OK (+ SMS overstay warning to driver)

3.4 Delivery confirmation (mobile driver)

Out on the route, the driver confirms each customer via DeliveryScheduleController API methods:

sequenceDiagram
    participant D as Driver (mobile)
    participant API as DeliveryScheduleController
    participant Cust as Customer
    D->>API: POST /initiate-order-delivery (:3271)
    API->>API: geo-fence check (order_location_logs.driver_status = passed|failed)
    alt REQUEST_DELIVERY_OTP on
        API->>Cust: SMS 4-digit delivery_otp
        API-->>D: show_delivery_otp = true
        D->>API: POST /verify-delivery-otp (:3467)
        API->>API: OTP match?
        API->>API: delivery_code_status=approved, visited=true, order.status=Delivered, delivery_date=now
        API->>API: dispatch NotifySeviOrderDeliveredJob
    else OTP off
        API->>API: delivery_code_status = approved immediately (:3350)
    end
  • completeDelivery (:3221) finalizes with a payment reference: customer delivery_code_status='approved', orders status='COMPLETED'.
  • Customer-level display status: DeliveryScheduleCustomer::status() maps delivery_code_status=='approved' → "Delivered", else "Not Delivered" (app/DeliveryScheduleCustomer.php:74).
  • The schedule reaches finished via DeliveryScheduleFinishTracker::recordFinish() (app/Services/DeliveryScheduleFinishTracker.php:31) when the shift ends — this also writes a backend_delivery_actions audit row.

3.5 Delivery failures

When a customer can't be served, the driver files a failure (mobile) via DeliveryFailureController@reportDeliveryFailure (:235): creates a DeliveryFailure with status='pending', attaches field values + customers, and (if setting ALLOW_REPORT_DELIVERY_FAILURE_VIA_CRM) dispatches CreateCaseTicketJob. Back office reviews under Delivery Failures:

stateDiagram-v2
    [*] --> pending: driver reports (mobile)
    pending --> approved: approve() :116 (SMS to driver)
    pending --> rejected: reject() :130 (reason required, SMS to driver)
    approved --> [*]
    rejected --> [*]

3.6 Merging & splitting deliveries

  • Same-branch (DeliverySplittingAndMergingController): eligible schedules are those in consolidating/consolidated. mergeDeliveries (:338) creates a new schedule (is_merge_result=true) and sets each source status='merged' (:427). splitDelivery (:672) creates a child (is_split_result=true, split_source_delivery_schedule_id). Both record a DeliveryOperationReversal (OPERATION_MERGE/OPERATION_SPLIT) so they can be reversed (reverseMerge :832, reverseSplit :877, perm ...___reverse).
  • Cross-branch (CrossBranchDeliveryMergingController): merges schedules from ≥2 branches into a multi-stop delivery (is_cross_branch_merge=true); sources → status='merged'. The truck then works sequential load stops (DeliveryScheduleRouteStop, statuses pending → in_progress → completed, app/Models/DeliveryScheduleRouteStop.php:15); when all stops complete the schedule flips to status='loaded' (CrossBranchLoadStopService.php:369).

4. Tables touched & key data

Process Table (migration) Key columns / states
Loading sheet dispatch (3-stage & bay) salesman_shift_store_dispatches (2023_11_30_074725 + 2026_01_15_100000) status enum-ish (pending, preparing, prepared, validating, validated, loading, dispatched, also legacy dispatched_to_bay); dispatched bool; dispatch_time, dispatcher_id, validator_id, validated_at; stage timestamps preparation_/validation_/loading_started_at/_completed_at/_by; dispatched_to_bay_time/_by; delivery_schedule_id, shift_id, store_id, bin_location_id
Loading sheet items salesman_shift_store_dispatch_items dispatched_quantity, validated_quantity, variance_quantity, total_quantity, is_dispatched, is_validated, returns_allocated, wa_inventory_item_id, dispatch_id
Delivery schedule delivery_schedules (2023_11_22_170401 + many alters) status (consolidating, consolidated, loaded, in_progress, finished, reversed, merged); gate_pass_status (pending, initiated, verified); gateman_verification_status (pending, approved, rejected); gate_pass_valid_date, gate_pass_initiated_at/_by, gateman_verified_at/_by, gateman_rejection_reason, driver_verification_image; vehicle_id, driver_id, turnboy_id, operator_id; mileage fields; is_merge_result, merged_source_deliveries (json), is_split_result, split_source_delivery_schedule_id, result_delivery_schedule_id, is_cross_branch_merge; sales_order_loading_sheet_id(_ids); finished_by, report_cleared_at/_by, issued_gate_pass, has_gatepass
Delivery customers delivery_schedule_customers (2023_11_23_180335) customer_id, order_id (comma-sep requisition IDs), delivery_code, delivery_code_status (pending, sent, approved), visited, tonnage_kg, arrival_time, departure_time
Delivery items delivery_schedule_items wa_inventory_item_id, total_quantity, received_quantity, uom cols
Gate pass gate_passes (2026_01_23_090630 + alters) status (pending, initiated, verified, rejected, also cancelled in code); gate_pass_valid_date, time_window_start (05:00), time_window_end (18:00); vehicle_id, driver_id, route_id, delivery_schedule_id, inbound_delivery_id, issued_by, verified_by, verified_at, driver_image; soft deletes
Delivery failures delivery_failures (2025_06_19_114041 + alters) branch_id, driver_id, delivery_schedule_id, reason, status (pending, approved, rejected), rejection_reason, approved_by, approved_at; pivot customer_delivery_failure
Route stops (cross-branch) delivery_schedule_route_stops (2026_07_13_160100) status (pending, in_progress, completed), route_sequence, merged_delivery_schedule_id
Reversals delivery_operation_reversals (2026_07_30_120000) result_delivery_schedule_id, reversed_at, operation type
Analytics / logs delivery_center_logs, customer_offloading_time_logs, backend_delivery_actions, order_location_logs travel speed, offloading time, action audit, geo-fence result (driver_status)
Interbranch dispatch interbranch_loading_sheet_dispatches / _items (2025_08_10_145018) dispatch_status (pending, dispatched), dispatched_at, loaded_quantity, inbound_delivery_id
Legacy loading sheets / small packs loading_sheet_dispatches / _items (2023_10_24_105243); delivery_man_shifts (status open); parking_list_items, parking_list_item_dispatches delivery_status (not_started, in_progress, finished)

Note on model naming: ParkingListItem / ParkingListItemDispatch models exist but are imported-but-unused in ParkingListController; the real workhorse tables are salesman_shift_store_dispatches (+items). LoadingSheetDispatch/LoadingSheetDispatchItem back the small packs / legacy dispatch (SmallPacksContoller), not the current loading-sheet UI.


5. Interactions with other modules

Inbound (into this module): - Order Taking & Sales Invoicing — confirmed requisitions/invoices (wa_internal_requisitions) and their loading sheets (SalesOrderLoadingSheet) are the source that seeds SalesmanShiftStoreDispatch rows and delivery_schedule_customers.order_id. - Route Management — routes, route customers, and delivery centres define who is on the trip and where. - Fleet & Logistics — vehicles, drivers, turnboys, garage/idle status; assignVehicle writes DeliverySchedule.vehicle_id; createFuelLpo() (DeliverySchedule.php:428) creates a draft NewFuelEntry fuel LPO for the trip.

Outbound (out of this module): - Returns / Approvals — validation shortfalls create WaInventoryLocationItemReturn (pending_approval) → surfaced as Pending Returns Allocation. - Inventory — dispatch decrements stock at the store/bin; interbranch stock moves are created at sheet creation time. - Order status — delivery confirmation writes back wa_internal_requisitions.status = Delivered/COMPLETED and delivery_date, feeding sales/AR reporting. - SEVI (settlement) — OTP-verified delivery dispatches NotifySeviOrderDeliveredJob (DeliveryScheduleController ~:3561). - CRM — delivery failures can spawn a case ticket (CreateCaseTicketJob). - SMS — OTPs to customers, overstay warnings and failure approve/reject notices to drivers (SmsService). - Logistics & Inbound Deliveries — shares the GatePass model (inbound passes via inbound_delivery_id) and InterbranchLoadingSheet* (interbranch is inbound-adjacent; documented here only for the outbound gate).


6. Alternatives & variants

  • Sales-order flow vs. legacy normal flow — the single most important switch. Setting slug 'identify-sales-orders-from-normal-orders' == 1 turns on the 3-stage preparing/prepared/validating/validated/loading/dispatched state machine; off falls back to the dispatched boolean / two-step bay flow. Checked pervasively in ParkingListController and DeliveryScheduleController.
  • Returns-allocation gate — SalesmanShiftStoreDispatch::requiresReturnsAllocation() is a hard-coded PHP toggle (currently true, SalesmanShiftStoreDispatch.php:27) rather than a DB setting; when true, validation cannot complete with unallocated variances.
  • Delivery OTP — setting REQUEST_DELIVERY_OTP decides whether the driver must enter a customer OTP or can mark delivered immediately.
  • Geo-fence enforcement — setting DELIVERY_DISTANCE (with a 400 m grace) governs whether an out-of-range delivery is blocked (order_location_logs.driver_status = failed).
  • CRM failure ticketing — setting ALLOW_REPORT_DELIVERY_FAILURE_VIA_CRM gates automatic case-ticket creation on failure.
  • UOM-based inventory — AdministrationSetting INVENTORY_SETUP == 'UOM BASED' changes quantity breakdowns on interbranch/credit-sales dispatch and delivery sheets.
  • Turnboy read-only mobile — isTurnboyReadOnlyMobileAccessEnabled() blocks assigning such a turnboy as delivery operator.
  • Time window on gate pass — defaults time_window_start=05:00, time_window_end=18:00; validateGatePass enforces ~04:50–18:00.
  • Driver undispatched workflow — an alternative driver-driven prepare/verify/dispatch workflow exists (columns driver_workflow_status, driver_prep_*, driver_verification_* on SSSD; setting ENABLE_DRIVER_ACCESS_TO_UNDISPATCHED_ITEMS) but is currently disabled — routes and menu are commented out (sales_and_receivables.blade.php:1722, routes/web.php:5194), reverted to pre-KB-1434 behavior.
  • Standalone vs. delivery-linked gate passes — GatePassController manages standalone passes (editable/deletable) and read-only aggregates passes derived from delivery schedules and inbound deliveries; standalone Gate Passes menu is only shown when the sales-order setting is on.
  • POS cash-sale dispatch & Credit-sales dispatch — separate, lighter dispatch screens (pos-cash-sales.dispatch, CreditSalesController@dispatchScreen) for cash/credit sales rather than route loading sheets; credit-sales dispatch lists backend requisitions in COMPLETED/PAID status with undispatched items for the user's bin.
  • Small packs / legacy loading sheets — SmallPacksContoller (routes/modules/sales_and_receivables.php:250) uses the older loading_sheet_dispatches tables; not surfaced in the current Dispatch & Delivery menu.
  • Flavor/tenant differences — all behavioral differences above are driven by per-tenant Setting/AdministrationSetting rows and permission assignment; no hard-coded tenant branches were observed in the traced files.

7. Open questions to confirm (inferences flagged)

  1. [Inference] The dispatched_to_bay two-step web flow appears to be an earlier version of the 3-stage workflow (both live in ParkingListController). Confirm which flow is active per tenant, and whether both can be enabled simultaneously.
  2. [Inference] delivery_schedules.status values consolidating/consolidated/loaded/in_progress — the transition into in_progress (truck starts route) was not located in the four controllers traced (the finish→finished transition is confirmed in DeliveryScheduleFinishTracker). Confirm where in_progress is set (likely a driver-app "start delivery" endpoint such as ShiftController@endDelivery/start, or SalesAndDeliveryShiftController).
  3. [Inference] Small packs (SmallPacksContoller) and the legacy loading_sheet_dispatches tables: confirm whether any live tenant still uses them, or if they are fully superseded by salesman_shift_store_dispatches.
  4. [Inference] DeliveryManShift (status='open') and DeliveryManShiftCustomer are bare models queried from Controller.php:694; they look like an older driver-app shift concept parallel to DeliverySchedule. Confirm whether they are still written to or are dead schema.
  5. [Unconfirmed] Exact permission-slug seeding — slugs are inferred from @if isset($my_permissions['<slug>']) and can() usage in the sidebar/controllers; the authoritative permission list (seeder/table) was not located by grep. Confirm the canonical slug names and default role grants.
  6. [Inference] gate_pass_status on a delivery vs. the separate gate_passes row: initiateGatePass sets only boolean flags while createGatePass sets gate_pass_status='initiated'. Confirm which is the current UI entry point and whether initiateGatePass is legacy.
  7. [Unconfirmed] POS cash-sale dispatch (pos-cash-sales.dispatch) sits in this menu but is owned largely by the POS module; confirm the boundary — this chapter treats it as a light reference only.
  8. [Inference] The requiresReturnsAllocation() hard-coded toggle: confirm it is intended to stay code-level (not a per-tenant setting) given the "CHANGE THIS LINE" comment.

8. Source references

Nav / IA - resources/views/admin/includes/sidebar_includes/sales_and_receivables.blade.php:1690 (Dispatch & Delivery menu block)

Routes - routes/web.php:5175–5279 (loading sheets, delivery schedules, merging/splitting, gate pass, failures) - routes/modules/api.php:493–506 (mobile store-loading-sheets + delivery-schedules) - routes/api.php:661–765 (mobile delivery confirmation, OTP, gateman gate-pass endpoints) - routes/modules/logistics.php:181–184 (interbranch loading sheets) - routes/creditSales.php:85 (credit-sales dispatch) - routes/modules/sales_and_receivables.php:250 (small packs — legacy)

Controllers - app/Http/Controllers/StoreKeeper/ParkingListController.php (loading-sheet dispatch, 3-stage workflow, bay/validate, returns) - app/Http/Controllers/Admin/DeliveryScheduleController.php (schedules, gate pass issue/verify, driver delivery API, reports) - app/Http/Controllers/Admin/GatePassController.php (standalone gate passes) - app/Http/Controllers/Admin/DeliveryFailureController.php (failure review + mobile reporting) - app/Http/Controllers/Admin/DeliverySplittingAndMergingController.php (same-branch merge/split) - app/Http/Controllers/Admin/CrossBranchDeliveryMergingController.php (cross-branch merge + load stops) - app/Http/Controllers/Admin/InterbranchLoadingSheetController.php (interbranch dispatch) - app/Http/Controllers/Admin/CreditSales/CreditSalesController.php:36 (dispatchScreen) - app/Http/Controllers/Api/DeliveryController.php (legacy deliver/return endpoints)

Models - app/SalesmanShiftStoreDispatch.php (state machine, stage access rules — :233, :288), app/SalesmanShiftStoreDispatchItem.php - app/DeliverySchedule.php (statuses, scopes, merge/split, tonnage, fuel LPO, center logging) - app/DeliveryScheduleCustomer.php (delivery status accessor :74, tonnage), app/DeliveryScheduleItem.php - app/GatePass.php, app/Models/DeliveryFailure.php, app/Models/DeliveryScheduleRouteStop.php (:15), app/Models/DeliveryOperationReversal.php - app/DeliveryManShift.php, app/DeliveryManShiftCustomer.php (legacy driver-shift) - app/LoadingSheetDispatch.php, app/LoadingSheetDispatchItem.php, app/ParkingListItem.php, app/ParkingListItemDispatch.php (legacy / unused-in-current-flow)

Services - app/Services/DeliveryScheduleFinishTracker.php:31 (recordFinish → finished) - CrossBranchLoadStopService.php:369 (all stops done → loaded), CrossBranchDeliveryMergeService.php:121

Key migrations - 2023_11_30_074725_create_salesman_shift_store_dispatches_table.php, 2026_01_15_100000_add_status_to_salesman_shift_store_dispatches.php - 2023_11_22_170401_create_delivery_schedules_table.php, 2024_04_18_114904_add_gate_pass_status_to_delivery_schedules.php, 2026_01_19_154148_add_gateman_verification_to_delivery_schedules_table.php - 2026_01_23_090630_create_gate_passes_table.php, 2026_01_23_121353_add_time_window_to_gate_passes_table.php - 2025_06_19_114041_create_delivery_failures_table.php, 2026_07_13_160100_create_delivery_schedule_route_stops_table.php

Mobile app (bizwizorderanddelivery, Flutter) - lib/app/app.router.dart (role home views: gateman, delivery man, POS dispatcher) - lib/utils/constants/api_endpoints.dart:108,109,182,183,184 (delivery/gateman endpoint constants) - lib/ui/views/gateman/, lib/ui/views/delivery/, lib/ui/views/pos/pos_dispatcher_home, lib/services/gate_man_verification_service.dart:43