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