feat(bank): chequera register module (plan step 7)
Adds the office's own bank-register browser over the migrated SCOTHIA
data (22,354 bank_transactions), the last self-contained feature module.
API (apps/api/src/bank):
- GET /bank register browser: search over concepto/reference/notes/
amountInWords; direction (income|expense|void), cleared and
date-range filters; 5 sorts; income/expense/net totals for
the whole filtered set, not just the page
- GET /bank/stats headline income/expense/net + counts, date span, pending
- GET /bank/facets year list for the period filter
- GET /bank/summary year and month rollups with a running net-movement figure
Web (/banco): "Movimientos" register + "Resumen por periodo" with year->month
drill-down; added to the AppShell nav as "Chequera".
Deliberately kept OUT of /estado-cuenta: this is the office's own money, not
customer balances, and the two are never summed or shown together.
No category/ramo dimension, and the deferred concept->ramo classifier is
dropped as won't-build: concepto is a payee name (0 of 22,354 match a
category) and TABLA RAMODOS is an expense chart of accounts + owner names,
not the insurance/servicios/fideicomiso split it was assumed to be, so a
classifier would invent data. Single currency (MXN); the "acumulado" is net
movement since the register opened (no opening balance in the source), not a
bank balance. Verified end-to-end in the browser; totals reconcile.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
import { Controller, Get, Query, UseGuards } from "@nestjs/common";
|
||||
import { AuthenticatedGuard } from "../auth/authenticated.guard";
|
||||
import {
|
||||
BankCleared,
|
||||
BankDirection,
|
||||
BankService,
|
||||
BankSort,
|
||||
} from "./bank.service";
|
||||
|
||||
const DIRECTIONS: BankDirection[] = ["income", "expense", "void"];
|
||||
const CLEARED: BankCleared[] = ["cleared", "pending"];
|
||||
const SORTS: BankSort[] = [
|
||||
"date_desc",
|
||||
"date_asc",
|
||||
"amount_desc",
|
||||
"amount_asc",
|
||||
"reference",
|
||||
];
|
||||
|
||||
function one<T>(allowed: T[], value: string | undefined): T | undefined {
|
||||
return allowed.includes(value as T) ? (value as T) : undefined;
|
||||
}
|
||||
|
||||
/** A `YYYY-MM-DD` bound; anything unparseable is treated as absent. */
|
||||
function parseDate(v: string | undefined, endOfDay = false): Date | undefined {
|
||||
if (!v) return undefined;
|
||||
const d = new Date(endOfDay ? `${v}T23:59:59.999Z` : `${v}T00:00:00.000Z`);
|
||||
return Number.isNaN(d.getTime()) ? undefined : d;
|
||||
}
|
||||
|
||||
@UseGuards(AuthenticatedGuard)
|
||||
@Controller("bank")
|
||||
export class BankController {
|
||||
constructor(private readonly bank: BankService) {}
|
||||
|
||||
@Get("stats")
|
||||
stats() {
|
||||
return this.bank.stats();
|
||||
}
|
||||
|
||||
@Get("facets")
|
||||
facets() {
|
||||
return this.bank.facets();
|
||||
}
|
||||
|
||||
/** Year and month rollups with a running net-movement figure. */
|
||||
@Get("summary")
|
||||
summary(@Query("year") year?: string) {
|
||||
const y = Number(year);
|
||||
return this.bank.summary(
|
||||
Number.isInteger(y) && y >= 1900 && y <= 2999 ? y : undefined,
|
||||
);
|
||||
}
|
||||
|
||||
/** The register browser. */
|
||||
@Get()
|
||||
list(
|
||||
@Query("query") query?: string,
|
||||
@Query("page") page?: string,
|
||||
@Query("pageSize") pageSize?: string,
|
||||
@Query("direction") direction?: string,
|
||||
@Query("cleared") cleared?: string,
|
||||
@Query("from") from?: string,
|
||||
@Query("to") to?: string,
|
||||
@Query("sort") sort?: string,
|
||||
) {
|
||||
return this.bank.list({
|
||||
query,
|
||||
page: Math.max(1, Number(page) || 1),
|
||||
pageSize: Math.min(100, Math.max(1, Number(pageSize) || 25)),
|
||||
direction: one(DIRECTIONS, direction),
|
||||
cleared: one(CLEARED, cleared),
|
||||
from: parseDate(from),
|
||||
to: parseDate(to, true),
|
||||
sort: one(SORTS, sort) ?? "date_desc",
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user