feat(front) : onglet comptabilite prestataire (ERP-144) (#106)
Auto Tag Develop / tag (push) Successful in 8s

Empilée sur ERP-143 (#105).

## Périmètre ERP-144
Onglet **Comptabilité** de l'écran `/providers/new` — gated par permission + blocs RIB conditionnels.

- Champs (`Malio*`) : SIREN / Numéro de compte / Mode de TVA (`/api/tva_modes`) / N° de TVA / Délai (`/api/payment_delays`) / Type de règlement (`/api/payment_types`) / Banque (`/api/banks`).
- **RG-3.07** : Banque visible **et** obligatoire **seulement si** Type = `VIREMENT` (affichage conditionnel + payload `bank` forcé à null sinon).
- **RG-3.08** : blocs RIB (Libellé/BIC/IBAN) affichés et requis si Type = `LCR` ; « + RIB » gated (dernier RIB complet) / Supprimer (modal). À la validation, **POST des RIB AVANT** le PATCH des scalaires (le back valide RG-3.08 sur le PATCH).
- **Gating** : onglet présent uniquement si `technique.providers.accounting.view` ; **éditable** uniquement si `.manage` (sinon lecture seule). Masqué pour Bureau/Commerciale.
- « Valider » → PATCH `/api/providers/{id}` (groupe `provider:write:accounting`) + sous-ressource RIBs (`/providers/{id}/ribs` + `/provider_ribs/{id}`). Erreurs 422 inline (scalaires) et par ligne (RIB).
- `useProviderReferentials.loadAccounting()` (chargé seulement si l'onglet est accessible). Helpers purs `utils/forms/providerAccounting.ts`.
- i18n `technique.providers.form.accounting` + `confirmDelete.rib`.

> NB : les placeholders **Rapports / Échanges** relèvent des écrans Consultation/Modification (ERP-145) — le flux de **création** ne porte que 3 onglets (Contact/Adresse/Comptabilité), conformément à la spec.

## Conformité
- `useApi()` only ; `Malio*` only ; pas de masque email ; aucun texte FR en dur ; pas d'import inter-module (helpers ré-implémentés côté Technique, règle ABSOLUE n°1).

## Vérifications
- Vitest : 454/454 (18 nouveaux : helpers compta RG-3.07/3.08, workflow VIREMENT/LCR, ordre RIB→scalaires, 422 inline + par ligne, lecture seule sans manage).
- ESLint : OK.
- `nuxi typecheck` : 0 erreur sur les fichiers source du ticket.
- Golden path navigateur : page compile, onglet Comptabilité visible (gating accounting.view OK pour admin). Contenu de l'onglet gaté derrière le déverrouillage des 3 onglets (multiselect `Malio` non pilotable en a11y) — couvert par les tests unitaires + typecheck.

Reviewed-on: #106
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #106.
This commit is contained in:
2026-06-15 09:15:20 +00:00
committed by Autin
parent 17aa61d014
commit c25c33116d
8 changed files with 793 additions and 5 deletions
@@ -28,10 +28,20 @@ export interface RefOption {
label: string
}
/** Option de type de reglement enrichie de son code stable (RG-3.07 / RG-3.08). */
export interface PaymentTypeOption extends RefOption {
code: string
}
interface HydraMember {
'@id': string
}
interface ReferentialMember extends HydraMember {
code: string
label: string
}
interface CategoryMember extends HydraMember {
code: string
name: string
@@ -55,6 +65,11 @@ export function useProviderReferentials() {
const categories = ref<RefOption[]>([])
const sites = ref<RefOption[]>([])
const countries = ref<RefOption[]>([])
// Referentiels comptables (charges a la demande via loadAccounting).
const tvaModes = ref<RefOption[]>([])
const paymentDelays = ref<RefOption[]>([])
const paymentTypes = ref<PaymentTypeOption[]>([])
const banks = ref<RefOption[]>([])
/** Recupere une collection complete (pagination desactivee) en Hydra. */
async function fetchAll<T extends HydraMember>(
@@ -88,10 +103,34 @@ export function useProviderReferentials() {
])
}
/**
* Charge les referentiels comptables (onglet Comptabilite, ERP-144). Appele
* uniquement quand l'utilisateur peut voir l'onglet (accounting.view). Resilient
* (allSettled) : un referentiel en echec reste vide.
*/
async function loadAccounting(): Promise<void> {
await Promise.allSettled([
fetchAll<ReferentialMember>('/tva_modes')
.then((list) => { tvaModes.value = list.map(t => ({ value: t['@id'], label: t.label })) }),
fetchAll<ReferentialMember>('/payment_delays')
.then((list) => { paymentDelays.value = list.map(d => ({ value: d['@id'], label: d.label })) }),
// Le code stable du type sert les RG-3.07 (VIREMENT) / RG-3.08 (LCR).
fetchAll<ReferentialMember>('/payment_types')
.then((list) => { paymentTypes.value = list.map(p => ({ value: p['@id'], label: p.label, code: p.code })) }),
fetchAll<ReferentialMember>('/banks')
.then((list) => { banks.value = list.map(b => ({ value: b['@id'], label: b.label })) }),
])
}
return {
categories,
sites,
countries,
tvaModes,
paymentDelays,
paymentTypes,
banks,
loadMain,
loadAccounting,
}
}