002e99f6bf
- Added PersianDateTimeService for converting Gregorian dates to Persian format in the BackOffice frontend. - Updated multiple frontend pages (Dashboard, UserPayouts, WorkerControl, UserNetworkInfo) to utilize the new Persian date service. - Enhanced GetUserNetworkPositionDto with 28+ new fields for comprehensive user network data. - Updated GetUserNetworkPositionQueryHandler to include new methods for calculating network statistics. - Modified Protobuf messages to accommodate the new fields, increasing from 14 to 42. - Refined week number calculation algorithm to ensure consistency across C# and SQL implementations. - Created new CSV and Excel files for binary plan calculations. - Ensured all changes are tested and validated for accuracy and performance.
11 KiB
11 KiB
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:
-- برای هر کاربر با شارژ >= 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:
-- نسخه کامل:
SUM(uwcl.ChangeValue) >= 56000000 -- از تاریخچه
-- نسخه ساده:
uw.Balance >= 56000000 -- از موجودی فعلی
🔧 Technical Details
Transaction Strategy
قبلی (اشتباه):
BEGIN TRANSACTION; -- یک transaction بزرگ
-- 100 INSERT...
COMMIT TRANSACTION;
❌ با cursor سازگار نیست! → log file overflow
فعلی (صحیح):
WHILE @@FETCH_STATUS = 0
BEGIN
BEGIN TRANSACTION; -- transaction جداگانه
INSERT ClubMemberships;
INSERT ClubMembershipHistories;
INSERT UserClubFeatures (4 rows);
COMMIT TRANSACTION; -- برای هر کاربر
END
✅ هر کاربر مستقل → اگر یکی خطا داد، بقیه commit میشوند
Schema Compatibility
تغییرات از Schema واقعی:
- ❌ حذف
User.ClubMembershipId(این ستون وجود نداره!) - ✅ رابطه:
ClubMemberships.UserId → Users.Id(یکطرفه) - ✅
Actionاز نوعINTاست (نهNVARCHAR):0= Activated1= Deactivated
Unicode Encoding:
-- اشتباه (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
DECLARE @InitialContribution BIGINT = 25000000; -- 25M به صندوق
DECLARE @ChargeAmount BIGINT = 56000000; -- 56M شارژ
DECLARE @CurrentDateTime DATETIME2(7) = SYSDATETIME();
Adjustable:
@ChargeAmount: تغییر حداقل مبلغ شارژ@InitialContribution: تغییر سهم استخر
🧪 Testing Queries
1. شمارش کاربران واجد شرایط
-- نسخه کامل:
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. تأیید ویژگیهای ثبت شده
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
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:
- "Invalid column 'UserName'" → ستون وجود نداره (باید
FirstName + LastName) - "Invalid column 'ClubMembershipId'" → در جدول
Usersنیست - "Conversion failed 'Activated'" → باید
0باشه نه'Activated' - "Transaction cannot be committed" → نباید
SET XACT_ABORT ONباشه با cursor
📝 Notes
- Idempotent: اجرای مجدد اسکریپت، کاربران قبلی را skip میکند
- Rollback-Safe: اگر کل script fail شد، چیزی commit نمیشه
- Performance: برای 1000+ کاربر، ممکنه 5-10 دقیقه طول بکشه
- 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