Files
ERP_Distribution/Distribution/docs/04_loading_event.md
T
2026-08-25 15:38:22 +05:30

6.2 KiB

04 - Loading Event

Status: Done Depends On: 03 - Ride Lifecycle


Goal

Move stock from a source warehouse onto an opened ride's vehicle, with two-party confirmation. When loading is confirmed, the vehicle's stock ledger is credited and the ride transitions Open -> Active automatically.

This loading flow serves both ride types:

  • Delivery rides load stock to fulfill orders already linked to the ride.
  • Sale rides load stock so the sales agent can sell in the field and create sale-linked orders.

Background / Context

A vehicle is just a location with LocationType.Vehicle in the stock ledger - the same math as a warehouse. When loading is confirmed, two stock movements are created per item:

  • Debit source warehouse: -qty at LocationType.Warehouse
  • Credit vehicle: +qty at LocationType.Vehicle

From this point the vehicle carries live inventory that decreases with every sale or delivery and must return to zero before the ride can close.


Data Model Changes

New Entity - LoadingSheet

Column Type Notes
Id Guid PK
FK_RideId Guid FK -> DeliveryRun
FK_SourceWarehouseId Guid FK -> Warehouse
Status LoadingSheetStatus State machine below
DispatchConfirmedAt DateTime? Set when warehouse confirms dispatch
DispatchConfirmedBy Guid? UserId of warehouse manager
ReceiptConfirmedAt DateTime? Set when driver confirms receipt
ReceiptConfirmedBy Guid? UserId of driver
CreatedAt DateTime

New Entity - LoadingSheetItem

Column Type Notes
Id Guid PK
FK_LoadingSheetId Guid FK -> LoadingSheet
FK_ItemId Guid FK -> Item
QuantityDispatched decimal Set by warehouse manager at confirm-dispatch
QuantityReceived decimal? Set by driver before confirm-receipt
QuantityResolved decimal? Set by supervisor when resolving a discrepancy

New Enum - LoadingSheetStatus

public enum LoadingSheetStatus
{
    Pending,
    DispatchConfirmed,
    ReceiptConfirmed,
    DiscrepancyFlagged,
    Resolved
}

No changes to existing entities. Vehicle capacity check is deferred to Step 13.


State Machine

Pending -> DispatchConfirmed -> ReceiptConfirmed
                           \-> DiscrepancyFlagged -> Resolved
Transition Trigger What it does
Pending -> DispatchConfirmed POST /{id}/confirm-dispatch Warehouse manager locks in QuantityDispatched per line. Ride stays Open.
DispatchConfirmed -> ReceiptConfirmed POST /{id}/confirm-receipt Driver's received quantities all match dispatched. Creates stock movements. Auto-triggers ride Open -> Active.
DispatchConfirmed -> DiscrepancyFlagged POST /{id}/confirm-receipt Any line mismatch. No stock movements created. Ride stays Open.
DiscrepancyFlagged -> Resolved POST /{id}/resolve Supervisor enters QuantityResolved per line. Creates stock movements using resolved quantities. Auto-triggers ride Open -> Active.

Item Population by Ride Type

Ride Type How items are added to the sheet
Delivery Auto-populated on sheet creation from the aggregate of all order lines assigned to the ride's route
Sale Manually entered by warehouse manager via PUT /{id}/items based on expected field selling demand

For Delivery rides the warehouse manager reviews the pre-populated quantities and may adjust before confirming dispatch. PUT /{id}/items is still available to override if needed.


Stock Movements

Created at ReceiptConfirmed or Resolved. One pair per line item:

  • Debit warehouse: -QuantityFinal at LocationType.Warehouse, FK_LocationId = SourceWarehouseId
  • Credit vehicle: +QuantityFinal at LocationType.Vehicle, FK_LocationId = VehicleId

QuantityFinal = QuantityReceived on a clean confirmation, or QuantityResolved when a discrepancy was resolved.

Movement Type = Load.


API Endpoints

Base route: /api/loading-sheets

Method Route Who Description
POST / Warehouse mgr Create sheet for an Open ride. Delivery rides auto-populate items from orders.
GET / Any List sheets. Filter by rideId, status. Paginated.
GET /{id} Any Get sheet detail with all line items
PUT /{id}/items Warehouse mgr Set or override item quantities
POST /{id}/confirm-dispatch Warehouse mgr Pending -> DispatchConfirmed
PUT /{id}/receipt-items Driver Set QuantityReceived per line
POST /{id}/confirm-receipt Driver -> ReceiptConfirmed or DiscrepancyFlagged
POST /{id}/resolve Supervisor Enter QuantityResolved per line -> Resolved plus ride activation

Business Rules

  1. A loading sheet can only be created for a ride in Open status.
  2. A ride can only have one active loading sheet at a time.
  3. QuantityDispatched != QuantityReceived on any line -> DiscrepancyFlagged. No partial activation.
  4. Stock movements are created only once - at ReceiptConfirmed or Resolved. Never on dispatch.
  5. Discrepancies must be resolved per line item with an explicit QuantityResolved value.
  6. All list endpoints return paginated responses.
  7. Vehicle capacity check is not enforced in this step.
  8. Immediate handover from a Sale ride does not remove the need for an Order; every sale still creates an order, and that order is fulfilled immediately when stock is handed over at sale time.

Permissions to Seed

Code Who
loading.view All roles
loading.dispatch Warehouse manager and above
loading.receive Driver
loading.resolve Supervisor and above

Fraud / Control Considerations

  • Discrepancies are immediately visible and block activation.
  • QuantityResolved is permanently stored per line for audit purposes.

Open Questions

  1. Vehicle capacity check - deferred to Step 13.
  2. Discrepancy resolution - supervisor enters QuantityResolved per line item.
  3. Ride activation trigger - confirm-receipt and resolve auto-trigger Open -> Active.
  4. Delivery item population - from assigned orders on the ride's route.

Implementation Notes

Build after the ride model and before full delivery/sale execution.