---
suivi: 1458
date: 2026-09-04
sujet: Tâche opérationnelle — Compléter et valider une facture
chantier: depot_factures
type: feature
statut: poussé
hash: 38583986
fichiers:
  - app/Models/TaskType.php
  - app/Models/Task.php
  - app/Services/TaskSyncService.php
  - app/Services/Tasks/CompleterSaisieFactureTaskSync.php
  - app/Services/Tasks/CompleterSaisieFactureWorkflowHooks.php
  - app/Console/Commands/BackfillCompleterSaisieFactureTasksCommand.php
  - database/migrations/2026_09_04_190000_seed_completer_saisie_facture_task_type.php
  - app/Http/Controllers/DepotFactureController.php
  - app/Http/Controllers/MesTachesController.php
  - resources/js/utils/tacheSuiviLabels.js
  - public/build/
  - docs/suivi/SUIVI_1458_tache_completer_saisie_facture.md
---

# SUIVI #1458 — Tâche « Compléter et valider une facture »

## PROMPT ENVOYÉ

Implémenter la tâche opérationnelle amont (valideur désigné, immédiat, clone NV1,
taskable DepotFacture, clôture à l’envoi, backfill des 32). Diagnostic #1457.

## FICHES LUES

- **#1457** — mécanisme NV1 = Task / TaskSyncService ; analyse AMONT ; fiche_url à
  étendre ; rail fermé ; digest ouvert ; valideur JSON mixte azure_id / users.id.
- **#1450** — enregistrement permissif + assertRattachementBudgetCompletPourEnvoi
  conservés ; défaut valideur = déposant (tâche aussi dans ce cas, décision 5).
- **#1453** — `depot-factures:backfill-validateur` non modifié. Namespace artisan
  = token avant le premier `:`.
- **#1454 / #1455 / #1456** — hors périmètre, non défaits.

Base : `origin/main` `1e06bf76` (chore #1457). Rebase inutile (déjà dessus).
Gisement prod (Robin F1) : 32 dépôts. Aucun autre chiffre.

## SYNTHÈSE

Type `completer_saisie_facture`, libellé « Compléter et valider une facture »,
72 h. Taskable `DepotFacture`. Assignee via `FactureValidateurNv1AssignmentService::resolveUser`
(3ᵉ arg `$allowAnnuaire` : false en backfill CLI, pas de Graph).

Upsert : `applyDepotSaisieFromValidated` + `ensureValidateurDeposantParDefaut`
(création dépôt). Clôture `envoi_validation` → `realise` à l’envoi (sauf
intention `bloquer`). Valideur vidé → `validateur_vide` / `annule`.
Rejet / suppression → `annule`.

Digest : `queryTasksDigest` = toutes Task ouvertes `assignee_id` (aucun filtre
de type). Rail Mes tâches : `SAISIE`. fiche_url : `/depot-factures?depot={uuid}`.

## TABLEAU ÉVÉNEMENTS

| Événement | Action tâche | Statut | closed_reason |
|-----------|--------------|--------|---------------|
| Enregistrement / création avec valideur résolu | upsert | nouveau | — |
| Valideur == déposant | upsert (pas d’exception) | nouveau | — |
| Valideur non résolu | aucune création, Log::warning | — | — |
| Valideur changé | reassign forceFill | inchangé | — |
| Valideur vidé | close | annule | validateur_vide |
| Envoi validation (sauf bloquer) | close | realise | envoi_validation |
| Envoi intention bloquer | aucune clôture amont | ouvert | — |
| Rejet | close | annule | rejet_erp |
| Suppression dépôt | close | annule | facture_supprimee |
| 2e upsert | updateOrCreate même clé | 1 seule | — |
| Tâche déjà fermée | non ressuscitée | — | — |

## DÉPLOIEMENT-TEST

OVH :
1. `git pull origin main`
2. `php artisan migrate --force` (seed `task_types` updateOrCreate)
3. `php artisan view:clear` puis `php artisan journal:sync`
4. `php artisan optimize:clear`
5. Touch OPcache si le cluster le requiert (PHP-FPM)
6. Dry-run : `php artisan taches:backfill-completer-saisie`
7. Apply : `php artisan taches:backfill-completer-saisie --apply`
8. Contrôle digest : `php artisan taches:digest --dry --only-email=... --force`

JAMAIS npm / composer / optimize / config:cache sur OVH.

Test visibilité : compte TIERCE = le valideur, pas Robin (GS_ADMIN_ERP).

## LEÇON

NV1 taskable = WorkflowValidation ; amont = DepotFacture, clés distinctes.
`ensureValidateurDeposantParDefaut` écrit aussi le valideur : brancher l’upsert
là, pas seulement dans `applyDepotSaisieFromValidated`. Namespace artisan =
premier token (`taches:…` ≠ `depot:…`). Rail Mes tâches = liste fermée à étendre
sinon `OPÉR.` ; digest et badge sont ouverts.
