002e99f6bf
- 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.
311 lines
9.3 KiB
Markdown
311 lines
9.3 KiB
Markdown
# مستندات سیستم کمیسیون (Commission System)
|
|
|
|
> **آخرین بروزرسانی**: ۲۹ آذر ۱۴۰۴ (19 December 2025)
|
|
|
|
---
|
|
|
|
## 📋 خلاصه
|
|
|
|
سیستم کمیسیون مسئول محاسبه، ذخیره و پرداخت کمیسیونهای کاربران بر اساس ساختار شبکه بازاریابی است.
|
|
|
|
---
|
|
|
|
## 🗄️ موجودیتها (Entities)
|
|
|
|
### WeekDefinition
|
|
جدول مرجع برای تعریف هفتههای مالی:
|
|
|
|
```csharp
|
|
public class WeekDefinition : BaseAuditableEntity
|
|
{
|
|
public int WeekOrder { get; set; } // شماره ترتیبی هفته
|
|
public int Year { get; set; } // سال میلادی
|
|
public int PersianYear { get; set; } // سال شمسی
|
|
public DateTime StartDate { get; set; } // تاریخ شروع
|
|
public DateTime EndDate { get; set; } // تاریخ پایان
|
|
public string StartDatePersian { get; set; } // تاریخ شروع شمسی
|
|
public string EndDatePersian { get; set; } // تاریخ پایان شمسی
|
|
public bool IsActive { get; set; } // آیا هفته جاری است
|
|
}
|
|
```
|
|
|
|
### NetworkWeeklyBalance
|
|
تعادل هفتگی شاخه چپ و راست کاربر:
|
|
|
|
```csharp
|
|
public class NetworkWeeklyBalance : BaseAuditableEntity
|
|
{
|
|
public long UserId { get; set; }
|
|
public long WeekDefinitionId { get; set; } // FK به WeekDefinition
|
|
public long LeftBalance { get; set; } // امتیاز شاخه چپ
|
|
public long RightBalance { get; set; } // امتیاز شاخه راست
|
|
|
|
// Navigation Properties
|
|
public virtual User User { get; set; }
|
|
public virtual WeekDefinition WeekDefinition { get; set; }
|
|
}
|
|
```
|
|
|
|
**Index**: `(UserId, WeekDefinitionId)` - Unique
|
|
|
|
### WeeklyCommissionPool
|
|
استخر کمیسیون هفتگی:
|
|
|
|
```csharp
|
|
public class WeeklyCommissionPool : BaseAuditableEntity
|
|
{
|
|
public long WeekDefinitionId { get; set; } // FK به WeekDefinition
|
|
public long TotalPoolAmount { get; set; } // مجموع استخر
|
|
public long DistributedAmount { get; set; } // مقدار توزیع شده
|
|
public int TotalBalances { get; set; } // تعداد کل تعادلها
|
|
public long PerBalanceAmount { get; set; } // مبلغ هر تعادل
|
|
public bool IsFinalized { get; set; } // آیا نهایی شده
|
|
|
|
// Navigation Property
|
|
public virtual WeekDefinition WeekDefinition { get; set; }
|
|
}
|
|
```
|
|
|
|
### UserCommissionPayout
|
|
رکورد پرداخت کمیسیون به کاربر:
|
|
|
|
```csharp
|
|
public class UserCommissionPayout : BaseAuditableEntity
|
|
{
|
|
public long UserId { get; set; }
|
|
public long WeekDefinitionId { get; set; } // FK به WeekDefinition
|
|
public int BalancesEarned { get; set; } // تعداد تعادلهای کسب شده
|
|
public long Amount { get; set; } // مبلغ کمیسیون
|
|
public CommissionPayoutStatus Status { get; set; } // وضعیت پرداخت
|
|
public DateTime? PaidAt { get; set; } // تاریخ پرداخت
|
|
|
|
// Navigation Properties
|
|
public virtual User User { get; set; }
|
|
public virtual WeekDefinition WeekDefinition { get; set; }
|
|
}
|
|
```
|
|
|
|
**وضعیتها (Status)**:
|
|
- `Created` - ایجاد شده
|
|
- `Paid` - پرداخت به کیف پول
|
|
- `WithdrawalRequested` - درخواست برداشت
|
|
- `Withdrawn` - برداشت شده
|
|
- `Cancelled` - لغو شده
|
|
|
|
### CommissionPayoutHistory
|
|
تاریخچه تغییرات وضعیت پرداخت:
|
|
|
|
```csharp
|
|
public class CommissionPayoutHistory : BaseAuditableEntity
|
|
{
|
|
public long UserCommissionPayoutId { get; set; }
|
|
public long WeekDefinitionId { get; set; } // FK به WeekDefinition
|
|
public CommissionPayoutStatus FromStatus { get; set; }
|
|
public CommissionPayoutStatus ToStatus { get; set; }
|
|
public string? Notes { get; set; }
|
|
|
|
// Navigation Properties
|
|
public virtual UserCommissionPayout UserCommissionPayout { get; set; }
|
|
public virtual WeekDefinition WeekDefinition { get; set; }
|
|
}
|
|
```
|
|
|
|
### WorkerExecutionLog
|
|
لاگ اجرای Worker های محاسبه کمیسیون:
|
|
|
|
```csharp
|
|
public class WorkerExecutionLog : BaseAuditableEntity
|
|
{
|
|
public string WorkerName { get; set; } // نام Worker
|
|
public long? WeekDefinitionId { get; set; } // FK به WeekDefinition (nullable)
|
|
public DateTime StartedAt { get; set; } // زمان شروع
|
|
public DateTime? CompletedAt { get; set; } // زمان پایان
|
|
public bool IsSuccess { get; set; } // موفقیت
|
|
public string? ErrorMessage { get; set; } // پیام خطا
|
|
public int ProcessedCount { get; set; } // تعداد پردازش شده
|
|
|
|
// Navigation Property
|
|
public virtual WeekDefinition? WeekDefinition { get; set; }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🔗 روابط (Relationships)
|
|
|
|
```
|
|
WeekDefinition (1) ─────┬──── (*) NetworkWeeklyBalance
|
|
├──── (*) WeeklyCommissionPool
|
|
├──── (*) UserCommissionPayout
|
|
├──── (*) CommissionPayoutHistory
|
|
└──── (*) WorkerExecutionLog
|
|
|
|
User (1) ───────────────┬──── (*) NetworkWeeklyBalance
|
|
└──── (*) UserCommissionPayout
|
|
|
|
UserCommissionPayout (1) ──── (*) CommissionPayoutHistory
|
|
```
|
|
|
|
---
|
|
|
|
## 📡 Proto Models
|
|
|
|
### UserCommissionPayoutModel
|
|
```protobuf
|
|
message UserCommissionPayoutModel {
|
|
int64 id = 1;
|
|
int64 user_id = 2;
|
|
string user_full_name = 3;
|
|
int64 week_definition_id = 4; // شناسه هفته
|
|
int32 balances_earned = 5; // تعداد تعادل
|
|
int64 amount = 6; // مبلغ
|
|
int32 status = 7; // وضعیت
|
|
google.protobuf.Timestamp paid_at = 8;
|
|
google.protobuf.Timestamp created = 9;
|
|
string mobile = 10;
|
|
string week_display_name = 11; // نام نمایشی هفته
|
|
}
|
|
```
|
|
|
|
### UserWeeklyBalanceModel
|
|
```protobuf
|
|
message UserWeeklyBalanceModel {
|
|
int64 user_id = 1;
|
|
int64 week_definition_id = 2; // شناسه هفته
|
|
int64 left_balance = 3;
|
|
int64 right_balance = 4;
|
|
string start_date_persian = 5;
|
|
string end_date_persian = 6;
|
|
int32 year = 7;
|
|
int32 week_order = 8;
|
|
bool is_active = 9;
|
|
string week_display_name = 10; // نام نمایشی هفته
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 نامگذاری فیلدها
|
|
|
|
### قبل از مایگریشن (Legacy)
|
|
```
|
|
WeekNumber: "2025-01" (string)
|
|
GregorianWeekNumber: "2025-01" (string)
|
|
PersianWeekNumber: "1403-40" (string)
|
|
WeekLabel: "هفته 1 - 1403/10/01"
|
|
```
|
|
|
|
### بعد از مایگریشن (Current)
|
|
```
|
|
WeekDefinitionId: 42 (long) // FK به جدول WeekDefinition
|
|
WeekDisplayName: "هفته 1 - 1403/10/01" // ساخته شده از WeekDefinition
|
|
```
|
|
|
|
**فرمول WeekDisplayName**:
|
|
```csharp
|
|
$"هفته {WeekDefinition.WeekOrder} - {WeekDefinition.StartDatePersian}"
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Query Examples
|
|
|
|
### دریافت کمیسیونهای کاربر
|
|
```csharp
|
|
var payouts = await _context.UserCommissionPayouts
|
|
.Include(p => p.WeekDefinition)
|
|
.Where(p => p.UserId == userId)
|
|
.OrderByDescending(p => p.WeekDefinition.WeekOrder)
|
|
.Select(p => new {
|
|
p.Id,
|
|
p.WeekDefinitionId,
|
|
WeekDisplayName = $"هفته {p.WeekDefinition.WeekOrder} - {p.WeekDefinition.StartDatePersian}",
|
|
p.BalancesEarned,
|
|
p.Amount,
|
|
p.Status
|
|
})
|
|
.ToListAsync();
|
|
```
|
|
|
|
### دریافت تعادل هفتگی
|
|
```csharp
|
|
var balance = await _context.NetworkWeeklyBalances
|
|
.Include(b => b.WeekDefinition)
|
|
.Where(b => b.UserId == userId && b.WeekDefinitionId == weekDefinitionId)
|
|
.Select(b => new {
|
|
b.WeekDefinitionId,
|
|
WeekDisplayName = $"هفته {b.WeekDefinition.WeekOrder} - {b.WeekDefinition.StartDatePersian}",
|
|
b.LeftBalance,
|
|
b.RightBalance,
|
|
b.WeekDefinition.StartDatePersian,
|
|
b.WeekDefinition.EndDatePersian
|
|
})
|
|
.FirstOrDefaultAsync();
|
|
```
|
|
|
|
---
|
|
|
|
## ⚠️ ملاحظات مایگریشن
|
|
|
|
### EF Migration
|
|
```bash
|
|
# ایجاد migration
|
|
dotnet ef migrations add MigrateWeekNumberToWeekDefinitionId \
|
|
-p CMSMicroservice.Infrastructure \
|
|
-s CMSMicroservice.WebApi
|
|
|
|
# اجرای migration
|
|
dotnet ef database update \
|
|
-p CMSMicroservice.Infrastructure \
|
|
-s CMSMicroservice.WebApi
|
|
```
|
|
|
|
### Data Migration Script
|
|
```sql
|
|
-- Step 1: Add new column
|
|
ALTER TABLE NetworkWeeklyBalances ADD WeekDefinitionId BIGINT NULL;
|
|
|
|
-- Step 2: Populate from WeekDefinitions
|
|
UPDATE nwb
|
|
SET nwb.WeekDefinitionId = wd.Id
|
|
FROM NetworkWeeklyBalances nwb
|
|
INNER JOIN WeekDefinitions wd ON
|
|
CONCAT(wd.Year, '-', RIGHT('0' + CAST(wd.WeekOrder AS VARCHAR), 2)) = nwb.WeekNumber;
|
|
|
|
-- Step 3: Add FK constraint
|
|
ALTER TABLE NetworkWeeklyBalances
|
|
ADD CONSTRAINT FK_NetworkWeeklyBalances_WeekDefinitions
|
|
FOREIGN KEY (WeekDefinitionId) REFERENCES WeekDefinitions(Id);
|
|
|
|
-- Step 4: Drop old column (after verification)
|
|
ALTER TABLE NetworkWeeklyBalances DROP COLUMN WeekNumber;
|
|
```
|
|
|
|
---
|
|
|
|
## 📝 تغییرات API
|
|
|
|
### Request Changes
|
|
```
|
|
// قبل
|
|
GET /api/commission/payouts?weekNumber=2025-01
|
|
|
|
// بعد
|
|
GET /api/commission/payouts?weekDefinitionId=42
|
|
```
|
|
|
|
### Response Changes
|
|
```json
|
|
// قبل
|
|
{
|
|
"weekNumber": "2025-01",
|
|
"weekLabel": "هفته 1 - 1403/10/01"
|
|
}
|
|
|
|
// بعد
|
|
{
|
|
"weekDefinitionId": 42,
|
|
"weekDisplayName": "هفته 1 - 1403/10/01"
|
|
}
|
|
```
|