# Taux de change BCE - Guide développeur

## Objectif
Ce module importe les taux FX de la BCE dans `exchange_rates` afin que l'application puisse utiliser un historique local et exploitable en base.

## Modèle de données
Table : `exchange_rates`

- `id` (UUID, clé primaire)
- `cur1` (devise de base, 3 caractères)
- `cur2` (devise de cotation, 3 caractères)
- `rate` (decimal 20,10)
- `rate_date` (date)
- `source` (valeur par défaut `ECB`)
- timestamps

Clé unique :

- (`cur1`, `cur2`, `rate_date`, `source`)

## Composants principaux

- Migration : `database/migrations/2026_03_24_120000_create_exchange_rates_table.php`
- Modèle : `app/Models/ExchangeRate.php`
- Service : `app/Services/EcbExchangeRateService.php`
- Commande : `app/Console/Commands/SyncEcbExchangeRates.php`

## Stratégie API BCE
Le service utilise l'endpoint historique BCE :

- `https://data-api.ecb.europa.eu/service/data/EXR/D..EUR.SP00.A`

Paramètres de requête utilisés :

- `startPeriod=YYYY-MM-DD`
- `endPeriod=YYYY-MM-DD`
- `format=csvdata`

Comportement :

- Fenêtre par défaut : 7 derniers jours
- Sans `--start` : `--years=X` signifie **X ans en arrière depuis aujourd'hui**
- Avec `--start` : `--years=X` signifie **X ans à partir de `--start`**, plafonné à aujourd'hui (sauf si `--end` est défini)
- Avec `--start` et `--end` : plage explicite `[début, fin]` (`--years` est ignoré)
- Les longues plages sont découpées en **plusieurs appels HTTP BCE** (`--chunk-years`, défaut **1 an par requête**) pour éviter les timeouts et les CSV trop volumineux
- Devise de base : EUR (`cur1 = EUR`)
- Ajout de lignes synthétiques `EUR/EUR = 1` pour chaque date importée
- Échec si **aucune ligne** n'est trouvée sur la période sélectionnée (évite les synchronisations vides "réussies")

## Logs

- Logs job : `storage/logs/job_logs.log`
  - Début : `lnc:sync-ecb-exchange-rates started`
  - Fin : `lnc:sync-ecb-exchange-rates finished`
  - Erreur : `lnc:sync-ecb-exchange-rates failed`

## Configuration TLS / vérification HTTPS

Le service utilise les options du client HTTP Laravel pilotées par la config :

- `services.ecb.verify` (défaut `true`)
- `services.ecb.ca_bundle` (chemin vers un bundle CA ; si renseigné, il remplace `verify`)

## Utilisation de la commande

- Par défaut (7 jours) :
  - `php artisan lnc:sync-ecb-exchange-rates`
- Historique depuis aujourd'hui (exemple 10 ans en arrière) :
  - `php artisan lnc:sync-ecb-exchange-rates --years=10`
- **X années à partir d'une date fixe** (recommandé pour des backfills 20–30 ans) :
  - `php artisan lnc:sync-ecb-exchange-rates --start=2000-01-01 --years=30`
- Plage de dates explicite :
  - `php artisan lnc:sync-ecb-exchange-rates --start=2015-01-01 --end=2020-12-31`
- Blocs plus larges par requête (moins d'appels HTTP ; peut timeout si réseau lent) :
  - `php artisan lnc:sync-ecb-exchange-rates --start=2000-01-01 --years=30 --chunk-years=2`

Validation :

- `--years` doit être `>= 1` lorsqu'il est fourni
- `--chunk-years` doit être `>= 1`

## Planification via cron système (pas via scheduler Laravel)
Utiliser le cron de l'OS pour lancer la commande, par exemple en semaine à 16h30 :

```bash
30 16 * * 1-5 cd /path/to/tikeasy && php artisan lnc:sync-ecb-exchange-rates >> storage/logs/cron.log 2>&1
```

Si vous avez besoin d'un fuseau explicite :

```bash
CRON_TZ=Europe/Paris
30 16 * * 1-5 cd /path/to/tikeasy && php artisan lnc:sync-ecb-exchange-rates >> storage/logs/cron.log 2>&1
```

## Gestion des conflits
Pour éviter les cas limites de conflit PostgreSQL, l'écriture est faite avec `updateOrInsert` ligne par ligne, après déduplication du payload sur :

- `cur1`, `cur2`, `rate_date`, `source`

Cela évite les collisions de clé dupliquée dans un unique batch d'upsert.

## Dépannage

- **Aucune ligne importée**
  - Vérifier la plage de dates demandée et les jours de publication BCE (jours ouvrés).
- **Erreur HTTP**
  - Vérifier l'accès réseau sortant vers `data-api.ecb.europa.eu`.
- **Format CSV inattendu**
  - Les en-têtes BCE ont peut-être changé ; inspecter la réponse et adapter le mapping du parser.
