signe expense

This commit is contained in:
2026-03-23 09:48:19 +01:00
parent 9b2cc83512
commit 5859221fca
4 changed files with 116 additions and 80 deletions
+15 -5
View File
@@ -10,18 +10,26 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($action === 'save') {
$id = $_POST['id'] ?? '';
$name = $_POST['name'];
$amount = $_POST['amount'];
$category = $_POST['category'];
$type = $_POST['type'];
$payment_day = $_POST['payment_day'];
$payment_day = empty($_POST['payment_day']) ? null : (int)$_POST['payment_day'];
$is_estimate = $_POST['is_estimate'];
$reg_month = $_POST['reg_month'];
$keywords = $_POST['mapping_keywords'] ?? '';
// NOUVEAU : Récupération de l'ID des vacances
$holiday_id = !empty($_POST['holiday_id']) ? (int)$_POST['holiday_id'] : null;
// ==========================================
// NOUVELLE NORME COMPTABLE : Dépense = Négatif
// ==========================================
// On récupère le montant en valeur absolue (pour éviter les erreurs si l'utilisateur a tapé un '-')
$amount = abs((float)$_POST['amount']);
// Si c'est un frais, on l'enregistre en négatif
if ($category === 'expense') {
$amount = -$amount;
}
// ==========================================
if ($id) {
// UPDATE
$stmt = $pdo->prepare("UPDATE pf_budget_items SET name=?, amount=?, category=?, type=?, payment_day=?, is_estimate=?, reg_month=?, mapping_keywords=?, holiday_id=? WHERE id=?");
@@ -31,6 +39,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$stmt = $pdo->prepare("INSERT INTO pf_budget_items (name, amount, category, type, payment_day, is_estimate, reg_month, mapping_keywords, holiday_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([$name, $amount, $category, $type, $payment_day, $is_estimate, $reg_month, $keywords, $holiday_id]);
}
// Redirection
header('Location: /budget.php?tab=recap');
exit;
}
+2 -1
View File
@@ -123,7 +123,7 @@ input[type="number"].no-spinners {
<td class="text-center text-muted">
<?php if ($amount != 0): ?>
<div class="cell-content">
<span>- <?= number_format($amount, 0, ',', ' ') ?> €</span>
<span style="color:#1e293b; font-weight:500;"><?= number_format($amount, 0, ',', ' ') ?> €</span>
<button class="btn-cell-delete"
onclick="deleteSavingsEntry('<?= $month ?>', '<?= htmlspecialchars($cat, ENT_QUOTES) ?>', '<?= $currentOwner ?>')">
&times;
@@ -140,6 +140,7 @@ input[type="number"].no-spinners {
<?php foreach ($months as $month):
$total = $data[$month]['TOTAL_BANQUE'] ?? 0;
$sum = 0;
// Le calcul reste identique : Total de la banque - Somme des enveloppes
foreach ($allCategories as $cat) $sum += ($data[$month][$cat] ?? 0);
$extra = $total - $sum;
?>
+22 -13
View File
@@ -38,7 +38,9 @@ $totalRevenus = 0;
<tbody>
<?php foreach ($items as $item):
// --- 1. CALCUL DES TOTAUX PRÉVUS ---
$amountToAdd = ($item['type'] === 'Annuel') ? $item['amount'] / 12 : $item['amount'];
$targetAbs = abs((float)$item['amount']); // On utilise l'absolu pour l'affichage
$amountToAdd = ($item['type'] === 'Annuel') ? $targetAbs / 12 : $targetAbs;
if ($item['category'] === 'expense') $totalDepenses += $amountToAdd;
else $totalRevenus += $amountToAdd;
@@ -63,19 +65,20 @@ $totalRevenus = 0;
}
if ($match) {
if ($item['category'] === 'income') {
$realSum += abs((float)$exp['amount']);
} else {
// Avec la nouvelle norme, on additionne simplement les montants.
// Si c'est une dépense, ça s'additionne en négatif.
// S'il y a un remboursement partiel, le "+" vient réduire le "-". C'est mathématiquement parfait.
$realSum += (float)$exp['amount'];
}
$hasMatchingExpense = true;
}
}
// --- 3. LOGIQUE D'ÉTAT (Uniquement dynamique) ---
$gap = $realSum - $item['amount'];
// On convertit le résultat réel en positif pour simplifier la comparaison visuelle UI
$realAbs = abs($realSum);
// --- 3. LOGIQUE D'ÉTAT ---
$isAutoChecked = false;
if ($hasMatchingExpense && ($realSum >= ($item['amount'] - 0.10))) {
if ($hasMatchingExpense && ($realAbs >= ($targetAbs - 0.10))) {
$isAutoChecked = true;
}
@@ -100,12 +103,17 @@ $totalRevenus = 0;
</td>
<td class="cell-amount" style="font-weight:600; padding:15px; color:<?= $item['category']==='income'?'#10b981':'#1e293b' ?>;">
<?= number_format($item['amount'], 2, ',', ' ') ?> €
<?= number_format($targetAbs, 2, ',', ' ') ?> €
<?php if ($hasMatchingExpense): ?>
<?php if ($gap > 0.05): ?>
<?php
// Le "Gap" est la différence visuelle.
// S'il y a plus de $realAbs que prévu, c'est un dépassement ou un bonus.
$gap = $realAbs - $targetAbs;
if ($gap > 0.05): ?>
<div style="font-size:0.75rem; color:#ef4444; font-weight:bold;">
Dépassement : +<?= number_format($gap, 2, ',', ' ') ?> €
<?= $item['category'] === 'income' ? 'Bonus :' : 'Dépassement :' ?> +<?= number_format($gap, 2, ',', ' ') ?> €
</div>
<?php elseif ($gap < -0.05): ?>
<div style="font-size:0.75rem; color:#f59e0b; font-weight:normal;">
@@ -198,7 +206,7 @@ $totalRevenus = 0;
<div class="form-group" style="margin-bottom:15px;">
<label class="pf-label" style="display:block; margin-bottom:5px; font-weight:600; color:#475569; font-size:0.9rem;">Mots-clés (Détection Auto)</label>
<input type="text" name="mapping_keywords" id="item_keywords" class="pf-input" placeholder="Ex: NETFLIX, PRIME VIDEO (séparés par virgule)" style="width:100%; padding:10px; border:1px solid #cbd5e1; border-radius:8px; background:#f0f9ff; border-color:#bae6fd;">
<small style="color:#64748b; font-size:0.75rem;">Si une dépense du mois contient ce mot, la ligne passera en "Payé".</small>
<small style="color:#64748b; font-size:0.75rem;">Si une dépense du mois contient ce mot, la ligne passera en "Validé".</small>
</div>
<div style="display:flex; gap:15px; margin-bottom:15px;">
@@ -285,7 +293,8 @@ function editRecapItem(item) {
document.getElementById("item_id").value = data.id;
document.getElementById("item_name").value = data.name;
document.getElementById("item_keywords").value = data.mapping_keywords || '';
document.getElementById("item_amount").value = data.amount;
// On affiche toujours la valeur en positif dans le formulaire
document.getElementById("item_amount").value = Math.abs(data.amount);
document.getElementById("item_category").value = data.category;
document.getElementById("item_type").value = data.type;
document.getElementById("item_day").value = data.payment_day;
+77 -61
View File
@@ -5,12 +5,10 @@
// 1. GESTION DES ACTIONS ET DE LA NAVIGATION
// ============================================================================
// --- NAVIGATION PAR MOIS ---
$currentMonth = isset($_GET['m']) ? str_pad((int)$_GET['m'], 2, '0', STR_PAD_LEFT) : date('m');
$currentYear = isset($_GET['y']) ? (int)$_GET['y'] : date('Y');
$currentMonthKey = $currentMonth . '-' . $currentYear;
// Calcul des liens de navigation
$prevM = (int)$currentMonth - 1; $prevY = $currentYear;
if ($prevM < 1) { $prevM = 12; $prevY--; }
$nextM = (int)$currentMonth + 1; $nextY = $currentYear;
@@ -23,10 +21,13 @@ $todayLink = "?tab=suivi";
// A. AJOUT CATÉGORIE TEMPORAIRE MANUELLE
if (isset($_POST['action']) && $_POST['action'] === 'add_temp_cat') {
$name = trim($_POST['cat_name']);
$budget = floatval($_POST['cat_budget']);
$budget = floatval($_POST['cat_budget']); // Saisi en positif par l'utilisateur
$type = $_POST['cat_type'] === 'credit' ? 'credit' : 'debit';
if ($name && $budget >= 0) {
// Si c'est un budget alloué (débit), on le stocke en négatif
if ($type === 'debit') $budget = -$budget;
if ($name) {
$stmt = $pdo->prepare("INSERT INTO pf_monthly_categories (month_year, name, type, budget) VALUES (?, ?, ?, ?)");
$stmt->execute([$currentMonthKey, $name, $type, $budget]);
header("Location: ?tab=suivi&m=$currentMonth&y=$currentYear"); exit;
@@ -48,7 +49,7 @@ if (isset($_POST['action']) && $_POST['action'] === 'save_snapshot') {
header("Location: ?tab=suivi&m=$currentMonth&y=$currentYear"); exit;
}
// D. SAUVEGARDE IMPORT CSV (LIGNE PAR LIGNE AVEC CHECKBOX)
// D. SAUVEGARDE IMPORT CSV
if (isset($_POST['action']) && $_POST['action'] === 'save_import') {
$count = 0;
$viewMonth = $_POST['view_month'] ?? $currentMonth;
@@ -81,7 +82,8 @@ if (isset($_POST['action']) && $_POST['action'] === 'save_import') {
$cat = 'TEMP_' . $tempCatMapping[$cat];
}
$finalAmount = $is_credit ? -abs($line['amount']) : abs($line['amount']);
// LOGIQUE INVERSÉE : Crédit = Positif, Débit = Négatif
$finalAmount = $is_credit ? abs($line['amount']) : -abs($line['amount']);
$dateToSave = $line['date'];
if (!empty($line['force_current'])) {
@@ -125,7 +127,9 @@ if (isset($_POST['action']) && $_POST['action'] === 'save_expense_manual') {
if ($label && $amount > 0) {
$is_credit = isset($_POST['is_credit']) ? (int)$_POST['is_credit'] : 0;
$finalAmount = $is_credit ? -abs($amount) : abs($amount);
// LOGIQUE INVERSÉE : Crédit = Positif, Débit = Négatif
$finalAmount = $is_credit ? abs($amount) : -abs($amount);
if ($id) {
$pdo->prepare("UPDATE pf_expenses SET date_exp=?, category=?, label=?, amount=?, budget_item_id=?, holiday_id=? WHERE id=?")
@@ -160,15 +164,17 @@ $today_day = (int)date('j');
$fixedChargesList = [];
$incomeList = [];
$stmtIds = $pdo->prepare("SELECT DISTINCT budget_item_id FROM pf_expenses WHERE MONTH(date_exp) = ? AND YEAR(date_exp) = ? AND budget_item_id IS NOT NULL AND amount > 0");
// On sélectionne les charges qui ont un montant NÉGATIF ou POSITIF selon la nouvelle règle (plus besoin de filtrer sur > 0)
$stmtIds = $pdo->prepare("SELECT DISTINCT budget_item_id FROM pf_expenses WHERE MONTH(date_exp) = ? AND YEAR(date_exp) = ? AND budget_item_id IS NOT NULL");
$stmtIds->execute([$currentMonth, $currentYear]);
$paidItemIds = $stmtIds->fetchAll(PDO::FETCH_COLUMN);
$stmtLabels = $pdo->prepare("SELECT label FROM pf_expenses WHERE MONTH(date_exp) = ? AND YEAR(date_exp) = ? AND amount > 0");
// On récupère uniquement les libellés des dépenses (montant < 0)
$stmtLabels = $pdo->prepare("SELECT label FROM pf_expenses WHERE MONTH(date_exp) = ? AND YEAR(date_exp) = ? AND amount < 0");
$stmtLabels->execute([$currentMonth, $currentYear]);
$realExpensesLabels = $stmtLabels->fetchAll(PDO::FETCH_COLUMN);
// Snapshot Bancaire (Sert uniquement pour l'affichage "Actuel", plus pour le "Théorique")
// Snapshot Bancaire
$snapshot = ['date' => date('Y-m-d'), 'amount' => 0];
try {
$snapStmt = $pdo->query("SELECT * FROM pf_bank_snapshots ORDER BY id DESC LIMIT 1");
@@ -179,20 +185,22 @@ try {
$solde_actuel = $snapshot['amount'];
// Lecture Budget Prévisionnel (Sert pour les cartes et pour calculer le Reste à venir)
// Lecture Budget Prévisionnel
$stmt = $pdo->query("SELECT id, name, amount, type, category, is_estimate, payment_day, is_checked, mapping_keywords FROM pf_budget_items ORDER BY name ASC");
while ($item = $stmt->fetch(PDO::FETCH_ASSOC)) {
// Les montants en base ont leur vrai signe (- pour dépense, + pour revenu)
$rawAmount = (float)$item['amount'];
$amt = ($item['type'] === 'Annuel') ? $rawAmount / 12 : $rawAmount;
$absAmount = abs($rawAmount); // On utilise l'absolu pour le visuel des jauges
$amt = ($item['type'] === 'Annuel') ? $absAmount / 12 : $absAmount;
$name = trim($item['name']);
$pDay = (int)$item['payment_day'];
$isChecked = (int)$item['is_checked'];
if ($item['category'] === 'expense' && $item['type'] === 'Mensuel' && (int)$item['is_estimate'] === 0) {
$fixedChargesList[] = $item;
$fixedChargesList[] = ['id' => $item['id'], 'name' => $name, 'amount' => $absAmount]; // Passé en array propre pour l'HTML
}
if ($item['category'] === 'income') {
$incomeList[] = $item;
$incomeList[] = ['id' => $item['id'], 'name' => $name, 'amount' => $absAmount];
$total_income += $amt;
$budget_income_prevu += $amt;
} else {
@@ -215,9 +223,8 @@ while ($item = $stmt->fetch(PDO::FETCH_ASSOC)) {
}
}
// Somme de toutes les charges encore à venir
if (!$isPaid) {
$reste_a_venir += $rawAmount;
$reste_a_venir += $absAmount;
}
}
@@ -225,7 +232,7 @@ while ($item = $stmt->fetch(PDO::FETCH_ASSOC)) {
elseif ($name === 'Estimacio escola') $budget_school = $amt;
elseif ($name === 'Estimation gasolina') $budget_essence = $amt;
elseif ((int)$item['is_estimate'] === 0 && $item['type'] === 'Mensuel' && $item['category'] === 'expense') {
$budget_frais += $rawAmount;
$budget_frais += $absAmount;
}
}
}
@@ -238,7 +245,7 @@ try {
$tempCats = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach($tempCats as $tc) {
if ($tc['type'] === 'debit') {
$total_temp_budget += $tc['budget'];
$total_temp_budget += abs($tc['budget']);
}
}
} catch (Exception $e) {}
@@ -263,7 +270,7 @@ $colorIdx = 0;
foreach ($tempCats as $tc) {
$catKey = 'TEMP_' . $tc['id'];
$categoriesConfig[$catKey] = [
'type' => $tc['type'], 'label' => $tc['name'], 'budget' => $tc['budget'], 'color' => $tempColors[$colorIdx++ % count($tempColors)], 'suggestions' => [], 'is_temp' => true, 'id' => $tc['id']
'type' => $tc['type'], 'label' => $tc['name'], 'budget' => abs($tc['budget']), 'color' => $tempColors[$colorIdx++ % count($tempColors)], 'suggestions' => [], 'is_temp' => true, 'id' => $tc['id']
];
}
$categoriesConfig['Autres'] = ['type'=>'debit', 'label'=>'Autres / Imprévus', 'budget'=>$budget_autres, 'color'=>'#64748b', 'suggestions'=>['Restaurant', 'Cadeau']];
@@ -275,7 +282,32 @@ $categoriesConfig['LivretA'] = ['type'=>'debit', 'label'=>'Epargne', 'budget'=>0
$csvData = [];
$showPreview = false;
// ... (Gestion de l'upload CSV inchangée, elle se fait plus haut) ...
if (isset($_FILES['csv_file']) && $_FILES['csv_file']['error'] == 0) {
$file = $_FILES['csv_file']['tmp_name'];
$handle = fopen($file, "r");
$rules = []; try { $rules = $pdo->query("SELECT keyword, category FROM pf_import_rules")->fetchAll(PDO::FETCH_KEY_PAIR); } catch(Exception $e){}
$existingRefs = []; try { $existingRefs = $pdo->query("SELECT import_ref FROM pf_expenses WHERE import_ref IS NOT NULL")->fetchAll(PDO::FETCH_COLUMN); } catch(Exception $e){}
fgetcsv($handle, 1000, ";", "\"", "\\");
while (($data = fgetcsv($handle, 1000, ";", "\"", "\\")) !== FALSE) {
$rawDebit = $data[8] ?? ''; $rawCredit = $data[9] ?? '';
$amount = 0; $isCredit = 0;
if (!empty(trim($rawCredit))) { $amount = abs((float)str_replace(',', '.', str_replace(' ', '', $rawCredit))); $isCredit = 1; }
elseif (!empty(trim($rawDebit))) { $amount = abs((float)str_replace(',', '.', str_replace(' ', '', $rawDebit))); }
else continue;
$dateParts = explode('/', $data[0]);
$dateSql = (count($dateParts) == 3) ? $dateParts[2].'-'.$dateParts[1].'-'.$dateParts[0] : date('Y-m-d');
$label = trim($data[1]) ?: trim($data[2]);
$refCSV = trim($data[3]);
$uniqueKey = !empty($refCSV) ? "REF_".$refCSV : "HASH_".md5($dateSql.$label.number_format($amount, 2).$isCredit);
$isDuplicate = in_array($uniqueKey, $existingRefs);
$suggestedCat = '';
foreach ($rules as $kw => $c) { if (stripos($label, $kw) !== false) { $suggestedCat = $c; break; } }
$csvData[] = ['date'=>$dateSql, 'label'=>$label, 'amount'=>$amount, 'cat'=>$suggestedCat, 'ref'=>$uniqueKey, 'is_duplicate'=>$isDuplicate, 'is_credit'=>$isCredit];
}
fclose($handle);
$showPreview = true;
}
// DÉPENSES EN BDD
$stmt = $pdo->prepare("SELECT * FROM pf_expenses WHERE MONTH(date_exp) = ? AND YEAR(date_exp) = ? ORDER BY date_exp DESC");
@@ -285,7 +317,6 @@ $allExpenses = $stmt->fetchAll(PDO::FETCH_ASSOC);
$totals = array_fill_keys(array_keys($categoriesConfig), 0);
$expensesByCategory = array_fill_keys(array_keys($categoriesConfig), []);
// --- PREPARATION SOLDE THEORIQUE ---
$capacite_max = 0;
$depenses_reelles = 0;
@@ -293,55 +324,43 @@ foreach ($allExpenses as $exp) {
$cat = $exp['category'];
if (!isset($totals[$cat])) $cat = 'Autres';
$val = (float)$exp['amount'];
$val = (float)$exp['amount']; // NOUVELLE RÈGLE : + = Revenu/Remboursement, - = Dépense
// 1. Remplissage pour l'affichage visuel des cartes
// 1. Remplissage Visuel des cartes
if ($cat === 'Income') {
$totals[$cat] += abs($val);
} else {
if ($val < 0) {
$categoriesConfig[$cat]['budget'] += abs($val);
} else {
$totals[$cat] += $val;
} else {
if ($val > 0) {
// C'est un remboursement d'une dépense (+), il augmente le budget
$categoriesConfig[$cat]['budget'] += $val;
} else {
// C'est une dépense normale (-), on l'ajoute au total dépensé (en valeur absolue pour l'UI)
$totals[$cat] += abs($val);
}
}
$expensesByCategory[$cat][] = $exp;
// 2. Calcul des briques du Solde Théorique (Respect des signes BDD)
if ($val < 0) {
// L'argent qui RENTRE sur le compte est stocké en négatif
// 2. Calcul du Théorique
if ($val > 0) {
if ($cat === 'Income' || $cat !== 'Frais') {
// Règle 1 et 2 : Somme Revenus + Tout autre virement positif HORS charges fixes
$capacite_max += abs($val);
$capacite_max += $val;
} else {
// C'est un remboursement d'une charge fixe, il vient diminuer les dépenses
$depenses_reelles -= abs($val);
$depenses_reelles -= $val;
}
} else {
// L'argent qui SORT (dépense) est stocké en positif
// Règle 3 : Somme de tous les autres virements sortants
$depenses_reelles += $val;
$depenses_reelles += abs($val);
}
}
// ============================================================================
// CALCUL FINAL DU SOLDE THÉORIQUE
// ============================================================================
// On applique ta règle exacte :
$solde_theorique = $capacite_max - $depenses_reelles - $reste_a_venir;
// Sécurité : Si 0 injection ce mois-ci, on se base sur le prévisionnel pour avoir une jauge visuelle
if ($capacite_max <= 0) {
$capacite_max = $budget_income_prevu > 0 ? $budget_income_prevu : 1;
}
// --- Calculs pour la Barre de Déchargement ---
$solde_actuel = max(0, $snapshot['amount']);
$charges_a_venir = max(0, $reste_a_venir);
$solde_net = max(0, $solde_actuel - $charges_a_venir);
$charges_visibles = min($solde_actuel, $charges_a_venir);
$solde_net = max(0, $solde_actuel - $reste_a_venir);
$charges_visibles = min($solde_actuel, $reste_a_venir);
// L'échelle de la jauge (Le Max) (+10% visuel)
$max_scale = max($solde_actuel, $solde_theorique, $capacite_max, 1) * 1.1;
$pct_net = min(100, max(0, ($solde_net / $max_scale) * 100));
@@ -393,7 +412,7 @@ $monthName = $moisFr[(int)$currentMonth] . ' ' . $currentYear;
<div style="padding:15px; background:#f8fafc; border-radius:12px; border:1px solid #e2e8f0;">
<div style="font-size:0.85rem; color:#64748b; margin-bottom:4px;">Solde théorique <span style="font-size:0.75rem;">(au <?= date('d/m') ?>)</span></div>
<div style="font-size:1.4rem; font-weight:700; color:<?= $solde_theorique < 0 ? '#ef4444' : '#334155' ?>;" title="Calcul : Solde du relevé + Apports depuis le relevé - Dépenses depuis le relevé - Charges en attente.">
<div style="font-size:1.4rem; font-weight:700; color:<?= $solde_theorique < 0 ? '#ef4444' : '#334155' ?>;" title="Calcul : Capacité Max - Dépenses Réelles - Charges en attente.">
<?= number_format($solde_theorique, 2, ',', ' ') ?> €
</div>
</div>
@@ -610,10 +629,10 @@ $monthName = $moisFr[(int)$currentMonth] . ' ' . $currentYear;
<span title="Lié à une charge/revenu" style="font-size:0.7rem; cursor:help;">🔗</span>
<?php endif; ?>
</td>
<?php if($exp['amount'] < 0): ?>
<td style="padding:10px 15px; text-align:right; font-weight:600; color:#10b981;">+<?= number_format(abs($exp['amount']), 2) ?></td>
<?php if($exp['amount'] > 0): ?>
<td style="padding:10px 15px; text-align:right; font-weight:600; color:#10b981;">+<?= number_format($exp['amount'], 2) ?></td>
<?php else: ?>
<td style="padding:10px 15px; text-align:right; font-weight:600; color:#1e293b;">-<?= number_format($exp['amount'], 2) ?></td>
<td style="padding:10px 15px; text-align:right; font-weight:600; color:#1e293b;">-<?= number_format(abs($exp['amount']), 2) ?></td>
<?php endif; ?>
<td style="width:60px; padding-right:10px; text-align:right; white-space:nowrap;">
<button onclick='openEditModal(<?= json_encode($exp) ?>)'
@@ -640,7 +659,7 @@ $monthName = $moisFr[(int)$currentMonth] . ' ' . $currentYear;
<div id="manualExpenseModal" class="pf-modal">
<div class="pf-modal-content" style="max-width:400px;">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:20px;">
<h3 style="margin:0;" id="modalTitle">Nouvelle dépense</h3>
<h3 style="margin:0;" id="modalTitle">Nouvelle transaction</h3>
<button type="button" onclick="closeSuiviModal('manualExpenseModal')" style="border:none; background:none; font-size:1.8rem; cursor:pointer; color:#64748b; line-height:1;">&times;</button>
</div>
@@ -799,7 +818,6 @@ function handleModalCatChange(select) {
const selectFrais = document.getElementById('fraisSelect');
const selectIncome = document.getElementById('incomeSelect');
// Reset visibility
blockText.style.display = 'none';
blockSelect.style.display = 'none';
blockFrais.style.display = 'none';
@@ -810,11 +828,10 @@ function handleModalCatChange(select) {
selectFrais.required = false;
selectIncome.required = false;
// Affichage conditionnel des Vacances (Si Epargne/LivretA OU si la catégorie contient le mot vacance)
if (catKey === 'LivretA' || catText.includes('vacance')) {
blockHoliday.style.display = 'block';
} else {
document.getElementById('modalHolidayId').value = ''; // On reset si on cache
document.getElementById('modalHolidayId').value = '';
}
if (catKey === 'School') {
@@ -869,14 +886,15 @@ function openAddModal(catKey, catLabel) {
// Ouvre la modale pour MODIFIER
function openEditModal(expenseData) {
openSuiviModal('manualExpenseModal');
document.getElementById('modalTitle').innerText = "Modifier la dépense";
document.getElementById('modalTitle').innerText = "Modifier la transaction";
document.getElementById('modalExpenseId').value = expenseData.id;
document.getElementById('modalDate').value = expenseData.date_exp;
document.getElementById('modalLabelInput').value = expenseData.label;
const rawAmount = parseFloat(expenseData.amount);
document.getElementById('modalIsCredit').value = rawAmount < 0 ? "1" : "0";
// LOGIQUE INVERSÉE POUR L'INTERFACE : Si > 0 c'est un crédit
document.getElementById('modalIsCredit').value = rawAmount > 0 ? "1" : "0";
document.getElementById('modalAmount').value = Math.abs(rawAmount);
document.getElementById('modalHolidayId').value = expenseData.holiday_id || "";
@@ -918,7 +936,6 @@ function handleLineCatChange(select) {
const catKey = select.value;
const catText = select.options[select.selectedIndex].text.toLowerCase();
// Reset
fraisSelect.style.display = 'none';
incomeSelect.style.display = 'none';
holidaySelect.style.display = 'none';
@@ -926,7 +943,6 @@ function handleLineCatChange(select) {
fraisSelect.value = '';
incomeSelect.value = '';
// Condition d'affichage pour les vacances
if (catKey === 'LivretA' || catText.includes('vacance')) {
holidaySelect.style.display = 'block';
} else {