update
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,547 @@
|
||||
# 🎯 اسپرینت جاری (Current Sprint)
|
||||
|
||||
**تاریخ شروع**: ۱۴ آذر ۱۴۰۴
|
||||
**آخرین بروزرسانی**: ۲۸ آذر ۱۴۰۴
|
||||
**مدت**: 2 هفته
|
||||
**هدف**: تکمیل BackOffice UI و رفع Anti-Patterns معماری
|
||||
|
||||
---
|
||||
|
||||
## 🔧 تغییرات اخیر (۲۸ آذر) - Session 2
|
||||
|
||||
### ✅ سیستم مدیریت موجودی محصولات
|
||||
**CMS Handler**: چک موجودی در `SubmitShopBuyOrderCommandHandler`
|
||||
- چک موجودی قبل از تأیید سفارش
|
||||
- کاهش `RemainingCount` و افزایش `SaleCount` بعد از پرداخت
|
||||
- پیام خطای فارسی با جزئیات محصول و تعداد
|
||||
|
||||
**FrontOffice ProductDetail**:
|
||||
- `MaxQty` داینامیک بر اساس موجودی واقعی
|
||||
- نمایش Chip موجودی (سبز/قرمز) با تعداد
|
||||
- غیرفعال کردن دکمه افزودن وقتی ناموجود
|
||||
|
||||
### ✅ ویژگیهای باشگاه (ClubFeatures) - اصلاح معماری
|
||||
**حذف فیلدها از UserClubFeature**:
|
||||
- `DetailedDescriptionHtml`, `Icon`, `Color` فقط در `ClubFeature` (جدول قالب)
|
||||
- `UserClubFeature` فقط: `IsActive`, `GrantedAt`, `Notes`
|
||||
|
||||
**فایلهای اصلاحشده**:
|
||||
- CMS: `UserClubFeatureDto`, `clubmembership.proto`, `ClubFeatureProfile`
|
||||
- BFF: `GetClubFeaturesQueryHandler`, `GetClubFeaturesResponseDto`, `configuration.proto`, `ConfigurationProfile`
|
||||
- FrontOffice: `ClubConfigurationService`, `FeaturesPage`
|
||||
|
||||
**MembershipPage - مزایای عضویت**:
|
||||
1. شارژ ۵۶ میلیون تومان کیف پول فروشگاه تخفیفی
|
||||
2. عضویت در شبکه بازاریابی و دریافت پورسانت
|
||||
3. امکان جذب زیرمجموعه
|
||||
|
||||
### ✅ رفع باگ مدال آدرسها
|
||||
- **Snackbar تکراری**: حذف inject از code-behind (global در `_Imports.razor`)
|
||||
- **NullReferenceException**: null check برای `dialog.Result`
|
||||
|
||||
### ✅ VAT و Cart Services
|
||||
- **VATService**: نرخ پیشفرض 9.99% برای debug
|
||||
- **CartService**: `EnsureInitializedAsync` + `IsAuthenticatedAsync` برای لود فقط برای کاربران لاگینشده
|
||||
|
||||
---
|
||||
|
||||
## 🔧 تغییرات قبلی (۲۸ آذر) - Session 1
|
||||
|
||||
### ✅ نمودار درختی شبکه در FrontOffice با d3-org-chart
|
||||
**کتابخانهها**: d3-org-chart v3 + d3.js v7 + d3-flextree v2.1.2
|
||||
**ویژگیها**:
|
||||
- نمایش درختی باینری شبکه
|
||||
- کلیک روی نود → نمایش درخت زیرمجموعه
|
||||
- دکمه بازگشت به نود قبلی
|
||||
- دکمه "درخت من" برای بازگشت به درخت کاربر
|
||||
- انتخاب عمق درخت با MudSelect (2-10 سطح)
|
||||
- FitToScreen برای تناسب با صفحه
|
||||
- Responsive با MudBlazor components
|
||||
|
||||
### ✅ API جدید GetSubordinateTree
|
||||
**Proto**: `GetSubordinateTreeRequest` با `target_user_id` و `max_depth`
|
||||
**BFF Handler**: `GetSubordinateTreeQueryHandler.cs`
|
||||
**Frontend Service**: `GetSubordinateTreeAsync(targetUserId, maxDepth)`
|
||||
**امنیت**: JWT Authentication (بدون check سنگین subordinate)
|
||||
|
||||
### ✅ رفع مشکل Encoding فارسی در Geography
|
||||
**Entity های تغییر یافته**: Country, State, City
|
||||
**تغییرات Configuration**: `NVARCHAR` با `Persian_100_CI_AI` collation
|
||||
**Migration**: `FixPersianCollation_Geography`
|
||||
|
||||
---
|
||||
|
||||
## 🔧 تغییرات قبلی (۱۷ آذر)
|
||||
|
||||
### ✅ رفع Anti-Pattern معماری در BackOffice.BFF
|
||||
**مشکل**: BackOffice.BFF.WebApi از پکیجهای Protobuf مربوط به CMS استفاده میکرد
|
||||
**راهحل**:
|
||||
- ساخت Protobuf های اختصاصی BackOffice.BFF (ClubMembership, Commission, Configuration, NetworkMembership)
|
||||
- تغییر namespace از `CMSMicroservice` به `Foursat.BackOffice.BFF.*`
|
||||
- تغییر GrpcServices از "Client" به "Both" (برای پشتیبانی هم از Server و هم Client)
|
||||
- نسخههای منتشر شده: 0.0.6 (ClubMembership, Commission, NetworkMembership), 1.0.6 (Configuration)
|
||||
|
||||
### ✅ اضافه شدن HTTP Annotations به Protobuf
|
||||
- افزودن `google/api/annotations.proto` به 4 پروژه Protobuf
|
||||
- پیادهسازی HTTP endpoints برای Swagger: 33 endpoint
|
||||
- ClubMembership: 7 endpoints
|
||||
- Commission: 14 endpoints
|
||||
- Configuration: 5 endpoints
|
||||
- NetworkMembership: 7 endpoints
|
||||
- نصب `Google.Api.CommonProtos v2.10.0`
|
||||
|
||||
### ✅ رفع مشکل Mapster با Immutable Types
|
||||
- ساخت `NetworkMembershipProfile.cs` با استفاده از `MapWith()`
|
||||
- مپینگ دستی برای `RepeatedField` و `Timestamp`
|
||||
- رفع خطای "Cannot convert immutable type"
|
||||
|
||||
### ✅ پشتیبانی از Multi-Role Authorization
|
||||
- تغییر `AuthorizationService` برای خواندن چندین رول از JWT
|
||||
- اضافه شدن متد `GetUserRolesAsync()`
|
||||
- استفاده از `user.FindAll(ClaimTypes.Role)` بجای `FindFirst`
|
||||
- پشتیبانی از رولهای آرایهای در `ApiAuthenticationStateProvider`
|
||||
|
||||
### ✅ نمایش درختی شبکه (Network Tree Visualization)
|
||||
- پیادهسازی درخت تعاملی با D3.js v7
|
||||
- ویژگیهای درخت:
|
||||
- Zoom & Pan با mouse/touch
|
||||
- دکمه Reset برای بازگشت به حالت اولیه
|
||||
- رنگبندی: سبز (فعال), قرمز (غیرفعال), سبز (چپ), نارنجی (راست)
|
||||
- کلیک روی node برای بارگذاری درخت آن کاربر
|
||||
- Responsive با viewBox و preserveAspectRatio
|
||||
- اضافه شدن `UserAutoComplete` برای جستجوی کاربر
|
||||
- جستجوی همزمان در Mobile, FirstName, LastName, NationalCode
|
||||
- نمایش نام + موبایل در لیست
|
||||
|
||||
### ✅ رفع مشکلات UI
|
||||
- رفع NullReferenceException در `NetworkTreeViewer` (JoinedAt null check)
|
||||
- رفع timing issue در render درخت (StateHasChanged + Task.Delay)
|
||||
- رفع خطای JSInterop با استفاده از `setDotNetReference`
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ یادآوری مهم: Proto Package Workflow
|
||||
|
||||
**قبل از هر کاری این را بخوانید!**
|
||||
|
||||
### قانون اجباری برای تغییر Proto (ALL Services):
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ تغییر Proto File │
|
||||
│ ↓ │
|
||||
│ افزایش Version در csproj │
|
||||
│ ↓ │
|
||||
│ dotnet pack -c Release │
|
||||
│ ↓ │
|
||||
│ Update Version در لایه بالاتر │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**این برای همه سرویسها اجباری است:**
|
||||
- ✅ CMS Proto changes → Update BFF
|
||||
- ✅ BackOffice.BFF Proto changes → Update BackOffice UI
|
||||
- ✅ FrontOffice.BFF Proto changes → Update FrontOffice UI
|
||||
|
||||
**عدم رعایت = ساعتها Debug و سردرگمی بیهوده!**
|
||||
|
||||
GitLab Registry: `https://git.afrino.co/api/packages/FourSat/nuget/index.json`
|
||||
|
||||
---
|
||||
|
||||
## 📋 وضعیت کلی پروژه
|
||||
|
||||
### Backend:
|
||||
- ✅ **CMS Microservice**: ~98% Complete
|
||||
- ✅ **Daya Loan Integration**: 100% Complete (Real API implemented - Dec 6, 2025)
|
||||
- ✅ **BackOffice.BFF**: 100% Complete (35+ Handlers)
|
||||
- ✅ **Architecture Fixed**: Anti-pattern با CMS Protobuf رفع شد
|
||||
- ✅ **HTTP Annotations**: 33 endpoint با Swagger support
|
||||
- ✅ **Mapster Profiles**: NetworkMembership, Products با MapWith()
|
||||
- ✅ **FrontOffice.BFF**: 98% Complete (همه سرویسهای مورد نیاز مشتری پیادهسازی شده)
|
||||
|
||||
### Frontend:
|
||||
- ✅ **BackOffice UI**: ~97% Complete (65+ صفحه)
|
||||
- ✅ **Multi-Role Authorization**: پشتیبانی از چندین نقش همزمان
|
||||
- ✅ **Network Tree Visualization**: نمایش درختی تعاملی با D3.js
|
||||
- ✅ **User AutoComplete**: جستجوی پیشرفته کاربران
|
||||
- ✅ **FrontOffice UI**: **98% Complete** (تمام صفحات مورد نیاز مشتری پیادهسازی شده)
|
||||
|
||||
---
|
||||
|
||||
## 🎉 جمعبندی نهایی FrontOffice (سمت مشتری)
|
||||
|
||||
### ✅ صفحات پیادهسازی شده و متصل به API:
|
||||
|
||||
#### 🔐 احراز هویت:
|
||||
| صفحه | Route | وضعیت |
|
||||
|------|-------|-------|
|
||||
| ثبتنام (OTP) | `/register` | ✅ متصل به gRPC |
|
||||
| ورود (OTP) | Dialog | ✅ متصل به gRPC |
|
||||
| تایید قرارداد | `/register` Step 3 | ✅ متصل به gRPC |
|
||||
|
||||
#### 👤 پروفایل:
|
||||
| صفحه | Route | وضعیت |
|
||||
|------|-------|-------|
|
||||
| داشبورد پروفایل | `/profile` | ✅ متصل به gRPC |
|
||||
| ویرایش اطلاعات شخصی | `/profile/personal` | ✅ متصل به gRPC |
|
||||
| مدیریت آدرسها | `/profile/addresses` | ✅ متصل به gRPC |
|
||||
| تنظیمات | `/profile/settings` | ✅ متصل به gRPC |
|
||||
| کیف پول | `/profile/wallet` | ✅ متصل به gRPC |
|
||||
| درخت شبکه | `/profile/tree` | ✅ متصل به gRPC |
|
||||
|
||||
#### 🛒 فروشگاه:
|
||||
| صفحه | Route | وضعیت |
|
||||
|------|-------|-------|
|
||||
| لیست محصولات | `/products` | ✅ متصل به gRPC |
|
||||
| جزئیات محصول | `/products/{id}` | ✅ متصل به gRPC |
|
||||
| دستهبندیها | `/categories` | ✅ متصل به gRPC |
|
||||
| سبد خرید | `/cart` | ✅ متصل به gRPC |
|
||||
| تایید خرید (VAT) | `/checkout` | ✅ متصل به gRPC |
|
||||
|
||||
#### 📦 سفارشات:
|
||||
| صفحه | Route | وضعیت |
|
||||
|------|-------|-------|
|
||||
| لیست سفارشات | `/orders` | ✅ متصل به gRPC |
|
||||
| جزئیات سفارش (VAT) | `/orders/{id}` | ✅ متصل به gRPC |
|
||||
| پیگیری سفارش | `/order-tracking/{id}` | ✅ متصل به gRPC |
|
||||
|
||||
#### 💰 کمیسیون:
|
||||
| صفحه | Route | وضعیت |
|
||||
|------|-------|-------|
|
||||
| داشبورد کمیسیون | `/commission` | ✅ متصل به gRPC |
|
||||
| تاریخچه پرداختها | `/commission/history` | ✅ متصل به gRPC |
|
||||
| تعادل هفتگی | `/commission/weekly-balance` | ✅ متصل به gRPC |
|
||||
|
||||
#### 🌐 شبکه:
|
||||
| صفحه | Route | وضعیت |
|
||||
|------|-------|-------|
|
||||
| آمار شبکه | `/network/statistics` | ✅ متصل به gRPC |
|
||||
| درخت شبکه | `/profile/tree` | ✅ متصل به gRPC |
|
||||
|
||||
#### 🏆 باشگاه:
|
||||
| صفحه | Route | وضعیت |
|
||||
|------|-------|-------|
|
||||
| عضویت باشگاه | `/club/membership` | ✅ متصل به gRPC |
|
||||
| امکانات باشگاه | `/club/features` | ✅ Static |
|
||||
|
||||
#### 📦 پکیجها:
|
||||
| صفحه | Route | وضعیت |
|
||||
|------|-------|-------|
|
||||
| لیست پکیجها | `/packages` | ✅ متصل به gRPC |
|
||||
| پکیجهای من | `/my-packages` | ✅ متصل به gRPC |
|
||||
| جزئیات پکیج | `/packages/{id}` | ✅ متصل به gRPC |
|
||||
|
||||
#### 📄 سایر صفحات:
|
||||
| صفحه | Route | وضعیت |
|
||||
|------|-------|-------|
|
||||
| صفحه اصلی | `/` | ✅ Complete |
|
||||
| درباره ما | `/about` | ✅ Static |
|
||||
| سوالات متداول | `/faq` | ✅ Static |
|
||||
| تماس با ما | `/contact` | ⚠️ UI آماده، Mock |
|
||||
|
||||
---
|
||||
|
||||
### ⚠️ موارد Mock (نیاز به CMS):
|
||||
|
||||
| قابلیت | وضعیت UI | نیاز CMS |
|
||||
|--------|----------|----------|
|
||||
| **فرم تماس با ما** | ✅ UI کامل | Entity `ContactMessage` |
|
||||
| **نظرات محصول** | ❌ | Entity `Review` |
|
||||
| **کد تخفیف** | ❌ | RPC `ValidateDiscountCode` |
|
||||
|
||||
---
|
||||
|
||||
### ❌ موارد حذف شده (نیاز نیست):
|
||||
|
||||
| قابلیت | دلیل |
|
||||
|--------|------|
|
||||
| `ChangePassword` | سیستم فقط OTP دارد، رمز عبور نداریم |
|
||||
| `ForgotPassword` | سیستم فقط OTP دارد |
|
||||
|
||||
> **نکته**: صفحه `ChangePassword.razor` ساخته شده ولی فعلاً کاربردی ندارد چون لاگین فقط با OTP است.
|
||||
|
||||
---
|
||||
|
||||
## 📊 مقایسه CMS vs FrontOffice.BFF
|
||||
|
||||
### سرویسهای CMS که در FrontOffice.BFF پیادهسازی شده:
|
||||
|
||||
| CMS Service | FrontOffice.BFF | وضعیت |
|
||||
|-------------|-----------------|-------|
|
||||
| UserService | ✅ UserService | کامل |
|
||||
| OtpTokenService | ✅ (در UserService) | کامل |
|
||||
| UserAddressService | ✅ UserAddressService | کامل |
|
||||
| ProductsService | ✅ ProductsService | کامل |
|
||||
| CategoryService | ✅ CategoriesService | کامل |
|
||||
| UserCartsService | ✅ ShopingCartService | کامل |
|
||||
| UserOrderService | ✅ UserOrderService | کامل |
|
||||
| UserWalletService | ✅ UserWalletService | کامل |
|
||||
| TransactionsService | ✅ TransactionService | کامل |
|
||||
| CommissionService | ✅ CommissionService | کامل |
|
||||
| ClubMembershipService | ✅ ClubMembershipService | کامل |
|
||||
| NetworkMembershipService | ✅ NetworkMembershipService | کامل |
|
||||
| PackageService | ✅ PackageService | کامل |
|
||||
| DiscountShopServices | ✅ DiscountShopService | کامل |
|
||||
| UserContractService | ✅ (در UserService - AcceptContract) | کامل |
|
||||
|
||||
### سرویسهای CMS که فقط برای Admin هستند (نیاز مشتری نیست):
|
||||
|
||||
| CMS Service | توضیح |
|
||||
|-------------|-------|
|
||||
| ConfigurationService | تنظیمات سیستم (Admin) |
|
||||
| ContractService | مدیریت قراردادها (Admin) |
|
||||
| ManualPaymentService | پرداخت دستی (Admin) |
|
||||
| RoleService | مدیریت نقشها (Admin) |
|
||||
| UserRoleService | اختصاص نقش (Admin) |
|
||||
| TagService | مدیریت تگها (Admin) |
|
||||
| ProductTagService | اختصاص تگ به محصول (Admin) |
|
||||
| PublicMessageService | پیامهای عمومی (Admin) |
|
||||
| ProductImagesService | مدیریت تصاویر (Admin) |
|
||||
| ProductGalleriesService | گالری محصول (Admin) |
|
||||
| ProductCategoryService | دستهبندی محصول (Admin) |
|
||||
| FactorDetailsService | جزئیات فاکتور (Admin) |
|
||||
| UserWalletChangeLogService | لاگ تغییرات کیف پول (Admin) |
|
||||
|
||||
---
|
||||
|
||||
### 2. ✅ Package Purchase System - UI Implementation
|
||||
**Status**: ✅ تکمیل شد
|
||||
**Owner**: FrontOffice Team
|
||||
**تاریخ تکمیل**: ۱۵ آذر ۱۴۰۴
|
||||
|
||||
#### CMS Status:
|
||||
- ✅ Entities (5) - `PackagePurchase`, `PackagePurchaseItem`, etc.
|
||||
- ✅ Commands (6) - `CreatePackagePurchaseCommand`, etc.
|
||||
- ✅ Queries (3) - `GetPackagePurchaseByIdQuery`, etc.
|
||||
- ✅ Protobuf (4 RPCs) - 264 lines
|
||||
|
||||
#### تغییرات انجام شده:
|
||||
- ✅ **PackageService.cs**: سرویس gRPC برای دریافت پکیجها
|
||||
- ✅ **RouteConstants.cs**: اضافه شدن مسیرهای `/packages` و `/my-packages`
|
||||
- ✅ **ConfigureServices.cs**: ثبت `PackageService` در DI
|
||||
- ✅ **Packages.razor**: صفحه لیست پکیجها با Grid View، جستجو، و Loading States
|
||||
- ✅ **MyPackages.razor**: صفحه پکیجهای کاربر با نمایش وضعیت خرید
|
||||
|
||||
**Build Status**: ✅ FrontOffice Build Succeeded - 0 Errors
|
||||
|
||||
**Reference**: `01-BUSINESS/package-purchase-system.md`
|
||||
|
||||
---
|
||||
|
||||
### 3. ✅ اصلاح محاسبه کمیسیون هفتگی (بحرانی)
|
||||
**Status**: ✅ تکمیل شد
|
||||
**Owner**: CMS Team
|
||||
**تاریخ شروع**: ۱۴ آذر ۱۴۰۴
|
||||
**تاریخ تکمیل**: ۱۴ آذر ۱۴۰۴
|
||||
|
||||
#### شرح مشکلات رفع شده:
|
||||
|
||||
| # | مشکل | وضعیت |
|
||||
|---|------|-------|
|
||||
| 1 | محدودیت لول (15) پیادهسازی نشده | ✅ Fixed |
|
||||
| 2 | فقط تعادل شخصی حساب میشود (نه زیرمجموعه) | ✅ Fixed |
|
||||
|
||||
#### فرمول پیادهسازی شده:
|
||||
```
|
||||
کمیسیون = (تعادل_شخص + SUM(تعادل_زیرمجموعه تا 15 لول)) × ارزش_هر_تعادل
|
||||
```
|
||||
|
||||
#### تسکهای تکمیل شده:
|
||||
|
||||
| فاز | شرح | وضعیت |
|
||||
|-----|------|-------|
|
||||
| 1 | اضافه کردن `Commission.MaxNetworkLevel` به Config | ✅ |
|
||||
| 2 | اصلاح `CalculateWeeklyBalancesCommandHandler` - محدودیت لول | ✅ |
|
||||
| 3 | اصلاح `ProcessUserPayoutsCommandHandler` - تعادل زیرمجموعه | ✅ |
|
||||
| 4 | تست و Build | ✅ (0 Errors) |
|
||||
|
||||
#### تغییرات انجام شده:
|
||||
- **Config**: اضافه کردن `Commission.MaxNetworkLevel = 15`
|
||||
- **CalculateWeeklyBalances**: پارامتر `maxLevel` به متدهای بازگشتی اضافه شد
|
||||
- **ProcessUserPayouts**: متد `SumSubordinateBalancesAsync` برای جمع تعادل زیرمجموعهها تا 15 لول
|
||||
|
||||
**Reference**: `01-BUSINESS/commission-calculation-fix.md`
|
||||
|
||||
---
|
||||
|
||||
### 4. ✅ اصلاح سقف تعادل هفتگی (MaxWeeklyBalances)
|
||||
**Status**: ✅ تکمیل شد
|
||||
**Owner**: CMS Team
|
||||
**تاریخ تکمیل**: ۱۴ آذر ۱۴۰۴
|
||||
|
||||
#### شرح مشکل:
|
||||
سقف تعادل هفتگی در پیادهسازی فعلی **300 کل** بود، اما باید **300 برای هر دست** باشد.
|
||||
|
||||
| توضیح | منطق قدیم | منطق جدید |
|
||||
|-------|-----------|-----------|
|
||||
| سقف | 300 کل | 300 هر دست |
|
||||
| Max Total | 300 | 300+300=600 |
|
||||
|
||||
#### تغییرات انجام شده:
|
||||
|
||||
**CMS Changes:**
|
||||
- ✅ **SystemConfiguration**: تغییر کلید از `MaxWeeklyBalancesPerUser` به `MaxWeeklyBalancesPerLeg`
|
||||
- ✅ **CalculateWeeklyBalancesCommandHandler**: اصلاح منطق محاسبه سقف
|
||||
- اعمال سقف روی هر دست جداگانه قبل از محاسبه MIN
|
||||
- باقیمانده = مازاد سقف هر دست (نه نصف تعادل کل)
|
||||
- ✅ **ApplicationDbContextInitialiser**: اصلاح Seed Data
|
||||
|
||||
**منطق جدید:**
|
||||
```csharp
|
||||
// ✅ سقف روی هر دست جداگانه
|
||||
var cappedLeftTotal = Math.Min(leftTotal, maxBalancesPerLeg);
|
||||
var cappedRightTotal = Math.Min(rightTotal, maxBalancesPerLeg);
|
||||
var totalBalances = Math.Min(cappedLeftTotal, cappedRightTotal);
|
||||
var leftRemainder = leftTotal - cappedLeftTotal; // مازاد سقف
|
||||
var rightRemainder = rightTotal - cappedRightTotal;
|
||||
```
|
||||
|
||||
**Build Status**: ✅ CMS Build Succeeded - 0 Errors
|
||||
|
||||
**مستندات:**
|
||||
- ✅ `01-BUSINESS/balance-calculation-rules.md` - آپدیت شد
|
||||
|
||||
---
|
||||
|
||||
## 🟢 Low Priority (هفته بعد)
|
||||
|
||||
### 5. ✅ VAT System Implementation
|
||||
**Status**: ✅ تکمیل شد
|
||||
**Owner**: CMS + BFF + FrontOffice UI
|
||||
**تاریخ تکمیل**: ۱۵ آذر ۱۴۰۴
|
||||
|
||||
#### تغییرات انجام شده:
|
||||
|
||||
**CMS:**
|
||||
- ✅ **OrderVAT Entity**: قبلاً موجود بود
|
||||
- ✅ **GetUserOrderResponseDto**: اضافه شدن `VatInfo` با فیلدهای `VatRate`, `BaseAmount`, `VatAmount`, `TotalAmount`, `IsPaid`
|
||||
- ✅ **GetUserOrderQueryHandler**: اضافه شدن `.Include(i => i.OrderVAT)` و mapping VAT
|
||||
- ✅ **CMS Proto**: اضافه شدن `OrderVATInfo` message
|
||||
|
||||
**FrontOffice.BFF:**
|
||||
- ✅ **Proto**: اضافه شدن `OrderVATInfo` و `vat_info` field
|
||||
- ✅ **GetUserOrderResponseDto**: اضافه شدن `OrderVATInfoDto`
|
||||
|
||||
**FrontOffice UI:**
|
||||
- ✅ **CheckoutSummary.razor**: نمایش جزئیات مالی شامل:
|
||||
- جمع کالاها
|
||||
- مالیات بر ارزش افزوده (۹%)
|
||||
- مبلغ قابل پرداخت
|
||||
- ✅ **OrderDetail.razor**: نمایش جزئیات مالی مشابه
|
||||
|
||||
**Build Status**: ✅ All Projects - 0 Errors
|
||||
|
||||
---
|
||||
|
||||
### 6. Manual Payment System
|
||||
**Status**: 🟡 In Progress (CMS + BackOffice.BFF)
|
||||
**Owner**: CMS + BackOffice.BFF
|
||||
**Estimate**: 2 روز (UI باقیمانده)
|
||||
|
||||
#### وضعیت فعلی:
|
||||
- ✅ CMS Domain & Application: ManualPayment + CreateManualPayment/ApproveManualPayment/RejectManualPayment + GetAllManualPayments
|
||||
- ✅ CMS gRPC: ManualPaymentContract (Create/Approve/Reject/GetAllManualPayments)
|
||||
- ✅ BackOffice.BFF: 4 Handler (CreateManualPayment, ApproveManualPayment, RejectManualPayment, GetManualPayments)
|
||||
- ⏳ BackOffice UI: صفحه لیست Manual Payments + Dialog جزئیات/Approve/Reject
|
||||
- ⏳ FrontOffice Flow (CreateManualPaymentRequest از سمت کاربر)
|
||||
|
||||
---
|
||||
|
||||
### 7. RBAC System Implementation
|
||||
**Status**: 🟡 In Progress (BackOffice.BFF Permission Layer پیادهسازی شده؛ CMS + BackOffice UI باقی مانده)
|
||||
**Owner**: CMS + BFF Teams
|
||||
**Estimate**: 1.5 هفته
|
||||
|
||||
#### Requirements:
|
||||
- تعریف Roles و Permissions (CMS Domain/Application)
|
||||
- Policy-based Authorization (CMS + BackOffice UI)
|
||||
- Admin Panel برای مدیریت دسترسیها
|
||||
- ✅ BackOffice.BFF: IPermissionService + CheckUserPermissionHandler / GetUserRolesHandler + gRPC PermissionInterceptor
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Blockers & Dependencies
|
||||
|
||||
### 🟢 Resolved:
|
||||
1. ~~**Protobuf Mismatch** (FrontOffice.BFF ↔ CMS)~~ ✅ Fixed
|
||||
2. ~~**WalletService Mock Data**~~ ✅ Connected to gRPC
|
||||
3. ~~**Tree Builder Missing** (NetworkMembership)~~ ✅ Implemented
|
||||
|
||||
### 🟡 Minor Issues:
|
||||
1. **MudBlazor Warnings** - ~100 warnings (غیر critical)
|
||||
2. **Missing CMS Entities** - Review, ContactMessage, DiscountValidation
|
||||
|
||||
---
|
||||
|
||||
## 📊 Progress Summary
|
||||
|
||||
### ✅ وضعیت نهایی FrontOffice (سمت مشتری):
|
||||
|
||||
**FrontOffice UI: 98% Complete** 🎉
|
||||
|
||||
- ✅ **28+ صفحه** پیادهسازی شده
|
||||
- ✅ **همه سرویسها** به gRPC متصل
|
||||
- ✅ **Build موفق** بدون Error
|
||||
- ⚠️ فقط **فرم تماس با ما** Mock است (نیاز به CMS entity)
|
||||
|
||||
### کارهای تمام شده این اسپرینت (۱۴-۱۵ آذر):
|
||||
|
||||
**روز اول (۱۴ آذر):**
|
||||
- ✅ FrontOffice Proto Projects: 5 پروژه جدید
|
||||
- ✅ FrontOffice UI Services: 4 سرویس به gRPC وصل شدند
|
||||
- ✅ FrontOffice.BFF Handlers: 15+ handler
|
||||
- ✅ Commission Calculation Fix
|
||||
- ✅ Balance Cap Fix: 300 per leg
|
||||
|
||||
**روز دوم (۱۵ آذر):**
|
||||
- ✅ Package Purchase UI: Packages.razor + MyPackages.razor
|
||||
- ✅ VAT System: CheckoutSummary + OrderDetail
|
||||
- ✅ OrderTracking: Timeline پیگیری سفارش
|
||||
- ✅ ChangePassword: UI آماده (برای آینده)
|
||||
- ✅ Documentation: جمعبندی نهایی
|
||||
|
||||
---
|
||||
|
||||
## 🗂️ Backlog (کارهای آینده)
|
||||
|
||||
### Low Priority - FrontOffice:
|
||||
|
||||
| تسک | توضیحات | اولویت |
|
||||
|-----|---------|--------|
|
||||
| **Password Authentication** | اضافه کردن لاگین با رمز عبور علاوه بر OTP | 🟡 Low |
|
||||
| **ForgotPassword** | بازیابی رمز عبور (نیاز به CMS RPC) | 🟡 Low |
|
||||
| **Contact Form Backend** | اتصال فرم تماس به CMS | 🟡 Low |
|
||||
| **Product Reviews** | سیستم نظرات محصول | 🟡 Low |
|
||||
| **Discount Code** | اعتبارسنجی کد تخفیف | 🟡 Low |
|
||||
|
||||
### High Priority - BackOffice (Admin):
|
||||
|
||||
| تسک | توضیحات | اولویت |
|
||||
|-----|---------|--------|
|
||||
| **Manual Payment UI** | صفحه مدیریت پرداختهای دستی | 🔴 High |
|
||||
| **RBAC System** | سیستم کنترل دسترسی | 🔴 High |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Definition of Done
|
||||
|
||||
### برای هر Task:
|
||||
- [x] Code Review Complete
|
||||
- [x] Build با 0 error
|
||||
- [x] Manual Testing انجام شده
|
||||
- [x] Documentation بروز شده
|
||||
|
||||
---
|
||||
|
||||
## 📝 نتیجهگیری نهایی
|
||||
|
||||
### سمت مشتری (FrontOffice):
|
||||
✅ **آماده Production** - تمام قابلیتهای اصلی پیادهسازی شده
|
||||
|
||||
### سمت ادمین (BackOffice):
|
||||
🟡 **95% Complete** - Manual Payment و RBAC باقیمانده
|
||||
|
||||
---
|
||||
|
||||
**آخرین بروزرسانی**: ۱۵ آذر ۱۴۰۴ 🚀
|
||||
@@ -0,0 +1,507 @@
|
||||
# 🛒 Discount Shop - Implementation Plan
|
||||
|
||||
**تاریخ ایجاد**: ۱۰ دی ۱۴۰۴ (30 December 2025)
|
||||
**وضعیت**: 🚧 در حال اجرا
|
||||
**اولویت**: 🔴 بالا
|
||||
|
||||
---
|
||||
|
||||
## 📊 وضعیت فعلی
|
||||
|
||||
### ✅ موارد کامل شده:
|
||||
|
||||
| بخش | فایلها | وضعیت |
|
||||
|-----|---------|-------|
|
||||
| **Domain Entities** | `DiscountProduct`, `DiscountCategory`, `DiscountOrder`, `DiscountOrderDetail`, `DiscountShoppingCart`, `DiscountProductCategory` | ✅ کامل |
|
||||
| **CMS Commands** | Create/Update/Delete برای Product, Category, Order, Cart | ✅ کامل |
|
||||
| **CMS Queries** | GetProducts, GetCategories, GetUserOrders, GetUserCart, GetOrderById | ✅ کامل |
|
||||
| **Proto Files** | `discountproduct.proto`, `discountcategory.proto`, `discountorder.proto`, `discountshoppingcart.proto` | ✅ کامل |
|
||||
| **BackOffice UI** | DiscountProductsMainPage, DiscountCategoriesMainPage, DiscountOrdersMainPage, SalesReports | ✅ کامل |
|
||||
| **BackOffice Services** | IDiscountProductService, IDiscountCategoryService, IDiscountOrderService | ✅ کامل |
|
||||
| **UI کامپوننت گالری** | ProductImageGallery.razor (فقط کلاینت، بدون Backend) | ⚠️ ناقص |
|
||||
|
||||
### ❌ موارد باقیمانده:
|
||||
|
||||
| # | مورد | توضیح | تخمین زمان |
|
||||
|---|------|-------|------------|
|
||||
| 1 | گالری تصاویر محصول | Entity + CRUD + Proto + Backend | 4 ساعت |
|
||||
| 2 | API لیست سفارشات ادمین | GetAllDiscountOrders با فیلترها | 2 ساعت |
|
||||
| 3 | محاسبه VAT | فعالسازی مالیات 10% در سفارشات | 1 ساعت |
|
||||
| 4 | گزارش فروش | API آماری برای SalesReports | 2 ساعت |
|
||||
| 5 | اتصال گالری به Backend | Upload + Service در BackOffice | 2 ساعت |
|
||||
| **جمع** | | | **11 ساعت** |
|
||||
|
||||
---
|
||||
|
||||
## 📋 مراحل پیادهسازی
|
||||
|
||||
---
|
||||
|
||||
## مرحله ۱: گالری تصاویر محصول (Backend)
|
||||
|
||||
### 1.1 ایجاد Entity
|
||||
|
||||
**فایل**: `CMS/src/CMSMicroservice.Domain/Entities/DiscountShop/DiscountProductImage.cs`
|
||||
|
||||
```csharp
|
||||
namespace CMSMicroservice.Domain.Entities.DiscountShop;
|
||||
|
||||
/// <summary>
|
||||
/// تصویر گالری محصول تخفیفی
|
||||
/// </summary>
|
||||
public class DiscountProductImage : BaseAuditableEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه محصول
|
||||
/// </summary>
|
||||
public long DiscountProductId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// محصول
|
||||
/// </summary>
|
||||
public virtual DiscountProduct DiscountProduct { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// عنوان تصویر
|
||||
/// </summary>
|
||||
public string? Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// متن جایگزین (Alt)
|
||||
/// </summary>
|
||||
public string? AltText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مسیر تصویر اصلی
|
||||
/// </summary>
|
||||
public string ImagePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مسیر تصویر کوچک
|
||||
/// </summary>
|
||||
public string? ThumbnailPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ترتیب نمایش
|
||||
/// </summary>
|
||||
public int SortOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// آیا تصویر اصلی محصول است؟
|
||||
/// </summary>
|
||||
public bool IsPrimary { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
### 1.2 ایجاد Configuration
|
||||
|
||||
**فایل**: `CMS/src/CMSMicroservice.Infrastructure/Persistence/Configurations/DiscountShop/DiscountProductImageConfiguration.cs`
|
||||
|
||||
```csharp
|
||||
using CMSMicroservice.Domain.Entities.DiscountShop;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace CMSMicroservice.Infrastructure.Persistence.Configurations.DiscountShop;
|
||||
|
||||
public class DiscountProductImageConfiguration : IEntityTypeConfiguration<DiscountProductImage>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<DiscountProductImage> builder)
|
||||
{
|
||||
builder.ToTable("DiscountProductImages");
|
||||
|
||||
builder.HasKey(x => x.Id);
|
||||
|
||||
builder.Property(x => x.Title)
|
||||
.HasMaxLength(200);
|
||||
|
||||
builder.Property(x => x.AltText)
|
||||
.HasMaxLength(500);
|
||||
|
||||
builder.Property(x => x.ImagePath)
|
||||
.IsRequired()
|
||||
.HasMaxLength(500);
|
||||
|
||||
builder.Property(x => x.ThumbnailPath)
|
||||
.HasMaxLength(500);
|
||||
|
||||
builder.HasOne(x => x.DiscountProduct)
|
||||
.WithMany(p => p.Images)
|
||||
.HasForeignKey(x => x.DiscountProductId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
builder.HasIndex(x => x.DiscountProductId);
|
||||
builder.HasIndex(x => new { x.DiscountProductId, x.SortOrder });
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 1.3 بهروزرسانی DiscountProduct Entity
|
||||
|
||||
**فایل**: `CMS/src/CMSMicroservice.Domain/Entities/DiscountShop/DiscountProduct.cs`
|
||||
|
||||
اضافه کردن Navigation Property:
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// تصاویر گالری محصول
|
||||
/// </summary>
|
||||
public virtual ICollection<DiscountProductImage> Images { get; set; }
|
||||
```
|
||||
|
||||
### 1.4 بهروزرسانی DbContext
|
||||
|
||||
**فایل**: `CMS/src/CMSMicroservice.Infrastructure/Persistence/ApplicationDbContext.cs`
|
||||
|
||||
```csharp
|
||||
public DbSet<DiscountProductImage> DiscountProductImages { get; set; }
|
||||
```
|
||||
|
||||
### 1.5 ایجاد Migration
|
||||
|
||||
```bash
|
||||
cd CMS/src/CMSMicroservice.Infrastructure
|
||||
dotnet ef migrations add AddDiscountProductImages -s ../CMSMicroservice.WebApi
|
||||
```
|
||||
|
||||
### 1.6 ایجاد Commands
|
||||
|
||||
**پوشه**: `CMS/src/CMSMicroservice.Application/DiscountShopCQ/Commands/`
|
||||
|
||||
| Command | فایلها |
|
||||
|---------|---------|
|
||||
| `AddDiscountProductImage` | Command.cs, Handler.cs, Validator.cs |
|
||||
| `UpdateDiscountProductImage` | Command.cs, Handler.cs, Validator.cs |
|
||||
| `DeleteDiscountProductImage` | Command.cs, Handler.cs |
|
||||
| `ReorderDiscountProductImages` | Command.cs, Handler.cs |
|
||||
|
||||
### 1.7 ایجاد Query
|
||||
|
||||
**پوشه**: `CMS/src/CMSMicroservice.Application/DiscountShopCQ/Queries/GetDiscountProductImages/`
|
||||
|
||||
| فایل | توضیح |
|
||||
|------|-------|
|
||||
| `GetDiscountProductImagesQuery.cs` | Request با ProductId |
|
||||
| `GetDiscountProductImagesQueryHandler.cs` | Handler |
|
||||
| `GetDiscountProductImagesResponseDto.cs` | Response با لیست تصاویر |
|
||||
|
||||
### 1.8 بهروزرسانی Proto
|
||||
|
||||
**فایل**: `CMS/src/CMSMicroservice.Protobuf/Protos/discountproduct.proto`
|
||||
|
||||
```protobuf
|
||||
// اضافه کردن به service DiscountProductContract:
|
||||
rpc AddDiscountProductImage(AddDiscountProductImageRequest) returns (AddDiscountProductImageResponse);
|
||||
rpc UpdateDiscountProductImage(UpdateDiscountProductImageRequest) returns (google.protobuf.Empty);
|
||||
rpc DeleteDiscountProductImage(DeleteDiscountProductImageRequest) returns (google.protobuf.Empty);
|
||||
rpc ReorderDiscountProductImages(ReorderDiscountProductImagesRequest) returns (google.protobuf.Empty);
|
||||
rpc GetDiscountProductImages(GetDiscountProductImagesRequest) returns (GetDiscountProductImagesResponse);
|
||||
|
||||
// Messages:
|
||||
message AddDiscountProductImageRequest {
|
||||
int64 product_id = 1;
|
||||
string title = 2;
|
||||
string alt_text = 3;
|
||||
string image_path = 4;
|
||||
string thumbnail_path = 5;
|
||||
int32 sort_order = 6;
|
||||
bool is_primary = 7;
|
||||
}
|
||||
|
||||
message AddDiscountProductImageResponse {
|
||||
int64 image_id = 1;
|
||||
}
|
||||
|
||||
message UpdateDiscountProductImageRequest {
|
||||
int64 image_id = 1;
|
||||
string title = 2;
|
||||
string alt_text = 3;
|
||||
string image_path = 4;
|
||||
string thumbnail_path = 5;
|
||||
int32 sort_order = 6;
|
||||
bool is_primary = 7;
|
||||
}
|
||||
|
||||
message DeleteDiscountProductImageRequest {
|
||||
int64 image_id = 1;
|
||||
}
|
||||
|
||||
message ReorderDiscountProductImagesRequest {
|
||||
int64 product_id = 1;
|
||||
repeated int64 image_ids = 2; // ترتیب جدید
|
||||
}
|
||||
|
||||
message GetDiscountProductImagesRequest {
|
||||
int64 product_id = 1;
|
||||
}
|
||||
|
||||
message GetDiscountProductImagesResponse {
|
||||
repeated DiscountProductImageDto images = 1;
|
||||
}
|
||||
|
||||
message DiscountProductImageDto {
|
||||
int64 id = 1;
|
||||
int64 product_id = 2;
|
||||
string title = 3;
|
||||
string alt_text = 4;
|
||||
string image_path = 5;
|
||||
string thumbnail_path = 6;
|
||||
int32 sort_order = 7;
|
||||
bool is_primary = 8;
|
||||
}
|
||||
```
|
||||
|
||||
### 1.9 ایجاد gRPC Service Methods
|
||||
|
||||
**فایل**: `CMS/src/CMSMicroservice.WebApi/Services/DiscountProductService.cs`
|
||||
|
||||
اضافه کردن 5 متد جدید برای Image CRUD.
|
||||
|
||||
---
|
||||
|
||||
## مرحله ۲: API لیست سفارشات ادمین
|
||||
|
||||
### 2.1 ایجاد Query
|
||||
|
||||
**پوشه**: `CMS/src/CMSMicroservice.Application/DiscountShopCQ/Queries/GetAllDiscountOrders/`
|
||||
|
||||
```csharp
|
||||
// GetAllDiscountOrdersQuery.cs
|
||||
public class GetAllDiscountOrdersQuery : IRequest<GetAllDiscountOrdersResponseDto>
|
||||
{
|
||||
public long? UserId { get; set; }
|
||||
public bool? PaymentCompleted { get; set; }
|
||||
public int? DeliveryStatus { get; set; }
|
||||
public DateTime? FromDate { get; set; }
|
||||
public DateTime? ToDate { get; set; }
|
||||
public string? SearchQuery { get; set; } // جستجو در شماره سفارش
|
||||
public int PageNumber { get; set; } = 1;
|
||||
public int PageSize { get; set; } = 20;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 بهروزرسانی Proto
|
||||
|
||||
**فایل**: `CMS/src/CMSMicroservice.Protobuf/Protos/discountorder.proto`
|
||||
|
||||
```protobuf
|
||||
// اضافه کردن به service:
|
||||
rpc GetAllDiscountOrders(GetAllDiscountOrdersRequest) returns (GetAllDiscountOrdersResponse);
|
||||
|
||||
message GetAllDiscountOrdersRequest {
|
||||
google.protobuf.Int64Value user_id = 1;
|
||||
google.protobuf.BoolValue payment_completed = 2;
|
||||
google.protobuf.Int32Value delivery_status = 3;
|
||||
google.protobuf.Timestamp from_date = 4;
|
||||
google.protobuf.Timestamp to_date = 5;
|
||||
google.protobuf.StringValue search_query = 6;
|
||||
int32 page_number = 7;
|
||||
int32 page_size = 8;
|
||||
}
|
||||
|
||||
message GetAllDiscountOrdersResponse {
|
||||
messages.MetaData meta_data = 1;
|
||||
repeated OrderSummaryDto models = 2;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 بهروزرسانی BackOffice Service
|
||||
|
||||
**فایل**: `BackOffice/src/BackOffice/Services/DiscountOrder/DiscountOrderService.cs`
|
||||
|
||||
تغییر `GetOrdersAsync` برای استفاده از API جدید (GetAllDiscountOrders به جای GetUserOrders با UserId=0).
|
||||
|
||||
---
|
||||
|
||||
## مرحله ۳: فعالسازی محاسبه VAT
|
||||
|
||||
### 3.1 بهروزرسانی PlaceOrderCommandHandler
|
||||
|
||||
**فایل**: `CMS/src/CMSMicroservice.Application/DiscountShopCQ/Commands/PlaceOrder/PlaceOrderCommandHandler.cs`
|
||||
|
||||
```csharp
|
||||
// محاسبه VAT (10%)
|
||||
const decimal VatRate = 0.10m;
|
||||
var vatAmount = (long)(totalAmount * VatRate);
|
||||
order.VatAmount = vatAmount;
|
||||
|
||||
// مبلغ نهایی شامل VAT
|
||||
var finalAmount = totalAmount + vatAmount;
|
||||
```
|
||||
|
||||
### 3.2 بهروزرسانی Proto Response
|
||||
|
||||
**فایل**: `CMS/src/CMSMicroservice.Protobuf/Protos/discountorder.proto`
|
||||
|
||||
اضافه کردن `int64 vat_amount` به `PlaceOrderResponse` و `GetOrderByIdResponse`.
|
||||
|
||||
### 3.3 بهروزرسانی UI
|
||||
|
||||
**فایل**: `BackOffice/src/BackOffice/Pages/DiscountShop/Components/OrderDetailsDialog.razor`
|
||||
|
||||
نمایش VAT در جزئیات سفارش.
|
||||
|
||||
---
|
||||
|
||||
## مرحله ۴: گزارش فروش (Statistics API)
|
||||
|
||||
### 4.1 ایجاد Query
|
||||
|
||||
**پوشه**: `CMS/src/CMSMicroservice.Application/DiscountShopCQ/Queries/GetDiscountShopStatistics/`
|
||||
|
||||
```csharp
|
||||
public class GetDiscountShopStatisticsResponseDto
|
||||
{
|
||||
// خلاصه کلی
|
||||
public long TotalSales { get; set; }
|
||||
public int TotalOrders { get; set; }
|
||||
public int TotalProducts { get; set; }
|
||||
public int TotalCustomers { get; set; }
|
||||
|
||||
// گزارش بازه زمانی
|
||||
public long PeriodSales { get; set; }
|
||||
public int PeriodOrders { get; set; }
|
||||
|
||||
// پرفروشترینها
|
||||
public List<TopProductDto> TopProducts { get; set; }
|
||||
|
||||
// فروش روزانه (برای نمودار)
|
||||
public List<DailySalesDto> DailySales { get; set; }
|
||||
}
|
||||
|
||||
public class TopProductDto
|
||||
{
|
||||
public long ProductId { get; set; }
|
||||
public string Title { get; set; }
|
||||
public int SalesCount { get; set; }
|
||||
public long TotalRevenue { get; set; }
|
||||
}
|
||||
|
||||
public class DailySalesDto
|
||||
{
|
||||
public DateTime Date { get; set; }
|
||||
public long Amount { get; set; }
|
||||
public int OrderCount { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 بهروزرسانی Proto
|
||||
|
||||
**فایل**: `CMS/src/CMSMicroservice.Protobuf/Protos/discountorder.proto`
|
||||
|
||||
```protobuf
|
||||
rpc GetDiscountShopStatistics(GetDiscountShopStatisticsRequest) returns (GetDiscountShopStatisticsResponse);
|
||||
|
||||
message GetDiscountShopStatisticsRequest {
|
||||
google.protobuf.Timestamp from_date = 1;
|
||||
google.protobuf.Timestamp to_date = 2;
|
||||
}
|
||||
|
||||
message GetDiscountShopStatisticsResponse {
|
||||
int64 total_sales = 1;
|
||||
int32 total_orders = 2;
|
||||
int32 total_products = 3;
|
||||
int32 total_customers = 4;
|
||||
int64 period_sales = 5;
|
||||
int32 period_orders = 6;
|
||||
repeated TopProductDto top_products = 7;
|
||||
repeated DailySalesDto daily_sales = 8;
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 تکمیل SalesReports.razor
|
||||
|
||||
**فایل**: `BackOffice/src/BackOffice/Pages/DiscountShop/SalesReports.razor`
|
||||
|
||||
اتصال به API جدید و نمایش:
|
||||
- کارتهای آماری (Total Sales, Orders, Products, Customers)
|
||||
- جدول پرفروشترین محصولات
|
||||
- نمودار فروش روزانه (MudChart)
|
||||
|
||||
---
|
||||
|
||||
## مرحله ۵: اتصال گالری به Backend
|
||||
|
||||
### 5.1 ایجاد Service در BackOffice
|
||||
|
||||
**فایل**: `BackOffice/src/BackOffice/Services/DiscountProduct/IDiscountProductService.cs`
|
||||
|
||||
اضافه کردن متدهای:
|
||||
```csharp
|
||||
Task<List<DiscountProductImageDto>> GetProductImagesAsync(long productId);
|
||||
Task<long> AddProductImageAsync(AddProductImageDto dto);
|
||||
Task UpdateProductImageAsync(UpdateProductImageDto dto);
|
||||
Task DeleteProductImageAsync(long imageId);
|
||||
Task ReorderProductImagesAsync(long productId, List<long> imageIds);
|
||||
```
|
||||
|
||||
### 5.2 بهروزرسانی ProductFormDialog
|
||||
|
||||
**فایل**: `BackOffice/src/BackOffice/Pages/DiscountShop/Components/ProductFormDialog.razor`
|
||||
|
||||
- در حالت Edit: بارگذاری تصاویر موجود از API
|
||||
- اتصال کامپوننت `ProductImageGallery` به متدهای Service
|
||||
- ذخیره تغییرات گالری همزمان با ذخیره محصول
|
||||
|
||||
### 5.3 آپلود فایل
|
||||
|
||||
بررسی سیستم آپلود موجود در پروژه:
|
||||
- اگر MinIO/S3 استفاده میشود: استفاده از همان سرویس
|
||||
- اگر فایلسیستم: ایجاد endpoint آپلود در CMS
|
||||
|
||||
---
|
||||
|
||||
## 📝 Checklist
|
||||
|
||||
### مرحله ۱: گالری تصاویر
|
||||
- [ ] ایجاد Entity `DiscountProductImage`
|
||||
- [ ] ایجاد Configuration
|
||||
- [ ] بهروزرسانی `DiscountProduct` Entity
|
||||
- [ ] بهروزرسانی DbContext
|
||||
- [ ] ایجاد و اجرای Migration
|
||||
- [ ] ایجاد Commands (Add, Update, Delete, Reorder)
|
||||
- [ ] ایجاد Query (GetImages)
|
||||
- [ ] بهروزرسانی Proto
|
||||
- [ ] پیادهسازی gRPC Service Methods
|
||||
- [ ] تست با Postman/gRPCurl
|
||||
|
||||
### مرحله ۲: API سفارشات ادمین
|
||||
- [ ] ایجاد Query `GetAllDiscountOrders`
|
||||
- [ ] بهروزرسانی Proto
|
||||
- [ ] پیادهسازی gRPC Service Method
|
||||
- [ ] بهروزرسانی BackOffice Service
|
||||
- [ ] تست UI DiscountOrdersMainPage
|
||||
|
||||
### مرحله ۳: محاسبه VAT
|
||||
- [ ] بهروزرسانی `PlaceOrderCommandHandler`
|
||||
- [ ] بهروزرسانی Proto (VatAmount در responses)
|
||||
- [ ] بهروزرسانی UI نمایش سفارش
|
||||
- [ ] تست محاسبه VAT
|
||||
|
||||
### مرحله ۴: گزارش فروش
|
||||
- [ ] ایجاد Query `GetDiscountShopStatistics`
|
||||
- [ ] بهروزرسانی Proto
|
||||
- [ ] پیادهسازی gRPC Service Method
|
||||
- [ ] ایجاد Service در BackOffice
|
||||
- [ ] تکمیل UI `SalesReports.razor`
|
||||
|
||||
### مرحله ۵: اتصال گالری
|
||||
- [ ] اضافه کردن متدهای Image به Service
|
||||
- [ ] بهروزرسانی ProductFormDialog
|
||||
- [ ] پیادهسازی/اتصال به سیستم آپلود
|
||||
- [ ] تست کامل گالری
|
||||
|
||||
---
|
||||
|
||||
## 🔗 فایلهای مرتبط
|
||||
|
||||
| فایل | توضیح |
|
||||
|------|-------|
|
||||
| `totalDoc/01-BUSINESS/discount-shop-business.md` | مستندات اصلی طراحی |
|
||||
| `totalDoc/03-BACKEND/BackOffice.BFF/discount-shop-integration.md` | پلن اولیه integration |
|
||||
| `CMS/src/CMSMicroservice.Domain/Entities/DiscountShop/` | Entity های موجود |
|
||||
| `CMS/src/CMSMicroservice.Application/DiscountShopCQ/` | Commands و Queries موجود |
|
||||
| `BackOffice/src/BackOffice/Pages/DiscountShop/` | صفحات UI موجود |
|
||||
|
||||
---
|
||||
|
||||
**آخرین بهروزرسانی**: ۱۰ دی ۱۴۰۴
|
||||
@@ -0,0 +1,617 @@
|
||||
# 📋 Task List - توضیحات جدید بیزینس 2025-12-08
|
||||
|
||||
**تاریخ ایجاد**: 2025-12-08
|
||||
**آخرین بهروزرسانی**: 2025-12-09
|
||||
**منبع**: تحلیل توضیحات شفاهی جدید بیزینس
|
||||
**وضعیت**: ✅ Task #0 Complete, بقیه آماده برای اجرا
|
||||
|
||||
---
|
||||
|
||||
## ✅ Completed Tasks
|
||||
|
||||
### ~~Task #0: اصلاح محاسبات تعادل و فلش~~ ✅
|
||||
|
||||
**شرح**:
|
||||
کد محاسبه تعادل با توضیحات دقیق بیزینس تطبیق داده شد.
|
||||
|
||||
**انجام شده**:
|
||||
- ✅ ترتیب محاسبات اصلاح شد (تعادل → باقیمانده → سقف → فلش)
|
||||
- ✅ فلش از هر دو طرف محاسبه میشود
|
||||
- ✅ باقیمانده جداگانه ذخیره میشود (چپ و راست)
|
||||
- ✅ Documentation بهروزرسانی شد
|
||||
- ✅ مثالهای 5 لول عمقی اضافه شد
|
||||
|
||||
**فایلهای تغییر یافته**:
|
||||
```
|
||||
CMS/src/.../CalculateWeeklyBalancesCommandHandler.cs (اصلاح شد)
|
||||
totalDoc/01-BUSINESS/balance-calculation-rules.md (بهروزرسانی شد)
|
||||
totalDoc/01-BUSINESS/balance-calculation-examples-5-levels.md (جدید)
|
||||
```
|
||||
|
||||
**تاریخ اتمام**: 2025-12-09
|
||||
|
||||
---
|
||||
|
||||
## 🔥 Priority 1: Critical Tasks
|
||||
|
||||
### Task #1: پیادهسازی Worker حذف خودکار کاربران غیرفعال
|
||||
|
||||
**شرح**:
|
||||
کاربرانی که تا 2 هفته بعد از ثبت نام هیچکدام از موارد زیر را انجام ندادند باید به صورت خودکار حذف شوند:
|
||||
- وام دایا نگرفتند
|
||||
- پرداخت مستقیم 56 میلیون نکردند
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- [ ] Worker روزانه یک بار اجرا شود (مثلاً ساعت 3 صبح)
|
||||
- [ ] کاربرانی با `CreatedAt < Now - 14 days` و `IsActive = false` و `ClubMembershipId = null` شناسایی شوند
|
||||
- [ ] کاربر به صورت Soft Delete حذف شود (یا Hard Delete بر اساس تصمیم)
|
||||
- [ ] جایگاه شبکه (Network Position) آزاد شود
|
||||
- [ ] معرف (Parent) بتواند دوباره کاربر جدید جذب کند
|
||||
- [ ] Log کامل عملیات حذف ثبت شود
|
||||
|
||||
**فایلهای نیاز به ایجاد/تغییر**:
|
||||
```
|
||||
CMS/src/CMSMicroservice.WebApi/BackgroundWorkers/
|
||||
└── DeleteInactiveUsersJob.cs (جدید)
|
||||
|
||||
CMS/src/CMSMicroservice.Application/UserCQ/Commands/
|
||||
└── DeleteInactiveUser/
|
||||
├── DeleteInactiveUserCommand.cs (جدید)
|
||||
└── DeleteInactiveUserCommandHandler.cs (جدید)
|
||||
|
||||
CMS/src/CMSMicroservice.WebApi/Program.cs
|
||||
└── services.AddHostedService<DeleteInactiveUsersJob>();
|
||||
```
|
||||
|
||||
**کد پیشنهادی**:
|
||||
```csharp
|
||||
public class DeleteInactiveUsersJob : BackgroundService
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILogger<DeleteInactiveUsersJob> _logger;
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
// محاسبه زمان اجرا (3 صبح)
|
||||
var now = DateTime.Now;
|
||||
var next3AM = now.Date.AddDays(1).AddHours(3);
|
||||
var delay = next3AM - now;
|
||||
|
||||
await Task.Delay(delay, stoppingToken);
|
||||
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var context = scope.ServiceProvider.GetRequiredService<IApplicationDbContext>();
|
||||
|
||||
var twoWeeksAgo = DateTime.Now.AddDays(-14);
|
||||
|
||||
var inactiveUsers = await context.Users
|
||||
.Where(u => u.Created < twoWeeksAgo
|
||||
&& u.ClubMembershipId == null
|
||||
&& !u.IsActive)
|
||||
.ToListAsync(stoppingToken);
|
||||
|
||||
_logger.LogInformation($"🧹 حذف {inactiveUsers.Count} کاربر غیرفعال بیش از 2 هفته");
|
||||
|
||||
foreach (var user in inactiveUsers)
|
||||
{
|
||||
// حذف کاربر
|
||||
user.IsDeleted = true; // Soft Delete
|
||||
user.DeletedAt = DateTime.Now;
|
||||
|
||||
// آزادسازی جایگاه شبکه
|
||||
// (NetworkParentId را null نکنید چون تاریخچه نیاز دارد)
|
||||
|
||||
_logger.LogWarning($"❌ حذف کاربر: {user.Id} - {user.UserName}");
|
||||
}
|
||||
|
||||
await context.SaveChangesAsync(stoppingToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**تست**:
|
||||
1. کاربر جدید با `CreatedAt = DateTime.Now.AddDays(-15)` ایجاد کنید
|
||||
2. `IsActive = false`, `ClubMembershipId = null`
|
||||
3. Worker را مجبور به اجرا کنید (یا زمان را تغییر دهید)
|
||||
4. چک کنید: `user.IsDeleted = true`
|
||||
|
||||
**تخمین زمان**: 4-6 ساعت
|
||||
|
||||
---
|
||||
|
||||
### Task #2: الزامی کردن دیالوگ باشگاه مشتریان
|
||||
|
||||
**شرح**:
|
||||
بعد از پرداخت موفق 56 میلیون تومان، کاربر **باید** قرارداد باشگاه مشتریان را امضا کند. تا زمانی که امضا نکند، نمیتواند به سایر بخشهای سیستم دسترسی داشته باشد و لینک معرفی خود را ببیند.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- [ ] بعد از تأیید پرداخت، Modal/Dialog باشگاه مشتریان باز شود
|
||||
- [ ] دکمه Close غیرفعال باشد (یا Modal با `disableBackdropClick` باز شود)
|
||||
- [ ] کاربر نتواند از دیالوگ خارج شود (ESC هم کار نکند)
|
||||
- [ ] بعد از امضای قرارداد:
|
||||
- `ClubMembership` record ایجاد شود
|
||||
- `User.ClubMembershipId` Set شود
|
||||
- 25 میلیون تومان به `WeeklyCommissionPool` اضافه شود
|
||||
- [ ] بعد از امضا، redirect به Dashboard
|
||||
- [ ] در Dashboard لینک معرفی نمایش داده شود
|
||||
|
||||
**فایلهای نیاز به تغییر**:
|
||||
```
|
||||
FrontOffice/src/FrontOffice.Main/Pages/
|
||||
└── Payment/PaymentSuccess.razor
|
||||
└── Payment/PaymentSuccess.razor.cs
|
||||
|
||||
FrontOffice/src/FrontOffice.Main/Components/
|
||||
└── ClubMembershipDialog.razor (جدید یا اصلاح)
|
||||
|
||||
CMS/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/
|
||||
└── CreateClubMembership/
|
||||
├── CreateClubMembershipCommand.cs
|
||||
└── CreateClubMembershipCommandHandler.cs
|
||||
```
|
||||
|
||||
**کد پیشنهادی (Frontend)**:
|
||||
```razor
|
||||
@* PaymentSuccess.razor *@
|
||||
@if (_showClubDialog)
|
||||
{
|
||||
<MudDialog @bind-IsVisible="_showClubDialog"
|
||||
Options="@(new DialogOptions {
|
||||
DisableBackdropClick = true,
|
||||
CloseButton = false
|
||||
})">
|
||||
<DialogContent>
|
||||
<h3>عضویت در باشگاه مشتریان</h3>
|
||||
<p>برای ادامه، لطفاً قرارداد باشگاه مشتریان را مطالعه و امضا کنید.</p>
|
||||
|
||||
<MudPaper Class="pa-4 my-4" Elevation="2">
|
||||
<p>متن قرارداد...</p>
|
||||
</MudPaper>
|
||||
|
||||
<MudCheckBox @bind-Checked="_agreedToTerms">
|
||||
متن قرارداد را مطالعه کردم و با آن موافقم
|
||||
</MudCheckBox>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
Disabled="!_agreedToTerms"
|
||||
OnClick="SignContract">
|
||||
امضای قرارداد
|
||||
</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
}
|
||||
```
|
||||
|
||||
```csharp
|
||||
// PaymentSuccess.razor.cs
|
||||
private bool _showClubDialog = false;
|
||||
private bool _agreedToTerms = false;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
// بعد از تأیید پرداخت
|
||||
if (PaymentConfirmed && !User.ClubMembershipId.HasValue)
|
||||
{
|
||||
_showClubDialog = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SignContract()
|
||||
{
|
||||
var request = new CreateClubMembershipRequest
|
||||
{
|
||||
UserId = User.Id,
|
||||
InitialContribution = 25000000
|
||||
};
|
||||
|
||||
await ClubMembershipContract.CreateClubMembershipAsync(request);
|
||||
|
||||
_showClubDialog = false;
|
||||
NavigationManager.NavigateTo("/dashboard");
|
||||
}
|
||||
```
|
||||
|
||||
**تست**:
|
||||
1. پرداخت 56M انجام دهید
|
||||
2. بعد از موفقیت، باید Dialog باز شود
|
||||
3. سعی کنید Close کنید → نشود
|
||||
4. بدون tick نزدن → دکمه غیرفعال باشد
|
||||
5. tick بزنید و امضا کنید → redirect به Dashboard
|
||||
6. لینک معرفی نمایش داده شود
|
||||
|
||||
**تخمین زمان**: 6-8 ساعت
|
||||
|
||||
---
|
||||
|
||||
### Task #3: شرط نمایش لینک معرفی
|
||||
|
||||
**شرح**:
|
||||
لینک معرفی فقط باید برای کاربرانی نمایش داده شود که:
|
||||
1. پرداخت کردهاند (`IsActive = true`)
|
||||
2. عضو باشگاه مشتریان شدهاند (`ClubMembershipId != null`)
|
||||
3. عضویت باشگاه فعال است (`ClubMembership.IsActive = true`)
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- [ ] در صفحه Dashboard یا Profile، شرط بالا چک شود
|
||||
- [ ] اگر شرایط برقرار نیست:
|
||||
- پیغام: "برای دریافت لینک معرفی، ابتدا عضو باشگاه مشتریان شوید"
|
||||
- دکمه "عضویت در باشگاه" (در صورت عدم عضویت)
|
||||
- [ ] اگر شرایط برقرار است:
|
||||
- لینک معرفی نمایش داده شود
|
||||
- دکمه کپی
|
||||
- QR Code (اختیاری)
|
||||
|
||||
**فایلهای نیاز به تغییر**:
|
||||
```
|
||||
FrontOffice/src/FrontOffice.Main/Pages/
|
||||
└── Dashboard/Dashboard.razor
|
||||
└── Dashboard/Dashboard.razor.cs
|
||||
|
||||
یا
|
||||
|
||||
FrontOffice/src/FrontOffice.Main/Pages/
|
||||
└── Profile/MyProfile.razor
|
||||
```
|
||||
|
||||
**کد پیشنهادی**:
|
||||
```razor
|
||||
@if (CanShowReferralLink)
|
||||
{
|
||||
<MudCard Class="my-4">
|
||||
<MudCardHeader>
|
||||
<CardHeaderContent>
|
||||
<MudText Typo="Typo.h6">🔗 لینک معرفی شما</MudText>
|
||||
</CardHeaderContent>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<MudTextField @bind-Value="_referralLink"
|
||||
ReadOnly="true"
|
||||
Adornment="Adornment.End"
|
||||
AdornmentIcon="@Icons.Material.Filled.ContentCopy"
|
||||
OnAdornmentClick="CopyLink"/>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudAlert Severity="Severity.Warning" Class="my-4">
|
||||
برای دریافت لینک معرفی، ابتدا عضو باشگاه مشتریان شوید.
|
||||
@if (!User.ClubMembershipId.HasValue)
|
||||
{
|
||||
<MudButton Color="Color.Primary"
|
||||
Variant="Variant.Filled"
|
||||
Class="mt-2"
|
||||
OnClick="OpenClubDialog">
|
||||
عضویت در باشگاه
|
||||
</MudButton>
|
||||
}
|
||||
</MudAlert>
|
||||
}
|
||||
```
|
||||
|
||||
```csharp
|
||||
private bool CanShowReferralLink =>
|
||||
User.IsActive
|
||||
&& User.ClubMembershipId.HasValue
|
||||
&& User.ClubMembership?.IsActive == true;
|
||||
```
|
||||
|
||||
**تست**:
|
||||
1. کاربر بدون `ClubMembership` → Alert نمایش داده شود
|
||||
2. کاربر با `ClubMembership` فعال → لینک نمایش داده شود
|
||||
3. دکمه کپی کار کند
|
||||
|
||||
**تخمین زمان**: 3-4 ساعت
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Priority 2: Medium Tasks
|
||||
|
||||
### Task #4: Validation دقیقتر محدودیت 2 فرزند فعال
|
||||
|
||||
**شرح**:
|
||||
در هنگام ثبت نام با کد معرف، باید بررسی شود که آیا Parent حداکثر **2 فرزند فعال** دارد یا نه (نه فقط 2 فرزند).
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- [ ] Validation در `CreateUserCommandHandler` یا `NetworkPlacementService`
|
||||
- [ ] شمارش فرزندان با شرط:
|
||||
```csharp
|
||||
u.NetworkParentId == parentId
|
||||
&& u.IsActive
|
||||
&& u.ClubMembershipId != null
|
||||
```
|
||||
- [ ] اگر `activeChildCount >= 2`:
|
||||
- Exception: "این کاربر تعداد زیرمجموعههاش پر شده و شما نمیتونید جزو زیرمجموعه این آدم بشید"
|
||||
- یا Auto-Placement (بر اساس تصمیم)
|
||||
|
||||
**فایلهای نیاز به تغییر**:
|
||||
```
|
||||
CMS/src/CMSMicroservice.Application/Services/
|
||||
└── NetworkPlacementService.cs
|
||||
|
||||
CMS/src/CMSMicroservice.Application/UserCQ/Commands/CreateUser/
|
||||
└── CreateUserCommandHandler.cs
|
||||
└── CreateUserCommandValidator.cs
|
||||
```
|
||||
|
||||
**کد پیشنهادی**:
|
||||
```csharp
|
||||
public async Task<NetworkLeg?> CalculateLegPositionAsync(long parentId, CancellationToken cancellationToken)
|
||||
{
|
||||
var activeChildrenCount = await _context.Users
|
||||
.CountAsync(u => u.NetworkParentId == parentId
|
||||
&& u.IsActive
|
||||
&& u.ClubMembershipId != null,
|
||||
cancellationToken);
|
||||
|
||||
if (activeChildrenCount >= 2)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"این کاربر تعداد زیرمجموعههاش پر شده و شما نمیتونید جزو زیرمجموعه این آدم بشید");
|
||||
}
|
||||
|
||||
// بررسی Left و Right
|
||||
var hasLeft = await _context.Users
|
||||
.AnyAsync(u => u.NetworkParentId == parentId
|
||||
&& u.LegPosition == NetworkLeg.Left
|
||||
&& u.IsActive
|
||||
&& u.ClubMembershipId != null,
|
||||
cancellationToken);
|
||||
|
||||
if (!hasLeft) return NetworkLeg.Left;
|
||||
|
||||
var hasRight = await _context.Users
|
||||
.AnyAsync(u => u.NetworkParentId == parentId
|
||||
&& u.LegPosition == NetworkLeg.Right
|
||||
&& u.IsActive
|
||||
&& u.ClubMembershipId != null,
|
||||
cancellationToken);
|
||||
|
||||
if (!hasRight) return NetworkLeg.Right;
|
||||
|
||||
return null; // هر دو پر است
|
||||
}
|
||||
```
|
||||
|
||||
**تست**:
|
||||
1. Parent با 2 فرزند فعال
|
||||
2. ثبت نام با کد این Parent
|
||||
3. باید Exception بیاید
|
||||
|
||||
**تخمین زمان**: 3-4 ساعت
|
||||
|
||||
---
|
||||
|
||||
### Task #5: بهبود پیغام خطای کد معرف پر
|
||||
|
||||
**شرح**:
|
||||
در صفحه ثبت نام، اگر کاربر کد معرفی وارد کند که ظرفیتش پر است، باید پیغام خطای واضح و فارسی نمایش داده شود.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
- [ ] در Frontend، بعد از وارد کردن کد معرف، validation شود
|
||||
- [ ] اگر کد پر بود، پیغام:
|
||||
> "این کد معرف ظرفیتش پر شده، لطفا از کد معرف دیگری استفاده کنید"
|
||||
- [ ] Snackbar یا Alert با Severity.Warning
|
||||
- [ ] فیلد کد معرف هایلایت شود (قرمز)
|
||||
|
||||
**فایلهای نیاز به تغییر**:
|
||||
```
|
||||
FrontOffice/src/FrontOffice.Main/Pages/
|
||||
└── Register.razor
|
||||
└── Register.razor.cs
|
||||
```
|
||||
|
||||
**کد پیشنهادی**:
|
||||
```csharp
|
||||
private async Task ValidateReferralCode()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_referralCode))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var request = new ValidateReferralCodeRequest
|
||||
{
|
||||
ReferralCode = _referralCode
|
||||
};
|
||||
|
||||
var response = await UserContract.ValidateReferralCodeAsync(request);
|
||||
|
||||
if (!response.IsValid)
|
||||
{
|
||||
_referralCodeError = "کد معرف نامعتبر است";
|
||||
}
|
||||
else if (response.IsFull)
|
||||
{
|
||||
_referralCodeError = "این کد معرف ظرفیتش پر شده، لطفا از کد معرف دیگری استفاده کنید";
|
||||
Snackbar.Add(_referralCodeError, Severity.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_referralCodeError = "خطا در بررسی کد معرف";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**تست**:
|
||||
1. Parent پر را پیدا کنید
|
||||
2. کد معرف او را در Register وارد کنید
|
||||
3. پیغام واضح نمایش داده شود
|
||||
|
||||
**تخمین زمان**: 2-3 ساعت
|
||||
|
||||
---
|
||||
|
||||
## 📝 Priority 3: Documentation Tasks
|
||||
|
||||
### Task #6: بهروزرسانی مستندات
|
||||
|
||||
**شرح**:
|
||||
با توجه به توضیحات جدید، داکیومنتهای زیر باید Update شوند.
|
||||
|
||||
**فایلهای نیاز به تغییر**:
|
||||
|
||||
#### 1. `totalDoc/01-BUSINESS/network-commission-system.md`
|
||||
```markdown
|
||||
# اضافه کردن بخش جدید:
|
||||
|
||||
## ۱۰. حذف خودکار کاربران غیرفعال
|
||||
|
||||
کاربرانی که تا 2 هفته بعد از ثبت نام:
|
||||
- وام دایا نگرفتهاند
|
||||
- پرداخت مستقیم 56 میلیون نکردهاند
|
||||
|
||||
به صورت خودکار حذف میشوند.
|
||||
|
||||
**Worker**: `DeleteInactiveUsersJob`
|
||||
**زمان اجرا**: روزانه ساعت 3 صبح
|
||||
**منطق**: `CreatedAt < Now - 14 days && !IsActive && ClubMembershipId == null`
|
||||
|
||||
---
|
||||
|
||||
## ۱۱. شرایط نمایش لینک معرفی
|
||||
|
||||
لینک معرفی فقط برای کاربرانی نمایش داده میشود که:
|
||||
1. پرداخت کردهاند (IsActive = true)
|
||||
2. عضو باشگاه مشتریان شدهاند (ClubMembershipId != null)
|
||||
3. عضویت باشگاه فعال است (ClubMembership.IsActive = true)
|
||||
|
||||
**تا زمانی که این شرایط برقرار نباشد، کاربر نمیتواند لینک معرفی خود را ببیند.**
|
||||
|
||||
---
|
||||
|
||||
## ۱۲. الزامی بودن دیالوگ باشگاه مشتریان
|
||||
|
||||
بعد از پرداخت موفق 56 میلیون تومان، کاربر **باید** قرارداد باشگاه مشتریان را امضا کند.
|
||||
|
||||
**فرآیند**:
|
||||
1. پرداخت موفق
|
||||
2. Dialog باشگاه مشتریان باز میشود
|
||||
3. کاربر نمیتواند Dialog را ببندد
|
||||
4. باید قرارداد را بخواند و امضا کند
|
||||
5. بعد از امضا → redirect به Dashboard
|
||||
6. لینک معرفی نمایش داده میشود
|
||||
```
|
||||
|
||||
#### 2. `totalDoc/01-BUSINESS/binary-tree-guide.md`
|
||||
```markdown
|
||||
# اصلاح بخش Validation:
|
||||
|
||||
### محدودیت 2 فرزند **فعال**
|
||||
|
||||
هر Parent فقط میتواند **2 فرزند فعال** داشته باشد.
|
||||
|
||||
**تعریف فعال**:
|
||||
- IsActive = true
|
||||
- ClubMembershipId != null
|
||||
- عضویت باشگاه فعال است
|
||||
|
||||
**نکته مهم**: کاربرانی که ثبت نام کردهاند اما هنوز فعال نشدهاند، در شمارش 2 فرزند محسوب نمیشوند.
|
||||
```
|
||||
|
||||
#### 3. `totalDoc/03-BACKEND/CMS/implementation-status.md`
|
||||
```markdown
|
||||
# افزودن به بخش Background Workers:
|
||||
|
||||
### ✅ DeleteInactiveUsersWorker (NEW - 2025-12-08)
|
||||
|
||||
**وضعیت**: 🔴 نیاز به پیادهسازی
|
||||
|
||||
**شرح**: حذف خودکار کاربران غیرفعال بعد از 2 هفته
|
||||
|
||||
**منطق**:
|
||||
- روزانه ساعت 3 صبح اجرا میشود
|
||||
- کاربرانی که `CreatedAt < Now - 14 days`
|
||||
- و `IsActive = false`
|
||||
- و `ClubMembershipId = null`
|
||||
- به صورت Soft Delete حذف میشوند
|
||||
|
||||
**فایل**: `CMS/BackgroundWorkers/DeleteInactiveUsersJob.cs`
|
||||
|
||||
**Dependencies**:
|
||||
- IApplicationDbContext
|
||||
- ILogger
|
||||
```
|
||||
|
||||
#### 4. `totalDoc/05-TASKS/BACKLOG.md`
|
||||
```markdown
|
||||
# اضافه کردن این 5 Task به Backlog
|
||||
|
||||
## 🔥 Critical
|
||||
|
||||
- [ ] Task #1: پیادهسازی DeleteInactiveUsersWorker (6h)
|
||||
- [ ] Task #2: الزامی کردن دیالوگ باشگاه (8h)
|
||||
- [ ] Task #3: شرط نمایش لینک معرفی (4h)
|
||||
|
||||
## ⚠️ Medium
|
||||
|
||||
- [ ] Task #4: Validation 2 فرزند فعال (4h)
|
||||
- [ ] Task #5: پیغام خطای کد معرف پر (3h)
|
||||
|
||||
## 📝 Low
|
||||
|
||||
- [ ] Task #6: Update Documentation (2h)
|
||||
|
||||
**زمان کل**: 27 ساعت (~4 روز کاری)
|
||||
```
|
||||
|
||||
**تخمین زمان**: 2-3 ساعت
|
||||
|
||||
---
|
||||
|
||||
## 📊 خلاصه Task ها
|
||||
|
||||
| # | عنوان | Priority | زمان | وضعیت |
|
||||
|---|--------|----------|------|--------|
|
||||
| 1 | DeleteInactiveUsersWorker | 🔥 Critical | 6h | ⬜ Todo |
|
||||
| 2 | الزامی دیالوگ باشگاه | 🔥 Critical | 8h | ⬜ Todo |
|
||||
| 3 | شرط لینک معرفی | 🔥 Critical | 4h | ⬜ Todo |
|
||||
| 4 | Validation 2 فرزند فعال | ⚠️ Medium | 4h | ⬜ Todo |
|
||||
| 5 | پیغام کد معرف پر | ⚠️ Medium | 3h | ⬜ Todo |
|
||||
| 6 | Update Documentation | 📝 Low | 3h | ⬜ Todo |
|
||||
|
||||
**مجموع زمان**: 28 ساعت (~4 روز کاری)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 پلان اجرا (پیشنهادی)
|
||||
|
||||
### روز 1 (8 ساعت):
|
||||
- [ ] Task #1: DeleteInactiveUsersWorker (6h)
|
||||
- [ ] شروع Task #2 (2h)
|
||||
|
||||
### روز 2 (8 ساعت):
|
||||
- [ ] ادامه Task #2: Dialog الزامی (6h)
|
||||
- [ ] شروع Task #3 (2h)
|
||||
|
||||
### روز 3 (8 ساعت):
|
||||
- [ ] ادامه Task #3: شرط لینک (2h)
|
||||
- [ ] Task #4: Validation (4h)
|
||||
- [ ] شروع Task #5 (2h)
|
||||
|
||||
### روز 4 (4 ساعت):
|
||||
- [ ] ادامه Task #5 (1h)
|
||||
- [ ] Task #6: Documentation (3h)
|
||||
|
||||
---
|
||||
|
||||
## ✅ Definition of Done
|
||||
|
||||
هر Task زمانی Complete حساب میشود که:
|
||||
1. ✅ کد نوشته شده و Build موفق
|
||||
2. ✅ Unit Test / Manual Test انجام شده
|
||||
3. ✅ Code Review شده
|
||||
4. ✅ Documentation بهروز شده
|
||||
5. ✅ Merge به Main Branch
|
||||
|
||||
---
|
||||
|
||||
**تهیهکننده**: AI Assistant
|
||||
**تاریخ**: 2025-12-08
|
||||
**نسخه**: 1.0
|
||||
@@ -0,0 +1,250 @@
|
||||
# گزارش بررسی تطبیق بیزینس با کد
|
||||
|
||||
**تاریخ بررسی**: _________
|
||||
**بررسیکننده**: _________
|
||||
**نسخه کد**: _________
|
||||
|
||||
---
|
||||
|
||||
## ✅ بیزینس 1: Binary Tree (درخت دودویی)
|
||||
|
||||
### بررسی کد:
|
||||
```bash
|
||||
# دستور اجرا شده:
|
||||
cd CMS/src/CMSMicroservice.Domain/Entities
|
||||
grep -A 20 "class User" User.cs | grep -E "Parent|Left|Right"
|
||||
```
|
||||
|
||||
### نتیجه:
|
||||
- [ ] ✅ User دارای Parent, LeftChild, RightChild است
|
||||
- [ ] ✅ Spillover Logic پیادهسازی شده
|
||||
- [ ] ✅ Depth محاسبه میشود
|
||||
- [ ] ✅ Parent تغییر نمیکند
|
||||
|
||||
### تست عملی:
|
||||
```
|
||||
ثبتنام 7 کاربر:
|
||||
- User1 (Root)
|
||||
- User2 (Left of 1)
|
||||
- User3 (Right of 1)
|
||||
- User4 (Left of 2) ✓
|
||||
- User5 (Right of 2) ✓
|
||||
- User6 (Left of 3) ✓
|
||||
- User7 (Right of 3) ✓
|
||||
|
||||
نتیجه: [✅ موفق] [❌ ناموفق]
|
||||
```
|
||||
|
||||
### تطبیق با داکیومنت:
|
||||
- فایل: `totalDoc/CMS/binary-tree-registration-guide.md`
|
||||
- وضعیت: [✅ تطبیق کامل] [⚠️ نیاز به بهروزرسانی] [❌ عدم تطبیق]
|
||||
- توضیحات: _________________
|
||||
|
||||
---
|
||||
|
||||
## 💰 بیزینس 2: محاسبه کمیسیون
|
||||
|
||||
### بررسی کد:
|
||||
```bash
|
||||
# Cron Job
|
||||
cd CMS/src/CMSMicroservice.Application/BackgroundWorkers
|
||||
grep "Cron.*Sunday" -r .
|
||||
|
||||
# فرمول
|
||||
grep "TotalPV.*Percentage" -r .
|
||||
```
|
||||
|
||||
### نتیجه:
|
||||
- [ ] ✅ Cron: یکشنبه 00:05 UTC
|
||||
- [ ] ✅ فرمول: Commission = TotalPV × Percentage
|
||||
- [ ] ✅ MinimumPV چک میشود
|
||||
- [ ] ✅ CarryOver به هفته بعد
|
||||
- [ ] ✅ MaxCommission رعایت میشود
|
||||
|
||||
### تست عملی:
|
||||
```
|
||||
User: TestUser1
|
||||
PV این هفته: 1000
|
||||
Percentage: 10%
|
||||
MinimumPV: 500
|
||||
|
||||
محاسبه شده: _______
|
||||
انتظار: 100
|
||||
|
||||
نتیجه: [✅ موفق] [❌ ناموفق]
|
||||
```
|
||||
|
||||
### تطبیق با داکیومنت:
|
||||
- فایل: `totalDoc/CMS/network-club-commission-system-v1.1.md`
|
||||
- وضعیت: [✅ تطبیق کامل] [⚠️ نیاز به بهروزرسانی] [❌ عدم تطبیق]
|
||||
- توضیحات: _________________
|
||||
|
||||
---
|
||||
|
||||
## 🏆 بیزینس 3: سطوح باشگاه
|
||||
|
||||
### بررسی کد:
|
||||
```bash
|
||||
cd CMS/src/CMSMicroservice.Domain/Entities
|
||||
grep -A 10 "ClubLevel" ClubMembership.cs
|
||||
```
|
||||
|
||||
### نتیجه:
|
||||
- [ ] ✅ 4 سطح: Bronze, Silver, Gold, Platinum
|
||||
- [ ] ✅ شرط ارتقا پیادهسازی شده
|
||||
- [ ] ✅ سطح پایین نمیآید
|
||||
- [ ] ✅ Duration (ماهانه/سالانه)
|
||||
|
||||
### تست عملی:
|
||||
```
|
||||
User: TestUser2
|
||||
PV فعلی: 5000 (Bronze)
|
||||
شرط Silver: 10000 PV
|
||||
|
||||
بعد از رسیدن به 10000:
|
||||
- سطح فعلی: _______
|
||||
- انتظار: Silver
|
||||
|
||||
نتیجه: [✅ موفق] [❌ ناموفق]
|
||||
```
|
||||
|
||||
### تطبیق با داکیومنت:
|
||||
- فایل: `totalDoc/CMS/network-club-commission-system-v1.1.md`
|
||||
- وضعیت: [✅ تطبیق کامل] [⚠️ نیاز به بهروزرسانی] [❌ عدم تطبیق]
|
||||
- توضیحات: _________________
|
||||
|
||||
---
|
||||
|
||||
## 💳 بیزینس 4: برداشت (Withdrawal)
|
||||
|
||||
### بررسی کد:
|
||||
```bash
|
||||
cd CMS/src/CMSMicroservice.Application/WithdrawalCQ
|
||||
ls -1 *Command.cs
|
||||
```
|
||||
|
||||
### نتیجه:
|
||||
- [ ] ✅ حداقل موجودی چک میشود
|
||||
- [ ] ✅ کارمزد محاسبه میشود
|
||||
- [ ] ✅ وضعیتها: Pending/Approved/Rejected
|
||||
- [ ] ✅ فقط مدیر میتواند تأیید کند
|
||||
- [ ] ✅ واریز بعد از Approve
|
||||
|
||||
### تست عملی:
|
||||
```
|
||||
موجودی: 200,000
|
||||
درخواست برداشت: 150,000
|
||||
کارمزد 2%: 3,000
|
||||
مبلغ نهایی: 147,000
|
||||
|
||||
نتیجه: [✅ موفق] [❌ ناموفق]
|
||||
```
|
||||
|
||||
### تطبیق با داکیومنت:
|
||||
- فایل: `totalDoc/CMS/implementation-progress.md`
|
||||
- وضعیت: [✅ تطبیق کامل] [⚠️ نیاز به بهروزرسانی] [❌ عدم تطبیق]
|
||||
- توضیحات: _________________
|
||||
|
||||
---
|
||||
|
||||
## 📧 بیزینس 5: اطلاعرسانی (Email/SMS)
|
||||
|
||||
### بررسی کد:
|
||||
```bash
|
||||
cd CMS/src/CMSMicroservice.Application/Common/Services
|
||||
ls -1 *Notification*
|
||||
```
|
||||
|
||||
### نتیجه:
|
||||
- [ ] ✅ Email برای Commission ارسال میشود
|
||||
- [ ] ✅ SMS برای تأیید موبایل
|
||||
- [ ] ✅ Template های HTML
|
||||
- [ ] ✅ ارسال بلافاصله بعد از event
|
||||
|
||||
### تست عملی:
|
||||
```
|
||||
Event: Commission Calculated
|
||||
User Email: test@example.com
|
||||
|
||||
Email دریافت شد؟ [✅ بله] [❌ خیر]
|
||||
محتوای Email صحیح؟ [✅ بله] [❌ خیر]
|
||||
|
||||
نتیجه: [✅ موفق] [❌ ناموفق]
|
||||
```
|
||||
|
||||
### تطبیق با داکیومنت:
|
||||
- فایل: `totalDoc/CMS/email-sms-configuration-guide.md`
|
||||
- وضعیت: [✅ تطبیق کامل] [⚠️ نیاز به بهروزرسانی] [❌ عدم تطبیق]
|
||||
- توضیحات: _________________
|
||||
|
||||
---
|
||||
|
||||
## 🛒 بیزینس 6: سفارش و فاکتور
|
||||
|
||||
### بررسی کد:
|
||||
```bash
|
||||
cd CMS/src/CMSMicroservice.Domain/Entities
|
||||
grep -A 20 "class UserOrder" UserOrder.cs
|
||||
```
|
||||
|
||||
### نتیجه:
|
||||
- [ ] ✅ UserOrder و FactorDetail
|
||||
- [ ] ✅ محاسبه PV
|
||||
- [ ] ✅ وضعیت سفارش
|
||||
- [ ] ✅ VatPercentage اضافه شده
|
||||
|
||||
### تست عملی:
|
||||
```
|
||||
محصول 1: قیمت 100,000، PV: 50
|
||||
محصول 2: قیمت 200,000، PV: 100
|
||||
|
||||
جمع PV: _______
|
||||
انتظار: 150
|
||||
|
||||
VAT 10%: _______
|
||||
انتظار: 30,000
|
||||
|
||||
نتیجه: [✅ موفق] [❌ ناموفق]
|
||||
```
|
||||
|
||||
### تطبیق با داکیومنت:
|
||||
- فایل: `totalDoc/CMS/network-club-commission-system-v1.1.md`
|
||||
- وضعیت: [✅ تطبیق کامل] [⚠️ نیاز به بهروزرسانی] [❌ عدم تطبیق]
|
||||
- توضیحات: _________________
|
||||
|
||||
---
|
||||
|
||||
## 📊 خلاصه نتایج
|
||||
|
||||
### آمار کلی:
|
||||
- تعداد بیزینس بررسی شده: 6
|
||||
- تطبیق کامل: _____ (___%)
|
||||
- نیاز به بهروزرسانی داکیومنت: _____
|
||||
- عدم تطبیق (Bug): _____
|
||||
|
||||
### موارد نیازمند اقدام فوری:
|
||||
1. _________________
|
||||
2. _________________
|
||||
3. _________________
|
||||
|
||||
### موارد نیازمند بهروزرسانی داکیومنت:
|
||||
1. _________________
|
||||
2. _________________
|
||||
3. _________________
|
||||
|
||||
---
|
||||
|
||||
## 🎯 اقدامات بعدی
|
||||
|
||||
### این هفته:
|
||||
- [ ] _________________
|
||||
- [ ] _________________
|
||||
|
||||
### ماه آینده:
|
||||
- [ ] _________________
|
||||
- [ ] _________________
|
||||
|
||||
---
|
||||
|
||||
**امضا**: _________
|
||||
**تاریخ تکمیل گزارش**: _________
|
||||
Reference in New Issue
Block a user