/* PHASE 3 — Remaining 16 users from WrongDaya→Manual list (no manualy Tx from Phase 1/2). Users: 2,7,8,9,10,11,12,13,40,41,105,106,130,162,169,176 Already done in Phase 1+2 (22 users with manualy Tx): excluded here. Per user (skip if UPP already exists for that UserId): 1) Reuse deposit Tx if WH links to Success Tx with Amount=56000000 2) Else fix WH.RefrenceId when CreatedBy hints an existing manualy Tx 3) Else CREATE Transaction (RefId FIX3-{UserId}) — no wallet charge 4) Link stub WH (Ref=0) to Tx OR insert history-only WH 5) INSERT UserPackagePurchases Manual(3) User 162: skipped for UPP if any UPP already exists (has UPP from ManualPayment flow). Does NOT change Users.PackagePurchaseMethod (Phase 4 later). Defaults to ROLLBACK. Uncomment COMMIT after preview. */ SET NOCOUNT ON; SET XACT_ABORT ON; BEGIN TRAN; DECLARE @Now DATETIME2 = SYSUTCDATETIME(); DECLARE @ChargeAmount BIGINT = 56000000; DECLARE @BasePackageId BIGINT; DECLARE @BasePackagePrice BIGINT; SELECT TOP (1) @BasePackageId = Id, @BasePackagePrice = Price FROM CMS.Packages WHERE IsDeleted = 0 AND IsBasePackage = 1 ORDER BY Id; IF @BasePackageId IS NULL THROW 50001, 'Base package not found.', 1; DECLARE @Phase3 TABLE (UserId BIGINT PRIMARY KEY); INSERT INTO @Phase3 (UserId) VALUES (2),(7),(8),(9),(10),(11),(12),(13),(40),(41), (105),(106),(130),(162),(169),(176); DECLARE @Phase3Count INT = (SELECT COUNT(*) FROM @Phase3); PRINT CONCAT('Phase3 users: ', @Phase3Count); ------------------------------------------------------------ -- Preview: current ledger state ------------------------------------------------------------ SELECT p.UserId, u.Mobile, u.FirstName, u.LastName, u.PackagePurchaseMethod, (SELECT COUNT(*) FROM CMS.UserPackagePurchases upp WHERE upp.UserId = p.UserId AND upp.IsDeleted = 0) AS UppCount, (SELECT TOP (1) upp.Id FROM CMS.UserPackagePurchases upp WHERE upp.UserId = p.UserId AND upp.IsDeleted = 0 ORDER BY upp.Id DESC) AS LatestUppId, (SELECT COUNT(*) FROM CMS.UserWalletHistories h INNER JOIN CMS.UserWallets w ON w.Id = h.WalletId AND w.IsDeleted = 0 WHERE w.UserId = p.UserId AND h.IsDeleted = 0) AS WhCount, (SELECT COUNT(*) FROM CMS.UserWalletHistories h INNER JOIN CMS.UserWallets w ON w.Id = h.WalletId AND w.IsDeleted = 0 WHERE w.UserId = p.UserId AND h.IsDeleted = 0 AND h.ChangeValue >= @ChargeAmount AND h.RefrenceId > 0) AS WhFullDepositCount, CASE WHEN EXISTS ( SELECT 1 FROM CMS.UserPackagePurchases upp WHERE upp.UserId = p.UserId AND upp.IsDeleted = 0 ) THEN N'SKIP_HAS_UPP' ELSE N'NEEDS_UPP' END AS UppPlan FROM @Phase3 p INNER JOIN CMS.Users u ON u.Id = p.UserId AND u.IsDeleted = 0 ORDER BY p.UserId; ------------------------------------------------------------ -- Resolve Tx per user needing UPP ------------------------------------------------------------ SELECT p.UserId, u.Mobile, COALESCE( NULLIF(cm.LastPackageId, 0), NULLIF(cm.FirstPackageId, 0), @BasePackageId ) AS PackageId, COALESCE(cm.ActivatedAt, cm.Created, @Now) AS PurchasedAt, dep.TxId AS ExistingDepositTxId, dep.WhId AS ExistingDepositWhId, stub.StubWhId, stub.StubCreatedBy, CAST(NULL AS BIGINT) AS ResolvedTxId, CAST(N'' AS NVARCHAR(40)) AS TxSource, CAST(N'' AS NVARCHAR(40)) AS PlanAction INTO #Plan FROM @Phase3 p INNER JOIN CMS.Users u ON u.Id = p.UserId AND u.IsDeleted = 0 LEFT JOIN CMS.ClubMemberships cm ON cm.UserId = p.UserId AND cm.IsDeleted = 0 OUTER APPLY ( SELECT TOP (1) t.Id AS TxId, h.Id AS WhId FROM CMS.UserWallets w INNER JOIN CMS.UserWalletHistories h ON h.WalletId = w.Id AND h.IsDeleted = 0 INNER JOIN CMS.Transactions t ON t.Id = h.RefrenceId AND t.IsDeleted = 0 AND t.PaymentStatus = 0 AND t.Amount = @ChargeAmount WHERE w.UserId = p.UserId AND w.IsDeleted = 0 AND h.ChangeValue >= @ChargeAmount AND h.IsIncrease = 1 ORDER BY h.Id ASC ) dep OUTER APPLY ( SELECT TOP (1) h.Id AS StubWhId, h.CreatedBy AS StubCreatedBy FROM CMS.UserWallets w INNER JOIN CMS.UserWalletHistories h ON h.WalletId = w.Id AND h.IsDeleted = 0 WHERE w.UserId = p.UserId AND w.IsDeleted = 0 AND (h.RefrenceId IS NULL OR h.RefrenceId = 0) ORDER BY h.Id ASC ) stub WHERE NOT EXISTS ( SELECT 1 FROM CMS.UserPackagePurchases upp WHERE upp.UserId = p.UserId AND upp.IsDeleted = 0 ); -- Pass 1: existing full deposit WH→Tx UPDATE pl SET ResolvedTxId = pl.ExistingDepositTxId, TxSource = N'WH_DEPOSIT', PlanAction = N'CREATE_UPP_REUSE_TX' FROM #Plan pl WHERE pl.ExistingDepositTxId IS NOT NULL; -- Pass 2: stub CreatedBy → manualy Tx UPDATE pl SET ResolvedTxId = t.Id, TxSource = N'WH_STUB_HINT', PlanAction = N'FIX_STUB_LINK_UPP' FROM #Plan pl INNER JOIN CMS.Transactions t ON t.Id = TRY_CAST(pl.StubCreatedBy AS BIGINT) AND t.IsDeleted = 0 AND t.PaymentStatus = 0 AND t.RefId LIKE N'manualy%' WHERE pl.ResolvedTxId IS NULL AND TRY_CAST(pl.StubCreatedBy AS BIGINT) > 0; -- Pass 3: need new Tx UPDATE pl SET TxSource = N'CREATE_TX', PlanAction = N'CREATE_TX_WH_UPP' FROM #Plan pl WHERE pl.ResolvedTxId IS NULL; SELECT UserId, Mobile, PackageId, PurchasedAt, ExistingDepositTxId, ExistingDepositWhId, StubWhId, StubCreatedBy, ResolvedTxId, TxSource, PlanAction FROM #Plan ORDER BY UserId; DECLARE @NeedPlan INT = (SELECT COUNT(*) FROM #Plan); PRINT CONCAT('Users needing UPP in Phase3: ', @NeedPlan); ------------------------------------------------------------ -- Execute: cursor per user ------------------------------------------------------------ DECLARE @UserId BIGINT; DECLARE @Mobile NVARCHAR(50); DECLARE @PackageId BIGINT; DECLARE @PurchasedAt DATETIME2; DECLARE @ExistingDepositTxId BIGINT; DECLARE @StubWhId BIGINT; DECLARE @ResolvedTxId BIGINT; DECLARE @TxSource NVARCHAR(40); DECLARE @TxId BIGINT; DECLARE @WalletId BIGINT; DECLARE @DiscountAmount BIGINT; DECLARE @NetworkBalance BIGINT; DECLARE @HistoryAt DATETIME2; DECLARE @CreatedTx INT = 0; DECLARE @CreatedUpp INT = 0; DECLARE @CreatedWh INT = 0; DECLARE @FixedWh INT = 0; DECLARE cur CURSOR LOCAL FAST_FORWARD FOR SELECT UserId, Mobile, PackageId, PurchasedAt, ExistingDepositTxId, StubWhId, ResolvedTxId, TxSource FROM #Plan; OPEN cur; FETCH NEXT FROM cur INTO @UserId, @Mobile, @PackageId, @PurchasedAt, @ExistingDepositTxId, @StubWhId, @ResolvedTxId, @TxSource; WHILE @@FETCH_STATUS = 0 BEGIN SET @TxId = @ResolvedTxId; IF @TxId IS NULL BEGIN INSERT INTO CMS.Transactions ( Amount, Description, PaymentStatus, PaymentDate, RefId, Type, Created, CreatedBy, LastModified, LastModifiedBy, IsDeleted ) VALUES ( @ChargeAmount, N'عضویت دستی باشگاه مشتریان - backfill Phase3 WrongDaya', 0, @PurchasedAt, CONCAT(N'FIX3-', @UserId), 2, @PurchasedAt, @Mobile, @PurchasedAt, @Mobile, 0 ); SET @TxId = SCOPE_IDENTITY(); SET @CreatedTx = @CreatedTx + 1; END IF @StubWhId IS NOT NULL AND EXISTS ( SELECT 1 FROM CMS.UserWalletHistories h WHERE h.Id = @StubWhId AND h.IsDeleted = 0 AND (h.RefrenceId IS NULL OR h.RefrenceId = 0) ) BEGIN UPDATE CMS.UserWalletHistories SET RefrenceId = @TxId, LastModified = @Now WHERE Id = @StubWhId; SET @FixedWh = @FixedWh + @@ROWCOUNT; END SELECT @WalletId = w.Id, @NetworkBalance = COALESCE(w.NetworkBalance, 0) FROM CMS.UserWallets w WHERE w.UserId = @UserId AND w.IsDeleted = 0; IF @WalletId IS NULL BEGIN INSERT INTO CMS.UserWallets (UserId, Balance, NetworkBalance, DiscountBalance, WalletMode, Created, LastModified, IsDeleted) VALUES (@UserId, 0, 0, 0, 0, @PurchasedAt, @PurchasedAt, 0); SET @WalletId = SCOPE_IDENTITY(); SET @NetworkBalance = 0; END IF NOT EXISTS ( SELECT 1 FROM CMS.UserWalletHistories h WHERE h.WalletId = @WalletId AND h.IsDeleted = 0 AND h.RefrenceId = @TxId ) BEGIN SELECT @HistoryAt = COALESCE(t.PaymentDate, @PurchasedAt), @DiscountAmount = CAST(ROUND(@ChargeAmount * COALESCE(pkg.DiscountMultiplier, 2.0), 0) AS BIGINT) FROM CMS.Transactions t LEFT JOIN CMS.Packages pkg ON pkg.Id = @PackageId AND pkg.IsDeleted = 0 WHERE t.Id = @TxId; INSERT INTO CMS.UserWalletHistories ( WalletId, CurrentBalance, ChangeValue, CurrentNetworkBalance, ChangeNerworkValue, CurrentDiscountBalance, ChangeDiscountValue, IsIncrease, RefrenceId, PackageId, Created, CreatedBy, LastModified, LastModifiedBy, IsDeleted ) VALUES ( @WalletId, 0, @ChargeAmount, @NetworkBalance, 0, 0, @DiscountAmount, 1, @TxId, @PackageId, @HistoryAt, NULL, @HistoryAt, NULL, 0 ); SET @CreatedWh = @CreatedWh + 1; END IF NOT EXISTS ( SELECT 1 FROM CMS.UserPackagePurchases upp WHERE upp.UserId = @UserId AND upp.IsDeleted = 0 AND upp.TransactionId = @TxId ) BEGIN INSERT INTO CMS.UserPackagePurchases ( UserId, PackageId, PurchaseMethod, PurchasedAt, Amount, OrderId, TransactionId, Created, CreatedBy, LastModified, LastModifiedBy, IsDeleted ) VALUES ( @UserId, @PackageId, 3, @PurchasedAt, @ChargeAmount, NULL, @TxId, @Now, NULL, @Now, NULL, 0 ); SET @CreatedUpp = @CreatedUpp + 1; END FETCH NEXT FROM cur INTO @UserId, @Mobile, @PackageId, @PurchasedAt, @ExistingDepositTxId, @StubWhId, @ResolvedTxId, @TxSource; END CLOSE cur; DEALLOCATE cur; DROP TABLE #Plan; PRINT CONCAT('Tx created: ', @CreatedTx, ' | WH Ref fixed: ', @FixedWh, ' | WH created: ', @CreatedWh, ' | UPP created: ', @CreatedUpp); ------------------------------------------------------------ -- Verify all 16 have UPP ------------------------------------------------------------ SELECT p.UserId, u.Mobile, CASE WHEN upp.UppId IS NOT NULL THEN N'OK' ELSE N'MISSING_UPP' END AS UppStatus, upp.UppId, upp.PurchaseMethod, upp.TransactionId AS UppTxId, t.RefId AS TxRefId FROM @Phase3 p INNER JOIN CMS.Users u ON u.Id = p.UserId AND u.IsDeleted = 0 OUTER APPLY ( SELECT TOP (1) upp2.Id AS UppId, upp2.PurchaseMethod, upp2.TransactionId FROM CMS.UserPackagePurchases upp2 WHERE upp2.UserId = p.UserId AND upp2.IsDeleted = 0 ORDER BY upp2.Id DESC ) upp LEFT JOIN CMS.Transactions t ON t.Id = upp.TransactionId ORDER BY p.UserId; SELECT N'Phase3 users still without UPP' AS CheckName, COUNT(*) AS Cnt FROM @Phase3 p WHERE NOT EXISTS ( SELECT 1 FROM CMS.UserPackagePurchases upp WHERE upp.UserId = p.UserId AND upp.IsDeleted = 0 ); ROLLBACK; -- COMMIT; PRINT 'Done (rolled back by default). Uncomment COMMIT when preview looks correct.';