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:
masoodafar-web
2025-12-20 06:15:59 +03:30
parent 13a3489765
commit 002e99f6bf
32 changed files with 10263 additions and 106 deletions
+86 -42
View File
@@ -1,16 +1,36 @@
# Balance Calculation with Carryover Logic - Complete Guide
**Date**: 2025-12-01
**Last Updated**: 2025-12-04 (⚠️ تغییر مهم: سقف 300 برای هر دست، نه کل)
**Status**: ✅ Implemented (نیاز به اصلاح سقف دارد)
**Last Updated**: 2025-12-09 (✅ اصلاح نهایی: محاسبات تعادل و فلش)
**Status**: ✅ Fully Implemented & Verified
**Migration**: `UpdateNetworkWeeklyBalanceWithCarryover`
---
## ⚠️ اصلاحیه مهم بیزینس (2025-12-04)
## ✅ آخرین به‌روزرسانی (2025-12-09)
### مشکل شناسایی شده:
در پیاده‌سازی فعلی، سقف تعادل هفتگی **300 کل** در نظر گرفته شده بود. اما طبق قانون صحیح بیزینس:
### تغییرات اعمال شده:
کد محاسبه تعادل با توضیحات دقیق بیزینس تطبیق داده شد:
1.**ترتیب محاسبات اصلاح شد**:
- اول تعادل اولیه محاسبه می‌شود
- بعد باقیمانده (برای هفته بعد)
- سپس سقف 300 اعمال می‌شود
- در نهایت فلش محاسبه می‌شود
2.**فلش از هر دو طرف**:
- اگر تعادل > 300 باشد
- از چپ: (تعادل - 300) فلش می‌شود
- از راست: (تعادل - 300) فلش می‌شود
- جمع فلش = (تعادل - 300) × 2
3.**باقیمانده جداگانه ذخیره می‌شود**:
- `LeftLegRemainder`: باقیمانده دست چپ
- `RightLegRemainder`: باقیمانده دست راست
---
## 📋 قوانین اصلی بیزینس
| توضیح | منطق فعلی (اشتباه) | منطق صحیح |
|-------|---------------------|-----------|
@@ -71,10 +91,10 @@ Key = "Commission.MaxWeeklyBalancesPerLeg", Value = "300"
// تمام مقادیر از جدول SystemConfigurations خوانده می‌شوند
Club.ActivationFee = 25,000,000 ریال (هزینه فعالسازی)
Commission.WeeklyPoolContributionPercent = 20% (سهم استخر)
Commission.MaxWeeklyBalancesPerLeg = 300 ( سقف تعادل هفتگی - هر دست)
Commission.MaxWeeklyBalancesPerLeg = 300 ( سقف امتیاز نهایی)
```
**توجه:** کلید قدیمی `MaxWeeklyBalancesPerUser` باید به `MaxWeeklyBalancesPerLeg` تغییر کند.
**نکته مهم**: سقف 300 روی **امتیاز نهایی** اعمال می‌شود، نه روی تعادل اولیه!
### **Pool Contribution Calculation:**
@@ -90,38 +110,52 @@ weeklyPoolContribution = totalNewMembers × activationFee × poolPercent
---
## 🚫 MaxWeeklyBalances Cap (محدودیت سقف - هر دست)
## 🚫 MaxWeeklyBalances Cap (محدودیت سقف 300)
### **Logic (صحیح):**
### **Logic صحیح (به‌روز شده 2025-12-09):**
```csharp
// ⚠️ سقف روی هر دست جداگانه اعمال می‌شود
cappedLeftTotal = MIN(leftTotal, maxBalancesPerLeg) // 300
cappedRightTotal = MIN(rightTotal, maxBalancesPerLeg) // 300
// ✅ مرحله 1: محاسبه تعادل اولیه (بدون سقف)
totalBalances = MIN(leftTotal, rightTotal)
// تعادل = کمترین مقدار بعد از اعمال سقف
totalBalances = MIN(cappedLeftTotal, cappedRightTotal)
// ✅ مرحله 2: محاسبه باقیمانده برای هفته بعد
leftRemainder = leftTotal - totalBalances
rightRemainder = rightTotal - totalBalances
// باقیمانده = مقدار قبل از سقف - سقف (نه از totalBalances)
leftRemainder = leftTotal - cappedLeftTotal
rightRemainder = rightTotal - cappedRightTotal
// ✅ مرحله 3: اعمال سقف 300 (برای امتیاز نهایی)
cappedBalances = MIN(totalBalances, 300)
// ✅ مرحله 4: محاسبه فلش (از هر دو طرف)
flushedPerSide = totalBalances - cappedBalances
totalFlushed = flushedPerSide × 2
```
### **Example (جدید):**
### **Example (مثال کامل):**
```
Week 5:
leftTotal = 350, rightTotal = 400
maxBalancesPerLeg = 300
leftTotal = 500, rightTotal = 600
cappedLeftTotal = MIN(350, 300) = 300
cappedRightTotal = MIN(400, 300) = 300
مرحله 1️⃣: تعادل اولیه
totalBalances = MIN(500, 600) = 500
totalBalances = MIN(300, 300) = 300 ✅
مرحله 2️⃣: باقیمانده برای هفته بعد
leftRemainder = 500 - 500 = 0 ✅
rightRemainder = 600 - 500 = 100 ✅
// باقیمانده = اضافه‌ای که از سقف رد شده
leftRemainder = 350 - 300 = 50
rightRemainder = 400 - 300 = 100
مرحله 3️⃣: اعمال سقف
cappedBalances = MIN(500, 300) = 300 ✅
مرحله 4️⃣: محاسبه فلش
flushedPerSide = 500 - 300 = 200
از چپ: 200 فلش می‌شود
از راست: 200 فلش می‌شود
totalFlushed = 200 × 2 = 400 ✅
نتیجه نهایی:
✅ امتیاز این هفته: 300
✅ باقیمانده چپ: 0
✅ باقیمانده راست: 100
✅ جمع فلش: 400 (از بین می‌رود)
```
### **مقایسه منطق قدیم vs جدید:**
@@ -147,24 +181,34 @@ leftRemainder = leftTotal - cappedLeftTotal // باقیمانده از سقف
```csharp
// محاسبه تعداد کل اعضا در هر پا
leftLegBalances = CountAllMembers(userId, Left);
rightLegBalances = CountAllMembers(userId, Right);
## **Current (Correct) Logic - Updated 2025-12-09:**
// تعادل = کمترین مقدار
TotalBalances = MIN(leftLegBalances, rightLegBalances);
### **Formula (4 مرحله):**
```
// مرحله 1: جمع با هفته قبل
leftTotal = leftNewMembers + leftCarryover
rightTotal = rightNewMembers + rightCarryover
// مرحله 2: محاسبه تعادل اولیه
totalBalances = MIN(leftTotal, rightTotal)
// مرحله 3: محاسبه باقیمانده برای هفته بعد
leftRemainder = leftTotal - totalBalances
rightRemainder = rightTotal - totalBalances
// مرحله 4: اعمال سقف 300
cappedBalances = MIN(totalBalances, 300)
flushedPerSide = totalBalances - cappedBalances
totalFlushed = flushedPerSide × 2
```
**مشکلات:**
1. تعداد کل اعضا را می‌شمارد (نه فقط جدیدها)
2. باقیمانده هفته قبل را نادیده می‌گیرد
3. هر هفته از صفر شروع می‌کند
---
## ✅ **Current (Correct) Logic:**
### **Formula:**
```
### **Key Principles:**
1. **Only count NEW members** activated in current week
2. **Add carryover** from previous week (جداگانه چپ و راست)
3. **Calculate remainder** for next week (قبل از سقف)
4. **Apply cap 300** on final score (بعد از تعادل)
5. **Flush from both sides** if balance > 300
6. **Recursive counting** through entire tree structure
leftTotal = leftNewMembers + leftCarryover
rightTotal = rightNewMembers + rightCarryover