/* DIAGNOSTIC ONLY — no data changes (read-only) Trace WrongDaya→Manual FixUsers ledger via UserWalletHistory: WalletHistory → CreatedBy/LastModifiedBy (mobile) → User → Wallet → Transaction (RefrenceId / CreatedBy-as-TxId / Tx.CreatedBy mobile) → UPP / ManualPayment / PurchaseMethod Known IDs from manual CSV exports (UserWalletHistories*.csv, Transactions.csv): WH: 102-108,122,138-142,292-295,118-121,124,201 Tx: 23-31,42-46,56-59,68,107-110 RefrenceId=0 rule (ChargeUserWallets.sql): RefId = 'manualy' + original ChangeLogId. After id remap, WH.RefrenceId may be 0. For Ref=0 rows, assume Tx exists ONLY if CreatedBy is numeric AND that Tx has RefId manualy%. Do NOT infer Tx from mobile alone or from manualy{N} suffix alone. See also: 10-Diagnose_Manualy_Transaction_Map.sql Run on staging, review Verdict + RecommendedAction per user before any fix script. */ SET NOCOUNT ON; DECLARE @FixUsers TABLE (UserId BIGINT PRIMARY KEY); INSERT INTO @FixUsers (UserId) VALUES (2),(7),(8),(9),(10),(11),(12),(13),(40),(41),(43),(45),(47), (52),(58),(69),(71),(72),(74),(75),(87),(88),(89),(90),(91),(93), (96),(99),(103),(105),(106),(111),(113),(115),(116),(119),(121), (125),(130),(142),(162),(169),(170),(171),(172),(175),(176); -- Known WalletHistory / Transaction ids from CSV exports (for cross-check) DECLARE @KnownWh TABLE (WalletHistoryId BIGINT PRIMARY KEY); INSERT INTO @KnownWh (WalletHistoryId) VALUES (102),(103),(104),(105),(106),(107),(108),(122), (138),(139),(140),(141),(142), (292),(293),(294),(295), (118),(119),(120),(121),(124),(201); DECLARE @KnownTx TABLE (TransactionId BIGINT PRIMARY KEY); INSERT INTO @KnownTx (TransactionId) VALUES (23),(24),(25),(26),(28),(29),(30),(31), (42),(43),(44),(45),(46), (56),(57),(58),(59),(68), (107),(108),(109),(110); DECLARE @TargetUserCount INT = (SELECT COUNT(*) FROM @FixUsers); PRINT CONCAT('FixUsers scope: ', @TargetUserCount); ------------------------------------------------------------ -- 1) WalletHistories found BY mobile in CreatedBy / LastModifiedBy -- (starts from WH — user request) ------------------------------------------------------------ PRINT '=== 1) WalletHistory → User via CreatedBy/LastModifiedBy mobile ==='; SELECT h.Id AS WalletHistoryId, h.WalletId, h.RefrenceId AS WhRefrenceId, h.ChangeValue, h.ChangeDiscountValue, h.Created AS WhCreated, h.CreatedBy AS WhCreatedBy, h.LastModifiedBy AS WhLastModifiedBy, u.Id AS UserId, u.Mobile, u.FirstName, u.LastName, u.PackagePurchaseMethod AS UserMethod, CASE WHEN kwh.WalletHistoryId IS NOT NULL THEN 1 ELSE 0 END AS InKnownWhCsv, CASE WHEN u.Id IS NULL THEN N'NO_USER_FOR_MOBILE' WHEN f.UserId IS NULL THEN N'USER_NOT_IN_FIX_SCOPE' ELSE N'IN_FIX_SCOPE' END AS ScopeStatus FROM CMS.UserWalletHistories h LEFT JOIN CMS.Users u ON u.IsDeleted = 0 AND u.Mobile IN ( NULLIF(LTRIM(RTRIM(h.CreatedBy)), N''), NULLIF(LTRIM(RTRIM(h.LastModifiedBy)), N'') ) LEFT JOIN @FixUsers f ON f.UserId = u.Id LEFT JOIN @KnownWh kwh ON kwh.WalletHistoryId = h.Id WHERE h.IsDeleted = 0 AND ( (h.CreatedBy LIKE N'09%' AND LEN(h.CreatedBy) >= 10) OR (h.LastModifiedBy LIKE N'09%' AND LEN(h.LastModifiedBy) >= 10) ) ORDER BY h.Id; ------------------------------------------------------------ -- 2) All WalletHistories for FixUsers (via Wallet → User) ------------------------------------------------------------ PRINT '=== 2) All WalletHistory rows for FixUsers ==='; SELECT f.UserId, u.Mobile, u.FirstName, u.LastName, u.PackagePurchaseMethod AS UserMethod, w.Id AS WalletId, h.Id AS WalletHistoryId, h.RefrenceId AS WhRefrenceId, h.ChangeValue, h.ChangeDiscountValue, h.Created AS WhCreated, h.CreatedBy AS WhCreatedBy, h.LastModifiedBy AS WhLastModifiedBy, CASE WHEN kwh.WalletHistoryId IS NOT NULL THEN 1 ELSE 0 END AS InKnownWhCsv, CASE WHEN h.RefrenceId IS NULL OR h.RefrenceId = 0 THEN N'WH_NO_REF' ELSE N'WH_HAS_REF' END AS WhRefStatus FROM @FixUsers f INNER JOIN CMS.Users u ON u.Id = f.UserId AND u.IsDeleted = 0 INNER JOIN CMS.UserWallets w ON w.UserId = f.UserId AND w.IsDeleted = 0 INNER JOIN CMS.UserWalletHistories h ON h.WalletId = w.Id AND h.IsDeleted = 0 LEFT JOIN @KnownWh kwh ON kwh.WalletHistoryId = h.Id ORDER BY f.UserId, h.Id; ------------------------------------------------------------ -- 3) Per-user ledger verdict (WH + Tx + UPP) ------------------------------------------------------------ PRINT '=== 3) Per-user ledger verdict ==='; ;WITH UserWh AS ( SELECT f.UserId, COUNT(*) AS WalletHistoryCount, SUM(CASE WHEN h.RefrenceId IS NULL OR h.RefrenceId = 0 THEN 1 ELSE 0 END) AS WhMissingRefCount, SUM(CASE WHEN kwh.WalletHistoryId IS NOT NULL THEN 1 ELSE 0 END) AS KnownCsvWhCount, MAX(h.Id) AS LatestWhId, MAX(h.RefrenceId) AS LatestWhRefId FROM @FixUsers f INNER JOIN CMS.UserWallets w ON w.UserId = f.UserId AND w.IsDeleted = 0 LEFT JOIN CMS.UserWalletHistories h ON h.WalletId = w.Id AND h.IsDeleted = 0 LEFT JOIN @KnownWh kwh ON kwh.WalletHistoryId = h.Id GROUP BY f.UserId ), UserTxViaWh AS ( SELECT uw.UserId, COUNT(DISTINCT t.Id) AS TxViaWhRefCount, MAX(t.Id) AS SampleTxViaWhRef FROM UserWh uw INNER JOIN CMS.UserWallets w ON w.UserId = uw.UserId AND w.IsDeleted = 0 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 GROUP BY uw.UserId ), UserTxViaMobile AS ( SELECT f.UserId, COUNT(DISTINCT t.Id) AS TxViaMobileCount, MAX(t.Id) AS SampleTxViaMobile FROM @FixUsers f INNER JOIN CMS.Users u ON u.Id = f.UserId AND u.IsDeleted = 0 INNER JOIN CMS.Transactions t ON t.IsDeleted = 0 AND (t.CreatedBy = u.Mobile OR t.LastModifiedBy = u.Mobile) GROUP BY f.UserId ), UserTxViaCreatedByHint AS ( -- WH.CreatedBy stores Tx Id when RefrenceId=0 failed to update (UserWalletHistories2.csv). -- Only count when hinted Tx exists AND is manualy% (may still be wrong user — verify mobile). SELECT f.UserId, COUNT(DISTINCT t.Id) AS TxViaWhCreatedByHintCount, MAX(t.Id) AS SampleTxViaHint FROM @FixUsers f INNER JOIN CMS.UserWallets w ON w.UserId = f.UserId AND w.IsDeleted = 0 INNER JOIN CMS.UserWalletHistories h ON h.WalletId = w.Id AND h.IsDeleted = 0 INNER JOIN CMS.Transactions t ON t.Id = TRY_CAST(h.CreatedBy AS BIGINT) AND t.IsDeleted = 0 AND t.RefId LIKE N'manualy%' WHERE (h.RefrenceId IS NULL OR h.RefrenceId = 0) AND TRY_CAST(h.CreatedBy AS BIGINT) > 0 GROUP BY f.UserId ), UserTxViaManualyMobile AS ( -- Informational only — NOT used alone for Ref=0 WH linking SELECT f.UserId, COUNT(DISTINCT t.Id) AS TxViaManualyMobileCount, MAX(t.Id) AS SampleManualyTxViaMobile FROM @FixUsers f INNER JOIN CMS.Users u ON u.Id = f.UserId AND u.IsDeleted = 0 INNER JOIN CMS.Transactions t ON t.IsDeleted = 0 AND t.RefId LIKE N'manualy%' AND u.Mobile IN ( NULLIF(LTRIM(RTRIM(t.CreatedBy)), N''), NULLIF(LTRIM(RTRIM(t.LastModifiedBy)), N'') ) GROUP BY f.UserId ), UserUpp AS ( SELECT f.UserId, COUNT(*) AS UppCount, SUM(CASE WHEN upp.PurchaseMethod = 1 THEN 1 ELSE 0 END) AS UppDayaCount, SUM(CASE WHEN upp.PurchaseMethod = 3 THEN 1 ELSE 0 END) AS UppManualCount, MAX(upp.TransactionId) AS LatestUppTxId FROM @FixUsers f LEFT JOIN CMS.UserPackagePurchases upp ON upp.UserId = f.UserId AND upp.IsDeleted = 0 GROUP BY f.UserId ), UserMp AS ( SELECT f.UserId, COUNT(*) AS ManualPaymentCount, MAX(mp.TransactionId) AS LatestMpTxId FROM @FixUsers f LEFT JOIN CMS.ManualPayments mp ON mp.UserId = f.UserId AND mp.IsDeleted = 0 GROUP BY f.UserId ) SELECT * FROM ( SELECT f.UserId, u.Mobile, u.FirstName, u.LastName, u.PackagePurchaseMethod AS UserMethod, ISNULL(uwh.WalletHistoryCount, 0) AS WalletHistoryCount, ISNULL(uwh.WhMissingRefCount, 0) AS WhMissingRefCount, ISNULL(uwh.KnownCsvWhCount, 0) AS KnownCsvWhCount, uwh.LatestWhId, uwh.LatestWhRefId, ISNULL(utw.TxViaWhRefCount, 0) AS TxViaWhRefCount, utw.SampleTxViaWhRef, ISNULL(utm.TxViaMobileCount, 0) AS TxViaMobileCount, utm.SampleTxViaMobile, ISNULL(uth.TxViaWhCreatedByHintCount, 0) AS TxViaWhCreatedByHintCount, uth.SampleTxViaHint, ISNULL(utmm.TxViaManualyMobileCount, 0) AS TxViaManualyMobileCount, utmm.SampleManualyTxViaMobile, ISNULL(uu.UppCount, 0) AS UppCount, ISNULL(uu.UppDayaCount, 0) AS UppDayaCount, uu.LatestUppTxId, ISNULL(ump.ManualPaymentCount, 0) AS ManualPaymentCount, ump.LatestMpTxId, CASE WHEN ISNULL(uwh.WalletHistoryCount, 0) = 0 THEN N'NO_WALLET_HISTORY' WHEN ISNULL(uwh.WhMissingRefCount, 0) > 0 AND ISNULL(uth.TxViaWhCreatedByHintCount, 0) > 0 THEN N'WH_REF_BROKEN_FIX_VIA_CREATEDBY_HINT' WHEN ISNULL(uwh.WhMissingRefCount, 0) > 0 AND ISNULL(utmm.TxViaManualyMobileCount, 0) > 0 THEN N'WH_REF_BROKEN_MANUALY_TX_BY_MOBILE_REVIEW' WHEN ISNULL(uwh.WhMissingRefCount, 0) > 0 THEN N'WH_REF_BROKEN_NO_TX_HINT' WHEN ISNULL(utw.TxViaWhRefCount, 0) > 0 AND ISNULL(uu.UppCount, 0) = 0 THEN N'HAS_WH+TX_NEED_UPP' WHEN ISNULL(utw.TxViaWhRefCount, 0) > 0 AND ISNULL(uu.UppDayaCount, 0) > 0 THEN N'HAS_WH+TX_UPP_DAYA_FIX_METHOD' WHEN ISNULL(utw.TxViaWhRefCount, 0) > 0 THEN N'OK_WH+TX' WHEN ISNULL(utm.TxViaMobileCount, 0) > 0 THEN N'TX_BY_MOBILE_WH_LINK_UNCLEAR' ELSE N'NEEDS_MANUAL_REVIEW' END AS Verdict, CASE WHEN ISNULL(uwh.WalletHistoryCount, 0) = 0 THEN N'Create WH+Tx+UPP (or find hidden WH by mobile)' WHEN ISNULL(uwh.WhMissingRefCount, 0) > 0 AND ISNULL(uth.TxViaWhCreatedByHintCount, 0) > 0 THEN N'Link WH.RefrenceId to manualy Tx from CreatedBy hint only' WHEN ISNULL(uwh.WhMissingRefCount, 0) > 0 AND ISNULL(utmm.TxViaManualyMobileCount, 0) > 0 THEN N'manualy Tx exists by mobile but WH hint missing — manual review' WHEN ISNULL(uwh.WhMissingRefCount, 0) > 0 THEN N'No Tx hint — do NOT assume Tx exists; review charge log' WHEN ISNULL(utw.TxViaWhRefCount, 0) > 0 AND ISNULL(uu.UppCount, 0) = 0 THEN N'Create UPP Manual(3) reusing Tx' WHEN ISNULL(uu.UppDayaCount, 0) > 0 OR u.PackagePurchaseMethod = 1 THEN N'Fix PurchaseMethod 1→3 only' ELSE N'Likely OK — verify PurchaseMethod' END AS RecommendedAction FROM @FixUsers f INNER JOIN CMS.Users u ON u.Id = f.UserId AND u.IsDeleted = 0 LEFT JOIN UserWh uwh ON uwh.UserId = f.UserId LEFT JOIN UserTxViaWh utw ON utw.UserId = f.UserId LEFT JOIN UserTxViaMobile utm ON utm.UserId = f.UserId LEFT JOIN UserTxViaCreatedByHint uth ON uth.UserId = f.UserId LEFT JOIN UserTxViaManualyMobile utmm ON utmm.UserId = f.UserId LEFT JOIN UserUpp uu ON uu.UserId = f.UserId LEFT JOIN UserMp ump ON ump.UserId = f.UserId ) q ORDER BY CASE q.Verdict WHEN N'OK_WH+TX' THEN 9 WHEN N'HAS_WH+TX_UPP_DAYA_FIX_METHOD' THEN 8 ELSE 1 END, q.UserId; ------------------------------------------------------------ -- 4) Summary counts by Verdict ------------------------------------------------------------ PRINT '=== 4) Summary by Verdict ==='; ;WITH PerUser AS ( SELECT f.UserId, u.PackagePurchaseMethod AS UserMethod, ISNULL(uwh.Cnt, 0) AS WhCnt, ISNULL(uwh.BadRefCnt, 0) AS WhBadRefCnt, ISNULL(utw.Cnt, 0) AS TxViaWhCnt, ISNULL(utm.Cnt, 0) AS TxViaMobileCnt, ISNULL(uth.Cnt, 0) AS TxViaHintCnt, ISNULL(uu.Cnt, 0) AS UppCnt FROM @FixUsers f INNER JOIN CMS.Users u ON u.Id = f.UserId AND u.IsDeleted = 0 OUTER APPLY ( SELECT COUNT(*) AS Cnt, SUM(CASE WHEN h.RefrenceId IS NULL OR h.RefrenceId = 0 THEN 1 ELSE 0 END) AS BadRefCnt FROM CMS.UserWallets w INNER JOIN CMS.UserWalletHistories h ON h.WalletId = w.Id AND h.IsDeleted = 0 WHERE w.UserId = f.UserId AND w.IsDeleted = 0 ) uwh OUTER APPLY ( SELECT COUNT(DISTINCT t.Id) AS Cnt 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 WHERE w.UserId = f.UserId AND w.IsDeleted = 0 ) utw OUTER APPLY ( SELECT COUNT(DISTINCT t.Id) AS Cnt FROM CMS.Transactions t WHERE t.IsDeleted = 0 AND (t.CreatedBy = u.Mobile OR t.LastModifiedBy = u.Mobile) ) utm OUTER APPLY ( SELECT COUNT(DISTINCT t.Id) AS Cnt 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 = TRY_CAST(h.CreatedBy AS BIGINT) AND t.IsDeleted = 0 AND t.RefId LIKE N'manualy%' WHERE w.UserId = f.UserId AND w.IsDeleted = 0 AND (h.RefrenceId IS NULL OR h.RefrenceId = 0) AND TRY_CAST(h.CreatedBy AS BIGINT) > 0 ) uth OUTER APPLY ( SELECT COUNT(*) AS Cnt FROM CMS.UserPackagePurchases upp WHERE upp.UserId = f.UserId AND upp.IsDeleted = 0 ) uu ), Verdicts AS ( SELECT UserId, CASE WHEN WhCnt = 0 THEN N'NO_WALLET_HISTORY' WHEN WhBadRefCnt > 0 AND TxViaHintCnt > 0 THEN N'WH_REF_BROKEN_FIX_VIA_CREATEDBY_HINT' WHEN WhBadRefCnt > 0 THEN N'WH_REF_BROKEN_NO_TX_HINT' WHEN TxViaWhCnt > 0 AND UppCnt = 0 THEN N'HAS_WH+TX_NEED_UPP' WHEN TxViaWhCnt > 0 THEN N'OK_WH+TX' WHEN TxViaMobileCnt > 0 THEN N'TX_BY_MOBILE_WH_LINK_UNCLEAR' ELSE N'NEEDS_MANUAL_REVIEW' END AS Verdict FROM PerUser ) SELECT Verdict, COUNT(*) AS UserCount FROM Verdicts GROUP BY Verdict ORDER BY UserCount DESC; ------------------------------------------------------------ -- 5) Known CSV Tx ids — exist in DB? linked to WH/UPP? ------------------------------------------------------------ PRINT '=== 5) Known Transaction IDs from CSV ==='; SELECT kt.TransactionId, CASE WHEN t.Id IS NULL THEN N'MISSING_IN_DB' ELSE N'EXISTS' END AS TxStatus, t.Amount, t.Description, t.RefId, t.CreatedBy AS TxCreatedBy, t.LastModifiedBy AS TxLastModifiedBy, u.Id AS UserByMobile, u.Mobile, h.Id AS LinkedWalletHistoryId, h.WalletId, h.RefrenceId AS WhRefrenceId, upp.UserId AS UppUserId, upp.PurchaseMethod AS UppMethod FROM @KnownTx kt LEFT JOIN CMS.Transactions t ON t.Id = kt.TransactionId LEFT JOIN CMS.Users u ON u.IsDeleted = 0 AND u.Mobile IN (NULLIF(t.CreatedBy, N''), NULLIF(t.LastModifiedBy, N'')) LEFT JOIN CMS.UserWalletHistories h ON h.IsDeleted = 0 AND h.RefrenceId = kt.TransactionId LEFT JOIN CMS.UserPackagePurchases upp ON upp.IsDeleted = 0 AND upp.TransactionId = kt.TransactionId ORDER BY kt.TransactionId; ------------------------------------------------------------ -- 6) Known CSV WH ids — RefrenceId vs CreatedBy hint vs mobile ------------------------------------------------------------ PRINT '=== 6) Known WalletHistory IDs from CSV ==='; SELECT kw.WalletHistoryId, h.WalletId, h.RefrenceId AS WhRefrenceId, h.ChangeValue, h.CreatedBy AS WhCreatedBy, h.LastModifiedBy AS WhLastModifiedBy, w.UserId AS WalletUserId, u.Mobile AS WalletUserMobile, u_by_mobile.Id AS UserByWhMobile, u_by_mobile.Mobile AS MatchedMobile, t_ref.Id AS TxByRefrenceId, t_ref.Description AS TxByRefDescription, t_hint.Id AS TxByCreatedByHint, t_hint.RefId AS TxByHintRefId, t_hint.Description AS TxByHintDescription, TRY_CAST( SUBSTRING(t_hint.RefId, LEN(N'manualy') + 1, 20) AS BIGINT ) AS ManualyOriginalChangeLogId, CASE WHEN h.Id IS NULL THEN N'WH_MISSING_IN_DB' WHEN t_ref.Id IS NOT NULL AND t_ref.RefId LIKE N'manualy%' THEN N'WH_LINKED_TO_MANUALY_TX' WHEN t_ref.Id IS NOT NULL THEN N'WH_LINKED_TO_OTHER_TX' WHEN t_hint.Id IS NOT NULL AND t_hint.RefId LIKE N'manualy%' THEN N'WH_REF_BROKEN_USE_CREATEDBY_HINT' WHEN TRY_CAST(h.CreatedBy AS BIGINT) > 0 AND t_hint.Id IS NULL THEN N'WH_HINT_TX_MISSING' WHEN u_by_mobile.Id IS NOT NULL THEN N'WH_MOBILE_ONLY_NO_AUTO_LINK' ELSE N'WH_ORPHAN_REVIEW' END AS WhLinkStatus FROM @KnownWh kw LEFT JOIN CMS.UserWalletHistories h ON h.Id = kw.WalletHistoryId AND h.IsDeleted = 0 LEFT JOIN CMS.UserWallets w ON w.Id = h.WalletId AND w.IsDeleted = 0 LEFT JOIN CMS.Users u ON u.Id = w.UserId AND u.IsDeleted = 0 LEFT JOIN CMS.Users u_by_mobile ON u_by_mobile.IsDeleted = 0 AND u_by_mobile.Mobile IN ( NULLIF(LTRIM(RTRIM(h.CreatedBy)), N''), NULLIF(LTRIM(RTRIM(h.LastModifiedBy)), N'') ) LEFT JOIN CMS.Transactions t_ref ON t_ref.Id = h.RefrenceId AND t_ref.IsDeleted = 0 LEFT JOIN CMS.Transactions t_hint ON t_hint.Id = TRY_CAST(h.CreatedBy AS BIGINT) AND t_hint.IsDeleted = 0 ORDER BY kw.WalletHistoryId; PRINT 'Done (diagnostic only — no changes).';