fix epargne
Deploy HouseHub / deploy (push) Successful in 1s

This commit is contained in:
2026-06-17 13:04:03 +02:00
parent 96df90d372
commit e73524b2ae
2 changed files with 66 additions and 47 deletions
+61 -43
View File
@@ -12,7 +12,7 @@ $stmtSalaries->execute([$currentYear]);
$salaries = $stmtSalaries->fetchAll(PDO::FETCH_ASSOC); $salaries = $stmtSalaries->fetchAll(PDO::FETCH_ASSOC);
// 3. Récupération des Items du Budget (Charges Fixes et Estimations) // 3. Récupération des Items du Budget (Charges Fixes et Estimations)
$stmt = $pdo->query("SELECT * FROM pf_budget_items ORDER BY is_estimate ASC, sort_order ASC, name ASC"); $stmt = $pdo->query("SELECT * FROM pf_budget_items WHERE category != 'SAVINGS' ORDER BY is_estimate ASC, sort_order ASC, name ASC");
$items = $stmt->fetchAll(PDO::FETCH_ASSOC); $items = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 4. Gestion du mois actif // 4. Gestion du mois actif
@@ -21,22 +21,36 @@ $defaultActiveMonth = $stmtActive->fetchColumn() ?: date('Y-m-01');
$currentMonth = isset($_GET['m']) ? str_pad((int)$_GET['m'], 2, '0', STR_PAD_LEFT) : date('m', strtotime($defaultActiveMonth)); $currentMonth = isset($_GET['m']) ? str_pad((int)$_GET['m'], 2, '0', STR_PAD_LEFT) : date('m', strtotime($defaultActiveMonth));
$viewMonthDate = "$currentYear-$currentMonth-01"; $viewMonthDate = "$currentYear-$currentMonth-01";
// 5. Récupération du Réel (Dépenses) // 5. Récupération optimisée et unifiée du Réel
$stmtReal = $pdo->prepare("SELECT budget_item_id, SUM(amount) as total_real FROM pf_expenses WHERE gestion_month = ? AND budget_item_id IS NOT NULL GROUP BY budget_item_id"); // On récupère tout en une seule requête pour éviter les décalages entre ID et Catégorie
$stmtReal = $pdo->prepare("
SELECT budget_item_id, category, SUM(amount) as total_real
FROM pf_expenses
WHERE gestion_month = ?
GROUP BY budget_item_id, category
");
$stmtReal->execute([$viewMonthDate]); $stmtReal->execute([$viewMonthDate]);
$realTotals = $stmtReal->fetchAll(PDO::FETCH_KEY_PAIR); $allExpenses = $stmtReal->fetchAll(PDO::FETCH_ASSOC);
$stmtCatReal = $pdo->prepare("SELECT category, SUM(amount) as total_real FROM pf_expenses WHERE gestion_month = ? AND budget_item_id IS NULL GROUP BY category"); // On initialise les tableaux de correspondance
$stmtCatReal->execute([$viewMonthDate]); $realTotalsById = []; // Pour les lignes liées par ID
$catTotals = $stmtCatReal->fetchAll(PDO::FETCH_KEY_PAIR); $realTotalsByCat = []; // Pour les lignes orphelines (NULL) liées par Catégorie
$stmtLabels = $pdo->prepare("SELECT label, amount FROM pf_expenses WHERE gestion_month = ? AND budget_item_id IS NULL"); foreach ($allExpenses as $row) {
if (!empty($row['budget_item_id'])) {
$realTotalsById[$row['budget_item_id']] = (float)$row['total_real'];
} else {
$realTotalsByCat[$row['category']] = (float)$row['total_real'];
}
}
// Récupération des détails pour le mapping par mots-clés (si besoin de précision)
$stmtLabels = $pdo->prepare("SELECT label, amount, category FROM pf_expenses WHERE gestion_month = ? AND budget_item_id IS NULL");
$stmtLabels->execute([$viewMonthDate]); $stmtLabels->execute([$viewMonthDate]);
$unlinkedExpenses = $stmtLabels->fetchAll(PDO::FETCH_ASSOC); $unlinkedExpenses = $stmtLabels->fetchAll(PDO::FETCH_ASSOC);
$moisFr = ['', 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre']; // Gestion des libellés et totaux
$currentMonthName = tr('month_' . str_pad((int)$currentMonth, 2, '0', STR_PAD_LEFT)) . ' ' . $currentYear; $currentMonthName = tr('month_' . str_pad((int)$currentMonth, 2, '0', STR_PAD_LEFT)) . ' ' . $currentYear;
$totalDepenses = 0; $totalDepenses = 0;
$totalRevenus = 0; $totalRevenus = 0;
?> ?>
@@ -88,41 +102,45 @@ $totalRevenus = 0;
<?php endforeach; ?> <?php endforeach; ?>
<?php foreach ($items as $item): <?php foreach ($items as $item):
$targetAbs = abs((float)$item['amount']); // 1. Calculs de base
$amountToAdd = ($item['type'] === 'Annuel') ? $targetAbs / 12 : $targetAbs; $targetAbs = abs((float)$item['amount']);
$totalDepenses += $amountToAdd; $amountToAdd = ($item['type'] === 'Annuel') ? $targetAbs / 12 : $targetAbs;
$totalDepenses += $amountToAdd;
$realSum = 0;
$hasMatchingExpense = false; // 2. RÉINITIALISATION STRICTE ET CALCUL DU RÉEL
$realSum = 0;
$hasMatchingExpense = false;
// A. Correspondance par ID direct // A. Correspondance par ID direct (Priorité 1)
if (isset($realTotals[$item['id']])) { if (isset($realTotalsById[$item['id']])) {
$realSum = $realTotals[$item['id']]; $realSum = (float)$realTotalsById[$item['id']];
$hasMatchingExpense = true; $hasMatchingExpense = true;
} }
// B. Correspondance par Catégorie système // B. Correspondance par Catégorie système (Priorité 2 : rattrape les NULL de Juin)
elseif (!empty($item['category']) && isset($catTotals[$item['category']])) { elseif (!empty($item['category']) && isset($realTotalsByCat[$item['category']])) {
$realSum = $catTotals[$item['category']]; $realSum = (float)$realTotalsByCat[$item['category']];
$hasMatchingExpense = true; $hasMatchingExpense = true;
} }
// C. Correspondance par mots-clés bancaires // C. Correspondance par mots-clés bancaires (Priorité 3 : affinement manuel)
elseif (!empty($item['mapping_keywords'])) { elseif (!empty($item['mapping_keywords'])) {
$keywords = array_map('trim', explode(',', $item['mapping_keywords'])); $keywords = array_map('trim', explode(',', $item['mapping_keywords']));
foreach ($unlinkedExpenses as $uexp) { foreach ($unlinkedExpenses as $uexp) {
foreach ($keywords as $kw) { foreach ($keywords as $kw) {
if (!empty($kw) && stripos($uexp['label'], $kw) !== false) { if (!empty($kw) && stripos($uexp['label'], $kw) !== false) {
$realSum += (float)$uexp['amount']; $realSum += (float)$uexp['amount'];
$hasMatchingExpense = true; $hasMatchingExpense = true;
break; break;
} }
} }
} }
} }
$realAbs = abs($realSum); // 3. Finalisation de la ligne
$isAutoChecked = ($hasMatchingExpense && ($realAbs >= ($targetAbs - 0.10))); $realAbs = abs($realSum);
$rowClass = 'row-expense' . ($item['is_estimate'] ? ' row-estimate' : ''); // Un item est validé si le montant réel est proche du prévu
?> $isAutoChecked = ($hasMatchingExpense && ($realAbs >= ($targetAbs - 0.10)));
$rowClass = 'row-expense' . ($item['is_estimate'] ? ' row-estimate' : '');
?>
<tr class="<?= $rowClass ?>" style="border-bottom:1px solid var(--border-light);"> <tr class="<?= $rowClass ?>" style="border-bottom:1px solid var(--border-light);">
<td style="padding:15px;"> <td style="padding:15px;">
<strong><?= htmlspecialchars($item['name']) ?></strong> <strong><?= htmlspecialchars($item['name']) ?></strong>
+5 -4
View File
@@ -230,9 +230,9 @@ while ($item = $stmt->fetch(PDO::FETCH_ASSOC)) {
$absAmount = abs((float)$item['amount']); $absAmount = abs((float)$item['amount']);
$amt = ($item['type'] === 'Annuel') ? $absAmount / 12 : $absAmount; $amt = ($item['type'] === 'Annuel') ? $absAmount / 12 : $absAmount;
$name = trim($item['name']); $name = trim($item['name']);
$catCode = $item['category']; // Ex: FIXED, FMCG, INCOME... $catCode = $item['category']; // Ex: FIXED, FMCG, INCOME ou income
$isIncome = (isset($categoriesConfig[$catCode]) && $categoriesConfig[$catCode]['db_type'] === 'Income'); $isIncome = (strtoupper($catCode) === 'INCOME' || (float)$item['amount'] > 0);
if ($isIncome) { if ($isIncome) {
$incomeList[] = ['id' => $item['id'], 'name' => $name, 'amount' => $absAmount]; $incomeList[] = ['id' => $item['id'], 'name' => $name, 'amount' => $absAmount];
@@ -621,10 +621,11 @@ $monthName = $monthNames[(int)$viewM] . ' ' . $viewY;
</select> </select>
</div> </div>
<!-- 🛠️ FIX VISUEL : On demande la personne concernée (Bénéficiaire) -->
<div class="form-group" id="blockInputIncome" style="margin-bottom:15px; display:none;"> <div class="form-group" id="blockInputIncome" style="margin-bottom:15px; display:none;">
<label class="pf-label"><?= tr('bud_expected_income') ?></label> <label class="pf-label"><?= tr('bud_beneficiary') ?></label>
<select name="budget_item_id" id="incomeSelect" class="pf-input" disabled> <select name="budget_item_id" id="incomeSelect" class="pf-input" disabled>
<option value=""><?= tr('bud_select_beneficiary') ?> </option> <option value=""><?= tr('gift_filter_all_adults') ?></option>
<?php foreach ($incomeList as $inc): ?><option value="<?= $inc['id'] ?>"><?= htmlspecialchars($inc['name']) ?></option><?php endforeach; ?> <?php foreach ($incomeList as $inc): ?><option value="<?= $inc['id'] ?>"><?= htmlspecialchars($inc['name']) ?></option><?php endforeach; ?>
</select> </select>
</div> </div>