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.
9.9 KiB
03 - Ride Lifecycle
Status: Done Depends On: 02 - Stock Ledger
Goal
Turn the currently-unused DeliveryRun model into a fully working ride - a session that turns a
vehicle into a temporary warehouse. Covers driver profile management, ride creation, state
transitions, cancellation workflow, and the vehicle breakdown scenario.
Current Business Understanding
- A
Rideis one operational trip for one vehicle and one driver on one route for now. RideTypedistinguishes business behavior:Deliveryride: used to fulfill existing orders.Saleride: used by sales agents in the field to create sales, and every sale creates an order.
SaleandOrderare different:Saleis the commercial transaction created by the sales agent.Orderis the fulfillment document created from every sale.- Item lines are maintained once in
OrderItem;Saledoes not keep a separate item-line table.
Salestatuses use sales language such asCompleted.Orderstatuses use logistics language such asFulfilled.
Data Model Changes
New Entity - DriverProfile
Linked one-to-one with User. Holds compliance data only - no login or auth fields.
| Column | Type | Notes |
|---|---|---|
| Id | Guid | PK |
| FK_UserId | Guid | FK -> User (unique) |
| LicenseNumber | string | |
| LicenseExpiry | DateTime | |
| MedicalClearanceExpiry | DateTime | |
| IsActive | bool | Can be suspended without deleting |
| CreatedAt | DateTime |
No license class tied to vehicle type - not required.
Compliance check rule: Driver is compliant if IsActive = true, plus any checks that are
enabled in DriverComplianceConfig. By default all checks are disabled. When enabled:
LicenseExpiry > today and/or MedicalClearanceExpiry > today.
Updated Entity - Vehicle
Add one nullable field:
| Column | Type | Notes |
|---|---|---|
| FK_DefaultWarehouseId | Guid? | If set, ride always loads from this warehouse. If null, warehouse is selected at ride creation. |
Updated Entity - DeliveryRun (becomes Ride)
Add the following fields to the existing DeliveryRun:
| Column | Type | Notes |
|---|---|---|
| RideType | RideType | Delivery or Sale |
| Status | RideStatus | State machine below |
| FK_DriverProfileId | Guid | FK -> DriverProfile |
| FK_SourceWarehouseId | Guid | Where stock is loaded from. Must be the same warehouse stock returns to on cancel/close. |
| StartedAt | DateTime? | Set when Draft -> Open |
| ActivatedAt | DateTime? | Set when Open -> Active |
| ClosedAt | DateTime? | Set when Active -> Closed |
New Enum - RideType
public enum RideType { Delivery, Sale }
New Enum - RideStatus
public enum RideStatus { Draft, Open, Active, CancelRequested, Cancelled, Closed }
Meaning of statuses:
Draft: ride exists but operational work has not started.Open: ride is prepared and ready for loading/preparation work.Active: ride is live in the field.CancelRequested: active ride is waiting for cancellation approval or rejection.Cancelled: ride ended through approved cancellation.Closed: ride ended normally.
New Entity - RideCancelRequest
| Column | Type | Notes |
|---|---|---|
| Id | Guid | PK |
| FK_RideId | Guid | FK -> DeliveryRun |
| TypeCode | CancelRequestType | Reason category |
| Reason | string | Free text explanation |
| RequestedBy | Guid | UserId |
| RequestedAt | DateTime | |
| Status | CancelRequestStatus | Pending, Approved, Rejected |
| ApprovedBy | Guid? | UserId of approver |
| ApprovedAt | DateTime? |
New Enum - CancelRequestType
public enum CancelRequestType
{
VehicleBreakdown,
DriverUnavailable,
RouteIssue,
Other
}
New Entity - DriverComplianceConfig
Single-row configuration table. Controls which compliance checks are enforced at ride open time.
| Column | Type | Notes |
|---|---|---|
| Id | Guid | PK |
| EnforceLicenseExpiry | bool | Default false. If true, ride open is blocked if driver license is expired. |
| EnforceMedicalClearance | bool | Default false. If true, ride open is blocked if medical clearance is expired. |
| UpdatedAt | DateTime | |
| UpdatedBy | Guid | UserId of last person who changed the config. |
Managed via a dedicated config endpoint. Only one row ever exists.
New Enum - CancelRequestStatus
public enum CancelRequestStatus { Pending, Approved, Rejected }
State Machine
Draft -> Open -> Active -> Closed
\-> CancelRequested -> Cancelled
| Transition | Trigger | What it does |
|---|---|---|
| Draft -> Open | POST /api/rides/{id}/open |
Validates driver compliance. Checks vehicle has no other Open/Active ride. Sets StartedAt. |
| Open -> Active | POST /api/rides/{id}/activate |
Called by loading event confirmation (Step 04). Sets ActivatedAt. |
| Active -> Closed | POST /api/rides/{id}/close |
Called after ride reconciliation (Step 07). All stock must be returned to source warehouse. Sets ClosedAt. |
| Active -> CancelRequested | POST /api/rides/{id}/cancel-request |
Driver submits cancel request with type code and reason. Ride status changes to CancelRequested. |
| CancelRequested -> Cancelled | POST /api/rides/cancel-requests/{id}/approve |
Supervisor approves. Ride status changes to Cancelled. All stock must return to source warehouse before cancel completes. |
| CancelRequested -> Active | POST /api/rides/cancel-requests/{id}/reject |
Supervisor rejects. Ride returns to Active. |
Order assignment window: Orders can be assigned to a Delivery ride from Draft until the ride transitions to Open. No new orders after Open.
Warehouse Configuration
Per vehicle. A vehicle either has FK_DefaultWarehouseId set (always loads from that warehouse)
or it is null (warehouse is selected manually at ride creation time).
Loading and unloading warehouse are always the same - stock must return to its source warehouse before a ride can close or cancel.
Vehicle Breakdown Scenario
- Driver submits cancel request with
TypeCode = VehicleBreakdown. - Ride status moves to
CancelRequested. - Supervisor views a breakdown assist endpoint that lists all currently
Activerides with their current vehicle stock levels and the stranded ride's open orders. Supervisor decides manually which ride takes over which orders. - Supervisor approves the cancel request.
- Ride moves to
Cancelledonce all stock is confirmed returned to source warehouse.
The system surfaces the information - it does not automatically reassign orders.
API Endpoints
Base route: /api/rides
| Method | Route | Description |
|---|---|---|
| POST | / |
Create ride (Draft). If vehicle has default warehouse, pre-populate it. |
| GET | / |
List rides (paginated). Filter by status, type, driverProfileId, vehicleId. |
| GET | /{id} |
Get ride detail |
| PUT | /{id}/driver |
Assign or change driver profile |
| POST | /{id}/open |
Transition Draft -> Open |
| POST | /{id}/activate |
Transition Open -> Active (called by loading event) |
| POST | /{id}/close |
Transition Active -> Closed (called by reconciliation) |
| POST | /{id}/cancel-request |
Submit cancel request (Active rides only) |
| GET | /cancel-requests |
List cancel requests (paginated). Filter by status. |
| POST | /cancel-requests/{id}/approve |
Approve cancel request |
| POST | /cancel-requests/{id}/reject |
Reject cancel request |
| GET | /breakdown-assist/{rideId} |
Lists active rides with stock plus stranded ride's open orders |
DriverComplianceConfig
Base route: /api/driver-compliance-config
| Method | Route | Description |
|---|---|---|
| GET | / |
Get current config |
| PUT | / |
Update config flags |
DriverProfile
Base route: /api/driver-profiles
| Method | Route | Description |
|---|---|---|
| POST | / |
Create driver profile (links to a User) |
| GET | / |
List driver profiles (paginated) |
| GET | /{id} |
Get driver profile detail |
| PUT | /{id} |
Update compliance fields |
| DELETE | /{id} |
Soft deactivate |
Business Rules
- A ride cannot transition Draft -> Open if
IsActive = falseon the driver profile. IfEnforceLicenseExpiry = true, also block if license is expired. IfEnforceMedicalClearance = true, also block if medical clearance is expired. - A vehicle cannot be on more than one Open or Active ride at a time.
- Orders can only be assigned to a Delivery ride while it is in Draft status.
- Loading and unloading warehouse must be the same - enforced at close/cancel.
- A CancelRequested ride cannot close or activate until the request is resolved.
- All cancel requests must have a TypeCode - free text reason alone is not sufficient.
- All list endpoints return paginated responses.
- A ride uses a single route for now.
Open Questions
- Cancel request type codes - resolved.
VehicleBreakdown,DriverUnavailable,RouteIssue,Other. - Breakdown assist endpoint - resolved. System shows info only, supervisor decides manually. No auto-reassignment.
- Driver compliance - resolved. Checks are configurable via
DriverComplianceConfig.IsActiveis always enforced. License and medical checks are optional flags, default off. - Multi-route ride assignment - deferred for now. Current model stays single-route.
Implementation Notes
Build order:
- Enums -
RideType,RideStatus,CancelRequestType,CancelRequestStatus - Entities -
DriverProfile,DriverComplianceConfig,RideCancelRequest AppDBContext- new DbSets plus Fluent config- Migrations - ride lifecycle schema and permissions
- DTOs - driver profile, compliance config, ride
- Repositories - ride and ride cancel request support
- Services - driver profile, compliance config, ride
- Controllers - driver profile, compliance config, ride
- DI registration in
Program.cs
Feature folders: Features/Ride/, Features/DriverProfile/, Features/DriverComplianceConfig/