Resolve the full entrée/versement group regardless of the sliding window

filterEntreeGroup, reconciliationByEntree and versementStatus only ever
searched `rows`, the currently loaded date-range slice -- a versement
linked to entrées from other years (confirmed live: one node had 3
linked entrées spanning 2023/2025/2025) silently only showed whatever
happened to be in the loaded window, both in the drill-down modal and in
the reste-à-verser/sur-versé math.

Added LedgerStatsController::groupeEntree() (GET /lignes/api/groupe/
{node}), a real DB query following field_entree_liee in both directions
(a node's own targets, and any node referencing it) -- something the
client can't discover from a partial window. toggleEntreeFilter() now
fetches the complete group up front and merges whatever isn't already
loaded into groupExtraRows; every affected computed reads the combined
pool via a new allKnownRows.

Also stopped versementStatus from defaulting to a false "ok" when a
linked entrée's reconciliation can't be resolved yet -- it now reports a
distinct "inconnu" (À vérifier) status instead of silently assuming
everything's settled.
This commit is contained in:
2026-09-05 19:03:41 +02:00
parent 619a2ab70c
commit b73a980282
4 changed files with 177 additions and 19 deletions
@@ -3,6 +3,7 @@
namespace Drupal\figli_compta_ledger\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\node\NodeInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
@@ -176,4 +177,51 @@ class LedgerStatsController extends ControllerBase {
return new JsonResponse($result);
}
/**
* GET /lignes/api/groupe/{node} -- the full transitive closure of
* entrée/sortie nodes connected via field_entree_liee, following links
* in *both* directions (this node's own field_entree_liee targets, and
* any other node that references it). The client's sliding window only
* ever holds a date-range slice of `rows` -- a versement can link to
* (or be linked from) an entrée dated years earlier or later, so
* finding the complete group from whatever happens to be loaded is not
* possible client-side; the reverse direction in particular ("which
* sorties reference this entrée") needs a real query, not a scan of
* already-loaded rows. Returns node ids only (not full ligne data) --
* the client re-fetches those specific ids via JSON:API, reusing its
* existing row-building/reconciliation code for the result.
*/
public function groupeEntree(NodeInterface $node) {
$storage = $this->entityTypeManager()->getStorage('node');
$ids = [(int) $node->id() => TRUE];
$queue = [(int) $node->id()];
while ($queue) {
$current_id = array_shift($queue);
$current = $storage->load($current_id);
if (!$current || !$current->hasField('field_entree_liee')) {
continue;
}
foreach ($current->get('field_entree_liee')->referencedEntities() as $entree) {
$eid = (int) $entree->id();
if (!isset($ids[$eid])) {
$ids[$eid] = TRUE;
$queue[] = $eid;
}
}
$referencing = $storage->getQuery()
->accessCheck(TRUE)
->condition('type', 'ligne_comptable')
->condition('field_entree_liee', $current_id)
->execute();
foreach ($referencing as $nid) {
$nid = (int) $nid;
if (!isset($ids[$nid])) {
$ids[$nid] = TRUE;
$queue[] = $nid;
}
}
}
return new JsonResponse(['nids' => array_keys($ids)]);
}
}