From b053d860060907010cc40a218b58ed7262ce1f5f Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Fri, 1 May 2026 00:27:44 +0330 Subject: [PATCH] feat: Add GetNetworkTree stored procedure for binary network retrieval with activation logic --- .../StoredProcedures/GetNetworkTree.sql | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 src/CMSMicroservice.Infrastructure/Persistence/StoredProcedures/GetNetworkTree.sql diff --git a/src/CMSMicroservice.Infrastructure/Persistence/StoredProcedures/GetNetworkTree.sql b/src/CMSMicroservice.Infrastructure/Persistence/StoredProcedures/GetNetworkTree.sql new file mode 100644 index 0000000..ca42abb --- /dev/null +++ b/src/CMSMicroservice.Infrastructure/Persistence/StoredProcedures/GetNetworkTree.sql @@ -0,0 +1,136 @@ +-- ============================================= +-- Stored Procedure: GetNetworkTree +-- Description: دریافت درخت شبکه باینری با CTE recursive +-- Author: FourSat Team +-- Updated: 2026-04-30 — اضافه کردن IsNewActivation، PackageName، PackageId +-- منطق هفته‌بندی از ActivatedAt به PackagePurchasedAt تغییر کرد +-- ============================================= + +CREATE OR ALTER PROCEDURE [CMS].[GetNetworkTree] + @RootUserId BIGINT, + @MaxDepth INT = 100, + @IsClubActive BIT = NULL, + @ActivationWeekDefinitionId BIGINT = NULL +AS +BEGIN + SET NOCOUNT ON; + + -- تاریخ شروع و پایان هفته فیلتر + DECLARE @WeekStartDate DATETIME = NULL; + DECLARE @WeekEndDate DATETIME = NULL; + + IF @ActivationWeekDefinitionId IS NOT NULL + BEGIN + SELECT @WeekStartDate = StartDate, @WeekEndDate = EndDate + FROM [CMS].[WeekDefinitions] + WHERE Id = @ActivationWeekDefinitionId; + END + + -- CTE برای پیمایش درخت باینری به صورت recursive + ;WITH NetworkTreeCTE AS ( + -- Base case: ریشه درخت + SELECT + u.Id AS UserId, + u.Mobile, + u.FirstName, + u.LastName, + u.ReferralCode, + u.LegPosition, + u.NetworkParentId AS ParentId, + 0 AS NetworkLevel, + u.Created AS UserCreated + FROM [CMS].[Users] u + WHERE u.Id = @RootUserId + AND u.IsDeleted = 0 + + UNION ALL + + -- Recursive case: فرزندان + SELECT + u.Id AS UserId, + u.Mobile, + u.FirstName, + u.LastName, + u.ReferralCode, + u.LegPosition, + u.NetworkParentId AS ParentId, + parent.NetworkLevel + 1 AS NetworkLevel, + u.Created AS UserCreated + FROM [CMS].[Users] u + INNER JOIN NetworkTreeCTE parent ON u.NetworkParentId = parent.UserId + WHERE u.IsDeleted = 0 + AND parent.NetworkLevel < @MaxDepth + ) + SELECT + t.UserId, + t.Mobile, + t.FirstName, + t.LastName, + t.ReferralCode, + t.LegPosition, + t.ParentId, + t.NetworkLevel, + cm.ActivatedAt AS ClubActivatedAt, + ISNULL(cm.IsActive, 0) AS IsClubActive, + + -- هفته فعال‌سازی بر اساس Cycle جاری (PackagePurchasedAt) + wd.Id AS ActivationWeekDefinitionId, + wd.DisplayName AS ActivationWeekDisplayName, + + -- آیا کاربر در هفته هدف Cycle داشته؟ + CASE WHEN cc_target.UserId IS NOT NULL THEN 1 ELSE 0 END AS IsActivatedInTargetWeek, + + -- نوع فعال‌سازی: 1=جدید، 0=تمدید/خرید مجدد، NULL=بدون Cycle + CASE + WHEN cc_eff.CycleNumber IS NULL THEN NULL + WHEN cc_eff.CycleNumber = 1 THEN 1 + ELSE 0 + END AS IsNewActivation, + + -- نام پکیج موثر (هفته هدف اگر فیلتر باشد، وگرنه پکیج فعلی) + ISNULL(p_eff.Title, '') AS PackageName, + cc_eff.PackageId AS PackageId, + + t.UserCreated + FROM NetworkTreeCTE t + LEFT JOIN [CMS].[ClubMemberships] cm ON cm.UserId = t.UserId AND cm.IsDeleted = 0 + + -- Cycle جاری — برای نمایش هفته و پکیج وقتی فیلتر هفته نیست + OUTER APPLY ( + SELECT TOP 1 CycleNumber, PackageId, PackagePurchasedAt + FROM [CMS].[ClubMembershipCycles] + WHERE UserId = t.UserId AND IsCurrentCycle = 1 + ) cc_current + + -- Cycle هفته هدف — برای IsActivatedInTargetWeek و نوع فعال‌سازی + OUTER APPLY ( + SELECT TOP 1 UserId, CycleNumber, PackageId + FROM [CMS].[ClubMembershipCycles] + WHERE UserId = t.UserId + AND @WeekStartDate IS NOT NULL + AND PackagePurchasedAt >= @WeekStartDate + AND PackagePurchasedAt < @WeekEndDate + ORDER BY CycleNumber ASC + ) cc_target + + -- Cycle موثر: اگر هفته فیلتر داریم → cc_target، وگرنه → cc_current + CROSS APPLY ( + SELECT + CASE WHEN @WeekStartDate IS NOT NULL AND cc_target.UserId IS NOT NULL + THEN cc_target.CycleNumber ELSE cc_current.CycleNumber END AS CycleNumber, + CASE WHEN @WeekStartDate IS NOT NULL AND cc_target.UserId IS NOT NULL + THEN cc_target.PackageId ELSE cc_current.PackageId END AS PackageId + ) cc_eff + + -- پکیج موثر + LEFT JOIN [CMS].[Packages] p_eff ON p_eff.Id = cc_eff.PackageId AND p_eff.IsDeleted = 0 + + -- هفته بر اساس PackagePurchasedAt سایکل جاری + LEFT JOIN [CMS].[WeekDefinitions] wd + ON cc_current.PackagePurchasedAt >= wd.StartDate + AND cc_current.PackagePurchasedAt < wd.EndDate + + WHERE (@IsClubActive IS NULL OR ISNULL(cm.IsActive, 0) = @IsClubActive OR t.NetworkLevel = 0) + ORDER BY t.NetworkLevel, t.ParentId, t.LegPosition + OPTION (MAXRECURSION 0); +END