4d6d77531d
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 15m3s
- SP sp_CalculateWeeklyBalances: added @PackageId, @InputMaxBalancesPerLeg, @InputMaxNetworkLevel params; filters by PackageId - SP sp_CalculateWeeklyCommissionPool: added @PackageId param; all queries filter by PackageId/WeeklyPoolId for isolation - ICommissionCalculationStrategy: added optional PackageId param to both methods - StoredProcedureCommissionCalculationStrategy: loops per-package for both Balance and Pool methods; filters by packageId if provided - OrmCommissionCalculationStrategy: signature updated to match interface - TriggerWeeklyCalculationCommand: added PackageId optional field - TriggerWeeklyCalculationCommandHandler: passes PackageId to strategy - GetWeeklyCommissionPoolQuery: added optional PackageId filter - GetWeeklyCommissionPoolQueryHandler: filters pool by PackageId if provided - GetAllWeeklyPoolsQuery/Handler/DTO: added PackageId filter + PackageTitle in response - Proto commission.proto: added package_id to TriggerWeeklyCalculationRequest, GetWeeklyCommissionPoolRequest, WeeklyCommissionPoolModel, GetWeeklyCommissionPoolResponse, GetAllWeeklyPoolsRequest - CommissionProfile: added explicit mappings for TriggerWeeklyCalculation, GetWeeklyCommissionPool, GetAllWeeklyPools Fixes: SP picks wrong pool when multiple packages per week Fixes: SP ignores PackageId on ForceRecalculate (now uses WeeklyPoolId) Fixes: Zero-balance pools not fully recorded (now sets TotalBalances=0, ValuePerBalance=0)
183 lines
7.5 KiB
C#
183 lines
7.5 KiB
C#
using CMSMicroservice.Application.Common.Interfaces;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace CMSMicroservice.Infrastructure.Services.Commission;
|
|
|
|
/// <summary>
|
|
/// پیادهسازی محاسبه کمیسیون با استفاده از Stored Procedure
|
|
/// این روش برای دادههای زیاد بهینهتر است و از CTE استفاده میکند
|
|
/// حلقه روی پکیجهای فعال — هر پکیج با تنظیمات خودش
|
|
/// </summary>
|
|
public class StoredProcedureCommissionCalculationStrategy : ICommissionCalculationStrategy
|
|
{
|
|
private readonly IApplicationDbContext _context;
|
|
|
|
public StoredProcedureCommissionCalculationStrategy(IApplicationDbContext context)
|
|
{
|
|
_context = context;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<int> CalculateWeeklyBalancesAsync(
|
|
long weekDefinitionId,
|
|
bool forceRecalculate,
|
|
long? packageId = null,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var dbContext = _context as DbContext;
|
|
if (dbContext == null)
|
|
{
|
|
throw new InvalidOperationException("DbContext برای اجرای Stored Procedure در دسترس نیست");
|
|
}
|
|
|
|
// بارگذاری پکیجهای فعال — اگر packageId داده شده فقط همان پکیج
|
|
var packagesQuery = _context.Packages.Where(p => !p.IsDeleted && p.IsActive);
|
|
if (packageId.HasValue)
|
|
packagesQuery = packagesQuery.Where(p => p.Id == packageId.Value);
|
|
var activePackages = await packagesQuery.ToListAsync(cancellationToken);
|
|
|
|
if (!activePackages.Any())
|
|
{
|
|
throw new InvalidOperationException("هیچ پکیج فعالی یافت نشد");
|
|
}
|
|
|
|
var totalRowCount = 0;
|
|
|
|
var connection = dbContext.Database.GetDbConnection();
|
|
await connection.OpenAsync(cancellationToken);
|
|
|
|
try
|
|
{
|
|
// حلقه روی پکیجها — هر پکیج با تنظیمات خودش
|
|
foreach (var package in activePackages)
|
|
{
|
|
using var command = connection.CreateCommand();
|
|
command.CommandText = "CMS.sp_CalculateWeeklyBalances";
|
|
command.CommandType = System.Data.CommandType.StoredProcedure;
|
|
command.CommandTimeout = 300; // 5 دقیقه timeout
|
|
|
|
// پارامتر WeekDefinitionId
|
|
var paramWeekDefinitionId = command.CreateParameter();
|
|
paramWeekDefinitionId.ParameterName = "@WeekDefinitionId";
|
|
paramWeekDefinitionId.Value = weekDefinitionId;
|
|
command.Parameters.Add(paramWeekDefinitionId);
|
|
|
|
// پارامتر ForceRecalculate
|
|
var paramForceRecalculate = command.CreateParameter();
|
|
paramForceRecalculate.ParameterName = "@ForceRecalculate";
|
|
paramForceRecalculate.Value = forceRecalculate;
|
|
command.Parameters.Add(paramForceRecalculate);
|
|
|
|
// پارامتر PackageId — per-package
|
|
var paramPackageId = command.CreateParameter();
|
|
paramPackageId.ParameterName = "@PackageId";
|
|
paramPackageId.Value = package.Id;
|
|
command.Parameters.Add(paramPackageId);
|
|
|
|
// پارامتر MaxBalancesPerLeg — per-package
|
|
var paramMaxBalances = command.CreateParameter();
|
|
paramMaxBalances.ParameterName = "@InputMaxBalancesPerLeg";
|
|
paramMaxBalances.Value = package.MaxBalancesPerLeg;
|
|
command.Parameters.Add(paramMaxBalances);
|
|
|
|
// پارامتر MaxNetworkLevel — per-package
|
|
var paramMaxLevel = command.CreateParameter();
|
|
paramMaxLevel.ParameterName = "@InputMaxNetworkLevel";
|
|
paramMaxLevel.Value = package.MaxNetworkLevel;
|
|
command.Parameters.Add(paramMaxLevel);
|
|
|
|
// پارامتر خروجی
|
|
var paramRowCount = command.CreateParameter();
|
|
paramRowCount.ParameterName = "@RowCount";
|
|
paramRowCount.Direction = System.Data.ParameterDirection.Output;
|
|
paramRowCount.DbType = System.Data.DbType.Int32;
|
|
command.Parameters.Add(paramRowCount);
|
|
|
|
await command.ExecuteNonQueryAsync(cancellationToken);
|
|
|
|
var rowCount = (int)(paramRowCount.Value ?? 0);
|
|
totalRowCount += rowCount;
|
|
}
|
|
|
|
return totalRowCount;
|
|
}
|
|
finally
|
|
{
|
|
await connection.CloseAsync();
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<long> CalculateWeeklyCommissionPoolAsync(
|
|
long weekDefinitionId,
|
|
bool forceRecalculate,
|
|
long? packageId = null,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var dbContext = _context as DbContext;
|
|
if (dbContext == null)
|
|
{
|
|
throw new InvalidOperationException("DbContext برای اجرای Stored Procedure در دسترس نیست");
|
|
}
|
|
|
|
// بارگذاری پکیجهای فعال — اگر packageId داده شده فقط همان پکیج
|
|
var packagesQuery = _context.Packages.Where(p => !p.IsDeleted && p.IsActive);
|
|
if (packageId.HasValue)
|
|
packagesQuery = packagesQuery.Where(p => p.Id == packageId.Value);
|
|
var activePackages = await packagesQuery.ToListAsync(cancellationToken);
|
|
|
|
if (!activePackages.Any())
|
|
{
|
|
throw new InvalidOperationException("هیچ پکیج فعالی یافت نشد");
|
|
}
|
|
|
|
var connection = dbContext.Database.GetDbConnection();
|
|
await connection.OpenAsync(cancellationToken);
|
|
|
|
long lastPoolId = 0;
|
|
|
|
try
|
|
{
|
|
// حلقه روی پکیجها — هر پکیج Pool مستقل دارد
|
|
foreach (var package in activePackages)
|
|
{
|
|
using var command = connection.CreateCommand();
|
|
command.CommandText = "CMS.sp_CalculateWeeklyCommissionPool";
|
|
command.CommandType = System.Data.CommandType.StoredProcedure;
|
|
command.CommandTimeout = 300;
|
|
|
|
var paramWeekDefinitionId = command.CreateParameter();
|
|
paramWeekDefinitionId.ParameterName = "@WeekDefinitionId";
|
|
paramWeekDefinitionId.Value = weekDefinitionId;
|
|
command.Parameters.Add(paramWeekDefinitionId);
|
|
|
|
var paramPackageId = command.CreateParameter();
|
|
paramPackageId.ParameterName = "@PackageId";
|
|
paramPackageId.Value = package.Id;
|
|
command.Parameters.Add(paramPackageId);
|
|
|
|
var paramForceRecalculate = command.CreateParameter();
|
|
paramForceRecalculate.ParameterName = "@ForceRecalculate";
|
|
paramForceRecalculate.Value = forceRecalculate;
|
|
command.Parameters.Add(paramForceRecalculate);
|
|
|
|
var paramPoolId = command.CreateParameter();
|
|
paramPoolId.ParameterName = "@PoolId";
|
|
paramPoolId.Direction = System.Data.ParameterDirection.Output;
|
|
paramPoolId.DbType = System.Data.DbType.Int64;
|
|
command.Parameters.Add(paramPoolId);
|
|
|
|
await command.ExecuteNonQueryAsync(cancellationToken);
|
|
|
|
lastPoolId = (long)(paramPoolId.Value ?? 0L);
|
|
}
|
|
|
|
return lastPoolId;
|
|
}
|
|
finally
|
|
{
|
|
await connection.CloseAsync();
|
|
}
|
|
}
|
|
}
|