# Facture d'acompte : champs `t_facture`

Ajout des colonnes nécessaires à la gestion des factures d'acompte.

## Fichiers modifiés / créés

- `database/migrations/2026_09_30_1000_V905000_NB_t_facture_acompte.php` (nouveau), sur `t_facture` :
  - `facture_acompte` : boolean, défaut 0, après `facture_avoir`. Indique une facture d'acompte.
  - `facture_acompte_deduit` : boolean, défaut 0. Indique que l'acompte a été déduit.
  - `facture_acompte_num_facture_deduite` : varchar(20), nullable. N° de la facture sur laquelle l'acompte est déduit (même taille que `facture_numero`).
  - Met la version des paramètres à `9.05.000`. Le `down()` supprime les trois colonnes.
- `helpers/Modele_helpers.php` : ajout des `@property` sur le modèle `facture`.

Le modèle `facture` utilise `$guarded` : aucune modification de `$fillable` n'est nécessaire.

## Création manuelle d'une facture d'acompte (Laravel)

- `resources/views/facture/form.blade.php` (mode création) :
  - Titre : « Création manuelle d'une facture ou d'un avoir ou d'un acompte ».
  - Nouveau choix radio « Facture acompte » (`nouvelle_facture_avoir` = 2), en plus de Facture (0) et Avoir (1).
  - Bouton « Valider » placé sous les choix Facture / Avoir / Facture acompte.
  - Cadre `#affiche_nouvelle_facture` : `height: auto; max-height: 95vh; overflow-y: auto` surchargé dans la vue, car `public/inc/css/style.css` (partagé avec le legacy) impose `height: 50vh` sans défilement et coupait le bas du formulaire.
- `app/Http/Controllers/facture_controller.php` : `creer()` transmet `nouvelle_facture_avoir == 2` à `creer_entete_facture_manuelle()` (nouveau paramètre `bool $acompte = false`), qui enregistre `facture_acompte` = 1.

Décision : une facture d'acompte suit la numérotation des factures (pas celle des avoirs) et `facture_avoir` reste à 0.

Prérequis : la migration `2026_09_30_1000_V905000_NB_t_facture_acompte.php` doit être passée, sinon la création échoue (colonne `facture_acompte` inconnue).

## Titre de la fiche facture (mode édition)

- `resources/views/facture/form.blade.php` : le titre `<h1>` dépend du type : « Avoir » si `facture_avoir` = 1, « Facture d'acompte » si `facture_acompte` = 1, sinon « Facture ».

## Bouton « + Factures d'acomptes » (fiche facture)

- `resources/views/facture/form.blade.php` : bouton `#ajouter_factures_acompte` entre les onglets (Corps de facture…) et les totaux, affiché uniquement pour une facture normale (`facture_avoir` != 1 et `facture_acompte` != 1). Pas encore d'action associée.
- Au clic : ouverture d'une fenêtre `#affiche_factures_acompte` (style inline, sans toucher à `style.css`) avec un DataTable chargé au premier clic puis rechargé à chaque ouverture.
- Route `GET facture_laravel/acomptes/{facture}` → `facture_controller::data_table_acomptes()` : factures du même client avec `facture_acompte` = 1 et `facture_acompte_deduit` = 0, hors facture courante, triées par date décroissante. Colonnes : N°, date, HT, TVA, TTC, validée.
- Sélection : case à cocher `.selection_facture_acompte` (valeur = `id_facture` de l'acompte) en première colonne, case « tout sélectionner » `#select_all_factures_acompte` dans l'en-tête (décochée à chaque ouverture). Bouton `#valider_factures_acompte` sous le tableau, sans action pour le moment.
- Correctif affichage : `#affiche_facture` a un `transform` (style.css), ce qui rend le `position:fixed` de la fenêtre relatif au cadre de la facture (fenêtre coupée, bouton Valider invisible). La fenêtre est donc déplacée dans le `body` au chargement du formulaire, et supprimée à la fermeture de la facture (`index.blade.php`). DataTable en `autoWidth: false` avec colonne case à cocher à 40px.

## Paramètre article de déduction d'acompte

- `database/migrations/2026_09_30_1100_V905000_NB_t_parametre_article_deduction_acompte_id.php` (nouveau) : ajoute `parametre_article_deduction_acompte_id` (integer, défaut 0) dans `t_parametre`. Version `9.05.000`. Le `down()` supprime la colonne.
- `helpers/Modele_helpers.php` : `@property` ajoutée sur le modèle `parametre`.
- Fiche paramètre, onglet Article / Produit (`resources/views/parametre/index.blade.php`) : combo « Article déduction acompte » (liste des services, « Aucun » = 0), après « Article contribution environ granulat », même fonctionnement que « Article contribution environ ».
- `app/Http/Controllers/parametre_controller.php` : règle de validation `numeric` ; la sauvegarde passe par le `fill($champs_valide->validated())` existant.

## Déduction des acomptes (bouton Valider de la fenêtre)

- Route `POST facture_laravel/{facture}/deduire_acomptes` → `facture_controller::deduire_acomptes()` (données : `acomptes[]` = ids des factures d'acompte cochées).
- Contrôles : profil facture 3, 4 ou 5 ; facture non validée ; facture normale (ni avoir, ni acompte) ; article `parametre_article_deduction_acompte_id` existant dans `t_service` ; acomptes du même client, non déduits.
- En transaction, en fin de corps de facture :
  - 2 lignes vides (type `E`) avant la première déduction ; pas de nouvelles lignes vides si la facture contient déjà une déduction (ligne `S` de l'article de déduction dont le libellé commence par « Déduction acompte »).
  - Par acompte et par taux de TVA de ses lignes tarifées : ligne `S`, article = service de déduction (compte comptable du service), libellé « Déduction acompte N° du JJ/MM/AAAA », qté 1, PU = total = −HT de l'acompte, taux / compte TVA repris de l'acompte.
  - Acompte : `facture_acompte_deduit` = 1, `facture_acompte_num_facture_deduite` = N° de la facture. Traçabilité « Déduction acompte N° ».
- Puis `recalculerTotaux()` / `recalculerSousTotaux()` (totaux, reste à régler, encours client).
- JS : fenêtre fermée si succès, message dans `.message_facture`, rechargement du corps de facture.

## Ajout de ligne de facture Laravel (portage legacy)

L'ajout de ligne ne fonctionnait pas côté Laravel (recherche produit non branchée, création de ligne incomplète).

- `facture_controller::valider_ligne()` réécrit sur le modèle de `public/facture/valider_ligne_facture.php` :
  - Droits : modification profils 3, 4, 5 ; création profils 2, 4, 5.
  - Création : `article_ligne_facture()` (nouvelle méthode privée) donne type de ligne (F/S/J/D/Z/G/C), TVA, compte comptable, prix de base et unité selon l'article (formule, service, ajout, adjuvant, zone, granulat, commentaire).
  - Facture sans ligne (`facture_manuelle_creation` = 1) : ligne n° 1, BL / chantier 0. Sinon insertion sous la ligne sélectionnée (BL, chantier, date BL, liste BL repris), lignes suivantes décalées.
  - Zone : prix m3 ou voyage selon le mode de transport du chantier (qté forcée à 1 au voyage).
  - Refus des doublons formule / zone / granulat (même BL, chantier, centrale).
  - Quantité et prix acceptent la virgule décimale.
- `resources/views/facture/form.blade.php` :
  - Bouton loupe `#btn_recherche_produit_facture` branché sur les pages legacy `public/facture/recherche_produit/*.php`, affichées dans `#affiche_recherche_dans_facture` (déplacée dans le `body` à cause du `transform` de `#affiche_facture`). « Sélectionnez une ligne ! » si la facture a déjà des lignes et qu'aucune n'est sélectionnée.
  - Double-clic : parité legacy (type de ligne positionné dans le select, unité modifiable seulement pour service / ajout, « Ligne non modifiable » pour les sous-totaux).
  - Valider : « Choisissez un produit » si aucun article ; libellé et unité (champs désactivés) ajoutés à l'envoi ; `facture_manuelle_creation` calculé à partir du nombre de lignes renvoyé par le tableau.
- `resources/views/facture/index.blade.php` : les fenêtres déplacées dans le `body` sont supprimées à la fermeture de la facture.

Test serveur (transaction annulée) : 1re ligne sur facture vide, 2e ligne insérée dessous, déduction d'un acompte → 2 lignes vides + ligne « Déduction acompte … » à −80,00, totaux recalculés (HT 170,50 / TVA 34,10), acompte marqué déduit et plus proposé.

## Suppression d'une déduction d'acompte

- `facture_controller::supprimer_ligne()` : si la ligne supprimée est une ligne de déduction (type `S`, libellé initial « Déduction acompte N° du JJ/MM/AAAA », lu par `numero_acompte_ligne_deduction()`), et qu'il ne reste plus de ligne de déduction pour cet acompte sur la facture (cas multi-TVA), l'acompte repasse à `facture_acompte_deduit` = 0 et `facture_acompte_num_facture_deduite` = NULL (traçabilité « Annulation déduction acompte N° »). Totaux recalculés comme pour toute suppression de ligne.
- `facture_controller::supprimer()` : la suppression d'une facture libère aussi les acomptes déduits dessus.
- Les 2 lignes vides ne sont pas supprimées automatiquement.
- Le libellé initial sert de lien entre la ligne et l'acompte : il ne doit pas être modifié (non modifiable depuis la fiche pour une ligne de service).

Test (transaction annulée) : après suppression de la ligne de déduction, HT 170,50 → 250,50, acompte déduit = 0, N° vidé, acompte de nouveau proposé dans la liste.

## Unités dans le corps de facture

- `app/Models/ligne_facture.php` : ajout de la relation `lier_unite()` (`unite_id` → `t_unite`). Elle manquait : la colonne Unité du tableau des lignes Laravel était toujours vide (le legacy fait un LEFT JOIN `t_unite`).
- `facture_controller::data_table_lignes()` : chargement anticipé `with(['lier_centrale', 'lier_unite'])`.
- `helpers/Modele_helpers.php` : `@property-read` `lier_unite`.

## Unité au choix de l'article (loupe)

- Les pages de recherche legacy (`public/facture/recherche_produit/*.php`) renseignent `#unite_ligne_facture` avec le code unité (service), le libellé (ajout) ou « M3 » (formule), alors que la liste attend l'`id_unite` : la liste restait vide (même défaut dans le legacy).
- `resources/views/facture/form.blade.php` : options de l'unité avec `data-code` / `data-libelle`, et surcharge de `$.valHooks.select` limitée à `#unite_ligne_facture` : une valeur qui n'est pas un id est recherchée par code ou libellé (sans casse) ; vide ou inconnue → « Aucune » (0). Surcharge posée une seule fois (drapeau `unite_ligne_facture`) malgré les rechargements du formulaire. Pages legacy inchangées.

## Filtre « Facture acompte » dans la liste des factures

- `resources/views/facture/index.blade.php` : case `#filtre_acomptes` « Facture acompte » (cochée par défaut) après « Avoirs », envoyée en `acomptes` ; rechargement au changement comme les autres cases.
- `facture_controller::data_table()` : union des types cochés — Factures = ni avoir ni acompte, Avoirs = `facture_avoir` = 1, Facture acompte = `facture_acompte` = 1 ; aucune case cochée = pas de filtre (comportement existant).
- Changement de comportement : « Factures » seul n'affiche plus les factures d'acompte.

Test sur toute la base : 3 239 factures + 46 avoirs + 1 acompte = 3 286 lignes avec les trois cases cochées.
