# 🛒 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 موجود |

---

**آخرین به‌روزرسانی**: ۱۰ دی ۱۴۰۴
