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
+11 -2
View File
@@ -96,6 +96,13 @@ export class CustomersService {
/** Full unified customer view: identity + both business lines + ledger. */
async detail(id: string) {
// The movement list on the customer file is the same statement the office
// prints, so it follows the same rule as BillingService.statement: this
// calendar year, oldest-first. No `take` any more — the cap used to hide
// the end of a busy customer's year once the order flipped, and a single
// year is small (365 rows for the heaviest customer in the book).
const yearStart = new Date(Date.UTC(new Date().getUTCFullYear(), 0, 1));
const customer = await this.prisma.customer.findUnique({
where: { id },
include: {
@@ -117,8 +124,8 @@ export class CustomersService {
},
},
transactions: {
orderBy: { transactionDate: "desc" },
take: 100,
where: { transactionDate: { gte: yearStart } },
orderBy: [{ transactionDate: "asc" }, { id: "asc" }],
include: { type: true },
},
},
@@ -140,6 +147,8 @@ export class CustomersService {
return {
...customer,
/** Calendar year the movement list covers. */
transactionYear: yearStart.getUTCFullYear(),
transactionSummary: summary.map((s) => ({
domain: s.domain,
currency: s.currency,