# 05 — Delivery Ride Execution **Status**: Done **Depends On**: 04 — Loading Event --- ## Goal Fulfill pending orders against an active Delivery ride. The driver visits each store on the route, delivers the ordered items, gets customer confirmation, and the system creates the stock movement, updates the order, and completes the sale. --- ## Background / Context - A Delivery ride goes `Active` after the loading event is confirmed. - Orders are linked to a ride implicitly through route: `Ride → Route → Stores → Pending Orders`. - `QuantityFulfilled` on `OrderItem` tracks what was actually delivered (added in pre-planning). - No separate backorder entity — partially fulfilled orders stay `PartiallyFulfilled` and get picked up by the next delivery ride on the same route. - Customer confirmation in v1 is a boolean flag (`CustomerConfirmed`). Full signature/OTP deferred to Step 09 (Fraud Controls). --- ## Data Model Changes ### New Entity — DeliveryTask Extends `Template` (adds `IsActive`, `CreatedAt` — consistent with all other entities). | Column | Type | Notes | |---|---|---| | Id | Guid | PK (from Template) | | FK_RideId | Guid | FK → DeliveryRun | | FK_OrderId | Guid | FK → Order | | Sequence | int | Visit order on the route | | Status | DeliveryTaskStatus | State machine below | | CustomerConfirmed | bool | Set to true at confirm time | | ConfirmedAt | DateTime? | Timestamp of customer confirmation | | Note | string? | Driver note on failure or partial delivery | | IsActive | bool | From Template (soft delete) | | CreatedAt | DateTime | From Template | ### New Enum — DeliveryTaskStatus ```csharp public enum DeliveryTaskStatus { Pending, Delivered, PartiallyDelivered, Failed } ``` ### No new columns on OrderItem `QuantityFulfilled` already added in pre-planning. No further model changes needed. --- ## State Machine ``` Pending → Delivered (all lines fully delivered + customer confirmed) Pending → PartiallyDelivered (some lines short + customer confirmed) Pending → Failed (driver could not deliver, no stock movement) ``` --- ## Stock Movements Created on `Delivered` or `PartiallyDelivered` after customer confirmation. One movement per item: - **Debit** vehicle: `-QuantityFulfilled` at `LocationType.Vehicle`, `FK_LocationId = VehicleId` - `VehicleId` is resolved from `DeliveryTask.FK_RideId → DeliveryRun.FK_VehicleId` - `MovementType.Sale` - `ReferenceId = OrderId` No movement on `Failed`. --- ## Order and Sale Status Transitions (triggered internally) | Condition | Order | Sale | |---|---|---| | All OrderItem lines: QuantityFulfilled == Quantity | → Fulfilled | → Completed | | Any OrderItem line: QuantityFulfilled < Quantity | → PartiallyFulfilled | stays Pending | | Task Failed | stays Pending | stays Pending | --- ## API Endpoints Base routes: `/api/rides/{rideId}/tasks` and `/api/delivery-tasks` | Method | Route | Who | Description | |---|---|---|---| | POST | `/api/rides/{rideId}/tasks/generate` | Driver/System | Auto-create tasks from all Pending/PartiallyFulfilled orders for stores on ride's route | | GET | `/api/rides/{rideId}/tasks` | Driver | List all tasks for this ride with current status | | GET | `/api/delivery-tasks/{id}` | Driver | Task detail with order items and quantities | | PUT | `/api/delivery-tasks/{id}/quantities` | Driver | Set QuantityFulfilled per order item before confirming | | POST | `/api/delivery-tasks/{id}/confirm` | Driver | Customer confirmed — creates stock movements, transitions order/sale | | POST | `/api/delivery-tasks/{id}/fail` | Driver | Mark task as failed with a note | --- ## Business Rules 1. Delivery tasks can only be created for a ride in `Active` status and of type `Delivery`. 2. One task per order per ride — cannot create a second task for the same order on the same ride. 3. `QuantityFulfilled` must be set on all order items before calling confirm. 4. `QuantityFulfilled` cannot exceed `Quantity` on any line. 5. `CustomerConfirmed` must be true before the task can move to `Delivered` or `PartiallyDelivered`. 6. Stock movement is created only once — at confirm. Never on fail. 7. A failed task does not change the order or sale status — the order stays available for the next ride. 8. Partial delivery: the unfulfilled quantity (`Quantity - QuantityFulfilled`) remains on the same order. The next delivery ride on the same route will pick it up automatically via `generate`. --- ## Implementation Build Order 1. Enum — add `DeliveryTaskStatus` to `Models/Enums.cs` 2. Entity — `DeliveryTask` in `Models/` 3. `AppDBContext` — new DbSet + Fluent config (Restrict on Ride, Order FKs) 4. Migration 5. DTOs — `DeliveryTaskDTOs.cs` in `Features/DeliveryRide/` 6. Repository — `IDeliveryTaskRepository`, `DeliveryTaskRepository` 7. Service — `DeliveryTaskService` 8. Controller — `DeliveryTaskController` 9. DI registration in `Program.cs` **Feature folder:** `Features/DeliveryRide/` --- ## Open Questions — Resolved - ✅ Customer confirmation — boolean flag in v1, full signature/OTP in Step 09 - ✅ Backorder — no separate entity; same order stays PartiallyFulfilled for next ride - ✅ Task generation — on-demand via `generate` endpoint, not automatic on ride activation - ✅ Failed task — order stays Pending, available for next ride, no stock movement