Files
docs/archive/03-BACKEND/CMS/club-membership-migration.md
T
masoodafar-web 5965b98728 update
2026-01-03 18:27:49 +03:30

282 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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