# Club Membership Migration Scripts **Created**: 2025-12-09 **Purpose**: مهاجرت کاربران موجود به سیستم باشگاه مشتریان **Location**: `/dbbkup/` --- ## 📋 Overview این اسکریپت‌ها کاربرانی که قبل از راه‌اندازی سیستم باشگاه مشتریان، مبلغ 56 میلیون ریال شارژ کرده‌اند را به‌طور خودکار عضو باشگاه می‌کنند. --- ## 📄 Scripts ### 1. MigrateUsersToClubMembership.sql (نسخه کامل) **Path**: `/dbbkup/MigrateUsersToClubMembership.sql` **Features**: - ✅ بررسی `UserWalletChangeLogs` برای محاسبه مجموع شارژ‌ها - ✅ Fallback به `Transactions` اگر Logs خالی بود - ✅ ثبت تاریخ دقیق اولین شارژ به‌عنوان `ActivatedAt` - ✅ Skip کاربرانی که قبلاً عضو باشگاه هستند - ✅ Transaction-safe (هر کاربر یک transaction جداگانه) - ✅ گزارش کامل (موفقیت‌ها + خطاها) **What It Does**: ```sql -- برای هر کاربر با شارژ >= 56M: 1. INSERT INTO ClubMemberships (UserId, ActivatedAt=FirstChargeDate, InitialContribution=25M) 2. INSERT INTO ClubMembershipHistories (Action=0, Reason='فعال‌سازی خودکار - مهاجرت') 3. INSERT INTO UserClubFeatures (ClubFeatureId IN (1,2,3,4), Notes='اعطا شده خودکار') ``` **Sample Output**: ``` ╔═══════════════════════════════════════════════════════════════╗ ║ شروع فرآیند انتقال کاربران به باشگاه مشتریان ║ ╚═══════════════════════════════════════════════════════════════╝ تاریخ و زمان اجرا: 2025-12-09 16:30:00.0000000 مبلغ سهم استخر: 25,000,000 ریال ───────────────────────────────────────────────────────────────── 📊 تعداد کاربران کاندید: 45 ───────────────────────────────────────────────────────────────── 🔄 شروع ثبت عضویت‌ها... ✓ کاربر 1001 (علی محمدی - 1234567890): عضویت با ID 501 ایجاد شد. ✓ کاربر 1002 (سارا احمدی - 0987654321): عضویت با ID 502 ایجاد شد. ... ───────────────────────────────────────────────────────────────── ╔═══════════════════════════════════════════════════════════════╗ ║ گزارش نهایی مهاجرت ║ ╚═══════════════════════════════════════════════════════════════╝ تعداد کل کاندیدها: 45 تعداد قبلاً عضو: 0 تعداد پردازش شده: 45 تعداد خطا: 0 مجموع سهم استخر: 1,125,000,000 ریال ✓ فرآیند مهاجرت با موفقیت به پایان رسید. ``` --- ### 2. MigrateUsersToClubMembership_Simple.sql (نسخه ساده) **Path**: `/dbbkup/MigrateUsersToClubMembership_Simple.sql` **Features**: - ✅ بررسی موجودی فعلی (`UserWallets.Balance` >= 56M) - ✅ سریع‌تر از نسخه کامل - ✅ برای سیستم‌هایی که تاریخچه شارژ ندارند - ✅ همان Transaction safety **Difference**: ```sql -- نسخه کامل: SUM(uwcl.ChangeValue) >= 56000000 -- از تاریخچه -- نسخه ساده: uw.Balance >= 56000000 -- از موجودی فعلی ``` --- ## 🔧 Technical Details ### Transaction Strategy **قبلی (اشتباه)**: ```sql BEGIN TRANSACTION; -- یک transaction بزرگ -- 100 INSERT... COMMIT TRANSACTION; ``` ❌ با cursor سازگار نیست! → `log file overflow` **فعلی (صحیح)**: ```sql WHILE @@FETCH_STATUS = 0 BEGIN BEGIN TRANSACTION; -- transaction جداگانه INSERT ClubMemberships; INSERT ClubMembershipHistories; INSERT UserClubFeatures (4 rows); COMMIT TRANSACTION; -- برای هر کاربر END ``` ✅ هر کاربر مستقل → اگر یکی خطا داد، بقیه commit می‌شوند --- ### Schema Compatibility **تغییرات از Schema واقعی**: 1. ❌ حذف `User.ClubMembershipId` (این ستون وجود نداره!) 2. ✅ رابطه: `ClubMemberships.UserId → Users.Id` (یک‌طرفه) 3. ✅ `Action` از نوع `INT` است (نه `NVARCHAR`): - `0` = Activated - `1` = Deactivated **Unicode Encoding**: ```sql -- اشتباه (encoding خراب): N'فارسی' -- در SELECT باز هم خراب می‌شه! -- درست: CAST(N'فعال‌سازی خودکار' AS NVARCHAR(500)) ``` --- ## 📊 Data Flow ``` ┌─────────────────────────────────────────────────────────┐ │ 1. Query: Users with TotalCharge >= 56M │ │ Sources: UserWalletChangeLogs OR Transactions │ └─────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────┐ │ 2. Filter: Skip users already in ClubMemberships │ └─────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────┐ │ 3. For Each User (in cursor): │ │ BEGIN TRANSACTION │ │ ├─ INSERT ClubMembership │ │ │ (UserId, ActivatedAt=FirstCharge, │ │ │ InitialContribution=25M) │ │ ├─ INSERT ClubMembershipHistory │ │ │ (Action=0, Reason='مهاجرت داده‌ها') │ │ └─ INSERT UserClubFeatures (x4) │ │ (ClubFeatureId IN (1,2,3,4)) │ │ COMMIT TRANSACTION │ └─────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────┐ │ 4. Report: Success count, Errors, Summary │ └─────────────────────────────────────────────────────────┘ ``` --- ## ⚙️ Configuration Variables ```sql DECLARE @InitialContribution BIGINT = 25000000; -- 25M به صندوق DECLARE @ChargeAmount BIGINT = 56000000; -- 56M شارژ DECLARE @CurrentDateTime DATETIME2(7) = SYSDATETIME(); ``` **Adjustable**: - `@ChargeAmount`: تغییر حداقل مبلغ شارژ - `@InitialContribution`: تغییر سهم استخر --- ## 🧪 Testing Queries ### 1. شمارش کاربران واجد شرایط ```sql -- نسخه کامل: SELECT COUNT(DISTINCT u.Id) FROM [CMS].[Users] u INNER JOIN [CMS].[UserWallets] uw ON uw.UserId = u.Id INNER JOIN [CMS].[UserWalletChangeLogs] uwcl ON uwcl.WalletId = uw.Id WHERE u.IsDeleted = 0 AND uwcl.IsIncrease = 1 AND uwcl.ChangeValue > 0 GROUP BY u.Id HAVING SUM(uwcl.ChangeValue) >= 56000000; -- نسخه ساده: SELECT COUNT(*) FROM [CMS].[Users] u INNER JOIN [CMS].[UserWallets] uw ON uw.UserId = u.Id LEFT JOIN [CMS].[ClubMemberships] cm ON cm.UserId = u.Id WHERE u.IsDeleted = 0 AND cm.Id IS NULL AND uw.Balance >= 56000000; ``` ### 2. تأیید ویژگی‌های ثبت شده ```sql SELECT cm.Id AS MembershipId, cm.UserId, u.FirstName + ' ' + u.LastName AS FullName, cm.ActivatedAt, COUNT(ucf.Id) AS FeaturesCount FROM [CMS].[ClubMemberships] cm INNER JOIN [CMS].[Users] u ON u.Id = cm.UserId LEFT JOIN [CMS].[UserClubFeatures] ucf ON ucf.ClubMembershipId = cm.Id WHERE cm.Created >= '2025-12-09' -- امروز GROUP BY cm.Id, cm.UserId, u.FirstName, u.LastName, cm.ActivatedAt HAVING COUNT(ucf.Id) != 4; -- باید 4 تا باشه! ``` ### 3. چک کردن History ```sql SELECT h.UserId, u.FirstName + ' ' + u.LastName AS FullName, h.Action, h.Reason, h.Created FROM [CMS].[ClubMembershipHistories] h INNER JOIN [CMS].[Users] u ON u.Id = h.UserId WHERE h.CreatedBy = 'MigrationScript' ORDER BY h.Created DESC; ``` --- ## 🚨 Error Handling **Script Behavior**: - ✅ هر transaction جداگانه → اگر یک کاربر fail شد، بقیه commit می‌شوند - ✅ خطاها در `@ProcessLog` ذخیره می‌شوند - ✅ گزارش نهایی شامل لیست کامل خطاها **Common Errors**: 1. **"Invalid column 'UserName'"** → ستون وجود نداره (باید `FirstName + LastName`) 2. **"Invalid column 'ClubMembershipId'"** → در جدول `Users` نیست 3. **"Conversion failed 'Activated'"** → باید `0` باشه نه `'Activated'` 4. **"Transaction cannot be committed"** → نباید `SET XACT_ABORT ON` باشه با cursor --- ## 📝 Notes 1. **Idempotent**: اجرای مجدد اسکریپت، کاربران قبلی را skip می‌کند 2. **Rollback-Safe**: اگر کل script fail شد، چیزی commit نمی‌شه 3. **Performance**: برای 1000+ کاربر، ممکنه 5-10 دقیقه طول بکشه 4. **Logging**: تمام عملیات‌ها با `CreatedBy = 'MigrationScript'` قابل شناسایی هستند --- ## 🎯 Post-Migration Checklist - [ ] شمارش کاربران مهاجرت شده = تعداد موردانتظار - [ ] تمام اعضای جدید 4 ویژگی دارند (`UserClubFeatures.Count = 4`) - [ ] همه `ClubMembershipHistories` با `Action = 0` ثبت شده‌اند - [ ] مجموع `InitialContribution` با `ClubMemberships.Count × 25M` برابره - [ ] هیچ خطایی در گزارش نهایی نیست (`@ErrorCount = 0`) --- **Last Updated**: 2025-12-09 **Author**: Migration Script Generator **Version**: 1.0