prepare("
SELECT title, amount, expected_date
FROM pf_expected_expenses
WHERE is_paid = 0
AND YEAR(expected_date) = ?
AND MONTH(expected_date) = ?
ORDER BY expected_date ASC
");
$stmtExpenses->execute([$current_year, $current_month]);
$expenses = $stmtExpenses->fetchAll(PDO::FETCH_ASSOC);
$q1_expenses_total = 0;
$q2_expenses_total = 0;
$detail_html = '
';
foreach ($expenses as $e) {
$day = intval(date('d', strtotime($e['expected_date'])));
if ($day <= 15) {
$q1_expenses_total += $e['amount'];
} else {
$q2_expenses_total += $e['amount'];
}
$detail_html .= '- ' . htmlspecialchars($e['title']) . ' (' . number_format($e['amount'], 2, ',', ' ') . ' € le ' . date('d/m', strtotime($e['expected_date'])) . ')
';
}
$detail_html .= '
';
$total_expenses = $q1_expenses_total + $q2_expenses_total;
// 2. Récupération des dettes
$stmtDebts = $pdo->query("SELECT payer, SUM(amount) as total_debt FROM pf_advances WHERE is_resolved = 0 GROUP BY payer");
$debts = $stmtDebts->fetchAll(PDO::FETCH_KEY_PAIR);
// 3. NOUVELLE LOGIQUE : Clearing intelligent (Compensation partielle ou totale)
$total_base_inputs = array_sum(array_map('floatval', $savings_inputs));
$surplus_for_clearing = $total_base_inputs - $total_expenses;
$monthly_savings = 0; // Le vrai total qui sera viré après déduction des dettes
$contributions_html = '';
foreach ($savings_inputs as $person => $amount) {
$base_amount = floatval($amount);
$debt = $debts[$person] ?? 0;
// Formatage bancaire propre pour les textes
$base_fmt = number_format($base_amount, 2, ',', ' ');
if ($debt > 0) {
if ($surplus_for_clearing > 0) {
$compensation = min($debt, $base_amount, $surplus_for_clearing);
$net_amount = $base_amount - $compensation;
$surplus_for_clearing -= $compensation;
$monthly_savings += $net_amount;
$comp_fmt = number_format($compensation, 2, ',', ' ');
$net_fmt = number_format($net_amount, 2, ',', ' ');
$reste_dette = $debt - $compensation;
$txt_reste = ($reste_dette > 0)
? ' (Reste ' . number_format($reste_dette, 2, ',', ' ') . ' € de dette)'
: ' (Dette soldée 🎉)';
// Harmonisation en bleu (#2563eb) pour le montant net à verser
$contributions_html .= '- ' . htmlspecialchars($person) . ' : Base ' . $base_fmt . ' € − Remboursé ' . $comp_fmt . ' € = ' . $net_fmt . ' € à verser' . $txt_reste . '
';
} else {
$monthly_savings += $base_amount;
$contributions_html .= '- ' . htmlspecialchars($person) . ' : ' . $base_fmt . ' € à verser (Dette gelée, liquidités insuffisantes)
';
}
} else {
$monthly_savings += $base_amount;
$contributions_html .= '- ' . htmlspecialchars($person) . ' : ' . $base_fmt . ' € à verser
';
}
}
$contributions_html .= '
';
$contributions_html .= 'Total net atterrissant sur les comptes : ' . number_format($monthly_savings, 2, ',', ' ') . ' €
';
if(empty($expenses)) {
$detail_html = '🎉 Aucune grosse dépense enregistrée sur ce mois.
';
}
// --- MOTEUR DE RÈGLES DES QUINZAINES (Remplacement des ** par ) ---
$instructions = [];
$remaining_to_allocate = $monthly_savings;
// Règle 1 : Première quinzaine
if ($q1_expenses_total > 0) {
if ($remaining_to_allocate >= $q1_expenses_total) {
$remaining_to_allocate -= $q1_expenses_total;
$instructions[] = "💼 Dès le 1er : Laissez " . number_format($q1_expenses_total, 2, ',', ' ') . " € sur le compte commun pour honorer les dépenses de la 1ère quinzaine.";
} else {
$deficit = $q1_expenses_total - $remaining_to_allocate;
$remaining_to_allocate = 0;
$instructions[] = "💼 Dès le 1er : Gardez l'intégralité des apports sur le compte commun.";
$instructions[] = "⚠️ Retrait requis : Retirez " . number_format($deficit, 2, ',', ' ') . " € depuis le Livret A vers le commun pour couvrir la 1ère quinzaine.";
}
}
// Règle 2 : Deuxième quinzaine
if ($q2_expenses_total > 0) {
if ($remaining_to_allocate >= $q2_expenses_total) {
$remaining_to_allocate -= $q2_expenses_total;
$instructions[] = "📈 Dès le 1er : Placez " . number_format($q2_expenses_total, 2, ',', ' ') . " € sur le Livret A pour générer des intérêts sur la 1ère quinzaine.";
$instructions[] = "🔄 Le 16 du mois : Transférez ces " . number_format($q2_expenses_total, 2, ',', ' ') . " € sur le compte commun pour payer la dépense.";
} else {
if ($remaining_to_allocate > 0) {
$instructions[] = "📈 Dès le 1er : Placez le reste des apports (" . number_format($remaining_to_allocate, 2, ',', ' ') . " €) sur le Livret A.";
$instructions[] = "🔄 Le 16 du mois : Retirez " . number_format($q2_expenses_total, 2, ',', ' ') . " € global du Livret A pour payer la fin de mois.";
$remaining_to_allocate = 0;
} else {
$instructions[] = "🔄 Le 16 du mois : Retirez " . number_format($q2_expenses_total, 2, ',', ' ') . " € du Livret A vers le commun. Ne le faites pas avant le 16 !";
}
}
}
// Solde résiduel long terme
if ($remaining_to_allocate > 0) {
$instructions[] = "💰 Épargne stable : Placez les " . number_format($remaining_to_allocate, 2, ',', ' ') . " € restants sur votre Livret A dès le 1er.";
}
// --- CONSTITUTION DU RENDU HTML FINAL ---
$html = '';
// Titre de l'état du Clearing simplifié et clair
$html .= '
🤝 Résumé des apports et remboursements internes :
';
$html .= '
';
$html .= $contributions_html;
$html .= '
';
$html .= '
Analyse des dépenses du mois :
';
$html .= $detail_html;
$html .= '
';
$html .= '
📋 Plan d\'action recommandé :
';
foreach ($instructions as $ins) {
$html .= '
' . $ins . '
';
}
$html .= '
';
echo json_encode(['success' => true, 'html' => $html]);
} catch (PDOException $e) {
echo json_encode(['success' => false, 'message' => 'Calcul impossible : ' . $e->getMessage()]);
}