---
suivi: 1620
date: 2026-09-18
sujet: Paiement manuel historique — valideur désigné + bouton visible
chantier: comptabilite / depot-factures
type: feature
statut: poussé
hash: 9b7485e7
fichiers:
  - app/Services/FacturePaiementManuelHistoriqueService.php
  - app/Http/Controllers/FacturePaiementManuelHistoriqueController.php
  - app/Http/Controllers/DepotFactureController.php
  - resources/js/Pages/DepotFactures/DepotFactureSaisieForm.vue
  - resources/js/Pages/DepotFactures/Index.vue
  - resources/js/Pages/DepotFactures/Show.vue
  - resources/js/Pages/DepotFactures/SaisieConsultation.vue
  - resources/js/Pages/Marches/Show.vue
  - tests/Unit/PaiementManuelValideur1620SourceTest.php
  - tests/Unit/FacturePaiementManuelHistorique1604SourceTest.php
  - database/data/journal_mises_a_jour_post_2026_06_12.php
  - public/build/
  - docs/suivi/SUIVI_1620_paiement_manuel_valideur.md
---

# SUIVI #1620 — paiement manuel historique : valideur + bouton visible

## PROMPT ENVOYÉ

#1604 : marquage manuel payée réservé GS_COMPTABILITE. En prod,
le valideur désigné ne peut pas marquer, et l’action est cachée
dans le menu à trois points à côté d’Enregistrer. Ouvrir le droit
au valideur (JSON, helper #1604), DG si déjà le cas, bouton
distinct visible. Contrôle serveur 403, m365GroupNames brut.

## FICHES LUES

- **#1604 LEÇON** — valideur = JSON `ocr_raw.saisie`, pas de colonne
  `validateur_id` ; `userEstValidateurDesigne` déjà écrit ;
  `Gate::before` / compte Robin ne prouvent aucun 403. Impact :
  réutiliser le helper, groupes en brut.
- **#1619** — dernier numéro consommé. Impact : 1620 libre.
- **#1188** — `DepotFactureSaisieForm.vue` zone commune. Impact :
  un seul build, rebase `origin/main` avant Vite.

## SYNTHÈSE

### Diagnostic (avant modification)

Droit fiche (#1604) : `FacturePaiementManuelHistoriqueService`
`userEstCompta` L32-35 (`m365GroupNames` GS_COMPTABILITE) ;
`peutMarquer` L54-57 ; `marquer` L120-122 ; contrôleur
`FacturePaiementManuelHistoriqueController::store` L29-33 et
`destroy` L67-71 — **uniquement GS_COMPTABILITE**. DG : **non**.

Droit saisie dépôt : `DepotFactureController::validerHistorique`
L2833-2836 → `canValiderHistoriquePaye` L5013-5028. Avant ce lot :
`isAdminERP()` + `hasAnyM365Group(DSI, COMPTA, DG)` (donc
GS_ADMIN_ERP passait via Gate/hasAny) **ou**
`utilisateurEstAttributaire` (JSON validateur_id/email), **pas**
`userEstValidateurDesigne`.

Valideur désigné : `FactureSuppressionService::userEstValidateurDesigne`
L47-52 via `resolveValidateurDepuisSaisie` (`ocr_raw.saisie.validateur_email`
puis `validateur_id`). Réutilisé.

Bouton : `DepotFactureSaisieForm.vue` L4889-4894 menu `⋯`
(`saisieOverflowMenuItems`) ; header collant forçait
`showEnregistrerMarquerPayeHistorique: false` (L5023-5025).
Action réelle : `enregistrerMarquerPayeHistorique` enregistre
(saveDraftAjax) puis `submitValidationHistorique` → libellé
« Enregistrer et marquer comme payé » conservé.

### Correctif

Une seule habilitation : COMPTA + DG (`m365GroupNames` brut) ou
`userEstValidateurDesigne`. Fiche et `validerHistorique` partagent
`userEstHabiliteMarquageDepot`. Bouton à côté d’Enregistrer,
uniquement si saisie historique **et** droit. Retiré du menu `⋯`.
GS_ADMIN_ERP / GS_DSI ne sont plus un droit dédié (403 si ni
compta, ni DG, ni valideur).

## DÉPLOIEMENT-TEST

OVH : `git pull origin main` ; `php artisan view:clear` ;
`php artisan journal:sync`. Pas de migrate.

Compte refus : GS_HECTARE ou GS_ENVOL, **pas** le valideur de la
pièce, sans GS_COMPTABILITE ni GS_DIRECTION_GENERALE. Le compte
Robin (GS_ADMIN_ERP) ne prouve pas un 403.

## LEÇON

`hasAnyM365Group` / `isAdminERP` = GS_ADMIN_ERP toujours vrai.
Pour un 403 métier : `m365GroupNames()` brut. Valideur = JSON
saisie, helper unique `userEstValidateurDesigne`. Action utile
cachée dans `⋯` = action introuvable.
