# Pricing Simulation Mode Documentation

## Overview

The portal has two pricing modes controlled by the `SIMULATE_PACKAGE_PRICING` environment variable:

1. **Simulation Mode (true):** Mock pricing for demo/testing - quotations can be created with estimated prices and invoices generated automatically
2. **Reality Mode (false):** Real-world pricing flow - quotations require Odoo pricing, invoices come from Odoo

## Configuration

**File:** `afinet-portal-backend/.env`

```env
# Enable simulated pricing for packages without fixed prices (for demo/testing)
# When true: Packages will show estimated prices for UI testing
# When false: Packages without fixed pricing will show "Request Quote" only
SIMULATE_PACKAGE_PRICING=false

# Simulated pricing ranges (used when SIMULATE_PACKAGE_PRICING=true)
SIMULATE_MONTHLY_PRICE_MIN=50
SIMULATE_MONTHLY_PRICE_MAX=500
SIMULATE_INSTALLATION_FEE_MIN=100
SIMULATE_INSTALLATION_FEE_MAX=1000
```

**Current Setting:** `false` (Reality Mode)

## How It Works

### Simulation Mode (SIMULATE_PACKAGE_PRICING=true)

**Purpose:** Demo, testing, UI development without Odoo integration

**Behavior:**

1. **Package Display:**
   - Packages without fixed pricing show estimated prices
   - Prices calculated based on package characteristics (type, category, bandwidth)
   - Marked as "Estimated Pricing (Demo)"

2. **Quotation Creation:**
   - Quotations created with simulated pricing
   - Can be accepted immediately
   - No Odoo sync required

3. **Invoice Generation:**
   - Invoices can be generated directly from quotations
   - Use simulated pricing
   - No Odoo dependency

4. **Payment Flow:**
   - Payments can be made against simulated invoices
   - Full flow works without Odoo

**Use Cases:**
- Frontend development and testing
- Demo presentations
- UI/UX testing
- Development without Odoo access

### Reality Mode (SIMULATE_PACKAGE_PRICING=false) ✓ CURRENT

**Purpose:** Production use with real Odoo integration

**Behavior:**

1. **Package Display:**
   - Packages with `pricing_model = 'fixed'`: Show real prices
   - Packages with `pricing_model = 'custom'`: Show "Request Quote"
   - Packages with `pricing_model = 'distance_based'`: Calculate based on feasibility
   - Packages with `pricing_model = 'bandwidth_based'`: Calculate based on bandwidth

2. **Quotation Creation:**
   
   **For Fixed/Calculated Pricing:**
   ```
   Customer → Portal: Request quotation
   Portal → PricingService: Calculate pricing
   Portal → Odoo: Create quotation with pricing
   Portal → Customer: Show quotation with pricing
   ```
   
   **For Custom Pricing:**
   ```
   Customer → Portal: Request quotation
   Portal: Create quotation with $0 pricing
   Portal → Odoo: Create draft quotation (no order lines)
   Portal → Customer: "Quotation submitted for review"
   
   Sales Team → Odoo: Add products and pricing
   Odoo → Portal: Webhook 'quotation.updated'
   Portal: Update quotation with real pricing
   Portal → Customer: Email notification "Quotation ready"
   
   Customer → Portal: Review and accept quotation
   Portal → Odoo: Confirm quotation
   Odoo: Convert to sales order
   Odoo → Portal: Webhook 'sale.order.confirmed'
   Portal: Create sales order, update quotation pricing
   ```

3. **Invoice Generation:**
   ```
   Odoo: Generate invoice from sales order
   Odoo → Portal: Webhook 'invoice.created'
   Portal: Create invoice with real pricing
   Portal → Customer: Show invoice
   ```

4. **Payment Flow:**
   ```
   Customer → Portal: Pay invoice
   Portal → Payment Gateway: Process payment
   Payment Gateway → Portal: Payment confirmation
   Portal → Odoo: Record payment on invoice
   Odoo: Mark invoice as paid
   Odoo → Portal: Webhook 'invoice.paid'
   Portal: Update invoice status
   ```

## Pricing Models

### 1. Fixed Pricing
- **Simulation:** Uses package's fixed prices
- **Reality:** Uses package's fixed prices
- **Example:** Satellite packages with set monthly fees

### 2. Distance-Based Pricing
- **Simulation:** Uses base price + simulated extension costs
- **Reality:** Uses base price + actual extension costs from feasibility check
- **Example:** Fibre packages requiring extension

### 3. Bandwidth-Based Pricing
- **Simulation:** Calculates based on bandwidth with simulated per-Mbps rates
- **Reality:** Calculates based on bandwidth with real per-Mbps rates
- **Example:** Business packages with variable bandwidth

### 4. Custom Pricing
- **Simulation:** Generates estimated prices based on package type
- **Reality:** Requires manual pricing by sales team in Odoo
- **Example:** Enterprise packages, complex installations

## Code Implementation

### PricingSimulationService

**File:** `afinet-portal-backend/app/Services/PricingSimulationService.php`

```php
public static function isEnabled(): bool
{
    return config('services.pricing_simulation.enabled', false);
}

public static function applySimulatedPricing(ProductPackage $package): array
{
    // Only simulate if enabled and package doesn't have fixed pricing
    if (!self::isEnabled() || $package->has_fixed_pricing) {
        return $packageData;
    }
    
    // Generate simulated prices
    $simulatedPrices = self::generateSimulatedPrices($package);
    
    $packageData['is_simulated_pricing'] = true;
    $packageData['monthly_price'] = $simulatedPrices['monthly_price'];
    $packageData['installation_fee'] = $simulatedPrices['installation_fee'];
    $packageData['pricing_note'] = 'Estimated pricing for demonstration.';
    
    return $packageData;
}
```

### PricingService

**File:** `afinet-portal-backend/app/Services/PricingService.php`

```php
public function calculateServicePricing(ProductPackage $package, ...)
{
    switch ($package->pricing_model) {
        case 'custom':
            return [
                'requires_custom_quote' => true,
                'monthly_price' => 0,
                'total_amount' => 0,
                // ... all $0 in reality mode
            ];
        
        case 'fixed':
        case 'distance_based':
        case 'bandwidth_based':
            // Calculate real pricing
            return $this->calculateRealPricing(...);
    }
}
```

### QuotationController

**File:** `afinet-portal-backend/app/Http/Controllers/API/QuotationController.php`

```php
public function requestQuotation(Request $request)
{
    $pricing = $pricingService->calculateServicePricing($package, ...);
    
    if ($pricing['requires_custom_quote']) {
        // Reality mode: Create with $0, wait for Odoo pricing
        $quotation = Quotation::create([
            'status' => 'pending_review',
            'monthly_price' => 0,
            'total_amount' => 0,
            // ...
        ]);
        
        // Send to Odoo for manual pricing
        $odooService->createQuotation($quotationData);
        
        return 'Quotation submitted for review';
    } else {
        // Fixed/calculated pricing: Create with real prices
        $quotation = Quotation::create([
            'status' => 'pending',
            'monthly_price' => $pricing['monthly_price'],
            'total_amount' => $pricing['total_amount'],
            // ...
        ]);
        
        return 'Quotation created successfully';
    }
}
```

## Frontend Integration

The frontend receives `simulation_enabled` flag in API responses:

```json
{
  "success": true,
  "data": [...],
  "simulation_enabled": false
}
```

**Frontend Behavior:**

- **Simulation Mode:** Show "Demo Pricing" badges, allow quick checkout
- **Reality Mode:** Show "Request Quote" for custom pricing, enforce Odoo flow

## Testing

### Test Simulation Mode

1. Set `SIMULATE_PACKAGE_PRICING=true` in `.env`
2. Clear config cache: `php artisan config:clear`
3. Request quotation for custom pricing package
4. Verify quotation created with estimated prices
5. Verify can accept and generate invoice immediately

### Test Reality Mode

1. Set `SIMULATE_PACKAGE_PRICING=false` in `.env`
2. Clear config cache: `php artisan config:clear`
3. Request quotation for custom pricing package
4. Verify quotation created with $0 pricing
5. Verify status is "pending_review"
6. Price quotation in Odoo
7. Verify portal syncs pricing
8. Verify customer receives notification
9. Accept quotation
10. Verify sales order created
11. Verify invoice synced from Odoo

## Production Checklist

✓ `SIMULATE_PACKAGE_PRICING=false` in production `.env`
✓ Odoo webhooks configured and tested
✓ Email notifications working
✓ Payment gateway configured
✓ All pricing models tested with real Odoo data

## Troubleshooting

### Issue: Packages showing $0 in production

**Cause:** Simulation mode disabled, packages have `pricing_model = 'custom'`

**Solution:** This is correct behavior. Packages require quotation request and Odoo pricing.

### Issue: Quotations not getting priced

**Cause:** Odoo webhooks not configured or not firing

**Solution:** 
1. Check Odoo webhook configuration
2. Check webhook logs in Laravel
3. Manually sync: `php artisan sync:data quotations`

### Issue: Customers not receiving pricing notifications

**Cause:** Email configuration or notification not sent

**Solution:**
1. Check email configuration: `php artisan email:test`
2. Check logs for notification errors
3. Verify `QuotationStatusChanged` email template exists

## Summary

**Simulation Mode (true):**
- For: Demo, testing, development
- Pricing: Estimated/mock
- Odoo: Optional
- Flow: Fast, automated

**Reality Mode (false):** ✓ CURRENT
- For: Production
- Pricing: Real from Odoo
- Odoo: Required
- Flow: Quotation → Odoo pricing → Sales order → Invoice

The system is currently in **Reality Mode**, which means all pricing for custom packages comes from Odoo, and the complete quotation → sales order → invoice flow is enforced.
