update epargne auto
This commit is contained in:
@@ -82,3 +82,152 @@ if ($action === 'delete_category') {
|
||||
header("Location: " . $_SERVER['HTTP_REFERER']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 6. VALIDATION DES VIREMENTS (Complex Business Logic)
|
||||
if ($action === 'validate_transfers') {
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$person = $_POST['person']; // Alex ou Laia
|
||||
$monthDate = $_POST['month_date'];
|
||||
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
|
||||
// 1. Récupérer tous les virements prévus pour ce mois/personne dans le BUDGET
|
||||
// On joint avec les catégories pour avoir le nom et la cible
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT v.*, c.name as cat_name, c.target
|
||||
FROM pf_alloc_values v
|
||||
JOIN pf_alloc_categories c ON v.cat_id = c.id
|
||||
WHERE v.month_date = ?
|
||||
");
|
||||
$stmt->execute([$monthDate]);
|
||||
$budgetLines = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// On prépare les totaux à transférer par Cible
|
||||
// Structure : ['Alex' => ['total'=>100, 'cats'=>['Noel'=>50, 'Eco'=>50]], 'Pol' => ...]
|
||||
$transfersToDo = [];
|
||||
|
||||
foreach ($budgetLines as $line) {
|
||||
$amount = ($person === 'Alex') ? $line['amount_alex'] : $line['amount_laia'];
|
||||
if ($amount <= 0) continue; // Rien à virer
|
||||
|
||||
$target = trim($line['target']);
|
||||
$catName = trim($line['cat_name']);
|
||||
|
||||
// MAPPING DES PROPRIÉTAIRES CIBLES
|
||||
$targetOwner = null;
|
||||
if ($target === 'vers L.Perso') {
|
||||
$targetOwner = $person; // Alex -> Alex, Laia -> Laia
|
||||
} elseif ($target === 'vers L.Pol') {
|
||||
$targetOwner = 'Pol';
|
||||
} elseif ($target === 'vers L.Pep') {
|
||||
$targetOwner = 'Pep';
|
||||
} elseif ($target === 'vers commune') {
|
||||
continue; // On ignore (Business Rule)
|
||||
}
|
||||
|
||||
if ($targetOwner) {
|
||||
if (!isset($transfersToDo[$targetOwner])) {
|
||||
$transfersToDo[$targetOwner] = ['total_add' => 0, 'cats' => []];
|
||||
}
|
||||
$transfersToDo[$targetOwner]['total_add'] += $amount;
|
||||
|
||||
if (!isset($transfersToDo[$targetOwner]['cats'][$catName])) {
|
||||
$transfersToDo[$targetOwner]['cats'][$catName] = 0;
|
||||
}
|
||||
$transfersToDo[$targetOwner]['cats'][$catName] += $amount;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Traiter chaque Propriétaire Cible (Alex, Laia, Pol, Pep)
|
||||
foreach ($transfersToDo as $owner => $data) {
|
||||
|
||||
// A. VÉRIFIER SI LE MOIS EXISTE EN EPARGNE
|
||||
$stmtCheck = $pdo->prepare("SELECT COUNT(*) FROM pf_savings WHERE owner = ? AND month_date = ? AND category = 'TOTAL_BANQUE'");
|
||||
$stmtCheck->execute([$owner, $monthDate]);
|
||||
$exists = $stmtCheck->fetchColumn() > 0;
|
||||
|
||||
if (!$exists) {
|
||||
// SCENARIO : LE MOIS N'EXISTE PAS -> DUPLICATION DEPUIS M-1
|
||||
$prevDate = date('Y-m-d', strtotime($monthDate . ' -1 month'));
|
||||
|
||||
// Récup M-1
|
||||
$stmtPrev = $pdo->prepare("SELECT category, amount FROM pf_savings WHERE owner = ? AND month_date = ?");
|
||||
$stmtPrev->execute([$owner, $prevDate]);
|
||||
$prevLines = $stmtPrev->fetchAll(PDO::FETCH_KEY_PAIR); // [Cat => Montant]
|
||||
|
||||
if (empty($prevLines)) {
|
||||
// Si M-1 n'existe pas non plus, on initialise à 0 (ou on lève une erreur selon préférence)
|
||||
$prevLines = ['TOTAL_BANQUE' => 0];
|
||||
}
|
||||
|
||||
// Insertion M (Copie de M-1)
|
||||
$stmtInsert = $pdo->prepare("INSERT INTO pf_savings (month_date, owner, category, amount) VALUES (?, ?, ?, ?)");
|
||||
foreach ($prevLines as $cat => $amt) {
|
||||
$stmtInsert->execute([$monthDate, $owner, $cat, $amt]);
|
||||
}
|
||||
}
|
||||
|
||||
// B. MISE À JOUR DU TOTAL_BANQUE
|
||||
// On ajoute le montant du virement au montant existant (qu'il vienne d'être créé ou non)
|
||||
$stmtUpdTotal = $pdo->prepare("UPDATE pf_savings SET amount = amount + ? WHERE owner = ? AND month_date = ? AND category = 'TOTAL_BANQUE'");
|
||||
$stmtUpdTotal->execute([$data['total_add'], $owner, $monthDate]);
|
||||
|
||||
// C. MISE À JOUR / CRÉATION DES CATÉGORIES
|
||||
foreach ($data['cats'] as $catName => $catAmount) {
|
||||
// On utilise ON DUPLICATE KEY UPDATE pour gérer "Créer ou Sommer" en une seule requête
|
||||
// Note: category est-il unique par (month, owner)? Si ta table pf_savings n'a pas de clé unique là-dessus, il faut faire un SELECT avant.
|
||||
// Supposons qu'il n'y a pas de contrainte UNIQUE stricte, faisons le check manuel PHP pour être sûr.
|
||||
|
||||
$stmtCheckCat = $pdo->prepare("SELECT id FROM pf_savings WHERE owner = ? AND month_date = ? AND category = ?");
|
||||
$stmtCheckCat->execute([$owner, $monthDate, $catName]);
|
||||
$catId = $stmtCheckCat->fetchColumn();
|
||||
|
||||
if ($catId) {
|
||||
// Update : Sommer
|
||||
$stmtUpdateCat = $pdo->prepare("UPDATE pf_savings SET amount = amount + ? WHERE id = ?");
|
||||
$stmtUpdateCat->execute([$catAmount, $catId]);
|
||||
} else {
|
||||
// Insert : Créer
|
||||
$stmtInsertCat = $pdo->prepare("INSERT INTO pf_savings (month_date, owner, category, amount) VALUES (?, ?, ?, ?)");
|
||||
$stmtInsertCat->execute([$monthDate, $owner, $catName, $catAmount]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. ENREGISTRER LA VALIDATION (Mise à jour table existante)
|
||||
|
||||
// a. Trouver l'ID de la catégorie système
|
||||
$stmtSys = $pdo->prepare("SELECT id FROM pf_alloc_categories WHERE name = 'SYSTEM_VALIDATION' LIMIT 1");
|
||||
$stmtSys->execute();
|
||||
$sysCatId = $stmtSys->fetchColumn();
|
||||
|
||||
if ($sysCatId) {
|
||||
// b. Mettre à jour la valeur (1 = Validé)
|
||||
// On utilise une astuce SQL : on met à jour uniquement la colonne de la personne concernée
|
||||
// Si la ligne n'existe pas, on l'insère avec 1 pour la personne et 0 pour l'autre.
|
||||
|
||||
if ($person === 'Alex') {
|
||||
$sql = "INSERT INTO pf_alloc_values (month_date, cat_id, amount_alex, amount_laia)
|
||||
VALUES (?, ?, 1, 0)
|
||||
ON DUPLICATE KEY UPDATE amount_alex = 1";
|
||||
} else {
|
||||
$sql = "INSERT INTO pf_alloc_values (month_date, cat_id, amount_alex, amount_laia)
|
||||
VALUES (?, ?, 0, 1)
|
||||
ON DUPLICATE KEY UPDATE amount_laia = 1";
|
||||
}
|
||||
|
||||
$stmtVal = $pdo->prepare($sql);
|
||||
$stmtVal->execute([$monthDate, $sysCatId]);
|
||||
}
|
||||
|
||||
$pdo->commit();
|
||||
echo json_encode(['success' => true]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
$pdo->rollBack();
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
@@ -44,6 +44,30 @@ $allocs = [];
|
||||
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$allocs[$row['month_date']][$row['cat_id']] = $row;
|
||||
}
|
||||
|
||||
// 5. Récupération de l'ID de la catégorie système
|
||||
// On cherche l'ID de la catégorie 'SYSTEM_VALIDATION'
|
||||
$sysCatId = null;
|
||||
foreach ($cats as $key => $c) {
|
||||
if ($c['name'] === 'SYSTEM_VALIDATION') {
|
||||
$sysCatId = $c['id'];
|
||||
// IMPORTANT : On retire cette catégorie de la liste affichable ($cats)
|
||||
// pour qu'elle n'apparaisse pas dans le tableau HTML !
|
||||
unset($cats[$key]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Lecture des statuts de validation (1 = Validé, 0 = Non)
|
||||
$focusDate = $months[0];
|
||||
$isValidatedAlex = false;
|
||||
$isValidatedLaia = false;
|
||||
|
||||
if ($sysCatId && isset($allocs[$focusDate][$sysCatId])) {
|
||||
$row = $allocs[$focusDate][$sysCatId];
|
||||
$isValidatedAlex = ($row['amount_alex'] == 1);
|
||||
$isValidatedLaia = ($row['amount_laia'] == 1);
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="prev-container">
|
||||
@@ -221,18 +245,46 @@ while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
$focusMonth = $months[0];
|
||||
$focusMonth = $months[0]; // Mois affiché à gauche
|
||||
|
||||
// On initialise toutes les cibles possibles pour avoir les lignes prêtes
|
||||
// Note : On utilise md5() sur la cible pour créer des ID compatibles HTML (sans espaces/points)
|
||||
// 1. Initialisation des cibles par défaut
|
||||
$targetsOrder = ['vers commune', 'vers L.Pol', 'vers L.Pep', 'vers L.Perso'];
|
||||
|
||||
// On récupère toutes les cibles uniques utilisées dans les catégories + celles par défaut
|
||||
// 2. CORRECTION : On reconstruit la liste complète $allTargets
|
||||
// On part des cibles par défaut
|
||||
$allTargets = $targetsOrder;
|
||||
|
||||
// On ajoute les cibles personnalisées trouvées dans les catégories actives
|
||||
foreach($cats as $c) {
|
||||
if(!empty($c['target']) && !in_array($c['target'], $allTargets)) $allTargets[] = $c['target'];
|
||||
$t = trim($c['target']);
|
||||
if(!empty($t) && !in_array($t, $allTargets)) {
|
||||
$allTargets[] = $t;
|
||||
}
|
||||
}
|
||||
$allTargets = array_unique($allTargets);
|
||||
|
||||
// 3. Calcul des sommes (Logiciel d'affichage)
|
||||
$summaryData = [];
|
||||
foreach($allTargets as $t) $summaryData[$t] = ['Alex' => 0, 'Laia' => 0];
|
||||
|
||||
foreach ($cats as $cat) {
|
||||
$t = trim($cat['target']);
|
||||
if (empty($t)) continue;
|
||||
|
||||
$val = $allocs[$focusMonth][$cat['id']] ?? ['amount_alex'=>0, 'amount_laia'=>0];
|
||||
|
||||
if (!isset($summaryData[$t])) {
|
||||
$summaryData[$t] = ['Alex' => 0, 'Laia' => 0];
|
||||
}
|
||||
|
||||
$summaryData[$t]['Alex'] += $val['amount_alex'];
|
||||
$summaryData[$t]['Laia'] += $val['amount_laia'];
|
||||
}
|
||||
|
||||
// Récupération des totaux pour le footer
|
||||
$grandTotalAlex = 0;
|
||||
$grandTotalLaia = 0;
|
||||
$grandTotalGlobal = 0;
|
||||
?>
|
||||
|
||||
<div class="recap-wrapper">
|
||||
@@ -245,8 +297,37 @@ while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:left;">Destination</th>
|
||||
<th class="col-alex">Alex</th>
|
||||
<th class="col-laia">Laia</th>
|
||||
|
||||
<th class="col-alex">
|
||||
<div style="display:flex; flex-direction:column; align-items:center; gap:5px;">
|
||||
<span>ALEX</span>
|
||||
<?php if($isValidatedAlex): ?>
|
||||
<div style="background:#10b981; color:white; padding:4px 8px; border-radius:4px; font-size:0.7rem; display:flex; align-items:center; gap:4px;">
|
||||
✓ FAIT
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<button onclick="validateTransfers('Alex', '<?= $focusMonth ?>')" class="pf-btn btn-small" style="background:white; color:#0891b2; border:1px solid #0891b2; font-size:0.7rem; padding:2px 8px; height:auto;">
|
||||
Valider
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</th>
|
||||
|
||||
<th class="col-laia">
|
||||
<div style="display:flex; flex-direction:column; align-items:center; gap:5px;">
|
||||
<span>LAIA</span>
|
||||
<?php if($isValidatedLaia): ?>
|
||||
<div style="background:#10b981; color:white; padding:4px 8px; border-radius:4px; font-size:0.7rem; display:flex; align-items:center; gap:4px;">
|
||||
✓ FAIT
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<button onclick="validateTransfers('Laia', '<?= $focusMonth ?>')" class="pf-btn btn-small" style="background:white; color:#d97706; border:1px solid #d97706; font-size:0.7rem; padding:2px 8px; height:auto;">
|
||||
Valider
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</th>
|
||||
|
||||
<th class="col-global">Global</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -618,4 +699,30 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function validateTransfers(person, month) {
|
||||
if (!confirm(`Confirmer que ${person} a bien effectué tous ses virements pour ${month} ?\n\nCela mettra à jour l'Épargne automatiquement.`)) return;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('action', 'validate_transfers');
|
||||
formData.append('person', person);
|
||||
formData.append('month_date', month);
|
||||
|
||||
// On récupère aussi les données calculées du tableau pour les envoyer au backend
|
||||
// Mais pour plus de sécurité, le backend recalculera tout lui-même.
|
||||
|
||||
fetch('/modules/budget/includes/api/save-budget.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if(data.success) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert("Erreur: " + data.error);
|
||||
}
|
||||
})
|
||||
.catch(e => alert("Erreur technique"));
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user