change
This commit is contained in:
@@ -68,6 +68,9 @@ if ($sysCatId && isset($allocs[$focusDate][$sysCatId])) {
|
||||
$isValidatedAlex = ($row['amount_alex'] == 1);
|
||||
$isValidatedLaia = ($row['amount_laia'] == 1);
|
||||
}
|
||||
|
||||
// 7. Récupération des vacances actives pour les lier au budget
|
||||
$activeHolidays = $pdo->query("SELECT id, title FROM pf_holidays WHERE status IN ('draft', 'planned', 'booked') ORDER BY start_date ASC")->fetchAll(PDO::FETCH_ASSOC);
|
||||
?>
|
||||
|
||||
<div class="prev-container">
|
||||
@@ -191,6 +194,7 @@ if ($sysCatId && isset($allocs[$focusDate][$sysCatId])) {
|
||||
<td class="col-sticky" style="position:relative; <?= $isIndicative ? 'opacity:0.8;' : '' ?>">
|
||||
<div style="font-weight:600; color:<?= $isIndicative ? '#64748b' : 'var(--text-main)' ?>;">
|
||||
<?= htmlspecialchars($cat['name']) ?>
|
||||
<?php if(!empty($cat['holiday_id'])) echo " 🌴"; ?>
|
||||
<?php if($isIndicative): ?><span style="font-size:0.7rem; border:1px solid #cbd5e1; border-radius:4px; padding:0 4px; margin-left:5px;">Info</span><?php endif; ?>
|
||||
</div>
|
||||
<div style="font-size:0.75rem; color:var(--text-muted); font-style:italic; text-align:right;">
|
||||
@@ -204,6 +208,7 @@ if ($sysCatId && isset($allocs[$focusDate][$sysCatId])) {
|
||||
data-id="<?= $cat['id'] ?>"
|
||||
data-name="<?= htmlspecialchars($cat['name']) ?>"
|
||||
data-target="<?= htmlspecialchars($cat['target']) ?>"
|
||||
data-holiday="<?= $cat['holiday_id'] ?? '' ?>"
|
||||
onclick="openEditModal(this)">
|
||||
✎
|
||||
</button>
|
||||
@@ -369,7 +374,7 @@ if ($sysCatId && isset($allocs[$focusDate][$sysCatId])) {
|
||||
<label class="pf-label">Nom (ex: Vacances)</label>
|
||||
<input type="text" name="name" class="pf-input" required>
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom:20px;">
|
||||
<div class="form-group" style="margin-bottom:15px;">
|
||||
<label class="pf-label">Cible (Destination)</label>
|
||||
<select name="target" class="pf-input" required>
|
||||
<option value="" disabled selected>-- Choisir --</option>
|
||||
@@ -379,6 +384,15 @@ if ($sysCatId && isset($allocs[$focusDate][$sysCatId])) {
|
||||
<option value="vers commune">vers commune</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom:20px;">
|
||||
<label class="pf-label" style="color:#8b5cf6;">🌴 Lier à un voyage (Optionnel)</label>
|
||||
<select name="holiday_id" class="pf-input" style="border-color:#8b5cf6; background:#f5f3ff;">
|
||||
<option value="">-- Ne pas associer --</option>
|
||||
<?php foreach ($activeHolidays as $hol): ?>
|
||||
<option value="<?= $hol['id'] ?>"><?= htmlspecialchars($hol['title']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" onclick="document.getElementById('addCatModal').style.display='none'" class="pf-btn btn-secondary">Annuler</button>
|
||||
<button type="submit" class="pf-btn">Ajouter</button>
|
||||
@@ -386,6 +400,7 @@ if ($sysCatId && isset($allocs[$focusDate][$sysCatId])) {
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="editCatModal" class="pf-modal">
|
||||
<div class="pf-modal-content" style="max-width:400px;">
|
||||
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:20px;">
|
||||
@@ -396,11 +411,11 @@ if ($sysCatId && isset($allocs[$focusDate][$sysCatId])) {
|
||||
<input type="hidden" name="action" value="update_category">
|
||||
<input type="hidden" name="cat_id" id="edit_cat_id">
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-group" style="margin-bottom:15px;">
|
||||
<label class="pf-label">Nom</label>
|
||||
<input type="text" name="name" id="edit_cat_name" class="pf-input" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-group" style="margin-bottom:15px;">
|
||||
<label class="pf-label">Cible (Destination)</label>
|
||||
<select name="target" id="edit_cat_target" class="pf-input" required>
|
||||
<option value="vers L.Pol">vers L.Pol</option>
|
||||
@@ -409,6 +424,15 @@ if ($sysCatId && isset($allocs[$focusDate][$sysCatId])) {
|
||||
<option value="vers commune">vers commune</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom:20px;">
|
||||
<label class="pf-label" style="color:#8b5cf6;">🌴 Lier à un voyage (Optionnel)</label>
|
||||
<select name="holiday_id" id="edit_cat_holiday" class="pf-input" style="border-color:#8b5cf6; background:#f5f3ff;">
|
||||
<option value="">-- Ne pas associer --</option>
|
||||
<?php foreach ($activeHolidays as $hol): ?>
|
||||
<option value="<?= $hol['id'] ?>"><?= htmlspecialchars($hol['title']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" onclick="document.getElementById('editCatModal').style.display='none'" class="pf-btn btn-secondary">Annuler</button>
|
||||
<button type="submit" class="pf-btn">Enregistrer</button>
|
||||
@@ -420,21 +444,16 @@ if ($sysCatId && isset($allocs[$focusDate][$sysCatId])) {
|
||||
<script>
|
||||
// Fonction pour ouvrir la modale et pré-remplir les valeurs
|
||||
function openEditModal(btn) {
|
||||
// 1. Récupération des données depuis le bouton
|
||||
// getAttribute est plus sûr pour éviter les bugs si des données sont manquantes
|
||||
const id = btn.getAttribute('data-id');
|
||||
const name = btn.getAttribute('data-name');
|
||||
const target = btn.getAttribute('data-target');
|
||||
const holiday = btn.getAttribute('data-holiday'); // NOUVEAU
|
||||
|
||||
// 2. Remplissage du formulaire
|
||||
document.getElementById('edit_cat_id').value = id;
|
||||
document.getElementById('edit_cat_name').value = name;
|
||||
|
||||
// Pour le SELECT, définir la .value sélectionne automatiquement la bonne option
|
||||
// Si la valeur actuelle en base n'existe pas dans la liste, ça sélectionnera la 1ère par défaut
|
||||
document.getElementById('edit_cat_target').value = target;
|
||||
document.getElementById('edit_cat_holiday').value = holiday; // NOUVEAU
|
||||
|
||||
// 3. Affichage
|
||||
document.getElementById('editCatModal').style.display = 'flex';
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -35,11 +35,11 @@ if (isset($_POST['action']) && $_POST['action'] === 'save_snapshot') {
|
||||
header("Location: ?tab=suivi"); exit;
|
||||
}
|
||||
|
||||
// D. SAUVEGARDE IMPORT CSV (AVEC BUDGET_ITEM_ID)
|
||||
// D. SAUVEGARDE IMPORT CSV (AVEC BUDGET_ITEM_ID ET HOLIDAY_ID)
|
||||
if (isset($_POST['action']) && $_POST['action'] === 'save_import') {
|
||||
$count = 0;
|
||||
|
||||
// 1. Catégories temporaires
|
||||
// 1. Catégories temporaires (Inchangé)
|
||||
$tempCatMapping = [];
|
||||
if (!empty($_POST['new_temp_cats'])) {
|
||||
$stmtTemp = $pdo->prepare("INSERT INTO pf_monthly_categories (month_year, name, type, budget) VALUES (?, ?, ?, 0)");
|
||||
@@ -49,8 +49,8 @@ if (isset($_POST['action']) && $_POST['action'] === 'save_import') {
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Insertion avec budget_item_id
|
||||
$stmtExp = $pdo->prepare("INSERT INTO pf_expenses (date_exp, category, label, amount, import_ref, budget_item_id) VALUES (?, ?, ?, ?, ?, ?)");
|
||||
// 2. Insertion avec budget_item_id ET holiday_id
|
||||
$stmtExp = $pdo->prepare("INSERT INTO pf_expenses (date_exp, category, label, amount, import_ref, budget_item_id, holiday_id) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmtRule = $pdo->prepare("INSERT INTO pf_import_rules (keyword, category) VALUES (?, ?) ON DUPLICATE KEY UPDATE category = VALUES(category)");
|
||||
|
||||
if (isset($_POST['lines']) && is_array($_POST['lines'])) {
|
||||
@@ -59,6 +59,7 @@ if (isset($_POST['action']) && $_POST['action'] === 'save_import') {
|
||||
$cat = $line['cat'];
|
||||
$is_credit = isset($line['is_credit']) ? (int)$line['is_credit'] : 0;
|
||||
$budgetItemId = !empty($line['budget_item_id']) ? (int)$line['budget_item_id'] : null;
|
||||
$holidayId = !empty($line['holiday_id']) ? (int)$line['holiday_id'] : null; // NOUVEAU
|
||||
|
||||
if ($is_credit && empty($cat)) continue;
|
||||
if (!$is_credit && empty($cat)) continue;
|
||||
@@ -70,7 +71,7 @@ if (isset($_POST['action']) && $_POST['action'] === 'save_import') {
|
||||
$finalAmount = $is_credit ? -abs($line['amount']) : abs($line['amount']);
|
||||
|
||||
try {
|
||||
$stmtExp->execute([$line['date'], $cat, $line['label'], $finalAmount, $line['ref'], $budgetItemId]);
|
||||
$stmtExp->execute([$line['date'], $cat, $line['label'], $finalAmount, $line['ref'], $budgetItemId, $holidayId]);
|
||||
$stmtRule->execute([$line['label'], $cat]);
|
||||
$count++;
|
||||
} catch (Exception $e) { continue; }
|
||||
@@ -89,6 +90,7 @@ if (isset($_POST['action']) && $_POST['action'] === 'save_expense_manual') {
|
||||
|
||||
$label = trim($_POST['label']);
|
||||
$budgetItemId = null;
|
||||
$holidayId = !empty($_POST['holiday_id']) ? (int)$_POST['holiday_id'] : null; // NOUVEAU
|
||||
|
||||
if ($cat === 'School' && !empty($_POST['label_select'])) {
|
||||
$label = trim($_POST['label_select']);
|
||||
@@ -98,19 +100,17 @@ if (isset($_POST['action']) && $_POST['action'] === 'save_expense_manual') {
|
||||
}
|
||||
|
||||
if ($label && $amount > 0) {
|
||||
// Gestion du signe (Revenu = Négatif en BDD, Dépense = Positif)
|
||||
// Note: L'utilisateur saisit toujours du positif dans le formulaire
|
||||
$finalAmount = ($cat === 'Income') ? -abs($amount) : abs($amount);
|
||||
|
||||
$is_credit = isset($_POST['is_credit']) ? (int)$_POST['is_credit'] : 0;
|
||||
$finalAmount = $is_credit ? -abs($amount) : abs($amount);
|
||||
if ($id) {
|
||||
// UPDATE
|
||||
$pdo->prepare("UPDATE pf_expenses SET date_exp=?, category=?, label=?, amount=?, budget_item_id=? WHERE id=?")
|
||||
->execute([$date, $cat, $label, $finalAmount, $budgetItemId, $id]);
|
||||
$pdo->prepare("UPDATE pf_expenses SET date_exp=?, category=?, label=?, amount=?, budget_item_id=?, holiday_id=? WHERE id=?")
|
||||
->execute([$date, $cat, $label, $finalAmount, $budgetItemId, $holidayId, $id]);
|
||||
} else {
|
||||
// INSERT
|
||||
$uniqueRef = "MANUAL_" . uniqid();
|
||||
$pdo->prepare("INSERT INTO pf_expenses (date_exp, category, label, amount, import_ref, budget_item_id) VALUES (?, ?, ?, ?, ?, ?)")
|
||||
->execute([$date, $cat, $label, $finalAmount, $uniqueRef, $budgetItemId]);
|
||||
$pdo->prepare("INSERT INTO pf_expenses (date_exp, category, label, amount, import_ref, budget_item_id, holiday_id) VALUES (?, ?, ?, ?, ?, ?, ?)")
|
||||
->execute([$date, $cat, $label, $finalAmount, $uniqueRef, $budgetItemId, $holidayId]);
|
||||
}
|
||||
header("Location: ?tab=suivi"); exit;
|
||||
}
|
||||
@@ -122,6 +122,9 @@ if (isset($_GET['delete_expense'])) {
|
||||
header("Location: ?tab=suivi"); exit;
|
||||
}
|
||||
|
||||
// G. RECUPERATION VACANCES
|
||||
$activeHolidays = $pdo->query("SELECT id, title FROM pf_holidays WHERE status IN ('draft', 'planned', 'booked') ORDER BY start_date ASC")->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// ============================================================================
|
||||
// 2. CALCUL DES BUDGETS & CHARGES FIXES
|
||||
// ============================================================================
|
||||
@@ -318,7 +321,13 @@ function getDisplayLogic($spent, $bg, $type) {
|
||||
} else {
|
||||
$pct = ($bg > 0) ? min(100, ($spent / $bg) * 100) : ($spent > 0 ? 100 : 0);
|
||||
$isOver = ($spent > $bg && $bg > 0);
|
||||
$text = number_format(ceil($spent), 0, ',', ' ') . ' / ' . number_format(ceil($bg), 0, ',', ' ') . ' €';
|
||||
|
||||
// MODIFICATION ICI : On cache le "/ 0 €" si le budget est à 0
|
||||
if ($bg > 0) {
|
||||
$text = number_format(ceil($spent), 0, ',', ' ') . ' / ' . number_format(ceil($bg), 0, ',', ' ') . ' €';
|
||||
} else {
|
||||
$text = number_format(ceil($spent), 0, ',', ' ') . ' €';
|
||||
}
|
||||
}
|
||||
return ['pct' => $pct, 'isOver' => $isOver, 'text' => $text];
|
||||
}
|
||||
@@ -476,6 +485,12 @@ function getDisplayLogic($spent, $bg, $type) {
|
||||
<option value="<?= $inc['id'] ?>"><?= htmlspecialchars($inc['name']) ?> (<?= number_format($inc['amount'],0) ?>€)</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<select name="lines[<?= $idx ?>][holiday_id]" class="pf-input" style="flex:1; border-color:#8b5cf6; background:#f5f3ff;" <?= $dis ?>>
|
||||
<option value="">-- Voyage (Optionnel) --</option>
|
||||
<?php foreach ($activeHolidays as $hol): ?>
|
||||
<option value="<?= $hol['id'] ?>"><?= htmlspecialchars($hol['title']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -565,6 +580,7 @@ function getDisplayLogic($spent, $bg, $type) {
|
||||
<form method="POST">
|
||||
<input type="hidden" name="action" value="save_expense_manual">
|
||||
<input type="hidden" name="expense_id" id="modalExpenseId">
|
||||
|
||||
<div class="form-group" style="margin-bottom:15px;">
|
||||
<label class="pf-label">Catégorie</label>
|
||||
<select name="category" id="modalCatSelect" class="pf-input" onchange="handleModalCatChange(this)">
|
||||
@@ -574,6 +590,14 @@ function getDisplayLogic($spent, $bg, $type) {
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom:15px;">
|
||||
<label class="pf-label">Type de mouvement</label>
|
||||
<select name="is_credit" id="modalIsCredit" class="pf-input" style="font-weight:bold;">
|
||||
<option value="0">Dépense ( - sur le compte )</option>
|
||||
<option value="1">Revenu / Remboursement ( + sur le compte )</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom:15px;">
|
||||
<label class="pf-label">Date</label>
|
||||
<input type="date" name="date" id="modalDate" class="pf-input" value="<?= date('Y-m-d') ?>" required>
|
||||
@@ -613,6 +637,16 @@ function getDisplayLogic($spent, $bg, $type) {
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom:15px;">
|
||||
<label class="pf-label" style="color:#8b5cf6;">🌴 Associer à un voyage (Optionnel)</label>
|
||||
<select name="holiday_id" id="modalHolidayId" class="pf-input" style="border-color:#8b5cf6; background:#f5f3ff;">
|
||||
<option value="">-- Ne pas associer --</option>
|
||||
<?php foreach ($activeHolidays as $hol): ?>
|
||||
<option value="<?= $hol['id'] ?>"><?= htmlspecialchars($hol['title']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom:15px;">
|
||||
<label class="pf-label">Montant (€)</label>
|
||||
<input type="number" step="0.01" name="amount" id="modalAmount" class="pf-input" placeholder="0.00" required>
|
||||
@@ -741,15 +775,19 @@ function openAddModal(catKey, catLabel) {
|
||||
openSuiviModal('manualExpenseModal');
|
||||
document.getElementById('modalTitle').innerText = "Ajouter : " + catLabel;
|
||||
|
||||
document.getElementById('modalExpenseId').value = ""; // Reset ID (ajout)
|
||||
document.getElementById('modalExpenseId').value = "";
|
||||
document.getElementById('modalDate').value = new Date().toISOString().split('T')[0];
|
||||
document.getElementById('modalLabelInput').value = "";
|
||||
document.getElementById('modalAmount').value = "";
|
||||
document.getElementById('modalHolidayId').value = "";
|
||||
|
||||
const catSelect = document.getElementById('modalCatSelect');
|
||||
catSelect.value = catKey;
|
||||
handleModalCatChange(catSelect);
|
||||
|
||||
// Auto-sélection : Si on clique sur le + de "Revenus", on pré-sélectionne "Revenu"
|
||||
document.getElementById('modalIsCredit').value = (catKey === 'Income') ? "1" : "0";
|
||||
|
||||
setTimeout(() => document.getElementById('modalLabelInput').focus(), 100);
|
||||
}
|
||||
|
||||
@@ -762,14 +800,17 @@ function openEditModal(expenseData) {
|
||||
document.getElementById('modalDate').value = expenseData.date_exp;
|
||||
document.getElementById('modalLabelInput').value = expenseData.label;
|
||||
|
||||
// Le montant en BDD est signé (- pour revenus), on remet en absolu pour l'input
|
||||
document.getElementById('modalAmount').value = Math.abs(parseFloat(expenseData.amount));
|
||||
// NOUVEAU : On lit la vraie valeur en BDD pour définir le type (+ ou -)
|
||||
const rawAmount = parseFloat(expenseData.amount);
|
||||
document.getElementById('modalIsCredit').value = rawAmount < 0 ? "1" : "0";
|
||||
|
||||
document.getElementById('modalAmount').value = Math.abs(rawAmount);
|
||||
document.getElementById('modalHolidayId').value = expenseData.holiday_id || "";
|
||||
|
||||
const catSelect = document.getElementById('modalCatSelect');
|
||||
catSelect.value = expenseData.category;
|
||||
handleModalCatChange(catSelect);
|
||||
|
||||
// Pré-remplir les selects spécifiques
|
||||
if (expenseData.category === 'Frais') {
|
||||
document.getElementById('fraisSelect').value = expenseData.budget_item_id;
|
||||
} else if (expenseData.category === 'Income') {
|
||||
|
||||
Reference in New Issue
Block a user