-- ============================================= -- Stored Procedure: sp_CalculateWeeklyCommissionPool -- Description: محاسبه استخر کمیسیون هفتگی و توزیع بین کاربران -- Author: System -- Created: 2025-12-19 -- Updated: Q29 — اضافه کردن @PackageId، fix فیلتر pool، مدیریت pool خالی -- ============================================= CREATE OR ALTER PROCEDURE [CMS].[sp_CalculateWeeklyCommissionPool] @WeekDefinitionId BIGINT, @PackageId BIGINT, -- هر بار به ازای یک پکیج اجرا می‌شود @ForceRecalculate BIT = 0, @PoolId BIGINT OUTPUT AS BEGIN SET NOCOUNT ON; SET XACT_ABORT ON; DECLARE @ErrorMessage NVARCHAR(4000); DECLARE @TotalPoolAmount BIGINT = 0; DECLARE @TotalBalances INT; DECLARE @ValuePerBalance BIGINT; DECLARE @CalculatedAt DATETIME = GETDATE(); BEGIN TRY BEGIN TRANSACTION; -- ============================================= -- 1. پیدا کردن Pool هفته (فیلتر بر اساس PackageId) -- ============================================= SELECT @PoolId = Id, @TotalPoolAmount = TotalPoolAmount FROM CMS.WeeklyCommissionPools WHERE WeekDefinitionId = @WeekDefinitionId AND PackageId = @PackageId; -- اگر Pool وجود ندارد (هیچ فعال‌سازی در این هفته نبوده)، یک رکورد خالی ایجاد می‌کنیم IF @PoolId IS NULL BEGIN INSERT INTO CMS.WeeklyCommissionPools ( WeekDefinitionId, PackageId, TotalPoolAmount, TotalBalances, ValuePerBalance, IsCalculated, CalculatedAt, IsDeleted, Created, CreatedBy, LastModified, LastModifiedBy ) VALUES ( @WeekDefinitionId, @PackageId, 0, 0, 0, 0, NULL, 0, @CalculatedAt, 'SP', @CalculatedAt, 'SP' ); SET @PoolId = SCOPE_IDENTITY(); SET @TotalPoolAmount = 0; END -- ============================================= -- 2. بررسی محاسبات قبلی (بر اساس همین Pool نه کل هفته) -- ============================================= IF EXISTS (SELECT 1 FROM CMS.UserCommissionPayouts WHERE WeeklyPoolId = @PoolId) BEGIN IF @ForceRecalculate = 0 BEGIN SET @ErrorMessage = N'کمیسیون هفته ' + CAST(@WeekDefinitionId AS NVARCHAR(20)) + N' (پکیج ' + CAST(@PackageId AS NVARCHAR(20)) + N') قبلاً محاسبه شده است. برای محاسبه مجدد از ForceRecalculate استفاده کنید'; RAISERROR(@ErrorMessage, 16, 1); RETURN; END -- ============================================= -- 3. Revert کیف پول‌ها (در صورت ForceRecalculate، فقط پرداخت‌های این Pool) -- ============================================= -- کم کردن مقادیر قبلی از NetworkBalance UPDATE uw SET uw.NetworkBalance = uw.NetworkBalance - ISNULL( (SELECT SUM(wl.ChangeNerworkValue) FROM CMS.UserWalletChangeLogs wl WHERE wl.WalletId = uw.Id AND wl.RefrenceId IN (SELECT Id FROM CMS.UserCommissionPayouts WHERE WeeklyPoolId = @PoolId) ), 0) FROM CMS.UserWallets uw WHERE uw.Id IN ( SELECT DISTINCT wl.WalletId FROM CMS.UserWalletChangeLogs wl WHERE wl.RefrenceId IN (SELECT Id FROM CMS.UserCommissionPayouts WHERE WeeklyPoolId = @PoolId) ); -- حذف لاگ‌های تغییرات قبلی DELETE FROM CMS.UserWalletChangeLogs WHERE RefrenceId IN (SELECT Id FROM CMS.UserCommissionPayouts WHERE WeeklyPoolId = @PoolId); -- حذف تاریخچه پرداخت DELETE FROM CMS.CommissionPayoutHistories WHERE UserCommissionPayoutId IN (SELECT Id FROM CMS.UserCommissionPayouts WHERE WeeklyPoolId = @PoolId); -- حذف پرداخت‌های قبلی این Pool DELETE FROM CMS.UserCommissionPayouts WHERE WeeklyPoolId = @PoolId; -- Reset وضعیت Pool UPDATE CMS.WeeklyCommissionPools SET IsCalculated = 0 WHERE Id = @PoolId; END -- ============================================= -- 4. بررسی وجود تعادل‌های هفتگی -- ============================================= IF NOT EXISTS (SELECT 1 FROM CMS.NetworkWeeklyBalances WHERE WeekDefinitionId = @WeekDefinitionId) BEGIN -- بالانسی محاسبه نشده — pool را به عنوان "محاسبه شده بدون پرداخت" علامت می‌زنیم UPDATE CMS.WeeklyCommissionPools SET IsCalculated = 1, CalculatedAt = @CalculatedAt WHERE Id = @PoolId; COMMIT TRANSACTION; RETURN; END -- ============================================= -- 5. محاسبه مجموع تعادل‌ها -- ============================================= SELECT @TotalBalances = SUM(TotalBalances) FROM CMS.NetworkWeeklyBalances WHERE WeekDefinitionId = @WeekDefinitionId AND TotalBalances > 0; IF @TotalBalances IS NULL OR @TotalBalances = 0 BEGIN -- هیچ تعادلی برای توزیع وجود ندارد — pool محاسبه شده اما پرداختی ندارد UPDATE CMS.WeeklyCommissionPools SET IsCalculated = 1, CalculatedAt = @CalculatedAt WHERE Id = @PoolId; COMMIT TRANSACTION; RETURN; END -- ============================================= -- 6. محاسبه ارزش هر تعادل -- ============================================= SET @ValuePerBalance = @TotalPoolAmount / @TotalBalances; -- ============================================= -- 7. ایجاد پرداخت برای هر کاربر -- ============================================= INSERT INTO CMS.UserCommissionPayouts ( UserId, WeekDefinitionId, WeeklyPoolId, BalancesEarned, ValuePerBalance, TotalAmount, Status, PaidAt, IsDeleted, Created, CreatedBy, LastModified, LastModifiedBy ) SELECT nb.UserId, @WeekDefinitionId, @PoolId, nb.TotalBalances, @ValuePerBalance, nb.TotalBalances * @ValuePerBalance, 0, -- Status: Pending NULL, -- PaidAt 0, -- IsDeleted @CalculatedAt, 'SP', @CalculatedAt, 'SP' FROM CMS.NetworkWeeklyBalances nb WHERE nb.WeekDefinitionId = @WeekDefinitionId AND nb.TotalBalances > 0; -- ============================================= -- 8. ثبت تاریخچه پرداخت -- ============================================= INSERT INTO CMS.CommissionPayoutHistories ( UserCommissionPayoutId, UserId, WeekDefinitionId, AmountBefore, AmountAfter, OldStatus, NewStatus, Action, PerformedBy, Reason, IsDeleted, Created, CreatedBy, LastModified, LastModifiedBy ) SELECT cp.Id, cp.UserId, @WeekDefinitionId, 0, cp.TotalAmount, 0, -- OldStatus: Pending 0, -- NewStatus: Pending 0, -- Action: Created 'SP', N'محاسبه اولیه توسط SP', 0, @CalculatedAt, 'SP', @CalculatedAt, 'SP' FROM CMS.UserCommissionPayouts cp WHERE cp.WeeklyPoolId = @PoolId; -- ============================================= -- 9. شارژ کیف پول کاربران -- ============================================= -- بروزرسانی NetworkBalance UPDATE uw SET uw.NetworkBalance = uw.NetworkBalance + cp.TotalAmount FROM CMS.UserWallets uw INNER JOIN CMS.UserCommissionPayouts cp ON cp.UserId = uw.UserId WHERE cp.WeeklyPoolId = @PoolId; -- ثبت لاگ تغییرات کیف پول INSERT INTO CMS.UserWalletChangeLogs ( WalletId, CurrentBalance, ChangeValue, CurrentNetworkBalance, ChangeNerworkValue, CurrentDiscountBalance, ChangeDiscountValue, IsIncrease, RefrenceId, IsDeleted, Created, CreatedBy, LastModified, LastModifiedBy ) SELECT uw.Id, uw.Balance, 0, -- ChangeValue (no change to main balance) uw.NetworkBalance, -- CurrentNetworkBalance (after update) cp.TotalAmount, -- ChangeNerworkValue uw.DiscountBalance, 0, -- ChangeDiscountValue 1, -- IsIncrease: true cp.Id, -- RefrenceId: PayoutId 0, @CalculatedAt, 'SP', @CalculatedAt, 'SP' FROM CMS.UserCommissionPayouts cp INNER JOIN CMS.UserWallets uw ON uw.UserId = cp.UserId WHERE cp.WeeklyPoolId = @PoolId; -- ============================================= -- 10. بروزرسانی Pool -- ============================================= UPDATE CMS.WeeklyCommissionPools SET IsCalculated = 1, CalculatedAt = @CalculatedAt, TotalBalances = @TotalBalances, ValuePerBalance = @ValuePerBalance, LastModified = @CalculatedAt, LastModifiedBy = 'SP' WHERE Id = @PoolId; COMMIT TRANSACTION; END TRY BEGIN CATCH IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION; SET @ErrorMessage = ERROR_MESSAGE(); RAISERROR(@ErrorMessage, 16, 1); END CATCH END GO