diff --git a/.claude/worktrees/agent-a203fc082069b1faf b/.claude/worktrees/agent-a203fc082069b1faf new file mode 160000 index 0000000..ade41b4 --- /dev/null +++ b/.claude/worktrees/agent-a203fc082069b1faf @@ -0,0 +1 @@ +Subproject commit ade41b4a60b1381b8f3027f457139f5b9879a869 diff --git a/Distribution/docs/00_existing_gaps.md b/Distribution/docs/00_existing_gaps.md index 73cf60e..3c486e9 100644 --- a/Distribution/docs/00_existing_gaps.md +++ b/Distribution/docs/00_existing_gaps.md @@ -1,6 +1,6 @@ # 00 — Existing Gap Fixes -**Status**: Not Started +**Status**: Done **Depends On**: — --- diff --git a/Distribution/docs/01_item_catalog.md b/Distribution/docs/01_item_catalog.md index 4ba379e..22313ab 100644 --- a/Distribution/docs/01_item_catalog.md +++ b/Distribution/docs/01_item_catalog.md @@ -1,6 +1,6 @@ # 01 — Item Catalog -**Status**: Ready +**Status**: Done **Depends On**: 00 — Existing Gap Fixes (gaps 1 & 2 done) --- diff --git a/Distribution/docs/04_loading_event.md b/Distribution/docs/04_loading_event.md index d936cdc..e4d2cb0 100644 --- a/Distribution/docs/04_loading_event.md +++ b/Distribution/docs/04_loading_event.md @@ -1,6 +1,6 @@ # 04 - Loading Event -**Status**: Planning +**Status**: Done **Depends On**: 03 - Ride Lifecycle --- diff --git a/Distribution/docs/mainPlan.md b/Distribution/docs/mainPlan.md index e5eec00..3c63180 100644 --- a/Distribution/docs/mainPlan.md +++ b/Distribution/docs/mainPlan.md @@ -11,26 +11,32 @@ | Region / Route / Vehicle CRUD | Done | Full API surface with permission checks | | Store / Warehouse CRUD | Done | Full API surface with permission checks | | Store Management (Beyond CRUD) | Done | Credit limit, KYC, segment, dashboard, scheme eligibility; see [12_store_management.md](./12_store_management.md) | -| Order CRUD | Done | Scope-aware (user only sees their assigned stores) | +| Order CRUD | Done | Scope-aware (user only sees their assigned stores); an `Order` is now created only as a side effect of `Sale` creation, not standalone — see §1 Order Management notes below | +| Sale & Payment | Done | `Features/Sale` creates a `Sale`+linked `Order` together (pricing, KYC threshold, immediate-handover stock check); `Features/Payment` records collections against a `Sale` and drives its `PaymentStatus` | | Unit of Work + Repositories | Done | Transaction support throughout | | Soft Deletes | Done | IsActive pattern on all entities | | Price Lists / Suppliers | Done | Region-scoped price lists + supplier master; see [14_pricing_and_suppliers.md](./14_pricing_and_suppliers.md) | | Promotions & Trade Schemes | Done | BuyXGetY/FreeBundle/SlabDiscount/FlatPercent schemes, free-goods fulfillment, spend/ROI tracking; see [17_promotions_schemes.md](./17_promotions_schemes.md) | | Procurement / Purchasing | Done | Purchase Order → Goods Receipt → Purchase Return, supplier evaluation; see [15_procurement.md](./15_procurement.md) | +| Returns & Claims Management | Done | Sale returns, claims, supplier claims; see [18_returns_claims.md](./18_returns_claims.md) | -## Known Gaps in Existing System (Pre-Work) +## Known Gaps in Existing System (Pre-Work) — Resolved -These are not new features — they are fixable holes in what's already built. -They must be resolved before new feature steps begin because later steps depend on correct foundations. +Step 00 closed these. Kept here for history; all are fixed in the current codebase. + +| Gap | Impact | Resolution | +|---|---|---| +| Route DTOs missing RegionId | Can't link routes to regions via API | Fixed — `CreateRouteRequest`/`UpdateRouteRequest`/`RouteResponse` all carry `RegionId` (`Features/Route/RouteDTOs.cs`). | +| Store DTOs missing RouteId | Can't link stores to routes via API | Fixed — all Store DTOs carry `RouteId` (`Features/Store/StoreDTOs.cs`). | +| Role endpoints have no [Authorize] | Anyone can read roles without authentication | Fixed — `[Authorize]` on `RoleController` (`Features/Role/RoleController.cs`). | +| Item model is empty (no properties) | OrderItems reference items that have no data | Fixed — `Item` has `Sku`/`Name`/`Description`/category/brand/UOM/pricing fields (`Models/Item.cs`). | + +### Still open (not a step-00 blocker, tracked separately) | Gap | Impact | |---|---| -| Route DTOs missing RegionId | Can't link routes to regions via API | -| Store DTOs missing RouteId | Can't link stores to routes via API | -| Role endpoints have no [Authorize] | Anyone can read roles without authentication | -| JWT key & DB credentials in appsettings.json | Security risk in any shared/production environment | -| No input validation on any DTO | Bad data can enter the system silently | -| Item model is empty (no properties) | OrderItems reference items that have no data | +| JWT key & DB credentials in appsettings.json | Security risk in any shared/production environment — `appsettings.json` still has a literal DB password and placeholder JWT key. | +| No input validation on any DTO | Bad data can enter the system silently. | --- @@ -56,7 +62,7 @@ They must be resolved before new feature steps begin because later steps depend | 15 | Procurement / Purchasing | Done | 01, 14 | [15_procurement.md](./15_procurement.md) | | 16 | Sales Force Automation / CRM | Not Started | 12 | [16_sfa_crm.md](./16_sfa_crm.md) | | 17 | Promotions & Trade Scheme Management | Done | 01, 14 | [17_promotions_schemes.md](./17_promotions_schemes.md) | -| 18 | Returns & Claims Management | Not Started | 05, 06 | [18_returns_claims.md](./18_returns_claims.md) | +| 18 | Returns & Claims Management | Done | 05, 06 | [18_returns_claims.md](./18_returns_claims.md) | | 19 | Finance & Accounting | Not Started | 05, 06, 18 | [19_finance_accounting.md](./19_finance_accounting.md) | | 20 | Reporting, Analytics & BI | Not Started | all prior | [20_reporting_analytics.md](./20_reporting_analytics.md) | | 21 | Notifications & Alerts | Not Started | 02, 12, 08 | [21_notifications_alerts.md](./21_notifications_alerts.md) | @@ -81,18 +87,27 @@ here — see `SRS_User_Management_Module.pdf`. ### 1. Order Management +> **Design change since this section was first written**: `Order` is no longer created directly +> from `storeId/items/salesRepId`. Order creation was folded into `Features/Sale` — every `Order` +> is now a 1:1 side effect of `SaleService.CreateAsync` (see §6 Sale Ride Execution). `POST +> /api/orders` (`OrderService.CreateAsync`) is now just a lookup — it throws +> `"Orders are created automatically from sales"` if called for a sale that doesn't already have +> one, rather than creating a standalone order. All the validation described below (stock check, +> KYC threshold, pricing) now happens in `SaleService.CreateAsync` +> (`Features/Sale/SaleService.cs`), not `OrderService`. + | Function | What it does | Status | |---|---|---| -| `createOrder(storeId, items[], salesRepId)` | Validates stock/credit, creates a new order in `pending` state. | Partially implemented - `OrderService.CreateAsync` exists, enforces store scope, blocks inactive stores, applies the unverified-KYC order threshold from config, and now checks stock availability (see `checkStockAvailability` below). It still has no credit-limit validation, approval flow, or order state machine. | -| `validateCreditLimit(storeId, orderAmount)` | Checks store's outstanding balance + new order value against its credit limit. | Not implemented - `Store` now has `CreditLimit` and `OutstandingBalance`, but there is no dedicated validator or order-time credit-limit enforcement yet. | -| `checkStockAvailability(items[])` | Confirms requested SKUs/quantities are available at the fulfilling warehouse. | Implemented — `OrderService.CreateAsync` rejects an order if any line's requested quantity exceeds total `StockBalance` for that item summed across every location (added alongside [15_procurement.md](./15_procurement.md)). Not location-specific yet (no fulfilling-warehouse concept on `Store`/`Order`), and does not reserve or decrement stock — that stays deferred to loading/delivery (§05-06). | -| `applyPricingAndDiscounts(orderId)` | Runs the active price list and eligible scheme rules against order lines. | Partially implemented — `OrderService.CreateAsync` resolves the price-list half via `PriceListService.ResolveUnitPriceAsync` (region-scoped → global → `Item.SalePrice`, or a caller-supplied `UnitPrice`). The scheme-discount half now exists as a separate call — `SchemeService.EvaluateEligibilityAsync`/`ApplySchemeAsync` (§11) — but is not yet auto-invoked from `OrderService.CreateAsync`; the caller applies a scheme explicitly via `POST /api/orders/{id}/apply-scheme` after order creation. | +| `createOrder(storeId, items[], salesRepId)` | Validates stock/credit, creates a new order in `pending` state. | Superseded — see design-change note above. The equivalent entry point is `SaleService.CreateAsync` (`createSale`, §6), which creates the `Sale` and its linked `Order` together. `OrderService.CreateAsync` itself only fetches the existing order for a given `SaleId`. | +| `validateCreditLimit(storeId, orderAmount)` | Checks store's outstanding balance + new order value against its credit limit. | Not implemented - `Store` has `CreditLimit` and `OutstandingBalance`, but there is no dedicated validator or sale/order-time credit-limit enforcement yet. | +| `checkStockAvailability(items[])` | Confirms requested SKUs/quantities are available at the fulfilling warehouse. | Partially implemented — `SaleService.CreateAsync` checks `StockBalance` at the ride's vehicle, but **only** when `FulfillImmediately = true` and a `RideId` is supplied (immediate van-sale handover); a deferred/pending sale does no stock check at create time at all. Not warehouse-wide, not reserved — a failed check simply returns `null` (400) rather than a typed error. | +| `applyPricingAndDiscounts(orderId)` | Runs the active price list and eligible scheme rules against order lines. | Partially implemented — `SaleService.CreateAsync` resolves the price-list half via `ResolveUnitPriceAsync` → `PriceListService.ResolvePriceAsync` (region-scoped via the store's route → `Item.SalePrice` fallback, or a caller-supplied `UnitPrice` validated against `[MinPrice, Price]`). The scheme-discount half is a separate call — `SchemeService.EvaluateEligibilityAsync`/`ApplySchemeAsync` (§11) — not auto-invoked from `createSale`; the caller applies a scheme explicitly via `POST /api/orders/{id}/apply-scheme` after the order exists. | | `submitOrderForApproval(orderId)` | Routes the order to the correct approver based on its value/discount threshold. | Not implemented — depends on [08_sales_agent_controls.md](./08_sales_agent_controls.md). | | `approveOrder(orderId, approverId)` / `rejectOrder(orderId, reason)` | Moves order to `approved` or `rejected`, logging the actor. | Not implemented. | -| `updateOrderStatus(orderId, status)` | Transitions order through `pending → approved → picked → dispatched → delivered → invoiced`. | Not implemented — `Order` has no status field or state machine today. | +| `updateOrderStatus(orderId, status)` | Transitions order through `pending → approved → picked → dispatched → delivered → invoiced`. | Implemented, with a smaller state machine than described — `Models/Enums.cs` defines `OrderStatus { Pending, PartiallyFulfilled, Fulfilled, Cancelled }`; `OrderService.UpdateAsync` (`PUT /api/orders/{id}`) sets `Order.Status` directly (any status accepted, no transition guard) and mirrors it onto the linked `Sale.Status`/`CompletedAt`. No `approved/picked/dispatched/invoiced` states exist. | | `convertOrderToInvoice(orderId)` | Generates the invoice once the order is dispatched/delivered. | Not implemented — depends on §13 Finance & Accounting. | | `createBackorder(orderId, unfulfilledItems[])` | Splits unfulfillable quantity into a linked backorder. | Not implemented. | -| `cancelOrder(orderId, reason)` | Cancels an order pre-dispatch and releases any reserved stock. | Not implemented — `OrderController` supports soft delete only, no reason code or stock release. | +| `cancelOrder(orderId, reason)` | Cancels an order pre-dispatch and releases any reserved stock. | Partially implemented — `OrderService.DeleteAsync` (`DELETE /api/orders/{id}`) soft-deletes the order and cascades `Sale.Status = Cancelled`, but takes no reason code and releases no reserved stock (nothing is reserved at create time to release). | | `getOrdersByStore(storeId)` / `getOrdersBySalesRep(salesRepId)` | Scoped order listings. | `getOrdersByStore` implemented (`GET /api/orders/store/{storeId}`). `getOrdersBySalesRep` not implemented. | | `getOrderAnalytics(filters)` | Returns fill rate, average order value, rejection rate over a period. | Not implemented. | @@ -129,8 +144,11 @@ here — see `SRS_User_Management_Module.pdf`. | Function | What it does | Status | |---|---|---| | `createStore(storeData, kycDocs)` | Onboards a new outlet with required KYC. | Partially implemented - store create exists, and KYC documents can now be uploaded/listed via separate `/api/stores/{id}/kyc-documents` endpoints rather than inline on create. | +| `uploadStoreKycDocument(storeId, documentType, file)` | Appends a KYC document to a store. | Implemented — `POST /api/stores/{id}/kyc-documents`. | +| `listStoreKycDocuments(storeId)` | Lists KYC documents for a store. | Implemented — `GET /api/stores/{id}/kyc-documents`. | | `verifyStoreKyc(storeId)` | Marks KYC as verified/rejected by an approver. | Implemented - `PUT /api/stores/{id}/kyc/verify` updates `Store.KycStatus`. | | `updateStoreCreditLimit(storeId, newLimit, approverId)` | Changes a store's credit limit, subject to approval authority. | Implemented - `PUT /api/stores/{id}/credit-limit` updates `Store.CreditLimit` and requires the `stores.credit.update` permission plus role level >= 20. | +| `updateStoreOutstandingBalance(storeId, amount, reason?)` | Manually adjusts the cached outstanding balance. | Implemented — `PUT /api/stores/{id}/outstanding-balance`. | | `getStoreOutstandingBalance(storeId)` | Returns current receivables against the store. | Partially implemented - `GET /api/stores/{id}/outstanding-balance` returns the cached `OutstandingBalance`, `CreditLimit`, and available credit. It is not yet driven by Finance events or invoice/payment records. | | `classifyStore(storeId, segment)` | Sets/updates the store's segment (key account, general trade, etc.). | Implemented - `PUT /api/stores/{id}/segment` updates the free-text `Store.Segment` field. | | `deactivateStore(storeId, reason)` | Soft-deletes a store, blocking new orders against it. | Partially implemented — `DELETE /api/stores/{id}` soft-deletes via `IsActive`, no reason code captured. | @@ -177,9 +195,18 @@ here — see `SRS_User_Management_Module.pdf`. |---|---|---| | `createProduct(skuData)` | Creates a SKU with category, UOM, barcode, pack hierarchy. | Not implemented — `Item` model exists but has no properties; see [01_item_catalog.md](./01_item_catalog.md). | | `deactivateSku(sku, reason)` | Retires a SKU from active ordering. | Not implemented. | +| `listPriceLists(regionId?)` | Lists price lists, optionally filtered by region. | Implemented — `GET /api/price-lists`. | +| `getPriceList(priceListId)` | Fetches a price list and its items. | Implemented — `GET /api/price-lists/{id}`. | | `createPriceList(name, region, effectiveDates)` | Defines a new price list scoped to a region/date range. | Implemented — `POST /api/price-lists`, see [14_pricing_and_suppliers.md](./14_pricing_and_suppliers.md). | -| `updateProductPricing(sku, priceListId, price)` | Sets/updates the price of a SKU within a price list. | Implemented — `PUT /api/price-lists/{id}/items/{sku}`. | +| `updatePriceList(priceListId, name, region, effectiveDates)` | Updates price-list metadata. | Implemented — `PUT /api/price-lists/{id}`. | +| `deletePriceList(priceListId)` | Soft-deletes a price list. | Implemented — `DELETE /api/price-lists/{id}`. | +| `updateProductPricing(sku, priceListId, price, minPrice?)` | Sets/updates the price of a SKU within a price list. | Implemented — `PUT /api/price-lists/{id}/items/{sku}`. | +| `removeProductPricing(sku, priceListId)` | Removes a SKU override from a price list. | Implemented — `DELETE /api/price-lists/{id}/items/{sku}`. | +| `listSuppliers()` | Lists suppliers. | Implemented — `GET /api/suppliers`. | +| `getSupplier(supplierId)` | Fetches a supplier by ID. | Implemented — `GET /api/suppliers/{id}`. | | `createSupplierMaster(supplierData)` | Registers a new supplier/vendor. | Implemented — `POST /api/suppliers`. `PerformanceScore` stays null until [15_procurement.md](./15_procurement.md)'s `evaluateSupplier` exists. | +| `updateSupplier(supplierId, supplierData)` | Updates supplier master data. | Implemented — `PUT /api/suppliers/{id}`. `PerformanceScore` remains read-only here. | +| `deleteSupplier(supplierId)` | Soft-deletes a supplier. | Implemented — `DELETE /api/suppliers/{id}`. Blocked if an active PurchaseOrder references the supplier. | ### 8. Enterprise-wide Inventory & Stock @@ -197,9 +224,21 @@ here — see `SRS_User_Management_Module.pdf`. |---|---|---| | `createPurchaseRequisition(items[], requestedBy)` | Raises an internal request to purchase stock. | Not implemented — no procurement entities exist. | | `createPurchaseOrder(supplierId, items[])` | Issues a PO to a supplier. | Implemented — `POST /api/purchase-orders`, see [15_procurement.md](./15_procurement.md). Also has `updatePurchaseOrder`, `closePurchaseOrder`, `cancelPurchaseOrder`, `cancelPurchaseOrderLine`. | +| `getPurchaseOrder(poId)` | Fetches a purchase order. | Implemented — `GET /api/purchase-orders/{id}`. | +| `listPurchaseOrders(filters)` | Lists purchase orders. | Implemented — `GET /api/purchase-orders`. | +| `updatePurchaseOrder(poId, items[])` | Updates an open purchase order. | Implemented — `PUT /api/purchase-orders/{id}`. | +| `closePurchaseOrder(poId)` | Closes a received purchase order. | Implemented — `POST /api/purchase-orders/{id}/close`. | +| `cancelPurchaseOrder(poId, reason)` | Cancels a purchase order before receipts exist. | Implemented — `POST /api/purchase-orders/{id}/cancel`. | +| `cancelPurchaseOrderLine(poId, poItemId, reason)` | Cancels a single PO line. | Implemented — `POST /api/purchase-orders/{id}/items/{itemId}/cancel`. | | `matchInvoiceToPO(invoiceId, poId, grnId)` | Performs the 3-way match (PO–GRN–Invoice) before payment. | Partially implemented — `POST /api/purchase-orders/{id}/match-invoice` reconciles PurchaseOrderItem vs GoodsReceiptItem quantities/cost only; full 3-way match activates once Finance's `Invoice` entity (§13, not built) exists. `resolveInvoiceVariance` records the mismatch and its resolution. | -| `evaluateSupplier(supplierId, criteria)` | Scores a supplier on delivery/quality/price performance. | Implemented — `POST /api/suppliers/{id}/evaluate`, the only writer of `Supplier.PerformanceScore`. Scored from accepted-vs-rejected quantity ratio and cancelled-vs-fulfilled line ratio across that supplier's PurchaseOrders/GoodsReceipts. | +| `resolveInvoiceVariance(poId, variance, resolution)` | Records how a mismatch should be handled. | Implemented — `POST /api/purchase-orders/{id}/resolve-variance`. | +| `getGoodsReceipt(grnId)` | Fetches a goods receipt. | Implemented — `GET /api/goods-receipts/{id}`. | +| `listGoodsReceipts(poId)` | Lists goods receipts for a purchase order. | Implemented — `GET /api/purchase-orders/{id}/goods-receipts`. | +| `createGoodsReceipt(poId, warehouseId, items[])` | Records inbound stock against a purchase order. | Implemented — `POST /api/purchase-orders/{id}/goods-receipts`. | +| `getPurchaseReturn(returnId)` | Fetches a purchase return. | Implemented — `GET /api/purchase-returns/{id}`. | +| `listPurchaseReturns(poId)` | Lists purchase returns for a purchase order. | Implemented — `GET /api/purchase-orders/{id}/returns`. | | `createPurchaseReturn(poId, items[], reason)` | Initiates a return of received goods to the supplier. | Implemented — `POST /api/purchase-orders/{id}/returns`, see [15_procurement.md](./15_procurement.md). Debits `StockBalance`/`StockMovement` at the PO's receiving warehouse. | +| `evaluateSupplier(supplierId, criteria)` | Scores a supplier on delivery/quality/price performance. | Implemented — `POST /api/suppliers/{id}/evaluate`, the only writer of `Supplier.PerformanceScore`. Scored from accepted-vs-rejected quantity ratio and cancelled-vs-fulfilled line ratio across that supplier's PurchaseOrders/GoodsReceipts. | ### 10. Sales Force Automation (SFA) / CRM @@ -225,19 +264,25 @@ here — see `SRS_User_Management_Module.pdf`. | Function | What it does | Status | |---|---|---| -| `createReturnRequest(orderId, items[], reasonCode)` | Initiates a return against a delivered order. | Not implemented — see [09_fraud_controls.md](./09_fraud_controls.md) for the fraud-control angle on returns. | -| `approveReturn(returnId, approverId)` | Approves/rejects the return request. | Not implemented. | -| `generateCreditNote(returnId)` | Issues a credit note against the original invoice. | Not implemented. | -| `createClaim(agencyId, claimDetails)` | Raises a claim against a Regional Agency (e.g., damaged stock). | Not implemented. | -| `settleClaim(claimId, settlementAmount)` | Closes out a claim with a final settlement amount. | Not implemented. | +| `createSaleReturn(orderId, mode, items[])` | Records a customer return against a delivered order. | Implemented — `POST /api/orders/{id}/returns`, settles immediately and credits the ride's vehicle. No approval step. | +| `getSaleReturn(returnId)` | Fetches a sale return by ID. | Implemented — `GET /api/returns/{id}`. | +| `listSaleReturns(orderId)` | Lists sale returns for an order. | Implemented — `GET /api/orders/{id}/returns`. | +| `createClaim(agencyUserId, details)` | Raises a claim against a Regional Agency user. | Implemented — `POST /api/claims`. | +| `getClaim(claimId)` | Fetches a claim by ID. | Implemented — `GET /api/claims/{id}`. | +| `settleClaim(claimId, settlementAmount)` | Closes out a claim with a final settlement amount. | Implemented — `POST /api/claims/{id}/settle`, requires `claims.settle`. | +| `createSupplierClaim(poId, grnId?, items[], details, evidenceUrl?)` | Raises a supplier claim against a purchase order. | Implemented — `POST /api/purchase-orders/{id}/claims`. | +| `getSupplierClaim(claimId)` | Fetches a supplier claim by ID. | Implemented — `GET /api/supplier-claims/{id}`. | +| `listSupplierClaims(poId)` | Lists supplier claims for a purchase order. | Implemented — `GET /api/purchase-orders/{id}/claims`. | +| `approveSupplierClaim(claimId, resolutionType, resolutionAmount?, notes?)` | Approves a supplier claim. | Implemented — `POST /api/supplier-claims/{id}/approve`, requires `suppliers.claims.approve`. | +| `rejectSupplierClaim(claimId, notes?)` | Rejects a supplier claim. | Implemented — `POST /api/supplier-claims/{id}/reject`, requires `suppliers.claims.approve`. | ### 13. Finance & Accounting | Function | What it does | Status | |---|---|---| -| `createInvoice(orderId)` | Generates a formal invoice from a fulfilled order. | Not implemented — no invoice entity exists. | -| `recordPayment(invoiceId, amount, method)` | Logs a payment/collection against an invoice. | Not implemented. | -| `postToGeneralLedger(transactionId)` | Posts a financial transaction to the GL. | Not implemented. | +| `createInvoice(orderId)` | Generates a formal invoice from a fulfilled order. | Not implemented — no `Invoice` entity exists; `Sale`/`Order` remain the billable record. | +| `recordPayment(invoiceId, amount, method)` | Logs a payment/collection against an invoice. | Implemented against `Sale` rather than an invoice — `POST /api/sales/{saleId}/payments` (`Features/Payment`). Each payment sums against `Sale.TotalAmount` and updates `Sale.PaymentStatus` (`Pending`/`PartiallyPaid`/`Paid`); rejects (400) if the sale is `Cancelled`. `Method` is `Cash` or `Credit` (`Models/Enums.cs`). | +| `postToGeneralLedger(transactionId)` | Posts a financial transaction to the GL. | Not implemented — no GL/ledger entity exists. | | `generateTaxInvoice(invoiceId, jurisdiction)` | Produces a tax-compliant invoice (GST/VAT e-invoicing). | Not implemented. | | `getFinancialReport(entityId, period, reportType)` | Returns P&L/cash-flow reports scoped to a region/area. | Not implemented. | @@ -359,8 +404,9 @@ and approval chains for exceptions. Supervisors can grant one-time overrides log A dedicated audit log records every sensitive event (who, what, when, from where). Automated checks flag: returns without a matching prior sale, sales outside the geofenced route, agents with consistently high variance rates, and cash collected below invoiced amounts. -Return approval requires supervisor sign-off before stock is credited. Anomaly reports are -surfaced to area managers on a scheduled basis. +Return-related processing is handled in §12 as an immediate-settlement flow; this step focuses on +audit logging and anomaly detection around those events. Anomaly reports are surfaced to area +managers on a scheduled basis. **Gate**: Every sensitive event is logged immutably. Automated flags surface to the right level of management. ---