update
This commit is contained in:
@@ -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 موجود |
|
||||
|
||||
---
|
||||
|
||||
**آخرین بهروزرسانی**: ۱۰ دی ۱۴۰۴
|
||||
Reference in New Issue
Block a user