# VAT Implementation Documentation

## Overview

This document describes the VAT (Value Added Tax) implementation for the Sellzaki POS system, covering sales, returns, and exchanges with support for promotional invoices.

## Table of Contents

1. [VAT Fundamentals](#vat-fundamentals)
2. [VAT Calculation Modes](#vat-calculation-modes)
3. [Sales VAT Handling](#sales-vat-handling)
4. [Returns VAT Handling](#returns-vat-handling)
5. [Exchanges VAT Handling](#exchanges-vat-handling)
6. [Promotional Invoices](#promotional-invoices)
7. [Admin VAT Settings](#admin-vat-settings)
8. [Database Schema](#database-schema)
9. [API Endpoints](#api-endpoints)
10. [Examples](#examples)

## VAT Fundamentals

### VAT Rate

- Single active VAT rate (e.g., 15%)
- Configurable via Admin → Settings → VAT & Pricing Settings
- Rate changes are **prospective** (affect new transactions only)
- Historical invoices maintain their stored VAT rates

### Prices Mode

Two pricing modes are supported:

1. **Prices Include VAT** (`prices_include_vat = true`)
   - Displayed prices already include VAT
   - Tax amount is derived from the inclusive price
   - Example: Price shown = 100 EGP (includes 15% VAT)

2. **Prices Exclude VAT** (`prices_include_vat = false`)
   - Displayed prices exclude VAT
   - VAT is added at checkout
   - Example: Price shown = 100 EGP + 15 EGP VAT = 115 EGP total

## VAT Calculation Modes

### Inclusive Mode Formulas

When `prices_include_vat = true`:

```
tax_base = unit_price / (1 + vat_rate/100)
tax_amount = unit_price - tax_base
gross = unit_price (already includes tax)
```

**Example:**
- Unit Price: 100 EGP (includes VAT)
- VAT Rate: 15%
- Tax Base: 100 / 1.15 = 86.96 EGP
- Tax Amount: 100 - 86.96 = 13.04 EGP
- Gross: 100 EGP

### Exclusive Mode Formulas

When `prices_include_vat = false`:

```
tax_base = unit_price (after discounts)
tax_amount = tax_base × (vat_rate/100)
gross = tax_base + tax_amount
```

**Example:**
- Unit Price: 100 EGP (excludes VAT)
- VAT Rate: 15%
- Tax Base: 100 EGP
- Tax Amount: 100 × 0.15 = 15 EGP
- Gross: 100 + 15 = 115 EGP

### Rounding

All amounts are rounded to 2 decimal places using standard rounding.

## Sales VAT Handling

### Process Flow

1. **Get Active VAT Settings**
   - System fetches current VAT settings (cached)
   - If no settings exist, default settings are initialized (15% VAT, exclusive mode)

2. **Calculate Line Totals**
   - For each item in the sale:
     - Apply discounts (if any)
     - Calculate tax based on pricing mode (inclusive/exclusive)
     - Store: `unit_price`, `tax_base`, `tax_amount`, `line_total_gross`

3. **Calculate Invoice Totals**
   - Sum all line totals
   - Store: `subtotal_net`, `tax_total`, `grand_total`

4. **Store VAT Context**
   - Invoice Header: `vat_rate_at_sale`, `prices_include_vat_at_sale`, `subtotal_net`, `tax_total`, `grand_total`
   - Invoice Detail: `unit_price`, `tax_base`, `tax_amount`, `line_total_gross`

### Example: Sale with Discount

**Scenario:**
- Item: 100 EGP, Quantity: 2, Discount: 10 EGP per unit
- VAT Rate: 15%, Prices Exclude VAT

**Calculation:**
- Price after discount: 100 - 10 = 90 EGP per unit
- Tax base: 90 × 2 = 180 EGP
- Tax amount: 180 × 0.15 = 27 EGP
- Gross total: 180 + 27 = 207 EGP

**Stored Values:**
- `subtotal_net`: 180.00
- `tax_total`: 27.00
- `grand_total`: 207.00
- `vat_rate_at_sale`: 15.00
- `prices_include_vat_at_sale`: false

## Returns VAT Handling

### Key Principle

**Returns use stored VAT amounts from the original invoice. VAT is NOT recalculated with current settings.**

### Process Flow

1. **Retrieve Original Invoice**
   - Fetch invoice with stored VAT context
   - Get invoice details with stored tax amounts

2. **Calculate Proportional Refund**
   - For partial returns: Calculate proportion of returned quantity
   - Refund = stored amounts × proportion
   - Example: Return 1 of 2 items → refund = 50% of stored amounts

3. **Store Return VAT Context**
   - Return invoice inherits VAT context from original invoice
   - Return details store proportional VAT amounts

### Example: Partial Return

**Original Invoice:**
- Item: 100 EGP × 2 units
- Tax Base: 200 EGP, Tax: 30 EGP, Gross: 230 EGP
- VAT Rate: 15%

**Return:**
- Return 1 unit (50% of original)

**Refund Calculation:**
- Tax Base Refund: 200 × 0.5 = 100 EGP
- Tax Refund: 30 × 0.5 = 15 EGP
- Gross Refund: 230 × 0.5 = 115 EGP

**Note:** Even if current VAT rate is 17%, the refund uses the stored 15% rate and amounts.

## Exchanges VAT Handling

### Key Principles

1. **Returned Items:** Use stored VAT from original invoice (same as returns)
2. **New Items:** Use current VAT settings (or historical if `use_historical_vat_for_exchanges` is enabled)

### Process Flow

1. **Return Side**
   - Use stored VAT amounts from original invoice (proportional if partial)
   - Same logic as returns

2. **New Items Side**
   - Check `use_historical_vat_for_exchanges` setting:
     - **If false (default):** Use current VAT settings
     - **If true:** Use `vat_rate_at_sale` from original invoice
   - Calculate VAT for new items using selected rate
   - Store VAT context in exchange invoice

3. **Net Difference**
   - Settlement = New Items Gross - Return Gross
   - Positive = Customer pays difference
   - Negative = Store refunds difference

### Example: Exchange with Historical VAT

**Original Invoice (15% VAT):**
- Item A: 100 EGP × 2 units
- Tax: 30 EGP, Gross: 230 EGP

**Current VAT Settings:**
- VAT Rate: 17%
- `use_historical_vat_for_exchanges`: true

**Exchange:**
- Return: Item A (2 units) → Refund: 230 EGP (using stored 15% VAT)
- New: Item B (2 units × 100 EGP) → Charge: 230 EGP (using historical 15% VAT)
- Net Difference: 0 EGP

**If `use_historical_vat_for_exchanges` was false:**
- New items would use 17% VAT → Charge: 234 EGP
- Net Difference: 4 EGP (customer pays)

## Promotional Invoices

### Full Return Rule

**Rule:** If an invoice has any applied promotion, it must be fully returned. Partial returns are not allowed.

**Implementation:**
- Frontend: Auto-selects all items with full quantities, disables quantity controls
- Backend: Validates full return before processing
- Error Message: "This invoice includes a promotion and must be fully returned."

### Exchange Rule

**Rule:** When exchanging a promotional invoice, the original promotion is reapplied to new items, even if:
- The promotion is expired
- The promotion is inactive
- Newer promotions exist

**Implementation:**
- System retrieves original promotion IDs from `applied_promotions` field
- Promotion engine reapplies original promotions to exchange basket
- Current active promotions are ignored

### VAT with Promotions

- Promotions affect the tax base (discounts reduce taxable amount)
- VAT is calculated on the discounted amount
- All VAT context is stored as described above

## Admin VAT Settings

### Access

- **Location:** Admin → Settings → VAT & Pricing Settings
- **Permission:** `Settings.Admin` role required

### Settings Fields

1. **VAT Rate (%)**
   - Range: 0-100
   - Default: 15.00
   - Decimal precision: 2

2. **Prices Include VAT**
   - Toggle: Yes/No
   - Default: No (prices exclude VAT)

3. **Use Historical VAT for Exchanges**
   - Toggle: Yes/No
   - Default: No
   - **Tooltip:** "When enabled, exchanges reuse the VAT rate from the original invoice rather than current VAT settings."

4. **VAT Labels (Localization)**
   - English: Default "VAT"
   - Arabic: Default "الضريبة"
   - Customizable per language

### Behavior

- **Immediate Effect:** Changes affect all new transactions immediately
- **Historical Preservation:** Existing invoices remain unchanged
- **Audit Logging:** All changes are logged with:
  - Who changed it
  - When it was changed
  - Old → New values
  - Reason (optional)

### Cache Strategy

- Active settings are cached with key: `vat_settings:active`
- Cache TTL: 1 hour
- Cache is invalidated immediately after update
- Frontend polls every 30 seconds for updates

## Database Schema

### `vat_settings` Table

```sql
CREATE TABLE vat_settings (
    id BIGINT PRIMARY KEY,
    vat_rate DECIMAL(5,2) DEFAULT 15.00,
    prices_include_vat BOOLEAN DEFAULT false,
    use_historical_vat_for_exchanges BOOLEAN DEFAULT false,
    vat_labels JSON,
    effective_from TIMESTAMP,
    effective_to TIMESTAMP NULL,
    is_active BOOLEAN DEFAULT true,
    created_by BIGINT,
    created_at TIMESTAMP,
    updated_at TIMESTAMP
);
```

### `vat_settings_audit_log` Table

```sql
CREATE TABLE vat_settings_audit_log (
    id BIGINT PRIMARY KEY,
    vat_setting_id BIGINT,
    changed_by BIGINT,
    old_vat_rate DECIMAL(5,2) NULL,
    new_vat_rate DECIMAL(5,2),
    old_prices_include_vat BOOLEAN NULL,
    new_prices_include_vat BOOLEAN,
    old_use_historical_vat_for_exchanges BOOLEAN NULL,
    new_use_historical_vat_for_exchanges BOOLEAN,
    reason TEXT NULL,
    created_at TIMESTAMP
);
```

### `invoice_header` Table (VAT Fields)

```sql
ALTER TABLE invoice_header ADD COLUMN vat_rate_at_sale DECIMAL(5,2);
ALTER TABLE invoice_header ADD COLUMN prices_include_vat_at_sale BOOLEAN DEFAULT false;
ALTER TABLE invoice_header ADD COLUMN subtotal_net DECIMAL(19,2);
ALTER TABLE invoice_header ADD COLUMN tax_total DECIMAL(19,2);
ALTER TABLE invoice_header ADD COLUMN grand_total DECIMAL(19,2);
```

### `invoice_detail` Table (VAT Fields)

```sql
ALTER TABLE invoice_detail ADD COLUMN tax_base DECIMAL(19,2);
ALTER TABLE invoice_detail ADD COLUMN tax_amount DECIMAL(19,2);
ALTER TABLE invoice_detail ADD COLUMN line_total_gross DECIMAL(19,2);
ALTER TABLE invoice_detail ADD COLUMN unit_price DECIMAL(19,2);
```

## API Endpoints

### Admin VAT Settings

- `GET /api/admin/vat-settings` - Get current active settings
- `PUT /api/admin/vat-settings` - Update settings (requires `Settings.Admin` permission)
- `GET /api/admin/vat-settings/audit-log` - Get audit log entries
- `GET /api/admin/vat-settings/history` - Get settings history

### Sales, Returns, Exchanges

- Existing endpoints automatically use VAT settings
- No API changes required for end users

## Examples

### Example 1: Sale with Inclusive Pricing

**Settings:**
- VAT Rate: 15%
- Prices Include VAT: Yes

**Sale:**
- Item: 115 EGP (includes VAT), Quantity: 1

**Calculation:**
- Tax Base: 115 / 1.15 = 100 EGP
- Tax Amount: 115 - 100 = 15 EGP
- Gross: 115 EGP

**Stored:**
- `subtotal_net`: 100.00
- `tax_total`: 15.00
- `grand_total`: 115.00

### Example 2: Return with VAT Rate Change

**Original Sale (15% VAT):**
- Item: 100 EGP × 2 units
- Tax: 30 EGP, Gross: 230 EGP

**Current VAT Rate:** 17%

**Full Return:**
- Refund: 230 EGP (uses stored 15% VAT, NOT current 17%)
- If recalculated with 17%: 234 EGP (WRONG - don't do this!)

### Example 3: Exchange with Historical VAT

**Original Invoice:**
- VAT Rate: 15%
- Item A: 230 EGP (includes tax)

**Current Settings:**
- VAT Rate: 17%
- Use Historical VAT for Exchanges: Yes

**Exchange:**
- Return: Item A → 230 EGP refund (stored 15% VAT)
- New: Item B (100 EGP × 2) → 230 EGP charge (historical 15% VAT)
- Net: 0 EGP

**If Historical VAT was disabled:**
- New: Item B → 234 EGP charge (current 17% VAT)
- Net: 4 EGP (customer pays)

### Example 4: Promotional Invoice Return

**Original Invoice:**
- Promotion: "Buy 2 Get 10% Off"
- Items: 2 × 100 EGP = 200 EGP
- Discount: 20 EGP (10%)
- Tax Base: 180 EGP
- Tax: 27 EGP (15%)
- Gross: 207 EGP

**Attempt Partial Return (1 item):**
- ❌ **Rejected:** "This invoice includes a promotion and must be fully returned."

**Full Return (2 items):**
- ✅ **Accepted:** Refund = 207 EGP (full stored gross amount)

## Testing

### Unit Tests

- `VatCalculationServiceTest`: Tests inclusive/exclusive calculations, rounding
- `VatSettingsServiceTest`: Tests caching, updates, audit logging, localization

### Integration Tests

- `VatIntegrationTest`: Tests sales, returns, exchanges with VAT
- `VatSettingsAdminTest`: Tests admin settings management

### Feature Tests

- `PromotionalInvoiceRulesTest`: Updated to verify VAT context storage

## Best Practices

1. **Always store VAT context** when creating invoices
2. **Never recalculate VAT** for returns - use stored amounts
3. **Respect historical VAT** for exchanges when setting is enabled
4. **Validate full returns** for promotional invoices
5. **Audit all VAT changes** for compliance
6. **Cache VAT settings** for performance
7. **Display VAT info** clearly in UI

## Troubleshooting

### Issue: VAT amounts don't match

**Solution:** Verify that stored VAT context is being used for returns, not current settings.

### Issue: Exchange VAT seems wrong

**Solution:** Check `use_historical_vat_for_exchanges` setting and verify which VAT rate is being used.

### Issue: Promotional invoice allows partial return

**Solution:** Verify that `hasPromotions` flag is correctly set and frontend validation is working.

### Issue: VAT settings not updating

**Solution:** Clear cache and verify cache invalidation is working after settings update.

## Support

For questions or issues related to VAT implementation, please refer to:
- Backend: `app/Services/VatCalculationService.php`, `app/Services/VatSettingsService.php`
- Frontend: `resources/js/stores/vatSettingsStore.ts`, `resources/js/utils/vatCalculations.ts`
- Admin UI: `resources/js/components/Pages/Admin/VatSettings.tsx`








