# 17 — Promotions & Trade Scheme Management **Status**: Not Started **Depends On**: 01 — Item Catalog, 14 — Pricing & Supplier Master Data --- ## Goal Covers [mainPlan.md §11](./mainPlan.md#11-promotions--trade-scheme-management) in full — an entirely new subsystem. Once built, `applyPricingAndDiscounts` (§1) and `checkStoreSchemeEligibility` (§4) both read from it. --- ## Background / Context No scheme/promotion entity exists today. Every reference to "eligible discount" elsewhere in this doc set (order pricing, field invoices, agent discount limits) currently has no scheme data source — it only enforces the flat per-role discount ceiling from [08_sales_agent_controls.md](./08_sales_agent_controls.md). --- ## Data Model Changes ### Scheme `Name`, `RuleType` (`BuyXGetY`, `SlabDiscount`, `FlatPercent`), `RuleConfig` (JSON), `Eligibility` (store segment / region scope), `DateRangeFrom`, `DateRangeTo`. ### Scheme Redemption `SchemeId`, `OrderId` (or `FieldInvoiceId`), `DiscountAmount`, `RedeemedAt` — feeds `trackSchemeSpend` and `getSchemeROI` without re-scanning every order. --- ## API Endpoints | Function reference | Endpoint intent | |---|---| | `createScheme(schemeRules, eligibility, dateRange)` | `POST /api/schemes` | | `evaluateSchemeEligibility(storeId, orderId)` | `GET /api/schemes/eligible?storeId=...&orderId=...` | | `applySchemeDiscount(orderId, schemeId)` | `POST /api/orders/{id}/apply-scheme` | | `trackSchemeSpend(schemeId)` | `GET /api/schemes/{id}/spend` | | `getSchemeROI(schemeId)` | `GET /api/schemes/{id}/roi` | --- ## Business Rules - A scheme discount stacks with, but does not bypass, the per-role discount ceiling in [08_sales_agent_controls.md](./08_sales_agent_controls.md) unless explicitly flagged as an agent-limit-exempt scheme. - `getSchemeROI` requires a baseline (pre-scheme expected sales) to compare against — confirm data source before implementing (see Open Questions). --- ## Open Questions - What counts as "incremental sales" for `getSchemeROI` — a manual baseline entered when the scheme is created, or a trailing-period average computed automatically? --- ## Implementation Notes > Fill this section in during planning discussion before writing any code.