diff --git a/client/src/pages/DsiOpex.tsx b/client/src/pages/DsiOpex.tsx index c71efd9..227078b 100644 --- a/client/src/pages/DsiOpex.tsx +++ b/client/src/pages/DsiOpex.tsx @@ -493,6 +493,19 @@ export default function DsiOpex() { const CATEGORIES_FILTER = useMemo(() => ['Toutes', ...categoriesPresentes], [categoriesPresentes]); + // Basculer le mode de ventilation d'une ligne (Prorata classe 6 ↔ Manuel) + const handleToggleVentilation = useCallback((id: string) => { + if (isValidated) return; + setOpexState(prev => ({ + ...prev, + lignes: prev.lignes.map(l => l.id === id ? { + ...l, + mode_ventilation: (l.mode_ventilation === 'Manuel') ? 'Prorata classe 6' : 'Manuel', + } : l), + })); + setIsDirty(true); + }, [isValidated]); + // Modifier un montant directement dans le tableau const handleMontantChange = useCallback((id: string, value: number) => { if (isValidated) return; @@ -683,14 +696,20 @@ export default function DsiOpex() { const montantsRecalcules: Record = {}; let totalEtab = 0; for (const ligne of opexState.lignes) { + // Priorité : mode_ventilation de la ligne (modifié par l'utilisateur) > source JSON > isCustom const srcPoste = srcData.postes.find(p => p.libelle === ligne.libelle); - const isManuel = srcPoste?.mode_ventilation === 'Manuel' || ligne.isCustom; + const modeVentilation = ligne.mode_ventilation ?? srcPoste?.mode_ventilation ?? null; + const isManuel = modeVentilation === 'Manuel' || ligne.isCustom; let montant: number; if (isManuel && etabOverrides[ligne.libelle] !== undefined) { // Override saisi manuellement par l'utilisateur montant = etabOverrides[ligne.libelle]; - } else if (ligne.montant > 0) { + } else if (!isManuel && ligne.montant > 0) { + // Prorata automatique montant = Math.round(ligne.montant * ratio); + } else if (isManuel) { + // Manuel sans override : 0 (en attente de saisie) + montant = 0; } else { montant = 0; } @@ -1122,7 +1141,28 @@ export default function DsiOpex() { {ligne.type || '—'} {ligne.facturation || '—'} {showDetails && {ligne.compte || '—'}} - {showDetails && {(() => { const mv = ligne.mode_ventilation || 'Prorata'; const isManuelV = mv === 'Manuel'; return {mv}; })()}} + {showDetails && ( + + {isValidated ? ( + {ligne.mode_ventilation || 'Prorata classe 6'} + ) : ( + + )} + + )} {formatNum(ligne.budget_n1)} @@ -1265,21 +1305,23 @@ export default function DsiOpex() { {/* Tableau scrollable horizontalement avec tous les postes */}
-
+
- - + {/* Colonnes postes — vert = prorata auto, bleu = manuel */} {opexState.lignes.map(ligne => { const srcPoste = getOpexDataForAnnee(annee).postes.find(p => p.libelle === ligne.libelle); - const isManuel = srcPoste?.mode_ventilation === 'Manuel' || ligne.isCustom; + const modeVentilation = ligne.mode_ventilation ?? srcPoste?.mode_ventilation ?? null; + const isManuel = modeVentilation === 'Manuel' || ligne.isCustom; return ( @@ -1308,7 +1350,8 @@ export default function DsiOpex() { {opexState.lignes.map(ligne => { const srcPoste = getOpexDataForAnnee(annee).postes.find(p => p.libelle === ligne.libelle); - const isManuel = srcPoste?.mode_ventilation === 'Manuel' || ligne.isCustom; + const modeVentilation = ligne.mode_ventilation ?? srcPoste?.mode_ventilation ?? null; + const isManuel = modeVentilation === 'Manuel' || ligne.isCustom; const montant = etab.montants[ligne.libelle] ?? 0; const cellKey = `${etab.code}|${ligne.libelle}`; const isEditing = inlineEditKey === cellKey; @@ -1373,7 +1416,8 @@ export default function DsiOpex() { {opexState.lignes.map(ligne => { const srcPoste = getOpexDataForAnnee(annee).postes.find(p => p.libelle === ligne.libelle); - const isManuel = srcPoste?.mode_ventilation === 'Manuel' || ligne.isCustom; + const modeVentilation = ligne.mode_ventilation ?? srcPoste?.mode_ventilation ?? null; + const isManuel = modeVentilation === 'Manuel' || ligne.isCustom; const totalColonne = sortedEtabs.reduce((s, e) => s + (e.montants[ligne.libelle] ?? 0), 0); return (
Code + Code ); })} - +
{etab.nom}