namespace Distribution.Models { public enum SchemeRuleType { BuyXGetY, SlabDiscount, FlatPercent, FreeBundle } public class Scheme : Template { public string Name { get; set; } public SchemeRuleType RuleType { get; set; } /// /// JSON payload for percentage-based rules only (SlabDiscount tiers, FlatPercent). Free-goods /// rules (BuyXGetY / FreeBundle) are structured fields/child rows below, not JSON, so they can /// be managed through their own CRUD endpoints instead of a hand-edited blob. /// public string? RuleConfig { get; set; } // ── BuyXGetY: trigger item/qty; shares FK_FreeItemId/FreeQty below as the payout. ────────── public Guid? FK_TriggerItemId { get; set; } public Item? TriggerItem { get; set; } public int? TriggerQty { get; set; } // ── Free-goods payout, used by both BuyXGetY and FreeBundle. ───────────────────────────── public Guid? FK_FreeItemId { get; set; } public Item? FreeItem { get; set; } public decimal? FreeQty { get; set; } /// Required component items for a FreeBundle scheme — managed via its own CRUD. public ICollection BundleComponents { get; set; } = []; public Guid? FK_RegionId { get; set; } public Region? Region { get; set; } /// Store segment this scheme applies to (Gold/Silver/Key Account/...); null = all segments. public string? EligibleSegment { get; set; } public DateTime DateRangeFrom { get; set; } public DateTime DateRangeTo { get; set; } /// /// When true, this scheme's discount is exempt from the per-role discount ceiling in /// 08_sales_agent_controls.md and stacks on top of it unconditionally. /// public bool AgentLimitExempt { get; set; } /// /// Manual baseline (expected sales with no scheme running) used by getSchemeROI. Per the /// open question in docs/17_promotions_schemes.md, this is entered at scheme creation /// rather than computed from a trailing-period average. /// public decimal? BaselineExpectedSales { get; set; } public ICollection Redemptions { get; set; } = []; } }