- 1<?php
- 2$isEdit = !empty($invoice['id']);
- 3?>
- 4<?php if (isset($edit)): ?>
- 5 <!-- Formulaire pré-rempli pour modification -->
- 6 <form method="POST" action="?action=update&id=<?= $edit['id'] ?>">
- 7 <input type="text" name="client_name" value="<?= htmlspecialchars($edit['client_name']) ?>">
- 8 <input type="date" name="invoice_date" value="<?= htmlspecialchars($edit['invoice_date']) ?>">
- 9 <!-- autres champs pré-remplis -->
- 10 <button type="submit">Mettre à jour</button>
- 11 </form>
- 12<?php else: ?>
- 13 <!-- Formulaire vide pour nouvelle facture -->
- 14 <form method="POST" action="?action=store">
- 15 <input type="text" name="client_name" placeholder="Nom du client">
- 16 <input type="date" name="invoice_date">
- 17 <!-- autres champs vides -->
- 18 <button type="submit">Créer</button>
- 19 </form>
- 20<?php endif; ?>
- 21<div class="card card-soft">
- 22 <div class="card-body">
- 23 <h2 class="h5 mb-3"><?= $isEdit ? 'Modifier la facture' : 'Nouvelle facture' ?></h2>
- 24
- 25 <form method="post" action="?action=<?= $isEdit ? 'update' : 'store' ?>">
- 26 <input type="hidden" name="id" value="<?= (int)($invoice['id'] ?? 0) ?>">
- 27<?php if (isset($edit)): ?>
- 28 <form method="POST" action="?action=update&id=<?= $edit->id ?>">
- 29 <!-- champs pré-remplis avec $edit -->
- 30 </form>
- 31<?php else: ?>
- 32 <form method="POST" action="?action=store">
- 33 <!-- champs vides -->
- 34 </form>
- 35<?php endif; ?>
- 36
- 37 <div class="row g-3">
- 38 <div class="col-md-6">
- 39 <label class="form-label">Numéro</label>
- 40 <input class="form-control" type="text" name="invoice_number" value="<?= e($invoice['invoice_number'] ?? $nextNumber ?? '') ?>" required>
- 41 </div>
- 42 <div class="col-md-6">
- 43 <label class="form-label">Date</label>
- 44 <input class="form-control" type="date" name="invoice_date" value="<?= e($invoice['invoice_date'] ?? date('Y-m-d')) ?>" required>
- 45 </div>
- 46 </div>
- 47
- 48 <div class="mt-3">
- 49 <label class="form-label">Notes</label>
- 50 <textarea class="form-control" name="notes" rows="3"><?= e($invoice['notes'] ?? '') ?></textarea>
- 51 </div>
- 52
- 53 <div class="mt-3">
- 54 <label class="form-label">Articles</label>
- 55 <div id="items-wrapper">
- 56 <?php if (!empty($invoice['items'])): ?>
- 57 <?php foreach ($invoice['items'] as $item): ?>
- 58 <div class="row g-2 mb-2 item-row">
- 59 <div class="col-md-6">
- 60 <input class="form-control desc" name="description[]" value="<?= e($item['description'] ?? '') ?>" placeholder="Désignation" required>
- 61 </div>
- 62 <div class="col-md-2">
- 63 <input class="form-control qty" type="number" step="0.01" min="1" name="quantity[]" value="<?= e($item['quantity'] ?? 1) ?>" required>
- 64 </div>
- 65 <div class="col-md-3">
- 66 <input class="form-control price" type="number" step="0.01" min="0" name="unit_price_ht[]" value="<?= e($item['unit_price_ht'] ?? 0) ?>" required>
- 67 </div>
- 68 <div class="col-md-1 d-flex align-items-center">
- 69 <button type="button" class="btn btn-outline-danger btn-sm remove-line">×</button>
- 70 </div>
- 71 </div>
- 72 <?php endforeach; ?>
- 73 <?php else: ?>
- 74 <div class="row g-2 mb-2 item-row">
- 75 <div class="col-md-6">
- 76 <input class="form-control desc" name="description[]" placeholder="Désignation" required>
- 77 </div>
- 78 <div class="col-md-2">
- 79 <input class="form-control qty" type="number" step="0.01" min="1" name="quantity[]" value="1" required>
- 80 </div>
- 81 <div class="col-md-3">
- 82 <input class="form-control price" type="number" step="0.01" min="0" name="unit_price_ht[]" placeholder="Prix HT" required>
- 83 </div>
- 84 <div class="col-md-1 d-flex align-items-center">
- 85 <button type="button" class="btn btn-outline-danger btn-sm remove-line">×</button>
- 86 </div>
- 87 </div>
- 88 <?php endif; ?>
- 89 </div>
- 90 <button type="button" class="btn btn-outline-secondary btn-sm mt-2" id="add-item">Ajouter un article</button>
- 91 </div>
- 92
- 93 <div class="card mt-3 mb-3">
- 94 <div class="card-body">
- 95 <div class="row g-3">
- 96 <div class="col-md-4">
- 97 <label class="form-label">Total HT</label>
- 98 <input class="form-control" id="total_ht" type="text" readonly value="0,00 MAD">
- 99 </div>
- 100 <div class="col-md-4">
- 101 <label class="form-label">TVA 20%</label>
- 102 <input class="form-control" id="total_vat" type="text" readonly value="0,00 MAD">
- 103 </div>
- 104 <div class="col-md-4">
- 105 <label class="form-label">Total TTC</label>
- 106 <input class="form-control" id="total_ttc" type="text" readonly value="0,00 MAD">
- 107 </div>
- 108 </div>
- 109 </div>
- 110 </div>
- 111
- 112 <div class="d-flex flex-wrap gap-2 mt-3">
- 113 <button type="submit" class="btn btn-primary"><?= $isEdit ? 'Mettre à jour' : 'Enregistrer' ?></button>
- 114 <a class="btn btn-outline-success" href="?action=csv">Export CSV</a>
- 115 <?php if ($isEdit && !empty($invoice['id'])): ?>
- 116 <a class="btn btn-success" href="?action=excel&id=<?= (int)$invoice['id'] ?>">Export Excel</a>
- 117 <a class="btn btn-danger" href="?action=pdf&id=<?= (int)$invoice['id'] ?>" target="_blank">PDF</a>
- 118 <?php endif; ?>
- 119 </div>
- 120 </form>
- 121 </div>
- 122</div>
- 123
- 124<script>
- 125function money(v){ return Number(v || 0).toFixed(2).replace('.', ',') + ' MAD'; }
- 126function calculateTotals(){
- 127 let ht = 0;
- 128 document.querySelectorAll('.item-row').forEach(row => {
- 129 const qty = parseFloat(row.querySelector('.qty')?.value || 0);
- 130 const price = parseFloat(row.querySelector('.price')?.value || 0);
- 131 if (!isNaN(qty) && !isNaN(price)) ht += qty * price;
- 132 });
- 133 const vat = ht * 0.20;
- 134 const ttc = ht + vat;
- 135 document.getElementById('total_ht').value = money(ht);
- 136 document.getElementById('total_vat').value = money(vat);
- 137 document.getElementById('total_ttc').value = money(ttc);
- 138}
- 139function addItemRow(){
- 140 const w = document.getElementById('items-wrapper');
- 141 const div = document.createElement('div');
- 142 div.className = 'row g-2 mb-2 item-row';
- 143 div.innerHTML = '<div class="col-md-6"><input class="form-control desc" name="description[]" placeholder="Désignation" required></div><div class="col-md-2"><input class="form-control qty" type="number" step="0.01" min="1" name="quantity[]" value="1" required></div><div class="col-md-3"><input class="form-control price" type="number" step="0.01" min="0" name="unit_price_ht[]" placeholder="Prix HT" required></div><div class="col-md-1 d-flex align-items-center"><button type="button" class="btn btn-outline-danger btn-sm remove-line">×</button></div>';
- 144 w.appendChild(div);
- 145 bindRow(div);
- 146 calculateTotals();
- 147}
- 148function bindRow(row){
- 149 row.querySelector('.qty')?.addEventListener('input', calculateTotals);
- 150 row.querySelector('.price')?.addEventListener('input', calculateTotals);
- 151 row.querySelector('.remove-line')?.addEventListener('click', function(){
- 152 if (document.querySelectorAll('.item-row').length > 1) row.remove();
- 153 calculateTotals();
- 154 });
- 155}
- 156document.querySelectorAll('.item-row').forEach(bindRow);
- 157document.getElementById('add-item')?.addEventListener('click', addItemRow);
- 158document.addEventListener('input', function(e){ if (e.target.classList.contains('qty') || e.target.classList.contains('price')) calculateTotals(); });
- 159document.addEventListener('DOMContentLoaded', calculateTotals);
- 160</script>
Paste brut