20 KiB
محاسبات پلن باینری (Binary Plan Calculations)
مستندات فرمولهای محاسبه کمیسیون باینری
این سند فرمولهای محاسباتی سیستم کمیسیون باینری را که از فایل اکسل استخراج شده، توضیح میدهد.
متغیرها و تعاریف
ورودیهای هفته قبل (Last Week Remainders)
| نام فارسی | نماد | توضیحات |
|---|---|---|
| باقیمانده هفته قبل چپ | LL (Last Left) |
باقیماندهای که از هفته قبل در پای چپ باقی مانده |
| باقیمانده هفته قبل راست | LR (Last Right) |
باقیماندهای که از هفته قبل در پای راست باقی مانده |
مثال از اکسل:
LL = 200(میلیون ریال)LR = 0
ورودیهای هفته جدید (New Week Values)
| نام فارسی | نماد | توضیحات |
|---|---|---|
| هفته جدید چپ | NL (New Left) |
مجموع فروش/شارژ پای چپ در هفته جاری |
| هفته جدید راست | NR (New Right) |
مجموع فروش/شارژ پای راست در هفته جاری |
مثال از اکسل:
NL = 400(میلیون ریال)NR = 500(میلیون ریال)
پارامتر سیستم (System Parameter)
| نام فارسی | نماد | توضیحات |
|---|---|---|
| ماکسیمم تعادل | MX (Maximum Balance) |
حداکثر مقداری که در یک هفته میتواند به عنوان تعادل (کمیسیون) محاسبه شود |
مثال از اکسل:
MX = 300(میلیون ریال)
نکته مهم: این مقدار معمولاً بر اساس سطح کاربر یا پکیج خریداری شده تعیین میشود.
فرمولهای محاسباتی
1️⃣ محاسبه مجموع پا چپ (Sum Left Total)
SLT = LL + NL
توضیح:
SLT(Sum Left Total) = مجموع کل پای چپ- باقیمانده هفته قبل + فروش هفته جدید
مثال:
SLT = 200 + 400 = 600
2️⃣ محاسبه مجموع پا راست (Sum Right Total)
SRT = LR + NR
توضیح:
SRT(Sum Right Total) = مجموع کل پای راست- باقیمانده هفته قبل + فروش هفته جدید
مثال:
SRT = 0 + 500 = 500
3️⃣ محاسبه کمترین کل (Minimum Total)
MinT = MIN(SLT, SRT)
توضیح:
MinT= کوچکترین مقدار بین دو پا- این مقدار نشاندهنده حداکثر تعادل بالقوه است
مثال:
MinT = MIN(600, 500) = 500
4️⃣ محاسبه باقیمانده هفته بعد چپ (Remainder Next Week Left)
RNWL = SLT - MinT
توضیح:
RNWL(Remainder Next Week Left) = باقیماندهای که به هفته بعد منتقل میشود- مازاد پای چپ که برای تعادل استفاده نشد
مثال:
RNWL = 600 - 500 = 100
5️⃣ محاسبه باقیمانده هفته بعد راست (Remainder Next Week Right)
RNWR = SRT - MinT
توضیح:
RNWR(Remainder Next Week Right) = باقیماندهای که به هفته بعد منتقل میشود- مازاد پای راست که برای تعادل استفاده نشد
مثال:
RNWR = 500 - 500 = 0
نکته: یکی از دو باقیمانده همیشه صفر است (چون MinT کوچکترین است).
6️⃣ محاسبه فلش چپ (Flush Left)
FL = SLT - MX - RNWL
توضیح:
FL(Flush Left) = مقداری که از ماکسیمم هم بیشتر بود و باید دور ریخته شود- این مقدار نشاندهنده سرریز (overflow) است که نمیتواند به هفته بعد منتقل شود
مثال:
FL = 600 - 300 - 100 = 200
معنی: از 600 میلیون پای چپ:
- 300 به عنوان کمیسیون استفاده شد (تا حد MX)
- 100 به هفته بعد منتقل شد
- 200 فلش شد (از دست رفت) ❌
7️⃣ محاسبه فلش راست (Flush Right)
FR = SRT - MX - RNWR
توضیح:
FR(Flush Right) = مقداری که از پای راست دور ریخته میشود
مثال:
FR = 500 - 300 - 0 = 200
معنی: از 500 میلیون پای راست:
- 300 به عنوان کمیسیون استفاده شد
- 0 به هفته بعد منتقل شد
- 200 فلش شد (از دست رفت) ❌
8️⃣ محاسبه کل تعادل (Total Balance / Commission)
TB = IF(MinT > MX, MX, MinT)
یا به زبان سادهتر:
TB = MIN(MinT, MX)
توضیح:
TB(Total Balance) = مقدار واقعی کمیسیونی که به کاربر تعلق میگیرد- نمیتواند از ماکسیمم تعادل (
MX) بیشتر شود
مثال:
TB = MIN(500, 300) = 300
معنی: هرچند تعادل واقعی 500 بود، اما به دلیل محدودیت MX، فقط 300 به عنوان کمیسیون پرداخت میشود.
خلاصه جریان محاسبات
┌─────────────────────────────────────────────────────────────┐
│ ورودیها │
├─────────────────────────────────────────────────────────────┤
│ LL = 200 باقیمانده هفته قبل چپ │
│ LR = 0 باقیمانده هفته قبل راست │
│ NL = 400 هفته جدید چپ │
│ NR = 500 هفته جدید راست │
│ MX = 300 ماکسیمم تعادل │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ گام 1: محاسبه مجموع دو پا │
├─────────────────────────────────────────────────────────────┤
│ SLT = LL + NL = 200 + 400 = 600 │
│ SRT = LR + NR = 0 + 500 = 500 │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ گام 2: محاسبه کمترین کل │
├─────────────────────────────────────────────────────────────┤
│ MinT = MIN(SLT, SRT) = MIN(600, 500) = 500 │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ گام 3: محاسبه کمیسیون واقعی (با اعمال Cap) │
├─────────────────────────────────────────────────────────────┤
│ TB = MIN(MinT, MX) = MIN(500, 300) = 300 ✅ کمیسیون │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ گام 4: محاسبه باقیمانده هفته بعد │
├─────────────────────────────────────────────────────────────┤
│ RNWL = SLT - MinT = 600 - 500 = 100 → هفته بعد │
│ RNWR = SRT - MinT = 500 - 500 = 0 → هفته بعد │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ گام 5: محاسبه فلش (از دست رفته) │
├─────────────────────────────────────────────────────────────┤
│ FL = SLT - MX - RNWL = 600 - 300 - 100 = 200 ❌ فلش │
│ FR = SRT - MX - RNWR = 500 - 300 - 0 = 200 ❌ فلش │
└─────────────────────────────────────────────────────────────┘
تحلیل نتایج
📊 خروجیهای نهایی
| مقدار | توضیح | وضعیت |
|---|---|---|
| TB = 300 | کمیسیون پرداختی این هفته | ✅ پرداخت میشود |
| RNWL = 100 | باقیمانده پای چپ برای هفته بعد | ⏭️ منتقل میشود |
| RNWR = 0 | باقیمانده پای راست برای هفته بعد | ⏭️ منتقل میشود |
| FL = 200 | فلش پای چپ | ❌ از دست میرود |
| FR = 200 | فلش پای راست | ❌ از دست میرود |
🔍 تفسیر کسبوکار
کمیسیون محاسبه شده
کمیسیون = 300 میلیون ریال
- به دلیل محدودیت
MX = 300، از تعادل بالقوه 500، فقط 300 قابل برداشت است - این یک مکانیزم کنترل هزینه است
باقیمانده به هفته بعد
هفته بعد LL = 100 (از پای چپ)
هفته بعد LR = 0 (از پای راست)
- 100 میلیون از پای چپ به هفته بعد منتقل میشود
- این باقیمانده در محاسبات هفته آینده دوباره استفاده خواهد شد
فلش (Flush) - نکته مهم ⚠️
فلش کل = 400 میلیون ریال (200 چپ + 200 راست)
چرا فلش رخ میدهد؟
- مجموع دو پا = 1100 میلیون (600 + 500)
- کمیسیون محاسبه شده = 300 میلیون
- باقیمانده منتقل شده = 100 میلیون
- فلش = 1100 - 300 - 100 = 700 میلیون ❌
توضیح:
- فلش نشاندهنده مقداری است که به دلیل عدم تعادل و محدودیت Cap از دست میرود
- این یک ضرر برای کاربر است که میتواند با متعادل کردن دو پا کاهش یابد
پیادهسازی در C#
کلاس مدل
public class BinaryPlanCalculationInput
{
// ورودیهای هفته قبل
public decimal LastLeftRemainder { get; set; } // LL
public decimal LastRightRemainder { get; set; } // LR
// ورودیهای هفته جاری
public decimal NewLeftVolume { get; set; } // NL
public decimal NewRightVolume { get; set; } // NR
// تنظیمات سیستم
public decimal MaximumBalance { get; set; } // MX
}
public class BinaryPlanCalculationResult
{
// محاسبات واسط
public decimal SumLeftTotal { get; set; } // SLT
public decimal SumRightTotal { get; set; } // SRT
public decimal MinimumTotal { get; set; } // MinT
// باقیماندهها
public decimal RemainderNextWeekLeft { get; set; } // RNWL
public decimal RemainderNextWeekRight { get; set; } // RNWR
// فلش
public decimal FlushLeft { get; set; } // FL
public decimal FlushRight { get; set; } // FR
// نتیجه نهایی
public decimal TotalBalance { get; set; } // TB - کمیسیون واقعی
public decimal TotalFlush { get; set; } // مجموع فلش
}
متد محاسبه
public static BinaryPlanCalculationResult Calculate(BinaryPlanCalculationInput input)
{
var result = new BinaryPlanCalculationResult();
// گام 1: محاسبه مجموع دو پا
result.SumLeftTotal = input.LastLeftRemainder + input.NewLeftVolume;
result.SumRightTotal = input.LastRightRemainder + input.NewRightVolume;
// گام 2: محاسبه کمترین کل
result.MinimumTotal = Math.Min(result.SumLeftTotal, result.SumRightTotal);
// گام 3: محاسبه کمیسیون واقعی (با اعمال Cap)
result.TotalBalance = Math.Min(result.MinimumTotal, input.MaximumBalance);
// گام 4: محاسبه باقیمانده هفته بعد
result.RemainderNextWeekLeft = result.SumLeftTotal - result.MinimumTotal;
result.RemainderNextWeekRight = result.SumRightTotal - result.MinimumTotal;
// گام 5: محاسبه فلش
result.FlushLeft = result.SumLeftTotal - input.MaximumBalance - result.RemainderNextWeekLeft;
result.FlushRight = result.SumRightTotal - input.MaximumBalance - result.RemainderNextWeekRight;
// محاسبه مجموع فلش
result.TotalFlush = result.FlushLeft + result.FlushRight;
// اطمینان از عدم منفی شدن فلش
result.FlushLeft = Math.Max(0, result.FlushLeft);
result.FlushRight = Math.Max(0, result.FlushRight);
result.TotalFlush = Math.Max(0, result.TotalFlush);
return result;
}
مثال استفاده
var input = new BinaryPlanCalculationInput
{
LastLeftRemainder = 200_000_000, // 200 میلیون
LastRightRemainder = 0,
NewLeftVolume = 400_000_000, // 400 میلیون
NewRightVolume = 500_000_000, // 500 میلیون
MaximumBalance = 300_000_000 // 300 میلیون
};
var result = Calculate(input);
Console.WriteLine($"کمیسیون قابل پرداخت: {result.TotalBalance:N0} ریال");
// Output: کمیسیون قابل پرداخت: 300,000,000 ریال
Console.WriteLine($"باقیمانده چپ هفته بعد: {result.RemainderNextWeekLeft:N0} ریال");
// Output: باقیمانده چپ هفته بعد: 100,000,000 ریال
Console.WriteLine($"باقیمانده راست هفته بعد: {result.RemainderNextWeekRight:N0} ریال");
// Output: باقیمانده راست هفته بعد: 0 ریال
Console.WriteLine($"فلش کل: {result.TotalFlush:N0} ریال");
// Output: فلش کل: 400,000,000 ریال
نکات مهم برای پیادهسازی
1️⃣ ذخیره باقیماندهها
// باید در دیتابیس ذخیره شود
await SaveWeeklyRemainders(userId, weekId, new WeeklyRemainders
{
LeftRemainder = result.RemainderNextWeekLeft,
RightRemainder = result.RemainderNextWeekRight
});
2️⃣ لاگ فلش برای تحلیل
if (result.TotalFlush > 0)
{
await LogFlush(userId, weekId, new FlushLog
{
FlushLeft = result.FlushLeft,
FlushRight = result.FlushRight,
Reason = "Cap limitation and imbalance"
});
}
3️⃣ تعیین MaximumBalance
// بر اساس سطح کاربر
decimal GetMaximumBalance(User user)
{
return user.MembershipLevel switch
{
MembershipLevel.Bronze => 100_000_000,
MembershipLevel.Silver => 300_000_000,
MembershipLevel.Gold => 500_000_000,
MembershipLevel.Platinum => 1_000_000_000,
_ => 50_000_000
};
}
4️⃣ واحد پول
// همه مقادیر باید در واحد ریال ذخیره شوند
// برای نمایش میتوان به میلیون یا تومان تبدیل کرد
decimal DisplayInMillions(decimal rials) => rials / 1_000_000;
decimal DisplayInTomans(decimal rials) => rials / 10;
سناریوهای مختلف
سناریو 1: تعادل کامل
LL = 0, LR = 0, NL = 300, NR = 300, MX = 500
→ TB = 300, RNWL = 0, RNWR = 0, FL = 0, FR = 0
نتیجه: کمیسیون کامل بدون فلش ✅
سناریو 2: یک پا خیلی بیشتر
LL = 0, LR = 0, NL = 1000, NR = 100, MX = 500
→ TB = 100, RNWL = 900, RNWR = 0, FL = 400, FR = 0
نتیجه: کمیسیون کم + فلش زیاد ❌
سناریو 3: باقیمانده قبلی موثر
LL = 400, LR = 0, NL = 100, NR = 400, MX = 300
→ SLT = 500, SRT = 400
→ TB = 300, RNWL = 100, RNWR = 0, FL = 100, FR = 100
نتیجه: باقیمانده قبلی در محاسبه کمیسیون موثر است ✅
تفاوت با کد فعلی
در کد فعلی (CalculateWeeklyBalancesCommandHandler.cs):
// 1. ابتدا Cap اعمال میشود
var cappedLeft = Math.Min(leftLegTotal, maxBalance);
var cappedRight = Math.Min(rightLegTotal, maxBalance);
// 2. سپس تعادل محاسبه میشود
var balance = Math.Min(cappedLeft, cappedRight);
// 3. باقیماندهها محاسبه میشوند
var leftRemainder = leftLegTotal - balance;
var rightRemainder = rightLegTotal - balance;
در فرمول اکسل:
// 1. ابتدا تعادل کامل محاسبه میشود
var minTotal = Math.Min(leftLegTotal, rightLegTotal);
// 2. سپس Cap اعمال میشود
var balance = Math.Min(minTotal, maxBalance);
// 3. باقیماندهها بر اساس minTotal محاسبه میشوند
var leftRemainder = leftLegTotal - minTotal;
var rightRemainder = rightLegTotal - minTotal;
// 4. فلش محاسبه میشود
var flushLeft = leftLegTotal - maxBalance - leftRemainder;
var flushRight = rightLegTotal - maxBalance - rightRemainder;
تفاوت کلیدی:
- کد فعلی Cap را ابتدا اعمال میکند (میتواند باقیماندههای بیشتری ایجاد کند)
- فرمول اکسل ابتدا تعادل را محاسبه میکند، سپس Cap اعمال میشود (فلش دقیقتر محاسبه میشود)
نتیجهگیری
این فرمولها نشان میدهند که:
- ✅ تعادل اهمیت دارد - هرچه دو پا متعادلتر باشند، فلش کمتر است
- ✅ Cap محدودیت ایجاد میکند - حتی با تعادل کامل، بیش از MX کمیسیون داده نمیشود
- ✅ باقیماندهها منتقل میشوند - برای هفته بعد ذخیره میشوند
- ❌ فلش ضرر است - مقداری که به دلیل عدم تعادل یا Cap از دست میرود
توصیه: برای افزایش کمیسیون، کاربران باید:
- دو پای خود را متعادل نگه دارند
- سطح عضویت خود را ارتقا دهند (برای افزایش MX)
- از باقیماندهها در هفتههای بعد استفاده کنند