This commit is contained in:
2026-03-20 16:35:04 +01:00
parent faaf89e1ab
commit 9b2cc83512
+28 -60
View File
@@ -168,7 +168,7 @@ $stmtLabels = $pdo->prepare("SELECT label FROM pf_expenses WHERE MONTH(date_exp)
$stmtLabels->execute([$currentMonth, $currentYear]); $stmtLabels->execute([$currentMonth, $currentYear]);
$realExpensesLabels = $stmtLabels->fetchAll(PDO::FETCH_COLUMN); $realExpensesLabels = $stmtLabels->fetchAll(PDO::FETCH_COLUMN);
// Snapshot // Snapshot Bancaire (Sert uniquement pour l'affichage "Actuel", plus pour le "Théorique")
$snapshot = ['date' => date('Y-m-d'), 'amount' => 0]; $snapshot = ['date' => date('Y-m-d'), 'amount' => 0];
try { try {
$snapStmt = $pdo->query("SELECT * FROM pf_bank_snapshots ORDER BY id DESC LIMIT 1"); $snapStmt = $pdo->query("SELECT * FROM pf_bank_snapshots ORDER BY id DESC LIMIT 1");
@@ -178,24 +178,8 @@ try {
} catch (Exception $e) {} } catch (Exception $e) {}
$solde_actuel = $snapshot['amount']; $solde_actuel = $snapshot['amount'];
$solde_theorique = $solde_actuel; // On part du solde actuel
$today_day = (int)date('j');
// CALCUL DU THEORIQUE PARTIE 1 : Appliquer les mouvements saisis après la date du relevé // Lecture Budget Prévisionnel (Sert pour les cartes et pour calculer le Reste à venir)
if (!empty($snapshot['date'])) {
try {
$stmtCalc = $pdo->prepare("SELECT SUM(amount) as total_diff FROM pf_expenses WHERE date_exp > ?");
$stmtCalc->execute([$snapshot['date']]);
$resDiff = $stmtCalc->fetch(PDO::FETCH_ASSOC);
if ($resDiff && $resDiff['total_diff'] !== null) {
// total_diff est positif pour les dépenses, négatif pour les revenus.
// On le soustrait donc au solde théorique.
$solde_theorique -= (float)$resDiff['total_diff'];
}
} catch (Exception $e) {}
}
// 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"); $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)) { while ($item = $stmt->fetch(PDO::FETCH_ASSOC)) {
$rawAmount = (float)$item['amount']; $rawAmount = (float)$item['amount'];
@@ -231,12 +215,9 @@ while ($item = $stmt->fetch(PDO::FETCH_ASSOC)) {
} }
} }
// Somme de toutes les charges encore à venir
if (!$isPaid) { if (!$isPaid) {
$reste_a_venir += $rawAmount; $reste_a_venir += $rawAmount;
// CALCUL DU THEORIQUE PARTIE 2 : Déduire les charges qui auraient dû passer
if ($pDay > 0 && $pDay <= $today_day) {
$solde_theorique -= $rawAmount;
}
} }
} }
@@ -294,32 +275,7 @@ $categoriesConfig['LivretA'] = ['type'=>'debit', 'label'=>'Epargne', 'budget'=>0
$csvData = []; $csvData = [];
$showPreview = false; $showPreview = false;
if (isset($_FILES['csv_file']) && $_FILES['csv_file']['error'] == 0) { // ... (Gestion de l'upload CSV inchangée, elle se fait plus haut) ...
$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 // DÉPENSES EN BDD
$stmt = $pdo->prepare("SELECT * FROM pf_expenses WHERE MONTH(date_exp) = ? AND YEAR(date_exp) = ? ORDER BY date_exp DESC"); $stmt = $pdo->prepare("SELECT * FROM pf_expenses WHERE MONTH(date_exp) = ? AND YEAR(date_exp) = ? ORDER BY date_exp DESC");
@@ -329,8 +285,9 @@ $allExpenses = $stmt->fetchAll(PDO::FETCH_ASSOC);
$totals = array_fill_keys(array_keys($categoriesConfig), 0); $totals = array_fill_keys(array_keys($categoriesConfig), 0);
$expensesByCategory = array_fill_keys(array_keys($categoriesConfig), []); $expensesByCategory = array_fill_keys(array_keys($categoriesConfig), []);
// Préparation de la capacité max // --- PREPARATION SOLDE THEORIQUE ---
$capacite_max = 0; $capacite_max = 0;
$depenses_reelles = 0;
foreach ($allExpenses as $exp) { foreach ($allExpenses as $exp) {
$cat = $exp['category']; $cat = $exp['category'];
@@ -338,7 +295,7 @@ foreach ($allExpenses as $exp) {
$val = (float)$exp['amount']; $val = (float)$exp['amount'];
// Remplissage des totaux des cartes // 1. Remplissage pour l'affichage visuel des cartes
if ($cat === 'Income') { if ($cat === 'Income') {
$totals[$cat] += abs($val); $totals[$cat] += abs($val);
} else { } else {
@@ -350,30 +307,41 @@ foreach ($allExpenses as $exp) {
} }
$expensesByCategory[$cat][] = $exp; $expensesByCategory[$cat][] = $exp;
// Calcul de la Capacité Max de la jauge // 2. Calcul des briques du Solde Théorique (Respect des signes BDD)
if ($cat === 'Income') { if ($val < 0) {
// Règle 1 : Somme des virements Revenus (val est négatif en base) // L'argent qui RENTRE sur le compte est stocké en négatif
$capacite_max -= $val; if ($cat === 'Income' || $cat !== 'Frais') {
} else { // Règle 1 et 2 : Somme Revenus + Tout autre virement positif HORS charges fixes
// Règle 2 : Tout autre virement positif (val est négatif) non charge fixe $capacite_max += abs($val);
if ($val < 0 && $cat !== 'Frais') { } else {
$capacite_max += abs($val); // C'est un remboursement d'une charge fixe, il vient diminuer les dépenses
$depenses_reelles -= abs($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;
} }
} }
// ============================================================================
// 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 // Sécurité : Si 0 injection ce mois-ci, on se base sur le prévisionnel pour avoir une jauge visuelle
if ($capacite_max <= 0) { if ($capacite_max <= 0) {
$capacite_max = $budget_income_prevu > 0 ? $budget_income_prevu : 1; $capacite_max = $budget_income_prevu > 0 ? $budget_income_prevu : 1;
} }
// --- Calculs finaux pour la Barre de Déchargement --- // --- Calculs pour la Barre de Déchargement ---
$solde_actuel = max(0, $snapshot['amount']); $solde_actuel = max(0, $snapshot['amount']);
$charges_a_venir = max(0, $reste_a_venir); $charges_a_venir = max(0, $reste_a_venir);
$solde_net = max(0, $solde_actuel - $charges_a_venir); $solde_net = max(0, $solde_actuel - $charges_a_venir);
$charges_visibles = min($solde_actuel, $charges_a_venir); $charges_visibles = min($solde_actuel, $charges_a_venir);
// Echelle Max (+10% pour l'esthétique) // L'échelle de la jauge (Le Max) (+10% visuel)
$max_scale = max($solde_actuel, $solde_theorique, $capacite_max, 1) * 1.1; $max_scale = max($solde_actuel, $solde_theorique, $capacite_max, 1) * 1.1;
$pct_net = min(100, max(0, ($solde_net / $max_scale) * 100)); $pct_net = min(100, max(0, ($solde_net / $max_scale) * 100));