From 9930e9ff5bac124df459fe6ed706f262cf489723 Mon Sep 17 00:00:00 2001 From: SepehrYahyaee <7heycallmegray@gmail.com> Date: Mon, 14 Sep 2026 14:27:23 +0330 Subject: [PATCH] Fixed Participants --- .../case-expert-report.builder.ts | 36 ++-- .../persian-report-labels.ts | 1 - src/common/dto/inquiry-participants.dto.ts | 27 +-- src/expert-claim/expert-claim.service.ts | 14 +- src/expert-insurer/expert-insurer.service.ts | 2 + .../entities/schema/partyRole.enum.ts | 2 +- .../schema/request-management.schema.ts | 2 + .../inquiry-participant-persistence.spec.ts | 30 +++ .../inquiry-participant-resolver.spec.ts | 129 +++++++++++-- .../inquiry-participant-resolver.ts | 121 +++++++----- ...request-management.damaged-inquiry.spec.ts | 44 +++++ ...t-management.previous-policyholder.spec.ts | 130 +++++++++++++ .../request-management.service.ts | 179 +++++++----------- 13 files changed, 518 insertions(+), 199 deletions(-) create mode 100644 src/request-management/request-management.damaged-inquiry.spec.ts create mode 100644 src/request-management/request-management.previous-policyholder.spec.ts diff --git a/src/case-expert-report/case-expert-report.builder.ts b/src/case-expert-report/case-expert-report.builder.ts index 7807991..986f629 100644 --- a/src/case-expert-report/case-expert-report.builder.ts +++ b/src/case-expert-report/case-expert-report.builder.ts @@ -4,6 +4,7 @@ import { } from "src/helpers/blame-damaged-party"; import { toJalaliDateAndTime } from "src/helpers/date-jalali"; import { PartyRole } from "src/request-management/entities/schema/partyRole.enum"; +import { sanitizeStoredInquiryParticipants } from "src/request-management/inquiry-participant-resolver"; import { InsurerFileReportField, InsurerFileReportSection, @@ -611,9 +612,8 @@ function buildParticipantRolesSection( title: string, party: ReportParty | null | undefined, ): InsurerFileReportSection | undefined { - const participants = Array.isArray(party?.participants) - ? party.participants - : []; + const participants = + sanitizeStoredInquiryParticipants(party?.participants) ?? []; const assignments = party?.participantRoles; if (!assignments || participants.length === 0) return undefined; @@ -627,22 +627,20 @@ function buildParticipantRolesSection( const participant = participants.find( (candidate) => String(candidate.participantId) === String(participantId), ); - const value = participant?.unknown - ? PR.unknown - : [ - asString(participant?.fullName), - participant?.nationalCode - ? `${PR.nationalCode}: ${asString(participant.nationalCode)}` - : undefined, - participant?.birthday - ? `${PR.birthDate}: ${formatBirthDate(participant.birthday)}` - : undefined, - participant?.licenseNumber - ? `${PR.licenseNumber}: ${asString(participant.licenseNumber)}` - : undefined, - ] - .filter(Boolean) - .join("، "); + const value = [ + asString(participant?.fullName), + participant?.nationalCode + ? `${PR.nationalCode}: ${asString(participant.nationalCode)}` + : undefined, + participant?.birthday + ? `${PR.birthDate}: ${formatBirthDate(participant.birthday)}` + : undefined, + participant?.licenseNumber + ? `${PR.licenseNumber}: ${asString(participant.licenseNumber)}` + : undefined, + ] + .filter(Boolean) + .join("، "); return { label: roleLabels[role] ?? persianFieldPath(role), value: value || PR.empty, diff --git a/src/case-expert-report/persian-report-labels.ts b/src/case-expert-report/persian-report-labels.ts index 7252051..358c6b1 100644 --- a/src/case-expert-report/persian-report-labels.ts +++ b/src/case-expert-report/persian-report-labels.ts @@ -67,7 +67,6 @@ export const PR = { vehicleOwnerRole: "مالک وسیله نقلیه", thirdPartyPolicyholderRole: "بیمه‌گذار شخص ثالث", carBodyPolicyholderRole: "بیمه‌گذار بدنه", - unknown: "نامشخص", data: "اطلاعات", date: "تاریخ", time: "زمان", diff --git a/src/common/dto/inquiry-participants.dto.ts b/src/common/dto/inquiry-participants.dto.ts index 3cc97c2..db53ff5 100644 --- a/src/common/dto/inquiry-participants.dto.ts +++ b/src/common/dto/inquiry-participants.dto.ts @@ -10,7 +10,7 @@ import { IsNotEmpty, IsOptional, IsString, - MaxLength, + Length, ValidateNested, } from "class-validator"; @@ -51,14 +51,6 @@ export class InquiryParticipantInputDto { @IsEnum(InquiryParticipantRole) sameAs?: InquiryParticipantRole; - @ApiPropertyOptional({ - description: - "Only for the damaged party's third-party policyholder when the identity is genuinely unknown.", - }) - @IsOptional() - @IsBoolean() - unknown?: boolean; - @ApiPropertyOptional({ example: "0012345678" }) @IsOptional() @IsString() @@ -111,10 +103,23 @@ export class InquiryVehicleInputDto { @Type(() => InquiryPlateDto) previousPlate?: InquiryPlateDto; - @ApiPropertyOptional({ maxLength: 17, example: "NAAM01E15HK123456" }) + @ApiPropertyOptional({ + description: + "National code of the policyholder associated with previousPlate. Required only for RECENTLY_TRANSFERRED vehicles.", + example: "0012345678", + }) @IsOptional() @IsString() - @MaxLength(17) + previousPolicyholderNationalCode?: string; + + @ApiPropertyOptional({ + minLength: 17, + maxLength: 17, + example: "NAAM01E15HK123456", + }) + @IsOptional() + @IsString() + @Length(17, 17) vin?: string; @ApiPropertyOptional({ diff --git a/src/expert-claim/expert-claim.service.ts b/src/expert-claim/expert-claim.service.ts index 69abe5f..b5b5681 100644 --- a/src/expert-claim/expert-claim.service.ts +++ b/src/expert-claim/expert-claim.service.ts @@ -92,6 +92,7 @@ import { ClaimWorkflowStep } from "src/Types&Enums/claim-request-management/clai import { ClaimRequiredDocumentType } from "src/Types&Enums/claim-request-management/required-document-type.enum"; import { BlameRequestType } from "src/Types&Enums/blame-request-management/blameRequestType.enum"; import { PartyRole } from "src/request-management/entities/schema/partyRole.enum"; +import { sanitizeStoredInquiryParticipants } from "src/request-management/inquiry-participant-resolver"; import { GetClaimListV2ResponseDto, ClaimListItemV2Dto, @@ -4551,7 +4552,12 @@ export class ExpertClaimService { (doc as Record).updatedAtFormatted = `${updatedDate} ${updatedTime}`; - docRec.parties = enrichBlamePartiesForAgreementView(docRec); + docRec.parties = enrichBlamePartiesForAgreementView(docRec).map( + (party) => ({ + ...party, + participants: sanitizeStoredInquiryParticipants(party.participants), + }), + ); return docRec; } @@ -4577,7 +4583,11 @@ export class ExpertClaimService { if (Array.isArray(parties)) { out.parties = parties.map((p: any) => p && typeof p === "object" - ? { ...p, vehicle: this.sanitizeVehicleInquiryForApi(p.vehicle) } + ? { + ...p, + participants: sanitizeStoredInquiryParticipants(p.participants), + vehicle: this.sanitizeVehicleInquiryForApi(p.vehicle), + } : p, ); } diff --git a/src/expert-insurer/expert-insurer.service.ts b/src/expert-insurer/expert-insurer.service.ts index 227a42d..d9459d1 100644 --- a/src/expert-insurer/expert-insurer.service.ts +++ b/src/expert-insurer/expert-insurer.service.ts @@ -46,6 +46,7 @@ import { toJalaliDateAndTime } from "src/helpers/date-jalali"; import { enrichBlamePartiesForAgreementView } from "src/helpers/blame-party-agreement-decision"; import { BlameRequestType } from "src/Types&Enums/blame-request-management/blameRequestType.enum"; import { PartyRole } from "src/request-management/entities/schema/partyRole.enum"; +import { sanitizeStoredInquiryParticipants } from "src/request-management/inquiry-participant-resolver"; import { ListQueryV2Dto } from "src/common/dto/list-query-v2.dto"; import { UnifiedFileStatusReportDto, @@ -449,6 +450,7 @@ export class ExpertInsurerService { if (!party || typeof party !== "object") return party; return { ...party, + participants: sanitizeStoredInquiryParticipants(party.participants), person: this.mapPersonForInsurer(party.person, clientNames), vehicle: this.sanitizeVehicleInquiry(party.vehicle), }; diff --git a/src/request-management/entities/schema/partyRole.enum.ts b/src/request-management/entities/schema/partyRole.enum.ts index 5217e74..b827092 100644 --- a/src/request-management/entities/schema/partyRole.enum.ts +++ b/src/request-management/entities/schema/partyRole.enum.ts @@ -66,7 +66,6 @@ export class InquiryParticipant { @Prop({ type: Boolean }) hasDrivingLicense?: boolean; @Prop() licenseNumber?: string; @Prop() licenseType?: string; - @Prop({ type: Boolean }) unknown?: boolean; } export const InquiryParticipantSchema = SchemaFactory.createForClass(InquiryParticipant); @@ -94,6 +93,7 @@ export class Vehicle { @Prop({ enum: ["CURRENT", "RECENTLY_TRANSFERRED"] }) registrationState?: "CURRENT" | "RECENTLY_TRANSFERRED"; @Prop() previousPlateId?: string; + @Prop() previousPolicyholderNationalCode?: string; /** * Full external inquiry payload (Tejarat/SandHub) stored as-is diff --git a/src/request-management/entities/schema/request-management.schema.ts b/src/request-management/entities/schema/request-management.schema.ts index f81b292..fcfbd07 100644 --- a/src/request-management/entities/schema/request-management.schema.ts +++ b/src/request-management/entities/schema/request-management.schema.ts @@ -161,6 +161,7 @@ export class FirstPartyDetail { @Prop() registrationState?: string; @Prop() previousPlateId?: string; + @Prop() previousPolicyholderNationalCode?: string; @Prop() vehicleVin?: string; } @@ -209,6 +210,7 @@ export class SecondPartyDetail { @Prop() registrationState?: string; @Prop() previousPlateId?: string; + @Prop() previousPolicyholderNationalCode?: string; @Prop() vehicleVin?: string; } diff --git a/src/request-management/inquiry-participant-persistence.spec.ts b/src/request-management/inquiry-participant-persistence.spec.ts index eaf64d9..77d5711 100644 --- a/src/request-management/inquiry-participant-persistence.spec.ts +++ b/src/request-management/inquiry-participant-persistence.spec.ts @@ -115,4 +115,34 @@ describe("inquiry participant persistence", () => { expect(() => (query as any)._castUpdate(query.getUpdate())).not.toThrow(); }); + + it("stores the previous policyholder national code with transferred vehicle data", () => { + const BlameRequestModel = model( + "PreviousPolicyholderPersistenceTest", + BlameRequestSchema, + ); + const request = new BlameRequestModel({ + requestNo: "BL-PREVIOUS-POLICYHOLDER", + publicId: "PREVIOUS-POLICYHOLDER", + type: BlameRequestType.THIRD_PARTY, + parties: [ + { + role: PartyRole.FIRST, + person: {}, + vehicle: { + plateId: "22-44-ب-111", + previousPlateId: "33-55-ج-222", + previousPolicyholderNationalCode: "0098765432", + registrationState: "RECENTLY_TRANSFERRED", + vin: "NAAM01E15HK123456", + }, + }, + ], + }); + + expect(request.validateSync()).toBeUndefined(); + expect(request.parties[0].vehicle?.previousPolicyholderNationalCode).toBe( + "0098765432", + ); + }); }); diff --git a/src/request-management/inquiry-participant-resolver.spec.ts b/src/request-management/inquiry-participant-resolver.spec.ts index 42a7956..89ba35a 100644 --- a/src/request-management/inquiry-participant-resolver.spec.ts +++ b/src/request-management/inquiry-participant-resolver.spec.ts @@ -14,6 +14,7 @@ import { resolveInquirySubjects, resolveInquiryVehicle, runPlateInquiryWithFallback, + sanitizeStoredInquiryParticipants, vehiclePlateCandidates, } from "./inquiry-participant-resolver"; @@ -55,6 +56,27 @@ describe("inquiry participant resolver", () => { ).toThrow(BadRequestException); }); + it("requires the previous policyholder national code for a recent transfer", () => { + expect(() => + resolveInquiryVehicle({ + registrationState: VehicleRegistrationState.RECENTLY_TRANSFERRED, + currentPlate: { + leftDigits: "44", + centerAlphabet: "ب", + centerDigits: "111", + ir: "22", + }, + previousPlate: { + leftDigits: "55", + centerAlphabet: "ج", + centerDigits: "222", + ir: "33", + }, + vin: "NAAM01E15HK123456", + }), + ).toThrow("previousPolicyholderNationalCode"); + }); + it("defaults an omitted registration state to CURRENT", () => { expect( resolveInquiryVehicle({ @@ -68,6 +90,75 @@ describe("inquiry participant resolver", () => { ).toBe(VehicleRegistrationState.CURRENT); }); + it("requires an exact 17-character VIN whenever VIN is provided", () => { + expect(() => + resolveInquiryVehicle({ + registrationState: VehicleRegistrationState.CURRENT, + currentPlate: { + leftDigits: "44", + centerAlphabet: "ب", + centerDigits: "111", + ir: "22", + }, + vin: "TOO-SHORT", + }), + ).toThrow("vehicle.vin must contain exactly 17 characters."); + }); + + it("rejects an incomplete current plate", () => { + expect(() => + resolveInquiryVehicle({ + currentPlate: { + leftDigits: "44", + centerAlphabet: "ب", + centerDigits: "", + ir: "22", + }, + }), + ).toThrow("vehicle.currentPlate.centerDigits is required."); + }); + + it("rejects invalid vehicle choice values", () => { + expect(() => + resolveInquiryVehicle({ + registrationState: "SOLD" as any, + currentPlate: { + leftDigits: "44", + centerAlphabet: "ب", + centerDigits: "111", + ir: "22", + }, + }), + ).toThrow("vehicle.registrationState must be CURRENT or RECENTLY_TRANSFERRED."); + + expect(() => + resolveInquiryVehicle({ + currentPlate: { + leftDigits: "44", + centerAlphabet: "ب", + centerDigits: "111", + ir: "22", + }, + isNewCar: "false" as any, + }), + ).toThrow("vehicle.isNewCar must be a boolean."); + }); + + it("rejects a previous policyholder national code for a current registration", () => { + expect(() => + resolveInquiryVehicle({ + registrationState: VehicleRegistrationState.CURRENT, + currentPlate: { + leftDigits: "44", + centerAlphabet: "ب", + centerDigits: "111", + ir: "22", + }, + previousPolicyholderNationalCode: "0098765432", + }), + ).toThrow(BadRequestException); + }); + it("rejects the removed flat inquiry contract", () => { expect(() => resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, { @@ -238,6 +329,7 @@ describe("inquiry participant resolver", () => { currentPlate, previousPlate, vin: "NAAM01E15HK123456", + previousPolicyholderNationalCode: "0098765432", }), ).toEqual([ { kind: "CURRENT", plate: currentPlate }, @@ -293,6 +385,7 @@ describe("inquiry participant resolver", () => { currentPlate, previousPlate, vin: "NAAM01E15HK123456", + previousPolicyholderNationalCode: "0098765432", }, fallbackCurrentPlate: currentPlate, query, @@ -301,6 +394,8 @@ describe("inquiry participant resolver", () => { }); expect(query).toHaveBeenCalledTimes(2); + expect(query).toHaveBeenNthCalledWith(1, currentPlate, "CURRENT"); + expect(query).toHaveBeenNthCalledWith(2, previousPlate, "PREVIOUS"); expect(result.plateKind).toBe("PREVIOUS"); expect(result.attempts).toMatchObject([ { plateKind: "CURRENT", succeeded: false, error: "not found" }, @@ -449,6 +544,7 @@ describe("inquiry participant resolver", () => { currentPlate, previousPlate, vin: "NAAM01E15HK123456", + previousPolicyholderNationalCode: "0098765432", }), fallbackCurrentPlate: currentPlate, query, @@ -487,6 +583,7 @@ describe("inquiry participant resolver", () => { currentPlate, previousPlate, vin: "NAAM01E15HK123456", + previousPolicyholderNationalCode: "0098765432", }), fallbackCurrentPlate: currentPlate, query: async () => ({ mapped: { CompanyName: "پارسیان" } }), @@ -526,6 +623,7 @@ describe("inquiry participant resolver", () => { ir: "33", }, vin: "NAAM01E15HK123456", + previousPolicyholderNationalCode: "0098765432", }), fallbackCurrentPlate: currentPlate, query, @@ -536,7 +634,7 @@ describe("inquiry participant resolver", () => { expect(query).toHaveBeenCalledTimes(1); }); - it("allows an explicitly unknown policyholder only for a damaged-party submission", () => { + it("rejects the removed unknown policyholder option", () => { const input = { driver: { nationalCode: "0012345678", @@ -548,19 +646,24 @@ describe("inquiry participant resolver", () => { }; expect(() => - resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, input), - ).toThrow(BadRequestException); + resolveInquiryParticipants(BlameRequestType.THIRD_PARTY, input as any), + ).toThrow("THIRD_PARTY_POLICYHOLDER does not support the unknown option."); + }); - const resolved = resolveInquiryParticipants( - BlameRequestType.THIRD_PARTY, - input, - { allowUnknownThirdPartyPolicyholder: true }, - ); + it("strips the removed unknown field from historical participant output", () => { expect( - participantForRole( - resolved, - InquiryParticipantRole.THIRD_PARTY_POLICYHOLDER, - ), - ).toMatchObject({ unknown: true }); + sanitizeStoredInquiryParticipants([ + { + participantId: "THIRD_PARTY_POLICYHOLDER", + nationalCode: "0012345678", + unknown: true, + }, + ]), + ).toEqual([ + { + participantId: "THIRD_PARTY_POLICYHOLDER", + nationalCode: "0012345678", + }, + ]); }); }); diff --git a/src/request-management/inquiry-participant-resolver.ts b/src/request-management/inquiry-participant-resolver.ts index 879e21d..15b5013 100644 --- a/src/request-management/inquiry-participant-resolver.ts +++ b/src/request-management/inquiry-participant-resolver.ts @@ -18,11 +18,6 @@ export interface ResolvedInquiryParticipant { hasDrivingLicense?: boolean; licenseNumber?: string; licenseType?: string; - unknown?: boolean; -} - -export interface InquiryParticipantResolutionOptions { - allowUnknownThirdPartyPolicyholder?: boolean; } export interface InquiryParticipantRoleAssignments { @@ -96,6 +91,22 @@ export type ResolvedInquiryVehicle = InquiryVehicleInputDto & { registrationState: VehicleRegistrationState; }; +function assertCompleteInquiryPlate( + plate: InquiryVehicleInputDto["currentPlate"], + path: "vehicle.currentPlate" | "vehicle.previousPlate", +): void { + for (const field of [ + "leftDigits", + "centerAlphabet", + "centerDigits", + "ir", + ] as const) { + if (plate?.[field] == null || String(plate[field]).trim() === "") { + throw new BadRequestException(`${path}.${field} is required.`); + } + } +} + export function participantForRole( resolved: ResolvedInquiryParticipants, role: InquiryParticipantRole, @@ -127,6 +138,23 @@ export function participantForStoredPartyRole( ); } +/** Remove fields retired from the participant contract from historical records. */ +export function sanitizeStoredInquiryParticipants( + participants: unknown, +): Array> | undefined { + if (!Array.isArray(participants)) return undefined; + return participants.map((participant) => { + const plain = + participant && + typeof participant === "object" && + typeof (participant as { toObject?: unknown }).toObject === "function" + ? (participant as { toObject: () => Record }).toObject() + : { ...(participant as Record) }; + delete plain.unknown; + return plain; + }); +} + const ROLE_FIELDS: Record< InquiryParticipantRole, keyof InquiryParticipantFieldsDto @@ -185,7 +213,6 @@ function requiredIdentity( export function resolveInquiryParticipants( caseType: BlameRequestType, input: Partial & Record, - options: InquiryParticipantResolutionOptions = {}, ): ResolvedInquiryParticipants { assertStructuredInquiryInput(input); const hasRoleCompleteInput = Object.values(ROLE_FIELDS).some( @@ -232,32 +259,7 @@ export function resolveInquiryParticipants( resolving.add(role); let participantId: string; - if ( - role === InquiryParticipantRole.THIRD_PARTY_POLICYHOLDER && - value.unknown === true - ) { - if (!options.allowUnknownThirdPartyPolicyholder) { - throw new BadRequestException( - "An unknown third-party policyholder is allowed only for the damaged party.", - ); - } - const hasIdentityFields = Object.entries(value).some( - ([field, fieldValue]) => field !== "unknown" && fieldValue != null, - ); - if (hasIdentityFields) { - throw new BadRequestException( - `${role} must contain either unknown=true or person fields, not both.`, - ); - } - const participant: ResolvedInquiryParticipant = { - participantId: role, - nationalCode: "", - birthday: "", - unknown: true, - }; - participants.set(participant.participantId, participant); - participantId = participant.participantId; - } else if (value.unknown != null) { + if (Object.prototype.hasOwnProperty.call(value, "unknown")) { throw new BadRequestException( `${role} does not support the unknown option.`, ); @@ -314,28 +316,59 @@ export function resolveInquiryParticipants( export function resolveInquiryVehicle( input: InquiryVehicleInputDto, ): ResolvedInquiryVehicle { + if (!input) { + throw new BadRequestException("vehicle is required."); + } const registrationState = input.registrationState ?? VehicleRegistrationState.CURRENT; + if (!Object.values(VehicleRegistrationState).includes(registrationState)) { + throw new BadRequestException( + "vehicle.registrationState must be CURRENT or RECENTLY_TRANSFERRED.", + ); + } + if (input.isNewCar != null && typeof input.isNewCar !== "boolean") { + throw new BadRequestException("vehicle.isNewCar must be a boolean."); + } + const previousPolicyholderNationalCode = String( + input.previousPolicyholderNationalCode ?? "", + ).trim(); if (!input.currentPlate) { throw new BadRequestException("vehicle.currentPlate is required."); } + assertCompleteInquiryPlate(input.currentPlate, "vehicle.currentPlate"); + const vin = String(input.vin ?? "").trim(); + if (vin && vin.length !== 17) { + throw new BadRequestException( + "vehicle.vin must contain exactly 17 characters.", + ); + } if ( registrationState === VehicleRegistrationState.RECENTLY_TRANSFERRED && - (!input.previousPlate || !String(input.vin ?? "").trim()) + (!input.previousPlate || !vin || !previousPolicyholderNationalCode) ) { throw new BadRequestException( - "RECENTLY_TRANSFERRED requires previousPlate and vin.", + "RECENTLY_TRANSFERRED requires previousPlate, vin, and previousPolicyholderNationalCode.", ); } if ( registrationState !== VehicleRegistrationState.RECENTLY_TRANSFERRED && - input.previousPlate + (input.previousPlate || input.previousPolicyholderNationalCode != null) ) { throw new BadRequestException( - "previousPlate is only allowed for RECENTLY_TRANSFERRED vehicles.", + "previousPlate and previousPolicyholderNationalCode are only allowed for RECENTLY_TRANSFERRED vehicles.", ); } - return { ...input, registrationState }; + if (input.previousPlate) { + assertCompleteInquiryPlate(input.previousPlate, "vehicle.previousPlate"); + } + return { + ...input, + registrationState, + ...(vin ? { vin } : {}), + ...(previousPolicyholderNationalCode + ? { previousPolicyholderNationalCode } + : {}), + }; } export function vehiclePlateCandidates(input?: ResolvedInquiryVehicle): Array<{ @@ -459,7 +492,10 @@ export function isPolicyNotFoundError(error: unknown): boolean { export async function runPlateInquiryWithFallback(options: { vehicle?: ResolvedInquiryVehicle; fallbackCurrentPlate: InquiryVehicleInputDto["currentPlate"]; - query: (plate: InquiryVehicleInputDto["currentPlate"]) => Promise; + query: ( + plate: InquiryVehicleInputDto["currentPlate"], + plateKind: "CURRENT" | "PREVIOUS", + ) => Promise; isUsable: (value: T) => boolean; mappedValue: (value: T) => Record; shouldFallbackOnError?: (error: unknown) => boolean; @@ -492,7 +528,7 @@ export async function runPlateInquiryWithFallback(options: { const candidate = candidates[index]; const isLast = index === candidates.length - 1; try { - const value = await options.query(candidate.plate); + const value = await options.query(candidate.plate, candidate.kind); const usable = options.isUsable(value); if (!usable) { attempts.push({ @@ -562,13 +598,8 @@ export async function runPlateInquiryWithFallback(options: { export function normalizeInquirySubmission>( caseType: BlameRequestType, input: T, - options: InquiryParticipantResolutionOptions = {}, ): NormalizedInquirySubmission { - const participants = resolveInquiryParticipants( - caseType, - input as any, - options, - ); + const participants = resolveInquiryParticipants(caseType, input as any); const driver = participantForRole( participants, InquiryParticipantRole.DRIVER, diff --git a/src/request-management/request-management.damaged-inquiry.spec.ts b/src/request-management/request-management.damaged-inquiry.spec.ts new file mode 100644 index 0000000..cb107f0 --- /dev/null +++ b/src/request-management/request-management.damaged-inquiry.spec.ts @@ -0,0 +1,44 @@ +import { RequestManagementService } from "./request-management.service"; + +describe("damaged-party inquiry requirements", () => { + const getService = () => { + const service = Object.create( + RequestManagementService.prototype, + ) as RequestManagementService; + (service as any).sandHubService = { + getShebaValidation: jest.fn().mockResolvedValue({ valid: true }), + }; + return service; + }; + + it("requires Sheba when the claimant/damaged-party validation runs", async () => { + const service = getService(); + + await expect( + (service as any).validateShebaV3( + undefined, + "0012345678", + "client-id", + ), + ).rejects.toThrow("sheba is required for the damaged party."); + expect( + (service as any).sandHubService.getShebaValidation, + ).not.toHaveBeenCalled(); + }); + + it("validates damaged-party Sheba against the vehicle owner's national code", async () => { + const service = getService(); + + await (service as any).validateShebaV3( + "IR123456789012345678901234", + "0012345678", + "client-id", + ); + + expect( + (service as any).sandHubService.getShebaValidation, + ).toHaveBeenCalledWith("0012345678", "IR123456789012345678901234", { + clientId: "client-id", + }); + }); +}); diff --git a/src/request-management/request-management.previous-policyholder.spec.ts b/src/request-management/request-management.previous-policyholder.spec.ts new file mode 100644 index 0000000..53874d5 --- /dev/null +++ b/src/request-management/request-management.previous-policyholder.spec.ts @@ -0,0 +1,130 @@ +import { BlameRequestType } from "src/Types&Enums/blame-request-management/blameRequestType.enum"; +import { RequestManagementService } from "./request-management.service"; + +describe("RequestManagementService previous policyholder routing", () => { + const currentPlate = { + leftDigits: "44", + centerAlphabet: "ب", + centerDigits: "111", + ir: "22", + }; + const previousPlate = { + leftDigits: "55", + centerAlphabet: "ج", + centerDigits: "222", + ir: "33", + }; + const vehicle = { + registrationState: "RECENTLY_TRANSFERRED", + currentPlate, + previousPlate, + previousPolicyholderNationalCode: "0098765432", + vin: "NAAM01E15HK123456", + }; + + function participantInput(caseType: BlameRequestType) { + return { + driver: { + nationalCode: "0011111111", + birthday: "1370/01/01", + hasDrivingLicense: false, + }, + vehicleOwner: { sameAs: "DRIVER" }, + thirdPartyPolicyholder: { + nationalCode: "0022222222", + birthday: "1360/02/02", + }, + ...(caseType === BlameRequestType.CAR_BODY + ? { + carBodyPolicyholder: { + nationalCode: "0033333333", + birthday: "1350/03/03", + }, + } + : {}), + vehicle, + }; + } + + it("uses the previous code only for the previous-plate third-party lookup", async () => { + const service = Object.create(RequestManagementService.prototype) as any; + service.sandHubService = { + getTejaratBlockInquiry: jest + .fn() + .mockResolvedValueOnce({ raw: {}, mapped: {} }) + .mockResolvedValueOnce({ + raw: {}, + mapped: { + CompanyName: "پارسیان", + VinNumberField: vehicle.vin, + }, + }), + }; + const submission = service.normalizeInquiryInput( + BlameRequestType.THIRD_PARTY, + participantInput(BlameRequestType.THIRD_PARTY), + ); + + const result = await service.getThirdPartyPlateInquiry(submission); + + expect(result.plateKind).toBe("PREVIOUS"); + expect( + service.sandHubService.getTejaratBlockInquiry, + ).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + plate: currentPlate, + nationalCodeOfInsurer: "0022222222", + }), + undefined, + ); + expect( + service.sandHubService.getTejaratBlockInquiry, + ).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + plate: previousPlate, + nationalCodeOfInsurer: "0098765432", + }), + undefined, + ); + }); + + it("uses the previous code only for the previous-plate car-body lookup", async () => { + const service = Object.create(RequestManagementService.prototype) as any; + service.sandHubService = { + getCarBodyInquiry: jest + .fn() + .mockResolvedValueOnce({ raw: {}, mapped: {} }) + .mockResolvedValueOnce({ + raw: {}, + mapped: { + policyNumber: "BODY-1", + VinNumberField: vehicle.vin, + }, + }), + }; + const submission = service.normalizeInquiryInput( + BlameRequestType.CAR_BODY, + participantInput(BlameRequestType.CAR_BODY), + ); + + const result = await service.getCarBodyPlateInquiry(submission); + + expect(result.plateKind).toBe("PREVIOUS"); + expect(service.sandHubService.getCarBodyInquiry).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + plate: currentPlate, + nationalCodeOfInsurer: "0033333333", + }), + ); + expect(service.sandHubService.getCarBodyInquiry).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + plate: previousPlate, + nationalCodeOfInsurer: "0098765432", + }), + ); + }); +}); diff --git a/src/request-management/request-management.service.ts b/src/request-management/request-management.service.ts index a3f6c9c..ef53df2 100644 --- a/src/request-management/request-management.service.ts +++ b/src/request-management/request-management.service.ts @@ -130,6 +130,7 @@ import { normalizeInquirySubmission, resolveInquirySubjects, runPlateInquiryWithFallback, + sanitizeStoredInquiryParticipants, } from "./inquiry-participant-resolver"; /** @@ -311,12 +312,8 @@ export class RequestManagementService { private normalizeInquiryInput>( type: BlameRequestType, input: T, - partyRole?: PartyRole, ): NormalizedInquirySubmission { - return normalizeInquirySubmission(type, input, { - allowUnknownThirdPartyPolicyholder: - type === BlameRequestType.THIRD_PARTY && partyRole === PartyRole.SECOND, - }); + return normalizeInquirySubmission(type, input); } private applyInquiryParticipantsToParty( @@ -334,6 +331,8 @@ export class RequestManagementService { party.vehicle.previousPlateId = submission.vehicle.previousPlate ? this.plateToPlateIdString(submission.vehicle.previousPlate) : undefined; + party.vehicle.previousPolicyholderNationalCode = + submission.vehicle.previousPolicyholderNationalCode; if (submission.vehicle.vin) party.vehicle.vin = submission.vehicle.vin; } } @@ -354,24 +353,18 @@ export class RequestManagementService { submission: NormalizedInquirySubmission>, options?: Record, ): Promise { - if (submission.thirdPartyPolicyholder.unknown) { - return { - raw: null, - mapped: {}, - skipped: true, - plateKind: "CURRENT", - attempts: [], - }; - } const subjects = resolveInquirySubjects(submission); const result = await runPlateInquiryWithFallback({ vehicle: submission.vehicle, fallbackCurrentPlate: submission.dto.plate, - query: (plate) => + query: (plate, plateKind) => this.sandHubService.getTejaratBlockInquiry( { plate: plate as any, - nationalCodeOfInsurer: subjects.thirdPartyPolicyNationalCode, + nationalCodeOfInsurer: + plateKind === "PREVIOUS" + ? submission.vehicle!.previousPolicyholderNationalCode! + : subjects.thirdPartyPolicyNationalCode, }, options, ), @@ -401,9 +394,12 @@ export class RequestManagementService { const result = await runPlateInquiryWithFallback({ vehicle: submission.vehicle, fallbackCurrentPlate: submission.dto.plate, - query: (plate) => + query: (plate, plateKind) => this.sandHubService.getCarBodyInquiry({ - nationalCodeOfInsurer: policyholderNationalCode, + nationalCodeOfInsurer: + plateKind === "PREVIOUS" + ? submission.vehicle!.previousPolicyholderNationalCode! + : policyholderNationalCode, plate: plate as any, }), isUsable: (value) => @@ -435,9 +431,6 @@ export class RequestManagementService { "vehicle.vin is required for a VIN/chassis inquiry.", ); } - if (submission.thirdPartyPolicyholder.unknown) { - return { raw: null, mapped: {}, skipped: true }; - } const subjects = resolveInquirySubjects(submission); const result = await this.sandHubService.getPolicyByChassisInquiry( { @@ -446,7 +439,7 @@ export class RequestManagementService { }, options, ); - return { ...result, skipped: false }; + return result; } private async runParticipantPersonalInquiries( @@ -457,9 +450,7 @@ export class RequestManagementService { ): Promise { const participants = submission.participants.legacy ? [submission.thirdPartyPolicyholder] - : submission.participants.participants.filter( - (participant) => !participant.unknown, - ); + : submission.participants.participants; const results: Record = {}; for (const participant of participants) { @@ -598,7 +589,6 @@ export class RequestManagementService { const personal: Record = {}; for (const participant of submission.participants.participants) { - if (participant.unknown) continue; personal[participant.participantId] = await this.sandHubService.getPersonalInquiry( participant.nationalCode, @@ -664,6 +654,8 @@ export class RequestManagementService { [`${prefix}.previousPlateId`]: submission.vehicle?.previousPlate ? this.plateToPlateIdString(submission.vehicle.previousPlate) : undefined, + [`${prefix}.previousPolicyholderNationalCode`]: + submission.vehicle?.previousPolicyholderNationalCode, [`${prefix}.vehicleVin`]: submission.vehicle?.vin, [`${prefix}.policyInquiry`]: audit, }, @@ -1732,12 +1724,9 @@ export class RequestManagementService { const inquirySubmission = this.normalizeInquiryInput( req.type, body, - role, ); body = inquirySubmission.dto as unknown as AddPlateDto; this.applyInquiryParticipantsToParty(party, inquirySubmission); - const policyholderUnknown = - inquirySubmission.thirdPartyPolicyholder.unknown === true; // Validation: driver/insurer sameness rules if (body.driverIsInsurer === false) { @@ -1801,19 +1790,13 @@ export class RequestManagementService { req, "thirdParty", role, - !inquiry.skipped, + true, { source: inquirySource, plateKind: inquiry.plateKind, attempts: inquiry.attempts, raw: inquiryRaw, mapped: inquiryMapped, - ...(inquiry.skipped - ? { - skipped: true, - reason: "Third-party policyholder is unknown", - } - : {}), }, ); if (inquiry.offline?.fanavaranDriverId != null) { @@ -1882,7 +1865,7 @@ export class RequestManagementService { // Find client by company code const clientName = inquiryMapped?.CompanyName; - if (!clientName && !policyholderUnknown) { + if (!clientName) { const error = new BadRequestException( `CompanyName missing from inquiry response`, ); @@ -2183,13 +2166,10 @@ export class RequestManagementService { const inquirySubmission = this.normalizeInquiryInput( req.type, body, - role, ); body = inquirySubmission.dto as unknown as InitialFormVinDto; const subjects = resolveInquirySubjects(inquirySubmission); this.applyInquiryParticipantsToParty(party, inquirySubmission); - const policyholderUnknown = - inquirySubmission.thirdPartyPolicyholder.unknown === true; // Validation: driver/insurer sameness rules (identical to plate path) if (body.driverIsInsurer === false) { @@ -2246,17 +2226,11 @@ export class RequestManagementService { req, "thirdParty", role, - !inquiry.skipped, + true, { source: "ESG_VIN_INQUIRY", raw: inquiryRaw, mapped: inquiryMapped, - ...(inquiry.skipped - ? { - skipped: true, - reason: "Third-party policyholder is unknown", - } - : {}), }, ); } catch (err: any) { @@ -2319,7 +2293,7 @@ export class RequestManagementService { // Resolve insurer client from inquiry response const clientName = inquiryMapped?.CompanyName; - if (!clientName && !policyholderUnknown) { + if (!clientName) { const error = new BadRequestException( "CompanyName missing from VIN inquiry response", ); @@ -3482,8 +3456,6 @@ export class RequestManagementService { const clientName = sandHubReport?.CompanyName; const companyCode = sandHubReport?.CompanyCode; - const policyholderUnknown = - inquirySubmission?.thirdPartyPolicyholder.unknown === true; const client = clientName ? await this.clientService.findOrCreateClientByCompanyCode( companyCode, @@ -3491,7 +3463,7 @@ export class RequestManagementService { ) : null; - if (!client && !policyholderUnknown) { + if (!client) { throw new HttpException("Client not found", HttpStatus.CONFLICT); } @@ -3529,13 +3501,11 @@ export class RequestManagementService { plate: body.plate, nationalCode: body.nationalCodeOfInsurer, }; - const sandHubDoc = policyInquiry?.skipped - ? null - : await this.sandHubService.sandHubDocumentCreator( - user.sub, - request["_doc"]._id, - sandHubDocData, - ); + const sandHubDoc = await this.sandHubService.sandHubDocumentCreator( + user.sub, + request["_doc"]._id, + sandHubDocData, + ); if (partyType === "firstParty" && sandHubDoc) { await this.requestManagementDbService.findAndUpdate( @@ -3592,6 +3562,8 @@ export class RequestManagementService { ?.previousPlate ? this.plateToPlateIdString(inquirySubmission.vehicle.previousPlate) : undefined; + setFields[`${partyDetails}.previousPolicyholderNationalCode`] = + inquirySubmission.vehicle?.previousPolicyholderNationalCode; setFields[`${partyDetails}.vehicleVin`] = inquirySubmission.vehicle?.vin; } @@ -3704,7 +3676,6 @@ export class RequestManagementService { const inquirySubmission = this.normalizeInquiryInput( request.type as BlameRequestType, body, - partyRole, ); body = inquirySubmission.dto as unknown as AddPlateDto; @@ -6641,7 +6612,6 @@ export class RequestManagementService { participantId: participant.participantId, fullName: participant.fullName, hasDrivingLicense: participant.hasDrivingLicense, - unknown: participant.unknown, })) : undefined; const evidenceRaw = party.evidence as Record | undefined; @@ -6951,7 +6921,6 @@ export class RequestManagementService { const inquirySubmission = this.normalizeInquiryInput( req.type, formData.firstPartyPlate, - PartyRole.FIRST, ); this.recordInquiryParticipantContext( req, @@ -7139,6 +7108,8 @@ export class RequestManagementService { previousPlateId: inquirySubmission.vehicle?.previousPlate ? this.plateToPlateIdString(inquirySubmission.vehicle.previousPlate) : undefined, + previousPolicyholderNationalCode: + inquirySubmission.vehicle?.previousPolicyholderNationalCode, vin: inquirySubmission.vehicle?.vin, inquiry: { ...sandHubReport, @@ -7279,7 +7250,6 @@ export class RequestManagementService { const inquirySubmission = this.normalizeInquiryInput( req.type, plateDto, - role, ); this.recordInquiryParticipantContext(req, role, inquirySubmission); const existingPartyIndex = this.getPartyIndex(req, role); @@ -7290,8 +7260,6 @@ export class RequestManagementService { ); } plateDto = inquirySubmission.dto; - const policyholderUnknown = - inquirySubmission.thirdPartyPolicyholder.unknown === true; let inquiry: any; try { if (inquirySubmission.participants.legacy) { @@ -7332,19 +7300,13 @@ export class RequestManagementService { req, "thirdParty", role, - !inquiry.skipped, + true, { source: inquiry.offline?.source ?? "TEJARAT_BLOCK_INQUIRY", plateKind: inquiry.plateKind, attempts: inquiry.attempts, raw: inquiry.raw, mapped: inquiry.mapped, - ...(inquiry.skipped - ? { - skipped: true, - reason: "Third-party policyholder is unknown", - } - : {}), }, ); const clientName = @@ -7358,7 +7320,7 @@ export class RequestManagementService { ) : await this.clientService.findOne({ clientName }) : null; - if (!client && !policyholderUnknown) { + if (!client) { const error = new NotFoundException( `Client not found for company: ${clientName}`, ); @@ -7434,6 +7396,8 @@ export class RequestManagementService { previousPlateId: inquirySubmission.vehicle?.previousPlate ? this.plateToPlateIdString(inquirySubmission.vehicle.previousPlate) : undefined, + previousPolicyholderNationalCode: + inquirySubmission.vehicle?.previousPolicyholderNationalCode, vin: inquirySubmission.vehicle?.vin, inquiry: sandHubReport, }, @@ -8071,7 +8035,6 @@ export class RequestManagementService { const firstInquirySubmission = this.normalizeInquiryInput( BlameRequestType.THIRD_PARTY, formData.firstPartyPlate, - PartyRole.FIRST, ); const firstPartyPlate = firstInquirySubmission.dto; let firstPolicyInquiry: any; @@ -8179,6 +8142,8 @@ export class RequestManagementService { firstInquirySubmission.vehicle.previousPlate, ) : undefined; + firstPartyDetails.previousPolicyholderNationalCode = + firstInquirySubmission.vehicle?.previousPolicyholderNationalCode; firstPartyDetails.vehicleVin = firstInquirySubmission.vehicle?.vin; } @@ -8209,7 +8174,6 @@ export class RequestManagementService { const secondInquirySubmission = this.normalizeInquiryInput( BlameRequestType.THIRD_PARTY, formData.secondParty.plate, - PartyRole.SECOND, ); let secondPolicyInquiry: any; try { @@ -8243,8 +8207,6 @@ export class RequestManagementService { const companyCode = sandHubReport?.CompanyCode; // Try to find client by company code first (more reliable) - const policyholderUnknown = - secondInquirySubmission.thirdPartyPolicyholder.unknown === true; const client = clientName ? companyCode ? await this.clientService.findOrCreateClientByCompanyCode( @@ -8254,7 +8216,7 @@ export class RequestManagementService { : await this.clientService.findOne({ clientName: clientName }) : null; - if (!client && !policyholderUnknown) { + if (!client) { const error = new NotFoundException( `Client not found for company: ${clientName}${companyCode ? ` (code: ${companyCode})` : ""}`, ); @@ -8319,6 +8281,8 @@ export class RequestManagementService { secondInquirySubmission.vehicle.previousPlate, ) : undefined; + secondPartyDetails.previousPolicyholderNationalCode = + secondInquirySubmission.vehicle?.previousPolicyholderNationalCode; secondPartyDetails.vehicleVin = secondInquirySubmission.vehicle?.vin; } @@ -8554,7 +8518,6 @@ export class RequestManagementService { const firstInquirySubmission = this.normalizeInquiryInput( BlameRequestType.CAR_BODY, formData.firstPartyPlate, - PartyRole.FIRST, ); const firstPartyPlate = firstInquirySubmission.dto; let thirdPartyPolicyInquiry: any; @@ -8687,6 +8650,8 @@ export class RequestManagementService { firstInquirySubmission.vehicle.previousPlate, ) : undefined; + firstPartyDetails.previousPolicyholderNationalCode = + firstInquirySubmission.vehicle?.previousPolicyholderNationalCode; firstPartyDetails.vehicleVin = firstInquirySubmission.vehicle?.vin; } firstPartyDetails.firstPartyClient.clientId = @@ -9805,13 +9770,10 @@ export class RequestManagementService { const inquirySubmission = this.normalizeInquiryInput( req.type, partyData, - partyRole, ); partyData = inquirySubmission.dto as RunInquiriesV3Dto; const subjects = resolveInquirySubjects(inquirySubmission); this.applyInquiryParticipantsToParty(party, inquirySubmission); - const policyholderUnknown = - inquirySubmission.thirdPartyPolicyholder.unknown === true; const roleLabel = partyRole === PartyRole.FIRST ? "FIRST" : "SECOND"; let clientId: string | undefined; const inquiryOptions = (cid?: string) => @@ -9838,19 +9800,13 @@ export class RequestManagementService { req, "thirdParty", partyRole, - !inquiry.skipped, + true, { source: inquirySource, plateKind: inquiry.plateKind, attempts: inquiry.attempts, raw: inquiryRaw, mapped: inquiryMapped, - ...(inquiry.skipped - ? { - skipped: true, - reason: "Third-party policyholder is unknown", - } - : {}), }, ); if (inquiry.offline?.fanavaranDriverId != null) { @@ -9900,7 +9856,7 @@ export class RequestManagementService { const clientName = inquiryMapped?.CompanyName; const companyCode = inquiryMapped?.CompanyCode; - if (!clientName && !policyholderUnknown) { + if (!clientName) { const error = new BadRequestException( `CompanyName missing from ${roleLabel} party inquiry response`, ); @@ -10162,10 +10118,14 @@ export class RequestManagementService { vehicleOwnerNationalCode: string, clientId?: string, ): Promise { - if (!sheba) return; + if (!String(sheba ?? "").trim()) { + throw new BadRequestException( + "sheba is required for the damaged party.", + ); + } await this.sandHubService.getShebaValidation( vehicleOwnerNationalCode, - sheba, + sheba!.trim(), clientId ? { clientId } : undefined, ); } @@ -10738,13 +10698,10 @@ export class RequestManagementService { const inquirySubmission = this.normalizeInquiryInput( req.type, partyData, - partyRole, ); partyData = inquirySubmission.dto as RunInquiriesVinV3Dto; const subjects = resolveInquirySubjects(inquirySubmission); this.applyInquiryParticipantsToParty(party, inquirySubmission); - const policyholderUnknown = - inquirySubmission.thirdPartyPolicyholder.unknown === true; const roleLabel = partyRole === PartyRole.FIRST ? "FIRST" : "SECOND"; let clientId: string | undefined; const inquiryOptions = (cid?: string) => @@ -10763,17 +10720,11 @@ export class RequestManagementService { req, "thirdParty", partyRole, - !inquiry.skipped, + true, { source: "ESG_VIN_INQUIRY", raw: inquiryRaw, mapped: inquiryMapped, - ...(inquiry.skipped - ? { - skipped: true, - reason: "Third-party policyholder is unknown", - } - : {}), }, ); } catch (err: any) { @@ -10817,7 +10768,7 @@ export class RequestManagementService { const clientName = inquiryMapped?.CompanyName; const companyCode = inquiryMapped?.CompanyCode; - if (!clientName && !policyholderUnknown) { + if (!clientName) { const error = new BadRequestException( `CompanyName missing from ${roleLabel} party VIN inquiry response`, ); @@ -12320,12 +12271,16 @@ export class RequestManagementService { message: "استعلام طرف مقصر با موفقیت انجام شد. اکنون می‌توانید لینک تقصیر را برای کاربر ارسال کنید.", guiltyParty: { - participants: firstPartyAfter?.participants, + participants: sanitizeStoredInquiryParticipants( + firstPartyAfter?.participants, + ), participantRoles: firstPartyAfter?.participantRoles, vehicle: firstPartyAfter?.vehicle ? { plateId: firstPartyAfter.vehicle.plateId, previousPlateId: firstPartyAfter.vehicle.previousPlateId, + previousPolicyholderNationalCode: + firstPartyAfter.vehicle.previousPolicyholderNationalCode, registrationState: firstPartyAfter.vehicle.registrationState, vin: firstPartyAfter.vehicle.vin, name: firstPartyAfter.vehicle.name, @@ -12435,13 +12390,17 @@ export class RequestManagementService { message: "استعلام VIN طرف مقصر با موفقیت انجام شد. اکنون می‌توانید لینک تقصیر را برای کاربر ارسال کنید.", guiltyParty: { - participants: firstPartyAfter?.participants, + participants: sanitizeStoredInquiryParticipants( + firstPartyAfter?.participants, + ), participantRoles: firstPartyAfter?.participantRoles, vehicle: firstPartyAfter?.vehicle ? { vin: firstPartyAfter.vehicle.vin, plateId: firstPartyAfter.vehicle.plateId, previousPlateId: firstPartyAfter.vehicle.previousPlateId, + previousPolicyholderNationalCode: + firstPartyAfter.vehicle.previousPolicyholderNationalCode, registrationState: firstPartyAfter.vehicle.registrationState, name: firstPartyAfter.vehicle.name, type: firstPartyAfter.vehicle.type, @@ -12684,7 +12643,7 @@ export class RequestManagementService { skipInitialFormStep: (req as any).skipInitialFormStep, parties: ((req as any).parties ?? []).map((p: any) => ({ role: p.role, - participants: p.participants, + participants: sanitizeStoredInquiryParticipants(p.participants), participantRoles: p.participantRoles, person: { phoneNumber: p.person?.phoneNumber, @@ -12709,6 +12668,8 @@ export class RequestManagementService { ? { plateId: p.vehicle.plateId, previousPlateId: p.vehicle.previousPlateId, + previousPolicyholderNationalCode: + p.vehicle.previousPolicyholderNationalCode, registrationState: p.vehicle.registrationState, vin: p.vehicle.vin, name: p.vehicle.name, @@ -12844,7 +12805,7 @@ export class RequestManagementService { requiresFileMakerApproval: plain.requiresFileMakerApproval, parties: (plain.parties ?? []).map((p: any) => ({ role: p.role, - participants: p.participants, + participants: sanitizeStoredInquiryParticipants(p.participants), participantRoles: p.participantRoles, person: { fullName: p.person?.fullName, @@ -12873,6 +12834,8 @@ export class RequestManagementService { ? { plateId: p.vehicle.plateId, previousPlateId: p.vehicle.previousPlateId, + previousPolicyholderNationalCode: + p.vehicle.previousPolicyholderNationalCode, registrationState: p.vehicle.registrationState, vin: p.vehicle.vin, name: p.vehicle.name, @@ -13027,7 +12990,7 @@ export class RequestManagementService { : null, parties: (plain.parties ?? []).map((p: any) => ({ role: p.role, - participants: p.participants, + participants: sanitizeStoredInquiryParticipants(p.participants), participantRoles: p.participantRoles, person: { fullName: p.person?.fullName, @@ -13056,6 +13019,8 @@ export class RequestManagementService { ? { plateId: p.vehicle.plateId, previousPlateId: p.vehicle.previousPlateId, + previousPolicyholderNationalCode: + p.vehicle.previousPolicyholderNationalCode, registrationState: p.vehicle.registrationState, vin: p.vehicle.vin, name: p.vehicle.name,