query("SELECT id, name, user_id, role, color FROM pf_people WHERE role NOT IN ('enfant', 'nounou') AND is_active = 1 ORDER BY id ASC"); $budgetParents = $stmtPeople->fetchAll(PDO::FETCH_ASSOC); // Sécurité : au cas où aucun adulte n'est trouvé, on évite un crash if (empty($budgetParents)) { $budgetParents[] = ['id' => 0, 'name' => 'Utilisateur', 'color' => '#0891b2']; } $currentYear = date('Y'); // Cartographie dynamique (Supporte 1, 2 ou N adultes) $parentMapping = []; foreach ($budgetParents as $index => $parent) { $num = $index + 1; $parentMapping[] = [ 'id' => (int)$parent['id'], 'name' => $parent['name'], 'css' => 'p' . $num, 'color' => $parent['color'] ?? (($num === 1) ? '#0891b2' : '#f59e0b') ]; } // 1.5 Récupération des VRAIS comptes bancaires créés dans les paramètres $stmtAccounts = $pdo->query("SELECT name FROM pf_bank_accounts ORDER BY is_default DESC, name ASC"); $bankAccounts = $stmtAccounts->fetchAll(PDO::FETCH_COLUMN); // 2. Récupération Config Salaires $salaryConfig = []; $stmt = $pdo->prepare("SELECT * FROM pf_salary_config WHERE year = ?"); $stmt->execute([$currentYear]); while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { $salaryConfig[$row['person']] = $row; } // Sécurité profils de salaire vides (Garantit l'affichage à 0 même si non configuré) foreach ($parentMapping as $map) { if (!isset($salaryConfig[$map['name']])) { $salaryConfig[$map['name']] = ['salary'=>0, 'mensualite'=>0, 'frais_func'=>0, 'eco_perso'=>0, 'eco_family'=>0]; } } // 3. Récupération Catégories $cats = $pdo->query("SELECT * FROM pf_alloc_categories ORDER BY sort_order ASC, id ASC")->fetchAll(PDO::FETCH_ASSOC); // 4. Gestion du mois FOCUS et Navigation $focusDate = isset($_GET['focus_date']) ? $_GET['focus_date'] : date('Y-m-01'); $focusTs = strtotime($focusDate); $months = []; for ($i = 0; $i < 6; $i++) { $months[] = date('Y-m-01', strtotime("-$i months", $focusTs)); } $prevMonthLink = date('Y-m-01', strtotime("-1 month", $focusTs)); $nextMonthLink = date('Y-m-01', strtotime("+1 month", $focusTs)); $cycleConfigs = []; $stmtNotes = $pdo->query("SELECT reference_id, content FROM pf_notes WHERE note_type = 'month_config'"); while ($row = $stmtNotes->fetch(PDO::FETCH_ASSOC)) { $parts = explode('-', $row['reference_id']); if (count($parts) == 2) { $mKey = $parts[1] . '-' . $parts[0] . '-01'; $cycleConfigs[$mKey] = json_decode($row['content'], true); } } // 5. Récupération Valeurs Répartition Relationnelles $inQuery = implode(',', array_fill(0, count($months), '?')); $stmt = $pdo->prepare("SELECT * FROM pf_alloc_values WHERE month_date IN ($inQuery)"); $stmt->execute($months); $allocs = []; while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { $allocs[$row['month_date']][$row['cat_id']][$row['person_id']] = (float)$row['amount']; } // 6. Récupération de l'ID de la catégorie système $sysCatId = null; foreach ($cats as $key => $c) { if ($c['name'] === 'SYSTEM_VALIDATION') { $sysCatId = $c['id']; unset($cats[$key]); break; } } // Statuts de validation $focusDate = $months[0]; $isValidated = []; foreach ($parentMapping as $map) { $isValidated[$map['css']] = false; if ($sysCatId && isset($allocs[$focusDate][$sysCatId][$map['id']])) { $isValidated[$map['css']] = ($allocs[$focusDate][$sysCatId][$map['id']] == 1); } } $stmtNote = $pdo->prepare("SELECT content FROM pf_notes WHERE note_type = 'budget_prev' AND reference_id = ?"); $stmtNote->execute([$focusDate]); $currentNote = $stmtNote->fetchColumn(); $activeHolidays = $pdo->query("SELECT id, title FROM pf_holidays WHERE status IN ('draft', 'planned', 'booked') ORDER BY start_date ASC")->fetchAll(PDO::FETCH_ASSOC); function getTranslatedMonthName($dateString) { $m = date('m', strtotime($dateString)); $y = date('Y', strtotime($dateString)); return tr('month_' . $m) . ' ' . $y; } // --- 🧠 PREPARATION DATA TRICOUNT / AVANCES (Dynamique) --- $stmtAdvancesList = $pdo->query("SELECT * FROM pf_advances WHERE is_resolved = 0 ORDER BY advance_date DESC"); $activeAdvances = $stmtAdvancesList->fetchAll(PDO::FETCH_ASSOC); $advTotal = []; $livretTotal = []; $labelsCC = []; $labelsLivret = []; foreach ($parentMapping as $map) { $advTotal[$map['name']] = 0; $livretTotal[$map['name']] = 0; $labelsCC[$map['name']] = []; $labelsLivret[$map['name']] = []; } foreach ($activeAdvances as $adv) { $p = $adv['payer']; $amt = (float)$adv['amount']; $labelStr = htmlspecialchars($adv['description']) . ' (' . number_format($amt, 0, ',', ' ') . '€)'; // Si un ancien nom traîne en base, on l'initialise if (!isset($advTotal[$p])) { $advTotal[$p] = 0; $livretTotal[$p] = 0; $labelsCC[$p] = []; $labelsLivret[$p] = []; } if ($adv['from_savings']) { $livretTotal[$p] += $amt; $labelsLivret[$p][] = $labelStr; } else { $advTotal[$p] += $amt; $labelsCC[$p][] = $labelStr; } } // Calcul de la dette croisée (Valable surtout si 2 parents) $balanceDiff = 0; $owedTo = ''; if (count($parentMapping) >= 2) { $p1 = $parentMapping[0]['name']; $p2 = $parentMapping[1]['name']; $balanceDiff = abs(($advTotal[$p1] ?? 0) - ($advTotal[$p2] ?? 0)); if (($advTotal[$p1] ?? 0) > ($advTotal[$p2] ?? 0)) $owedTo = $p1; elseif (($advTotal[$p2] ?? 0) > ($advTotal[$p1] ?? 0)) $owedTo = $p2; } ?>


()

()
" . sprintf(tr('bud_sav_from_date'), $cStart) . ""; } ?>
Global
Total 0 0
(Eco Family) - 0
Info
0) echo 'Obj: ' . round((float)$cat['target']) . '€ '; ?>
0

📝

1): ?>

$map): $pName = $map['name']; $bgClass = ($idx === 0) ? 'rgba(8, 145, 178, 0.06)' : 'rgba(217, 119, 6, 0.06)'; $bdClass = ($idx === 0) ? 'rgba(8, 145, 178, 0.2)' : 'rgba(217, 119, 6, 0.2)'; $colorMain = ($idx === 0) ? '#0891b2' : '#d97706'; $colorDark = ($idx === 0) ? '#164e63' : '#78350f'; ?>
0): ?>
+
🏛️
0.01): ?>
$m) { if($m['name'] === $adv['payer']) { $colorP = ($idx === 0) ? '#0891b2' : '#d97706'; break; } } ?>
-
Global
0 € 0 €
0 € 0 €

✏️

0 €