feat(billing,bank): capture + void web UI (plan phase 5 web)
Completes phase 5 — the ledger and chequera pages get the append+void UI on top of the phase-5 API. Web: - Shared MovementForm (customer picker + línea + cargo/abono sign + amount + moneda + concepto facet + periodo/referencia/cheque/mensaje). Used by both /estado-cuenta (cross-customer, picker) and /estado-cuenta/[id] (customer prefilled). - /estado-cuenta and /estado-cuenta/[id]: "Capturar movimiento" toggle gated ledger:create; per-row "Anular" gated ledger:void; voided rows struck-through. Save/void refresh the list + stats. - /banco: inline BankCaptureForm (ingreso/egreso sign, cheque, operado, transferencia, monto en letras) gated bank:create; per-row "Anular" gated bank:void; voided rows struck-through. - api.ts: createMovement/voidMovement, createBankMovement/voidBankMovement; CreateMovementInput/CreateBankMovementInput types; `voided` on the movement/statement/bank list items. Also: lookups.controller.ts now audit-logs provider/policy-type/adjuster create/update/delete (parity with the other write controllers). API + web compile clean. This is the last piece of the feat/crud-rbac branch — all five sections plus users are now full CRUD with role gating. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,8 @@ import type {
|
||||
BillingFacets,
|
||||
BillingStats,
|
||||
BusinessLine,
|
||||
CreateBankMovementInput,
|
||||
CreateMovementInput,
|
||||
CustomerDetail,
|
||||
CustomerInput,
|
||||
CustomerListResponse,
|
||||
@@ -43,6 +45,7 @@ import type {
|
||||
Role,
|
||||
ServiceKind,
|
||||
Statement,
|
||||
Transaction,
|
||||
TransactionDomain,
|
||||
TrustFilter,
|
||||
UserRow,
|
||||
@@ -477,6 +480,22 @@ export function getStatement(customerId: string): Promise<Statement> {
|
||||
return apiFetch<Statement>(`/billing/customers/${customerId}`);
|
||||
}
|
||||
|
||||
/** Append a new ledger movement. Booked movements are never edited — fix
|
||||
* mistakes with voidMovement + a fresh capture. */
|
||||
export function createMovement(
|
||||
input: CreateMovementInput,
|
||||
): Promise<Transaction> {
|
||||
return apiFetch<Transaction>("/billing", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
}
|
||||
|
||||
/** Reverse a movement by marking it voided; totals drop it. 400 if already void. */
|
||||
export function voidMovement(id: string): Promise<Transaction> {
|
||||
return apiFetch<Transaction>(`/billing/${id}/void`, { method: "POST" });
|
||||
}
|
||||
|
||||
/* ------------------------------------------------- Bank register (chequera) */
|
||||
|
||||
export interface BankQuery {
|
||||
@@ -517,6 +536,22 @@ export function getBankSummary(year?: number): Promise<BankSummary> {
|
||||
return apiFetch<BankSummary>(`/bank/summary${year ? `?year=${year}` : ""}`);
|
||||
}
|
||||
|
||||
/** Append a new chequera movement. Booked rows are never edited — fix mistakes
|
||||
* with voidBankMovement + a fresh capture. */
|
||||
export function createBankMovement(
|
||||
input: CreateBankMovementInput,
|
||||
): Promise<unknown> {
|
||||
return apiFetch("/bank", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
}
|
||||
|
||||
/** Reverse a chequera movement by marking it voided; totals drop it. */
|
||||
export function voidBankMovement(id: string): Promise<unknown> {
|
||||
return apiFetch(`/bank/${id}/void`, { method: "POST" });
|
||||
}
|
||||
|
||||
/* ------------------------------------------------- Users / administration */
|
||||
|
||||
export function listUsers(): Promise<UserRow[]> {
|
||||
|
||||
Reference in New Issue
Block a user