From b905c308c199c62d5f70338eea33e6e551abaa1b Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Mon, 4 May 2026 23:54:13 +0330 Subject: [PATCH] feat: enhance sp_CalculateWeeklyBalances to track package activity and optimize member calculations --- .../sp_CalculateWeeklyBalances.sql | 147 ++++++++++++++---- 1 file changed, 114 insertions(+), 33 deletions(-) diff --git a/src/CMSMicroservice.Infrastructure/Persistence/StoredProcedures/sp_CalculateWeeklyBalances.sql b/src/CMSMicroservice.Infrastructure/Persistence/StoredProcedures/sp_CalculateWeeklyBalances.sql index 5f5b93a..9b55e6d 100644 --- a/src/CMSMicroservice.Infrastructure/Persistence/StoredProcedures/sp_CalculateWeeklyBalances.sql +++ b/src/CMSMicroservice.Infrastructure/Persistence/StoredProcedures/sp_CalculateWeeklyBalances.sql @@ -24,6 +24,7 @@ BEGIN DECLARE @MaxBalancesPerLeg INT; DECLARE @MaxNetworkLevel INT; DECLARE @CalculatedAt DATETIME = GETDATE(); + DECLARE @HasPackageActivityUntilWeek BIT = 0; -- تعیین PackageId پیش‌فرض (پکیج پایه) IF @PackageId IS NULL @@ -66,6 +67,26 @@ BEGIN FROM CMS.WeekDefinitions WHERE Id = @WeekDefinitionId; + -- اگر تا پایان این هفته هنوز هیچ Cycle برای این پکیج وجود نداشته، + -- این پکیج نباید برای هفته‌های قبل از شروعش هیچ رکوردی بسازد. + IF EXISTS ( + SELECT 1 + FROM CMS.ClubMembershipCycles cc + WHERE cc.PackageId = @PackageId + AND cc.IsDeleted = 0 + AND cc.PackagePurchasedAt <= @EndDate + ) + BEGIN + SET @HasPackageActivityUntilWeek = 1; + END + + IF @HasPackageActivityUntilWeek = 0 + BEGIN + SET @RowCount = 0; + COMMIT TRANSACTION; + RETURN; + END + -- ============================================= -- 2. بررسی محاسبه قبلی -- ============================================= @@ -104,7 +125,7 @@ BEGIN -- @MaxBalancesPerLeg و @MaxNetworkLevel قبلاً مقداردهی شده‌اند -- ============================================= - -- 5. ایجاد جدول موقت برای نتایج + -- 5. ایجاد جداول موقت برای نتایج -- ============================================= CREATE TABLE #Balances ( UserId BIGINT PRIMARY KEY, @@ -122,31 +143,18 @@ BEGIN SubordinateBalances INT DEFAULT 0 ); - -- ============================================= - -- 6. دریافت کاربران فعال باشگاه - -- ============================================= - INSERT INTO #Balances (UserId) - SELECT DISTINCT u.Id - FROM CMS.Users u - INNER JOIN CMS.ClubMemberships cm ON cm.UserId = u.Id AND cm.IsActive = 1 - WHERE cm.LastPackageId = @PackageId; + CREATE TABLE #LeftNewMembers ( + UserId BIGINT PRIMARY KEY, + NewMembersCount INT NOT NULL + ); + + CREATE TABLE #RightNewMembers ( + UserId BIGINT PRIMARY KEY, + NewMembersCount INT NOT NULL + ); -- ============================================= - -- 7. دریافت باقیمانده هفته قبل - -- ============================================= - IF @PreviousWeekDefinitionId IS NOT NULL - BEGIN - UPDATE b - SET b.LeftLegCarryover = ISNULL(nb.LeftLegRemainder, 0), - b.RightLegCarryover = ISNULL(nb.RightLegRemainder, 0) - FROM #Balances b - LEFT JOIN CMS.NetworkWeeklyBalances nb ON nb.UserId = b.UserId - AND nb.WeekDefinitionId = @PreviousWeekDefinitionId - AND nb.PackageId = @PackageId; - END - - -- ============================================= - -- 8. محاسبه اعضای جدید هر پا با CTE (بهینه!) + -- 6. محاسبه اعضای جدید هر پا با CTE (بهینه!) -- ============================================= -- CTE برای شمارش اعضای جدید شاخه چپ @@ -177,13 +185,15 @@ BEGIN COUNT(DISTINCT cte.ChildId) AS NewMembersCount FROM LeftLegCTE cte INNER JOIN CMS.ClubMembershipCycles cc ON cc.UserId = cte.ChildId - WHERE cc.PackagePurchasedAt >= @StartDate AND cc.PackagePurchasedAt <= @EndDate + WHERE cc.PackagePurchasedAt >= @StartDate + AND cc.PackagePurchasedAt <= @EndDate + AND cc.PackageId = @PackageId + AND cc.IsDeleted = 0 GROUP BY cte.ParentId ) - UPDATE b - SET b.LeftLegNewMembers = ISNULL(lnm.NewMembersCount, 0) - FROM #Balances b - LEFT JOIN LeftNewMembers lnm ON lnm.UserId = b.UserId + INSERT INTO #LeftNewMembers (UserId, NewMembersCount) + SELECT UserId, NewMembersCount + FROM LeftNewMembers OPTION (MAXRECURSION 100); -- CTE برای شمارش اعضای جدید شاخه راست @@ -214,14 +224,65 @@ BEGIN COUNT(DISTINCT cte.ChildId) AS NewMembersCount FROM RightLegCTE cte INNER JOIN CMS.ClubMembershipCycles cc ON cc.UserId = cte.ChildId - WHERE cc.PackagePurchasedAt >= @StartDate AND cc.PackagePurchasedAt <= @EndDate + WHERE cc.PackagePurchasedAt >= @StartDate + AND cc.PackagePurchasedAt <= @EndDate + AND cc.PackageId = @PackageId + AND cc.IsDeleted = 0 GROUP BY cte.ParentId ) + INSERT INTO #RightNewMembers (UserId, NewMembersCount) + SELECT UserId, NewMembersCount + FROM RightNewMembers + OPTION (MAXRECURSION 100); + + -- ============================================= + -- 7. انتخاب parentهایی که باید برای این پکیج/هفته row بگیرند + -- شرط ورود: + -- - عضو فعال باشگاه باشند + -- - یا از هفته قبل برای همین پکیج carryover داشته باشند + -- - یا این هفته recruit جدید همین پکیج در چپ/راست subtree داشته باشند + -- ============================================= + INSERT INTO #Balances (UserId) + SELECT DISTINCT cm.UserId + FROM CMS.ClubMemberships cm + INNER JOIN CMS.Users u ON u.Id = cm.UserId + LEFT JOIN #LeftNewMembers lnm ON lnm.UserId = cm.UserId + LEFT JOIN #RightNewMembers rnm ON rnm.UserId = cm.UserId + LEFT JOIN CMS.NetworkWeeklyBalances prev ON prev.UserId = cm.UserId + AND prev.WeekDefinitionId = @PreviousWeekDefinitionId + AND prev.PackageId = @PackageId + WHERE cm.IsActive = 1 + AND u.IsDeleted = 0 + AND ( + ISNULL(lnm.NewMembersCount, 0) > 0 + OR ISNULL(rnm.NewMembersCount, 0) > 0 + OR ISNULL(prev.LeftLegRemainder, 0) > 0 + OR ISNULL(prev.RightLegRemainder, 0) > 0 + ); + + -- ============================================= + -- 8. دریافت باقیمانده هفته قبل + اعمال counts محاسبه‌شده + -- ============================================= + IF @PreviousWeekDefinitionId IS NOT NULL + BEGIN + UPDATE b + SET b.LeftLegCarryover = ISNULL(nb.LeftLegRemainder, 0), + b.RightLegCarryover = ISNULL(nb.RightLegRemainder, 0) + FROM #Balances b + LEFT JOIN CMS.NetworkWeeklyBalances nb ON nb.UserId = b.UserId + AND nb.WeekDefinitionId = @PreviousWeekDefinitionId + AND nb.PackageId = @PackageId; + END + + UPDATE b + SET b.LeftLegNewMembers = ISNULL(lnm.NewMembersCount, 0) + FROM #Balances b + LEFT JOIN #LeftNewMembers lnm ON lnm.UserId = b.UserId; + UPDATE b SET b.RightLegNewMembers = ISNULL(rnm.NewMembersCount, 0) FROM #Balances b - LEFT JOIN RightNewMembers rnm ON rnm.UserId = b.UserId - OPTION (MAXRECURSION 100); + LEFT JOIN #RightNewMembers rnm ON rnm.UserId = b.UserId; -- ============================================= -- 9. محاسبه تعادل‌ها @@ -354,11 +415,25 @@ BEGIN 'SP', -- CreatedBy @CalculatedAt, -- LastModified 'SP' -- LastModifiedBy - FROM #Balances; + FROM #Balances + WHERE LeftLegNewMembers <> 0 + OR RightLegNewMembers <> 0 + OR LeftLegCarryover <> 0 + OR RightLegCarryover <> 0 + OR LeftLegTotal <> 0 + OR RightLegTotal <> 0 + OR TotalBalances <> 0 + OR LeftLegRemainder <> 0 + OR RightLegRemainder <> 0 + OR FlushedPerSide <> 0 + OR TotalFlushed <> 0 + OR SubordinateBalances <> 0; SET @RowCount = @@ROWCOUNT; -- پاکسازی + DROP TABLE #RightNewMembers; + DROP TABLE #LeftNewMembers; DROP TABLE #Balances; COMMIT TRANSACTION; @@ -369,6 +444,12 @@ BEGIN ROLLBACK TRANSACTION; -- پاکسازی در صورت خطا + IF OBJECT_ID('tempdb..#RightNewMembers') IS NOT NULL + DROP TABLE #RightNewMembers; + + IF OBJECT_ID('tempdb..#LeftNewMembers') IS NOT NULL + DROP TABLE #LeftNewMembers; + IF OBJECT_ID('tempdb..#Balances') IS NOT NULL DROP TABLE #Balances;