# Coupon System Documentation

## Overview
The coupon system supports multiple types of coupons with flexible application rules:
- **General Coupons**: Apply to all products in the cart
- **Vendor-Specific Coupons**: Apply only when all cart items are from a specific vendor
- **Category-Specific Coupons**: Apply only when all cart items are from a specific category
- **Brand-Specific Coupons**: Apply only when all cart items are from a specific brand
- **First Order Coupons**: Apply only for users who haven't completed any orders yet

## Database Schema

### Migration Fields Added
```php
- apply_on: enum (general, vendor, category, brand, first_order)
- applicable_id: polymorphic ID (nullable)
- applicable_type: polymorphic type (nullable)
- is_first_order: boolean (default: false)
```

### Polymorphic Relationship
The coupon uses a polymorphic relationship (`applicable`) that can reference:
- **User** model (for vendor-specific coupons)
- **Category** model (for category-specific coupons)
- **Brand** model (for brand-specific coupons)

This provides a cleaner, more flexible structure compared to separate foreign keys.

## Coupon Types (CouponApplyOn Enum)

### 1. GENERAL
- Applies to all products in the cart
- No restrictions on vendor, category, or brand
- `apply_on = 'general'`

### 2. VENDOR
- Applies only when **ALL** cart items are from the specified vendor
- Uses polymorphic relationship: `applicable_id` = vendor user ID, `applicable_type` = User::class
- `apply_on = 'vendor'`
- Error message if cart contains items from other vendors

### 3. CATEGORY
- Applies only when **ALL** cart items belong to the specified category
- Uses polymorphic relationship: `applicable_id` = category ID, `applicable_type` = Category::class
- `apply_on = 'category'`
- Error message if cart contains items from other categories

### 4. BRAND
- Applies only when **ALL** cart items belong to the specified brand
- Uses polymorphic relationship: `applicable_id` = brand ID, `applicable_type` = Brand::class
- `apply_on = 'brand'`
- Error message if cart contains items from other brands

### 5. FIRST_ORDER
- Applies only for users who haven't completed any orders
- `apply_on = 'first_order'`
- `is_first_order = true`
- Checks if user has any non-cancelled orders

## API Endpoints

### Admin Endpoints

#### Create/Update Coupon
```
POST/PUT /api/dashboard/admin/coupons
```

**Request Body:**
```json
{
  "apply_on": "vendor|category|brand|general|first_order",
  "client_type": "normal|premium",
  "code": "SUMMER2024",
  "type": "percentage|fixed",
  "value": 20,
  "min_order_total": 100,
  "max_order_total": 1000,
  "start_at": "2024-01-01",
  "end_at": "2024-12-31",
  "limit": 100,
  "limit_for_user": 5,
  "is_active": true,
  "is_first_order": false,
  
  // Polymorphic field (required based on apply_on)
  "applicable_id": 1,  // ID of vendor/category/brand based on apply_on
  
  // Translations
  "en": {
    "name": "Summer Sale",
    "description": "Get 20% off on all items"
  },
  "ar": {
    "name": "تخفيضات الصيف",
    "description": "احصل على خصم 20٪ على جميع المنتجات"
  }
}
```

**Note:** The `applicable_type` is automatically set based on `apply_on`:
- `apply_on = 'vendor'` → `applicable_type = 'App\Models\User'`
- `apply_on = 'category'` → `applicable_type = 'App\Models\Category'`
- `apply_on = 'brand'` → `applicable_type = 'App\Models\Brand'`

#### List Coupons
```
GET /api/dashboard/admin/coupons
```

**Response:**
```json
{
  "status": "success",
  "data": {
    "coupons": [
      {
        "id": 1,
        "client_type": "normal",
        "apply_on": "vendor",
        "code": "VENDOR20",
        "name": "Vendor Discount",
        "value": 20,
        "type": "percentage",
        "is_first_order": false,
        "applicable_id": 1,
        "applicable_type": "App\\Models\\User",
        "applicable_name": "Store Name"
      }
    ]
  }
}
```

### App Endpoints

#### List Available Coupons
```
GET /api/app/coupons
```

**Response:**
```json
{
  "status": "success",
  "data": [
    {
      "id": 1,
      "client_type": "normal",
      "apply_on": "general",
      "code": "WELCOME10",
      "name": "Welcome Discount",
      "description": "Get 10% off on your first order",
      "type": "percentage",
      "value": 10,
      "is_first_order": true,
      "applicable_id": null,
      "applicable_type": null,
      "applicable_name": null
    }
  ]
}
```

#### Apply Coupon (via Cart Calculate)
```
POST /api/app/cart/calculate
```

**Request Body:**
```json
{
  "location_id": 1,
  "coupon_code": "VENDOR20"
}
```

**Success Response:**
```json
{
  "status": "success",
  "data": {
    "items": [...],
    "sub_total": 500.00,
    "discount": 100.00,
    "shipping_cost": 20.00,
    "vat": 42.00,
    "total": 462.00,
    "coupon_message": "Coupon applied successfully",
    "coupon_status": 200
  }
}
```

**Error Response (Wrong Vendor):**
```json
{
  "status": "success",
  "data": {
    "items": [...],
    "sub_total": 500.00,
    "discount": 0.00,
    "shipping_cost": 20.00,
    "vat": 52.00,
    "total": 572.00,
    "coupon_message": "This coupon requires all cart items to be from Store Name",
    "coupon_status": 400
  }
}
```

## Validation Rules

### Coupon Model Validation

#### isValid(User $user)
Checks:
1. Coupon is active
2. Current date is within start_at and end_at
3. User's client type matches coupon's client_type
4. Total usage limit not exceeded
5. Per-user usage limit not exceeded
6. If is_first_order, user has no completed orders

#### isApplicableToCart($cartItems)
Checks:
1. **General/First Order**: Always applicable
2. **Vendor**: All cart items must be from the specified vendor
3. **Category**: All cart items must be from the specified category
4. **Brand**: All cart items must be from the specified brand

Returns: `[bool $isApplicable, ?string $errorMessage]`

## Usage Flow

### 1. Admin Creates Coupon
```php
// Example: Vendor-specific coupon
POST /api/dashboard/admin/coupons
{
  "apply_on": "vendor",
  "vendor_id": 5,
  "code": "VENDOR20",
  "type": "percentage",
  "value": 20,
  ...
}
```

### 2. User Adds Items to Cart
```php
// User adds items from vendor_id = 5
POST /api/app/cart/add
{
  "product_id": 10,
  "quantity": 2
}
```

### 3. User Applies Coupon
```php
// Calculate cart with coupon
POST /api/app/cart/calculate
{
  "coupon_code": "VENDOR20"
}

// CouponService validates:
// 1. Coupon exists and is valid
// 2. All cart items are from vendor_id = 5
// 3. User meets all requirements
```

### 4. User Creates Order
```php
POST /api/app/orders
{
  "location_id": 1,
  "payment_method": "cash",
  "coupon_code": "VENDOR20"
}

// OrderService:
// 1. Re-validates coupon
// 2. Applies discount
// 3. Marks coupon as used
```

## Error Messages

### Coupon Not Found
```
"Invalid Coupon code"
```

### Coupon Expired/Invalid
```
"Coupon is not valid or expired"
```

### Vendor Mismatch
```
"This coupon requires all cart items to be from {vendor_name}"
```

### Category Mismatch
```
"This coupon requires all cart items to be from {category_name} category"
```

### Brand Mismatch
```
"This coupon requires all cart items to be from {brand_name} brand"
```

### First Order Only
```
"Coupon is not valid or expired" (when user has completed orders)
```

### Minimum Order Not Met
```
"The minimum order total for this coupon is {min}"
```

## Code Examples

### Creating Different Coupon Types

#### General Coupon
```php
Coupon::create([
    'apply_on' => CouponApplyOn::GENERAL,
    'code' => 'SAVE10',
    'type' => CouponType::PERCENTAGE,
    'value' => 10,
    'client_type' => ClientType::NORMAL,
    // ... other fields
]);
```

#### Vendor-Specific Coupon
```php
Coupon::create([
    'apply_on' => CouponApplyOn::VENDOR,
    'applicable_id' => 5,
    'applicable_type' => User::class,
    'code' => 'VENDOR20',
    'type' => CouponType::PERCENTAGE,
    'value' => 20,
    // ... other fields
]);
```

#### First Order Coupon
```php
Coupon::create([
    'apply_on' => CouponApplyOn::FIRST_ORDER,
    'is_first_order' => true,
    'code' => 'WELCOME15',
    'type' => CouponType::PERCENTAGE,
    'value' => 15,
    // ... other fields
]);
```

## Testing Scenarios

### Test Case 1: General Coupon
- Create general coupon
- Add items from different vendors
- Apply coupon → Should succeed

### Test Case 2: Vendor-Specific Coupon
- Create vendor coupon for vendor_id = 5
- Add items only from vendor_id = 5
- Apply coupon → Should succeed
- Add item from vendor_id = 6
- Apply coupon → Should fail with vendor mismatch error

### Test Case 3: First Order Coupon
- Create first order coupon
- New user applies coupon → Should succeed
- User completes order
- Same user tries to use coupon again → Should fail

### Test Case 4: Category-Specific Coupon
- Create category coupon for category_id = 3
- Add items only from category_id = 3
- Apply coupon → Should succeed
- Add item from category_id = 4
- Apply coupon → Should fail with category mismatch error

## Notes

1. **All Items Must Match**: For vendor/category/brand coupons, ALL items in the cart must match the specified criteria. Mixed carts will be rejected.

2. **First Order Check**: The system checks for any non-cancelled orders. If a user has completed at least one order, first_order coupons won't apply.

3. **Coupon Usage Tracking**: Each coupon usage is tracked in the `coupon_users` table with the user_id and order_group_id.

4. **Guest Users**: Guest users cannot apply coupons. Only authenticated users can use coupons.

5. **Subscription Benefits**: Premium users (with active subscriptions) get free shipping and can access premium-only coupons.
