estimation frais
Deploy HouseHub / deploy (push) Successful in 1s

This commit is contained in:
FeFeClochette committed 2026-09-15 19:18:38 +02:00
1 parent 4cfef07dc6
commit c3eae9e1d4
10 files changed
+503 -17

No files matched your search

+21
View File
@@ -128,6 +128,23 @@ $totalRevenus = 0;
foreach ($items as $item):
// 1. Calculs de base
$targetAbs = abs((float)$item['amount']);
// --- 🚀 INTERCEPTION DYNAMIQUE ---
$calcDetails = "";
if (isset($item['is_dynamic']) && $item['is_dynamic'] == 1 && !empty($item['dynamic_code'])) {
require_once __DIR__ . '/../includes/DynamicBudgetCalculator.php';
// Facturation à terme échu : on recule d'un mois pour le calcul
$prevDate = date('Y-m-d', strtotime('-1 month', strtotime("$currentYear-$currentMonth-01")));
$calcYear = date('Y', strtotime($prevDate));
$calcMonth = date('m', strtotime($prevDate));
$calc = new DynamicBudgetCalculator($pdo, $calcYear, $calcMonth);
$estimateData = $calc->getEstimate($item['dynamic_code']);
$targetAbs = $estimateData['amount'];
$calcDetails = $estimateData['details'];
}
// --------------------------------
$amountToAdd = ($item['type'] === 'Annuel') ? $targetAbs / 12 : $targetAbs;
$totalDepenses += $amountToAdd;
@@ -185,6 +202,10 @@ foreach ($items as $item):
<td class="cell-amount" style="font-weight:600; padding:15px; color:#1e293b;">
- <?= number_format($targetAbs, 2, ',', ' ') ?> €
<?php if (!empty($calcDetails)): ?>
<span title="<?= htmlspecialchars($calcDetails) ?>" style="cursor:help; margin-left:4px; font-size:0.85rem;">ℹ️</span>
<?php endif; ?>
<?php if ($hasMatchingExpense): ?>
<?php $gap = $realAbs - $targetAbs;
if ($gap > 0.05): ?>
+92 -4
View File
@@ -1,4 +1,12 @@
<?php
/**
* @var bool $hasAccounts
* @var bool $hasCategories
* @var bool $hasSalaries
* @var bool $hasBudgetItems
* @var bool $isBudgetSetupOk
*/
// Sécurité : Ce fichier ne doit pas être appelé directement
if (!defined('CURRENCY')) {
define('CURRENCY', '€');
@@ -26,6 +34,7 @@ if (!defined('CURRENCY')) {
<?php if (!$hasSalaries): ?><span class="alert-dot alert-dot-inline">!</span><?php endif; ?>
</button>
<button class="bs-tab-btn" onclick="switchBsTab('csv', this)"><?= tr('bs_tab_csv') ?></button>
<button class="bs-tab-btn" onclick="switchBsTab('children', this)">👶 <?= tr('bud_settings_dyn_title') ?></button>
</div>
<div class="bs-content">
@@ -212,10 +221,59 @@ if (!defined('CURRENCY')) {
</form>
</div>
</div>
</div>
</div>
</div>
<!-- NOUVEAU PANE ENFANTS -->
<div id="pane-children" class="bs-pane">
<h4 class="bs-section-title">👶 <?= tr('bud_settings_dyn_title') ?></h4>
<p class="pf-muted-tiny bs-desc">Configurez ici les tarifs pour le calcul dynamique des frais de garde et de cantine.</p>
<form id="form-dynamic-estimates" onsubmit="saveDynamicEstimates(event)">
<h5 class="bs-section-subtitle bordered">Assistante Maternelle</h5>
<div class="bs-grid-2">
<div>
<label class="pf-label"><?= tr('bud_dyn_nanny_fixed') ?></label>
<input type="number" step="0.01" name="budget_nanny_fixed" id="budget_nanny_fixed" class="pf-input" value="700">
</div>
<div>
<label class="pf-label"><?= tr('bud_dyn_nanny_daily') ?></label>
<input type="number" step="0.01" name="budget_nanny_daily" id="budget_nanny_daily" class="pf-input" value="4">
</div>
<div>
<label class="pf-label"><?= tr('bud_dyn_nanny_aid') ?></label>
<input type="number" step="0.01" name="budget_nanny_aid" id="budget_nanny_aid" class="pf-input" value="120">
</div>
<div>
<label class="pf-label"><?= tr('bud_dyn_nanny_cesu_avg') ?></label>
<input type="number" step="0.01" name="budget_nanny_cesu_avg" id="budget_nanny_cesu_avg" class="pf-input" value="170">
</div>
</div>
<h5 class="bs-section-subtitle bordered" style="margin-top: 20px;">École & Centre de loisirs</h5>
<div class="bs-grid-2">
<div>
<label class="pf-label"><?= tr('bud_dyn_school_meal') ?></label>
<input type="number" step="0.01" name="budget_school_meal" id="budget_school_meal" class="pf-input" value="5.62">
</div>
<div>
<label class="pf-label"><?= tr('bud_dyn_school_aftercare') ?></label>
<input type="number" step="0.01" name="budget_school_aftercare" id="budget_school_aftercare" class="pf-input" value="1.97">
</div>
<div>
<label class="pf-label"><?= tr('bud_dyn_school_fullday') ?></label>
<input type="number" step="0.01" name="budget_school_fullday" id="budget_school_fullday" class="pf-input" value="21.89">
</div>
</div>
<div class="bs-text-right" style="margin-top: 20px;">
<button type="submit" class="btn btn-secondary">💾 <?= tr('btn_save') ?></button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
@@ -273,6 +331,16 @@ async function loadBudgetSettingsData() {
renderSalaries(response.data.salaries, response.data.year);
const currencySelect = document.getElementById('bs-currency-select');
if (currencySelect && response.data.currency) currencySelect.value = response.data.currency;
const bs = response.data.budget_settings || {};
if (document.getElementById('budget_nanny_fixed')) document.getElementById('budget_nanny_fixed').value = bs.budget_nanny_fixed || 700;
if (document.getElementById('budget_nanny_daily')) document.getElementById('budget_nanny_daily').value = bs.budget_nanny_daily || 4;
if (document.getElementById('budget_nanny_aid')) document.getElementById('budget_nanny_aid').value = bs.budget_nanny_aid || 120;
if (document.getElementById('budget_nanny_cesu_avg')) document.getElementById('budget_nanny_cesu_avg').value = bs.budget_nanny_cesu_avg || 170;
if (document.getElementById('budget_school_meal')) document.getElementById('budget_school_meal').value = bs.budget_school_meal || 5.62;
if (document.getElementById('budget_school_aftercare')) document.getElementById('budget_school_aftercare').value = bs.budget_school_aftercare || 1.97;
if (document.getElementById('budget_school_fullday')) document.getElementById('budget_school_fullday').value = bs.budget_school_fullday || 21.89;
} catch (err) {
console.error("Erreur chargement paramètres :", err);
const errorMsg = `<div class="pf-alert pf-alert--error bs-input-mb">❌ ${tr('error_loading_settings')} : ${err.message}</div>`;
@@ -569,4 +637,24 @@ function handleCsvUpload(file) {
};
reader.readAsText(file, 'ISO-8859-1');
}
async function saveDynamicEstimates(e) {
e.preventDefault();
const form = e.target;
const btn = form.querySelector('button');
const oldText = btn.innerText;
btn.innerText = '⏳...';
btn.disabled = true;
try {
const fd = new FormData(form);
fd.append('action', 'save_dynamic_estimates');
await pachaFetch('/modules/budget/includes/api/settings.php', { method: 'POST', body: fd });
if (typeof showToast === 'function') showToast(window.I18N['fc_settings_updated'] || 'Paramètres enregistrés', 'success');
} catch (err) {
if (typeof showToast === 'function') showToast((window.I18N['error_occured'] || 'Erreur') + " : " + err.message, 'error');
} finally {
btn.innerText = oldText;
btn.disabled = false;
}
}
</script>
+25 -4
View File
@@ -287,13 +287,30 @@ while ($item = $stmt->fetch(PDO::FETCH_ASSOC)) {
// 2. C'est une estimation (Variable)
if ((int)$item['is_estimate'] === 1) {
$calcDetails = "";
// --- 🚀 INTERCEPTION DYNAMIQUE ---
if (isset($item['is_dynamic']) && $item['is_dynamic'] == 1 && !empty($item['dynamic_code'])) {
require_once __DIR__ . '/../includes/DynamicBudgetCalculator.php';
// Facturation à terme échu : on recule d'un mois
$prevDate = date('Y-m-d', strtotime('-1 month', strtotime("$viewY-$viewM-01")));
$calcYear = date('Y', strtotime($prevDate));
$calcMonth = date('m', strtotime($prevDate));
$calc = new DynamicBudgetCalculator($pdo, $calcYear, $calcMonth);
$estimateData = $calc->getEstimate($item['dynamic_code']);
$amt = $estimateData['amount'];
$calcDetails = $estimateData['details'];
}
// --------------------------------
$estimatesList[] = [
'name' => $name,
'amount' => $amt,
'categories' => !empty($catCode) ? array_map('trim', explode(',', $catCode)) : []
'categories' => !empty($catCode) ? array_map('trim', explode(',', $catCode)) : [],
'details' => $calcDetails
];
}
// 3. Attribution du budget aux jauges visuelles de la page
// Pour ne pas tout casser, on donne tout le plafond visuel à la 1ère catégorie de la liste
if (!empty($catCode)) {
@@ -352,11 +369,9 @@ foreach ($estimatesList as $est) {
$spentForEstimate = 0;
$detailsHover = [];
// On additionne les dépenses de toutes les catégories liées à cette estimation
foreach ($est['categories'] as $cCode) {
if (!empty($cCode) && isset($totals[$cCode])) {
$spentForEstimate += $totals[$cCode];
// On prépare le détail pour la petite bulle d'info (hover)
if ($totals[$cCode] > 0 && isset($categoriesConfig[$cCode])) {
$detailsHover[] = strip_tags($categoriesConfig[$cCode]['label']) . " : " . number_format($totals[$cCode], 0) . "€";
}
@@ -367,6 +382,12 @@ foreach ($estimatesList as $est) {
if ($rem > 0) {
$reste_a_venir_calc += $rem;
$tooltip = !empty($detailsHover) ? implode(' | ', $detailsHover) : 'Aucune dépense pour le moment';
// --- INJECTION DU DÉTAIL DYNAMIQUE ---
if (!empty($est['details'])) {
$tooltip .= "\n\n📊 Détail du calcul :\n" . $est['details'];
}
$pending_charges[] = [
'name' => 'Reste ' . $est['name'],
'amount' => $rem,