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>
147 lines
4.1 KiB
TypeScript
147 lines
4.1 KiB
TypeScript
import {
|
|
Body,
|
|
Controller,
|
|
Delete,
|
|
Get,
|
|
Param,
|
|
Patch,
|
|
Post,
|
|
Req,
|
|
UseGuards,
|
|
} from "@nestjs/common";
|
|
import { Request } from "express";
|
|
import { AuthenticatedGuard } from "../auth/authenticated.guard";
|
|
import { AbilityGuard } from "../auth/ability.guard";
|
|
import { RequireAbility } from "../auth/require-ability.decorator";
|
|
import { AuditService } from "../common/audit.service";
|
|
import { PoliciesService } from "./policies.service";
|
|
import {
|
|
AdjusterDto,
|
|
PolicyTypeDto,
|
|
ProviderDto,
|
|
UpdateAdjusterDto,
|
|
UpdatePolicyTypeDto,
|
|
UpdateProviderDto,
|
|
} from "./lookup.dto";
|
|
|
|
/**
|
|
* Insurance reference data: providers, policy types, adjusters. Reading is open
|
|
* to any authenticated user (the policy form needs the options); mutating needs
|
|
* "lookup:manage" (MANAGER+).
|
|
*/
|
|
@UseGuards(AuthenticatedGuard, AbilityGuard)
|
|
@Controller("lookups")
|
|
export class LookupsController {
|
|
constructor(
|
|
private readonly policies: PoliciesService,
|
|
private readonly audit: AuditService,
|
|
) {}
|
|
|
|
private actingId(req: Request): string {
|
|
return (req.user as { id: string }).id;
|
|
}
|
|
|
|
@Get()
|
|
list() {
|
|
return this.policies.listLookups();
|
|
}
|
|
|
|
@Post("providers")
|
|
@RequireAbility("lookup:manage")
|
|
async createProvider(@Body() dto: ProviderDto, @Req() req: Request) {
|
|
const row = await this.policies.createProvider(dto);
|
|
void this.audit.log(this.actingId(req), "lookup.provider.create", {
|
|
providerId: row.id,
|
|
name: row.name,
|
|
});
|
|
return row;
|
|
}
|
|
@Patch("providers/:id")
|
|
@RequireAbility("lookup:manage")
|
|
async updateProvider(
|
|
@Param("id") id: string,
|
|
@Body() dto: UpdateProviderDto,
|
|
@Req() req: Request,
|
|
) {
|
|
const row = await this.policies.updateProvider(id, dto);
|
|
void this.audit.log(this.actingId(req), "lookup.provider.update", {
|
|
providerId: id,
|
|
});
|
|
return row;
|
|
}
|
|
@Delete("providers/:id")
|
|
@RequireAbility("lookup:manage")
|
|
async removeProvider(@Param("id") id: string, @Req() req: Request) {
|
|
const row = await this.policies.removeProvider(id);
|
|
void this.audit.log(this.actingId(req), "lookup.provider.delete", {
|
|
providerId: id,
|
|
});
|
|
return row;
|
|
}
|
|
|
|
@Post("policy-types")
|
|
@RequireAbility("lookup:manage")
|
|
async createType(@Body() dto: PolicyTypeDto, @Req() req: Request) {
|
|
const row = await this.policies.createPolicyType(dto);
|
|
void this.audit.log(this.actingId(req), "lookup.policyType.create", {
|
|
policyTypeId: row.id,
|
|
name: row.name,
|
|
});
|
|
return row;
|
|
}
|
|
@Patch("policy-types/:id")
|
|
@RequireAbility("lookup:manage")
|
|
async updateType(
|
|
@Param("id") id: string,
|
|
@Body() dto: UpdatePolicyTypeDto,
|
|
@Req() req: Request,
|
|
) {
|
|
const row = await this.policies.updatePolicyType(id, dto);
|
|
void this.audit.log(this.actingId(req), "lookup.policyType.update", {
|
|
policyTypeId: id,
|
|
});
|
|
return row;
|
|
}
|
|
@Delete("policy-types/:id")
|
|
@RequireAbility("lookup:manage")
|
|
async removeType(@Param("id") id: string, @Req() req: Request) {
|
|
const row = await this.policies.removePolicyType(id);
|
|
void this.audit.log(this.actingId(req), "lookup.policyType.delete", {
|
|
policyTypeId: id,
|
|
});
|
|
return row;
|
|
}
|
|
|
|
@Post("adjusters")
|
|
@RequireAbility("lookup:manage")
|
|
async createAdjuster(@Body() dto: AdjusterDto, @Req() req: Request) {
|
|
const row = await this.policies.createAdjuster(dto);
|
|
void this.audit.log(this.actingId(req), "lookup.adjuster.create", {
|
|
adjusterId: row.id,
|
|
});
|
|
return row;
|
|
}
|
|
@Patch("adjusters/:id")
|
|
@RequireAbility("lookup:manage")
|
|
async updateAdjuster(
|
|
@Param("id") id: string,
|
|
@Body() dto: UpdateAdjusterDto,
|
|
@Req() req: Request,
|
|
) {
|
|
const row = await this.policies.updateAdjuster(id, dto);
|
|
void this.audit.log(this.actingId(req), "lookup.adjuster.update", {
|
|
adjusterId: id,
|
|
});
|
|
return row;
|
|
}
|
|
@Delete("adjusters/:id")
|
|
@RequireAbility("lookup:manage")
|
|
async removeAdjuster(@Param("id") id: string, @Req() req: Request) {
|
|
const row = await this.policies.removeAdjuster(id);
|
|
void this.audit.log(this.actingId(req), "lookup.adjuster.delete", {
|
|
adjusterId: id,
|
|
});
|
|
return row;
|
|
}
|
|
}
|