docs: fix all discrepancies based on comprehensive code audit
Corrections verified against actual CMS/BackOffice/FrontOffice source code: - ClubActivationFee: 25,200,000 (not 25,000,000) - Tree depth: no limit (15 is commission calculation depth only) - IPG wallet charge: Balance=56M + Discount=56M - DayaLoan wallet charge: Balance=56M + Discount=112M (2×) - Discount: per-product MaxDiscountPercent (not fixed 30%) - VAT: 10% (ShopVAT) vs 9% (discount store PlaceOrder) - Kavenegar template: 'Afrino' only (not verify-foursat) - SMS sender: 1000001110100 - DayaLoan job: every 20min (not 15min) - Commission job: Sunday 00:05 (not Saturday) - Network tree: on User entity (not separate NetworkNode table) - UserWallets entity (not UserWalletBalances) - OTP: 6 digits, 5 attempts, 2min TTL, 60s cooldown - Removed non-existent constants (ClubJoiningPercentage, ClubActivationThreshold) - Fixed Hangfire Chatika interval: every 5min - Removed InventorySync from recurring jobs list
This commit is contained in:
@@ -9,10 +9,10 @@
|
||||
|
||||
| مفهوم | توضیح |
|
||||
|-------|--------|
|
||||
| **عضویت باشگاه** | خرید پکیج طلایی (۵۶M) → فعالسازی (۲۵M) → عضو فعال باشگاه |
|
||||
| **درخت باینری** | هر کاربر حداکثر ۲ فرزند مستقیم (چپ/راست) — حداکثر ۱۵ سطح |
|
||||
| **کمیسیون هفتگی** | محاسبه بر اساس تعادل چپ/راست — هفته شمسی شنبهتاجمعه |
|
||||
| **۳ کیف پول** | `Balance` (نقدی) + `NetworkBalance` (شبکهای) + `DiscountBalance` (تخفیفی) |
|
||||
| **عضویت باشگاه** | خرید پکیج طلایی (۵۶M) → فعالسازی (۲۵.۲M) → عضو فعال باشگاه |
|
||||
| **درخت باینری** | هر کاربر حداکثر ۲ فرزند مستقیم (چپ/راست) — بدون محدودیت عمق |
|
||||
| **کمیسیون هفتگی** | محاسبه بر اساس تعادل چپ/راست — یکشنبه ۰۰:۰۵ (Hangfire cron) |
|
||||
| **۳ کیف پول** | `Balance` (نقدی) + `NetworkBalance` (طلایی/کمیسیون) + `DiscountBalance` (تخفیفی) |
|
||||
|
||||
---
|
||||
|
||||
@@ -25,14 +25,14 @@
|
||||
/ \ / \
|
||||
L1 L2 R1 R2
|
||||
/ \ / \ / \ / \
|
||||
... ... ... ... ... ← حداکثر ۱۵ سطح
|
||||
... ... ... ... ... ← بدون محدودیت عمق
|
||||
```
|
||||
|
||||
**قوانین:**
|
||||
- هر نود حداکثر ۲ فرزند (Binary)
|
||||
- جایگذاری: `LegPosition` ∈ {Left, Right}
|
||||
- عضو جدید → در اولین جای خالی از چپترین مسیر قرار میگیرد
|
||||
- `SP_GetNetworkTree` — Stored Procedure بازگشتی
|
||||
- هر نود حداکثر ۲ فرزند (Binary) — `MaxDirectChildrenPerLeg = 1`
|
||||
- جایگذاری: `LegPosition` ∈ {Left=0, Right=1} (enum `NetworkLeg`)
|
||||
- مدل شبکه مستقیم روی entity `User` — فیلدهای `NetworkParentId`, `LegPosition`, `NetworkChildren`
|
||||
- محاسبه کمیسیون تا عمق ۱۵ سطح (`CommissionMaxNetworkLevel = 15`) — اما درخت بدون محدودیت رشد میکند
|
||||
|
||||
---
|
||||
|
||||
@@ -56,11 +56,16 @@
|
||||
▼
|
||||
امضای قرارداد ← AcceptContract
|
||||
│
|
||||
├─→ شارژ ۳ کیف پول (Balance=56M, Network=56M, Discount=56M)
|
||||
├─→ کسر هزینه فعالسازی (25M از Balance)
|
||||
├─→ واریز 25.2M به Pool هفتگی
|
||||
├─→ شارژ ۲ کیف پول: Balance += 56M, DiscountBalance += 56M
|
||||
│ (NetworkBalance شارژ نمیشود — فقط برای کمیسیون)
|
||||
├─→ کسر هزینه فعالسازی (25.2M از Balance)
|
||||
├─→ واریز 25.2M به Pool هفتگی (ClubActivationFee)
|
||||
├─→ قرارگیری در درخت باینری
|
||||
└─→ رفرش JWT Token (claims جدید)
|
||||
|
||||
⚠️ در خرید با وام دایا:
|
||||
├─→ Balance += 56M
|
||||
└─→ DiscountBalance += 112M (دو برابر — DayaLoanAmount × 2)
|
||||
```
|
||||
|
||||
---
|
||||
@@ -109,17 +114,18 @@ SP: sp_CalculateWeeklyBalances → sp_CalculateWeeklyCommissionPool
|
||||
|
||||
## ۵. تنظیمات سیستمی (SystemConstants)
|
||||
|
||||
| ثابت | مقدار | توضیح |
|
||||
| ثابت (SystemConstants) | مقدار | توضیح |
|
||||
|------|-------|--------|
|
||||
| `Club.ActivationFee` | 25,000,000 | هزینه فعالسازی (تومان) |
|
||||
| `Club.GiftValue` | 25,200,000 | واریز به Pool |
|
||||
| `GoldenPackageAmount` | 56,000,000 | قیمت پکیج طلایی |
|
||||
| `DayaLoanAmount` | 56,000,000 | مبلغ وام دایا |
|
||||
| `MaxWeeklyBalancesPerLeg` | 300 | سقف هفتگی هر پا |
|
||||
| `MaxNetworkLevel` | 15 | حداکثر عمق درخت |
|
||||
| `ClubJoiningPercentage` | 0.35 | درصد پیوستن |
|
||||
| `ClubActivationThreshold` | 0.5 | آستانه فعالسازی |
|
||||
| `MaxCalculationAttempts` | 3 | حداکثر تلاش محاسبه |
|
||||
| `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%) | مالیات ارزش افزوده |
|
||||
| `CommissionCalculationMethod` | "SP" | روش محاسبه = Stored Procedure |
|
||||
|
||||
---
|
||||
|
||||
@@ -127,8 +133,8 @@ SP: sp_CalculateWeeklyBalances → sp_CalculateWeeklyCommissionPool
|
||||
|
||||
| سناریو | فلو | وضعیت |
|
||||
|--------|------|--------|
|
||||
| **وام دایا** | درخواست وام → تأیید خودکار → شارژ ۳ کیفپول (۱۶۸M) | ✅ پیادهشده |
|
||||
| **درگاه مستقیم** | IPG (ZarinPal) → callback → شارژ | ✅ پیادهشده |
|
||||
| **وام دایا** | درخواست وام → تأیید → Balance=56M + Discount=112M (مجموع ۱۶۸M) | ✅ پیادهشده |
|
||||
| **درگاه مستقیم** | IPG → callback → Balance=56M + Discount=56M (مجموع ۱۱۲M) | ✅ پیادهشده |
|
||||
| **پرداخت دستی** | کارتبهکارت → آپلود رسید → تأیید ادمین → شارژ | ⚠️ طراحیشده |
|
||||
|
||||
---
|
||||
@@ -136,7 +142,7 @@ SP: sp_CalculateWeeklyBalances → sp_CalculateWeeklyCommissionPool
|
||||
## ۷. یکپارچهسازی وام دایا
|
||||
|
||||
```
|
||||
Hangfire Worker (هر ۱۵ دقیقه)
|
||||
Hangfire Worker (هر ۲۰ دقیقه — cron: */20 * * * *)
|
||||
│
|
||||
▼
|
||||
بررسی درخواستهای pending
|
||||
@@ -145,13 +151,13 @@ Hangfire Worker (هر ۱۵ دقیقه)
|
||||
ارسال به API دایا (Mock/Real switchable)
|
||||
│
|
||||
▼
|
||||
دریافت نتیجه → شارژ ۳ کیفپول
|
||||
دریافت نتیجه → شارژ ۲ کیفپول
|
||||
│
|
||||
├─→ Balance = 56M
|
||||
├─→ NetworkBalance = 56M
|
||||
└─→ DiscountBalance = 56M (مجموع: 168M)
|
||||
├─→ Balance += 56M (DayaLoanAmount)
|
||||
└─→ DiscountBalance += 112M (DayaLoanAmount × 2 — دو برابر)
|
||||
مجموع: 168M
|
||||
|
||||
Polly Retry: 3 attempts, Exponential backoff
|
||||
Hangfire retry: [AutomaticRetry(Attempts = 3)]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -63,7 +63,7 @@ Redirect کاربر → صفحه پرداخت ZarinPal
|
||||
### ۳.۱ معماری
|
||||
|
||||
```
|
||||
Hangfire Recurring Job (هر ۱۵ دقیقه)
|
||||
Hangfire Recurring Job (هر ۲۰ دقیقه — cron: */20 * * * *)
|
||||
│
|
||||
▼
|
||||
DayaLoanProcessorJob.Execute()
|
||||
@@ -73,10 +73,10 @@ DayaLoanProcessorJob.Execute()
|
||||
│
|
||||
▼
|
||||
برای هر درخواست:
|
||||
├─→ ارسال به DayaLoan API (با Polly retry ×3)
|
||||
├─→ در صورت تأیید: شارژ ۳ کیفپول (هرکدام ۵۶M)
|
||||
├─→ ارسال به DayaLoan API ([AutomaticRetry(Attempts=3)])
|
||||
├─→ در صورت تأیید: Balance += 56M, DiscountBalance += 112M (2×)
|
||||
├─→ ثبت Transaction + Log
|
||||
└─→ در صورت رد: بروزرسانی Status=Rejected + ارسال SMS
|
||||
└─→ در صورت رد: Status=Rejected + ارسال SMS
|
||||
```
|
||||
|
||||
### ۳.۲ Mock Mode
|
||||
@@ -95,9 +95,11 @@ DayaLoanProcessorJob.Execute()
|
||||
|
||||
| آیتم | مقدار |
|
||||
|------|-------|
|
||||
| مبلغ وام | ۵۶,۰۰۰,۰۰۰ تومان |
|
||||
| شارژ هر کیفپول | ۵۶,۰۰۰,۰۰۰ تومان |
|
||||
| مجموع شارژ | ۱۶۸,۰۰۰,۰۰۰ تومان |
|
||||
| مبلغ وام (DayaLoanAmount) | ۵۶,۰۰۰,۰۰۰ ریال |
|
||||
| شارژ Balance | ۵۶,۰۰۰,۰۰۰ ریال |
|
||||
| شارژ DiscountBalance | ۱۱۲,۰۰۰,۰۰۰ ریال (دو برابر — DayaLoanAmount × 2) |
|
||||
| مجموع شارژ | ۱۶۸,۰۰۰,۰۰۰ ریال |
|
||||
| NetworkBalance | شارژ نمیشود |
|
||||
| بازپرداخت | طبق شرایط دایا |
|
||||
|
||||
---
|
||||
@@ -134,13 +136,15 @@ DayaLoanProcessorJob.Execute()
|
||||
### ۵.۱ فرمول
|
||||
|
||||
```
|
||||
قیمت محصول = 1,000,000 تومان
|
||||
تخفیف باشگاه = 30%
|
||||
قیمت محصول = 1,000,000 ریال
|
||||
MaxDiscountPercent محصول = 40% (هر محصول درصد تخفیف مخصوص خود را دارد)
|
||||
|
||||
پرداخت از DiscountBalance = 1,000,000 × 0.30 = 300,000
|
||||
پرداخت نقدی (IPG) = 1,000,000 × 0.70 = 700,000
|
||||
سهم تخفیف = MIN(1,000,000 × 40%, DiscountBalanceکاربر) = 400,000
|
||||
پرداخت نقدی (IPG) = 1,000,000 - 400,000 = 600,000
|
||||
─────────
|
||||
مجموع = 1,000,000
|
||||
|
||||
ℹ️ تخفیف ثابت ۳۰% نیست — فیلد Product.MaxDiscountPercent (0-100) تعیینکننده است.
|
||||
```
|
||||
|
||||
### ۵.۲ فلوی خرید فروشگاه تخفیفی
|
||||
@@ -204,7 +208,11 @@ service PaymentService {
|
||||
## ۷. مالیات و VAT
|
||||
|
||||
```
|
||||
VAT = 10% (configurable via SystemConstants)
|
||||
دو نرخ VAT در کد:
|
||||
|
||||
SystemConstants.ShopVAT = 0.1 (10%) — تنظیم سیستمی
|
||||
VAT_RATE = 0.09 (9%) — در فروشگاه تخفیفی (DiscountShop PlaceOrder)
|
||||
|
||||
قیمت نمایشی = قیمت پایه × (1 + VAT)
|
||||
در صورتحساب: قیمت پایه + مالیات جداگانه نمایش داده میشود
|
||||
```
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
├───────────────────────┼─────────────────────────────────┤
|
||||
│ • همه کاربران │ • فقط اعضای باشگاه │
|
||||
│ • پرداخت 100% نقدی │ • پرداخت ترکیبی (تخفیف+نقد) │
|
||||
│ • قیمت عادی │ • تخفیف ۳۰% از DiscountBalance │
|
||||
│ • بدون محدودیت │ • وابسته به موجودی تخفیفی │
|
||||
│ • قیمت عادی │ • تخفیف بر اساس MaxDiscountPercent │
|
||||
│ • VAT = 10% │ • VAT = 9% (در کد PlaceOrder) │
|
||||
├───────────────────────┴─────────────────────────────────┤
|
||||
│ Shared: Products, Categories, │
|
||||
│ Inventory, ProductImages (1:1 square) │
|
||||
@@ -93,6 +93,9 @@ public class Inventory {
|
||||
public int MinimumStock { get; set; } // حداقل موجودی (هشدار)
|
||||
public bool TrackInventory { get; set; } // آیا موجودی رصد شود؟
|
||||
}
|
||||
|
||||
// فیلد کلیدی در Product:
|
||||
public int MaxDiscountPercent { get; set; } // 0 تا 100 — درصد تخفیف در فروشگاه تخفیفی
|
||||
```
|
||||
|
||||
### ۳.۳ فلوی سفارش و موجودی
|
||||
|
||||
@@ -63,10 +63,12 @@ JWT Claims:
|
||||
|
||||
| مشکل | راهحل | وضعیت |
|
||||
|------|---------|--------|
|
||||
| OTP تکراری | Rate limiting: ۱ درخواست هر ۶۰ ثانیه | ✅ |
|
||||
| OTP تکراری | Cooldown: ۶۰ ثانیه بین درخواستها | ✅ |
|
||||
| شماره نامعتبر | Regex validation ایران `^09\d{9}$` | ✅ |
|
||||
| حمله brute-force | قفل حساب بعد از ۵ تلاش ناموفق | ✅ |
|
||||
| Race condition ثبتنام | Unique constraint + transaction | ✅ |
|
||||
| حمله brute-force | MaxAttempts: ۵ تلاش برای تأیید کد | ✅ |
|
||||
| انقضای کد | TTL: ۲ دقیقه | ✅ |
|
||||
| طول کد | ۶ رقم | ✅ |
|
||||
| قالب SMS | Kavenegar template: `Afrino` | ✅ |
|
||||
|
||||
---
|
||||
|
||||
@@ -136,15 +138,15 @@ RequestContractOtp → ارسال SMS
|
||||
### ۴.۲ ذخیرهسازی قرارداد
|
||||
|
||||
```csharp
|
||||
// از کد: UserContract : BaseAuditableEntity
|
||||
public class UserContract {
|
||||
public Guid Id { get; set; }
|
||||
public Guid UserId { get; set; }
|
||||
public string ContractVersion { get; set; } // e.g., "v1.2"
|
||||
public string ContractText { get; set; } // snapshot متن
|
||||
public DateTime AcceptedAt { get; set; }
|
||||
public string OtpVerificationId { get; set; }
|
||||
public string IpAddress { get; set; }
|
||||
public string UserAgent { get; set; }
|
||||
public long UserId { get; set; }
|
||||
public virtual User User { get; set; }
|
||||
public long ContractId { get; set; } // FK → Contract
|
||||
public virtual Contract Contract { get; set; }
|
||||
public string SignGuid { get; set; } // GUID یکتای امضا
|
||||
public string SignedPdfFile { get; set; } // فایل PDF امضاشده
|
||||
// فیلدهای BaseAuditableEntity: CreatedAt, ModifiedAt, ...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -132,13 +132,9 @@ FileManagementService → ذخیره در فایلسیستم + ثبت در DB
|
||||
{
|
||||
"Kavenegar": {
|
||||
"ApiKey": "***",
|
||||
"SenderNumber": "10008663",
|
||||
"Templates": {
|
||||
"OTP": "verify-foursat",
|
||||
"ContractOTP": "contract-verify",
|
||||
"WelcomeClub": "club-welcome",
|
||||
"OrderConfirm": "order-confirm"
|
||||
}
|
||||
"SenderNumber": "1000001110100",
|
||||
"DefaultTemplate": "Afrino",
|
||||
"_note": "تمام OTPها با قالب Afrino ارسال میشوند"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -183,16 +179,17 @@ CREATE TABLE SystemConfigurations (
|
||||
|
||||
| Category | Key | Value | توضیح |
|
||||
|----------|-----|-------|--------|
|
||||
| Club | `Club.ActivationFee` | 25000000 | هزینه فعالسازی |
|
||||
| Club | `Club.GiftValue` | 25200000 | واریز Pool |
|
||||
| Club | `GoldenPackageAmount` | 56000000 | قیمت پکیج طلایی |
|
||||
| Club | `MaxNetworkLevel` | 15 | حداکثر عمق درخت |
|
||||
| Club | `MaxWeeklyBalance` | 300 | سقف هفتگی |
|
||||
| Payment | `VAT.Percentage` | 10 | مالیات ارزش افزوده |
|
||||
| Payment | `DayaLoanAmount` | 56000000 | مبلغ وام |
|
||||
| Store | `DiscountPercentage` | 30 | تخفیف باشگاه |
|
||||
| Store | `ProductsPerPage` | 12 | تعداد در صفحه |
|
||||
| System | `SmsProvider` | Kavenegar | ارائهدهنده SMS |
|
||||
| Club | `ClubActivationFee` | 25200000 | هزینه فعالسازی (ریال) |
|
||||
| Club | `ClubMembershipGiftValue` | 25200000 | واریز Pool |
|
||||
| Club | `BasePackageAmount` | 56000000 | قیمت پکیج طلایی (ریال) |
|
||||
| Club | `CommissionMaxNetworkLevel` | 15 | عمق محاسبه کمیسیون |
|
||||
| Club | `CommissionMaxWeeklyBalancesPerLeg` | 300 | سقف هفتگی |
|
||||
| Payment | `ShopVAT` | 0.1 (10%) | مالیات (فروشگاه تخفیفی: 9%) |
|
||||
| Payment | `DayaLoanAmount` | 56000000 | مبلغ وام (ریال) |
|
||||
| Payment | `MinimumWithdrawAmount` | 1000000 | حداقل برداشت (ریال) |
|
||||
| Store | `MaxDiscountPercent` | per-product | 0-100، هر محصول جداگانه |
|
||||
| Store | `ProductsPerPage` | 12 (FO) / 10 (CMS) | تعداد در صفحه |
|
||||
| System | `CommissionCalculationMethod` | "SP" | Stored Procedure |
|
||||
| System | `MaintenanceMode` | false | حالت تعمیر |
|
||||
|
||||
---
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
│ ├──────────┬──────────┬──────────┬─────────────┤ │
|
||||
│ │ فروشگاه │ درخت شبکه │ کمیسیون │ Chatika AI │ │
|
||||
│ │ تخفیفی │ باینری │ هفتگی │ │ │
|
||||
│ │ (30%↓) │ │ │ │ │
|
||||
│ │ (per-product) │ │ │ │ │
|
||||
│ └──────────┴──────────┴──────────┴─────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
@@ -56,15 +56,17 @@
|
||||
│ [Daya Loan] ──→ ├──→ [PYMS Service] ──→ [DB Transaction] │
|
||||
│ [Manual Pay] ──→ ┘ │ │
|
||||
│ ▼ │
|
||||
│ ═══════════ توزیع به ۳ کیفپول ═══════════ │
|
||||
│ ═══════════ توزیع به کیفپولها ═══════════ │
|
||||
│ │
|
||||
│ ┌────────────────┐ ┌─────────────────┐ ┌──────────────────┐ │
|
||||
│ │ 💰 Balance │ │ 🌐 NetworkBal │ │ 🏷️ DiscountBal │ │
|
||||
│ │ (نقدی) │ │ (شبکهای) │ │ (تخفیفی) │ │
|
||||
│ │ 💰 Balance │ │ 🌟 NetworkBal │ │ 🏷️ DiscountBal │ │
|
||||
│ │ (نقدی) │ │ (طلایی/کمیسیون)│ │ (تخفیفی) │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │ • خرید فروشگاه │ │ • محاسبه │ │ • فروشگاه تخفیفی │ │
|
||||
│ │ • هزینه فعالسازی │ │ کمیسیون │ │ • سهم 30% از │ │
|
||||
│ │ (25M) │ │ • سقف 300/هفته │ │ قیمت محصول │ │
|
||||
│ │ • IPG: +56M │ │ • شارژ نمیشود │ │ • IPG: +56M │ │
|
||||
│ │ • Daya: +56M │ │ • فقط برای │ │ • Daya: +112M │ │
|
||||
│ │ • فعالسازی │ │ محاسبه │ │ (دو برابر) │ │
|
||||
│ │ -25.2M │ │ کمیسیون │ │ • per-product │ │
|
||||
│ │ • خرید فروشگاه │ │ • سقف 300/هفته │ │ MaxDiscount% │ │
|
||||
│ └───────┬────────┘ └────────┬────────┘ └────────┬─────────┘ │
|
||||
│ │ │ │ │
|
||||
│ ▼ ▼ ▼ │
|
||||
@@ -163,7 +165,8 @@ Legend:
|
||||
R = Right leg sales this week
|
||||
Active = فعال (contract signed)
|
||||
Pend. = در انتظار فعالسازی
|
||||
Max depth = 15 levels
|
||||
شبکه روی entity User مدل شده (NetworkParentId, LegPosition)
|
||||
محاسبه کمیسیون تا عمق 15 سطح — درخت بدون محدودیت عمق
|
||||
```
|
||||
|
||||
---
|
||||
@@ -188,8 +191,8 @@ Legend:
|
||||
│ │ │ [بررسی DiscountBalance] │
|
||||
│ ▼ │ │ │
|
||||
│ [Checkout] │ ▼ │
|
||||
│ │ │ [محاسبه سهم تخفیف (30%)] │
|
||||
│ ▼ │ [محاسبه سهم نقدی (70%)] │
|
||||
│ │ │ [محاسبه سهم تخفیف (MaxDiscount%)]│
|
||||
│ ▼ │ [محاسبه سهم نقدی (باقیمانده)] │
|
||||
│ [ZarinPal IPG] │ │ │
|
||||
│ [100% نقدی] │ ▼ │
|
||||
│ │ │ [کسر از DiscountBalance] │
|
||||
@@ -242,17 +245,23 @@ Legend:
|
||||
## ۷. Entity Relationship (سادهشده)
|
||||
|
||||
```
|
||||
┌──────────┐ ┌──────────────┐ ┌──────────────┐
|
||||
│ User │────→│ ClubMembership│────→│ NetworkNode │
|
||||
│ │ │ │ │ (BinaryTree)│
|
||||
└────┬─────┘ └──────────────┘ └──────────────┘
|
||||
┌──────────┐ ┌──────────────┐
|
||||
│ User │────→│ ClubMembership│
|
||||
│ +Network │ │ │
|
||||
│ ParentId│ └──────────────┘
|
||||
│ +LegPos │
|
||||
└────┬─────┘
|
||||
│
|
||||
├────→ ┌──────────┐ ┌──────────┐
|
||||
│ │ Order │────→│ OrderItem│────→ [Product]
|
||||
│ └──────────┘ └──────────┘
|
||||
│
|
||||
├────→ ┌──────────────┐
|
||||
│ │ Transaction │────→ [Wallet (×3)]
|
||||
│ │ Transaction │
|
||||
│ └──────────────┘
|
||||
│
|
||||
├────→ ┌──────────────┐
|
||||
│ │ UserWallet │────→ Balance + NetworkBalance + DiscountBalance
|
||||
│ └──────────────┘
|
||||
│
|
||||
├────→ ┌──────────────┐
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
| Pool هفتگی | Weekly Commission Pool | مخزن کمیسیون قابلتوزیع |
|
||||
| هزینه فعالسازی | Activation Fee | ۲۵M تومان از Balance |
|
||||
| واریز هدیه | Gift Value | ۲۵.۲M واریز به Pool |
|
||||
| فروشگاه تخفیفی | Discount Store | فروشگاه ۳۰% تخفیف برای اعضا |
|
||||
| فروشگاه تخفیفی | Discount Store | فروشگاه با تخفیف per-product برای اعضا |
|
||||
| پرداخت ترکیبی | Hybrid Payment | DiscountBalance + IPG |
|
||||
| وام دایا | Daya Loan | وام آنلاین برای خرید پکیج |
|
||||
| کد معرف | Referral Code | کد یکتا هر عضو برای دعوت |
|
||||
@@ -39,9 +39,9 @@
|
||||
| درگاه پرداخت | Payment Gateway (IPG) | ZarinPal |
|
||||
| سرویس پرداخت | PYMS | Payment Management Service |
|
||||
| کیفپول نقدی | Balance Wallet | موجودی قابلخرج |
|
||||
| کیفپول شبکهای | Network Balance | برای محاسبه کمیسیون |
|
||||
| کیفپول تخفیفی | Discount Balance | برای فروشگاه تخفیفی |
|
||||
| بارگذاری تنبل | Lazy Loading | لود محصولات ۱۲تایی |
|
||||
| کیفپول طلایی | Network Balance | برای محاسبه کمیسیون (شارژ نمیشود) |
|
||||
| کیفپول تخفیفی | Discount Balance | برای فروشگاه تخفیفی (Daya: 112M, IPG: 56M) |
|
||||
| بارگذاری تنبل | Lazy Loading | لود محصولات 12تایی (FO) / 10تایی (CMS default) |
|
||||
| صفحات سایت | Site Pages | صفحات قابلویرایش (Shopify-style) |
|
||||
| ثوابت سیستمی | System Constants | تنظیمات key-value |
|
||||
| پردازش پسزمینه | Background Job | Hangfire recurring/fire-and-forget |
|
||||
|
||||
@@ -163,16 +163,16 @@ Engine: MSSQL 2022-CU16, Collation=Arabic_CI_AS
|
||||
|
||||
| جدول | توضیح | رکوردهای تقریبی |
|
||||
|------|--------|----------------|
|
||||
| Users | کاربران | ~5K |
|
||||
| Products | محصولات | ~200 |
|
||||
| Users | کاربران + فیلدهای شبکه (NetworkParentId, LegPosition) | ~5K |
|
||||
| Products | محصولات (+ MaxDiscountPercent) | ~200 |
|
||||
| Categories | دستهبندیها | ~30 |
|
||||
| Orders | سفارشات | ~2K |
|
||||
| Inventories | موجودی | ~200 |
|
||||
| BlogPosts | پستهای بلاگ | ~50 |
|
||||
| SitePages | صفحات سایت | ~10 |
|
||||
| UserClubMemberships | عضویت باشگاه | ~500 |
|
||||
| UserContracts | قراردادها | ~500 |
|
||||
| NetworkNodes | نودهای درخت باینری | ~500 |
|
||||
| UserContracts | قراردادها (SignGuid, SignedPdfFile) | ~500 |
|
||||
| UserWallets | کیفپول (Balance, NetworkBalance, DiscountBalance) | ~5K |
|
||||
| Transactions | تراکنشها | ~5K |
|
||||
| SystemConfigurations | تنظیمات | ~30 |
|
||||
| ChatMessages | پیامهای چاتیکا | ~1K |
|
||||
@@ -225,12 +225,11 @@ FrontOffice Service Layer:
|
||||
|
||||
## ۷. Hangfire Jobs
|
||||
|
||||
| Job | فرکانس | کاربرد |
|
||||
| Job | فرکانس (cron) | کاربرد |
|
||||
|-----|---------|--------|
|
||||
| `DayaLoanProcessorJob` | هر ۱۵ دقیقه | پردازش درخواستهای وام |
|
||||
| `WeeklyCommissionJob` | هفتگی (شنبه ۰۰:۰۰) | محاسبه و توزیع کمیسیون |
|
||||
| `ChatikaJob` | هر ۵ دقیقه | همگامسازی پیامهای AI |
|
||||
| `InventorySyncJob` | هر ساعت | ایجاد رکوردهای موجودی گمشده |
|
||||
| `WeeklyCommissionCalculation` | `5 0 * * 0` (یکشنبه ۰۰:۰۵) | محاسبه و توزیع کمیسیون |
|
||||
| `DayaLoanProcessorJob` | `*/20 * * * *` (هر ۲۰ دقیقه) | پردازش درخواستهای وام |
|
||||
| `ChatikaAccountActivation` | `*/5 * * * *` (هر ۵ دقیقه) | فعالسازی حساب چاتیکا |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -162,8 +162,8 @@ DataMigration/
|
||||
| `dbo.Products` | `CMS.Products` | ImageUrl migration needed |
|
||||
| `dbo.Orders` | `CMS.Orders` | Status enum remapping |
|
||||
| `dbo.Categories` | `CMS.Categories` | Hierarchical → ParentId |
|
||||
| `dbo.NetworkTree` | `CMS.NetworkNodes` | Binary tree reconstruction |
|
||||
| `dbo.Wallets` | `CMS.UserWalletBalances` | ۳ wallet types split |
|
||||
| `dbo.NetworkTree` | `CMS.Users` | Binary tree via NetworkParentId + LegPosition روی User |
|
||||
| `dbo.Wallets` | `CMS.UserWallets` | ۳ wallet types: Balance, NetworkBalance, DiscountBalance |
|
||||
| `dbo.Transactions` | `CMS.Transactions` | Type enum remapping |
|
||||
| `dbo.Memberships` | `CMS.UserClubMemberships` | + Contract creation |
|
||||
|
||||
|
||||
@@ -176,10 +176,9 @@ public class ZarinPalService : IPaymentGateway
|
||||
```csharp
|
||||
public class KavenegarService : ISmsService
|
||||
{
|
||||
// Templates
|
||||
const string OTP_TEMPLATE = "verify-foursat";
|
||||
const string CONTRACT_TEMPLATE = "contract-verify";
|
||||
const string WELCOME_TEMPLATE = "club-welcome";
|
||||
// Templates — فقط یک تمپلیت در کد موجود است
|
||||
const string OTP_TEMPLATE = "Afrino"; // تنها تمپلیت استفادهشده
|
||||
// Sender: "1000001110100"
|
||||
|
||||
// Rate Limiting
|
||||
// ۱ SMS per phone per 60 seconds
|
||||
@@ -198,7 +197,7 @@ public class KavenegarService : ISmsService
|
||||
```csharp
|
||||
public class DayaLoanService : ILoanService
|
||||
{
|
||||
// Hangfire job — هر ۱۵ دقیقه
|
||||
// Hangfire job — هر ۲۰ دقیقه (*/20 * * * *)
|
||||
// Polly retry: 3 attempts, exponential backoff (2s, 4s, 8s)
|
||||
// Mock mode for staging (auto-approve)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user