Index.php

PHP Guest 23 Views Size: 20.06 KB Posted on: Jun 2, 26 @ 9:46 PM
  1. 1<?php
  2. 2session_start();
  3. 3ini_set('display_errors', 1);
  4. 4ini_set('display_startup_errors', 1);
  5. 5error_reporting(E_ALL);
  6. 6
  7. 7require_once __DIR__ . '/../app/Support/helpers.php';
  8. 8require_once __DIR__ . '/../app/Core/Database.php';
  9. 9require_once __DIR__ . '/../app/Core/View.php';
  10. 10require_once __DIR__ . '/../app/Repositories/InvoiceRepository.php';
  11. 11require_once __DIR__ . '/../app/Services/VatCalculator.php';
  12. 12require_once __DIR__ . '/../app/Services/InvoiceBuilder.php';
  13. 13require_once __DIR__ . '/../app/Services/PdfService.php';
  14. 14require_once __DIR__ . '/../app/Services/ExcelGenerator.php';
  15. 15require_once __DIR__ . '/../app/Controllers/DashboardController.php';
  16. 16require_once __DIR__ . '/../app/Controllers/InvoiceController.php';
  17. 17
  18. 18use App\Core\Database;
  19. 19use App\Repositories\InvoiceRepository;
  20. 20use App\Services\VatCalculator;
  21. 21use App\Services\InvoiceBuilder;
  22. 22use App\Services\PdfService;
  23. 23use App\Services\ExcelGenerator;
  24. 24use App\Controllers\DashboardController;
  25. 25use App\Controllers\InvoiceController;
  26. 26$config = require __DIR__ . '/../config/database.php';
  27. 27$pdo = Database::connect($config);
  28. 28
  29. 29$repository = new InvoiceRepository($pdo);
  30. 30$calculator = new VatCalculator(0.20);
  31. 31$builder = new InvoiceBuilder($calculator);
  32. 32$pdfService = new PdfService();
  33. 33$excelService = new ExcelGenerator();
  34. 34$dashboardController = new DashboardController($repository);
  35. 35$invoiceController = new InvoiceController($repository, $calculator, $builder, $pdfService, $excelService);
  36. 36
  37. 37$action = $_GET['action'] ?? 'dashboard';
  38. 38var_dump($action);
  39. 39$dashboardYear = isset($_GET['year']) ? (int)$_GET['year'] : (int)date('Y');
  40. 40
  41. 41if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  42. 42 if ($action === 'store') $invoiceController->store();
  43. 43 if ($action === 'update') $invoiceController->update();
  44. 44 if ($action === 'form') {
  45. 45 echo "TEST: inclusion form.php";
  46. 46 include __DIR__ . '/../app/Views/invoices/form.php';
  47. 47 exit;
  48. 48}
  49. 49
  50. 50
  51. 51if ($action === 'edit') {
  52. 52 $edit = $repository->find((int)($_GET['id'] ?? 0));
  53. 53 var_dump($edit); // ← test
  54. 54 include __DIR__ . '/../app/Views/invoices/form.php';
  55. 55 exit;
  56. 56}
  57. 57
  58. 58
  59. 59
  60. 60 if ($action === 'delete') $invoiceController->delete();
  61. 61 if ($action === 'tva') $invoiceController->selectedVat();
  62. 62}
  63. 63
  64. 64if ($action === 'pdf') {
  65. 65 $invoiceController->pdf();
  66. 66 exit;
  67. 67}
  68. 68
  69. 69if ($action === 'csv') {
  70. 70 // Filtres liste
  71. 71$listYear = isset($_GET['year']) ? (int)$_GET['year'] : (int)date('Y');
  72. 72$listPage = isset($_GET['page']) ? max(1,(int)$_GET['page']) : 1;
  73. 73$listSort = isset($_GET['sort']) ? $_GET['sort'] : 'date_desc';
  74. 74$listQuarter = isset($_GET['quarter']) ? trim($_GET['quarter']) : '';
  75. 75$listQ = isset($_GET['q']) ? trim($_GET['q']) : '';
  76. 76$perPage = 20;
  77. 77$totalInv = $repository->countSearch($listYear, $listQuarter, $listQ);
  78. 78$pages = max(1, (int)ceil($totalInv / $perPage));
  79. 79if ($listPage > $pages) $listPage = $pages;
  80. 80$invoices = $repository->search($listYear, $listPage, $perPage, $listSort, $listQuarter, $listQ);
  81. 81$availYears = $repository->availableYears();
  82. 82 header('Content-Type: text/csv; charset=UTF-8');
  83. 83 header('Content-Disposition: attachment; filename="factures.csv"');
  84. 84 $out = fopen('php://output', 'w');
  85. 85 fputcsv($out, ['FACTURE', 'NUMERO', 'DATE', 'TRIMESTRE', 'ANNEE'], ';');
  86. 86 fputcsv($out, ['LIGNE', 'DESIGNATION', 'QTE', 'PU HT', 'TOTAL HT'], ';');
  87. 87 fputcsv($out, [], ';');
  88. 88 foreach ($invoices as $inv) {
  89. 89 fputcsv($out, ['FACTURE', $inv['invoice_number'], $inv['invoice_date'], $inv['quarter'], $inv['year']], ';');
  90. 90 $it = $pdo->prepare('SELECT * FROM invoice_items WHERE invoice_id=:id ORDER BY id ASC');
  91. 91 $it->execute(['id' => $inv['id']]);
  92. 92 foreach ($it->fetchAll() as $item) {
  93. 93 fputcsv($out, ['LIGNE', $item['description'], $item['quantity'], $item['unit_price_ht'], $item['line_total_ht']], ';');
  94. 94 }
  95. 95 fputcsv($out, ['TOTAL HT', $inv['total_ht']], ';');
  96. 96 fputcsv($out, ['TVA 20%', $inv['total_vat']], ';');
  97. 97 fputcsv($out, ['TOTAL TTC', $inv['total_ttc']], ';');
  98. 98 fputcsv($out, [], ';');
  99. 99 }
  100. 100 fclose($out);
  101. 101 exit;
  102. 102}
  103. 103
  104. 104if ($action === 'excel') {
  105. 105 $xid = isset($_GET['id']) ? (int)$_GET['id'] : 0;
  106. 106 if ($xid > 0) {
  107. 107 ob_end_clean();
  108. 108 header('Location: /TV@/dlxls.php?id=' . $xid);
  109. 109 exit;
  110. 110 }
  111. 111 if (!empty($_POST['invoice_ids'])) {
  112. 112 ob_end_clean();
  113. 113 require_once dirname(__DIR__) . '/dlxls.php';
  114. 114 exit;
  115. 115 }
  116. 116 echo '<div class="container py-4"><div class="alert alert-warning">Selectionnez au moins une facture.</div></div>';
  117. 117 exit;
  118. 118}
  119. 119
  120. 120$invoices = $repository->all();
  121. 121$selectedTotals = $_SESSION['selected_totals'] ?? null;
  122. 122unset($_SESSION['selected_totals']);
  123. 123
  124. 124$edit = null;
  125. 125if ($action === 'edit') {
  126. 126 $edit = $repository->find((int)($_GET['id'] ?? 0));
  127. 127}
  128. 128
  129. 129$yearInvoices = array_values(array_filter($invoices, fn($inv) => (int)$inv['year'] === $dashboardYear));
  130. 130$yearTotals = ['c' => count($yearInvoices), 'ht' => 0, 'vat' => 0, 'ttc' => 0];
  131. 131foreach ($yearInvoices as $inv) {
  132. 132 $yearTotals['ht'] += (float)$inv['total_ht'];
  133. 133 $yearTotals['vat'] += (float)$inv['total_vat'];
  134. 134 $yearTotals['ttc'] += (float)$inv['total_ttc'];
  135. 135}
  136. 136$quarters = $repository->quarterSummary($dashboardYear);
  137. 137$latest = array_slice($yearInvoices, 0, 10);
  138. 138$nextNumber = $repository->nextNumber();
  139. 139?>
  140. 140<!doctype html>
  141. 141<html lang="fr">
  142. 142<head>
  143. 143<meta charset="utf-8">
  144. 144<meta name="viewport" content="width=device-width, initial-scale=1">
  145. 145<title>Facturation TVA</title>
  146. 146<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
  147. 147<link rel="stylesheet" href="assets/css/style.css">
  148. 148</head>
  149. 149<body class="bg-light">
  150. 150<div class="container py-4">
  151. 151 <div class="card card-soft mb-4">
  152. 152 <div class="card-body d-flex justify-content-between align-items-center flex-wrap gap-2">
  153. 153 <div>
  154. 154 <h1 class="h4 mb-1">Facturation TVA</h1>
  155. 155 <div class="text-muted">Dashboard, factures, TVA, PDF, CSV, Excel</div>
  156. 156 </div>
  157. 157 <div class="d-flex gap-2 flex-wrap">
  158. 158 <a href="?action=dashboard&year=<?= (int)$dashboardYear ?>" class="btn btn-outline-primary btn-sm">Dashboard</a>
  159. 159 <a href="?action=list" class="btn btn-outline-primary btn-sm">Factures</a>
  160. 160 <a href="?action=form" class="btn btn-primary btn-sm">Nouvelle facture</a>
  161. 161 <a href="?action=csv" class="btn btn-outline-success btn-sm">Export CSV</a>
  162. 162 <a href="?action=excel" class="btn btn-success btn-sm">Export Excel</a>
  163. 163 </div>
  164. 164 </div>
  165. 165 </div>
  166. 166
  167. 167 <?php if (!empty($_SESSION['success'])): ?>
  168. 168 <div class="alert alert-success"><?= e($_SESSION['success']); unset($_SESSION['success']); ?></div>
  169. 169 <?php endif; ?>
  170. 170
  171. 171 <?php if (!empty($_SESSION['error'])): ?>
  172. 172 <div class="alert alert-danger"><?= e($_SESSION['error']); unset($_SESSION['error']); ?></div>
  173. 173 <?php endif; ?>
  174. 174
  175. 175 <?php if ($action === 'dashboard'): ?>
  176. 176 <div class="card card-soft mb-4">
  177. 177 <div class="card-body">
  178. 178 <div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mb-3">
  179. 179 <h2 class="h5 mb-0">Dashboard <?= (int)$dashboardYear ?></h2>
  180. 180 <form method="get" class="d-flex gap-2 align-items-center">
  181. 181 <input type="hidden" name="action" value="dashboard">
  182. 182 <select name="year" class="form-select form-select-sm" style="width:auto">
  183. 183 <?php for ($y = date('Y'); $y >= date('Y') - 5; $y--): ?>
  184. 184 <option value="<?= (int)$y ?>" <?= $dashboardYear == $y ? 'selected' : '' ?>><?= (int)$y ?></option>
  185. 185 <?php endfor; ?>
  186. 186 </select>
  187. 187 <button class="btn btn-sm btn-primary" type="submit">Voir</button>
  188. 188 </form>
  189. 189 </div>
  190. 190
  191. 191 <div class="row g-3 mb-4">
  192. 192 <div class="col-md-3"><div class="card card-soft"><div class="card-body"><div class="text-muted">Factures <?= (int)$dashboardYear ?></div><div class="fs-4 fw-bold"><?= (int)$yearTotals['c'] ?></div></div></div></div>
  193. 193 <div class="col-md-3"><div class="card card-soft"><div class="card-body"><div class="text-muted">Total HT</div><div class="fs-4 fw-bold"><?= money($yearTotals['ht']) ?></div></div></div></div>
  194. 194 <div class="col-md-3"><div class="card card-soft"><div class="card-body"><div class="text-muted">TVA</div><div class="fs-4 fw-bold"><?= money($yearTotals['vat']) ?></div></div></div></div>
  195. 195 <div class="col-md-3"><div class="card card-soft"><div class="card-body"><div class="text-muted">TTC</div><div class="fs-4 fw-bold"><?= money($yearTotals['ttc']) ?></div></div></div></div>
  196. 196 </div>
  197. 197
  198. 198 <div class="table-responsive">
  199. 199 <table class="table table-sm align-middle mb-0">
  200. 200 <thead><tr><th>Trimestre</th><th>Factures</th><th>HT</th><th>TVA</th><th>TTC</th></tr></thead>
  201. 201 <tbody>
  202. 202 <?php foreach($quarters as $q): ?>
  203. 203 <tr>
  204. 204 <td><?= e($q['quarter']) ?></td>
  205. 205 <td><?= (int)$q['c'] ?></td>
  206. 206 <td><?= money($q['ht']) ?></td>
  207. 207 <td><?= money($q['vat']) ?></td>
  208. 208 <td><?= money($q['ttc']) ?></td>
  209. 209 </tr>
  210. 210 <?php endforeach; ?>
  211. 211 </tbody>
  212. 212 </table>
  213. 213 </div>
  214. 214 </div>
  215. 215 </div>
  216. 216
  217. 217 <div class="card card-soft">
  218. 218 <div class="card-body">
  219. 219 <h2 class="h5 mb-3">Dernières factures de lannée <?= (int)$dashboardYear ?></h2>
  220. 220 <div class="table-responsive">
  221. 221 <table class="table table-sm align-middle">
  222. 222 <thead><tr><th>N°</th><th>Date</th><th>Trimestre</th><th>TVA</th><th>TTC</th></tr></thead>
  223. 223 <tbody>
  224. 224 <?php foreach($latest as $inv): ?>
  225. 225 <tr>
  226. 226 <td><?= e($inv['invoice_number']) ?></td>
  227. 227 <td><?= e($inv['invoice_date']) ?></td>
  228. 228 <td><?= e($inv['quarter']) ?></td>
  229. 229 <td><?= money($inv['total_vat']) ?></td>
  230. 230 <td><?= money($inv['total_ttc']) ?></td>
  231. 231 </tr>
  232. 232 <?php endforeach; ?>
  233. 233 </tbody>
  234. 234 </table>
  235. 235 </div>
  236. 236 </div>
  237. 237 </div>
  238. 238
  239. 239<?php elseif ($action === 'list'): ?>
  240. 240<?php
  241. 241$listYear = isset($_GET['year']) ? (int)$_GET['year'] : (int)date('Y');
  242. 242$listPage = isset($_GET['page']) ? max(1,(int)$_GET['page']) : 1;
  243. 243$listSort = isset($_GET['sort']) ? $_GET['sort'] : 'date_desc';
  244. 244$listQuarter = isset($_GET['quarter']) ? trim($_GET['quarter']) : '';
  245. 245$listQ = isset($_GET['q']) ? trim($_GET['q']) : '';
  246. 246$perPage = 20;
  247. 247$totalInv = $repository->countSearch($listYear, $listQuarter, $listQ);
  248. 248$pages = max(1,(int)ceil($totalInv / $perPage));
  249. 249if ($listPage > $pages) $listPage = $pages;
  250. 250$invoices = $repository->search($listYear, $listPage, $perPage, $listSort, $listQuarter, $listQ);
  251. 251$availYears = $repository->availableYears();
  252. 252$baseParams = http_build_query(array_filter(["action"=>"list","year"=>$listYear,"sort"=>$listSort,"quarter"=>$listQuarter,"q"=>$listQ],fn($v)=>$v!==" "&&$v!==null&&$v!==0));
  253. 253?>
  254. 254
  255. 255<div class="card card-soft mb-3">
  256. 256 <div class="card-body py-2">
  257. 257 <form method="get" id="filterForm" class="row g-2 align-items-end">
  258. 258 <input type="hidden" name="action" value="list">
  259. 259 <div class="col-auto">
  260. 260 <label class="form-label mb-1 small text-muted">Ann&eacute;e</label>
  261. 261 <select name="year" class="form-select form-select-sm" style="width:100px" onchange="document.getElementById(&apos;filterForm&apos;).submit()">
  262. 262 <?php foreach ($availYears as $y): ?>
  263. 263 <option value="<?= (int)$y ?>" <?= (int)$y===$listYear?"selected":"" ?>><?= (int)$y ?></option>
  264. 264 <?php endforeach; ?>
  265. 265 </select>
  266. 266 </div>
  267. 267 <div class="col-auto">
  268. 268 <label class="form-label mb-1 small text-muted">Trimestre</label>
  269. 269 <select name="quarter" class="form-select form-select-sm" style="width:120px" onchange="document.getElementById(&apos;filterForm&apos;).submit()">
  270. 270 <option value="" <?= $listQuarter===""?"selected":"" ?>>Tous</option>
  271. 271 <option value="Q1" <?= $listQuarter==="Q1"?"selected":"" ?>>T1 (Jan-Mar)</option>
  272. 272 <option value="Q2" <?= $listQuarter==="Q2"?"selected":"" ?>>T2 (Avr-Jun)</option>
  273. 273 <option value="Q3" <?= $listQuarter==="Q3"?"selected":"" ?>>T3 (Jul-Sep)</option>
  274. 274 <option value="Q4" <?= $listQuarter==="Q4"?"selected":"" ?>>T4 (Oct-Dec)</option>
  275. 275 </select>
  276. 276 </div>
  277. 277 <div class="col-auto">
  278. 278 <label class="form-label mb-1 small text-muted">Trier</label>
  279. 279 <select name="sort" class="form-select form-select-sm" style="width:150px" onchange="document.getElementById(&apos;filterForm&apos;).submit()">
  280. 280 <option value="date_desc" <?= $listSort==="date_desc"?"selected":"" ?>>Date d&eacute;croissante</option>
  281. 281 <option value="date_asc" <?= $listSort==="date_asc"?"selected":"" ?>>Date croissante</option>
  282. 282 </select>
  283. 283 </div>
  284. 284 <div class="col-auto">
  285. 285 <label class="form-label mb-1 small text-muted">Recherche article</label>
  286. 286 <div class="input-group input-group-sm">
  287. 287 <input type="text" name="q" class="form-control" placeholder="Ex: b&eacute;ton, dalle..." value="<?= htmlspecialchars($listQ) ?>" style="width:180px">
  288. 288 <button type="submit" class="btn btn-primary btn-sm">OK</button>
  289. 289 </div>
  290. 290 </div>
  291. 291 <div class="col-auto">
  292. 292 <label class="form-label mb-1 d-block">&nbsp;</label>
  293. 293 <?php if ($listQuarter!==" "||$listQ!==" "||$listSort!=="date_desc"): ?>
  294. 294 <a href="?action=list&amp;year=<?= $listYear ?>" class="btn btn-sm btn-outline-danger">Effacer</a>
  295. 295 <?php endif; ?>
  296. 296 </div>
  297. 297 <div class="col-auto ms-auto">
  298. 298 <label class="form-label mb-1 d-block">&nbsp;</label>
  299. 299 <span class="text-muted small"><?= $totalInv ?> facture(s)</span>
  300. 300 </div>
  301. 301 </form>
  302. 302 </div>
  303. 303</div>
  304. 304
  305. 305<div class="card card-soft">
  306. 306 <div class="card-body p-0">
  307. 307 <form method="post" action="?action=tva" id="invForm">
  308. 308 <div class="d-flex align-items-center gap-2 px-3 py-2 border-bottom bg-light rounded-top">
  309. 309 <div class="form-check mb-0">
  310. 310 <input class="form-check-input" type="checkbox" id="chkAll" onchange="toggleAll(this)">
  311. 311 <label class="form-check-label small" for="chkAll">Tout s&eacute;lectionner</label>
  312. 312 </div>
  313. 313 <button type="button" class="btn btn-sm btn-outline-secondary" onclick="deselectAll()">D&eacute;s&eacute;lectionner tout</button>
  314. 314 <span class="badge bg-secondary" id="selCount">0 s&eacute;lectionn&eacute;(s)</span>
  315. 315 <div class="ms-auto d-flex gap-2">
  316. 316 <button type="submit" formaction="?action=tva" class="btn btn-sm btn-outline-info">TVA</button>
  317. 317 <button type="submit" formaction="/TV@/dlxls.php" class="btn btn-sm btn-success">Export Excel</button>
  318. 318 </div>
  319. 319 </div>
  320. 320 <div class="table-responsive">
  321. 321 <table class="table table-sm align-middle mb-0">
  322. 322 <thead class="table-light">
  323. 323 <tr>
  324. 324 <th style="width:36px"></th>
  325. 325 <th>N&deg;</th>
  326. 326 <th>Client</th>
  327. 327 <th>Date</th>
  328. 328 <th>Trimestre</th>
  329. 329 <th class="text-end">HT</th>
  330. 330 <th class="text-end">TVA</th>
  331. 331 <th class="text-end">TTC</th>
  332. 332 <th class="text-center">Actions</th>
  333. 333 </tr>
  334. 334 </thead>
  335. 335 <tbody>
  336. 336 <?php if (empty($invoices)): ?>
  337. 337 <tr><td colspan="9" class="text-center text-muted py-4">Aucune facture trouv&eacute;e</td></tr>
  338. 338 <?php else: ?>
  339. 339 <?php foreach ($invoices as $inv): ?>
  340. 340 <tr>
  341. 341 <td><input type="checkbox" name="invoice_ids[]" value="<?= $inv["id"] ?>" class="form-check-input chk" onchange="saveSelection();updateCount()"></td>
  342. 342 <td><strong><?= e($inv["invoice_number"]) ?></strong></td>
  343. 343 <td class="text-truncate" style="max-width:150px"><?= e($inv["client_name"]??"") ?></td>
  344. 344 <td><?= e($inv["invoice_date"]) ?></td>
  345. 345 <td><span class="badge bg-light text-dark border"><?= e($inv["quarter"]) ?></span></td>
  346. 346 <td class="text-end"><?= money($inv["total_ht"]) ?></td>
  347. 347 <td class="text-end"><?= money($inv["total_vat"]) ?></td>
  348. 348 <td class="text-end fw-semibold"><?= money($inv["total_ttc"]) ?></td>
  349. 349 <td class="text-center">
  350. 350 <a href="?action=edit&amp;id=<?= $inv["id"] ?>" class="btn btn-sm btn-outline-primary py-0 px-1">Modifier</a>
  351. 351 <a href="/TV@/genpdf.php?id=<?= $inv["id"] ?>" target="_blank" class="btn btn-sm btn-outline-danger py-0 px-1">PDF</a>
  352. 352 <a href="/TV@/dlxls.php?id=<?= $inv["id"] ?>" class="btn btn-sm btn-outline-success py-0 px-1">XLS</a>
  353. 353 <a href="?action=delete&amp;id=<?= $inv["id"] ?>" class="btn btn-sm btn-outline-secondary py-0 px-1" onclick="return confirm(&apos;Supprimer ?&apos;)">Suppr.</a>
  354. 354 </td>
  355. 355 </tr>
  356. 356 <?php endforeach; ?>
  357. 357 <?php endif; ?>
  358. 358 </tbody>
  359. 359 </table>
  360. 360 </div>
  361. 361 <?php if ($pages>1): ?>
  362. 362 <nav class="d-flex justify-content-center align-items-center py-3 gap-1 flex-wrap">
  363. 363 <?php if ($listPage>1): ?><a href="?<?= $baseParams ?>&amp;page=<?= $listPage-1 ?>" class="btn btn-sm btn-outline-secondary">&laquo;</a><?php endif; ?>
  364. 364 <?php $ps=max(1,$listPage-3);$pe=min($pages,$listPage+3); ?>
  365. 365 <?php if($ps>1): ?><a href="?<?= $baseParams ?>&amp;page=1" class="btn btn-sm btn-outline-secondary">1</a><?php if($ps>2): ?><span class="px-1 text-muted">...</span><?php endif; endif; ?>
  366. 366 <?php for($p=$ps;$p<=$pe;$p++): ?>
  367. 367 <a href="?<?= $baseParams ?>&amp;page=<?= $p ?>" class="btn btn-sm <?= $p===$listPage?"btn-primary":"btn-outline-secondary" ?>"><?= $p ?></a>
  368. 368 <?php endfor; ?>
  369. 369 <?php if($pe<$pages): ?><?php if($pe<$pages-1): ?><span class="px-1 text-muted">...</span><?php endif; ?><a href="?<?= $baseParams ?>&amp;page=<?= $pages ?>" class="btn btn-sm btn-outline-secondary"><?= $pages ?></a><?php endif; ?>
  370. 370 <?php if($listPage<$pages): ?><a href="?<?= $baseParams ?>&amp;page=<?= $listPage+1 ?>" class="btn btn-sm btn-outline-secondary">&raquo;</a><?php endif; ?>
  371. 371 <small class="text-muted ms-2">Page <?= $listPage ?>/<?= $pages ?></small>
  372. 372 </nav>
  373. 373 <?php endif; ?>
  374. 374 </form>
  375. 375 </div>
  376. 376</div>
  377. 377<script>
  378. 378const _SK="inv_sel";
  379. 379function _getS(){try{return JSON.parse(sessionStorage.getItem(_SK)||"[]")}catch(e){return[]}}
  380. 380function saveSelection(){const s=_getS();document.querySelectorAll(".chk").forEach(c=>{const id=c.value;if(c.checked&&!s.includes(id))s.push(id);else if(!c.checked){const i=s.indexOf(id);if(i>-1)s.splice(i,1);}});sessionStorage.setItem(_SK,JSON.stringify(s));updateCount();}
  381. 381function restoreSelection(){const s=_getS();document.querySelectorAll(".chk").forEach(c=>c.checked=s.includes(c.value));updateCount();syncChkAll();}
  382. 382function updateCount(){document.getElementById("selCount").textContent=_getS().length+" sélectionné(s)";}
  383. 383function toggleAll(m){document.querySelectorAll(".chk").forEach(c=>c.checked=m.checked);saveSelection();}
  384. 384function deselectAll(){sessionStorage.removeItem(_SK);document.querySelectorAll(".chk").forEach(c=>c.checked=false);document.getElementById("chkAll").checked=false;updateCount();}
  385. 385function syncChkAll(){const a=document.querySelectorAll(".chk").length,c=document.querySelectorAll(".chk:checked").length;const el=document.getElementById("chkAll");el.checked=a>0&&c===a;el.indeterminate=c>0&&c<a;}
  386. 386document.getElementById("invForm").addEventListener("submit",function(e){const btn=e.submitter;const s=_getS();this.querySelectorAll("input[name=\"invoice_ids[]\"]").forEach(e=>e.remove());s.forEach(id=>{const i=document.createElement("input");i.type="hidden";i.name="invoice_ids[]";i.value=id;this.appendChild(i);});if(btn&&btn.getAttribute("formaction")){this.action=btn.getAttribute("formaction");}});
  387. 387document.addEventListener("DOMContentLoaded",()=>restoreSelection());
  388. 388</script>
  389. 389<?php endif; ?>
  390. 390</div>
  391. 391</body>
  392. 392</html>

Paste brut

Comments 0
Login to join the discussion.
  • No comments yet — be the first.
Login to post a comment. Se connecter/S'enregistrer
We use cookies. To comply with GDPR in the EU and the UK we have to show you these.

We use cookies and similar technologies to keep this website functional (including spam protection via Google reCAPTCHA or Cloudflare Turnstile), and — with your consent — to measure usage and show ads. See Privacy.