# 🏆 سیستم باشگاه، کمیسیون و درخت شبکه‌ای > **منابع ادغام‌شده:** `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` — هر خرید پکیج = یک دور جدید (برای تاریخ کمیسیون) | --- ## ۲. ساختار درخت باینری ```mermaid 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`) — اما درخت بدون محدودیت رشد می‌کند --- ## ۳. فلوی عضویت و فعالسازی ```mermaid 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["کسر فعالسازی\n−25.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 هفتگی و توزیع ```mermaid 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) | ✅ پیاده‌شده | | **پرداخت دستی** | کارت‌به‌کارت → آپلود رسید → تأیید ادمین → شارژ | ⚠️ طراحی‌شده | --- ## ۷. یکپارچه‌سازی وام دایا ```mermaid 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](../roadmap/MAGIC-WALLET-SPEC.md) ### ۹.۱ چرخه کامل ```mermaid 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‌های جدید ```csharp // فیلدهای جدید 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; } // دور فعلی } ```