Add solde totals footer row + fix JSON:API pagination duplicate bug

- tfoot row: sum per compte (créditeur/débiteur colored) for the
  currently filtered rows, plus HT/TTC/écart totals
- Fixed a real bug: fetchAllLignes() paginated without a unique sort key
  (field_date_ligne alone, many ties), which let Drupal's JSON:API return
  the same row on two pages -- silently inflating totals (Bachir showed
  -3115,38€ instead of -3013,56€). Now sorts by
  field_date_ligne,drupal_internal__nid (home) / drupal_internal__nid
  (dashboard), plus a defensive client-side de-dup by node id either way.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-03 23:04:33 +02:00
co-authored by Claude Sonnet 5
parent 41ab7445f7
commit 2ebfa3b413
4 changed files with 64 additions and 4 deletions
@@ -11,7 +11,9 @@
const EUR = new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR' });
async function fetchAllLignes() {
let url = API_BASE + '?include=field_repartition,field_repartition.field_compte,field_client&page[limit]=50';
// sort by nid: without an explicit, unique sort key, offset pagination
// can silently duplicate or skip rows across pages.
let url = API_BASE + '?include=field_repartition,field_repartition.field_compte,field_client&page[limit]=50&sort=drupal_internal__nid';
const allData = [];
const includedMap = new Map();
while (url) {
@@ -22,7 +24,10 @@
(json.included || []).forEach((item) => includedMap.set(item.type + ':' + item.id, item));
url = json.links && json.links.next ? json.links.next.href : null;
}
return { data: allData, includedMap };
// Defensive de-dup by node id, in case pagination ever repeats a row.
const seen = new Set();
const dedup = allData.filter((n) => (seen.has(n.id) ? false : (seen.add(n.id), true)));
return { data: dedup, includedMap };
}
function resolve(includedMap, ref) {