Add scheme data model and migrations

This commit is contained in:
2026-08-21 14:10:40 +05:30
parent c9f5006727
commit f7101800cd
8 changed files with 694 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
namespace Distribution.Models
{
public enum SchemeRuleType
{
BuyXGetY,
SlabDiscount,
FlatPercent,
FreeBundle
}
public class Scheme : Template
{
public string Name { get; set; }
public SchemeRuleType RuleType { get; set; }
/// <summary>
/// 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.
/// </summary>
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; }
/// <summary>Required component items for a FreeBundle scheme — managed via its own CRUD.</summary>
public ICollection<SchemeBundleComponent> BundleComponents { get; set; } = [];
public Guid? FK_RegionId { get; set; }
public Region? Region { get; set; }
/// <summary>Store segment this scheme applies to (Gold/Silver/Key Account/...); null = all segments.</summary>
public string? EligibleSegment { get; set; }
public DateTime DateRangeFrom { get; set; }
public DateTime DateRangeTo { get; set; }
/// <summary>
/// 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.
/// </summary>
public bool AgentLimitExempt { get; set; }
/// <summary>
/// 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.
/// </summary>
public decimal? BaselineExpectedSales { get; set; }
public ICollection<SchemeRedemption> Redemptions { get; set; } = [];
}
}