Files
docs/business/BUSINESS-01-CLUB-COMMISSION.md
T
masoodafar-web f5173a4def docs: فعال‌سازی درگاه ZarinPal + مرج پروداکشن + بهبود UI ادمین
- CHANGELOG: اضافه Phase 18 BackOffice + فعال‌سازی درگاه FO + تنظیمات محیطی CMS + مرج پروداکشن
- PAYMENT-FINANCE: MerchantId واقعی + تنظیمات محیطی Staging/Production + Magic فاز 6 کامل
- ROADMAP: بروزرسانی درصدها + Magic 100% + Payment 97% + DONE section
- TECH-02: ساختار فولدر + UserAutoComplete + WalletManagement + دکمه‌های درگاه
- BUSINESS-01: Magic Wallet فاز 1-6 کامل
- TECH-04: Migration پروداکشن ExpandDiscountProductFullInformation + حذف u21 تکراری
- TECH-03: جزئیات مرج پروداکشن + تنظیمات appsettings.Production.json
- MAGIC-WALLET-PLAN: وضعیت کامل
- INDEX: بروزرسانی تاریخ
2026-02-22 23:26:36 +03:30

10 KiB
Raw Blame History

🏆 سیستم باشگاه، کمیسیون و درخت شبکه‌ای

منابع ادغام‌شده: club-commission-system-complete.md, balance-calculation-rules.md, club-membership-contract-system.md
آخرین بروزرسانی: اسفند ۱۴۰۴ (بروزرسانی: Magic Wallet کامل + بهبود مدیریت اعضا)


۱. مفاهیم کلیدی

مفهوم توضیح
عضویت باشگاه خرید پکیج طلایی (۵۶M) → فعالسازی (۲۵.۲M) → عضو فعال باشگاه
درخت باینری هر کاربر حداکثر ۲ فرزند مستقیم (چپ/راست) — بدون محدودیت عمق
کمیسیون هفتگی محاسبه بر اساس تعادل چپ/راست — یکشنبه ۰۰:۰۵ (Hangfire cron)
۳ کیف پول Balance (نقدی) + NetworkBalance (طلایی/کمیسیون) + DiscountBalance (اعتباری)
کیف‌پول جادویی وقتی Balance=0 → حالت Magic فعال → شارژ ×2.5 → سقف 100M/دور
چرخه عضویت ClubMembershipCycle — هر خرید پکیج = یک دور جدید (برای تاریخ کمیسیون)

۲. ساختار درخت باینری

graph TD
    ROOT["Root"] --- L["Left"]
    ROOT --- R["Right"]
    L --- L1["L1"] & L2["L2"]
    R --- R1["R1"] & R2["R2"]
    L1 --- L1a["..."] & L1b["..."]
    L2 --- L2a["..."] & L2b["..."]
    R1 --- R1a["..."] & R1b["..."]
    R2 --- R2a["..."] & R2b["..."]

← بدون محدودیت عمق

قوانین:

  • هر نود حداکثر ۲ فرزند (Binary) — MaxDirectChildrenPerLeg = 1
  • جایگذاری: LegPosition ∈ {Left=0, Right=1} (enum NetworkLeg)
  • مدل شبکه مستقیم روی entity User — فیلدهای NetworkParentId, LegPosition, NetworkChildren
  • محاسبه کمیسیون تا عمق ۱۵ سطح (CommissionMaxNetworkLevel = 15) — اما درخت بدون محدودیت رشد می‌کند

۳. فلوی عضویت و فعالسازی

flowchart TD
    A["خرید پکیج طلایی — 56M"] --> B["نمایش مودال قرارداد\nغیرقابل‌بسته‌شدن"]
    B --> C["مشاهده متن قرارداد\nReadContract RPC"]
    C --> D["درخواست OTP\nRequestContractOtp — Kavenegar"]
    D --> E["وارد کردن کد\nVerifyContractOtp"]
    E --> F["امضای قرارداد\nAcceptContract"]

    F --> G["شارژ ۲ کیف‌پول\nBalance += 56M\nDiscountBalance += 112M"]
    F --> H["کسر فعالسازی\n25.2M از Balance"]
    F --> I["واریز 25.2M\nبه Pool هفتگی"]
    F --> J["قرارگیری در\nدرخت باینری"]
    F --> K["رفرش JWT Token\nclaims جدید"]

⚠️ در خرید با وام دایا: Balance += 56M, DiscountBalance += 112M (DayaLoanAmount × 2)
NetworkBalance شارژ نمی‌شود — فقط برای کمیسیون


۴. الگوریتم محاسبه کمیسیون هفتگی

۴.۱ فرمول ۴ مرحله‌ای

مرحله ۱: جمع فروش هر پا
  SumLeft  = Σ(فروش‌های پای چپ در هفته جاری + CanOverLeft)
  SumRight = Σ(فروش‌های پای راست در هفته جاری + CanOverRight)

مرحله ۲: محاسبه تعادل
  WeeklyBalance = MIN(SumLeft, SumRight)

مرحله ۳: محاسبه باقیمانده (Carryover)
  CanOverLeft  = SumLeft  - WeeklyBalance
  CanOverRight = SumRight - WeeklyBalance

مرحله ۴: سقف هفتگی
  IF WeeklyBalance > 300  →  WeeklyBalance = 300
  IF CanOverLeft > 300    →  Flush (CanOverLeft = 0)
  IF CanOverRight > 300   →  Flush (CanOverRight = 0)

۴.۲ مثال عددی (درخت ۵ سطحی)

هفته ۱:  چپ=120, راست=80  →  Balance=80, Over(L=40, R=0)
هفته ۲:  چپ=90+40=130, راست=150  →  Balance=130, Over(L=0, R=20)
هفته ۳:  چپ=200, راست=180+20=200  →  Balance=200, Over(L=0, R=0)
هفته ۴:  چپ=500, راست=100  →  Balance=100, Over(L=400→FLUSH=0, R=0)

۴.۳ Pool هفتگی و توزیع

flowchart LR
    A["هر فعالسازی عضو\n25.2M واریز"] --> B["Pool هفتگی"]
    B --> C["sp_CalculateWeeklyBalances"]
    C --> D["sp_CalculateWeeklyCommissionPool"]
    D --> E["توزیع بر اساس\nUserBalance / TotalBalance"]

فرمت هفته: YYYY-Www (شمسی، شنبه‌پایه)

۴.۴ فیلتر کاربران Magic از کمیسیون

⚠️ کاربرانی که در حالت Magic هستند (WalletMode = 1) از محاسبات کمیسیون هفتگی خارج می‌شوند.

فیلتر در ۳ نقطه:
  ✅ CalculateWeeklyBalancesCommandHandler.cs  →  WHERE wallet.WalletMode != Magic
  ✅ OrmCommissionCalculationStrategy.cs       →  فیلتر LINQ
  ✅ sp_CalculateWeeklyBalances.sql            →  NOT EXISTS (WalletMode=1)

تاریخ محاسبه:
  قبل:  ClubMembership.ActivatedAt (مشکل: بعد از خرید مجدد overwrite می‌شد)
  بعد:  ClubMembershipCycle.PackagePurchasedAt (هر دور تاریخ مستقل)

۵. تنظیمات سیستمی (SystemConstants)

ثابت (SystemConstants) مقدار توضیح
ClubActivationFee 25,200,000 هزینه فعالسازی (ریال)
ClubMembershipGiftValue 25,200,000 واریز به Pool
BasePackageAmount 56,000,000 قیمت پکیج طلایی (ریال)
DayaLoanAmount 56,000,000 مبلغ وام دایا (ریال)
CommissionMaxWeeklyBalancesPerLeg 300 سقف هفتگی هر پا
CommissionMaxNetworkLevel 15 عمق محاسبه کمیسیون (نه محدودیت درخت)
MaxDirectChildrenPerLeg 1 حداکثر فرزند مستقیم هر پا
MinimumWithdrawAmount 1,000,000 حداقل مبلغ برداشت (ریال)
ShopVAT 0.1 (10%) مالیات ارزش افزوده
MagicWalletMultiplier 2.5 ضریب شارژ جادویی (واریز × 2.5)
MagicWalletMaxDeposit 1,000,000,000 سقف واریز هر دور (100M تومان = 1B ریال)
MagicWalletMaxCredit 2,500,000,000 سقف اعتبار هر دور (250M تومان)
CommissionCalculationMethod "SP" روش محاسبه = Stored Procedure

۶. ۳ سناریوی خرید پکیج طلایی

سناریو فلو وضعیت
وام دایا درخواست وام → تأیید → Balance=56M + Discount=112M (مجموع ۱۶۸M) پیاده‌شده
درگاه مستقیم IPG → callback → Balance=56M + Discount=112M (مجموع ۱۶۸M) پیاده‌شده
پرداخت دستی کارت‌به‌کارت → آپلود رسید → تأیید ادمین → شارژ ⚠️ طراحی‌شده

۷. یکپارچه‌سازی وام دایا

flowchart TD
    A["Hangfire Worker\nهر ۲۰ دقیقه — */20 * * * *"] --> B["بررسی درخواست‌های pending"]
    B --> C["ارسال به API دایا\nMock/Real switchable"]
    C --> D["دریافت نتیجه"]
    D --> E["Balance += 56M"]
    D --> F["DiscountBalance += 112M\nDayaLoanAmount × 2"]

مجموع شارژ: 168M — Hangfire retry: [AutomaticRetry(Attempts = 3)]


۸. Chatika AI — اولین فیچر باشگاه

آیتم جزئیات
نوع Hangfire recurring job
فرکانس هر ۵ دقیقه
Retry Polly — ۳ تلاش، backoff نمایی
فعال‌سازی فقط برای اعضای فعال باشگاه
وضعیت Production ready

۹. کیف‌پول جادویی (Magic Wallet)

وضعیت: فاز ۱ تا ۵ پیاده‌سازی شده — فاز ۶ باقیمانده
مرجع کامل: MAGIC-WALLET-SPEC

۹.۱ چرخه کامل

flowchart TD
    A["خرید پکیج 56M\nBalance=56M, Discount=112M"] --> B["خرید از فروشگاه\nBalance کم می‌شود"]
    B --> C{"Balance = 0?"}
    C -->|خیر| B
    C -->|بله| D{"عضو باشگاه فعال؟"}
    D -->|خیر| E["حالت عادی باقی بمان"]
    D -->|بله| F["🪄 ورود به حالت جادویی\nWalletMode = Magic"]
    F --> G["شارژ از درگاه\nواریز × 2.5 = اعتبار Balance"]
    G --> H{"Balance=0 AND\nTotalDeposited≥100M?"}
    H -->|خیر| G
    H -->|بله| I["خروج از جادویی\nWalletMode = Normal"]
    I --> J["خرید مجدد پکیج\nفقط IPG — بدون دایا"]
    J --> A

۹.۲ قوانین کلیدی

قانون مقدار
ضریب شارژ واریز × 2.5 = اعتبار Balance
سقف واریز/دور 100M تومان (1B ریال)
سقف اعتبار/دور 250M تومان (2.5B ریال)
کمیسیون در Magic غیرفعال
شرط خروج Balance=0 و TotalDeposited≥100M (هر دو همزمان)
ریست سقف هر خرید مجدد پکیج → سقف از صفر

۹.۳ Entity‌های جدید

// فیلدهای جدید UserWallet
public WalletMode WalletMode { get; set; }           // Normal=0, Magic=1
public long MagicTotalDeposited { get; set; }         // مجموع واریزی دور فعلی
public long MagicTotalCredited { get; set; }          // مجموع اعتبار دریافتی
public DateTime? MagicActivatedAt { get; set; }
public DateTime? MagicCompletedAt { get; set; }

// Entity جدید — حل مشکل تاریخ کمیسیون
public class ClubMembershipCycle {
    public long Id { get; set; }
    public long ClubMembershipId { get; set; }
    public int CycleNumber { get; set; }               // شماره دور (1, 2, 3, ...)
    public DateTime PackagePurchasedAt { get; set; }   // تاریخ خرید این دور
    public bool IsCurrentCycle { get; set; }           // دور فعلی
}