# 🛒 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; /// /// تصویر گالری محصول تخفیفی /// public class DiscountProductImage : BaseAuditableEntity { /// /// شناسه محصول /// public long DiscountProductId { get; set; } /// /// محصول /// public virtual DiscountProduct DiscountProduct { get; set; } /// /// عنوان تصویر /// public string? Title { get; set; } /// /// متن جایگزین (Alt) /// public string? AltText { get; set; } /// /// مسیر تصویر اصلی /// public string ImagePath { get; set; } /// /// مسیر تصویر کوچک /// public string? ThumbnailPath { get; set; } /// /// ترتیب نمایش /// public int SortOrder { get; set; } /// /// آیا تصویر اصلی محصول است؟ /// 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 { public void Configure(EntityTypeBuilder 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 /// /// تصاویر گالری محصول /// public virtual ICollection Images { get; set; } ``` ### 1.4 به‌روزرسانی DbContext **فایل**: `CMS/src/CMSMicroservice.Infrastructure/Persistence/ApplicationDbContext.cs` ```csharp public DbSet 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 { 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 TopProducts { get; set; } // فروش روزانه (برای نمودار) public List 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> GetProductImagesAsync(long productId); Task AddProductImageAsync(AddProductImageDto dto); Task UpdateProductImageAsync(UpdateProductImageDto dto); Task DeleteProductImageAsync(long imageId); Task ReorderProductImagesAsync(long productId, List 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 موجود | --- **آخرین به‌روزرسانی**: ۱۰ دی ۱۴۰۴