using CMSMicroservice.Application.Common.Interfaces; using Microsoft.EntityFrameworkCore; namespace CMSMicroservice.Infrastructure.Services.Commission; /// /// پیاده‌سازی محاسبه کمیسیون با استفاده از Stored Procedure /// این روش برای داده‌های زیاد بهینه‌تر است و از CTE استفاده می‌کند /// حلقه روی پکیج‌های فعال — هر پکیج با تنظیمات خودش /// public class StoredProcedureCommissionCalculationStrategy : ICommissionCalculationStrategy { private readonly IApplicationDbContext _context; public StoredProcedureCommissionCalculationStrategy(IApplicationDbContext context) { _context = context; } /// public async Task 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(); } } /// public async Task 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(); } } }