9.1 KiB
9.1 KiB
اصلاحات سیستم کمیسیون هفتگی
📋 خلاصه تغییرات
سیستم کمیسیون هفتگی از 3 مرحله به 2 مرحله سادهسازی شد:
❌ قبل (3 مرحله):
CalculateWeeklyBalances- محاسبه تعادلهاCalculateWeeklyCommissionPool- محاسبه استخرProcessUserPayouts- پردازش پرداختها (تکراری!)
✅ بعد (2 مرحله):
CalculateWeeklyBalances- محاسبه تعادلها تا 15 لولCalculateWeeklyCommissionPool- محاسبه استخر + پردازش پرداختها
🔧 تغییرات جزئی
1️⃣ اضافه شدن فیلدها به NetworkWeeklyBalance
فیلدهای جدید:
/// <summary>
/// مقدار فلش هر طرف (بعد از اعمال Cap)
/// </summary>
public int FlushedPerSide { get; set; }
/// <summary>
/// مجموع فلش از دو طرف (از دست رفته)
/// </summary>
public int TotalFlushed { get; set; }
Migration: AddFlushedFieldsToNetworkWeeklyBalance
2️⃣ اصلاح CalculateWeeklyBalances
تغییرات:
- ✅ فیلدهای
FlushedPerSideوTotalFlushedذخیره میشوند - ✅
WeeklyPoolContribution = 0(دیگر در این مرحله محاسبه نمیشه) - ✅ محدودیت 15 لول قبلاً موجود بود و درست کار میکند
کد:
// محاسبه فلش
var flushedPerSide = totalBalances - cappedBalances;
var totalFlushed = flushedPerSide * 2;
// ذخیره
balance.FlushedPerSide = flushedPerSide;
balance.TotalFlushed = totalFlushed;
balance.WeeklyPoolContribution = 0; // Pool در مرحله بعد محاسبه میشه
3️⃣ اصلاح کامل CalculateWeeklyCommissionPool
منطق جدید Pool:
// 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;
افزوده شدن محاسبه تعادل زیرمجموعه:
// برای هر کاربر:
// 1. تعادل خودش
var directBalances = balance.TotalBalances;
// 2. تعادل زیرمجموعه (تا 15 لول)
var subordinateBalances = await CalculateSubordinateBalancesAsync(
balance.UserId,
request.WeekNumber,
maxLevels: 15
);
var totalBalancesForUser = directBalances + subordinateBalances;
ایجاد UserCommissionPayout:
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
};
ثبت تاریخچه:
var history = new CommissionPayoutHistory
{
UserId = payout.UserId,
PayoutId = payout.Id,
Amount = payout.TotalAmount,
Status = CommissionPayoutStatus.Pending,
ChangeReason = "محاسبه اولیه کمیسیون هفتگی"
};
4️⃣ سادهسازی TriggerWeeklyCalculation
قبل:
// Step 1
await _mediator.Send(new CalculateWeeklyBalancesCommand { ... });
// Step 2
await _mediator.Send(new CalculateWeeklyCommissionPoolCommand { ... });
// Step 3
await _mediator.Send(new ProcessUserPayoutsCommand { ... });
بعد:
// Step 1: محاسبه تعادلها
if (!request.SkipBalances)
{
await _mediator.Send(new CalculateWeeklyBalancesCommand { ... });
}
// Step 2: محاسبه Pool و پرداختها
if (!request.SkipPayouts)
{
await _mediator.Send(new CalculateWeeklyCommissionPoolCommand { ... });
}
حذف شد:
- ❌
SkipPoolflag - ❌ 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 (فیلدهای جدید)
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: "محاسبه اولیه کمیسیون هفتگی"
✅ مزایا
- سادهتر: 2 مرحله به جای 3
- بدون تکرار: دیگر UserCommissionPayout دوبار ساخته نمیشه
- واضحتر: Pool از کجا میاد مشخصه
- قابل نگهداری: منطق مشابه یکجا هست
- کامل: تاریخچه + subordinate balances همه جا هست
🔄 مراحل بعدی (اختیاری)
مرحله 3: پرداخت واقعی (جدا از محاسبه)
میتوان یک Command جدید داشت که:
UserCommissionPayoutبا status=Pending رو بخونه- به کیف پول واریز کنه
- Status رو به Paid تغییر بده
- تاریخچه اضافه کنه
این مرحله جدا از محاسبات است و میتواند:
- دستی توسط ادمین اجرا شود
- یا به صورت خودکار بعد از تایید
📝 نکات مهم
Pool چطور پُر میشه؟
1. کاربر عضو Club میشه
2. در ActivateClubMembership مبلغی کسر میشه
3. این مبلغ به Pool اضافه **نمیشه** (فقط شمارش میشه)
4. در محاسبه Pool: تعداد × ActivationFee
چرا subordinate balances؟
در سیستم باینری، کاربر از تعادل زیرمجموعههای خود
(تا 15 لول پایینتر) هم کمیسیون میگیرد.
چرا 15 لول؟
محدودیت عمق برای جلوگیری از بارگذاری بیش از حد
و تشویق به ایجاد شبکه متعادل
🧪 تست
تست مرحله 1
// 1. ایجاد کاربران در شبکه
// 2. فعالسازی Club برای برخی
// 3. اجرای CalculateWeeklyBalances
// 4. بررسی NetworkWeeklyBalance
// - TotalBalances
// - FlushedPerSide
// - TotalFlushed
تست مرحله 2
// 1. اجرای مرحله 1
// 2. اجرای CalculateWeeklyCommissionPool
// 3. بررسی WeeklyCommissionPool
// - TotalPoolAmount = تعداد فعالسازیها × ActivationFee
// - ValuePerBalance صحیح باشد
// 4. بررسی UserCommissionPayout
// - برای هر کاربر ایجاد شده
// - BalancesEarned شامل subordinate هم هست
// - TotalAmount = BalancesEarned × ValuePerBalance
// 5. بررسی CommissionPayoutHistory
// - برای هر پرداخت ثبت شده
📚 فایلهای تغییر یافته
- ✅
NetworkWeeklyBalance.cs- اضافه شدن فیلدها - ✅
CalculateWeeklyBalancesCommandHandler.cs- ذخیره فلش - ✅
CalculateWeeklyCommissionPoolCommandHandler.cs- منطق کامل جدید - ✅
TriggerWeeklyCalculationCommandHandler.cs- حذف مرحله 3 - ✅
TriggerWeeklyCalculationCommand.cs- حذف SkipPool flag - ✅ Migration:
AddFlushedFieldsToNetworkWeeklyBalance
🎉 نتیجه
سیستم کمیسیون هفتگی حالا:
- ✅ سادهتر و قابل فهمتر
- ✅ بدون تکرار در کد
- ✅ Pool از منبع صحیح (فعالسازیهای Club)
- ✅ تعادل زیرمجموعه محاسبه میشه
- ✅ تاریخچه کامل ثبت میشه
- ✅ فلش دقیق ذخیره میشه
آماده برای استفاده در Production! 🚀