# Proposition: Table `cashier_account` (Ledger/Journal)

## Concept

Créer une table `cashier_account` qui agit comme un **grand livre/journal** pour chaque caissier, enregistrant toutes les transactions qui affectent le solde du compte caissier.

## Structure Proposée

```sql
CREATE TABLE cashier_account (
    id INT AUTO_INCREMENT PRIMARY KEY,
    cashier_id INT NOT NULL,
    shift_id INT NULL,  -- NULL pour transactions hors shift, ou shift_id si lié à un shift
    transaction_type ENUM(
        'SHIFT_START',           -- Début de shift (crédit: solde initial)
        'SHIFT_END',             -- Fin de shift (débit: fermeture)
        'INVOICE_PAYMENT',       -- Paiement facture non-crédit (crédit)
        'LOAN_REPAYMENT',       -- Remboursement crédit (crédit)
        'REQUISITION_PAYMENT',  -- Paiement réquisition (débit)
        'EXPENSE',               -- Dépense (débit)
        'BANK_DEPOSIT',          -- Dépôt bancaire (débit)
        'CASH_TRANSFER',         -- Transfert vers comptable (débit)
        'ADJUSTMENT'             -- Ajustement manuel (crédit ou débit)
    ) NOT NULL,
    direction ENUM('CREDIT', 'DEBIT') NOT NULL,
    amount BIGINT(20) NOT NULL,  -- Toujours positif, direction indique si crédit ou débit
    reference_type ENUM(
        'SHIFT',
        'INVOICE',
        'LOAN_PAYMENT',
        'REQUISITION',
        'EXPENSE',
        'BANK_DEPOSIT',
        'CASH_TRANSFER',
        'MANUAL'
    ) NOT NULL,
    reference_id INT NULL,  -- ID de la transaction source (invoice_id, loan_payment_id, etc.)
    description VARCHAR(255) DEFAULT NULL,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_by INT NULL,  -- User qui a créé la transaction
    
    INDEX idx_cashier_created (cashier_id, created_at),
    INDEX idx_shift (shift_id),
    INDEX idx_reference (reference_type, reference_id),
    CONSTRAINT fk_ca_cashier FOREIGN KEY (cashier_id) REFERENCES user(id) ON DELETE CASCADE,
    CONSTRAINT fk_ca_shift FOREIGN KEY (shift_id) REFERENCES cashier_balance(id) ON DELETE SET NULL,
    CONSTRAINT fk_ca_creator FOREIGN KEY (created_by) REFERENCES user(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
```

## Règles d'Enregistrement

### Transactions CRÉDIT (augmentent le solde):
1. **SHIFT_START**: Solde initial du shift
   - `amount` = beginning_balance
   - `shift_id` = ID du shift
   - `reference_type` = 'SHIFT', `reference_id` = shift_id

2. **INVOICE_PAYMENT**: Paiement facture (NON-crédit seulement)
   - `amount` = paid_amount
   - `shift_id` = shift actif
   - `reference_type` = 'INVOICE', `reference_id` = invoice_id
   - **EXCLURE** les factures avec `is_loan_sale = 1` (pas d'impact sur le compte)

3. **LOAN_REPAYMENT**: Remboursement crédit
   - `amount` = payment_amount
   - `shift_id` = shift actif
   - `reference_type` = 'LOAN_PAYMENT', `reference_id` = loan_payment_id

### Transactions DÉBIT (diminuent le solde):
1. **REQUISITION_PAYMENT**: Paiement réquisition
   - `amount` = requisition amount
   - `shift_id` = shift actif
   - `reference_type` = 'REQUISITION', `reference_id` = requisition_id

2. **EXPENSE**: Dépense
   - `amount` = expense amount
   - `shift_id` = shift actif
   - `reference_type` = 'EXPENSE', `reference_id` = expense_id

3. **BANK_DEPOSIT**: Dépôt bancaire
   - `amount` = deposit amount
   - `shift_id` = shift déposé (via cashier_shift_deposit)
   - `reference_type` = 'BANK_DEPOSIT', `reference_id` = bank_deposit_id

4. **CASH_TRANSFER**: Transfert vers comptable
   - `amount` = transfer amount
   - `shift_id` = shift transféré (via cashier_shift_transfer)
   - `reference_type` = 'CASH_TRANSFER', `reference_id` = cash_transfer_id
   - **Enregistrer même si status='pending'** (l'argent est déjà sorti)

### Transactions NEUTRES (pas d'enregistrement):
- **Factures crédit (loan invoices)**: `is_loan_sale = 1` - PAS d'enregistrement car pas d'impact sur le compte caissier

## Calcul du Solde Disponible

### Nouveau Calcul (Simple):
```php
// Solde disponible = SUM de tous les crédits - SUM de tous les débits
$stmt = $conn->prepare("
    SELECT 
        COALESCE(SUM(CASE WHEN direction = 'CREDIT' THEN amount ELSE 0 END), 0) AS total_credits,
        COALESCE(SUM(CASE WHEN direction = 'DEBIT' THEN amount ELSE 0 END), 0) AS total_debits
    FROM cashier_account
    WHERE cashier_id = ?
");
$stmt->bind_param("i", $cashier_id);
$stmt->execute();
$result = $stmt->get_result()->fetch_assoc();
$available_balance = (float)$result['total_credits'] - (float)$result['total_debits'];
if ($available_balance < 0) {
    $available_balance = 0;
}
```

### Solde par Shift:
```php
// Solde d'un shift spécifique
$stmt = $conn->prepare("
    SELECT 
        COALESCE(SUM(CASE WHEN direction = 'CREDIT' THEN amount ELSE 0 END), 0) AS credits,
        COALESCE(SUM(CASE WHEN direction = 'DEBIT' THEN amount ELSE 0 END), 0) AS debits
    FROM cashier_account
    WHERE shift_id = ?
");
```

## Avantages

### ✅ Résout les Problèmes Actuels:
1. **Pas de double comptage**: Chaque transaction enregistrée une seule fois
2. **Transferts pending gérés**: Enregistrés au moment du transfert, pas à la réception
3. **Calcul simple**: Juste SUM des crédits - SUM des débits
4. **Audit trail complet**: Historique complet de toutes les transactions
5. **Réconciliation facile**: Peut vérifier chaque transaction individuellement

### ✅ Avantages Supplémentaires:
1. **Single Source of Truth**: Une seule table pour le solde
2. **Performance**: Pas besoin de JOINs complexes
3. **Extensibilité**: Facile d'ajouter de nouveaux types de transactions
4. **Historique**: Peut voir l'évolution du solde dans le temps
5. **Débogage**: Facile de tracer les problèmes

## Points d'Enregistrement à Modifier

### 1. Début de Shift (`balance_management.php`)
```php
// Quand un shift démarre
INSERT INTO cashier_account (cashier_id, shift_id, transaction_type, direction, amount, reference_type, reference_id, created_by)
VALUES (?, ?, 'SHIFT_START', 'CREDIT', ?, 'SHIFT', ?, ?)
```

### 2. Paiement Facture (`process_payment.php`)
```php
// Quand une facture est payée (NON-crédit seulement)
if ($payment_method !== 'loan' && !$is_loan_sale) {
    INSERT INTO cashier_account (cashier_id, shift_id, transaction_type, direction, amount, reference_type, reference_id, created_by)
    VALUES (?, ?, 'INVOICE_PAYMENT', 'CREDIT', ?, 'INVOICE', ?, ?)
}
```

### 3. Remboursement Crédit (`loan_repayments.php`)
```php
// Quand un crédit est remboursé
INSERT INTO cashier_account (cashier_id, shift_id, transaction_type, direction, amount, reference_type, reference_id, created_by)
VALUES (?, ?, 'LOAN_REPAYMENT', 'CREDIT', ?, 'LOAN_PAYMENT', ?, ?)
```

### 4. Paiement Réquisition (`pay_requisitions.php`)
```php
// Quand une réquisition est payée
INSERT INTO cashier_account (cashier_id, shift_id, transaction_type, direction, amount, reference_type, reference_id, created_by)
VALUES (?, ?, 'REQUISITION_PAYMENT', 'DEBIT', ?, 'REQUISITION', ?, ?)
```

### 5. Dépense (`expenses/create.php` ou similaire)
```php
// Quand une dépense est enregistrée
INSERT INTO cashier_account (cashier_id, shift_id, transaction_type, direction, amount, reference_type, reference_id, created_by)
VALUES (?, ?, 'EXPENSE', 'DEBIT', ?, 'EXPENSE', ?, ?)
```

### 6. Dépôt Bancaire (`deposit.php`)
```php
// Quand un shift est déposé à la banque
INSERT INTO cashier_account (cashier_id, shift_id, transaction_type, direction, amount, reference_type, reference_id, created_by)
VALUES (?, ?, 'BANK_DEPOSIT', 'DEBIT', ?, 'BANK_DEPOSIT', ?, ?)
```

### 7. Transfert Comptable (`transfer_cash.php`)
```php
// Quand un shift est transféré au comptable (même si pending)
INSERT INTO cashier_account (cashier_id, shift_id, transaction_type, direction, amount, reference_type, reference_id, created_by)
VALUES (?, ?, 'CASH_TRANSFER', 'DEBIT', ?, 'CASH_TRANSFER', ?, ?)
```

## Migration des Données Existantes

### Option 1: Migration Complète
1. Parcourir tous les shifts fermés
2. Reconstruire les transactions depuis les tables existantes
3. Insérer dans `cashier_account`

### Option 2: Migration Progressive
1. Créer la table
2. Commencer à enregistrer les nouvelles transactions
3. Migrer les anciennes données progressivement
4. Utiliser les deux systèmes en parallèle pendant la transition

## Comparaison avec l'Approche Actuelle

| Aspect | Approche Actuelle | Approche cashier_account |
|--------|-------------------|--------------------------|
| **Complexité calcul** | Complexe (multiples JOINs) | Simple (SUM) |
| **Performance** | Lente (agrégations) | Rapide (index sur cashier_id) |
| **Audit trail** | Dispersé | Centralisé |
| **Double comptage** | Risque élevé | Impossible |
| **Maintenance** | Difficile | Facile |
| **Extensibilité** | Limitée | Excellente |

## Recommandation

**OUI, cette approche résout tous les problèmes actuels et est supérieure à l'approche actuelle.**

### Plan d'Implémentation:
1. ✅ Créer la table `cashier_account`
2. ✅ Modifier tous les points d'enregistrement pour écrire dans cette table
3. ✅ Remplacer les calculs complexes par des SUM simples
4. ✅ Migrer les données historiques (optionnel mais recommandé)
5. ✅ Tester exhaustivement
6. ✅ Déployer

### Risques à Gérer:
- **Oubli d'enregistrement**: S'assurer que TOUS les points de transaction écrivent dans la table
- **Données dupliquées**: Utiliser des contraintes UNIQUE si nécessaire
- **Migration**: Tester soigneusement la migration des données existantes

