Implement Persian Date Conversion and Enhance User Network Information Service
- Added PersianDateTimeService for converting Gregorian dates to Persian format in the BackOffice frontend. - Updated multiple frontend pages (Dashboard, UserPayouts, WorkerControl, UserNetworkInfo) to utilize the new Persian date service. - Enhanced GetUserNetworkPositionDto with 28+ new fields for comprehensive user network data. - Updated GetUserNetworkPositionQueryHandler to include new methods for calculating network statistics. - Modified Protobuf messages to accommodate the new fields, increasing from 14 to 42. - Refined week number calculation algorithm to ensure consistency across C# and SQL implementations. - Created new CSV and Excel files for binary plan calculations. - Ensured all changes are tested and validated for accuracy and performance.
This commit is contained in:
@@ -0,0 +1,317 @@
|
||||
# اصلاحات سیستم کمیسیون هفتگی
|
||||
|
||||
## 📋 خلاصه تغییرات
|
||||
|
||||
سیستم کمیسیون هفتگی از **3 مرحله به 2 مرحله** سادهسازی شد:
|
||||
|
||||
### ❌ قبل (3 مرحله):
|
||||
1. `CalculateWeeklyBalances` - محاسبه تعادلها
|
||||
2. `CalculateWeeklyCommissionPool` - محاسبه استخر
|
||||
3. `ProcessUserPayouts` - پردازش پرداختها (تکراری!)
|
||||
|
||||
### ✅ بعد (2 مرحله):
|
||||
1. `CalculateWeeklyBalances` - محاسبه تعادلها تا 15 لول
|
||||
2. `CalculateWeeklyCommissionPool` - محاسبه استخر + پردازش پرداختها
|
||||
|
||||
---
|
||||
|
||||
## 🔧 تغییرات جزئی
|
||||
|
||||
### 1️⃣ اضافه شدن فیلدها به `NetworkWeeklyBalance`
|
||||
|
||||
**فیلدهای جدید:**
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// مقدار فلش هر طرف (بعد از اعمال Cap)
|
||||
/// </summary>
|
||||
public int FlushedPerSide { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مجموع فلش از دو طرف (از دست رفته)
|
||||
/// </summary>
|
||||
public int TotalFlushed { get; set; }
|
||||
```
|
||||
|
||||
**Migration:** `AddFlushedFieldsToNetworkWeeklyBalance`
|
||||
|
||||
---
|
||||
|
||||
### 2️⃣ اصلاح `CalculateWeeklyBalances`
|
||||
|
||||
**تغییرات:**
|
||||
- ✅ فیلدهای `FlushedPerSide` و `TotalFlushed` ذخیره میشوند
|
||||
- ✅ `WeeklyPoolContribution = 0` (دیگر در این مرحله محاسبه نمیشه)
|
||||
- ✅ محدودیت 15 لول قبلاً موجود بود و درست کار میکند
|
||||
|
||||
**کد:**
|
||||
```csharp
|
||||
// محاسبه فلش
|
||||
var flushedPerSide = totalBalances - cappedBalances;
|
||||
var totalFlushed = flushedPerSide * 2;
|
||||
|
||||
// ذخیره
|
||||
balance.FlushedPerSide = flushedPerSide;
|
||||
balance.TotalFlushed = totalFlushed;
|
||||
balance.WeeklyPoolContribution = 0; // Pool در مرحله بعد محاسبه میشه
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3️⃣ اصلاح کامل `CalculateWeeklyCommissionPool`
|
||||
|
||||
**منطق جدید Pool:**
|
||||
```csharp
|
||||
// 1. Pool از فعالسازیهای باشگاه این هفته میاد (نه از تعادلها)
|
||||
var newClubMembersCount = await _context.ClubMemberships
|
||||
.Where(c => c.ActivatedAt >= startDate && c.ActivatedAt <= endDate)
|
||||
.CountAsync();
|
||||
|
||||
var totalPoolAmount = newClubMembersCount * activationFee;
|
||||
|
||||
// 2. ارزش هر امتیاز
|
||||
var totalBalancesInNetwork = weeklyBalances.Sum(x => x.TotalBalances);
|
||||
var valuePerBalance = totalPoolAmount / totalBalancesInNetwork;
|
||||
```
|
||||
|
||||
**افزوده شدن محاسبه تعادل زیرمجموعه:**
|
||||
```csharp
|
||||
// برای هر کاربر:
|
||||
// 1. تعادل خودش
|
||||
var directBalances = balance.TotalBalances;
|
||||
|
||||
// 2. تعادل زیرمجموعه (تا 15 لول)
|
||||
var subordinateBalances = await CalculateSubordinateBalancesAsync(
|
||||
balance.UserId,
|
||||
request.WeekNumber,
|
||||
maxLevels: 15
|
||||
);
|
||||
|
||||
var totalBalancesForUser = directBalances + subordinateBalances;
|
||||
```
|
||||
|
||||
**ایجاد UserCommissionPayout:**
|
||||
```csharp
|
||||
var payout = new UserCommissionPayout
|
||||
{
|
||||
UserId = balance.UserId,
|
||||
WeekNumber = request.WeekNumber,
|
||||
WeeklyPoolId = existingPool.Id,
|
||||
BalancesEarned = totalBalancesForUser,
|
||||
ValuePerBalance = valuePerBalance,
|
||||
TotalAmount = totalBalancesForUser * valuePerBalance,
|
||||
Status = CommissionPayoutStatus.Pending,
|
||||
// ... subordinate fields
|
||||
};
|
||||
```
|
||||
|
||||
**ثبت تاریخچه:**
|
||||
```csharp
|
||||
var history = new CommissionPayoutHistory
|
||||
{
|
||||
UserId = payout.UserId,
|
||||
PayoutId = payout.Id,
|
||||
Amount = payout.TotalAmount,
|
||||
Status = CommissionPayoutStatus.Pending,
|
||||
ChangeReason = "محاسبه اولیه کمیسیون هفتگی"
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4️⃣ سادهسازی `TriggerWeeklyCalculation`
|
||||
|
||||
**قبل:**
|
||||
```csharp
|
||||
// Step 1
|
||||
await _mediator.Send(new CalculateWeeklyBalancesCommand { ... });
|
||||
|
||||
// Step 2
|
||||
await _mediator.Send(new CalculateWeeklyCommissionPoolCommand { ... });
|
||||
|
||||
// Step 3
|
||||
await _mediator.Send(new ProcessUserPayoutsCommand { ... });
|
||||
```
|
||||
|
||||
**بعد:**
|
||||
```csharp
|
||||
// Step 1: محاسبه تعادلها
|
||||
if (!request.SkipBalances)
|
||||
{
|
||||
await _mediator.Send(new CalculateWeeklyBalancesCommand { ... });
|
||||
}
|
||||
|
||||
// Step 2: محاسبه Pool و پرداختها
|
||||
if (!request.SkipPayouts)
|
||||
{
|
||||
await _mediator.Send(new CalculateWeeklyCommissionPoolCommand { ... });
|
||||
}
|
||||
```
|
||||
|
||||
**حذف شد:**
|
||||
- ❌ `SkipPool` flag
|
||||
- ❌ Step 3 کاملاً حذف شد
|
||||
|
||||
---
|
||||
|
||||
## 🎯 فرآیند نهایی
|
||||
|
||||
### مرحله 1: محاسبه تعادلها
|
||||
```
|
||||
1. برای هر کاربر در شبکه
|
||||
2. تا 15 لول پایینتر شمارش کن
|
||||
3. محاسبه تعادل (MIN of left/right)
|
||||
4. محاسبه باقیمانده
|
||||
5. محاسبه فلش
|
||||
6. ذخیره در NetworkWeeklyBalance
|
||||
```
|
||||
|
||||
### مرحله 2: محاسبه Pool و توزیع
|
||||
```
|
||||
1. شمارش فعالسازیهای باشگاه این هفته
|
||||
2. Pool = تعداد × ActivationFee
|
||||
3. ارزش هر امتیاز = Pool ÷ مجموع تعادلها
|
||||
4. برای هر کاربر:
|
||||
a. تعادل خودش + تعادل زیرمجموعه (تا 15 لول)
|
||||
b. سهم = تعادل × ارزش
|
||||
c. ثبت در UserCommissionPayout
|
||||
d. ثبت تاریخچه
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 جداول درگیر
|
||||
|
||||
### `NetworkWeeklyBalance` (فیلدهای جدید)
|
||||
```sql
|
||||
ALTER TABLE [Network].[NetworkWeeklyBalances]
|
||||
ADD [FlushedPerSide] INT NOT NULL DEFAULT 0,
|
||||
[TotalFlushed] INT NOT NULL DEFAULT 0;
|
||||
```
|
||||
|
||||
### `WeeklyCommissionPool`
|
||||
```
|
||||
- TotalPoolAmount: از فعالسازیهای باشگاه
|
||||
- TotalBalances: مجموع تعادلهای شبکه
|
||||
- ValuePerBalance: Pool ÷ TotalBalances
|
||||
```
|
||||
|
||||
### `UserCommissionPayout`
|
||||
```
|
||||
- BalancesEarned: تعادل خودش + زیرمجموعه
|
||||
- DirectBalances: فقط تعادل خودش
|
||||
- SubordinateBalances: فقط زیرمجموعه
|
||||
- TotalAmount: BalancesEarned × ValuePerBalance
|
||||
- Status: Pending
|
||||
```
|
||||
|
||||
### `CommissionPayoutHistory`
|
||||
```
|
||||
- PayoutId: شناسه UserCommissionPayout
|
||||
- Status: Pending (در این مرحله)
|
||||
- ChangeReason: "محاسبه اولیه کمیسیون هفتگی"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ مزایا
|
||||
|
||||
1. **سادهتر**: 2 مرحله به جای 3
|
||||
2. **بدون تکرار**: دیگر UserCommissionPayout دوبار ساخته نمیشه
|
||||
3. **واضحتر**: Pool از کجا میاد مشخصه
|
||||
4. **قابل نگهداری**: منطق مشابه یکجا هست
|
||||
5. **کامل**: تاریخچه + subordinate balances همه جا هست
|
||||
|
||||
---
|
||||
|
||||
## 🔄 مراحل بعدی (اختیاری)
|
||||
|
||||
### مرحله 3: پرداخت واقعی (جدا از محاسبه)
|
||||
|
||||
میتوان یک Command جدید داشت که:
|
||||
1. `UserCommissionPayout` با status=Pending رو بخونه
|
||||
2. به کیف پول واریز کنه
|
||||
3. Status رو به Paid تغییر بده
|
||||
4. تاریخچه اضافه کنه
|
||||
|
||||
این مرحله **جدا از محاسبات** است و میتواند:
|
||||
- دستی توسط ادمین اجرا شود
|
||||
- یا به صورت خودکار بعد از تایید
|
||||
|
||||
---
|
||||
|
||||
## 📝 نکات مهم
|
||||
|
||||
### Pool چطور پُر میشه؟
|
||||
```
|
||||
1. کاربر عضو Club میشه
|
||||
2. در ActivateClubMembership مبلغی کسر میشه
|
||||
3. این مبلغ به Pool اضافه **نمیشه** (فقط شمارش میشه)
|
||||
4. در محاسبه Pool: تعداد × ActivationFee
|
||||
```
|
||||
|
||||
### چرا subordinate balances؟
|
||||
```
|
||||
در سیستم باینری، کاربر از تعادل زیرمجموعههای خود
|
||||
(تا 15 لول پایینتر) هم کمیسیون میگیرد.
|
||||
```
|
||||
|
||||
### چرا 15 لول؟
|
||||
```
|
||||
محدودیت عمق برای جلوگیری از بارگذاری بیش از حد
|
||||
و تشویق به ایجاد شبکه متعادل
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 تست
|
||||
|
||||
### تست مرحله 1
|
||||
```csharp
|
||||
// 1. ایجاد کاربران در شبکه
|
||||
// 2. فعالسازی Club برای برخی
|
||||
// 3. اجرای CalculateWeeklyBalances
|
||||
// 4. بررسی NetworkWeeklyBalance
|
||||
// - TotalBalances
|
||||
// - FlushedPerSide
|
||||
// - TotalFlushed
|
||||
```
|
||||
|
||||
### تست مرحله 2
|
||||
```csharp
|
||||
// 1. اجرای مرحله 1
|
||||
// 2. اجرای CalculateWeeklyCommissionPool
|
||||
// 3. بررسی WeeklyCommissionPool
|
||||
// - TotalPoolAmount = تعداد فعالسازیها × ActivationFee
|
||||
// - ValuePerBalance صحیح باشد
|
||||
// 4. بررسی UserCommissionPayout
|
||||
// - برای هر کاربر ایجاد شده
|
||||
// - BalancesEarned شامل subordinate هم هست
|
||||
// - TotalAmount = BalancesEarned × ValuePerBalance
|
||||
// 5. بررسی CommissionPayoutHistory
|
||||
// - برای هر پرداخت ثبت شده
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 فایلهای تغییر یافته
|
||||
|
||||
1. ✅ `NetworkWeeklyBalance.cs` - اضافه شدن فیلدها
|
||||
2. ✅ `CalculateWeeklyBalancesCommandHandler.cs` - ذخیره فلش
|
||||
3. ✅ `CalculateWeeklyCommissionPoolCommandHandler.cs` - منطق کامل جدید
|
||||
4. ✅ `TriggerWeeklyCalculationCommandHandler.cs` - حذف مرحله 3
|
||||
5. ✅ `TriggerWeeklyCalculationCommand.cs` - حذف SkipPool flag
|
||||
6. ✅ Migration: `AddFlushedFieldsToNetworkWeeklyBalance`
|
||||
|
||||
---
|
||||
|
||||
## 🎉 نتیجه
|
||||
|
||||
سیستم کمیسیون هفتگی حالا:
|
||||
- ✅ **سادهتر** و قابل فهمتر
|
||||
- ✅ **بدون تکرار** در کد
|
||||
- ✅ **Pool از منبع صحیح** (فعالسازیهای Club)
|
||||
- ✅ **تعادل زیرمجموعه** محاسبه میشه
|
||||
- ✅ **تاریخچه کامل** ثبت میشه
|
||||
- ✅ **فلش دقیق** ذخیره میشه
|
||||
|
||||
آماده برای استفاده در Production! 🚀
|
||||
Reference in New Issue
Block a user