421a651975
- All 14 totalDoc files updated with Magic Wallet additions - MAGIC-WALLET-PLAN.md: Phase 1-6 checklist fully marked complete - Business docs: Magic Wallet section, commission filter, new entities - Payment docs: VAT 9%→10%, TransactionType 14+15, ZarinPal 4th usage - Technical docs: UserWallet fields, ClubMembershipCycle, gRPC RPCs - Overview docs: Magic flowchart, ER diagram, changelog, glossary, roadmap
237 lines
10 KiB
Markdown
237 lines
10 KiB
Markdown
# 🏆 سیستم باشگاه، کمیسیون و درخت شبکهای
|
||
|
||
> **منابع ادغامشده:** `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; } // دور فعلی
|
||
}
|
||
```
|