# Club Discount Shop System - سیستم فروشگاه باشگاه مشتریان با تخفیف ترکیبی

**تاریخ ایجاد:** 2024-12-02  
**تاریخ آپدیت:** 2024-12-02  
**وضعیت:** طراحی (Phase 9)  
**اولویت:** 🔴 بالا (یکی از دو فاز باقیمانده)

---

## 📋 فهرست

1. [مقدمه](#مقدمه)
2. [مفهوم اصلی: پرداخت ترکیبی](#مفهوم-اصلی-پرداخت-ترکیبی)
3. [تفاوت با Regular Shop](#تفاوت-با-regular-shop)
4. [معماری جداسازی](#معماری-جداسازی)
5. [Entity Design](#entity-design)
6. [Business Rules](#business-rules)
7. [تسک‌های پیاده‌سازی](#تسک-های-پیاده-سازی)

---

## 🎯 مقدمه

### هدف:
ایجاد **فروشگاه باشگاه مشتریان** که در آن کاربران می‌توانند با **پرداخت ترکیبی** خرید کنند:

**🔑 قانون اصلی**: 
- کاربر **نمی‌تواند** کل محصول را فقط با `DiscountBalance` بخرد
- کاربر می‌تواند **درصدی از قیمت** را با `DiscountBalance` پرداخت کند
- **مابقی مبلغ** باید از طریق **درگاه پرداخت واقعی در Gateway/PYMS** پرداخت شود (نه در CMS)

### مثال عملی:
```
قیمت محصول: 1,000,000 تومان
حداکثر تخفیف مجاز: 30%
DiscountBalance کاربر: 500,000 تومان

محاسبه:
- حداکثر تخفیف قابل استفاده: 1,000,000 × 30% = 300,000 تومان
- DiscountBalance کاربر: 500,000 تومان (بیشتر از 300,000)
- مبلغ تخفیف نهایی: 300,000 تومان (محدود به 30%)
- مبلغ قابل پرداخت از درگاه: 1,000,000 - 300,000 = 700,000 تومان

نتیجه:
✅ کسر از DiscountBalance: 300,000 تومان
✅ پرداخت از درگاه: 700,000 تومان
✅ DiscountBalance باقیمانده: 200,000 تومان
```

---

## 🔄 مفهوم اصلی: پرداخت ترکیبی

### Flow خرید:

```
1. کاربر محصول را انتخاب می‌کند
2. سیستم چک می‌کند:
   - قیمت محصول: X تومان
   - حداکثر تخفیف مجاز: Y%
   - DiscountBalance کاربر: Z تومان
   
3. محاسبه تخفیف:
   MaxDiscountAmount = X × (Y / 100)
   ActualDiscountAmount = Min(Z, MaxDiscountAmount)
   
4. محاسبه مبلغ درگاه:
   GatewayAmount = X - ActualDiscountAmount
   
5. ریدایرکت به درگاه پرداخت (GatewayAmount)

6. بعد از بازگشت موفق از درگاه:
   - Verify payment از درگاه
   - کسر ActualDiscountAmount از DiscountBalance
   - ثبت سفارش با دو مبلغ جدا
   - ارسال اطلاعیه به کاربر
```

### مزایا:
✅ کاربر نمی‌تواند کل محصول را با تخفیف بخرد (محدودیت درصد)  
✅ کاربر می‌تواند از موجودی تخفیف خود استفاده کند  
✅ فروشنده مطمئن است مبلغی واقعی دریافت می‌کند  
✅ سیستم از سوء‌استفاده جلوگیری می‌کند  

---

## 🔄 تفاوت با Regular Shop

| ویژگی | فروشگاه عادی (Regular) | فروشگاه تخفیفی (Club Discount) |
|-------|------------------------|---------------------------|
| **نوع کیف پول** | `UserWallet.Balance` | `UserWallet.DiscountBalance` + درگاه |
| **نحوه پرداخت** | 100% از Balance یا IPG | **ترکیبی**: X% از DiscountBalance + مابقی از IPG |
| **محدودیت تخفیف** | ندارد | **دارد** (MaxDiscountPercent per product) |
| **نحوه شارژ** | خرید پکیج طلایی (56M) | کمیسیون برداشت Diamond |
| **ارتباط با باشگاه** | ✅ دارد | ✅ دارد (اعضای باشگاه) |
| **محصولات** | `Products` | `DiscountProduct` (یا flag در Products) |
| **سفارش** | `UserOrder` | `DiscountOrder` (با دو مبلغ جدا) |
| **پرداخت** | یک مرحله‌ای | **دو مرحله‌ای**: 1) Verify IPG، 2) Deduct DiscountBalance |
| **TransactionType** | `DepositIpg` | `DiscountPurchase` (hybrid) |

---

## 🏗️ معماری جداسازی

### اصل طراحی:
> **"همه چیز جدا، جز درگاه پرداخت و کیف پول"**

```
┌─────────────────────────────────────────────────────────────────┐
│                         User                                     │
│  - Id                                                            │
│  - FirstName, LastName, Mobile                                  │
│  - PackagePurchaseMethod                                        │
└────────────┬────────────────────────────────────────────────────┘
             │
             ├──────────────────────────────────────────┐
             │                                          │
             ▼                                          ▼
┌────────────────────────────┐          ┌──────────────────────────┐
│       UserWallet           │          │    Transactions (مشترک)  │
│  - Balance                 │          │  - Type                  │
│  - DiscountBalance         │          │  - RefId                 │
│  - NetworkBalance          │          │  - Amount                │
└────────────┬───────────────┘          └──────────────────────────┘
             │
             ├──────────────────────────────────────────┐
             │                                          │
             ▼                                          ▼
┌────────────────────────────┐          ┌──────────────────────────┐
│    Regular Shop            │          │    Discount Shop         │
│  - Products                │          │  - DiscountProduct       │
│  - Category                │          │  - DiscountCategory      │
│  - UserCarts               │          │  - DiscountShoppingCart  │
│  - UserOrder               │          │  - DiscountOrder         │
│  - FactorDetails           │          │  - DiscountOrderDetail   │
└────────────────────────────┘          └──────────────────────────┘
```

---

## 🗄️ Entity Design

### 1️⃣ `DiscountProduct`

```csharp
namespace CMSMicroservice.Domain.Entities.DiscountShop;

/// <summary>
/// محصول فروشگاه تخفیفی
/// </summary>
public class DiscountProduct : BaseAuditableEntity
{
    /// <summary>
    /// عنوان محصول
    /// </summary>
    public string Title { get; set; }
    
    /// <summary>
    /// توضیحات مختصر
    /// </summary>
    public string ShortInfomation { get; set; }
    
    /// <summary>
    /// توضیحات کامل
    /// </summary>
    public string FullInformation { get; set; }
    
    /// <summary>
    /// قیمت (ریال)
    /// </summary>
    public long Price { get; set; }
    
    /// <summary>
    /// درصد تخفیف
    /// </summary>
    public int DiscountPercent { get; set; }
    
    /// <summary>
    /// امتیاز (0 تا 5)
    /// </summary>
    public int Rate { get; set; }
    
    /// <summary>
    /// آدرس تصویر اصلی
    /// </summary>
    public string ImagePath { get; set; }
    
    /// <summary>
    /// آدرس تصویر کوچک
    /// </summary>
    public string ThumbnailPath { get; set; }
    
    /// <summary>
    /// تعداد فروش
    /// </summary>
    public int SaleCount { get; set; }
    
    /// <summary>
    /// تعداد بازدید
    /// </summary>
    public int ViewCount { get; set; }
    
    /// <summary>
    /// موجودی انبار
    /// </summary>
    public int RemainingCount { get; set; }
    
    /// <summary>
    /// وضعیت فعال/غیرفعال
    /// </summary>
    public bool IsActive { get; set; }
    
    // Navigation Properties
    public virtual ICollection<DiscountShoppingCart> ShoppingCarts { get; set; }
    public virtual ICollection<DiscountOrderDetail> OrderDetails { get; set; }
    public virtual ICollection<DiscountProductCategory> ProductCategories { get; set; }
}
```

---

### 2️⃣ `DiscountCategory`

```csharp
namespace CMSMicroservice.Domain.Entities.DiscountShop;

/// <summary>
/// دسته‌بندی فروشگاه تخفیفی
/// </summary>
public class DiscountCategory : BaseAuditableEntity
{
    /// <summary>
    /// نام لاتین (برای URL)
    /// </summary>
    public string Name { get; set; }
    
    /// <summary>
    /// عنوان فارسی
    /// </summary>
    public string Title { get; set; }
    
    /// <summary>
    /// توضیحات
    /// </summary>
    public string? Description { get; set; }
    
    /// <summary>
    /// آدرس تصویر
    /// </summary>
    public string? ImagePath { get; set; }
    
    /// <summary>
    /// شناسه والد (برای دسته‌بندی چند سطحی)
    /// </summary>
    public long? ParentId { get; set; }
    
    /// <summary>
    /// Parent Navigation Property
    /// </summary>
    public virtual DiscountCategory? Parent { get; set; }
    
    /// <summary>
    /// فعال/غیرفعال
    /// </summary>
    public bool IsActive { get; set; }
    
    /// <summary>
    /// ترتیب نمایش
    /// </summary>
    public int SortOrder { get; set; }
    
    // Navigation Properties
    public virtual ICollection<DiscountCategory> Children { get; set; }
    public virtual ICollection<DiscountProductCategory> ProductCategories { get; set; }
}
```

---

### 3️⃣ `DiscountProductCategory` (Many-to-Many)

```csharp
namespace CMSMicroservice.Domain.Entities.DiscountShop;

/// <summary>
/// رابطه محصول و دسته‌بندی در فروشگاه تخفیفی
/// </summary>
public class DiscountProductCategory : BaseAuditableEntity
{
    public long DiscountProductId { get; set; }
    public virtual DiscountProduct DiscountProduct { get; set; }
    
    public long DiscountCategoryId { get; set; }
    public virtual DiscountCategory DiscountCategory { get; set; }
}
```

---

### 4️⃣ `DiscountShoppingCart`

```csharp
namespace CMSMicroservice.Domain.Entities.DiscountShop;

/// <summary>
/// سبد خرید فروشگاه تخفیفی
/// </summary>
public class DiscountShoppingCart : BaseAuditableEntity
{
    /// <summary>
    /// شناسه کاربر
    /// </summary>
    public long UserId { get; set; }
    
    /// <summary>
    /// User Navigation Property
    /// </summary>
    public virtual User User { get; set; }
    
    /// <summary>
    /// شناسه محصول
    /// </summary>
    public long DiscountProductId { get; set; }
    
    /// <summary>
    /// DiscountProduct Navigation Property
    /// </summary>
    public virtual DiscountProduct DiscountProduct { get; set; }
    
    /// <summary>
    /// تعداد
    /// </summary>
    public int Count { get; set; }
    
    /// <summary>
    /// قیمت واحد در زمان افزودن به سبد
    /// </summary>
    public long UnitPrice { get; set; }
}
```

---

### 5️⃣ `DiscountOrder`

```csharp
namespace CMSMicroservice.Domain.Entities.DiscountShop;

/// <summary>
/// سفارش از فروشگاه تخفیفی
/// </summary>
public class DiscountOrder : BaseAuditableEntity
{
    /// <summary>
    /// شناسه کاربر
    /// </summary>
    public long UserId { get; set; }
    
    /// <summary>
    /// User Navigation Property
    /// </summary>
    public virtual User User { get; set; }
    
    /// <summary>
    /// مبلغ کل سفارش
    /// </summary>
    public long TotalAmount { get; set; }
    
    /// <summary>
    /// مبلغ تخفیف
    /// </summary>
    public long DiscountAmount { get; set; }
    
    /// <summary>
    /// مبلغ قابل پرداخت
    /// </summary>
    public long PayableAmount { get; set; }
    
    /// <summary>
    /// وضعیت پرداخت
    /// </summary>
    public PaymentStatus PaymentStatus { get; set; }
    
    /// <summary>
    /// تاریخ پرداخت
    /// </summary>
    public DateTime? PaymentDate { get; set; }
    
    /// <summary>
    /// شناسه تراکنش (اگر پرداخت موفق باشد)
    /// </summary>
    public long? TransactionId { get; set; }
    
    /// <summary>
    /// Transaction Navigation Property
    /// </summary>
    public virtual Transactions? Transaction { get; set; }
    
    /// <summary>
    /// شناسه آدرس کاربر
    /// </summary>
    public long UserAddressId { get; set; }
    
    /// <summary>
    /// UserAddress Navigation Property
    /// </summary>
    public virtual UserAddress UserAddress { get; set; }
    
    /// <summary>
    /// وضعیت ارسال
    /// </summary>
    public DeliveryStatus DeliveryStatus { get; set; }
    
    /// <summary>
    /// کد رهگیری مرسوله
    /// </summary>
    public string? TrackingCode { get; set; }
    
    /// <summary>
    /// توضیحات وضعیت ارسال
    /// </summary>
    public string? DeliveryDescription { get; set; }
    
    // Navigation Properties
    public virtual ICollection<DiscountOrderDetail> OrderDetails { get; set; }
}
```

---

### 6️⃣ `DiscountOrderDetail`

```csharp
namespace CMSMicroservice.Domain.Entities.DiscountShop;

/// <summary>
/// جزئیات سفارش از فروشگاه تخفیفی
/// </summary>
public class DiscountOrderDetail : BaseAuditableEntity
{
    /// <summary>
    /// شناسه سفارش
    /// </summary>
    public long DiscountOrderId { get; set; }
    
    /// <summary>
    /// DiscountOrder Navigation Property
    /// </summary>
    public virtual DiscountOrder DiscountOrder { get; set; }
    
    /// <summary>
    /// شناسه محصول
    /// </summary>
    public long DiscountProductId { get; set; }
    
    /// <summary>
    /// DiscountProduct Navigation Property
    /// </summary>
    public virtual DiscountProduct DiscountProduct { get; set; }
    
    /// <summary>
    /// تعداد
    /// </summary>
    public int Quantity { get; set; }
    
    /// <summary>
    /// قیمت واحد در زمان ثبت سفارش
    /// </summary>
    public long UnitPrice { get; set; }
    
    /// <summary>
    /// درصد تخفیف در زمان ثبت سفارش
    /// </summary>
    public int DiscountPercent { get; set; }
    
    /// <summary>
    /// مبلغ کل این آیتم (بعد از تخفیف)
    /// </summary>
    public long TotalPrice { get; set; }
}
```

---

## 📐 Business Rules

### قانون 1: خرید از Discount Shop فقط با DiscountBalance

```csharp
// در زمان Checkout از Discount Shop:
var wallet = await _context.UserWallets
    .FirstOrDefaultAsync(w => w.UserId == userId);

if (wallet.DiscountBalance < order.PayableAmount)
{
    throw new ValidationException(
        $"موجودی کیف پول تخفیفی شما کافی نیست. " +
        $"موجودی فعلی: {wallet.DiscountBalance:N0} تومان، " +
        $"مبلغ مورد نیاز: {order.PayableAmount:N0} تومان"
    );
}
```

---

### قانون 2: خرید از Regular Shop فقط با Balance

```csharp
// در زمان Checkout از Regular Shop:
var wallet = await _context.UserWallets
    .FirstOrDefaultAsync(w => w.UserId == userId);

if (wallet.Balance < order.Amount)
{
    throw new ValidationException(
        $"موجودی کیف پول اصلی شما کافی نیست. " +
        $"موجودی فعلی: {wallet.Balance:N0} تومان، " +
        $"مبلغ مورد نیاز: {order.Amount:N0} تومان"
    );
}
```

---

### قانون 3: شارژ DiscountBalance از طریق درگاه

```csharp
// در VerifyDiscountWalletChargeCommand:
wallet.DiscountBalance += amount;

var transaction = new Transactions
{
    Type = TransactionType.DiscountWalletCharge,
    Amount = amount,
    RefId = verifyResult.RefId
};
```

---

### قانون 4: محصولات Discount Shop جدا از Regular Shop

- یک محصول **نمی‌تواند** هم در `Products` باشد، هم در `DiscountProduct`
- Admin باید محصولات را جداگانه مدیریت کند
- هیچ رابطه‌ای بین `Products` و `DiscountProduct` نیست

---

## 🔄 Flow Diagram: خرید از Discount Shop

```
کاربر → مشاهده محصولات Discount Shop
  ↓
افزودن به DiscountShoppingCart
  ↓
Checkout (بررسی DiscountBalance)
  ↓
ثبت DiscountOrder (PaymentStatus: Pending)
  ↓
کم کردن DiscountBalance از کیف پول
  ↓
ثبت Transaction (Type: Buy) ← این تراکنش برای خرید است
  ↓
ثبت DiscountOrderDetail برای هر محصول
  ↓
به‌روزرسانی DiscountOrder (PaymentStatus: Success)
  ↓
خالی کردن DiscountShoppingCart
  ↓
نمایش پیام موفقیت + کد رهگیری
```

**نکته:** در این فلو از درگاه استفاده **نمی‌شود** چون موجودی از قبل شارژ شده است.

---

## 📝 تسک‌های پیاده‌سازی

### Phase 1: Entity Creation (2 روز)

1. **ایجاد namespace جدید**:
   - `CMSMicroservice.Domain/Entities/DiscountShop/`

2. **ایجاد Entity‌ها**:
   - `DiscountProduct`
   - `DiscountCategory`
   - `DiscountProductCategory`
   - `DiscountShoppingCart`
   - `DiscountOrder`
   - `DiscountOrderDetail`

3. **ایجاد Configuration‌ها**:
   - `DiscountProductConfiguration`
   - `DiscountCategoryConfiguration`
   - و غیره...

4. **به‌روزرسانی `DbContext`**:
   ```csharp
   public DbSet<DiscountProduct> DiscountProducts { get; set; }
   public DbSet<DiscountCategory> DiscountCategories { get; set; }
   // ...
   ```

5. **ایجاد Migration**:
   ```bash
   dotnet ef migrations add AddDiscountShopTables
   ```

---

### Phase 2: Commands & Queries (3 روز)

#### DiscountProduct CRUD:
- `CreateDiscountProductCommand`
- `UpdateDiscountProductCommand`
- `DeleteDiscountProductCommand`
- `GetDiscountProductByIdQuery`
- `GetDiscountProductsListQuery`

#### DiscountCategory CRUD:
- `CreateDiscountCategoryCommand`
- `UpdateDiscountCategoryCommand`
- `DeleteDiscountCategoryCommand`
- `GetDiscountCategoriesTreeQuery`

#### Shopping Cart:
- `AddToDiscountCartCommand`
- `RemoveFromDiscountCartCommand`
- `GetDiscountCartQuery`

#### Order:
- `CreateDiscountOrderCommand` (Checkout)
- `GetDiscountOrderByIdQuery`
- `GetMyDiscountOrdersQuery` (برای کاربر)
- `UpdateDiscountOrderDeliveryCommand` (برای Admin)

---

### Phase 3: BackOffice.BFF APIs (1 روز)

**Proto file**: `DiscountShopContract.proto`

```protobuf
service DiscountShopContract {
  // Product
  rpc CreateDiscountProduct(CreateDiscountProductRequest) returns (CreateDiscountProductResponse);
  rpc UpdateDiscountProduct(UpdateDiscountProductRequest) returns (UpdateDiscountProductResponse);
  rpc GetDiscountProducts(GetDiscountProductsRequest) returns (GetDiscountProductsResponse);
  
  // Category
  rpc CreateDiscountCategory(CreateDiscountCategoryRequest) returns (CreateDiscountCategoryResponse);
  rpc GetDiscountCategoriesTree(Empty) returns (GetDiscountCategoriesTreeResponse);
  
  // Orders
  rpc GetDiscountOrders(GetDiscountOrdersRequest) returns (GetDiscountOrdersResponse);
  rpc UpdateDiscountOrderDelivery(UpdateDiscountOrderDeliveryRequest) returns (UpdateDiscountOrderDeliveryResponse);
}
```

---

### Phase 4: FrontOffice.BFF APIs (1 روز)

**Proto file**: `DiscountShopContract.proto` (در FrontOffice.BFF)

```protobuf
service DiscountShopContract {
  // Browse
  rpc GetDiscountProducts(GetDiscountProductsRequest) returns (GetDiscountProductsResponse);
  rpc GetDiscountProductById(GetDiscountProductByIdRequest) returns (GetDiscountProductByIdResponse);
  
  // Cart
  rpc AddToDiscountCart(AddToDiscountCartRequest) returns (AddToDiscountCartResponse);
  rpc GetMyDiscountCart(Empty) returns (GetMyDiscountCartResponse);
  rpc RemoveFromDiscountCart(RemoveFromDiscountCartRequest) returns (RemoveFromDiscountCartResponse);
  
  // Order
  rpc CheckoutDiscountCart(CheckoutDiscountCartRequest) returns (CheckoutDiscountCartResponse);
  rpc GetMyDiscountOrders(Empty) returns (GetMyDiscountOrdersResponse);
}
```

---

### Phase 5: BackOffice UI (3 روز)

**صفحات مدیریت:**
1. **لیست محصولات تخفیفی** + CRUD
2. **دسته‌بندی‌ها** (Tree View) + CRUD
3. **سفارشات تخفیفی** + تغییر وضعیت ارسال
4. **گزارش فروش** Discount Shop

---

### Phase 6: FrontOffice UI (3 روز)

**صفحات کاربر:**
1. **لیست محصولات تخفیفی** (با فیلتر دسته‌بندی)
2. **جزئیات محصول تخفیفی**
3. **سبد خرید تخفیفی**
4. **Checkout** (با نمایش `DiscountBalance`)
5. **لیست سفارشات تخفیفی کاربر**

---

### Phase 7: Unit Tests (2 روز)

1. تست **CRUD محصولات تخفیفی**
2. تست **AddToDiscountCart**
3. تست **CheckoutDiscountCart**:
   - کاربر با موجودی کافی → موفق
   - کاربر با موجودی ناکافی → خطا

---

### Phase 8: Documentation (0.5 روز)

- به‌روزرسانی `implementation-progress.md`
- لینک از `REMAINING-TASKS-CONSOLIDATED.md`

---

## 📊 خلاصه Timeline

| Phase | عنوان | زمان |
|-------|-------|------|
| 1 | Entity Creation | 2 روز |
| 2 | Commands & Queries (CMS) | 3 روز |
| 3 | BackOffice.BFF APIs | 1 روز |
| 4 | FrontOffice.BFF APIs | 1 روز |
| 5 | BackOffice UI | 3 روز |
| 6 | FrontOffice UI | 3 روز |
| 7 | Unit Tests | 2 روز |
| 8 | Documentation | 0.5 روز |
| **جمع** | | **15.5 روز** (~3 هفته) |

---

## 🔗 مراجع

- [Package Purchase System](./package-purchase-system.md)
- [Manual Payment System](./manual-payment-system.md)
- [Implementation Progress](./implementation-progress.md)
- [REMAINING-TASKS](../REMAINING-TASKS-CONSOLIDATED.md)

---

**تاریخ آخرین به‌روزرسانی:** 2024-12-02  
**نویسنده:** GitHub Copilot  
**وضعیت:** ✅ تایید شده توسط کاربر
