# Plan de charge centrale (`plan_charge_centrale`)

Ce document décrit la fonctionnalité de **plan de charge visuel par centrale** : un barregraphe horaire comparant la quantité prévue et la quantité réalisée, complété par deux courbes de référence (capacité horaire et objectif horaire). Il couvre l'architecture, la logique de calcul du prévu/réalisé, la migration des objectifs horaires par centrale, et les modifications apportées à la fiche centrale.

## 1. Pourquoi cette fonctionnalité

Le besoin : visualiser, pour une centrale et une date données, la charge de production heure par heure — ce qui était planifié contre ce qui a réellement été produit — afin de repérer les heures en sur ou sous-charge par rapport aux objectifs de la centrale.

## 2. Architecture générale

```
routes/web.php
  └─ prefix /plan_charge_centrale  (middleware auth:sanctum + interne)
       ├─ GET /       → index()  page (sélecteur centrale + date + graphique)
       └─ GET /data   → data()   endpoint JSON consommé en AJAX par le graphique

app/Http/Controllers/plan_charge_centrale_controller.php
  ├─ index()                    liste des centrales autorisées pour l'utilisateur (lier_user_centrale)
  ├─ data(Request)               calcule labels + séries prévu/réalisé/objectif pour une centrale/date
  └─ plage_heures_planning()     borne l'axe des heures sur t_parametre (heure début/fin planning)

resources/views/planning/plan_charge_centrale.blade.php
  └─ Chart.js v2 (déjà utilisé ailleurs dans l'app, cf. resources/views/commande/graph_synthese.blade.php)
     type 'bar' (prévu / réalisé) + datasets 'line' superposés (capacité, objectif horaire)
```

### 2.1 Bornes de l'axe des heures

Les heures affichées viennent de `t_parametre.parametre_planning_heure_debut_default` / `..._heure_fin_default` (par défaut `05:00` → `18:00`), via `plan_charge_centrale_controller::plage_heures_planning()`. Une heure de fin avec des minutes (ex. `18:30`) inclut l'heure entière suivante dans la plage.

### 2.2 Calcul du prévu / réalisé

Les quantités viennent de deux tables déjà existantes dans l'application, toutes deux porteuses d'une colonne `planning_quantite` et d'un flag `planning_reel` :

- **`t_planning_prev`** : tournées prévisionnelles (commandes pas encore transformées en ordre de fabrication).
- **`t_planning`** : tournées liées à un ordre de fabrication (`planning_reel = 0` tant que le camion n'a pas réellement tourné, `= 1` une fois réalisé).

Regroupement par `HOUR(planning_debut)` (heure de départ centrale du chargement), filtré sur `centrale_id` et `planning_date` :

- **Prévu** = `SUM(planning_quantite)` de `t_planning_prev` (toutes lignes) **+** `t_planning` où `planning_reel = 0`.
- **Réalisé** = `SUM(planning_quantite)` de `t_planning` où `planning_reel = 1`.

Cette bascule prévisionnel/OF reprend la logique déjà utilisée dans `planning_controller::verifier_quantite_planifier()` (`$commande->commande_of == 1 ? planning::class : planning_prev::class`), à laquelle s'ajoute le filtre `planning_reel` pour isoler ce qui est réellement produit de ce qui reste planifié.

**Limite connue** : le bucket horaire se base sur l'heure courante (`planning_debut`), pas sur l'heure initialement prévue (`planning_debut_prev`). Une tournée déplacée dans le temps après sa création apparaît donc dans son nouveau créneau horaire, pas dans celui d'origine.

### 2.3 Courbes de référence

Deux courbes optionnelles se superposent aux barres (affichées seulement si la donnée existe) :

- **Capacité / heure** (ligne rouge pointillée, valeur plafond constante) : `t_centrale.centrale_prod_heure`.
- **Objectif horaire** (ligne orange, variable heure par heure) : `t_centrale.centrale_objectif_m3_HH_HH` correspondant à chaque créneau (cf. §3).

## 3. Objectifs horaires par centrale (`centrale_objectif_m3_*`)

### 3.1 Migration

`database/migrations/2026_09_08_1147_V905000_NB_t_centrale_objectif_m3_heure.php` ajoute 24 colonnes à `t_centrale`, une par créneau horaire :

```
centrale_objectif_m3_00_01, centrale_objectif_m3_01_02, ..., centrale_objectif_m3_23_24
```

Type `decimal(10,2)`, `nullable`, `default(0)`. Le fichier porte un `down()` permettant de retirer proprement les 24 colonnes.

### 3.2 Fiche centrale

Un onglet **Objectif m3** a été ajouté dans `resources/views/centrale/form.blade.php`, juste après l'onglet **Général**. Il affiche les 24 champs (générés par une boucle `@for`, noms de champs identiques aux colonnes DB) en `<input type="number" step="0.01">` pour restreindre la saisie aux nombres à 2 décimales.

Côté serveur, `centrale_controller::enregistrer()` valide chaque champ avec `['nullable','numeric','regex:/^\d{1,8}(\.\d{1,2})?$/']` — le regex borne explicitement la précision à 2 décimales (cohérent avec `decimal(10,2)`), motif déjà utilisé ailleurs dans l'app (`incident_controller::incident_imputation`). Sans ces règles de validation, les champs auraient été silencieusement ignorés par `$centrale->fill($champs_valide->validated())`, qui ne retient que les clés déclarées dans les règles.

## 4. Fichiers créés / modifiés

| Fichier | Rôle |
|---|---|
| `app/Http/Controllers/plan_charge_centrale_controller.php` | Nouveau — page + endpoint JSON du plan de charge |
| `resources/views/planning/plan_charge_centrale.blade.php` | Nouveau — vue Chart.js |
| `routes/web.php` | Ajout du groupe de routes `plan_charge_centrale.*` |
| `database/migrations/2026_09_08_1147_V905000_NB_t_centrale_objectif_m3_heure.php` | Nouveau — 24 colonnes `centrale_objectif_m3_*` |
| `resources/views/centrale/form.blade.php` | Ajout de l'onglet **Objectif m3** |
| `app/Http/Controllers/centrale_controller.php` | Ajout des 24 règles de validation correspondantes |

## 5. Limites connues

- Le lien vers `/plan_charge_centrale` n'a pas été ajouté au menu de navigation — celui-ci ne semble pas piloté par les vues Blade ni par `public/inc/haut.inc.php` (probablement une source dynamique non identifiée) ; la page reste accessible par URL directe.
- Le bucket horaire prévu/réalisé se base sur l'heure courante de la tournée, pas sur l'heure initialement prévue (cf. §2.2).
- La liste des centrales proposées dans le sélecteur est limitée à `$this->user->lier_user_centrale()`, comme dans le reste de l'application (ex. `bl_controller`).
