522 lines
28 KiB
Markdown
522 lines
28 KiB
Markdown
# یکسانسازی فروشگاه عادی و فروشگاه تخفیفی (BackOffice)
|
|
|
|
**تاریخ:** ۱۳۹۴/۱۱/۲۴ (2026-02-13)
|
|
**وضعیت:** ✅ فاز ۱ تا ۶ — تکمیل شده (CMS + BackOffice Build Succeeded — 0 Error)
|
|
|
|
---
|
|
|
|
## هدف
|
|
|
|
هر دو فروشگاه (عادی و تخفیفی) از نظر **UI/UX، ساختار صفحات، اکشنها و قابلیتها** عینبهعین یکسان باشند.
|
|
**تنها تفاوت مجاز:** منطق پرداخت — فروشگاه تخفیفی از کیفپول تخفیفی + درگاه، فروشگاه عادی فقط از کیفپول عادی.
|
|
|
|
### معیار یکسانسازی
|
|
- **مبنا:** فروشگاه عادی (Products, Category, UserOrder)
|
|
- **استثنا:** مزایای بدیهی فروشگاه تخفیفی به فروشگاه عادی هم اضافه شد
|
|
- **Bulk Operations:** بیخیال شد (طبق درخواست کاربر)
|
|
|
|
---
|
|
|
|
## تفاوتهای زیرساختی (تغییر نکرده — بیتأثیر روی UX)
|
|
|
|
| موضوع | فروشگاه عادی | فروشگاه تخفیفی |
|
|
|---|---|---|
|
|
| ارتباط با سرور | gRPC مستقیم (`ProductsContractClient`) | سرویس اینترفیس (`IDiscountProductService`) که داخلاً gRPC صدا میزنه |
|
|
| مدل داده | Protobuf models | C# DTOs |
|
|
|
|
> **نکته:** هر دو در نهایت از همان gRPC backend استفاده میکنند. تفاوت فقط در لایه abstraction است و تأثیری روی UX ندارد.
|
|
|
|
---
|
|
|
|
## تغییرات انجامشده
|
|
|
|
### ۱. صفحه محصولات (`DiscountProductsMainPage`)
|
|
|
|
| تغییر | قبل | بعد |
|
|
|---|---|---|
|
|
| نمایش تصویر | `MudAvatar` | کامپوننت `Image` (مطابق فروشگاه عادی) |
|
|
| برش عنوان | `Substring(0, 20) + "…"` | `Truncate(20, true)` (extension method مشترک) |
|
|
| گالری تصاویر | `ProductFormDialog` (کلاینتساید) | `GalleryDialog` سرور-محور (مطابق فروشگاه عادی) |
|
|
| پیشنمایش تصویر | HTML inline در `ShowMessageBox` | `ImagePreviewDialog` (مطابق فروشگاه عادی) |
|
|
| عنوان تولبار | «مدیریت محصولات تخفیفی» | «مدیریت محصولات» |
|
|
|
|
**اکشنهای جدید اضافهشده:**
|
|
- ✅ دکمه «مدیریت دستهبندی (درگ و دراپ)» → ناوبری به `ProductCategoriesDragDropPage`
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/DiscountShop/DiscountProductsMainPage.razor`
|
|
- `Pages/DiscountShop/DiscountProductsMainPage.razor.cs`
|
|
|
|
---
|
|
|
|
### ۲. صفحه دستهبندیها (`DiscountCategoriesMainPage`)
|
|
|
|
**اکشنهای جدید اضافهشده:**
|
|
- ✅ دکمه «مدیریت محصولات این دسته (درگ و دراپ)» → ناوبری به `CategoryProductsDragDropPage`
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/DiscountShop/DiscountCategoriesMainPage.razor`
|
|
- `Pages/DiscountShop/DiscountCategoriesMainPage.razor.cs`
|
|
|
|
---
|
|
|
|
### ۳. صفحه سفارشات (`DiscountOrdersMainPage`) — بازنویسی کامل
|
|
|
|
| تغییر | قبل | بعد |
|
|
|---|---|---|
|
|
| الگوی فیلتر | فیلترهای inline با دکمه جستجو | `BasePageComponent` با OnSubmit/OnClear (مطابق فروشگاه عادی) |
|
|
| لایهبندی | `MudPaper` تو در تو | `BasePageComponent > Filters + Content` |
|
|
| اکشنها | فقط مشاهده جزئیات + تغییر وضعیت | جزئیات + تغییر وضعیت + حذف (مطابق فروشگاه عادی) |
|
|
| آیکونهای اکشن | `Visibility` + `Edit` | `Info` + `LocalShipping` + `DeleteOutline` (مطابق فروشگاه عادی) |
|
|
| ساختار تولبار | بدون تولبار | تولبار با عنوان + دکمه Excel (مطابق فروشگاه عادی) |
|
|
|
|
**ستونها (حفظ شده — خاص فروشگاه تخفیفی):**
|
|
- شماره سفارش، تاریخ ثبت، مبلغ کل، **تخفیف کیفپول**، **پرداخت درگاه**، تعداد آیتم، وضعیت، پرداخت
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/DiscountShop/DiscountOrdersMainPage.razor` ← بازنویسی کامل
|
|
- `Pages/DiscountShop/DiscountOrdersMainPage.razor.cs` ← بازنویسی کامل
|
|
|
|
---
|
|
|
|
### ۴. گزارش فروش (`SalesReports`)
|
|
|
|
| تغییر | قبل | بعد |
|
|
|---|---|---|
|
|
| نمودارها | روند فروش + محصولات پرفروش | روند فروش + محصولات پرفروش + **وضعیت سفارشها** |
|
|
| عنوان | «گزارش فروش فروشگاه تخفیفی» | «گزارش فروش فروشگاه» |
|
|
| توضیح | «آمار فروش، تخفیف و وضعیت سفارشهای فروشگاه تخفیفی...» | «آمار فروش و وضعیت سفارشها بر اساس بازه تاریخ و وضعیت سفارش» |
|
|
|
|
**نمودار جدید:**
|
|
- ✅ «وضعیت سفارشها» — نمودار میلهای تعداد سفارش بر اساس وضعیت (مطابق فروشگاه عادی)
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/DiscountShop/SalesReports.razor`
|
|
|
|
---
|
|
|
|
### ۵. هاب سفارشات (`DiscountShopHub`)
|
|
|
|
| تغییر | قبل | بعد |
|
|
|---|---|---|
|
|
| عنوان | «فروشگاه تخفیفی» | «سفارشات فروشگاه تخفیفی» |
|
|
| آیکون تب سفارشات | `ShoppingCart` | `ReceiptLong` (مطابق `OrdersHub` فروشگاه عادی) |
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/DiscountShop/DiscountShopHub.razor`
|
|
|
|
---
|
|
|
|
### ۶. تغییرات فروشگاه عادی (مزایای تخفیفی ← عادی)
|
|
|
|
#### CategoryMainPage
|
|
- ✅ ستون **«ترتیب»** (`SortOrder`) اضافه شد (از تخفیفی)
|
|
- ✅ **غیرفعالسازی حذف** دستهبندی دارای زیردسته (از تخفیفی)
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/Category/CategoryMainPage.razor`
|
|
- `Pages/Category/CategoryMainPage.razor.cs`
|
|
|
|
---
|
|
|
|
## تغییرات فاز ۲ — ارتقاء به Admin RPC و فیلدهای پیشرفته
|
|
|
|
### ۷. سرویس سفارشات تخفیفی — سوئیچ به Admin RPC
|
|
|
|
| تغییر | قبل | بعد |
|
|
|---|---|---|
|
|
| RPC مورد استفاده | `GetUserOrders` (user-scoped) | `GetAllDiscountOrders` (admin-scoped) |
|
|
| DTO | `OrderSummaryDto` (محدود) | `AdminOrderDto` (کامل با user_full_name, user_mobile, shipping_address, payment_date, vat_amount...) |
|
|
| فیلترها | فقط userId, paymentCompleted, deliveryStatus | userId, paymentStatus, deliveryStatus, userMobile, trackingCode, fromDate, toDate, minAmount, maxAmount |
|
|
| گزارش فروش | محاسبه کلاینتساید + N+1 (۵۰ فراخوان gRPC جداگانه!) | `GetDiscountSalesReport` RPC سرور-ساید با fallback |
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Services/DiscountOrder/IDiscountOrderService.cs` ← فیلترهای جدید + DTOهای گزارش فروش
|
|
- `Services/DiscountOrder/DiscountOrderService.cs` ← سوئیچ به `GetAllDiscountOrdersAsync` + `GetDiscountSalesReportAsync`
|
|
|
|
### ۸. ستونها و فیلترهای ادمین در سفارشات تخفیفی
|
|
|
|
**ستونهای جدید اضافهشده:**
|
|
- ✅ **نام کاربر** (لینک به پروفایل — مطابق فروشگاه عادی)
|
|
- ✅ **موبایل کاربر**
|
|
- ✅ **وضعیت پرداخت** (Pending/Completed/Failed/Refunded — مطابق فروشگاه عادی)
|
|
- ✅ **تاریخ پرداخت**
|
|
- ✅ **آدرس** (truncated با tooltip — مطابق فروشگاه عادی)
|
|
- ✅ **وضعیت ارسال** (جدا از وضعیت پرداخت — مطابق فروشگاه عادی)
|
|
|
|
**فیلترهای جدید اضافهشده:**
|
|
- ✅ شناسه سفارش
|
|
- ✅ جستجوی کاربر (UserAutoComplete)
|
|
- ✅ موبایل کاربر
|
|
- ✅ کد رهگیری
|
|
- ✅ از تاریخ / تا تاریخ
|
|
- ✅ وضعیت پرداخت (Pending/Completed/Failed/Refunded)
|
|
- ✅ وضعیت ارسال
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/DiscountShop/DiscountOrdersMainPage.razor` ← ستونها + فیلترها
|
|
- `Pages/DiscountShop/DiscountOrdersMainPage.razor.cs` ← فیلدها + متدهای وضعیت پرداخت
|
|
|
|
### ۹. گزارش فروش تخفیفی — حذف مشکل N+1
|
|
|
|
| تغییر | قبل | بعد |
|
|
|---|---|---|
|
|
| محصولات پرفروش | ۵۰ فراخوان gRPC جداگانه (`GetByIdAsync` × 50) | یک فراخوان `GetDiscountSalesReport` |
|
|
| خلاصه آماری | محاسبه کلاینتساید | سرور-ساید (دقیقتر + سریعتر) |
|
|
| نمودار روند | GroupBy کلاینتساید | `SalesPeriodDto` از سرور |
|
|
| جدول سفارشها | فقط شماره سفارش | شناسه + نام کاربر (لینک) |
|
|
| خروجی Excel/PDF | فقط OrderNumber | شناسه + نام کاربر + موبایل |
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/DiscountShop/SalesReports.razor`
|
|
|
|
### ۱۰. دستهبندی فروشگاه عادی — فیلد ImagePath
|
|
|
|
- ✅ فیلد `ImagePath` به دیالوگ ایجاد/ویرایش دستهبندی اضافه شد (مطابق فروشگاه تخفیفی)
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/Category/Components/CreateOrUpdateCategoryDialog.razor`
|
|
- `Pages/Category/Components/CreateOrUpdateCategoryDialog.razor.cs`
|
|
|
|
### ۱۱. گزارش فروش عادی — نمودار محصولات پرفروش + خروجی PDF
|
|
|
|
- ✅ نمودار «محصولات پرفروش (بر اساس مبلغ)» از FactorDetails سفارشات
|
|
- ✅ دکمه خروجی PDF (نسخه متنی) — مطابق فروشگاه تخفیفی
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/UserOrder/OrderSalesReports.razor`
|
|
- `Pages/UserOrder/OrderSalesReports.razor.cs`
|
|
|
|
---
|
|
|
|
## تغییرات فاز ۳ — تگهای محصول و نهاییسازی
|
|
|
|
### ۱۲. تگهای محصول در فروشگاه تخفیفی
|
|
|
|
- ✅ دکمه «تگهای محصول» (`Label` icon) به ستون عملیات صفحه محصولات تخفیفی اضافه شد
|
|
- ✅ از همان `AssignTagsDialog` فروشگاه عادی استفاده شد (کامپوننت مشترک)
|
|
- ✅ سرویس `ProductTagContract` مشترک بین هر دو فروشگاه — بدون نیاز به API جدید
|
|
|
|
> **نکته:** `ProductTagContract` یک سرویس ژنریک `product_id ↔ tag_id` است و محدود به فروشگاه خاصی نیست.
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/DiscountShop/DiscountProductsMainPage.razor` ← دکمه تگ
|
|
- `Pages/DiscountShop/DiscountProductsMainPage.razor.cs` ← متد `OpenTagAssignment` + using
|
|
|
|
---
|
|
|
|
## تغییرات فاز ۴ — یکسانسازی دیالوگها و جزئیات تکمیلی
|
|
|
|
### ۱۳. دیالوگ جزئیات سفارش تخفیفی — Timeline + ویرایش Inline
|
|
|
|
| تغییر | قبل | بعد |
|
|
|---|---|---|
|
|
| Timeline وضعیت | ❌ فاقد | ✅ ۵ مرحله (ثبت → پرداخت → آمادهسازی → ارسال → تحویل/مرجوعی) |
|
|
| ویرایش وضعیت | ❌ فقط خواندنی | ✅ درونخطی (وضعیت + کد رهگیری + یادداشت ادمین) |
|
|
| دکمه ذخیره | ❌ فقط «بستن» | ✅ «ثبت تغییرات» + اسپینر بارگذاری |
|
|
| هشدارهای شرطی | ❌ فاقد | ✅ هشدار لغو/مرجوعی + اطلاعرسانی ارسال |
|
|
| Code-behind | `@code` درونخطی | فایل جداگانه `.razor.cs` |
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/DiscountShop/Components/OrderDetailsDialog.razor` ← Timeline + ویرایش inline
|
|
- `Pages/DiscountShop/Components/OrderDetailsDialog.razor.cs` ← فایل جدید — timeline + save logic
|
|
|
|
### ۱۴. دیالوگ تغییر وضعیت فروشگاه عادی — ارتقاء
|
|
|
|
| تغییر | قبل | بعد |
|
|
|---|---|---|
|
|
| فرم | `MudStack` ساده | `MudForm` با validation |
|
|
| فیلدها | فقط وضعیت | ✅ وضعیت + **کد رهگیری** + **توضیحات ارسال** |
|
|
| هشدارهای شرطی | ❌ فاقد | ✅ هشدار مرجوعی + اطلاعرسانی ارسال |
|
|
| دکمه | رنگ ثابت `Primary` | ✅ رنگ داینامیک بر اساس وضعیت + اسپینر |
|
|
| عنوان | بدون آیکون | ✅ آیکون `Edit` + عنوان |
|
|
| RPC | فقط `UpdateOrderStatusAsync` | ✅ `UpdateOrderStatusAsync` + `UpdateUserOrderAsync` (کد رهگیری + توضیحات) |
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/UserOrder/Components/ChangeOrderStatusDialog.razor`
|
|
- `Pages/UserOrder/Components/ChangeOrderStatusDialog.razor.cs`
|
|
|
|
### ۱۵. گزارش فروش تخفیفی — Empty chart guard + ترتیب نمودارها
|
|
|
|
| تغییر | قبل | بعد |
|
|
|---|---|---|
|
|
| نمودار روند فروش | بدون بررسی خالی بودن | ✅ نمایش «داده کافی برای نمایش نمودار وجود ندارد» |
|
|
| ترتیب نمودارها | روند → پرفروش → وضعیت | ✅ روند → **وضعیت** → پرفروش (مطابق فروشگاه عادی) |
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/DiscountShop/SalesReports.razor`
|
|
|
|
### ۱۶. گزارش فروش عادی — لینک نام کاربر
|
|
|
|
- ✅ نام کاربر در جدول سفارشها از متن ساده به `MudLink` تبدیل شد (لینک به پروفایل کاربر)
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/UserOrder/OrderSalesReports.razor`
|
|
|
|
### ۱۷. دیالوگ دستهبندی فروشگاه عادی — MudForm + UX
|
|
|
|
| تغییر | قبل | بعد |
|
|
|---|---|---|
|
|
| اعتبارسنجی | ❌ بدون validation | ✅ `MudForm` با `Required` + `RequiredError` |
|
|
| فیلد فعال | `MudCheckBox` | ✅ `MudSwitch` رنگی (مطابق فروشگاه تخفیفی) |
|
|
| Helper text | ❌ فاقد | ✅ «عدد کمتر = اولویت بالاتر» + «برای دسته اصلی خالی بگذارید» |
|
|
| دکمه ذخیره | همیشه «ثبت» | ✅ «ذخیره تغییرات» / «ایجاد دستهبندی» (داینامیک) |
|
|
| اسپینر بارگذاری | ❌ فاقد | ✅ `MudProgressCircular` + غیرفعالسازی دکمه |
|
|
| عنوان | بدون آیکون | ✅ آیکون `Edit`/`Add` + عنوان داینامیک |
|
|
| غیرفعالسازی دکمه | ❌ فاقد | ✅ غیرفعال تا validation سبز نشود |
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/Category/CreateOrUpdateCategoryDialog.razor`
|
|
- `Pages/Category/CreateOrUpdateCategoryDialog.razor.cs`
|
|
|
|
### ۱۸. سفارشات تخفیفی — لغو سفارش واقعی
|
|
|
|
| تغییر | قبل | بعد |
|
|
|---|---|---|
|
|
| دکمه «حذف» | آیکون `DeleteOutline` — فقط snackbar (بدون API) | ✅ آیکون `Cancel` — فراخوان `UpdateStatusAsync` با `Cancelled` |
|
|
| متن تأییدیه | «آیا از حذف مطمئن هستید؟» | «آیا از لغو سفارش مطمئن هستید؟ وضعیت به لغو شده تغییر میکند» |
|
|
| عملکرد | ❌ هیچ | ✅ واقعی — `UpdateStatusAsync(Cancelled)` |
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/DiscountShop/DiscountOrdersMainPage.razor` ← آیکون + tooltip
|
|
- `Pages/DiscountShop/DiscountOrdersMainPage.razor.cs` ← فراخوان API
|
|
|
|
---
|
|
|
|
## تغییرات فاز ۵ — فرمتبندی قیمت، زیردسته و برچسب فیلدها
|
|
|
|
### ۵.۱ فرمتبندی قیمت در لیست محصولات عادی
|
|
|
|
**مشکل:** ستون قیمت عدد خام بدون separator و بدون واحد نشان میداد.
|
|
**راهحل:** تبدیل `PropertyColumn` به `TemplateColumn` با `Price.ToString("N0") ریال` — مطابق فروشگاه تخفیفی.
|
|
|
|
**فایل تغییر یافته:**
|
|
- `Pages/Products/ProductsMainPage.razor` ← TemplateColumn + فرمت N0 + ریال
|
|
|
|
### ۵.۲ دکمه «افزودن زیردسته» در دستهبندیهای عادی
|
|
|
|
**مشکل:** فروشگاه تخفیفی دکمه «افزودن زیردسته» در ستون عملیات داشت ولی فروشگاه عادی نداشت.
|
|
**راهحل:** افزودن `MudIconButton` با آیکون `CreateNewFolder` + رنگ `Color.Primary` + متد `CreateSubcategory(parent)` که دیالوگ را با `ParentId = parent.Id` باز میکند.
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/Category/CategoryMainPage.razor` ← دکمه جدید در ستون عملیات
|
|
- `Pages/Category/CategoryMainPage.razor.cs` ← متد `CreateSubcategory`
|
|
|
|
### ۵.۳ برچسب واحد ریال در دیالوگهای محصول
|
|
|
|
**مشکل:** فیلد قیمت در دیالوگهای ایجاد/ویرایش محصول عادی `Label="قیمت"` داشت — بدون واحد.
|
|
**راهحل:** تغییر به `Label="قیمت (ریال)"` — مطابق فروشگاه تخفیفی.
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `Pages/Products/Components/CreateDialog.razor` ← قیمت (ریال)
|
|
- `Pages/Products/Components/UpdateDialog.razor` ← قیمت (ریال)
|
|
|
|
---
|
|
|
|
## تغییرات فاز ۶ — تغییرات بکند (Proto + Handler + gRPC Service)
|
|
|
|
این فاز تمام موارد "محدودیت API" که در فازهای قبلی شناسایی شده بودند را حل میکند.
|
|
|
|
### ۶.۱ ستون وضعیت فعال/غیرفعال محصولات (`is_active`)
|
|
|
|
**مشکل:** پروتوباف `GetAllProductsByFilterResponseModel` فیلد `is_active` نداشت. محصولات عادی ستون وضعیت نداشتند.
|
|
**راهحل (end-to-end):**
|
|
- **Proto:** افزودن `bool is_active = 15` به `GetAllProductsByFilterResponseModel` + `google.protobuf.BoolValue is_active = 15` به `GetAllProductsByFilterFilter`
|
|
- **DTO:** افزودن `bool IsActive` به `CustomerProductModel`
|
|
- **Query:** افزودن `bool? IsActive` به `GetCustomerProductsByFilterQuery`
|
|
- **Handler:** فیلتر `IsDeleted != IsActive` + مپ `IsActive = !p.IsDeleted`
|
|
- **gRPC Service:** مپ `IsActive` در فیلتر و ریسپانس `ProductsService`
|
|
- **Frontend:** ستون `TemplateColumn` با `MudChip` رنگی در `ProductsMainPage.razor`
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `CMS/.../Protos/products.proto`
|
|
- `CMS/.../GetCustomerProductsByFilterResponseDto.cs`
|
|
- `CMS/.../GetCustomerProductsByFilterQuery.cs`
|
|
- `CMS/.../GetCustomerProductsByFilterQueryHandler.cs`
|
|
- `CMS/.../Services/ProductsService.cs`
|
|
- `BackOffice/.../Pages/Products/ProductsMainPage.razor`
|
|
|
|
### ۶.۲ ستون تعداد محصولات دستهبندی (`product_count`)
|
|
|
|
**مشکل:** پروتوباف `GetAllCategoryByFilterResponseModel` فیلد `product_count` نداشت.
|
|
**راهحل (end-to-end):**
|
|
- **Proto:** افزودن `int32 product_count = 9` به `GetAllCategoryByFilterResponseModel`
|
|
- **DTO:** افزودن `int ProductCount` به `GetAllCategoryByFilterResponseModel` (C#)
|
|
- **Handler:** تغییر از `ProjectToType<>()` (Mapster auto-map) به manual `Select()` با `ProductCount = x.ProductCategories.Count`
|
|
- **gRPC Service:** auto-map Mapster (نام یکسان)
|
|
- **Frontend:** ستون `PropertyColumn` جدید در `CategoryMainPage.razor`
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `CMS/.../Protos/category.proto`
|
|
- `CMS/.../GetAllCategoryByFilterResponseDto.cs`
|
|
- `CMS/.../GetAllCategoryByFilterQueryHandler.cs`
|
|
- `BackOffice/.../Pages/Category/CategoryMainPage.razor`
|
|
|
|
### ۶.۳ فیلتر بازه تاریخ سفارشات (`from_date` / `to_date`)
|
|
|
|
**مشکل:** پروتوباف `GetAllUserOrderByFilterFilter` فقط یک `payment_date` داشت. امکان فیلتر بازه تاریخ وجود نداشت.
|
|
**راهحل (end-to-end):**
|
|
- **Proto:** افزودن `google.protobuf.Timestamp from_date = 11` و `google.protobuf.Timestamp to_date = 12` به فیلتر
|
|
- **gRPC Service:** مپ `FromDate` از `from_date` (با fallback به `payment_date`)، `ToDate` از `to_date`
|
|
- **Handler:** بدون تغییر — از قبل `FromDate`/`ToDate` را ساپورت میکرد
|
|
- **Frontend:** افزودن `MudDatePicker` دوم (تا تاریخ)، مپ به `Filter.FromDate`/`Filter.ToDate`
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `CMS/.../Protos/userorder.proto`
|
|
- `CMS/.../Services/UserOrderService.cs`
|
|
- `BackOffice/.../Pages/UserOrder/UserOrderMainPage.razor`
|
|
- `BackOffice/.../Pages/UserOrder/UserOrderMainPage.razor.cs`
|
|
|
|
### ۶.۴ تصویر محصول در آیتمهای سفارش تخفیفی (`image_path`)
|
|
|
|
**مشکل:** `OrderItemDto` در proto و C# فیلد `image_path` نداشت. آیتمهای سفارش بدون تصویر بودند.
|
|
**راهحل (end-to-end):**
|
|
- **Proto:** افزودن `string image_path = 9` و `string thumbnail_path = 10` به `OrderItemDto` در `discountorder.proto`
|
|
- **Backend DTO:** افزودن `ImagePath`/`ThumbnailPath` به `OrderItemDto` (C# Application layer)
|
|
- **Handler:** مپ `ImagePath = od.Product.ImagePath` در `GetOrderByIdQueryHandler` (Product nav property از قبل Include شده بود)
|
|
- **Frontend DTO:** افزودن فیلدها به `IDiscountOrderService.OrderItemDto`
|
|
- **Frontend Service:** مپ در `DiscountOrderService`
|
|
- **Frontend Dialog:** `MudImage` + `MudStack` برای نمایش تصویر کنار نام محصول
|
|
|
|
**فایلهای تغییر یافته:**
|
|
- `CMS/.../Protos/discountorder.proto`
|
|
- `CMS/.../GetOrderByIdQuery.cs` (OrderItemDto)
|
|
- `CMS/.../GetOrderByIdQueryHandler.cs`
|
|
- `BackOffice/.../Services/DiscountOrder/IDiscountOrderService.cs`
|
|
- `BackOffice/.../Services/DiscountOrder/DiscountOrderService.cs`
|
|
- `BackOffice/.../Pages/DiscountShop/Components/OrderDetailsDialog.razor`
|
|
|
|
---
|
|
|
|
## وضعیت مقایسهای نهایی
|
|
|
|
### محصولات
|
|
| قابلیت | عادی | تخفیفی |
|
|
|---|:---:|:---:|
|
|
| لیست با MudDataGrid + server-side | ✅ | ✅ |
|
|
| فیلتر با BasePageComponent | ✅ | ✅ |
|
|
| نمایش تصویر (Image component) | ✅ | ✅ |
|
|
| برش عنوان (Truncate) | ✅ | ✅ |
|
|
| ایجاد/ویرایش/حذف | ✅ | ✅ |
|
|
| گالری تصاویر (GalleryDialog سرور-محور) | ✅ | ✅ |
|
|
| پیشنمایش تصویر (ImagePreviewDialog) | ✅ | ✅ |
|
|
| مدیریت دستهبندی (درگ و دراپ) | ✅ | ✅ |
|
|
| خروجی Excel | ✅ | ✅ |
|
|
| تگهای محصول (AssignTagsDialog مشترک) | ✅ | ✅ |
|
|
| فرمت قیمت (N0 + ریال) | ✅ | ✅ |
|
|
| ستون وضعیت فعال/غیرفعال | ✅ | ✅ |
|
|
| Bulk Edit/Delete/Toggle | ✅ | ❌ (طبق درخواست — بیخیال) |
|
|
|
|
### دستهبندیها
|
|
| قابلیت | عادی | تخفیفی |
|
|
|---|:---:|:---:|
|
|
| درخت سایدبار | ✅ | ✅ |
|
|
| گرید با MudDataGrid | ✅ | ✅ |
|
|
| ستونها: شناسه، نام لاتین، عنوان، والد، ترتیب، فعال | ✅ | ✅ |
|
|
| ستون تعداد محصولات | ✅ | ✅ |
|
|
| ایجاد/ویرایش/حذف | ✅ | ✅ |
|
|
| غیرفعالسازی حذف دارای زیردسته | ✅ | ✅ |
|
|
| افزودن زیردسته | ✅ | ✅ |
|
|
| درگاندراپ محصولات دسته | ✅ | ✅ |
|
|
|
|
### سفارشات
|
|
| قابلیت | عادی | تخفیفی |
|
|
|---|:---:|:---:|
|
|
| BasePageComponent با فیلتر | ✅ | ✅ |
|
|
| MudDataGrid + تولبار | ✅ | ✅ |
|
|
| فیلتر شناسه / کاربر / تاریخ / وضعیت | ✅ | ✅ |
|
|
| فیلتر بازه تاریخ (از تاریخ + تا تاریخ) | ✅ | ✅ |
|
|
| ستون نام کاربر (لینک به پروفایل) | ✅ | ✅ |
|
|
| ستون وضعیت پرداخت (Chip رنگی) | ✅ | ✅ |
|
|
| ستون وضعیت ارسال (Chip رنگی) | ✅ | ✅ |
|
|
| ستون تاریخ پرداخت | ✅ | ✅ |
|
|
| ستون آدرس (truncated + tooltip) | ✅ | ✅ |
|
|
| جزئیات سفارش (Timeline + ویرایش inline) | ✅ | ✅ |
|
|
| تصویر محصول در آیتمهای سفارش | ✅ | ✅ |
|
|
| تغییر وضعیت (MudForm + کد رهگیری + هشدار) | ✅ | ✅ |
|
|
| لغو سفارش | ✅ | ✅ (via UpdateStatus) |
|
|
| خروجی Excel | ✅ | ✅ |
|
|
| ستونهای مالی تخفیف (DiscountBalanceUsed/GatewayAmount) | ❌ (مربوط نیست) | ✅ |
|
|
| اعمال تخفیف | ✅ | ❌ (API ندارد) |
|
|
|
|
### گزارش فروش
|
|
| قابلیت | عادی | تخفیفی |
|
|
|---|:---:|:---:|
|
|
| فیلتر تاریخ + وضعیت | ✅ | ✅ |
|
|
| کارتهای خلاصه | ✅ | ✅ |
|
|
| نمودار روند فروش | ✅ | ✅ |
|
|
| نمودار وضعیت سفارشها | ✅ | ✅ |
|
|
| نمودار محصولات پرفروش | ✅ | ✅ |
|
|
| خروجی Excel | ✅ | ✅ |
|
|
| خروجی PDF | ✅ | ✅ |
|
|
|
|
---
|
|
|
|
## موارد باقیمانده
|
|
|
|
این موارد نیاز به تغییرات بیشتر دارند:
|
|
|
|
| مورد | جزئیات | وضعیت |
|
|
|---|---|---|
|
|
| **اعمال تخفیف سفارش تخفیفی** | `discountorder.proto` فاقد `ApplyDiscountToOrder` RPC | نیاز به RPC جدید + لاجیک سرور |
|
|
| **لغو سفارش با بازپرداخت** | لغو وضعیت ✅ ولی refund/بازگشت موجودی نیاز به RPC اختصاصی | نیاز به `CancelOrder` RPC |
|
|
|
|
> **نکته:** موارد قبلی (is_active، product_count، from_date/to_date، image_path) در **فاز ۶** حل شدند.
|
|
|
|
---
|
|
|
|
## ساختار فایلهای تغییریافته
|
|
|
|
```
|
|
CMS/src/
|
|
├── CMSMicroservice.Protobuf/Protos/
|
|
│ ├── products.proto ← is_active (filter + response field 15)
|
|
│ ├── category.proto ← product_count (response field 9)
|
|
│ ├── userorder.proto ← from_date/to_date (filter fields 11,12)
|
|
│ └── discountorder.proto ← image_path/thumbnail_path (OrderItemDto fields 9,10)
|
|
├── CMSMicroservice.Application/
|
|
│ ├── ProductsCQ/Queries/GetCustomerProductsByFilter/
|
|
│ │ ├── GetCustomerProductsByFilterQuery.cs ← IsActive filter
|
|
│ │ ├── GetCustomerProductsByFilterQueryHandler.cs ← IsActive filter + mapping
|
|
│ │ └── GetCustomerProductsByFilterResponseDto.cs ← IsActive field
|
|
│ ├── CategoryCQ/Queries/GetAllCategoryByFilter/
|
|
│ │ ├── GetAllCategoryByFilterQueryHandler.cs ← manual Select + ProductCount
|
|
│ │ └── GetAllCategoryByFilterResponseDto.cs ← ProductCount field
|
|
│ └── DiscountShopCQ/Queries/GetOrderById/
|
|
│ ├── GetOrderByIdQuery.cs ← ImagePath/ThumbnailPath
|
|
│ └── GetOrderByIdQueryHandler.cs ← Product image mapping
|
|
└── CMSMicroservice.WebApi/Services/
|
|
├── ProductsService.cs ← IsActive filter + response mapping
|
|
└── UserOrderService.cs ← FromDate/ToDate mapping
|
|
|
|
BackOffice/src/BackOffice/
|
|
├── Services/DiscountOrder/
|
|
│ ├── IDiscountOrderService.cs ← OrderItemDto + ImagePath/ThumbnailPath
|
|
│ └── DiscountOrderService.cs ← image mapping
|
|
├── Pages/
|
|
│ ├── Category/
|
|
│ │ ├── CategoryMainPage.razor ← ستون ProductCount + SortOrder + زیردسته
|
|
│ │ ├── CategoryMainPage.razor.cs ← HasChildren + CreateSubcategory
|
|
│ │ ├── CreateOrUpdateCategoryDialog.razor ← MudForm + ImagePath
|
|
│ │ └── CreateOrUpdateCategoryDialog.razor.cs ← validation + loading
|
|
│ ├── DiscountShop/
|
|
│ │ ├── DiscountShopHub.razor
|
|
│ │ ├── DiscountProductsMainPage.razor/.cs
|
|
│ │ ├── DiscountCategoriesMainPage.razor/.cs
|
|
│ │ ├── DiscountOrdersMainPage.razor/.cs
|
|
│ │ ├── SalesReports.razor
|
|
│ │ └── Components/
|
|
│ │ ├── OrderDetailsDialog.razor ← تصویر محصول + Timeline
|
|
│ │ └── OrderDetailsDialog.razor.cs
|
|
│ ├── UserOrder/
|
|
│ │ ├── UserOrderMainPage.razor ← فیلتر بازه تاریخ (از + تا)
|
|
│ │ ├── UserOrderMainPage.razor.cs ← FromDate/ToDate mapping
|
|
│ │ ├── OrderSalesReports.razor/.cs
|
|
│ │ └── Components/ChangeOrderStatusDialog.razor/.cs
|
|
│ └── Products/
|
|
│ ├── ProductsMainPage.razor ← ستون IsActive + فرمت قیمت
|
|
│ └── Components/
|
|
│ ├── CreateDialog.razor ← قیمت (ریال)
|
|
│ └── UpdateDialog.razor ← قیمت (ریال)
|
|
```
|