feat(customers): the customer file's estado de cuenta follows the same year rule
Build and Push Images / Build jorgecuadros-web (push) Successful in 1m48s
Build and Push Images / Build jorgecuadros-api (push) Successful in 2m5s

`/clientes/:id` carries its own "Estado de cuenta" card, fed by
CustomersService.detail rather than by BillingService.statement, so the
previous commit left it reading the old way: the last 100 movements of all
time, newest first. Two pages, one label, two orders.

It now covers the current calendar year oldest-first, like the statement and
like the sheet the office prints. The `take: 100` is gone with it — capping a
descending list hid the oldest rows, but capping an ascending one would hide
the newest, and a single year is small (365 rows for the heaviest customer in
the book).

The per-domain totals above the list are untouched and still historical: they
are an unfloored groupBy, so they double-count every customer's opening
balance. That is a separate bug from this one; the card now says out loud that
those figures are lifetime, not this year's.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 20:21:51 -07:00
co-authored by Claude Opus 5
parent 8b8de0fdca
commit 9929a9a3ac
3 changed files with 22 additions and 9 deletions
+9 -7
View File
@@ -128,6 +128,7 @@ function Detail({ id }: { id: string }) {
customerId={data.id}
summary={data.transactionSummary}
transactions={data.transactions}
year={data.transactionYear}
/>
<DocumentosSection data={data} />
</div>
@@ -746,16 +747,18 @@ function EstadoCuentaSection({
customerId,
summary,
transactions,
year,
}: {
customerId: string;
summary: TransactionSummaryRow[];
transactions: Transaction[];
year: number;
}) {
return (
<section className="section">
<SectionHead
rule="cuenta"
title="Estado de cuenta"
title={`Estado de cuenta ${year}`}
count={transactions.length}
countSuffix="movimientos"
/>
@@ -782,7 +785,7 @@ function EstadoCuentaSection({
<div className="card">
{transactions.length === 0 ? (
<div className="empty-inline">Sin movimientos registrados.</div>
<div className="empty-inline">Sin movimientos en {year}.</div>
) : (
<div className="tx-scroll">
<table className="tx-table">
@@ -804,11 +807,10 @@ function EstadoCuentaSection({
</table>
</div>
)}
{transactions.length >= 100 && (
<div className="section-note" style={{ padding: "0 16px 14px" }}>
Mostrando los 100 movimientos más recientes.
</div>
)}
<div className="section-note" style={{ padding: "0 16px 14px" }}>
Movimientos de {year}, del más antiguo al más reciente. Los saldos de
arriba son el acumulado histórico, no el del año.
</div>
</div>
{transactions.length > 0 && (
<p className="section-note">
+2
View File
@@ -1129,6 +1129,8 @@ export interface CustomerDetail {
properties: Property[];
policies: Policy[];
transactions: Transaction[];
/** Calendar year `transactions` covers. */
transactionYear: number;
transactionSummary: TransactionSummaryRow[];
}