Sécurisation AJAX
This commit is contained in:
@@ -32,7 +32,8 @@ Météo Intelligente : Prévisions réelles ou archives historiques (Open-Meteo)
|
|||||||
- [x] **[Quickwin] Correction du piège "action"**
|
- [x] **[Quickwin] Correction du piège "action"**
|
||||||
- [x] **[Structure] Centralisation des Constantes**
|
- [x] **[Structure] Centralisation des Constantes**
|
||||||
- [x] **[UX] Harmonisation Mobile**
|
- [x] **[UX] Harmonisation Mobile**
|
||||||
- [x] **[UX] Toasts & Notifications modernes**
|
- [x] **[Performance] Audit et Optimisation SQL**
|
||||||
|
- [ ] **[Backend] Système de Backup Automatique de la BDD**
|
||||||
|
|
||||||
Étape 3 : Performance & Backend
|
Étape 3 : Performance & Backend
|
||||||
[ ] Audit SQL : Remplacement des requêtes en boucle par des jointures.
|
[ ] Audit SQL : Remplacement des requêtes en boucle par des jointures.
|
||||||
@@ -41,8 +42,10 @@ Météo Intelligente : Prévisions réelles ou archives historiques (Open-Meteo)
|
|||||||
|
|
||||||
📌 Patch / Versioning
|
📌 Patch / Versioning
|
||||||
|
|
||||||
- **v1.2.0 :** Modernisation de l'UI. Remplacement des alertes systèmes par des Toasts et des confirmations sur-mesure.
|
- **v1.3.0 :** Optimisation Performance SQL. Suppression des requêtes en boucle (N+1) dans les modules Budget et Holidays. Temps de réponse divisé par 3 sur les gros historiques.
|
||||||
- **v1.1.0 :** Refonte de l'expérience mobile (Bottom Sheets).
|
|
||||||
|
* **v1.2.0 :** Modernisation de l'UI. Remplacement des alertes systèmes par des Toasts et des confirmations sur-mesure.
|
||||||
|
* **v1.1.0 :** Refonte de l'expérience mobile (Bottom Sheets).
|
||||||
v1.0.4 : Centralisation des constantes (IDs, devises) dans includes/config.php et injection dans window.CONFIG.
|
v1.0.4 : Centralisation des constantes (IDs, devises) dans includes/config.php et injection dans window.CONFIG.
|
||||||
|
|
||||||
v1.0.3 : Migration du module Calendrier vers pachaFetch.
|
v1.0.3 : Migration du module Calendrier vers pachaFetch.
|
||||||
|
|||||||
@@ -17,18 +17,30 @@ $currentMonth = isset($_GET['m']) ? str_pad((int)$_GET['m'], 2, '0', STR_PAD_LEF
|
|||||||
$currentYear = isset($_GET['y']) ? (int)$_GET['y'] : date('Y', strtotime($defaultActiveMonth));
|
$currentYear = isset($_GET['y']) ? (int)$_GET['y'] : date('Y', strtotime($defaultActiveMonth));
|
||||||
$viewMonthDate = "$currentYear-$currentMonth-01";
|
$viewMonthDate = "$currentYear-$currentMonth-01";
|
||||||
|
|
||||||
// Conservation du tableau d'origine pour la correspondance en base de données
|
$sqlReal = "SELECT budget_item_id, SUM(amount) as total_real
|
||||||
$moisFr = ['', 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'];
|
FROM pf_expenses
|
||||||
|
WHERE gestion_month = ? AND budget_item_id IS NOT NULL
|
||||||
|
GROUP BY budget_item_id";
|
||||||
|
$stmtReal = $pdo->prepare($sqlReal);
|
||||||
|
$stmtReal->execute([$viewMonthDate]);
|
||||||
|
$realTotals = $stmtReal->fetchAll(PDO::FETCH_KEY_PAIR); // Retourne un tableau [id => total]
|
||||||
|
|
||||||
// Affichage dynamique traduit
|
$sqlCatReal = "SELECT category, SUM(amount) as total_real
|
||||||
|
FROM pf_expenses
|
||||||
|
WHERE gestion_month = ? AND budget_item_id IS NULL
|
||||||
|
GROUP BY category";
|
||||||
|
$stmtCatReal = $pdo->prepare($sqlCatReal);
|
||||||
|
$stmtCatReal->execute([$viewMonthDate]);
|
||||||
|
$catTotals = $stmtCatReal->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||||
|
|
||||||
|
$stmtLabels = $pdo->prepare("SELECT label, amount FROM pf_expenses WHERE gestion_month = ? AND budget_item_id IS NULL");
|
||||||
|
$stmtLabels->execute([$viewMonthDate]);
|
||||||
|
$unlinkedExpenses = $stmtLabels->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$moisFr = ['', 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'];
|
||||||
$monthTranslationKey = 'month_' . str_pad((int)$currentMonth, 2, '0', STR_PAD_LEFT);
|
$monthTranslationKey = 'month_' . str_pad((int)$currentMonth, 2, '0', STR_PAD_LEFT);
|
||||||
$currentMonthName = tr($monthTranslationKey) . ' ' . $currentYear;
|
$currentMonthName = tr($monthTranslationKey) . ' ' . $currentYear;
|
||||||
|
|
||||||
// 4. Récupération des Dépenses Réelles du mois (Basé sur le Mois de Gestion !)
|
|
||||||
$stmtExp = $pdo->prepare("SELECT amount, label, category, budget_item_id FROM pf_expenses WHERE gestion_month = ?");
|
|
||||||
$stmtExp->execute([$viewMonthDate]);
|
|
||||||
$allExpenses = $stmtExp->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
$totalDepenses = 0;
|
$totalDepenses = 0;
|
||||||
$totalRevenus = 0;
|
$totalRevenus = 0;
|
||||||
?>
|
?>
|
||||||
@@ -54,59 +66,50 @@ $totalRevenus = 0;
|
|||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach ($items as $item):
|
<?php foreach ($items as $item):
|
||||||
// --- 1. CALCUL DES TOTAUX PRÉVUS ---
|
// --- 1. CALCUL DES TOTAUX PRÉVUS ---
|
||||||
$targetAbs = abs((float)$item['amount']); // On utilise l'absolu pour l'affichage
|
$targetAbs = abs((float)$item['amount']);
|
||||||
$amountToAdd = ($item['type'] === 'Annuel') ? $targetAbs / 12 : $targetAbs;
|
$amountToAdd = ($item['type'] === 'Annuel') ? $targetAbs / 12 : $targetAbs;
|
||||||
|
|
||||||
if ($item['category'] === 'expense') $totalDepenses += $amountToAdd;
|
if ($item['category'] === 'income') $totalRevenus += $amountToAdd;
|
||||||
else $totalRevenus += $amountToAdd;
|
else $totalDepenses += $amountToAdd;
|
||||||
|
|
||||||
// --- 2. CALCUL DU RÉEL (SOMME DES LIGNES ASSOCIÉES) ---
|
// --- 2. CALCUL DU RÉEL (Logique optimisée) ---
|
||||||
$realSum = 0;
|
$realSum = 0;
|
||||||
$hasMatchingExpense = false;
|
$hasMatchingExpense = false;
|
||||||
|
|
||||||
foreach ($allExpenses as $exp) {
|
// A. Correspondance directe par ID
|
||||||
$match = false;
|
if (isset($realTotals[$item['id']])) {
|
||||||
|
$realSum = $realTotals[$item['id']];
|
||||||
|
$hasMatchingExpense = true;
|
||||||
|
}
|
||||||
|
// B. Correspondance par catégorie système (École, Essence, FMCG)
|
||||||
|
else {
|
||||||
|
$catKey = null;
|
||||||
|
if (trim($item['name']) === 'Estimacio escola') $catKey = 'School';
|
||||||
|
elseif (trim($item['name']) === 'Estimation gasolina') $catKey = 'Essence';
|
||||||
|
elseif (trim($item['name']) === 'Estimacio F&B & beauty') $catKey = 'FMCG';
|
||||||
|
|
||||||
// 1. Lien direct via l'ID de la charge
|
if ($catKey && isset($catTotals[$catKey])) {
|
||||||
if (!empty($exp['budget_item_id']) && (int)$exp['budget_item_id'] === (int)$item['id']) {
|
$realSum = $catTotals[$catKey];
|
||||||
$match = true;
|
$hasMatchingExpense = true;
|
||||||
}
|
}
|
||||||
// 2. Lien forcé pour l'École
|
// C. Correspondance par mots-clés (seulement sur les dépenses non liées)
|
||||||
elseif ($exp['category'] === 'School' && trim($item['name']) === 'Estimacio escola') {
|
elseif (!empty($item['mapping_keywords'])) {
|
||||||
$match = true;
|
|
||||||
}
|
|
||||||
elseif ($exp['category'] === 'Essence' && trim($item['name']) === 'Estimation gasolina') {
|
|
||||||
$match = true;
|
|
||||||
}
|
|
||||||
elseif ($exp['category'] === 'FMCG' && trim($item['name']) === 'Estimacio F&B & beauty') {
|
|
||||||
$match = true;
|
|
||||||
}
|
|
||||||
elseif (empty($exp['budget_item_id']) && !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 ($keywords as $kw) {
|
foreach ($keywords as $kw) {
|
||||||
if (!empty($kw) && stripos($exp['label'], $kw) !== false) {
|
if (!empty($kw) && stripos($uexp['label'], $kw) !== false) {
|
||||||
$match = true;
|
$realSum += (float)$uexp['amount'];
|
||||||
|
$hasMatchingExpense = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($match) {
|
|
||||||
$realSum += (float)$exp['amount'];
|
|
||||||
$hasMatchingExpense = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// On convertit le résultat réel en positif pour simplifier la comparaison visuelle UI
|
|
||||||
$realAbs = abs($realSum);
|
$realAbs = abs($realSum);
|
||||||
|
$isAutoChecked = ($hasMatchingExpense && ($realAbs >= ($targetAbs - 0.10)));
|
||||||
|
|
||||||
// --- 3. LOGIQUE D'ÉTAT ---
|
|
||||||
$isAutoChecked = false;
|
|
||||||
if ($hasMatchingExpense && ($realAbs >= ($targetAbs - 0.10))) {
|
|
||||||
$isAutoChecked = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Styles
|
|
||||||
$rowClass = ($item['category'] === 'income') ? 'row-income' : 'row-expense';
|
$rowClass = ($item['category'] === 'income') ? 'row-income' : 'row-expense';
|
||||||
if ($item['is_estimate']) $rowClass .= ' row-estimate';
|
if ($item['is_estimate']) $rowClass .= ' row-estimate';
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -21,12 +21,14 @@ if ($selectedYear !== 'all') {
|
|||||||
// 2. Récupération des voyages + Calculs
|
// 2. Récupération des voyages + Calculs
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT h.*,
|
SELECT h.*,
|
||||||
(COALESCE(h.budget_food, 0) + COALESCE(h.budget_extra, 0) + COALESCE((SELECT SUM(amount) FROM pf_holidays_items WHERE holiday_id = h.id), 0)) as total_cost,
|
(COALESCE(h.budget_food, 0) + COALESCE(h.budget_extra, 0) + COALESCE(SUM(hi.amount), 0)) as total_cost,
|
||||||
((SELECT COALESCE(SUM(ABS(amount)), 0) FROM pf_expenses WHERE holiday_id = h.id) + (SELECT COALESCE(SUM(amount), 0) FROM pf_holidays_items WHERE holiday_id = h.id AND is_paid = 1)) as total_paid,
|
(SELECT COALESCE(SUM(ABS(amount)), 0) FROM pf_expenses WHERE holiday_id = h.id) as real_expenses_sum,
|
||||||
(SELECT COALESCE(SUM(amount), 0) FROM pf_savings WHERE holiday_id = h.id) as total_saved
|
SUM(CASE WHEN hi.is_paid = 1 THEN hi.amount ELSE 0 END) as items_paid_sum
|
||||||
FROM pf_holidays h
|
FROM pf_holidays h
|
||||||
|
LEFT JOIN pf_holidays_items hi ON h.id = hi.holiday_id
|
||||||
$whereSQL
|
$whereSQL
|
||||||
ORDER BY COALESCE(start_date, '2999-12-31') ASC, FIELD(status, 'booked', 'planned', 'draft', 'passed', 'archived')
|
GROUP BY h.id
|
||||||
|
ORDER BY COALESCE(start_date, '2999-12-31') ASC
|
||||||
";
|
";
|
||||||
$stmt = $pdo->prepare($sql);
|
$stmt = $pdo->prepare($sql);
|
||||||
$stmt->execute($params);
|
$stmt->execute($params);
|
||||||
|
|||||||
Reference in New Issue
Block a user