feat(policies): full CRUD + child editors + insurance lookups (plan phase 3)
Policy header, all five child collections, and the insurance reference catalogs become create/edit/delete-able on the RBAC foundation. API: - Policy gains archivedAt (soft-delete); list/browser default to archivedAt=null with ?includeArchived opt-in. - PoliciesService: header create/update/archive/restore (customer FK validated for a clean 404); add/update/remove for installments, vehicles, drivers, beneficiaries, claims — each scoped to its policy so one policy's id can't touch another's rows; lookups CRUD for providers, policy types, adjusters. - PoliciesController write routes: header create/update need STAFF+ (policy:create/update), archive/restore need MANAGER+ (policy:delete), every child route needs policy:update. New LookupsController at /lookups (read open; mutate needs lookup:manage / MANAGER+). Mutations audited. - DTOs (policy header, children, lookups); dates coerced; shared coerce.ts. Web: - Generic ChildCollection editor (config-driven add/edit/remove table), reused by both the policy detail child editors and the catalogs screen. - PolicyForm (header) with type/provider selects and a debounced CustomerPicker; /polizas/nuevo (accepts ?customerId prefill) and /polizas/[id]/editar. Policy detail: gated action bar (Editar/Archivar) + "Administrar detalles" child editors for all five collections. - /catalogos admin screen (aseguradoras/tipos/ajustadores), nav-gated on lookup:manage. "Nueva póliza" buttons on the list and on the customer detail (prefilled). api.ts + types for all of the above. Verified against dev: policy create (dates coerced, archivedAt null), installment/vehicle add, VIEWER child-add 403, cross-policy child guard 404, lookups CRUD with VIEWER 403 / MANAGER 201, archive drops from the default list and includeArchived surfaces it. Both apps compile clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -98,7 +98,11 @@ function Detail({ id }: { id: string }) {
|
||||
|
||||
<DatosSection data={data} />
|
||||
<PropiedadesSection properties={data.properties} />
|
||||
<PolizasSection policies={data.policies} />
|
||||
<PolizasSection
|
||||
policies={data.policies}
|
||||
customerId={data.id}
|
||||
customerName={data.name}
|
||||
/>
|
||||
<EstadoCuentaSection
|
||||
customerId={data.id}
|
||||
summary={data.transactionSummary}
|
||||
@@ -452,14 +456,33 @@ function PropertyCard({ p }: { p: Property }) {
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------ Pólizas de seguro */
|
||||
function PolizasSection({ policies }: { policies: Policy[] }) {
|
||||
function PolizasSection({
|
||||
policies,
|
||||
customerId,
|
||||
customerName,
|
||||
}: {
|
||||
policies: Policy[];
|
||||
customerId: string;
|
||||
customerName: string;
|
||||
}) {
|
||||
const canCreate = useCan("policy:create");
|
||||
return (
|
||||
<section className="section">
|
||||
<SectionHead
|
||||
rule="seguros"
|
||||
title="Pólizas de seguro"
|
||||
count={policies.length}
|
||||
/>
|
||||
<div className="detail-actionbar">
|
||||
<SectionHead
|
||||
rule="seguros"
|
||||
title="Pólizas de seguro"
|
||||
count={policies.length}
|
||||
/>
|
||||
{canCreate && (
|
||||
<Link
|
||||
href={`/polizas/nuevo?customerId=${customerId}&customerName=${encodeURIComponent(customerName)}`}
|
||||
className="btn btn-outline"
|
||||
>
|
||||
+ Nueva póliza
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
<div className="card">
|
||||
{policies.length === 0 ? (
|
||||
<div className="empty-inline">
|
||||
|
||||
Reference in New Issue
Block a user