Add "Répartition de l'activité par type" chart to /dashboard/compte
Extends DashboardStatsController::stats()'s répartition-level SQL query to also group by type (not just année/compte), producing a new total_par_type_par_compte breakdown alongside the existing global one. Unlike the reconciliation tables on this page (deliberately entrée/ versement only), this chart covers every type touching the selected compte's répartition, matching what the general /dashboard already shows for the whole ledger. Fixed a latent bug the query change would otherwise have introduced: solde_par_compte_par_annee[année][compte] used to be a 1:1 assignment because each (année, compte) pair was unique in the old query -- adding type to the GROUP BY means several rows can now share that same pair, so it has to accumulate instead of overwrite (verified the accumulated totals exactly match a query without the type split, so this preserves existing behavior for the fields already in use). HBarChart in dashboard-compte.js gained the same colorFor prop dashboard.js's version already has (existing Top clients usage keeps its default green, unaffected). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -57,11 +57,14 @@ class DashboardStatsController extends ControllerBase {
|
||||
$nodeRows = $nodeQuery->execute()->fetchAll();
|
||||
|
||||
// Répartition-level aggregate: one row per (node, compte) répartition
|
||||
// share, pre-summed per (annee, compte) in SQL -- backs solde par
|
||||
// compte, both all-time and per-year (each year's own total already
|
||||
// includes that year's ouverture line, so it *is* that year's closing
|
||||
// balance -- same logic as LedgerStatsController::totauxAnnee()).
|
||||
// share, pre-summed per (annee, compte, type) in SQL -- backs solde
|
||||
// par compte, both all-time and per-year (each year's own total
|
||||
// already includes that year's ouverture line, so it *is* that
|
||||
// year's closing balance -- same logic as
|
||||
// LedgerStatsController::totauxAnnee()), and the per-compte type
|
||||
// breakdown used by /dashboard/compte.
|
||||
$compteQuery = $connection->select('node__field_date_ligne', 'd');
|
||||
$compteQuery->innerJoin('node__field_type_ligne', 't2', 't2.entity_id = d.entity_id');
|
||||
$compteQuery->innerJoin('node__field_repartition', 'r', 'r.entity_id = d.entity_id');
|
||||
$compteQuery->innerJoin('paragraph__field_montant', 'm', 'm.entity_id = r.field_repartition_target_id');
|
||||
$compteQuery->innerJoin('paragraph__field_compte', 'c', 'c.entity_id = r.field_repartition_target_id');
|
||||
@@ -69,9 +72,11 @@ class DashboardStatsController extends ControllerBase {
|
||||
$compteQuery->condition('d.bundle', 'ligne_comptable');
|
||||
$compteQuery->addExpression('SUBSTRING(d.field_date_ligne_value, 1, 4)', 'annee');
|
||||
$compteQuery->addField('tc', 'name', 'compte');
|
||||
$compteQuery->addField('t2', 'field_type_ligne_value', 'type');
|
||||
$compteQuery->addExpression('SUM(m.field_montant_value)', 'total');
|
||||
$compteQuery->groupBy('annee');
|
||||
$compteQuery->groupBy('compte');
|
||||
$compteQuery->groupBy('type');
|
||||
$compteRows = $compteQuery->execute()->fetchAll();
|
||||
|
||||
// --- Aggregate the node-level rows in PHP. ---
|
||||
@@ -114,16 +119,31 @@ class DashboardStatsController extends ControllerBase {
|
||||
// --- Aggregate the répartition-level rows in PHP. ---
|
||||
$soldeParCompte = [];
|
||||
$soldeParCompteParAnnee = [];
|
||||
$totalParTypeParCompte = [];
|
||||
foreach ($compteRows as $row) {
|
||||
$total = (float) $row->total;
|
||||
// Same reasoning: the all-time balance includes every line; the
|
||||
// per-year trend only makes sense for a real year.
|
||||
$soldeParCompte[$row->compte] = ($soldeParCompte[$row->compte] ?? 0) + $total;
|
||||
|
||||
// Per-compte équivalent of $totalParType above -- every type
|
||||
// counts here (not just entree/versement), same "hors ouverture,
|
||||
// valeur absolue" convention.
|
||||
if ($row->type !== 'ouverture') {
|
||||
$totalParTypeParCompte[$row->compte][$row->type] =
|
||||
($totalParTypeParCompte[$row->compte][$row->type] ?? 0) + abs($total);
|
||||
}
|
||||
|
||||
if (!$this->isAnneeValide($row->annee)) {
|
||||
continue;
|
||||
}
|
||||
$annees[$row->annee] = TRUE;
|
||||
$soldeParCompteParAnnee[$row->annee][$row->compte] = round($total, 2);
|
||||
// compteRows now has one row per (année, compte, type) -- several
|
||||
// types can share the same (année, compte), so this has to
|
||||
// accumulate, not overwrite, or only the last type processed for
|
||||
// that year+compte would survive.
|
||||
$soldeParCompteParAnnee[$row->annee][$row->compte] =
|
||||
round(($soldeParCompteParAnnee[$row->annee][$row->compte] ?? 0) + $total, 2);
|
||||
}
|
||||
|
||||
// array_keys() alone would leak PHP's array-key int-casting here: a
|
||||
@@ -148,6 +168,10 @@ class DashboardStatsController extends ControllerBase {
|
||||
'top_clients' => $topClients,
|
||||
'solde_par_compte' => array_map(fn ($v) => round($v, 2), $soldeParCompte),
|
||||
'solde_par_compte_par_annee' => $soldeParCompteParAnnee,
|
||||
'total_par_type_par_compte' => array_map(
|
||||
fn ($parType) => array_map(fn ($v) => round($v, 2), $parType),
|
||||
$totalParTypeParCompte
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user