Merge branch 'dev' into production
This commit is contained in:
@@ -45,6 +45,8 @@ quantities.
|
||||
a fresh set. `IsActive = true` = latest version; `IsActive = false` = history.
|
||||
- Editing allowed only while Shop PO (before confirmation).
|
||||
- No Invoice exists yet at this stage.
|
||||
- A Shop PO can be cancelled (`Order.Status → Cancelled`). No Invoice exists at this point so no
|
||||
cascade required.
|
||||
|
||||
**API:**
|
||||
| Method | Route | Description |
|
||||
@@ -52,6 +54,7 @@ quantities.
|
||||
| POST | `/api/orders` | Create Shop PO for a store. |
|
||||
| PUT | `/api/orders/{id}/items` | Rewrite line items (versioned). |
|
||||
| GET | `/api/orders/{id}` | Get PO with current active items. |
|
||||
| POST | `/api/orders/{id}/cancel` | Cancel a Shop PO. |
|
||||
|
||||
---
|
||||
|
||||
@@ -76,6 +79,9 @@ mode — controlled by the system-level `InvoiceCreationMode` config flag.
|
||||
- Confirmation requires no signature or OTP.
|
||||
- `OrderItem` lines are permanently locked after confirmation.
|
||||
- `Order.Status` (fulfillment tracking) is untouched — separate axis.
|
||||
- A Confirmed PO can be cancelled even after confirmation (`Order.Status → Cancelled`). If an
|
||||
Invoice was already created, cascade behaviour (void Invoice, impact on loading sheet items) is
|
||||
unresolved — see Open Questions.
|
||||
|
||||
---
|
||||
|
||||
@@ -150,8 +156,13 @@ enters any edits the agent made into the system and submits.
|
||||
|
||||
1. **Who can confirm a Shop PO?** — the creating sales agent, a supervisor, or either?
|
||||
2. **Can a Confirmed PO be reverted to Shop PO?** — no un-confirm path designed here.
|
||||
3. **Cancellation path for a Shop PO or Confirmed PO?** — not addressed here.
|
||||
4. **Exact adjustment payload for `POST /complete`** — the fields the office worker can edit
|
||||
(returns, damage, discounts) are assumed but not fully specified.
|
||||
5. **Does Stage 4 (loading sheet) depend on Stage 3 (invoice printed), or can they happen in
|
||||
parallel?** — not decided here.
|
||||
3. **Cancellation cascade** — both Shop PO and Confirmed PO can be cancelled. If cancelling a
|
||||
Confirmed PO that already has a linked Invoice: should the Invoice be voided automatically?
|
||||
If the PO's items were already pulled into a loading sheet: what happens to those loading sheet
|
||||
items? Cascade rules needed before implementation.
|
||||
4. **Exact adjustment payload for `POST /api/invoices/{id}/finalize`** — the fields the office
|
||||
worker can edit (returns, damage, discounts) are assumed but not fully specified. "Free issues"
|
||||
handling (items given to the shop at no charge) is a known case needing its own payload field(s).
|
||||
5. **Stage 3 and Stage 4 ordering** — Invoice printing (Stage 3) and loading sheet population
|
||||
(Stage 4) are independent flows. They are not strictly sequential — both depend on a Confirmed
|
||||
PO existing but neither requires the other to complete first.
|
||||
|
||||
@@ -13,7 +13,7 @@ Replace the previous loading event design with a dispatcher-driven, multi-PO mod
|
||||
1. **No more auto-creation.** Loading sheets are no longer generated automatically when a PO is
|
||||
confirmed. A dispatcher manually triggers population.
|
||||
2. **No more `Open → Active`.** `Ride.Status` collapses to `Open`/`Cancelled`/`Closed` — no
|
||||
`Active` stage. Loading sheet confirmation no longer changes `Ride.Status` at all.
|
||||
`Active` stage. Loading sheet confirmation no longer changes `Ride.Status`.
|
||||
3. **One sheet aggregates multiple POs.** A single loading sheet is created from all Confirmed POs
|
||||
matching a dispatcher's filter (route/agent/shop). No longer one sheet per PO.
|
||||
4. **Ride set at populate time.** The ride is provided when the dispatcher triggers population —
|
||||
@@ -22,15 +22,17 @@ Replace the previous loading event design with a dispatcher-driven, multi-PO mod
|
||||
loaded from different warehouses. Stock movements are generated per item's warehouse.
|
||||
6. **Item versioning.** Loading sheet items are versioned the same way as Shop PO items — every
|
||||
edit soft-deletes current rows (`IsActive = false`) and writes a fresh set.
|
||||
7. **Stock moves at confirmation.** When the dispatcher confirms the sheet, stock moves from each
|
||||
item's warehouse to the vehicle. No driver receipt confirmation step.
|
||||
|
||||
---
|
||||
|
||||
## Background / Context
|
||||
|
||||
Same physical mechanics as `04_loading_event.md`: a vehicle is a location with
|
||||
`LocationType.Vehicle` in the stock ledger. Confirming receipt (or resolving a discrepancy)
|
||||
creates stock movements — debit source warehouse(s), credit vehicle. What changes is *when and how
|
||||
a `LoadingSheet` comes into existence*, *which POs it covers*, and *how warehouse selection works*.
|
||||
`LocationType.Vehicle` in the stock ledger. Confirming the loading sheet creates stock movements —
|
||||
debit source warehouse(s), credit vehicle. What changes is *when and how a `LoadingSheet` comes
|
||||
into existence*, *which POs it covers*, and *how warehouse selection works*.
|
||||
|
||||
---
|
||||
|
||||
@@ -43,18 +45,12 @@ a `LoadingSheet` comes into existence*, *which POs it covers*, and *how warehous
|
||||
| Id | Guid | PK |
|
||||
| ~~`FK_OrderId`~~ | — | **Removed.** One sheet now aggregates multiple POs — replaced by `LoadingSheetOrder` linking table. |
|
||||
| **`FK_RideId`** | Guid | **Required. Set at population time** — dispatcher provides the ride when triggering populate. |
|
||||
| ~~`FK_SourceWarehouseId`~~ | — | **Removed.** Warehouse is tracked per item, not per sheet — a single sheet can be fulfilled from multiple warehouses. |
|
||||
| Status | LoadingSheetStatus | See state machine below. |
|
||||
| ~~`FK_SourceWarehouseId`~~ | — | **Removed.** Warehouse is tracked per item, not per sheet. |
|
||||
| Status | LoadingSheetStatus | `Planned` or `Confirmed`. |
|
||||
| **`PopulatedBy`** | Guid | **New.** UserId of dispatcher who triggered population. |
|
||||
| **`PopulatedAt`** | DateTime | **New.** When population was triggered. |
|
||||
| ~~`AssignedAt`~~ | — | **Removed.** No separate assign step. |
|
||||
| ~~`AssignedBy`~~ | — | **Removed.** Same reason. |
|
||||
| ConfirmedAt | DateTime? | Set when loading sheet is confirmed (items locked). |
|
||||
| ConfirmedBy | Guid? | UserId of whoever confirmed the sheet. |
|
||||
| DispatchConfirmedAt | DateTime? | Path B only — see Open Questions. |
|
||||
| DispatchConfirmedBy | Guid? | Path B only. |
|
||||
| ReceiptConfirmedAt | DateTime? | Path B only. |
|
||||
| ReceiptConfirmedBy | Guid? | Path B only. |
|
||||
| ConfirmedAt | DateTime? | Set when loading sheet is confirmed (items locked, stock moves). |
|
||||
| ConfirmedBy | Guid? | UserId of whoever confirmed the sheet. TBD — see Open Questions. |
|
||||
| CreatedAt | DateTime | From Template. |
|
||||
|
||||
### New Entity — `LoadingSheetOrder` (linking table)
|
||||
@@ -76,8 +72,6 @@ One loading sheet aggregates multiple Confirmed POs. This table records which PO
|
||||
| **`FK_OrderItemId`** | Guid? | **New.** Traces back to the source `OrderItem` from the Confirmed PO. Null for manually added lines. |
|
||||
| FK_ItemId | Guid | FK → Item (product) |
|
||||
| QuantityDispatched | decimal | Quantity to load from `FK_WarehouseId` |
|
||||
| QuantityReceived | decimal? | Driver's received qty (Path B only) |
|
||||
| QuantityResolved | decimal? | Supervisor's resolved qty after discrepancy (Path B only) |
|
||||
| **`IsActive`** | bool | **Versioning.** Every edit soft-deletes current items (`IsActive = false`) and writes a fresh set. Active items = latest version; soft-deleted = history. |
|
||||
| CreatedAt | DateTime | From Template |
|
||||
|
||||
@@ -86,36 +80,30 @@ One loading sheet aggregates multiple Confirmed POs. This table records which PO
|
||||
```csharp
|
||||
public enum LoadingSheetStatus
|
||||
{
|
||||
Planned, // populated by dispatcher (ride set, items editable/versioned)
|
||||
Confirmed, // items locked — stock movement path TBD (see Open Questions)
|
||||
DispatchConfirmed, // Path B only: warehouse confirms dispatch
|
||||
ReceiptConfirmed, // Path B only: driver confirms receipt, stock moves
|
||||
DiscrepancyFlagged, // Path B only: received qty mismatch
|
||||
Resolved // Path B only: supervisor resolves discrepancy, stock moves
|
||||
Planned, // populated by dispatcher — ride set, items editable and versioned
|
||||
Confirmed // items locked, stock movements created
|
||||
}
|
||||
```
|
||||
|
||||
`Pending` from `04_loading_event.md` is replaced by `Planned` and `Confirmed`. `Assigned` is
|
||||
removed — ride is set at populate time, no separate assign step.
|
||||
`Pending`, `Assigned`, `DispatchConfirmed`, `ReceiptConfirmed`, `DiscrepancyFlagged`, and
|
||||
`Resolved` from `04_loading_event.md` are all removed. Stock moves at `Confirmed` — no driver
|
||||
receipt confirmation step in this flow.
|
||||
|
||||
---
|
||||
|
||||
## State Machine
|
||||
|
||||
```text
|
||||
Planned -> Confirmed -> [Path A: stock moves here]
|
||||
\-> [Path B: DispatchConfirmed -> ReceiptConfirmed]
|
||||
\-> DiscrepancyFlagged -> Resolved
|
||||
Planned → Confirmed (stock moves)
|
||||
```
|
||||
|
||||
| Transition | Trigger | What it does |
|
||||
|---|---|---|
|
||||
| (create) → Planned | `POST /api/loading-sheets/populate` | Dispatcher provides `rideId` + filters. System finds all matching Confirmed POs, creates one `LoadingSheet` with `FK_RideId` set, populates `LoadingSheetItem` rows from active `OrderItem` lines, records PO links in `LoadingSheetOrder`. `PopulatedBy`/`PopulatedAt` set. Items editable (versioned via `IsActive`). Dispatcher sets `FK_WarehouseId` per item. |
|
||||
| Planned → Confirmed | `POST /{id}/confirm` | Locks the sheet — `LoadingSheetItem` rows frozen. Sets `ConfirmedAt`/`ConfirmedBy`. Stock movement path TBD (see Open Questions). |
|
||||
| Confirmed → DispatchConfirmed | `POST /{id}/confirm-dispatch` | **Path B only.** Warehouse manager confirms dispatch quantities. |
|
||||
| DispatchConfirmed → ReceiptConfirmed | `POST /{id}/confirm-receipt` | **Path B only.** Driver's received quantities all match. Stock movements created — one debit per `LoadingSheetItem.FK_WarehouseId`, one credit to the ride's vehicle. No ride status transition. |
|
||||
| DispatchConfirmed → DiscrepancyFlagged | `POST /{id}/confirm-receipt` | **Path B only.** Any line mismatch. No stock movements yet. |
|
||||
| DiscrepancyFlagged → Resolved | `POST /{id}/resolve` | **Path B only.** Supervisor enters `QuantityResolved` per line. Stock movements created using resolved quantities. |
|
||||
| Planned → Confirmed | `POST /{id}/confirm` | Locks the sheet — `LoadingSheetItem` rows frozen. Stock movements created: one debit per `LoadingSheetItem.FK_WarehouseId`, one credit to the ride's vehicle. Sets `ConfirmedAt`/`ConfirmedBy`. |
|
||||
|
||||
A `Planned` sheet stays as `Planned` indefinitely until the dispatcher confirms it — there is no
|
||||
timeout or auto-cancellation.
|
||||
|
||||
---
|
||||
|
||||
@@ -145,18 +133,14 @@ and writes a fresh set. Latest version = `IsActive = true` rows.
|
||||
|
||||
## Stock Movements
|
||||
|
||||
One stock movement pair per `LoadingSheetItem` (active rows only). Created exactly once.
|
||||
Created at `Confirmed`. One pair per active `LoadingSheetItem`:
|
||||
|
||||
- **Debit**: `LoadingSheetItem.FK_WarehouseId` (the warehouse that item loads from)
|
||||
- **Credit**: the vehicle on the assigned ride (`LoadingSheet.FK_RideId → DeliveryRun.FK_VehicleId`)
|
||||
- **Credit**: vehicle on the assigned ride (`LoadingSheet.FK_RideId → DeliveryRun.FK_VehicleId`)
|
||||
- **Type**: `Load`
|
||||
|
||||
Since different items can have different `FK_WarehouseId` values, one loading sheet can produce
|
||||
stock movements from multiple warehouses into one vehicle.
|
||||
|
||||
**When** movements are created depends on the path chosen (see Open Questions):
|
||||
- **Path A** — stock moves at `Confirmed`
|
||||
- **Path B** — stock moves at `ReceiptConfirmed` or `Resolved`
|
||||
stock movements from multiple warehouses into one vehicle in a single confirmation action.
|
||||
|
||||
---
|
||||
|
||||
@@ -166,15 +150,11 @@ Base route: `/api/loading-sheets`
|
||||
|
||||
| Method | Route | Who | Description |
|
||||
|---|---|---|---|
|
||||
| POST | `/populate` | Dispatcher | Trigger population: `{ rideId, routeId?, agentId?, shopId? }` — `rideId` required, at least one filter required. Creates one `LoadingSheet` at `Planned` with `FK_RideId` set. |
|
||||
| POST | `/populate` | Dispatcher | `{ rideId, routeId?, agentId?, shopId? }` — `rideId` required, at least one filter required. Creates one `LoadingSheet` at `Planned` with `FK_RideId` set. |
|
||||
| GET | `/` | Any | List sheets. Filter by `routeId`, `agentId`, `shopId`, `rideId`, `status`. Paginated. `routeId` resolves via `Store.FK_RouteId → Order.FK_StoreId → LoadingSheetOrder.FK_OrderId` server-side. |
|
||||
| GET | `/{id}` | Any | Get sheet detail. Active items only by default; `?history=true` includes soft-deleted versions. |
|
||||
| PUT | `/{id}/items` | Dispatcher | Rewrite items while `Planned`. Each item must include `FK_WarehouseId`. Soft-deletes current rows (`IsActive = false`) and writes a fresh set. |
|
||||
| POST | `/{id}/confirm` | Dispatcher | Lock the sheet. `Planned → Confirmed`. Items frozen. |
|
||||
| POST | `/{id}/confirm-dispatch` | Warehouse mgr | **Path B only.** `Confirmed → DispatchConfirmed`. |
|
||||
| PUT | `/{id}/receipt-items` | Driver | **Path B only.** Set `QuantityReceived` per line. |
|
||||
| POST | `/{id}/confirm-receipt` | Driver | **Path B only.** `→ ReceiptConfirmed` or `DiscrepancyFlagged`. |
|
||||
| POST | `/{id}/resolve` | Supervisor | **Path B only.** Enter `QuantityResolved` per line `→ Resolved`. |
|
||||
| POST | `/{id}/confirm` | TBD | Lock the sheet. `Planned → Confirmed`. Items frozen. Stock movements created. |
|
||||
|
||||
---
|
||||
|
||||
@@ -192,11 +172,12 @@ Base route: `/api/loading-sheets`
|
||||
8. Items are editable (versioned via `IsActive`) while `Planned` — frozen at `Confirmed`.
|
||||
9. Every item edit soft-deletes all current `LoadingSheetItem` rows (`IsActive = false`) and writes
|
||||
a fresh set. Active rows = latest version; soft-deleted = history.
|
||||
10. Stock movements are created exactly once — one debit per item warehouse, one credit to the
|
||||
vehicle. Timing depends on path chosen (see Open Questions).
|
||||
11. No `Ride.Status` transition is triggered at any point in this flow.
|
||||
12. All list endpoints return paginated responses.
|
||||
13. Vehicle capacity check is not enforced in this step.
|
||||
10. Stock movements are created at `Confirmed` — one debit per item's warehouse, one credit to the
|
||||
vehicle — all in one transaction.
|
||||
11. A `Planned` sheet stays `Planned` until confirmed — no timeout or auto-cancellation.
|
||||
12. No `Ride.Status` transition is triggered at any point in this flow.
|
||||
13. All list endpoints return paginated responses.
|
||||
14. Vehicle capacity check is not enforced in this step.
|
||||
|
||||
---
|
||||
|
||||
@@ -205,50 +186,49 @@ Base route: `/api/loading-sheets`
|
||||
| Code | Who |
|
||||
|---|---|
|
||||
| `loading.view` | All roles |
|
||||
| **`loading.populate`** | **New.** Dispatcher — trigger population, edit items, confirm sheet |
|
||||
| `loading.dispatch` | Warehouse manager — Path B dispatch confirmation |
|
||||
| `loading.receive` | Driver — Path B receipt confirmation |
|
||||
| `loading.resolve` | Supervisor — Path B discrepancy resolution |
|
||||
| **`loading.populate`** | **New.** Dispatcher — trigger population, edit items |
|
||||
| **`loading.confirm`** | **New.** TBD — who can confirm the sheet (see Open Questions) |
|
||||
|
||||
---
|
||||
|
||||
## Fraud / Control Considerations
|
||||
|
||||
- Discrepancies are immediately visible and block further progress.
|
||||
- `QuantityResolved` is permanently stored per line for audit purposes.
|
||||
- `PopulatedBy`/`PopulatedAt` gives an audit trail for who triggered population and when.
|
||||
- `ConfirmedBy`/`ConfirmedAt` records who committed stock movements.
|
||||
- `FK_OrderItemId` on each item traces the exact source PO line for full audit.
|
||||
- `IsActive = false` rows preserve the full edit history of the sheet before confirmation.
|
||||
|
||||
---
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. **Path A vs Path B — when do stock movements happen?** Stock can move at `Confirmed` (Path A)
|
||||
or at `ReceiptConfirmed`/`Resolved` (Path B). Both paths retained until decided.
|
||||
2. **Who confirms the loading sheet?** — the dispatcher who populated it, the warehouse manager,
|
||||
or either?
|
||||
3. **What happens to a `Planned` sheet if it is never confirmed?** — no cancellation or timeout
|
||||
path is designed here.
|
||||
4. Vehicle capacity check — still deferred.
|
||||
1. **Who confirms the loading sheet?** — dispatcher, warehouse manager, or either? TBD. Controls
|
||||
the `loading.confirm` permission assignment.
|
||||
2. **What happens to a `Planned` sheet if its source PO is cancelled?** — if a Confirmed PO is
|
||||
cancelled after a loading sheet has been populated from it, the sheet's items sourced from that
|
||||
PO become invalid. No cascade behaviour designed here.
|
||||
3. Vehicle capacity check — still deferred.
|
||||
|
||||
---
|
||||
|
||||
## Migration Notes (for when this is implemented)
|
||||
|
||||
- Remove `FK_OrderId` and `FK_SourceWarehouseId` from `Models/LoadingSheet.cs`. Make `FK_RideId`
|
||||
required (non-nullable). Remove `AssignedAt`/`AssignedBy`. Add `PopulatedBy`, `PopulatedAt`,
|
||||
- Remove `FK_OrderId`, `FK_SourceWarehouseId`, `AssignedAt`, `AssignedBy`,
|
||||
`DispatchConfirmedAt`, `DispatchConfirmedBy`, `ReceiptConfirmedAt`, `ReceiptConfirmedBy` from
|
||||
`Models/LoadingSheet.cs`. Make `FK_RideId` required. Add `PopulatedBy`, `PopulatedAt`,
|
||||
`ConfirmedAt`, `ConfirmedBy`.
|
||||
- Add `Models/LoadingSheetOrder.cs` (`FK_LoadingSheetId`, `FK_OrderId`) with composite PK.
|
||||
- Add `FK_WarehouseId` (required), `FK_OrderItemId` (nullable), `IsActive` to
|
||||
`Models/LoadingSheetItem.cs`.
|
||||
- Replace `LoadingSheetStatus.Pending` and `Assigned` with `Planned` and `Confirmed`; update all
|
||||
status checks in `LoadingSheetService`/`LoadingSheetRepository`.
|
||||
- Remove `POST /api/loading-sheets` (old manual create) and `POST /{id}/assign-ride`; add
|
||||
`POST /api/loading-sheets/populate` and `POST /{id}/confirm`.
|
||||
`Models/LoadingSheetItem.cs`. Remove `QuantityReceived`, `QuantityResolved`.
|
||||
- Replace `LoadingSheetStatus` entirely with `Planned` and `Confirmed`; remove all other values
|
||||
and update all status checks in `LoadingSheetService`/`LoadingSheetRepository`.
|
||||
- Remove `POST /api/loading-sheets` (old manual create), `POST /{id}/assign-ride`,
|
||||
`POST /{id}/confirm-dispatch`, `PUT /{id}/receipt-items`, `POST /{id}/confirm-receipt`,
|
||||
`POST /{id}/resolve`; add `POST /api/loading-sheets/populate` and `POST /{id}/confirm`.
|
||||
- Wire stock movements into `POST /{id}/confirm` — one debit per `LoadingSheetItem.FK_WarehouseId`,
|
||||
one credit to the ride's vehicle, in a single transaction.
|
||||
- Remove ride-route-based item population (`GetAggregatedOrderItemsByRouteIdAsync`); replace with
|
||||
filter-based multi-PO aggregation in `LoadingSheetService`.
|
||||
- Remove all calls to ride-activation logic from `confirm-receipt`/`resolve` — no `Ride.Status`
|
||||
transition exists anymore.
|
||||
- Seed the new `loading.populate` permission.
|
||||
- Resolve Open Question 1 (stock movement timing) before implementing `POST /{id}/confirm` and
|
||||
`POST /{id}/confirm-receipt` stock movement logic.
|
||||
filter-based multi-PO aggregation.
|
||||
- Remove all calls to ride-activation logic — no `Ride.Status` transition exists anymore.
|
||||
- Seed `loading.populate` and `loading.confirm` permissions.
|
||||
- Resolve Open Question 1 (who confirms) before assigning `loading.confirm` permission.
|
||||
|
||||
@@ -168,6 +168,11 @@ Draft → Printed → Finalized
|
||||
10. `Order.FK_SaleId` is optional — a PO can exist and be confirmed before any `Sale` is recorded.
|
||||
11. Loading sheet population is a separate dispatcher-triggered flow — not triggered by PO
|
||||
confirmation or invoice creation. See [dispatch_pipeline.md](./dispatch_pipeline.md).
|
||||
12. **A Shop PO (pre-confirmation) can be cancelled** — `Order.Status → Cancelled`. No Invoice
|
||||
exists at this stage so no cascade required.
|
||||
13. **A Confirmed PO can also be cancelled** even after confirmation — `Order.Status → Cancelled`.
|
||||
If an Invoice was already created for this PO, cascade behaviour (void/cancel the Invoice) and
|
||||
behaviour for any loading sheet that included this PO are open questions — see Open Questions.
|
||||
|
||||
---
|
||||
|
||||
@@ -191,9 +196,14 @@ Draft → Printed → Finalized
|
||||
2. ~~**One Invoice per PO or multiple?**~~ — **Resolved:** 1:1 for v1.
|
||||
3. **Should `Order.Status` and `Invoice.Status` eventually merge?** — kept separate; not decided.
|
||||
4. **How does `Payment` attach to `Invoice`?** — see Impact item 2. Not designed here.
|
||||
5. **Cancellation/void path for a Shop PO, Confirmed PO, or Invoice?** — not addressed here.
|
||||
5. **Cancellation cascade — Invoice and LoadingSheet** — a Shop PO can be cancelled (no Invoice
|
||||
exists yet, no cascade). A Confirmed PO can be cancelled even after confirmation. If the PO
|
||||
already has a linked Invoice, what happens to that Invoice (voided? stays Draft?) is unresolved.
|
||||
If the PO's items were pulled into a loading sheet, what happens to those loading sheet items is
|
||||
also unresolved. Both cases need explicit cascade rules before implementation.
|
||||
6. **Exact adjustment payload for `POST /finalize`** — quantity adjustments, returns, damage, and
|
||||
discounts are assumed but the payload shape is not fully specified here.
|
||||
discounts are assumed but the payload shape is not fully specified. "Free issues" handling (items
|
||||
given to the shop at no charge) is a known case that needs its own field(s) in the payload.
|
||||
|
||||
---
|
||||
|
||||
@@ -219,3 +229,5 @@ Draft → Printed → Finalized
|
||||
`FinalizedAt`/`FinalizedBy`. Resolve Open Question 6 before specifying the exact payload shape.
|
||||
- `LoadingSheet` population is a separate flow — see [dispatch_pipeline.md](./dispatch_pipeline.md).
|
||||
- A new PO-creation path independent of `SaleService.CreateAsync` is needed — not specified here.
|
||||
- Add `POST /api/orders/{id}/cancel` — cancels a Shop PO or Confirmed PO. Resolve Open Question 5
|
||||
(cascade to Invoice and LoadingSheet) before implementing for the Confirmed PO case.
|
||||
|
||||
Reference in New Issue
Block a user