Implemented DeliveryTask, Payment, and Sale entities with full CRUD, business logic, and API endpoints. Updated Order/OrderItem for sale linkage and fulfillment tracking. Registered new DbSets and DI services. Revised documentation for delivery, sale, and payment workflows.
6.2 KiB
04 - Loading Event
Status: Planning 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:
Deliveryrides load stock to fulfill orders already linked to the ride.Salerides 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:
-qtyatLocationType.Warehouse - Credit vehicle:
+qtyatLocationType.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:
-QuantityFinalatLocationType.Warehouse,FK_LocationId = SourceWarehouseId - Credit vehicle:
+QuantityFinalatLocationType.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
- A loading sheet can only be created for a ride in
Openstatus. - A ride can only have one active loading sheet at a time.
QuantityDispatched != QuantityReceivedon any line ->DiscrepancyFlagged. No partial activation.- Stock movements are created only once - at
ReceiptConfirmedorResolved. Never on dispatch. - Discrepancies must be resolved per line item with an explicit
QuantityResolvedvalue. - All list endpoints return paginated responses.
- Vehicle capacity check is not enforced in this step.
- 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.
QuantityResolvedis permanently stored per line for audit purposes.
Open Questions
- Vehicle capacity check - deferred to Step 13.
- Discrepancy resolution - supervisor enters
QuantityResolvedper line item. - Ride activation trigger -
confirm-receiptandresolveauto-triggerOpen -> Active. - Delivery item population - from assigned orders on the ride's route.
Implementation Notes
Build after the ride model and before full delivery/sale execution.