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>
63 lines
2.6 KiB
TypeScript
63 lines
2.6 KiB
TypeScript
import {
|
|
IsBoolean,
|
|
IsInt,
|
|
IsNumber,
|
|
IsOptional,
|
|
IsString,
|
|
MinLength,
|
|
} from "class-validator";
|
|
import { Currency } from "@jorgecuadros/database";
|
|
import { IsEnum } from "class-validator";
|
|
|
|
/** Editable policy-header fields. coveragesJson (freeform legacy blob) is not
|
|
* exposed for editing. Dates arrive as ISO strings and are coerced by the
|
|
* service. `total` is legacy-dead data — the UI uses netPremium. */
|
|
export class CreatePolicyDto {
|
|
@IsString() @MinLength(1) policyNumber!: string;
|
|
@IsString() @MinLength(1) customerId!: string;
|
|
|
|
@IsOptional() @IsString() policyTypeId?: string;
|
|
@IsOptional() @IsString() insuranceProviderId?: string;
|
|
@IsOptional() @IsString() agentName?: string;
|
|
@IsOptional() @IsString() policyDate?: string;
|
|
@IsOptional() @IsString() policyFrom?: string;
|
|
@IsOptional() @IsString() policyTo?: string;
|
|
@IsOptional() @IsInt() coveragePeriodDays?: number;
|
|
@IsOptional() @IsNumber() netPremium?: number;
|
|
@IsOptional() @IsNumber() policyFee?: number;
|
|
@IsOptional() @IsNumber() brokerFee?: number;
|
|
@IsOptional() @IsNumber() commission?: number;
|
|
@IsOptional() @IsNumber() total?: number;
|
|
@IsOptional() @IsEnum(Currency) currency?: Currency;
|
|
@IsOptional() @IsString() observations?: string;
|
|
@IsOptional() @IsString() notes?: string;
|
|
@IsOptional() @IsBoolean() endorsement?: boolean;
|
|
@IsOptional() @IsBoolean() liquidated?: boolean;
|
|
@IsOptional() @IsString() liquidationNumber?: string;
|
|
@IsOptional() @IsString() liquidationDate?: string;
|
|
}
|
|
|
|
/** All header fields optional (customerId is not re-assignable on update). */
|
|
export class UpdatePolicyDto {
|
|
@IsOptional() @IsString() @MinLength(1) policyNumber?: string;
|
|
@IsOptional() @IsString() policyTypeId?: string;
|
|
@IsOptional() @IsString() insuranceProviderId?: string;
|
|
@IsOptional() @IsString() agentName?: string;
|
|
@IsOptional() @IsString() policyDate?: string;
|
|
@IsOptional() @IsString() policyFrom?: string;
|
|
@IsOptional() @IsString() policyTo?: string;
|
|
@IsOptional() @IsInt() coveragePeriodDays?: number;
|
|
@IsOptional() @IsNumber() netPremium?: number;
|
|
@IsOptional() @IsNumber() policyFee?: number;
|
|
@IsOptional() @IsNumber() brokerFee?: number;
|
|
@IsOptional() @IsNumber() commission?: number;
|
|
@IsOptional() @IsNumber() total?: number;
|
|
@IsOptional() @IsEnum(Currency) currency?: Currency;
|
|
@IsOptional() @IsString() observations?: string;
|
|
@IsOptional() @IsString() notes?: string;
|
|
@IsOptional() @IsBoolean() endorsement?: boolean;
|
|
@IsOptional() @IsBoolean() liquidated?: boolean;
|
|
@IsOptional() @IsString() liquidationNumber?: string;
|
|
@IsOptional() @IsString() liquidationDate?: string;
|
|
}
|