prepare("SELECT content FROM pf_notes WHERE note_type = ? AND reference_id = ?"); $stmt->execute([$noteType, $refId]); // fetchColumn() renvoie false si aucune ligne n'est trouvée, on sécurise avec un coalesce (?? '') $content = $stmt->fetchColumn(); $content = $content !== false ? $content : ''; echo json_encode(['success' => true, 'content' => $content]); } catch (Exception $e) { echo json_encode(['success' => false, 'error' => $e->getMessage()]); } exit; } // ================================================================= // 7. SAUVEGARDE D'UNE NOTE GÉNÉRIQUE (pf_notes) // ================================================================= if ($action === 'save_note') { // On affiche les erreurs s'il y a un souci SQL pour pouvoir déboguer ini_set('display_errors', 1); error_reporting(E_ALL); header('Content-Type: application/json'); try { $noteType = $_POST['note_type'] ?? ''; $refId = $_POST['reference_id'] ?? ''; $content = $_POST['content'] ?? ''; if (empty($noteType) || empty($refId)) { throw new Exception("Le type et la référence de la note sont requis."); } // Insère ou met à jour la note si elle existe déjà $stmt = $pdo->prepare("INSERT INTO pf_notes (note_type, reference_id, content) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE content = VALUES(content)"); $stmt->execute([$noteType, $refId, $content]); echo json_encode(['success' => true]); } catch (\Throwable $e) { echo json_encode(['success' => false, 'error' => 'Erreur SQL: ' . $e->getMessage()]); } exit; } // ================================================================= // 1. MISE A JOUR TABLEAU SALAIRES (AJAX) if ($action === 'update_salary_config') { header('Content-Type: application/json'); $year = $_POST['year']; $person = $_POST['person']; $field = $_POST['field']; // salary, mensualite, etc. $value = floatval($_POST['value']); // Liste des champs autorisés pour éviter les injections $allowed = ['salary', 'mensualite', 'frais_func', 'eco_perso', 'eco_family']; if (!in_array($field, $allowed)) { echo json_encode(['success' => false, 'error' => 'Champ invalide']); exit; } $stmt = $pdo->prepare("INSERT INTO pf_salary_config (year, person, $field) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE $field = VALUES($field)"); $stmt->execute([$year, $person, $value]); echo json_encode(['success' => true]); exit; } // 2. MISE A JOUR TABLEAU REPARTITION (AJAX) if ($action === 'update_allocation') { header('Content-Type: application/json'); $date = $_POST['month_date']; $catId = (int)$_POST['cat_id']; $personId = (int)$_POST['person_id']; $value = floatval($_POST['value']); if ($catId <= 0 || $personId <= 0) { echo json_encode(['success' => false, 'error' => 'Données invalides.']); exit; } $stmt = $pdo->prepare("INSERT INTO pf_alloc_values (month_date, cat_id, person_id, amount) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE amount = VALUES(amount)"); $stmt->execute([$date, $catId, $personId, $value]); echo json_encode(['success' => true]); exit; } // 3. GESTION DES CATEGORIES (Ajout) if ($action === 'add_category') { try { $name = trim($_POST['name']); $transfer_dest = trim($_POST['transfer_dest'] ?? ''); $target = floatval($_POST['target'] ?? 0); $holiday_id = !empty($_POST['holiday_id']) ? (int)$_POST['holiday_id'] : null; if (!empty($name)) { $stmt = $pdo->prepare("INSERT INTO pf_alloc_categories (name, target, transfer_dest, holiday_id) VALUES (?, ?, ?, ?)"); $stmt->execute([$name, $target, $transfer_dest, $holiday_id]); } if (isset($_POST['ajax'])) { header('Content-Type: application/json'); echo json_encode(['success' => true]); exit; } header("Location: " . $_SERVER['HTTP_REFERER']); exit; } catch (Exception $e) { if (isset($_POST['ajax'])) { header('Content-Type: application/json'); echo json_encode(['success' => false, 'error' => $e->getMessage()]); exit; } die($e->getMessage()); } } // 4. MODIFICATION D'UNE CATEGORIE if ($action === 'update_category') { try { $id = (int)$_POST['cat_id']; $name = trim($_POST['name']); $transfer_dest = trim($_POST['transfer_dest'] ?? ''); $target = floatval($_POST['target'] ?? 0); $holiday_id = !empty($_POST['holiday_id']) ? (int)$_POST['holiday_id'] : null; if ($id > 0 && !empty($name)) { $stmt = $pdo->prepare("UPDATE pf_alloc_categories SET name = ?, target = ?, transfer_dest = ?, holiday_id = ? WHERE id = ?"); $stmt->execute([$name, $target, $transfer_dest, $holiday_id, $id]); } if (isset($_POST['ajax'])) { header('Content-Type: application/json'); echo json_encode(['success' => true]); exit; } header("Location: " . $_SERVER['HTTP_REFERER']); exit; } catch (Exception $e) { if (isset($_POST['ajax'])) { header('Content-Type: application/json'); echo json_encode(['success' => false, 'error' => $e->getMessage()]); exit; } die($e->getMessage()); } } // 5. SUPPRESSION CATEGORIE if ($action === 'delete_category') { $id = (int)($_POST['id'] ?? $_GET['id'] ?? 0); if ($id > 0) { $pdo->prepare("DELETE FROM pf_alloc_categories WHERE id = ?")->execute([$id]); $pdo->prepare("DELETE FROM pf_alloc_values WHERE cat_id = ?")->execute([$id]); } if (isset($_POST['ajax']) || isset($_GET['ajax'])) { header('Content-Type: application/json'); echo json_encode(['success' => true]); exit; } header("Location: " . ($_SERVER['HTTP_REFERER'] ?? '/budget.php')); exit; } // 6. VALIDATION DES VIREMENTS (Complex Business Logic) if ($action === 'validate_transfers') { header('Content-Type: application/json'); $personId = (int)$_POST['person_id']; // Reçoit l'ID parent $monthDate = $_POST['month_date']; try { $pdo->beginTransaction(); $stmtP = $pdo->prepare("SELECT name FROM pf_people WHERE id = ?"); $stmtP->execute([$personId]); $dbPersonName = $stmtP->fetchColumn(); if (!$dbPersonName) throw new Exception("Parent introuvable."); $stmt = $pdo->prepare(" SELECT v.amount, c.name as cat_name, c.transfer_dest, c.holiday_id FROM pf_alloc_values v JOIN pf_alloc_categories c ON v.cat_id = c.id WHERE v.month_date = ? AND v.person_id = ? "); $stmt->execute([$monthDate, $personId]); $budgetLines = $stmt->fetchAll(PDO::FETCH_ASSOC); $transfersToDo = []; foreach ($budgetLines as $line) { $amount = (float)$line['amount']; if ($amount <= 0) continue; $dest = trim($line['transfer_dest']); $catName = trim($line['cat_name']); $holidayId = $line['holiday_id']; $targetOwner = null; if ($dest === 'vers L.Perso') { $targetOwner = $dbPersonName; } elseif ($dest === 'vers L.Pol') { $targetOwner = 'Pol'; } elseif ($dest === 'vers L.Pep') { $targetOwner = 'Pep'; } elseif ($dest === 'vers commune') { continue; } 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] = ['amount' => 0, 'holiday_id' => $holidayId]; } $transfersToDo[$targetOwner]['cats'][$catName]['amount'] += $amount; } } foreach ($transfersToDo as $owner => $data) { $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) { $prevDate = date('Y-m-d', strtotime($monthDate . ' -1 month')); $stmtPrev = $pdo->prepare("SELECT category, amount, holiday_id FROM pf_savings WHERE owner = ? AND month_date = ?"); $stmtPrev->execute([$owner, $prevDate]); $prevLines = $stmtPrev->fetchAll(PDO::FETCH_ASSOC); if (empty($prevLines)) { $prevLines = [['category' => 'TOTAL_BANQUE', 'amount' => 0, 'holiday_id' => null]]; } $stmtInsert = $pdo->prepare("INSERT INTO pf_savings (month_date, owner, category, amount, holiday_id) VALUES (?, ?, ?, ?, ?)"); foreach ($prevLines as $row) { $stmtInsert->execute([$monthDate, $owner, $row['category'], $row['amount'], $row['holiday_id']]); } } $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]); foreach ($data['cats'] as $catName => $catInfo) { $catAmount = $catInfo['amount']; $catHolidayId = $catInfo['holiday_id']; if (strpos($catName, 'Eco P') === 0) { continue; } $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) { $stmtUpdateCat = $pdo->prepare("UPDATE pf_savings SET amount = amount + ?, holiday_id = ? WHERE id = ?"); $stmtUpdateCat->execute([$catAmount, $catHolidayId, $catId]); } else { $stmtInsertCat = $pdo->prepare("INSERT INTO pf_savings (month_date, owner, category, amount, holiday_id) VALUES (?, ?, ?, ?, ?)"); $stmtInsertCat->execute([$monthDate, $owner, $catName, $catAmount, $catHolidayId]); } } } $stmtSys = $pdo->prepare("SELECT id FROM pf_alloc_categories WHERE name = 'SYSTEM_VALIDATION' LIMIT 1"); $stmtSys->execute(); $sysCatId = $stmtSys->fetchColumn(); if ($sysCatId) { $stmtVal = $pdo->prepare("INSERT INTO pf_alloc_values (month_date, cat_id, person_id, amount) VALUES (?, ?, ?, 1) ON DUPLICATE KEY UPDATE amount = 1"); $stmtVal->execute([$monthDate, $sysCatId, $personId]); } $pdo->commit(); echo json_encode(['success' => true]); } catch (Exception $e) { $pdo->rollBack(); echo json_encode(['success' => false, 'error' => $e->getMessage()]); } exit; } // ================================================================= // 7. GESTION DES AVANCES / TRICOUNT (pf_advances) // ================================================================= if ($action === 'save_advance') { header('Content-Type: application/json'); try { $payer = trim($_POST['payer'] ?? ''); $advance_date = $_POST['advance_date'] ?? date('Y-m-d'); $description = trim($_POST['description'] ?? ''); $amount = abs((float)($_POST['amount'] ?? 0)); $from_savings = isset($_POST['from_savings']) ? 1 : 0; if (empty($payer) || empty($description) || $amount <= 0) { throw new Exception("Champs obligatoires manquants ou invalides."); } $stmt = $pdo->prepare("INSERT INTO pf_advances (advance_date, payer, description, amount, from_savings) VALUES (?, ?, ?, ?, ?)"); $stmt->execute([$advance_date, $payer, $description, $amount, $from_savings]); echo json_encode(['success' => true]); } catch (Exception $e) { http_response_code(400); echo json_encode(['success' => false, 'error' => $e->getMessage()]); } exit; } if ($action === 'update_advance') { header('Content-Type: application/json'); try { $id = (int)($_POST['id'] ?? 0); $payer = trim($_POST['payer'] ?? ''); $advance_date = $_POST['advance_date'] ?? date('Y-m-d'); $description = trim($_POST['description'] ?? ''); $amount = abs((float)($_POST['amount'] ?? 0)); $from_savings = isset($_POST['from_savings']) ? 1 : 0; if ($id <= 0 || empty($payer) || empty($description) || $amount <= 0) { throw new Exception("Paramètres invalides fournis."); } $stmt = $pdo->prepare("UPDATE pf_advances SET advance_date = ?, payer = ?, description = ?, amount = ?, from_savings = ? WHERE id = ?"); $stmt->execute([$advance_date, $payer, $description, $amount, $from_savings, $id]); echo json_encode(['success' => true]); } catch (Exception $e) { http_response_code(400); echo json_encode(['success' => false, 'error' => $e->getMessage()]); } exit; } if ($action === 'resolve_advance') { header('Content-Type: application/json'); try { $id = (int)($_POST['id'] ?? 0); if ($id <= 0) throw new Exception("ID invalide fourni."); $stmt = $pdo->prepare("UPDATE pf_advances SET is_resolved = 1 WHERE id = ?"); $stmt->execute([$id]); echo json_encode(['success' => true]); } catch (Exception $e) { http_response_code(400); echo json_encode(['success' => false, 'error' => $e->getMessage()]); } exit; } if ($action === 'delete_advance') { header('Content-Type: application/json'); try { $id = (int)($_POST['id'] ?? 0); if ($id <= 0) throw new Exception("ID invalide."); $stmt = $pdo->prepare("DELETE FROM pf_advances WHERE id = ?"); $stmt->execute([$id]); echo json_encode(['success' => true]); } catch (Exception $e) { http_response_code(400); echo json_encode(['success' => false, 'error' => $e->getMessage()]); } exit; }