From b5b18114d8dd4fd76abc0dab4d875f15c131c595 Mon Sep 17 00:00:00 2001 From: SepehrYahyaee <7heycallmegray@gmail.com> Date: Sun, 13 Sep 2026 11:29:43 +0330 Subject: [PATCH] Complete inquiry participant flow coverage --- .../case-expert-report.builder.spec.ts | 162 +++++--- .../case-expert-report.builder.ts | 207 ++++++++-- .../persian-report-labels.ts | 7 + src/common/dto/inquiry-participants.dto.ts | 9 +- .../schema/request-management.schema.ts | 32 ++ .../inquiry-participant-resolver.spec.ts | 35 ++ .../inquiry-participant-resolver.ts | 28 ++ .../request-management.service.ts | 385 +++++++++++++++--- 8 files changed, 698 insertions(+), 167 deletions(-) diff --git a/src/case-expert-report/case-expert-report.builder.spec.ts b/src/case-expert-report/case-expert-report.builder.spec.ts index e81d259..5fc36d4 100644 --- a/src/case-expert-report/case-expert-report.builder.spec.ts +++ b/src/case-expert-report/case-expert-report.builder.spec.ts @@ -70,6 +70,26 @@ describe("buildInsurerFileReport", () => { }, { role: "SECOND", + participants: [ + { + participantId: "DRIVER", + fullName: "راننده نمونه", + nationalCode: "0012345678", + birthday: "1370/01/01", + licenseNumber: "LIC-1", + }, + { + participantId: "VEHICLE_OWNER", + fullName: "زیان دیده نمونه", + nationalCode: "1234567890", + birthday: "1370/01/01", + }, + ], + participantRoles: { + driver: "DRIVER", + vehicleOwner: "VEHICLE_OWNER", + thirdPartyPolicyholder: "VEHICLE_OWNER", + }, person: { userId: "damaged-user-id", fullName: "زیان دیده نمونه", @@ -165,61 +185,89 @@ describe("buildInsurerFileReport", () => { }, }); - expect(getFieldValue(report, PR.ownerSection, PR.name)).toBe("زیان دیده نمونه"); - expect(getFieldValue(report, PR.guiltyOwnerSection, PR.name)).toBe("مقصر نمونه"); - expect(getFieldValue(report, PR.guiltyOwnerSection, PR.phone)).toBe("09120000000"); + expect(getFieldValue(report, PR.ownerSection, PR.name)).toBe( + "زیان دیده نمونه", + ); + expect( + getFieldValue(report, PR.damagedParticipantsSection, PR.driverRole), + ).toContain("راننده نمونه"); + expect( + getFieldValue( + report, + PR.damagedParticipantsSection, + PR.thirdPartyPolicyholderRole, + ), + ).toContain("1234567890"); + expect(getFieldValue(report, PR.guiltyOwnerSection, PR.name)).toBe( + "مقصر نمونه", + ); + expect(getFieldValue(report, PR.guiltyOwnerSection, PR.phone)).toBe( + "09120000000", + ); expect(getFieldValue(report, PR.guiltyOwnerSection, PR.nationalCode)).toBe( "0987654321", ); - expect(getFieldValue(report, PR.damagedThirdPartyInsuranceSection, PR.policyNumber)).toBe( - "TP-DAMAGED-001", - ); - expect(getFieldValue(report, PR.guiltyThirdPartyInsuranceSection, PR.policyNumber)).toBe( - "TP-GUILTY-001", - ); - expect(getFieldValue(report, PR.damagedCarBodyInsuranceSection, PR.policyNumber)).toBe( - "CB-DAMAGED-001", - ); - expect(getFieldValue(report, PR.guiltyCarBodyInsuranceSection, PR.policyNumber)).toBe( - "CB-GUILTY-001", - ); - - expect(getFieldValue(report, PR.damagedVehicleSection, "خودرو / نام خودرو")).toBe( - "207", - ); - expect(getFieldValue(report, PR.guiltyVehicleSection, "خودرو / نام خودرو")).toBe( - "206", - ); - - expect(getFieldValue(report, PR.damagedStatementSection, PR.partyDescription)).toBe( - "توضیحات زیان‌دیده", - ); - expect(getFieldValue(report, PR.damagedStatementSection, PR.claimsDamage)).toBe( - "بله", - ); expect( - getFieldValue(report, PR.damagedStatementSection, PR.acceptsExpertOpinion), + getFieldValue( + report, + PR.damagedThirdPartyInsuranceSection, + PR.policyNumber, + ), + ).toBe("TP-DAMAGED-001"); + expect( + getFieldValue( + report, + PR.guiltyThirdPartyInsuranceSection, + PR.policyNumber, + ), + ).toBe("TP-GUILTY-001"); + expect( + getFieldValue(report, PR.damagedCarBodyInsuranceSection, PR.policyNumber), + ).toBe("CB-DAMAGED-001"); + expect( + getFieldValue(report, PR.guiltyCarBodyInsuranceSection, PR.policyNumber), + ).toBe("CB-GUILTY-001"); + + expect( + getFieldValue(report, PR.damagedVehicleSection, "خودرو / نام خودرو"), + ).toBe("207"); + expect( + getFieldValue(report, PR.guiltyVehicleSection, "خودرو / نام خودرو"), + ).toBe("206"); + + expect( + getFieldValue(report, PR.damagedStatementSection, PR.partyDescription), + ).toBe("توضیحات زیان‌دیده"); + expect( + getFieldValue(report, PR.damagedStatementSection, PR.claimsDamage), + ).toBe("بله"); + expect( + getFieldValue( + report, + PR.damagedStatementSection, + PR.acceptsExpertOpinion, + ), ).toBe("خیر"); - expect(getFieldValue(report, PR.guiltyStatementSection, PR.partyDescription)).toBe( - "توضیحات مقصر", - ); - expect(getFieldValue(report, PR.guiltyStatementSection, PR.admitsGuilt)).toBe( - "بله", - ); + expect( + getFieldValue(report, PR.guiltyStatementSection, PR.partyDescription), + ).toBe("توضیحات مقصر"); + expect( + getFieldValue(report, PR.guiltyStatementSection, PR.admitsGuilt), + ).toBe("بله"); expect( getFieldValue(report, PR.guiltyStatementSection, PR.acceptsExpertOpinion), ).toBe("بله"); - expect(getFieldValue(report, PR.fanavaranSection, PR.fanavaranClaimNo)).toBe( - "111", - ); + expect( + getFieldValue(report, PR.fanavaranSection, PR.fanavaranClaimNo), + ).toBe("111"); expect( getFieldValue(report, PR.fanavaranSection, PR.fanavaranExpertiseId), ).toBe("444"); - expect(getFieldValue(report, PR.fanavaranSection, PR.fanavaranPolicyId)).toBe( - "555", - ); + expect( + getFieldValue(report, PR.fanavaranSection, PR.fanavaranPolicyId), + ).toBe("555"); expect(getFieldValue(report, PR.timelineSection, PR.fileRegisteredAt)).toBe( "1405/05/19 13:23", @@ -228,15 +276,15 @@ describe("buildInsurerFileReport", () => { getFieldValue(report, PR.timelineSection, PR.evaluationRegisteredAt), ).toBe("1405/05/19 16:00"); - expect(getFieldValue(report, PR.evaluationSection, PR.evaluationResult)).toBe( - "تأیید شده", - ); - expect(getFieldValue(report, PR.evaluationSection, PR.evaluationExpert)).toBe( - "کارشناس خسارت نمونه", - ); - expect(getFieldValue(report, PR.evaluationSection, PR.evaluationResponse)).toBe( - "نیاز به تعویض سپر جلو", - ); + expect( + getFieldValue(report, PR.evaluationSection, PR.evaluationResult), + ).toBe("تأیید شده"); + expect( + getFieldValue(report, PR.evaluationSection, PR.evaluationExpert), + ).toBe("کارشناس خسارت نمونه"); + expect( + getFieldValue(report, PR.evaluationSection, PR.evaluationResponse), + ).toBe("نیاز به تعویض سپر جلو"); expect(getFieldValue(report, "قیمت قطعات", "قطعه ۱ / نام قطعه")).toBe( "سپر جلو", ); @@ -345,9 +393,9 @@ describe("buildInsurerFileReport", () => { }); const fields = report.sections.flatMap((section) => section.fields); - expect(fields.find((field) => field.label === "خودرو / خودرو نو")?.value).toBe( - "بله", - ); + expect( + fields.find((field) => field.label === "خودرو / خودرو نو")?.value, + ).toBe("بله"); expect(fields.some((field) => field.value === "خیر")).toBe(true); expect(fields.some((field) => field.value === "true")).toBe(false); expect(fields.some((field) => field.value === "false")).toBe(false); @@ -372,10 +420,12 @@ describe("buildInsurerFileReport", () => { }); const fields = report.sections.flatMap((section) => section.fields); - expect(fields.some((field) => String(field.value).includes("ESG"))).toBe(false); - expect(fields.some((field) => String(field.value).includes("TEJARAT"))).toBe( + expect(fields.some((field) => String(field.value).includes("ESG"))).toBe( false, ); + expect( + fields.some((field) => String(field.value).includes("TEJARAT")), + ).toBe(false); expect(fields.some((field) => field.label.includes("منبع"))).toBe(false); }); diff --git a/src/case-expert-report/case-expert-report.builder.ts b/src/case-expert-report/case-expert-report.builder.ts index e65df0a..7807991 100644 --- a/src/case-expert-report/case-expert-report.builder.ts +++ b/src/case-expert-report/case-expert-report.builder.ts @@ -36,6 +36,8 @@ type ReportParty = ReportRecord & { vehicle?: ReportRecord; statement?: ReportRecord; location?: { lat?: number; lon?: number }; + participants?: ReportRecord[]; + participantRoles?: ReportRecord; }; function asString(value: unknown): string | undefined { @@ -66,7 +68,8 @@ function formatBirthDate(value: unknown): string | undefined { function formatDateTime(value: unknown): string | undefined { if (value === undefined || value === null || value === "") return undefined; - const date = value instanceof Date ? value : new Date(value as string | number); + const date = + value instanceof Date ? value : new Date(value as string | number); if (Number.isNaN(date.getTime())) return asString(value); const [d, t] = toJalaliDateAndTime(date); return `${d} ${t}`; @@ -126,13 +129,13 @@ function flattenObject( if (Array.isArray(obj)) { const value = normalizeListValue(obj); - return value - ? [{ label: persianFieldPath(prefix || "items"), value }] - : []; + return value ? [{ label: persianFieldPath(prefix || "items"), value }] : []; } if (typeof obj !== "object") { - return [{ label: persianFieldPath(prefix || "value"), value: asString(obj) }]; + return [ + { label: persianFieldPath(prefix || "value"), value: asString(obj) }, + ]; } const rows: InsurerFileReportField[] = []; @@ -160,7 +163,9 @@ function flattenObject( return rows; } -function dedupeFields(fields: InsurerFileReportField[]): InsurerFileReportField[] { +function dedupeFields( + fields: InsurerFileReportField[], +): InsurerFileReportField[] { const seen = new Set(); const out: InsurerFileReportField[] = []; @@ -180,7 +185,8 @@ function filterEmptySections( sections: Array, ): InsurerFileReportSection[] { return sections.filter( - (section): section is InsurerFileReportSection => !!section && section.fields.length > 0, + (section): section is InsurerFileReportSection => + !!section && section.fields.length > 0, ); } @@ -204,7 +210,9 @@ function expertNameFromSnapshot(snapshot?: { lastName?: string; }): string | undefined { if (!snapshot) return undefined; - const name = [snapshot.firstName, snapshot.lastName].filter(Boolean).join(" "); + const name = [snapshot.firstName, snapshot.lastName] + .filter(Boolean) + .join(" "); return name || undefined; } @@ -214,9 +222,8 @@ function collectExpertNames( ): string | undefined { const names = new Set(); - const blameDecision = ( - blame?.expert as Record | undefined - )?.decision as Record | undefined; + const blameDecision = (blame?.expert as Record | undefined) + ?.decision as Record | undefined; const blameExpert = expertNameFromSnapshot( blameDecision?.expertProfileSnapshot as | { firstName?: string; lastName?: string } @@ -280,13 +287,16 @@ function resolveReportBlameContext( (claim?.blameFileContext as Record | undefined) ?.blameRequestType ?? (snapshot.accident as Record | undefined)?.type, - blameStatus: (claim?.blameFileContext as Record | undefined) - ?.blameStatus, + blameStatus: ( + claim?.blameFileContext as Record | undefined + )?.blameStatus, parties: snapshot.parties, }; } -function getPartyRole(party: ReportParty | null | undefined): string | undefined { +function getPartyRole( + party: ReportParty | null | undefined, +): string | undefined { const role = party?.role; return typeof role === "string" ? role : undefined; } @@ -318,7 +328,8 @@ function sameParty( second: ReportParty | null | undefined, ): boolean { if (!first || !second) return false; - const firstUserId = first.person?.userId != null ? String(first.person.userId) : ""; + const firstUserId = + first.person?.userId != null ? String(first.person.userId) : ""; const secondUserId = second.person?.userId != null ? String(second.person.userId) : ""; if (firstUserId && secondUserId) return firstUserId === secondUserId; @@ -330,7 +341,9 @@ function resolveEvaluationReply( ): Record | undefined { const evaluation = claim?.evaluation as Record | undefined; return ( - (evaluation?.damageExpertReplyFinal as Record | undefined) ?? + (evaluation?.damageExpertReplyFinal as + | Record + | undefined) ?? (evaluation?.damageExpertReply as Record | undefined) ); } @@ -375,10 +388,18 @@ function buildThirdPartyInsuranceFields( const role = getPartyRole(party); const direct = (party?.insurance ?? {}) as Record; const blameInquiry = pickInquiryReportPayload( - inquiryRoleData(blame?.inquiries as Record | undefined, "thirdParty", role), + inquiryRoleData( + blame?.inquiries as Record | undefined, + "thirdParty", + role, + ), ); const claimInquiry = pickInquiryReportPayload( - inquiryRoleData(claim?.inquiries as Record | undefined, "thirdParty", role), + inquiryRoleData( + claim?.inquiries as Record | undefined, + "thirdParty", + role, + ), ); return [ @@ -462,12 +483,23 @@ function buildCarBodyInsuranceFields( party?.insurance?.carBody ?? {}) as Record; const blameInquiry = pickInquiryReportPayload( - inquiryRoleData(blame?.inquiries as Record | undefined, "carBody", role), + inquiryRoleData( + blame?.inquiries as Record | undefined, + "carBody", + role, + ), ); const claimInquiry = pickInquiryReportPayload( - inquiryRoleData(claim?.inquiries as Record | undefined, "carBody", role), + inquiryRoleData( + claim?.inquiries as Record | undefined, + "carBody", + role, + ), ); - const legacy = (blame?.carBodyInsuranceDetail ?? {}) as Record; + const legacy = (blame?.carBodyInsuranceDetail ?? {}) as Record< + string, + unknown + >; return [ { @@ -556,7 +588,10 @@ function buildPartyOwnerSection( { label: PR.nationalCode, value: options?.useClaimOwnerFallback - ? firstDefined(person?.nationalCodeOfInsurer, money?.nationalCodeOfInsurer) + ? firstDefined( + person?.nationalCodeOfInsurer, + money?.nationalCodeOfInsurer, + ) : firstDefined(person?.nationalCodeOfInsurer, person?.nationalCode), }, { @@ -572,9 +607,55 @@ function buildPartyOwnerSection( ]); } -function licenseFieldsFromInquiry( - inquiry?: Record, -): { licenseType?: string; licenseDate?: string } { +function buildParticipantRolesSection( + title: string, + party: ReportParty | null | undefined, +): InsurerFileReportSection | undefined { + const participants = Array.isArray(party?.participants) + ? party.participants + : []; + const assignments = party?.participantRoles; + if (!assignments || participants.length === 0) return undefined; + + const roleLabels: Record = { + driver: PR.driverRole, + vehicleOwner: PR.vehicleOwnerRole, + thirdPartyPolicyholder: PR.thirdPartyPolicyholderRole, + carBodyPolicyholder: PR.carBodyPolicyholderRole, + }; + const fields = Object.entries(assignments).map(([role, participantId]) => { + 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("، "); + return { + label: roleLabels[role] ?? persianFieldPath(role), + value: value || PR.empty, + }; + }); + + return buildSection(title, fields, false); +} + +function licenseFieldsFromInquiry(inquiry?: Record): { + licenseType?: string; + licenseDate?: string; +} { if (!inquiry) return {}; return { licenseType: firstDefined( @@ -700,7 +781,9 @@ function buildCaseTimelineSection( }, { label: PR.evaluationRegisteredAt, - value: formatDateTime(resolveEvaluationSubmittedAt(claim, evaluationReply)), + value: formatDateTime( + resolveEvaluationSubmittedAt(claim, evaluationReply), + ), }, ]); } @@ -709,10 +792,14 @@ function buildFanavaranCodesSection( claim?: Record | null, ): InsurerFileReportSection | undefined { if (!claim) return undefined; - const sync = (claim.fanavaranSync as Record | undefined) ?? {}; - const baseClaim = (sync.baseClaim as Record | undefined) ?? {}; - const damageCase = (sync.damageCase as Record | undefined) ?? {}; - const expertise = (sync.expertise as Record | undefined) ?? {}; + const sync = + (claim.fanavaranSync as Record | undefined) ?? {}; + const baseClaim = + (sync.baseClaim as Record | undefined) ?? {}; + const damageCase = + (sync.damageCase as Record | undefined) ?? {}; + const expertise = + (sync.expertise as Record | undefined) ?? {}; return buildSection(PR.fanavaranSection, [ { @@ -725,7 +812,11 @@ function buildFanavaranCodesSection( }, { label: PR.fanavaranDamageCaseId, - value: firstDefined(claim.dmgCaseId, damageCase.dmgCaseId, expertise.dmgCaseId), + value: firstDefined( + claim.dmgCaseId, + damageCase.dmgCaseId, + expertise.dmgCaseId, + ), }, { label: PR.fanavaranExpertiseId, @@ -824,10 +915,19 @@ function buildEvaluationPartsSection( const prefix = `${PR.part} ${PERSIAN_NUMBER_FORMATTER.format(index + 1)}`; return [ { label: `${prefix} / ${PR.partName}`, value: evaluationPartName(part) }, - { label: `${prefix} / ${PR.damageType}`, value: asString(part.typeOfDamage) }, + { + label: `${prefix} / ${PR.damageType}`, + value: asString(part.typeOfDamage), + }, { label: `${prefix} / ${PR.partPrice}`, value: formatToman(part.price) }, - { label: `${prefix} / ${PR.repairSalary}`, value: formatToman(part.salary) }, - { label: `${prefix} / ${PR.totalPayment}`, value: formatToman(part.totalPayment) }, + { + label: `${prefix} / ${PR.repairSalary}`, + value: formatToman(part.salary), + }, + { + label: `${prefix} / ${PR.totalPayment}`, + value: formatToman(part.totalPayment), + }, { label: `${prefix} / ${PR.factorNeeded}`, value: @@ -835,7 +935,10 @@ function buildEvaluationPartsSection( ? persianStatus(part.factorNeeded) : undefined, }, - { label: `${prefix} / ${PR.daghi}`, value: evaluationDaghiValue(part.daghi) }, + { + label: `${prefix} / ${PR.daghi}`, + value: evaluationDaghiValue(part.daghi), + }, ]; }); @@ -852,10 +955,11 @@ function buildAccidentReportSection( const snapshotAccident = ( claim?.snapshot as { accident?: Record } | undefined )?.accident; - const blameDecision = ( - blame?.expert as Record | undefined - )?.decision as Record | undefined; - const decisionFields = blameDecision?.fields as Record | undefined; + const blameDecision = (blame?.expert as Record | undefined) + ?.decision as Record | undefined; + const decisionFields = blameDecision?.fields as + | Record + | undefined; return buildSection(PR.accidentSection, [ { @@ -868,7 +972,8 @@ function buildAccidentReportSection( }, { label: PR.accidentTime, - value: asString(statement?.accidentTime) ?? asString(snapshotAccident?.time), + value: + asString(statement?.accidentTime) ?? asString(snapshotAccident?.time), }, { label: PR.experts, @@ -914,7 +1019,8 @@ function buildAccidentReportSection( { label: PR.accidentWay, value: asString( - (decisionFields?.accidentWay as { label?: string } | undefined)?.label ?? + (decisionFields?.accidentWay as { label?: string } | undefined) + ?.label ?? ( snapshotAccident?.classification as { accidentWay?: { label?: string }; @@ -925,7 +1031,8 @@ function buildAccidentReportSection( { label: PR.accidentReason, value: asString( - (decisionFields?.accidentReason as { label?: string } | undefined)?.label ?? + (decisionFields?.accidentReason as { label?: string } | undefined) + ?.label ?? ( snapshotAccident?.classification as { accidentReason?: { label?: string }; @@ -936,7 +1043,8 @@ function buildAccidentReportSection( { label: PR.accidentType, value: asString( - (decisionFields?.accidentType as { label?: string } | undefined)?.label ?? + (decisionFields?.accidentType as { label?: string } | undefined) + ?.label ?? ( snapshotAccident?.classification as { accidentType?: { label?: string }; @@ -968,12 +1076,17 @@ export function buildInsurerFileReport(file: { : null; const isCarBody = String((blameContext?.type as string | undefined) ?? "") === "CAR_BODY"; - const includeGuiltySections = !!guiltyParty && !(isCarBody && sameParty(damagedParty, guiltyParty)); + const includeGuiltySections = + !!guiltyParty && !(isCarBody && sameParty(damagedParty, guiltyParty)); const claimVehicle = claim?.vehicle as Record | undefined; const sections = filterEmptySections([ buildCaseTimelineSection(overview, claim), + buildParticipantRolesSection(PR.damagedParticipantsSection, damagedParty), + includeGuiltySections + ? buildParticipantRolesSection(PR.guiltyParticipantsSection, guiltyParty) + : undefined, buildPartyOwnerSection(PR.ownerSection, damagedParty, { claim, useClaimOwnerFallback: true, @@ -1003,7 +1116,11 @@ export function buildInsurerFileReport(file: { buildCarBodyInsuranceFields(guiltyParty, blameContext, claim), ) : undefined, - buildPartyVehicleSection(PR.damagedVehicleSection, damagedParty, claimVehicle), + buildPartyVehicleSection( + PR.damagedVehicleSection, + damagedParty, + claimVehicle, + ), includeGuiltySections ? buildPartyVehicleSection(PR.guiltyVehicleSection, guiltyParty) : undefined, diff --git a/src/case-expert-report/persian-report-labels.ts b/src/case-expert-report/persian-report-labels.ts index 56ef6de..7252051 100644 --- a/src/case-expert-report/persian-report-labels.ts +++ b/src/case-expert-report/persian-report-labels.ts @@ -5,6 +5,8 @@ export const PR = { empty: "-", ownerSection: "مالک خودروی زیان دیده", guiltyOwnerSection: "مالک خودروی مقصر", + damagedParticipantsSection: "اشخاص و نقش‌های خودروی زیان‌دیده", + guiltyParticipantsSection: "اشخاص و نقش‌های خودروی مقصر", driverSection: "راننده خودروی زیان دیده", damagedThirdPartyInsuranceSection: "بیمه شخص ثالث زیان‌دیده", damagedCarBodyInsuranceSection: "بیمه بدنه زیان‌دیده", @@ -61,6 +63,11 @@ export const PR = { claimsDamage: "ادعای خسارت", acceptsExpertOpinion: "پذیرش نظر کارشناس", partyRole: "نقش طرف", + driverRole: "راننده", + 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 d9969b3..dc19876 100644 --- a/src/common/dto/inquiry-participants.dto.ts +++ b/src/common/dto/inquiry-participants.dto.ts @@ -24,9 +24,8 @@ export enum VehicleRegistrationState { export class InquiryPlateDto { @ApiProperty({ example: "44" }) - @IsString() @IsNotEmpty() - leftDigits: string; + leftDigits: string | number; @ApiProperty({ example: "ب" }) @IsString() @@ -34,14 +33,12 @@ export class InquiryPlateDto { centerAlphabet: string; @ApiProperty({ example: "111" }) - @IsString() @IsNotEmpty() - centerDigits: string; + centerDigits: string | number; @ApiProperty({ example: "22" }) - @IsString() @IsNotEmpty() - ir: string; + ir: string | number; } export class InquiryParticipantInputDto { diff --git a/src/request-management/entities/schema/request-management.schema.ts b/src/request-management/entities/schema/request-management.schema.ts index e6456eb..f81b292 100644 --- a/src/request-management/entities/schema/request-management.schema.ts +++ b/src/request-management/entities/schema/request-management.schema.ts @@ -146,6 +146,22 @@ export class FirstPartyDetail { @Prop({ type: Boolean }) firstPartyCertificate: boolean | null; + + @Prop({ type: [MongooseSchema.Types.Mixed] }) + participants?: Record[]; + + @Prop({ type: MongooseSchema.Types.Mixed }) + participantRoles?: Record; + + @Prop({ type: MongooseSchema.Types.Mixed }) + participantInquiries?: Record; + + @Prop({ type: MongooseSchema.Types.Mixed }) + policyInquiry?: Record; + + @Prop() registrationState?: string; + @Prop() previousPlateId?: string; + @Prop() vehicleVin?: string; } export class SecondPartyDetail { @@ -178,6 +194,22 @@ export class SecondPartyDetail { @Prop({ type: SecondPartyFile }) secondPartyFiles?: SecondPartyFile; + + @Prop({ type: [MongooseSchema.Types.Mixed] }) + participants?: Record[]; + + @Prop({ type: MongooseSchema.Types.Mixed }) + participantRoles?: Record; + + @Prop({ type: MongooseSchema.Types.Mixed }) + participantInquiries?: Record; + + @Prop({ type: MongooseSchema.Types.Mixed }) + policyInquiry?: Record; + + @Prop() registrationState?: string; + @Prop() previousPlateId?: string; + @Prop() vehicleVin?: string; } export class LocationDto { diff --git a/src/request-management/inquiry-participant-resolver.spec.ts b/src/request-management/inquiry-participant-resolver.spec.ts index 062090d..b7646ec 100644 --- a/src/request-management/inquiry-participant-resolver.spec.ts +++ b/src/request-management/inquiry-participant-resolver.spec.ts @@ -421,6 +421,41 @@ describe("inquiry participant resolver", () => { }); }); + it("does not use the previous plate after a transport or provider outage", async () => { + const currentPlate = { + leftDigits: "44", + centerAlphabet: "ب", + centerDigits: "111", + ir: "22", + }; + const query = jest.fn().mockRejectedValue( + Object.assign(new Error("upstream timeout"), { + code: "ETIMEDOUT", + }), + ); + + await expect( + runPlateInquiryWithFallback({ + vehicle: resolveInquiryVehicle({ + registrationState: VehicleRegistrationState.RECENTLY_TRANSFERRED, + currentPlate, + previousPlate: { + leftDigits: "55", + centerAlphabet: "ج", + centerDigits: "222", + ir: "33", + }, + vin: "NAAM01E15HK123456", + }), + fallbackCurrentPlate: currentPlate, + query, + isUsable: () => false, + mappedValue: () => ({}), + }), + ).rejects.toThrow("upstream timeout"); + expect(query).toHaveBeenCalledTimes(1); + }); + it("allows an explicitly unknown policyholder only for a damaged-party submission", () => { const input = { driver: { diff --git a/src/request-management/inquiry-participant-resolver.ts b/src/request-management/inquiry-participant-resolver.ts index 0fd7303..fcb6af5 100644 --- a/src/request-management/inquiry-participant-resolver.ts +++ b/src/request-management/inquiry-participant-resolver.ts @@ -391,12 +391,31 @@ export function assertPreviousPlateInquiryMatchesVin( } } +export function isPolicyNotFoundError(error: unknown): boolean { + const candidate = error as Record | null; + const status = candidate?.status ?? candidate?.response?.status; + if (Number(status) === 404) return true; + const code = String( + candidate?.code ?? candidate?.response?.data?.code ?? "", + ).toUpperCase(); + if (["NOT_FOUND", "POLICY_NOT_FOUND", "NO_POLICY"].includes(code)) { + return true; + } + const message = String( + candidate?.message ?? candidate?.response?.data?.message ?? error ?? "", + ); + return /\bnot[ -]?found\b|\bno (?:relevant )?policy\b|یافت نشد|فاقد بیمه(?:نامه)?/i.test( + message, + ); +} + export async function runPlateInquiryWithFallback(options: { vehicle?: ResolvedInquiryVehicle; fallbackCurrentPlate: InquiryVehicleInputDto["currentPlate"]; query: (plate: InquiryVehicleInputDto["currentPlate"]) => Promise; isUsable: (value: T) => boolean; mappedValue: (value: T) => Record; + shouldFallbackOnError?: (error: unknown) => boolean; }): Promise<{ value: T; plateKind: "CURRENT" | "PREVIOUS"; @@ -462,6 +481,15 @@ export async function runPlateInquiryWithFallback(options: { error: error instanceof Error ? error.message : String(error), }); } + if ( + !isLast && + !(options.shouldFallbackOnError ?? isPolicyNotFoundError)(error) + ) { + if (typeof error === "object" && error != null) { + (error as { attempts?: typeof attempts }).attempts = attempts; + } + throw error; + } if (isLast) { if (typeof error === "object" && error != null) { (error as { attempts?: typeof attempts }).attempts = attempts; diff --git a/src/request-management/request-management.service.ts b/src/request-management/request-management.service.ts index 3294b1d..2f2e9ab 100644 --- a/src/request-management/request-management.service.ts +++ b/src/request-management/request-management.service.ts @@ -542,6 +542,44 @@ export class RequestManagementService { } } + /** Inquiry bundle for the still-routable legacy RequestManagement model. */ + private async collectLegacyParticipantInquiries( + submission: NormalizedInquirySubmission>, + ): Promise | undefined> { + if (submission.participants.legacy) return undefined; + + const personal: Record = {}; + for (const participant of submission.participants.participants) { + if (participant.unknown) continue; + personal[participant.participantId] = + await this.sandHubService.getPersonalInquiry( + participant.nationalCode, + participant.birthday, + ); + } + + const plate = submission.vehicle?.currentPlate ?? submission.dto.plate; + const ownership = + submission.vehicleOwner && plate + ? await this.sandHubService.getCarOwnershipInfo( + plate, + submission.vehicleOwner.nationalCode, + ) + : undefined; + const drivingLicence = + submission.driver.hasDrivingLicense === false + ? { + skipped: true, + reason: "Driver declared no driving licence", + } + : await this.sandHubService.getDrivingLicenseInfo( + submission.driver.nationalCode, + submission.driver.licenseNumber!, + ); + + return { personal, ownership, drivingLicence }; + } + private getPartyIndex(req: any, role: PartyRole): number { return Array.isArray(req.parties) ? req.parties.findIndex((p) => p?.role === role) @@ -3271,6 +3309,9 @@ export class RequestManagementService { user: any, body: AddPlateDto, partyType: "firstParty" | "secondParty", + inquirySubmission?: NormalizedInquirySubmission>, + policyInquiry?: Record, + participantInquiries?: Record, ) { if (request.type === "THIRD_PARTY" && partyType === "firstParty") { this.sandHubService.assertInsuranceMatchesDeployment( @@ -3282,12 +3323,16 @@ export class RequestManagementService { const clientName = sandHubReport?.CompanyName; const companyCode = sandHubReport?.CompanyCode; - const client = await this.clientService.findOrCreateClientByCompanyCode( - companyCode, - clientName, - ); + const policyholderUnknown = + inquirySubmission?.thirdPartyPolicyholder.unknown === true; + const client = clientName + ? await this.clientService.findOrCreateClientByCompanyCode( + companyCode, + clientName, + ) + : null; - if (!client) { + if (!client && !policyholderUnknown) { throw new HttpException("Client not found", HttpStatus.CONFLICT); } @@ -3313,23 +3358,27 @@ export class RequestManagementService { } try { - await this.userDbService.findOneAndUpdate( - { _id: user.sub }, - { clientKey: client["_doc"]._id }, - ); + if (client) { + await this.userDbService.findOneAndUpdate( + { _id: user.sub }, + { clientKey: (client as any)["_doc"]?._id ?? (client as any)._id }, + ); + } const sandHubDocData = { ...sandHubReport, plate: body.plate, nationalCode: body.nationalCodeOfInsurer, }; - const sandHubDoc = await this.sandHubService.sandHubDocumentCreator( - user.sub, - request["_doc"]._id, - sandHubDocData, - ); + const sandHubDoc = policyInquiry?.skipped + ? null + : await this.sandHubService.sandHubDocumentCreator( + user.sub, + request["_doc"]._id, + sandHubDocData, + ); - if (partyType === "firstParty") { + if (partyType === "firstParty" && sandHubDoc) { await this.requestManagementDbService.findAndUpdate( { _id: request._id }, { @@ -3352,8 +3401,6 @@ export class RequestManagementService { body.driverBirthday, [`${partyDetails}.${partyType}CarDetail.carType`]: `${sandHubReport.UsageField} / ${sandHubReport.MapUsageName || "-"}`, [`${partyDetails}.${partyType}CarDetail.isNewCar`]: body.isNewCar, - [`${partyDetails}.${partyType}Client.clientId`]: client["_doc"]._id, - [`${partyDetails}.${partyType}Client.clientName`]: clientName, [`${partyDetails}.${partyType}Certificate`]: body.userNoCertificate, [`${partyDetails}.${partyType}InsuranceDetail.insuranceId`]: sandHubReport.LastCompanyDocumentNumber, @@ -3367,12 +3414,38 @@ export class RequestManagementService { sandHubReport.EndDate, }; + if (client) { + setFields[`${partyDetails}.${partyType}Client.clientId`] = + (client as any)["_doc"]?._id ?? (client as any)._id; + setFields[`${partyDetails}.${partyType}Client.clientName`] = clientName; + } + if (inquirySubmission && !inquirySubmission.participants.legacy) { + setFields[`${partyDetails}.participants`] = + inquirySubmission.participants.participants; + setFields[`${partyDetails}.participantRoles`] = + inquirySubmission.participants.roles; + setFields[`${partyDetails}.participantInquiries`] = + participantInquiries ?? {}; + setFields[`${partyDetails}.policyInquiry`] = policyInquiry ?? {}; + setFields[`${partyDetails}.registrationState`] = + inquirySubmission.vehicle?.registrationState; + setFields[`${partyDetails}.previousPlateId`] = inquirySubmission.vehicle + ?.previousPlate + ? this.plateToPlateIdString(inquirySubmission.vehicle.previousPlate) + : undefined; + setFields[`${partyDetails}.vehicleVin`] = + inquirySubmission.vehicle?.vin; + } + // For CAR_BODY type, persist the provider response and its mapped fields. if (request.type === "CAR_BODY" && partyType === "firstParty") { - const carBodyInquiry = await this.sandHubService.getCarBodyInquiry({ - nationalCodeOfInsurer: body.nationalCodeOfInsurer, - plate: body.plate, - } as any); + const carBodyInquiry = + inquirySubmission && !inquirySubmission.participants.legacy + ? await this.getCarBodyPlateInquiry(inquirySubmission) + : await this.sandHubService.getCarBodyInquiry({ + nationalCodeOfInsurer: body.nationalCodeOfInsurer, + plate: body.plate, + } as any); const carBodyInfo = carBodyInquiry.mapped as any; this.logger.log( @@ -3400,6 +3473,18 @@ export class RequestManagementService { carBodyInquiry.raw; setFields["firstPartyDetails.firstPartyCarBodyInsuranceDetail.source"] = carBodyInquiry.source; + if (inquirySubmission && !inquirySubmission.participants.legacy) { + setFields[`${partyDetails}.policyInquiry`] = { + thirdParty: policyInquiry, + carBody: { + source: carBodyInquiry.source, + plateKind: carBodyInquiry.plateKind, + attempts: carBodyInquiry.attempts, + raw: carBodyInquiry.raw, + mapped: carBodyInquiry.mapped, + }, + }; + } setFields[`${partyDetails}.${partyType}Client.clientId`] = await this.resolveCarBodyPolicyClientId(carBodyInfo); } @@ -3456,6 +3541,13 @@ export class RequestManagementService { (request.nextStep === StepsEnum.F_addPlate || request.currentStep === StepsEnum.F_addPlate) && request.firstPartyDetails.firstPartyPhoneNumber === user.username; + const partyRole = isFirstParty ? PartyRole.FIRST : PartyRole.SECOND; + const inquirySubmission = this.normalizeInquiryInput( + request.type as BlameRequestType, + body, + partyRole, + ); + body = inquirySubmission.dto as unknown as AddPlateDto; if (!isFirstParty) { const firstPartyDetails = request.firstPartyDetails as any; @@ -3482,10 +3574,23 @@ export class RequestManagementService { // TODO: Activate // --- Proceed with existing logic if the check passes --- // 1) Main third-party/block inquiry (existing behavior) - const sanHubResponse = await this.sandHubService.getSandHubResponse({ - plate: body.plate, - nationalCodeOfInsurer: body.nationalCodeOfInsurer, - }); + const policyInquiry = inquirySubmission.participants.legacy + ? await (async () => { + const response = await this.sandHubService.getSandHubResponse({ + plate: body.plate, + nationalCodeOfInsurer: body.nationalCodeOfInsurer, + }); + return { + raw: response, + mapped: response["_doc"] || response, + plateKind: "CURRENT", + attempts: [{ plateKind: "CURRENT", succeeded: true, usable: true }], + }; + })() + : await this.getThirdPartyPlateInquiry(inquirySubmission); + const sanHubResponse = policyInquiry.mapped; + const participantInquiries = + await this.collectLegacyParticipantInquiries(inquirySubmission); // if (sanHubResponse.Error) { // throw new HttpException( @@ -3520,6 +3625,9 @@ export class RequestManagementService { user, body, isFirstParty ? "firstParty" : "secondParty", + inquirySubmission, + policyInquiry, + participantInquiries, ); } @@ -6292,7 +6400,7 @@ export class RequestManagementService { return none; } - /** Party payload for user blame detail: no national codes, licenses, phone, birthdays, or vehicle inquiry blobs. */ + /** Party payload for user blame detail: role links are visible, but participant PII and inquiry blobs remain private. */ private async sanitizePartyForBlameUserView( party: any, ): Promise> { @@ -6311,12 +6419,22 @@ export class RequestManagementService { const vehicle = party.vehicle ? { plateId: party.vehicle.plateId, + previousPlateId: party.vehicle.previousPlateId, + registrationState: party.vehicle.registrationState, name: party.vehicle.name, model: party.vehicle.model, type: party.vehicle.type, isNew: party.vehicle.isNew, } : undefined; + const participants = Array.isArray(party.participants) + ? party.participants.map((participant: any) => ({ + participantId: participant.participantId, + fullName: participant.fullName, + hasDrivingLicense: participant.hasDrivingLicense, + unknown: participant.unknown, + })) + : undefined; const evidenceRaw = party.evidence as Record | undefined; const evidence: Record | undefined = evidenceRaw ? { ...evidenceRaw } @@ -6350,6 +6468,8 @@ export class RequestManagementService { return { role: party.role, + participants, + participantRoles: party.participantRoles, person: safePerson, carBodyFirstForm: party.carBodyFirstForm, location: party.location, @@ -6689,10 +6809,26 @@ export class RequestManagementService { ); } - const carBodyInquiry = await this.getCarBodyPlateInquiry(inquirySubmission); + let carBodyInquiry: any; + try { + carBodyInquiry = await this.getCarBodyPlateInquiry(inquirySubmission); + } catch (error: any) { + this.recordPartyCaseInquiryStatus( + req, + "carBody", + PartyRole.FIRST, + false, + { attempts: error?.attempts ?? [] }, + error, + ); + await (req as any).save(); + this.throwCarBodyInquiryFailure(error); + } const carBodyInfo = carBodyInquiry.mapped as any; this.recordPartyCaseInquiryStatus(req, "carBody", PartyRole.FIRST, true, { source: carBodyInquiry.source, + plateKind: carBodyInquiry.plateKind, + attempts: carBodyInquiry.attempts, raw: carBodyInquiry.raw, mapped: carBodyInfo, }); @@ -7669,13 +7805,30 @@ export class RequestManagementService { stepsToAdd.push(StepsEnum.S_addDescription); // Process first party plate with SandHub lookup - const firstPartyPlate = formData.firstPartyPlate; + const firstInquirySubmission = this.normalizeInquiryInput( + BlameRequestType.THIRD_PARTY, + formData.firstPartyPlate, + PartyRole.FIRST, + ); + const firstPartyPlate = firstInquirySubmission.dto; try { - const sandHubResponse = await this.sandHubService.getSandHubResponse({ - plate: firstPartyPlate.plate, - nationalCodeOfInsurer: firstPartyPlate.nationalCodeOfInsurer, - }); - const sandHubReport = sandHubResponse["_doc"] || sandHubResponse; + const firstPolicyInquiry = firstInquirySubmission.participants.legacy + ? await (async () => { + const response = await this.sandHubService.getSandHubResponse({ + plate: firstPartyPlate.plate, + nationalCodeOfInsurer: firstPartyPlate.nationalCodeOfInsurer, + }); + return { + raw: response, + mapped: response["_doc"] || response, + plateKind: "CURRENT", + attempts: [ + { plateKind: "CURRENT", succeeded: true, usable: true }, + ], + }; + })() + : await this.getThirdPartyPlateInquiry(firstInquirySubmission); + const sandHubReport = firstPolicyInquiry.mapped; this.sandHubService.assertInsuranceMatchesDeployment( sandHubReport, "THIRD_PARTY", @@ -7727,6 +7880,26 @@ export class RequestManagementService { startDate: sandHubReport?.IssueDate || sandHubReport?.StartDate, endDate: sandHubReport?.EndDate, }; + if (!firstInquirySubmission.participants.legacy) { + firstPartyDetails.participants = + firstInquirySubmission.participants.participants; + firstPartyDetails.participantRoles = + firstInquirySubmission.participants.roles; + firstPartyDetails.participantInquiries = + await this.collectLegacyParticipantInquiries( + firstInquirySubmission, + ); + firstPartyDetails.policyInquiry = firstPolicyInquiry; + firstPartyDetails.registrationState = + firstInquirySubmission.vehicle?.registrationState; + firstPartyDetails.previousPlateId = firstInquirySubmission.vehicle + ?.previousPlate + ? this.plateToPlateIdString( + firstInquirySubmission.vehicle.previousPlate, + ) + : undefined; + firstPartyDetails.vehicleVin = firstInquirySubmission.vehicle?.vin; + } // Update the firstPartyDetails in the payload with all plate data updatePayload.$set.firstPartyDetails = firstPartyDetails; @@ -7742,26 +7915,47 @@ export class RequestManagementService { // Process second party plate try { - const secondPartyPlate = formData.secondParty.plate; - const sandHubResponse = await this.sandHubService.getSandHubResponse({ - plate: secondPartyPlate.plate, - nationalCodeOfInsurer: secondPartyPlate.nationalCodeOfInsurer, - }); - const sandHubReport = sandHubResponse["_doc"] || sandHubResponse; + const secondInquirySubmission = this.normalizeInquiryInput( + BlameRequestType.THIRD_PARTY, + formData.secondParty.plate, + PartyRole.SECOND, + ); + const secondPartyPlate = secondInquirySubmission.dto; + const secondPolicyInquiry = secondInquirySubmission.participants.legacy + ? await (async () => { + const response = await this.sandHubService.getSandHubResponse({ + plate: secondPartyPlate.plate, + nationalCodeOfInsurer: secondPartyPlate.nationalCodeOfInsurer, + }); + return { + raw: response, + mapped: response["_doc"] || response, + plateKind: "CURRENT", + attempts: [ + { plateKind: "CURRENT", succeeded: true, usable: true }, + ], + }; + })() + : await this.getThirdPartyPlateInquiry(secondInquirySubmission); + const sandHubReport = secondPolicyInquiry.mapped; const clientName = sandHubReport?.CompanyName || sandHubReport?.LastCompanyName; const companyCode = sandHubReport?.CompanyCode; // Try to find client by company code first (more reliable) - const client = companyCode - ? await this.clientService.findOrCreateClientByCompanyCode( - companyCode, - clientName, - ) - : await this.clientService.findOne({ clientName: clientName }); + const policyholderUnknown = + secondInquirySubmission.thirdPartyPolicyholder.unknown === true; + const client = clientName + ? companyCode + ? await this.clientService.findOrCreateClientByCompanyCode( + companyCode, + clientName, + ) + : await this.clientService.findOne({ clientName: clientName }) + : null; - if (!client) { + if (!client && !policyholderUnknown) { throw new NotFoundException( `Client not found for company: ${clientName}${companyCode ? ` (code: ${companyCode})` : ""}`, ); @@ -7778,10 +7972,12 @@ export class RequestManagementService { carType: `${sandHubReport?.UsageField || ""} / ${sandHubReport?.MapUsageName || "-"}`, isNewCar: secondPartyPlate.isNewCar, }; - secondPartyDetails.secondPartyClient = { - clientId: (client as any)["_doc"]?._id || (client as any)._id, - clientName: clientName, - }; + if (client) { + secondPartyDetails.secondPartyClient = { + clientId: (client as any)["_doc"]?._id || (client as any)._id, + clientName: clientName, + }; + } secondPartyDetails.secondPartyCertificate = secondPartyPlate.userNoCertificate; secondPartyDetails.secondPartyInsuranceDetail = { @@ -7795,6 +7991,26 @@ export class RequestManagementService { startDate: sandHubReport?.IssueDate || sandHubReport?.StartDate, endDate: sandHubReport?.EndDate, }; + if (!secondInquirySubmission.participants.legacy) { + secondPartyDetails.participants = + secondInquirySubmission.participants.participants; + secondPartyDetails.participantRoles = + secondInquirySubmission.participants.roles; + secondPartyDetails.participantInquiries = + await this.collectLegacyParticipantInquiries( + secondInquirySubmission, + ); + secondPartyDetails.policyInquiry = secondPolicyInquiry; + secondPartyDetails.registrationState = + secondInquirySubmission.vehicle?.registrationState; + secondPartyDetails.previousPlateId = secondInquirySubmission.vehicle + ?.previousPlate + ? this.plateToPlateIdString( + secondInquirySubmission.vehicle.previousPlate, + ) + : undefined; + secondPartyDetails.vehicleVin = secondInquirySubmission.vehicle?.vin; + } // Update the secondPartyDetails in the payload updatePayload.$set.secondPartyDetails = secondPartyDetails; @@ -8014,13 +8230,31 @@ export class RequestManagementService { stepsToAdd.push(StepsEnum.F_addDescription); // Process first party plate with SandHub lookup - const firstPartyPlate = formData.firstPartyPlate; + const firstInquirySubmission = this.normalizeInquiryInput( + BlameRequestType.CAR_BODY, + formData.firstPartyPlate, + PartyRole.FIRST, + ); + const firstPartyPlate = firstInquirySubmission.dto; try { - const sandHubResponse = await this.sandHubService.getSandHubResponse({ - plate: firstPartyPlate.plate, - nationalCodeOfInsurer: firstPartyPlate.nationalCodeOfInsurer, - }); - const sandHubReport = sandHubResponse["_doc"] || sandHubResponse; + const thirdPartyPolicyInquiry = firstInquirySubmission.participants + .legacy + ? await (async () => { + const response = await this.sandHubService.getSandHubResponse({ + plate: firstPartyPlate.plate, + nationalCodeOfInsurer: firstPartyPlate.nationalCodeOfInsurer, + }); + return { + raw: response, + mapped: response["_doc"] || response, + plateKind: "CURRENT", + attempts: [ + { plateKind: "CURRENT", succeeded: true, usable: true }, + ], + }; + })() + : await this.getThirdPartyPlateInquiry(firstInquirySubmission); + const sandHubReport = thirdPartyPolicyInquiry.mapped; const clientName = sandHubReport?.CompanyName || sandHubReport?.LastCompanyName; @@ -8070,10 +8304,12 @@ export class RequestManagementService { }; // CAR_BODY specific insurance info - const carBodyInquiry = await this.sandHubService.getCarBodyInquiry({ - nationalCodeOfInsurer: firstPartyPlate.nationalCodeOfInsurer, - plate: firstPartyPlate.plate, - } as any); + const carBodyInquiry = firstInquirySubmission.participants.legacy + ? await this.sandHubService.getCarBodyInquiry({ + nationalCodeOfInsurer: firstPartyPlate.nationalCodeOfInsurer, + plate: firstPartyPlate.plate, + } as any) + : await this.getCarBodyPlateInquiry(firstInquirySubmission); const carBodyInfo = carBodyInquiry.mapped as any; firstPartyDetails.firstPartyCarBodyInsuranceDetail = { @@ -8085,6 +8321,35 @@ export class RequestManagementService { raw: carBodyInquiry.raw, source: carBodyInquiry.source, }; + if (!firstInquirySubmission.participants.legacy) { + firstPartyDetails.participants = + firstInquirySubmission.participants.participants; + firstPartyDetails.participantRoles = + firstInquirySubmission.participants.roles; + firstPartyDetails.participantInquiries = + await this.collectLegacyParticipantInquiries( + firstInquirySubmission, + ); + firstPartyDetails.policyInquiry = { + thirdParty: thirdPartyPolicyInquiry, + carBody: { + source: carBodyInquiry.source, + plateKind: carBodyInquiry.plateKind, + attempts: carBodyInquiry.attempts, + raw: carBodyInquiry.raw, + mapped: carBodyInquiry.mapped, + }, + }; + firstPartyDetails.registrationState = + firstInquirySubmission.vehicle?.registrationState; + firstPartyDetails.previousPlateId = firstInquirySubmission.vehicle + ?.previousPlate + ? this.plateToPlateIdString( + firstInquirySubmission.vehicle.previousPlate, + ) + : undefined; + firstPartyDetails.vehicleVin = firstInquirySubmission.vehicle?.vin; + } firstPartyDetails.firstPartyClient.clientId = await this.resolveCarBodyPolicyClientId(carBodyInfo);