Phase 1: Package-Based Domain Infrastructure

ENTITIES:
- Package: +11 fields (SortOrder, IsActive, IsBasePackage, SupportsDaya/Direct,
  ActivationFee, DiscountMultiplier, MagicWalletMultiplier, MaxBalancesPerLeg,
  MaxNetworkLevel, MagicWalletMaxDeposit/Credit) + nav props
- PackageFeature: NEW junction entity (Package × ClubFeature) for feature DIFF
- ClubMembership: +4 fields (FirstActivationDate/PackageId, LastActivation/PackageId)
  ActivatedAt kept as [Obsolete] for backward compat
- ClubMembershipCycle: +PackageId FK (tracks which package per cycle)
- WeeklyCommissionPool: +PackageId FK (separate pool per package)
- UserCommissionPayout: +PackageId FK (payout per package)
- NetworkWeeklyBalance: +PackageId FK (balance per package)
- UserWalletChangeLog: +PackageId? FK (optional package tracking)

EF CONFIGS:
- PackageConfiguration: 11 new field configs + indexes
- PackageFeatureConfiguration: NEW (unique PackageId+ClubFeatureId)
- ClubMembershipConfiguration: First/Last Package FKs + LastActivationDate index
- ClubMembershipCycleConfiguration: Package FK
- WeeklyCommissionPoolConfiguration: Package FK + unique(WeekDef,Package)
- UserCommissionPayoutConfiguration: Package FK + unique(User,WeekDef,Package)
- NetworkWeeklyBalanceConfiguration: Package FK + unique(User,WeekDef,Package)
- UserWalletChangeLogConfiguration: Package FK (nullable)

DBCONTEXT:
- DbSet<PackageFeature> added to ApplicationDbContext + IApplicationDbContext

SYSTEMCONSTANTS:
- 9 constants marked [Obsolete] → moved to Package entity
  (ClubMembershipGiftValue, ClubActivationFee, BasePackageAmount, DayaLoanAmount,
   MagicWalletMultiplier, MagicWalletMaxDeposit, MagicWalletMaxCredit,
   CommissionMaxWeeklyBalancesPerLeg, CommissionMaxNetworkLevel)

Build: 0 errors, 610 warnings (40 new = expected Obsolete CS0618)
This commit is contained in:
masoodafar-web
2026-02-25 22:32:42 +03:30
parent fe3edd178d
commit ae92ab8697
19 changed files with 339 additions and 17 deletions
@@ -20,9 +20,45 @@ public class ClubMembership : BaseAuditableEntity
/// </summary>
public bool IsActive { get; set; }
// === v5: First/Last Activation Tracking (Q21) ===
/// <summary>
/// تاریخ فعال‌سازی عضویت
/// اولین فعال‌سازی — فقط یک بار ست می‌شود، هیچ‌وقت overwrite نمی‌شود
/// </summary>
public DateTime FirstActivationDate { get; set; }
/// <summary>
/// اولین پکیج خریداری‌شده — فقط یک بار ست می‌شود
/// </summary>
public long FirstPackageId { get; set; }
/// <summary>
/// FirstPackage Navigation Property
/// </summary>
public virtual Package FirstPackage { get; set; }
/// <summary>
/// آخرین/جاری فعال‌سازی — هر خرید مجدد بروزرسانی می‌شود
/// مبنای تشخیص "فعال‌شدگان این هفته" (Q22)
/// </summary>
public DateTime LastActivationDate { get; set; }
/// <summary>
/// آخرین/جاری پکیج — هر خرید مجدد بروزرسانی می‌شود
/// مبنای carryover per-package (Q23)
/// </summary>
public long LastPackageId { get; set; }
/// <summary>
/// LastPackage Navigation Property
/// </summary>
public virtual Package LastPackage { get; set; }
/// <summary>
/// [DEPRECATED] تاریخ فعال‌سازی — جایگزین با FirstActivationDate + LastActivationDate
/// حفظ موقت برای backward compatibility
/// </summary>
[Obsolete("Use FirstActivationDate / LastActivationDate instead")]
public DateTime? ActivatedAt { get; set; }
/// <summary>
@@ -57,6 +57,16 @@ public class ClubMembershipCycle : BaseAuditableEntity
/// </summary>
public long PackageAmount { get; set; }
/// <summary>
/// شناسه پکیج خریداری‌شده در این دور
/// </summary>
public long PackageId { get; set; }
/// <summary>
/// Package Navigation Property
/// </summary>
public virtual Package Package { get; set; }
/// <summary>
/// آیا این دور فعلی است؟ فقط یک رکورد true می‌باشد
/// </summary>
@@ -36,6 +36,16 @@ public class UserCommissionPayout : BaseAuditableEntity
/// </summary>
public virtual WeeklyCommissionPool WeeklyPool { get; set; }
/// <summary>
/// شناسه پکیج (کمیسیون هر پکیج جداگانه)
/// </summary>
public long PackageId { get; set; }
/// <summary>
/// Package Navigation Property
/// </summary>
public virtual Package Package { get; set; }
/// <summary>
/// تعداد امتیازی که کاربر داشت
/// </summary>
@@ -16,6 +16,16 @@ public class WeeklyCommissionPool : BaseAuditableEntity
/// </summary>
public virtual WeekDefinition WeekDefinition { get; set; }
/// <summary>
/// شناسه پکیج (استخر هر پکیج جداگانه)
/// </summary>
public long PackageId { get; set; }
/// <summary>
/// Package Navigation Property
/// </summary>
public virtual Package Package { get; set; }
/// <summary>
/// مجموع مبلغ جمع‌شده در استخر (ریال)
/// </summary>
@@ -25,6 +25,16 @@ public class NetworkWeeklyBalance : BaseAuditableEntity
/// </summary>
public virtual WeekDefinition WeekDefinition { get; set; }
/// <summary>
/// شناسه پکیج (تعادل هر پکیج جداگانه)
/// </summary>
public long PackageId { get; set; }
/// <summary>
/// Package Navigation Property
/// </summary>
public virtual Package Package { get; set; }
/// <summary>
/// تعداد اعضای جدید شاخه چپ در این هفته
/// </summary>
+67 -6
View File
@@ -1,15 +1,76 @@
namespace CMSMicroservice.Domain.Entities;
//پکیج
/// <summary>
/// پکیج — هر پکیج قیمت، ویژگی‌ها و تنظیمات مستقل دارد
/// </summary>
public class Package : BaseAuditableEntity
{
//عنوان
// === فیلدهای فعلی (حفظ) ===
/// <summary>عنوان پکیج</summary>
public string Title { get; set; }
//توضیحات
/// <summary>توضیحات</summary>
public string Description { get; set; }
//آدرس تصویر
/// <summary>آدرس تصویر</summary>
public string ImagePath { get; set; }
//قیمت
/// <summary>قیمت پکیج (ریال)</summary>
public long Price { get; set; }
//UserOrder Collection Navigation Reference
// === فیلدهای جدید v3 ===
/// <summary>ترتیب نمایش</summary>
public int SortOrder { get; set; }
/// <summary>فعال/غیرفعال</summary>
public bool IsActive { get; set; } = true;
/// <summary>پکیج پایه؟ (فقط یکی true)</summary>
public bool IsBasePackage { get; set; }
/// <summary>پشتیبانی از خرید دایا</summary>
public bool SupportsDayaPurchase { get; set; }
/// <summary>پشتیبانی از پرداخت مستقیم</summary>
public bool SupportsDirectPurchase { get; set; } = true;
// === محاسبات مالی ===
/// <summary>سهم Commission Pool (ریال) — معمولاً Price × 0.45</summary>
public long ActivationFee { get; set; }
/// <summary>ضریب شارژ DiscountBalance — فعلاً ×2 برای همه</summary>
public decimal DiscountMultiplier { get; set; } = 2.0m;
/// <summary>ضریب کیف‌پول جادویی — واریز × این مقدار = اعتبار</summary>
public decimal MagicWalletMultiplier { get; set; } = 2.5m;
// === تنظیمات پورسانت ===
/// <summary>سقف تعادل هر پا (نقره‌ای=۳۰، پایه=۳۰۰)</summary>
public int MaxBalancesPerLeg { get; set; } = 300;
/// <summary>عمق شبکه برای محاسبه کمیسیون</summary>
public int MaxNetworkLevel { get; set; } = 15;
// === تنظیمات کیف‌پول جادویی ===
/// <summary>سقف شارژ هر دور جادویی (ریال)</summary>
public long MagicWalletMaxDeposit { get; set; } = 1_000_000_000;
/// <summary>سقف اعتبار هر دور جادویی (ریال)</summary>
public long MagicWalletMaxCredit { get; set; } = 2_500_000_000;
// === Navigation Properties ===
/// <summary>فیچرهای این پکیج</summary>
public virtual ICollection<PackageFeature>? PackageFeatures { get; set; }
/// <summary>سفارشات مرتبط</summary>
public virtual ICollection<UserOrder> UserOrders { get; set; }
/// <summary>خریدهای پکیج</summary>
public virtual ICollection<UserPackagePurchase>? Purchases { get; set; }
}
@@ -0,0 +1,34 @@
using CMSMicroservice.Domain.Entities.Club;
namespace CMSMicroservice.Domain.Entities;
/// <summary>
/// ارتباط پکیج–فیچر — هر پکیج مجموعه فیچرهای خودش را دارد
/// </summary>
public class PackageFeature : BaseAuditableEntity
{
/// <summary>
/// شناسه پکیج
/// </summary>
public long PackageId { get; set; }
/// <summary>
/// Package Navigation Property
/// </summary>
public virtual Package Package { get; set; }
/// <summary>
/// شناسه فیچر باشگاه
/// </summary>
public long ClubFeatureId { get; set; }
/// <summary>
/// ClubFeature Navigation Property
/// </summary>
public virtual ClubFeature ClubFeature { get; set; }
/// <summary>
/// آیا این فیچر در پکیج فعال است
/// </summary>
public bool IsIncluded { get; set; } = true;
}
@@ -22,4 +22,14 @@ public class UserWalletChangeLog : BaseAuditableEntity
public bool IsIncrease { get; set; }
//شناسه ارجاع
public long? RefrenceId { get; set; }
/// <summary>
/// شناسه پکیج مرتبط (nullable — برای تغییرات کیف پول که مرتبط با پکیج هستند)
/// </summary>
public long? PackageId { get; set; }
/// <summary>
/// Package Navigation Property
/// </summary>
public virtual Package? Package { get; set; }
}