forked from Yara724/api
Complete inquiry participant flow coverage
This commit is contained in:
@@ -70,6 +70,26 @@ describe("buildInsurerFileReport", () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: "SECOND",
|
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: {
|
person: {
|
||||||
userId: "damaged-user-id",
|
userId: "damaged-user-id",
|
||||||
fullName: "زیان دیده نمونه",
|
fullName: "زیان دیده نمونه",
|
||||||
@@ -165,61 +185,89 @@ describe("buildInsurerFileReport", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(getFieldValue(report, PR.ownerSection, PR.name)).toBe("زیان دیده نمونه");
|
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.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(
|
expect(getFieldValue(report, PR.guiltyOwnerSection, PR.nationalCode)).toBe(
|
||||||
"0987654321",
|
"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(
|
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("خیر");
|
).toBe("خیر");
|
||||||
expect(getFieldValue(report, PR.guiltyStatementSection, PR.partyDescription)).toBe(
|
expect(
|
||||||
"توضیحات مقصر",
|
getFieldValue(report, PR.guiltyStatementSection, PR.partyDescription),
|
||||||
);
|
).toBe("توضیحات مقصر");
|
||||||
expect(getFieldValue(report, PR.guiltyStatementSection, PR.admitsGuilt)).toBe(
|
expect(
|
||||||
"بله",
|
getFieldValue(report, PR.guiltyStatementSection, PR.admitsGuilt),
|
||||||
);
|
).toBe("بله");
|
||||||
expect(
|
expect(
|
||||||
getFieldValue(report, PR.guiltyStatementSection, PR.acceptsExpertOpinion),
|
getFieldValue(report, PR.guiltyStatementSection, PR.acceptsExpertOpinion),
|
||||||
).toBe("بله");
|
).toBe("بله");
|
||||||
|
|
||||||
expect(getFieldValue(report, PR.fanavaranSection, PR.fanavaranClaimNo)).toBe(
|
expect(
|
||||||
"111",
|
getFieldValue(report, PR.fanavaranSection, PR.fanavaranClaimNo),
|
||||||
);
|
).toBe("111");
|
||||||
expect(
|
expect(
|
||||||
getFieldValue(report, PR.fanavaranSection, PR.fanavaranExpertiseId),
|
getFieldValue(report, PR.fanavaranSection, PR.fanavaranExpertiseId),
|
||||||
).toBe("444");
|
).toBe("444");
|
||||||
expect(getFieldValue(report, PR.fanavaranSection, PR.fanavaranPolicyId)).toBe(
|
expect(
|
||||||
"555",
|
getFieldValue(report, PR.fanavaranSection, PR.fanavaranPolicyId),
|
||||||
);
|
).toBe("555");
|
||||||
|
|
||||||
expect(getFieldValue(report, PR.timelineSection, PR.fileRegisteredAt)).toBe(
|
expect(getFieldValue(report, PR.timelineSection, PR.fileRegisteredAt)).toBe(
|
||||||
"1405/05/19 13:23",
|
"1405/05/19 13:23",
|
||||||
@@ -228,15 +276,15 @@ describe("buildInsurerFileReport", () => {
|
|||||||
getFieldValue(report, PR.timelineSection, PR.evaluationRegisteredAt),
|
getFieldValue(report, PR.timelineSection, PR.evaluationRegisteredAt),
|
||||||
).toBe("1405/05/19 16:00");
|
).toBe("1405/05/19 16:00");
|
||||||
|
|
||||||
expect(getFieldValue(report, PR.evaluationSection, PR.evaluationResult)).toBe(
|
expect(
|
||||||
"تأیید شده",
|
getFieldValue(report, PR.evaluationSection, PR.evaluationResult),
|
||||||
);
|
).toBe("تأیید شده");
|
||||||
expect(getFieldValue(report, PR.evaluationSection, PR.evaluationExpert)).toBe(
|
expect(
|
||||||
"کارشناس خسارت نمونه",
|
getFieldValue(report, PR.evaluationSection, PR.evaluationExpert),
|
||||||
);
|
).toBe("کارشناس خسارت نمونه");
|
||||||
expect(getFieldValue(report, PR.evaluationSection, PR.evaluationResponse)).toBe(
|
expect(
|
||||||
"نیاز به تعویض سپر جلو",
|
getFieldValue(report, PR.evaluationSection, PR.evaluationResponse),
|
||||||
);
|
).toBe("نیاز به تعویض سپر جلو");
|
||||||
expect(getFieldValue(report, "قیمت قطعات", "قطعه ۱ / نام قطعه")).toBe(
|
expect(getFieldValue(report, "قیمت قطعات", "قطعه ۱ / نام قطعه")).toBe(
|
||||||
"سپر جلو",
|
"سپر جلو",
|
||||||
);
|
);
|
||||||
@@ -345,9 +393,9 @@ describe("buildInsurerFileReport", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const fields = report.sections.flatMap((section) => section.fields);
|
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 === "خیر")).toBe(true);
|
||||||
expect(fields.some((field) => field.value === "true")).toBe(false);
|
expect(fields.some((field) => field.value === "true")).toBe(false);
|
||||||
expect(fields.some((field) => field.value === "false")).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);
|
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("ESG"))).toBe(
|
||||||
expect(fields.some((field) => String(field.value).includes("TEJARAT"))).toBe(
|
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
expect(
|
||||||
|
fields.some((field) => String(field.value).includes("TEJARAT")),
|
||||||
|
).toBe(false);
|
||||||
expect(fields.some((field) => field.label.includes("منبع"))).toBe(false);
|
expect(fields.some((field) => field.label.includes("منبع"))).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ type ReportParty = ReportRecord & {
|
|||||||
vehicle?: ReportRecord;
|
vehicle?: ReportRecord;
|
||||||
statement?: ReportRecord;
|
statement?: ReportRecord;
|
||||||
location?: { lat?: number; lon?: number };
|
location?: { lat?: number; lon?: number };
|
||||||
|
participants?: ReportRecord[];
|
||||||
|
participantRoles?: ReportRecord;
|
||||||
};
|
};
|
||||||
|
|
||||||
function asString(value: unknown): string | undefined {
|
function asString(value: unknown): string | undefined {
|
||||||
@@ -66,7 +68,8 @@ function formatBirthDate(value: unknown): string | undefined {
|
|||||||
|
|
||||||
function formatDateTime(value: unknown): string | undefined {
|
function formatDateTime(value: unknown): string | undefined {
|
||||||
if (value === undefined || value === null || value === "") return 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);
|
if (Number.isNaN(date.getTime())) return asString(value);
|
||||||
const [d, t] = toJalaliDateAndTime(date);
|
const [d, t] = toJalaliDateAndTime(date);
|
||||||
return `${d} ${t}`;
|
return `${d} ${t}`;
|
||||||
@@ -126,13 +129,13 @@ function flattenObject(
|
|||||||
|
|
||||||
if (Array.isArray(obj)) {
|
if (Array.isArray(obj)) {
|
||||||
const value = normalizeListValue(obj);
|
const value = normalizeListValue(obj);
|
||||||
return value
|
return value ? [{ label: persianFieldPath(prefix || "items"), value }] : [];
|
||||||
? [{ label: persianFieldPath(prefix || "items"), value }]
|
|
||||||
: [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof obj !== "object") {
|
if (typeof obj !== "object") {
|
||||||
return [{ label: persianFieldPath(prefix || "value"), value: asString(obj) }];
|
return [
|
||||||
|
{ label: persianFieldPath(prefix || "value"), value: asString(obj) },
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
const rows: InsurerFileReportField[] = [];
|
const rows: InsurerFileReportField[] = [];
|
||||||
@@ -160,7 +163,9 @@ function flattenObject(
|
|||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
function dedupeFields(fields: InsurerFileReportField[]): InsurerFileReportField[] {
|
function dedupeFields(
|
||||||
|
fields: InsurerFileReportField[],
|
||||||
|
): InsurerFileReportField[] {
|
||||||
const seen = new Set<string>();
|
const seen = new Set<string>();
|
||||||
const out: InsurerFileReportField[] = [];
|
const out: InsurerFileReportField[] = [];
|
||||||
|
|
||||||
@@ -180,7 +185,8 @@ function filterEmptySections(
|
|||||||
sections: Array<InsurerFileReportSection | undefined>,
|
sections: Array<InsurerFileReportSection | undefined>,
|
||||||
): InsurerFileReportSection[] {
|
): InsurerFileReportSection[] {
|
||||||
return sections.filter(
|
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;
|
lastName?: string;
|
||||||
}): string | undefined {
|
}): string | undefined {
|
||||||
if (!snapshot) return 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;
|
return name || undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,9 +222,8 @@ function collectExpertNames(
|
|||||||
): string | undefined {
|
): string | undefined {
|
||||||
const names = new Set<string>();
|
const names = new Set<string>();
|
||||||
|
|
||||||
const blameDecision = (
|
const blameDecision = (blame?.expert as Record<string, unknown> | undefined)
|
||||||
blame?.expert as Record<string, unknown> | undefined
|
?.decision as Record<string, unknown> | undefined;
|
||||||
)?.decision as Record<string, unknown> | undefined;
|
|
||||||
const blameExpert = expertNameFromSnapshot(
|
const blameExpert = expertNameFromSnapshot(
|
||||||
blameDecision?.expertProfileSnapshot as
|
blameDecision?.expertProfileSnapshot as
|
||||||
| { firstName?: string; lastName?: string }
|
| { firstName?: string; lastName?: string }
|
||||||
@@ -280,13 +287,16 @@ function resolveReportBlameContext(
|
|||||||
(claim?.blameFileContext as Record<string, unknown> | undefined)
|
(claim?.blameFileContext as Record<string, unknown> | undefined)
|
||||||
?.blameRequestType ??
|
?.blameRequestType ??
|
||||||
(snapshot.accident as Record<string, unknown> | undefined)?.type,
|
(snapshot.accident as Record<string, unknown> | undefined)?.type,
|
||||||
blameStatus: (claim?.blameFileContext as Record<string, unknown> | undefined)
|
blameStatus: (
|
||||||
?.blameStatus,
|
claim?.blameFileContext as Record<string, unknown> | undefined
|
||||||
|
)?.blameStatus,
|
||||||
parties: snapshot.parties,
|
parties: snapshot.parties,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPartyRole(party: ReportParty | null | undefined): string | undefined {
|
function getPartyRole(
|
||||||
|
party: ReportParty | null | undefined,
|
||||||
|
): string | undefined {
|
||||||
const role = party?.role;
|
const role = party?.role;
|
||||||
return typeof role === "string" ? role : undefined;
|
return typeof role === "string" ? role : undefined;
|
||||||
}
|
}
|
||||||
@@ -318,7 +328,8 @@ function sameParty(
|
|||||||
second: ReportParty | null | undefined,
|
second: ReportParty | null | undefined,
|
||||||
): boolean {
|
): boolean {
|
||||||
if (!first || !second) return false;
|
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 =
|
const secondUserId =
|
||||||
second.person?.userId != null ? String(second.person.userId) : "";
|
second.person?.userId != null ? String(second.person.userId) : "";
|
||||||
if (firstUserId && secondUserId) return firstUserId === secondUserId;
|
if (firstUserId && secondUserId) return firstUserId === secondUserId;
|
||||||
@@ -330,7 +341,9 @@ function resolveEvaluationReply(
|
|||||||
): Record<string, unknown> | undefined {
|
): Record<string, unknown> | undefined {
|
||||||
const evaluation = claim?.evaluation as Record<string, unknown> | undefined;
|
const evaluation = claim?.evaluation as Record<string, unknown> | undefined;
|
||||||
return (
|
return (
|
||||||
(evaluation?.damageExpertReplyFinal as Record<string, unknown> | undefined) ??
|
(evaluation?.damageExpertReplyFinal as
|
||||||
|
| Record<string, unknown>
|
||||||
|
| undefined) ??
|
||||||
(evaluation?.damageExpertReply as Record<string, unknown> | undefined)
|
(evaluation?.damageExpertReply as Record<string, unknown> | undefined)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -375,10 +388,18 @@ function buildThirdPartyInsuranceFields(
|
|||||||
const role = getPartyRole(party);
|
const role = getPartyRole(party);
|
||||||
const direct = (party?.insurance ?? {}) as Record<string, unknown>;
|
const direct = (party?.insurance ?? {}) as Record<string, unknown>;
|
||||||
const blameInquiry = pickInquiryReportPayload(
|
const blameInquiry = pickInquiryReportPayload(
|
||||||
inquiryRoleData(blame?.inquiries as Record<string, unknown> | undefined, "thirdParty", role),
|
inquiryRoleData(
|
||||||
|
blame?.inquiries as Record<string, unknown> | undefined,
|
||||||
|
"thirdParty",
|
||||||
|
role,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
const claimInquiry = pickInquiryReportPayload(
|
const claimInquiry = pickInquiryReportPayload(
|
||||||
inquiryRoleData(claim?.inquiries as Record<string, unknown> | undefined, "thirdParty", role),
|
inquiryRoleData(
|
||||||
|
claim?.inquiries as Record<string, unknown> | undefined,
|
||||||
|
"thirdParty",
|
||||||
|
role,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@@ -462,12 +483,23 @@ function buildCarBodyInsuranceFields(
|
|||||||
party?.insurance?.carBody ??
|
party?.insurance?.carBody ??
|
||||||
{}) as Record<string, unknown>;
|
{}) as Record<string, unknown>;
|
||||||
const blameInquiry = pickInquiryReportPayload(
|
const blameInquiry = pickInquiryReportPayload(
|
||||||
inquiryRoleData(blame?.inquiries as Record<string, unknown> | undefined, "carBody", role),
|
inquiryRoleData(
|
||||||
|
blame?.inquiries as Record<string, unknown> | undefined,
|
||||||
|
"carBody",
|
||||||
|
role,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
const claimInquiry = pickInquiryReportPayload(
|
const claimInquiry = pickInquiryReportPayload(
|
||||||
inquiryRoleData(claim?.inquiries as Record<string, unknown> | undefined, "carBody", role),
|
inquiryRoleData(
|
||||||
|
claim?.inquiries as Record<string, unknown> | undefined,
|
||||||
|
"carBody",
|
||||||
|
role,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
const legacy = (blame?.carBodyInsuranceDetail ?? {}) as Record<string, unknown>;
|
const legacy = (blame?.carBodyInsuranceDetail ?? {}) as Record<
|
||||||
|
string,
|
||||||
|
unknown
|
||||||
|
>;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@@ -556,7 +588,10 @@ function buildPartyOwnerSection(
|
|||||||
{
|
{
|
||||||
label: PR.nationalCode,
|
label: PR.nationalCode,
|
||||||
value: options?.useClaimOwnerFallback
|
value: options?.useClaimOwnerFallback
|
||||||
? firstDefined(person?.nationalCodeOfInsurer, money?.nationalCodeOfInsurer)
|
? firstDefined(
|
||||||
|
person?.nationalCodeOfInsurer,
|
||||||
|
money?.nationalCodeOfInsurer,
|
||||||
|
)
|
||||||
: firstDefined(person?.nationalCodeOfInsurer, person?.nationalCode),
|
: firstDefined(person?.nationalCodeOfInsurer, person?.nationalCode),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -572,9 +607,55 @@ function buildPartyOwnerSection(
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function licenseFieldsFromInquiry(
|
function buildParticipantRolesSection(
|
||||||
inquiry?: Record<string, unknown>,
|
title: string,
|
||||||
): { licenseType?: string; licenseDate?: 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<string, string> = {
|
||||||
|
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<string, unknown>): {
|
||||||
|
licenseType?: string;
|
||||||
|
licenseDate?: string;
|
||||||
|
} {
|
||||||
if (!inquiry) return {};
|
if (!inquiry) return {};
|
||||||
return {
|
return {
|
||||||
licenseType: firstDefined(
|
licenseType: firstDefined(
|
||||||
@@ -700,7 +781,9 @@ function buildCaseTimelineSection(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: PR.evaluationRegisteredAt,
|
label: PR.evaluationRegisteredAt,
|
||||||
value: formatDateTime(resolveEvaluationSubmittedAt(claim, evaluationReply)),
|
value: formatDateTime(
|
||||||
|
resolveEvaluationSubmittedAt(claim, evaluationReply),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -709,10 +792,14 @@ function buildFanavaranCodesSection(
|
|||||||
claim?: Record<string, unknown> | null,
|
claim?: Record<string, unknown> | null,
|
||||||
): InsurerFileReportSection | undefined {
|
): InsurerFileReportSection | undefined {
|
||||||
if (!claim) return undefined;
|
if (!claim) return undefined;
|
||||||
const sync = (claim.fanavaranSync as Record<string, unknown> | undefined) ?? {};
|
const sync =
|
||||||
const baseClaim = (sync.baseClaim as Record<string, unknown> | undefined) ?? {};
|
(claim.fanavaranSync as Record<string, unknown> | undefined) ?? {};
|
||||||
const damageCase = (sync.damageCase as Record<string, unknown> | undefined) ?? {};
|
const baseClaim =
|
||||||
const expertise = (sync.expertise as Record<string, unknown> | undefined) ?? {};
|
(sync.baseClaim as Record<string, unknown> | undefined) ?? {};
|
||||||
|
const damageCase =
|
||||||
|
(sync.damageCase as Record<string, unknown> | undefined) ?? {};
|
||||||
|
const expertise =
|
||||||
|
(sync.expertise as Record<string, unknown> | undefined) ?? {};
|
||||||
|
|
||||||
return buildSection(PR.fanavaranSection, [
|
return buildSection(PR.fanavaranSection, [
|
||||||
{
|
{
|
||||||
@@ -725,7 +812,11 @@ function buildFanavaranCodesSection(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: PR.fanavaranDamageCaseId,
|
label: PR.fanavaranDamageCaseId,
|
||||||
value: firstDefined(claim.dmgCaseId, damageCase.dmgCaseId, expertise.dmgCaseId),
|
value: firstDefined(
|
||||||
|
claim.dmgCaseId,
|
||||||
|
damageCase.dmgCaseId,
|
||||||
|
expertise.dmgCaseId,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: PR.fanavaranExpertiseId,
|
label: PR.fanavaranExpertiseId,
|
||||||
@@ -824,10 +915,19 @@ function buildEvaluationPartsSection(
|
|||||||
const prefix = `${PR.part} ${PERSIAN_NUMBER_FORMATTER.format(index + 1)}`;
|
const prefix = `${PR.part} ${PERSIAN_NUMBER_FORMATTER.format(index + 1)}`;
|
||||||
return [
|
return [
|
||||||
{ label: `${prefix} / ${PR.partName}`, value: evaluationPartName(part) },
|
{ 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.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}`,
|
label: `${prefix} / ${PR.factorNeeded}`,
|
||||||
value:
|
value:
|
||||||
@@ -835,7 +935,10 @@ function buildEvaluationPartsSection(
|
|||||||
? persianStatus(part.factorNeeded)
|
? persianStatus(part.factorNeeded)
|
||||||
: undefined,
|
: 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 = (
|
const snapshotAccident = (
|
||||||
claim?.snapshot as { accident?: Record<string, unknown> } | undefined
|
claim?.snapshot as { accident?: Record<string, unknown> } | undefined
|
||||||
)?.accident;
|
)?.accident;
|
||||||
const blameDecision = (
|
const blameDecision = (blame?.expert as Record<string, unknown> | undefined)
|
||||||
blame?.expert as Record<string, unknown> | undefined
|
?.decision as Record<string, unknown> | undefined;
|
||||||
)?.decision as Record<string, unknown> | undefined;
|
const decisionFields = blameDecision?.fields as
|
||||||
const decisionFields = blameDecision?.fields as Record<string, unknown> | undefined;
|
| Record<string, unknown>
|
||||||
|
| undefined;
|
||||||
|
|
||||||
return buildSection(PR.accidentSection, [
|
return buildSection(PR.accidentSection, [
|
||||||
{
|
{
|
||||||
@@ -868,7 +972,8 @@ function buildAccidentReportSection(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: PR.accidentTime,
|
label: PR.accidentTime,
|
||||||
value: asString(statement?.accidentTime) ?? asString(snapshotAccident?.time),
|
value:
|
||||||
|
asString(statement?.accidentTime) ?? asString(snapshotAccident?.time),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: PR.experts,
|
label: PR.experts,
|
||||||
@@ -914,7 +1019,8 @@ function buildAccidentReportSection(
|
|||||||
{
|
{
|
||||||
label: PR.accidentWay,
|
label: PR.accidentWay,
|
||||||
value: asString(
|
value: asString(
|
||||||
(decisionFields?.accidentWay as { label?: string } | undefined)?.label ??
|
(decisionFields?.accidentWay as { label?: string } | undefined)
|
||||||
|
?.label ??
|
||||||
(
|
(
|
||||||
snapshotAccident?.classification as {
|
snapshotAccident?.classification as {
|
||||||
accidentWay?: { label?: string };
|
accidentWay?: { label?: string };
|
||||||
@@ -925,7 +1031,8 @@ function buildAccidentReportSection(
|
|||||||
{
|
{
|
||||||
label: PR.accidentReason,
|
label: PR.accidentReason,
|
||||||
value: asString(
|
value: asString(
|
||||||
(decisionFields?.accidentReason as { label?: string } | undefined)?.label ??
|
(decisionFields?.accidentReason as { label?: string } | undefined)
|
||||||
|
?.label ??
|
||||||
(
|
(
|
||||||
snapshotAccident?.classification as {
|
snapshotAccident?.classification as {
|
||||||
accidentReason?: { label?: string };
|
accidentReason?: { label?: string };
|
||||||
@@ -936,7 +1043,8 @@ function buildAccidentReportSection(
|
|||||||
{
|
{
|
||||||
label: PR.accidentType,
|
label: PR.accidentType,
|
||||||
value: asString(
|
value: asString(
|
||||||
(decisionFields?.accidentType as { label?: string } | undefined)?.label ??
|
(decisionFields?.accidentType as { label?: string } | undefined)
|
||||||
|
?.label ??
|
||||||
(
|
(
|
||||||
snapshotAccident?.classification as {
|
snapshotAccident?.classification as {
|
||||||
accidentType?: { label?: string };
|
accidentType?: { label?: string };
|
||||||
@@ -968,12 +1076,17 @@ export function buildInsurerFileReport(file: {
|
|||||||
: null;
|
: null;
|
||||||
const isCarBody =
|
const isCarBody =
|
||||||
String((blameContext?.type as string | undefined) ?? "") === "CAR_BODY";
|
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<string, unknown> | undefined;
|
const claimVehicle = claim?.vehicle as Record<string, unknown> | undefined;
|
||||||
|
|
||||||
const sections = filterEmptySections([
|
const sections = filterEmptySections([
|
||||||
buildCaseTimelineSection(overview, claim),
|
buildCaseTimelineSection(overview, claim),
|
||||||
|
buildParticipantRolesSection(PR.damagedParticipantsSection, damagedParty),
|
||||||
|
includeGuiltySections
|
||||||
|
? buildParticipantRolesSection(PR.guiltyParticipantsSection, guiltyParty)
|
||||||
|
: undefined,
|
||||||
buildPartyOwnerSection(PR.ownerSection, damagedParty, {
|
buildPartyOwnerSection(PR.ownerSection, damagedParty, {
|
||||||
claim,
|
claim,
|
||||||
useClaimOwnerFallback: true,
|
useClaimOwnerFallback: true,
|
||||||
@@ -1003,7 +1116,11 @@ export function buildInsurerFileReport(file: {
|
|||||||
buildCarBodyInsuranceFields(guiltyParty, blameContext, claim),
|
buildCarBodyInsuranceFields(guiltyParty, blameContext, claim),
|
||||||
)
|
)
|
||||||
: undefined,
|
: undefined,
|
||||||
buildPartyVehicleSection(PR.damagedVehicleSection, damagedParty, claimVehicle),
|
buildPartyVehicleSection(
|
||||||
|
PR.damagedVehicleSection,
|
||||||
|
damagedParty,
|
||||||
|
claimVehicle,
|
||||||
|
),
|
||||||
includeGuiltySections
|
includeGuiltySections
|
||||||
? buildPartyVehicleSection(PR.guiltyVehicleSection, guiltyParty)
|
? buildPartyVehicleSection(PR.guiltyVehicleSection, guiltyParty)
|
||||||
: undefined,
|
: undefined,
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ export const PR = {
|
|||||||
empty: "-",
|
empty: "-",
|
||||||
ownerSection: "مالک خودروی زیان دیده",
|
ownerSection: "مالک خودروی زیان دیده",
|
||||||
guiltyOwnerSection: "مالک خودروی مقصر",
|
guiltyOwnerSection: "مالک خودروی مقصر",
|
||||||
|
damagedParticipantsSection: "اشخاص و نقشهای خودروی زیاندیده",
|
||||||
|
guiltyParticipantsSection: "اشخاص و نقشهای خودروی مقصر",
|
||||||
driverSection: "راننده خودروی زیان دیده",
|
driverSection: "راننده خودروی زیان دیده",
|
||||||
damagedThirdPartyInsuranceSection: "بیمه شخص ثالث زیاندیده",
|
damagedThirdPartyInsuranceSection: "بیمه شخص ثالث زیاندیده",
|
||||||
damagedCarBodyInsuranceSection: "بیمه بدنه زیاندیده",
|
damagedCarBodyInsuranceSection: "بیمه بدنه زیاندیده",
|
||||||
@@ -61,6 +63,11 @@ export const PR = {
|
|||||||
claimsDamage: "ادعای خسارت",
|
claimsDamage: "ادعای خسارت",
|
||||||
acceptsExpertOpinion: "پذیرش نظر کارشناس",
|
acceptsExpertOpinion: "پذیرش نظر کارشناس",
|
||||||
partyRole: "نقش طرف",
|
partyRole: "نقش طرف",
|
||||||
|
driverRole: "راننده",
|
||||||
|
vehicleOwnerRole: "مالک وسیله نقلیه",
|
||||||
|
thirdPartyPolicyholderRole: "بیمهگذار شخص ثالث",
|
||||||
|
carBodyPolicyholderRole: "بیمهگذار بدنه",
|
||||||
|
unknown: "نامشخص",
|
||||||
data: "اطلاعات",
|
data: "اطلاعات",
|
||||||
date: "تاریخ",
|
date: "تاریخ",
|
||||||
time: "زمان",
|
time: "زمان",
|
||||||
|
|||||||
@@ -24,9 +24,8 @@ export enum VehicleRegistrationState {
|
|||||||
|
|
||||||
export class InquiryPlateDto {
|
export class InquiryPlateDto {
|
||||||
@ApiProperty({ example: "44" })
|
@ApiProperty({ example: "44" })
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
leftDigits: string;
|
leftDigits: string | number;
|
||||||
|
|
||||||
@ApiProperty({ example: "ب" })
|
@ApiProperty({ example: "ب" })
|
||||||
@IsString()
|
@IsString()
|
||||||
@@ -34,14 +33,12 @@ export class InquiryPlateDto {
|
|||||||
centerAlphabet: string;
|
centerAlphabet: string;
|
||||||
|
|
||||||
@ApiProperty({ example: "111" })
|
@ApiProperty({ example: "111" })
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
centerDigits: string;
|
centerDigits: string | number;
|
||||||
|
|
||||||
@ApiProperty({ example: "22" })
|
@ApiProperty({ example: "22" })
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
ir: string;
|
ir: string | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InquiryParticipantInputDto {
|
export class InquiryParticipantInputDto {
|
||||||
|
|||||||
@@ -146,6 +146,22 @@ export class FirstPartyDetail {
|
|||||||
|
|
||||||
@Prop({ type: Boolean })
|
@Prop({ type: Boolean })
|
||||||
firstPartyCertificate: boolean | null;
|
firstPartyCertificate: boolean | null;
|
||||||
|
|
||||||
|
@Prop({ type: [MongooseSchema.Types.Mixed] })
|
||||||
|
participants?: Record<string, unknown>[];
|
||||||
|
|
||||||
|
@Prop({ type: MongooseSchema.Types.Mixed })
|
||||||
|
participantRoles?: Record<string, string>;
|
||||||
|
|
||||||
|
@Prop({ type: MongooseSchema.Types.Mixed })
|
||||||
|
participantInquiries?: Record<string, unknown>;
|
||||||
|
|
||||||
|
@Prop({ type: MongooseSchema.Types.Mixed })
|
||||||
|
policyInquiry?: Record<string, unknown>;
|
||||||
|
|
||||||
|
@Prop() registrationState?: string;
|
||||||
|
@Prop() previousPlateId?: string;
|
||||||
|
@Prop() vehicleVin?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SecondPartyDetail {
|
export class SecondPartyDetail {
|
||||||
@@ -178,6 +194,22 @@ export class SecondPartyDetail {
|
|||||||
|
|
||||||
@Prop({ type: SecondPartyFile })
|
@Prop({ type: SecondPartyFile })
|
||||||
secondPartyFiles?: SecondPartyFile;
|
secondPartyFiles?: SecondPartyFile;
|
||||||
|
|
||||||
|
@Prop({ type: [MongooseSchema.Types.Mixed] })
|
||||||
|
participants?: Record<string, unknown>[];
|
||||||
|
|
||||||
|
@Prop({ type: MongooseSchema.Types.Mixed })
|
||||||
|
participantRoles?: Record<string, string>;
|
||||||
|
|
||||||
|
@Prop({ type: MongooseSchema.Types.Mixed })
|
||||||
|
participantInquiries?: Record<string, unknown>;
|
||||||
|
|
||||||
|
@Prop({ type: MongooseSchema.Types.Mixed })
|
||||||
|
policyInquiry?: Record<string, unknown>;
|
||||||
|
|
||||||
|
@Prop() registrationState?: string;
|
||||||
|
@Prop() previousPlateId?: string;
|
||||||
|
@Prop() vehicleVin?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class LocationDto {
|
export class LocationDto {
|
||||||
|
|||||||
@@ -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", () => {
|
it("allows an explicitly unknown policyholder only for a damaged-party submission", () => {
|
||||||
const input = {
|
const input = {
|
||||||
driver: {
|
driver: {
|
||||||
|
|||||||
@@ -391,12 +391,31 @@ export function assertPreviousPlateInquiryMatchesVin(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isPolicyNotFoundError(error: unknown): boolean {
|
||||||
|
const candidate = error as Record<string, any> | 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<T>(options: {
|
export async function runPlateInquiryWithFallback<T>(options: {
|
||||||
vehicle?: ResolvedInquiryVehicle;
|
vehicle?: ResolvedInquiryVehicle;
|
||||||
fallbackCurrentPlate: InquiryVehicleInputDto["currentPlate"];
|
fallbackCurrentPlate: InquiryVehicleInputDto["currentPlate"];
|
||||||
query: (plate: InquiryVehicleInputDto["currentPlate"]) => Promise<T>;
|
query: (plate: InquiryVehicleInputDto["currentPlate"]) => Promise<T>;
|
||||||
isUsable: (value: T) => boolean;
|
isUsable: (value: T) => boolean;
|
||||||
mappedValue: (value: T) => Record<string, any>;
|
mappedValue: (value: T) => Record<string, any>;
|
||||||
|
shouldFallbackOnError?: (error: unknown) => boolean;
|
||||||
}): Promise<{
|
}): Promise<{
|
||||||
value: T;
|
value: T;
|
||||||
plateKind: "CURRENT" | "PREVIOUS";
|
plateKind: "CURRENT" | "PREVIOUS";
|
||||||
@@ -462,6 +481,15 @@ export async function runPlateInquiryWithFallback<T>(options: {
|
|||||||
error: error instanceof Error ? error.message : String(error),
|
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 (isLast) {
|
||||||
if (typeof error === "object" && error != null) {
|
if (typeof error === "object" && error != null) {
|
||||||
(error as { attempts?: typeof attempts }).attempts = attempts;
|
(error as { attempts?: typeof attempts }).attempts = attempts;
|
||||||
|
|||||||
@@ -542,6 +542,44 @@ export class RequestManagementService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Inquiry bundle for the still-routable legacy RequestManagement model. */
|
||||||
|
private async collectLegacyParticipantInquiries(
|
||||||
|
submission: NormalizedInquirySubmission<Record<string, any>>,
|
||||||
|
): Promise<Record<string, unknown> | undefined> {
|
||||||
|
if (submission.participants.legacy) return undefined;
|
||||||
|
|
||||||
|
const personal: Record<string, unknown> = {};
|
||||||
|
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 {
|
private getPartyIndex(req: any, role: PartyRole): number {
|
||||||
return Array.isArray(req.parties)
|
return Array.isArray(req.parties)
|
||||||
? req.parties.findIndex((p) => p?.role === role)
|
? req.parties.findIndex((p) => p?.role === role)
|
||||||
@@ -3271,6 +3309,9 @@ export class RequestManagementService {
|
|||||||
user: any,
|
user: any,
|
||||||
body: AddPlateDto,
|
body: AddPlateDto,
|
||||||
partyType: "firstParty" | "secondParty",
|
partyType: "firstParty" | "secondParty",
|
||||||
|
inquirySubmission?: NormalizedInquirySubmission<Record<string, any>>,
|
||||||
|
policyInquiry?: Record<string, any>,
|
||||||
|
participantInquiries?: Record<string, unknown>,
|
||||||
) {
|
) {
|
||||||
if (request.type === "THIRD_PARTY" && partyType === "firstParty") {
|
if (request.type === "THIRD_PARTY" && partyType === "firstParty") {
|
||||||
this.sandHubService.assertInsuranceMatchesDeployment(
|
this.sandHubService.assertInsuranceMatchesDeployment(
|
||||||
@@ -3282,12 +3323,16 @@ export class RequestManagementService {
|
|||||||
const clientName = sandHubReport?.CompanyName;
|
const clientName = sandHubReport?.CompanyName;
|
||||||
const companyCode = sandHubReport?.CompanyCode;
|
const companyCode = sandHubReport?.CompanyCode;
|
||||||
|
|
||||||
const client = await this.clientService.findOrCreateClientByCompanyCode(
|
const policyholderUnknown =
|
||||||
companyCode,
|
inquirySubmission?.thirdPartyPolicyholder.unknown === true;
|
||||||
clientName,
|
const client = clientName
|
||||||
);
|
? await this.clientService.findOrCreateClientByCompanyCode(
|
||||||
|
companyCode,
|
||||||
|
clientName,
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
|
||||||
if (!client) {
|
if (!client && !policyholderUnknown) {
|
||||||
throw new HttpException("Client not found", HttpStatus.CONFLICT);
|
throw new HttpException("Client not found", HttpStatus.CONFLICT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3313,23 +3358,27 @@ export class RequestManagementService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.userDbService.findOneAndUpdate(
|
if (client) {
|
||||||
{ _id: user.sub },
|
await this.userDbService.findOneAndUpdate(
|
||||||
{ clientKey: client["_doc"]._id },
|
{ _id: user.sub },
|
||||||
);
|
{ clientKey: (client as any)["_doc"]?._id ?? (client as any)._id },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const sandHubDocData = {
|
const sandHubDocData = {
|
||||||
...sandHubReport,
|
...sandHubReport,
|
||||||
plate: body.plate,
|
plate: body.plate,
|
||||||
nationalCode: body.nationalCodeOfInsurer,
|
nationalCode: body.nationalCodeOfInsurer,
|
||||||
};
|
};
|
||||||
const sandHubDoc = await this.sandHubService.sandHubDocumentCreator(
|
const sandHubDoc = policyInquiry?.skipped
|
||||||
user.sub,
|
? null
|
||||||
request["_doc"]._id,
|
: await this.sandHubService.sandHubDocumentCreator(
|
||||||
sandHubDocData,
|
user.sub,
|
||||||
);
|
request["_doc"]._id,
|
||||||
|
sandHubDocData,
|
||||||
|
);
|
||||||
|
|
||||||
if (partyType === "firstParty") {
|
if (partyType === "firstParty" && sandHubDoc) {
|
||||||
await this.requestManagementDbService.findAndUpdate(
|
await this.requestManagementDbService.findAndUpdate(
|
||||||
{ _id: request._id },
|
{ _id: request._id },
|
||||||
{
|
{
|
||||||
@@ -3352,8 +3401,6 @@ export class RequestManagementService {
|
|||||||
body.driverBirthday,
|
body.driverBirthday,
|
||||||
[`${partyDetails}.${partyType}CarDetail.carType`]: `${sandHubReport.UsageField} / ${sandHubReport.MapUsageName || "-"}`,
|
[`${partyDetails}.${partyType}CarDetail.carType`]: `${sandHubReport.UsageField} / ${sandHubReport.MapUsageName || "-"}`,
|
||||||
[`${partyDetails}.${partyType}CarDetail.isNewCar`]: body.isNewCar,
|
[`${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}Certificate`]: body.userNoCertificate,
|
||||||
[`${partyDetails}.${partyType}InsuranceDetail.insuranceId`]:
|
[`${partyDetails}.${partyType}InsuranceDetail.insuranceId`]:
|
||||||
sandHubReport.LastCompanyDocumentNumber,
|
sandHubReport.LastCompanyDocumentNumber,
|
||||||
@@ -3367,12 +3414,38 @@ export class RequestManagementService {
|
|||||||
sandHubReport.EndDate,
|
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.
|
// For CAR_BODY type, persist the provider response and its mapped fields.
|
||||||
if (request.type === "CAR_BODY" && partyType === "firstParty") {
|
if (request.type === "CAR_BODY" && partyType === "firstParty") {
|
||||||
const carBodyInquiry = await this.sandHubService.getCarBodyInquiry({
|
const carBodyInquiry =
|
||||||
nationalCodeOfInsurer: body.nationalCodeOfInsurer,
|
inquirySubmission && !inquirySubmission.participants.legacy
|
||||||
plate: body.plate,
|
? await this.getCarBodyPlateInquiry(inquirySubmission)
|
||||||
} as any);
|
: await this.sandHubService.getCarBodyInquiry({
|
||||||
|
nationalCodeOfInsurer: body.nationalCodeOfInsurer,
|
||||||
|
plate: body.plate,
|
||||||
|
} as any);
|
||||||
const carBodyInfo = carBodyInquiry.mapped as any;
|
const carBodyInfo = carBodyInquiry.mapped as any;
|
||||||
|
|
||||||
this.logger.log(
|
this.logger.log(
|
||||||
@@ -3400,6 +3473,18 @@ export class RequestManagementService {
|
|||||||
carBodyInquiry.raw;
|
carBodyInquiry.raw;
|
||||||
setFields["firstPartyDetails.firstPartyCarBodyInsuranceDetail.source"] =
|
setFields["firstPartyDetails.firstPartyCarBodyInsuranceDetail.source"] =
|
||||||
carBodyInquiry.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`] =
|
setFields[`${partyDetails}.${partyType}Client.clientId`] =
|
||||||
await this.resolveCarBodyPolicyClientId(carBodyInfo);
|
await this.resolveCarBodyPolicyClientId(carBodyInfo);
|
||||||
}
|
}
|
||||||
@@ -3456,6 +3541,13 @@ export class RequestManagementService {
|
|||||||
(request.nextStep === StepsEnum.F_addPlate ||
|
(request.nextStep === StepsEnum.F_addPlate ||
|
||||||
request.currentStep === StepsEnum.F_addPlate) &&
|
request.currentStep === StepsEnum.F_addPlate) &&
|
||||||
request.firstPartyDetails.firstPartyPhoneNumber === user.username;
|
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) {
|
if (!isFirstParty) {
|
||||||
const firstPartyDetails = request.firstPartyDetails as any;
|
const firstPartyDetails = request.firstPartyDetails as any;
|
||||||
@@ -3482,10 +3574,23 @@ export class RequestManagementService {
|
|||||||
// TODO: Activate
|
// TODO: Activate
|
||||||
// --- Proceed with existing logic if the check passes ---
|
// --- Proceed with existing logic if the check passes ---
|
||||||
// 1) Main third-party/block inquiry (existing behavior)
|
// 1) Main third-party/block inquiry (existing behavior)
|
||||||
const sanHubResponse = await this.sandHubService.getSandHubResponse({
|
const policyInquiry = inquirySubmission.participants.legacy
|
||||||
plate: body.plate,
|
? await (async () => {
|
||||||
nationalCodeOfInsurer: body.nationalCodeOfInsurer,
|
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) {
|
// if (sanHubResponse.Error) {
|
||||||
// throw new HttpException(
|
// throw new HttpException(
|
||||||
@@ -3520,6 +3625,9 @@ export class RequestManagementService {
|
|||||||
user,
|
user,
|
||||||
body,
|
body,
|
||||||
isFirstParty ? "firstParty" : "secondParty",
|
isFirstParty ? "firstParty" : "secondParty",
|
||||||
|
inquirySubmission,
|
||||||
|
policyInquiry,
|
||||||
|
participantInquiries,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6292,7 +6400,7 @@ export class RequestManagementService {
|
|||||||
return none;
|
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(
|
private async sanitizePartyForBlameUserView(
|
||||||
party: any,
|
party: any,
|
||||||
): Promise<Record<string, unknown>> {
|
): Promise<Record<string, unknown>> {
|
||||||
@@ -6311,12 +6419,22 @@ export class RequestManagementService {
|
|||||||
const vehicle = party.vehicle
|
const vehicle = party.vehicle
|
||||||
? {
|
? {
|
||||||
plateId: party.vehicle.plateId,
|
plateId: party.vehicle.plateId,
|
||||||
|
previousPlateId: party.vehicle.previousPlateId,
|
||||||
|
registrationState: party.vehicle.registrationState,
|
||||||
name: party.vehicle.name,
|
name: party.vehicle.name,
|
||||||
model: party.vehicle.model,
|
model: party.vehicle.model,
|
||||||
type: party.vehicle.type,
|
type: party.vehicle.type,
|
||||||
isNew: party.vehicle.isNew,
|
isNew: party.vehicle.isNew,
|
||||||
}
|
}
|
||||||
: undefined;
|
: 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<string, unknown> | undefined;
|
const evidenceRaw = party.evidence as Record<string, unknown> | undefined;
|
||||||
const evidence: Record<string, unknown> | undefined = evidenceRaw
|
const evidence: Record<string, unknown> | undefined = evidenceRaw
|
||||||
? { ...evidenceRaw }
|
? { ...evidenceRaw }
|
||||||
@@ -6350,6 +6468,8 @@ export class RequestManagementService {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
role: party.role,
|
role: party.role,
|
||||||
|
participants,
|
||||||
|
participantRoles: party.participantRoles,
|
||||||
person: safePerson,
|
person: safePerson,
|
||||||
carBodyFirstForm: party.carBodyFirstForm,
|
carBodyFirstForm: party.carBodyFirstForm,
|
||||||
location: party.location,
|
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;
|
const carBodyInfo = carBodyInquiry.mapped as any;
|
||||||
this.recordPartyCaseInquiryStatus(req, "carBody", PartyRole.FIRST, true, {
|
this.recordPartyCaseInquiryStatus(req, "carBody", PartyRole.FIRST, true, {
|
||||||
source: carBodyInquiry.source,
|
source: carBodyInquiry.source,
|
||||||
|
plateKind: carBodyInquiry.plateKind,
|
||||||
|
attempts: carBodyInquiry.attempts,
|
||||||
raw: carBodyInquiry.raw,
|
raw: carBodyInquiry.raw,
|
||||||
mapped: carBodyInfo,
|
mapped: carBodyInfo,
|
||||||
});
|
});
|
||||||
@@ -7669,13 +7805,30 @@ export class RequestManagementService {
|
|||||||
stepsToAdd.push(StepsEnum.S_addDescription);
|
stepsToAdd.push(StepsEnum.S_addDescription);
|
||||||
|
|
||||||
// Process first party plate with SandHub lookup
|
// 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 {
|
try {
|
||||||
const sandHubResponse = await this.sandHubService.getSandHubResponse({
|
const firstPolicyInquiry = firstInquirySubmission.participants.legacy
|
||||||
plate: firstPartyPlate.plate,
|
? await (async () => {
|
||||||
nationalCodeOfInsurer: firstPartyPlate.nationalCodeOfInsurer,
|
const response = await this.sandHubService.getSandHubResponse({
|
||||||
});
|
plate: firstPartyPlate.plate,
|
||||||
const sandHubReport = sandHubResponse["_doc"] || sandHubResponse;
|
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(
|
this.sandHubService.assertInsuranceMatchesDeployment(
|
||||||
sandHubReport,
|
sandHubReport,
|
||||||
"THIRD_PARTY",
|
"THIRD_PARTY",
|
||||||
@@ -7727,6 +7880,26 @@ export class RequestManagementService {
|
|||||||
startDate: sandHubReport?.IssueDate || sandHubReport?.StartDate,
|
startDate: sandHubReport?.IssueDate || sandHubReport?.StartDate,
|
||||||
endDate: sandHubReport?.EndDate,
|
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
|
// Update the firstPartyDetails in the payload with all plate data
|
||||||
updatePayload.$set.firstPartyDetails = firstPartyDetails;
|
updatePayload.$set.firstPartyDetails = firstPartyDetails;
|
||||||
@@ -7742,26 +7915,47 @@ export class RequestManagementService {
|
|||||||
|
|
||||||
// Process second party plate
|
// Process second party plate
|
||||||
try {
|
try {
|
||||||
const secondPartyPlate = formData.secondParty.plate;
|
const secondInquirySubmission = this.normalizeInquiryInput(
|
||||||
const sandHubResponse = await this.sandHubService.getSandHubResponse({
|
BlameRequestType.THIRD_PARTY,
|
||||||
plate: secondPartyPlate.plate,
|
formData.secondParty.plate,
|
||||||
nationalCodeOfInsurer: secondPartyPlate.nationalCodeOfInsurer,
|
PartyRole.SECOND,
|
||||||
});
|
);
|
||||||
const sandHubReport = sandHubResponse["_doc"] || sandHubResponse;
|
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 =
|
const clientName =
|
||||||
sandHubReport?.CompanyName || sandHubReport?.LastCompanyName;
|
sandHubReport?.CompanyName || sandHubReport?.LastCompanyName;
|
||||||
const companyCode = sandHubReport?.CompanyCode;
|
const companyCode = sandHubReport?.CompanyCode;
|
||||||
|
|
||||||
// Try to find client by company code first (more reliable)
|
// Try to find client by company code first (more reliable)
|
||||||
const client = companyCode
|
const policyholderUnknown =
|
||||||
? await this.clientService.findOrCreateClientByCompanyCode(
|
secondInquirySubmission.thirdPartyPolicyholder.unknown === true;
|
||||||
companyCode,
|
const client = clientName
|
||||||
clientName,
|
? companyCode
|
||||||
)
|
? await this.clientService.findOrCreateClientByCompanyCode(
|
||||||
: await this.clientService.findOne({ clientName: clientName });
|
companyCode,
|
||||||
|
clientName,
|
||||||
|
)
|
||||||
|
: await this.clientService.findOne({ clientName: clientName })
|
||||||
|
: null;
|
||||||
|
|
||||||
if (!client) {
|
if (!client && !policyholderUnknown) {
|
||||||
throw new NotFoundException(
|
throw new NotFoundException(
|
||||||
`Client not found for company: ${clientName}${companyCode ? ` (code: ${companyCode})` : ""}`,
|
`Client not found for company: ${clientName}${companyCode ? ` (code: ${companyCode})` : ""}`,
|
||||||
);
|
);
|
||||||
@@ -7778,10 +7972,12 @@ export class RequestManagementService {
|
|||||||
carType: `${sandHubReport?.UsageField || ""} / ${sandHubReport?.MapUsageName || "-"}`,
|
carType: `${sandHubReport?.UsageField || ""} / ${sandHubReport?.MapUsageName || "-"}`,
|
||||||
isNewCar: secondPartyPlate.isNewCar,
|
isNewCar: secondPartyPlate.isNewCar,
|
||||||
};
|
};
|
||||||
secondPartyDetails.secondPartyClient = {
|
if (client) {
|
||||||
clientId: (client as any)["_doc"]?._id || (client as any)._id,
|
secondPartyDetails.secondPartyClient = {
|
||||||
clientName: clientName,
|
clientId: (client as any)["_doc"]?._id || (client as any)._id,
|
||||||
};
|
clientName: clientName,
|
||||||
|
};
|
||||||
|
}
|
||||||
secondPartyDetails.secondPartyCertificate =
|
secondPartyDetails.secondPartyCertificate =
|
||||||
secondPartyPlate.userNoCertificate;
|
secondPartyPlate.userNoCertificate;
|
||||||
secondPartyDetails.secondPartyInsuranceDetail = {
|
secondPartyDetails.secondPartyInsuranceDetail = {
|
||||||
@@ -7795,6 +7991,26 @@ export class RequestManagementService {
|
|||||||
startDate: sandHubReport?.IssueDate || sandHubReport?.StartDate,
|
startDate: sandHubReport?.IssueDate || sandHubReport?.StartDate,
|
||||||
endDate: sandHubReport?.EndDate,
|
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
|
// Update the secondPartyDetails in the payload
|
||||||
updatePayload.$set.secondPartyDetails = secondPartyDetails;
|
updatePayload.$set.secondPartyDetails = secondPartyDetails;
|
||||||
@@ -8014,13 +8230,31 @@ export class RequestManagementService {
|
|||||||
stepsToAdd.push(StepsEnum.F_addDescription);
|
stepsToAdd.push(StepsEnum.F_addDescription);
|
||||||
|
|
||||||
// Process first party plate with SandHub lookup
|
// 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 {
|
try {
|
||||||
const sandHubResponse = await this.sandHubService.getSandHubResponse({
|
const thirdPartyPolicyInquiry = firstInquirySubmission.participants
|
||||||
plate: firstPartyPlate.plate,
|
.legacy
|
||||||
nationalCodeOfInsurer: firstPartyPlate.nationalCodeOfInsurer,
|
? await (async () => {
|
||||||
});
|
const response = await this.sandHubService.getSandHubResponse({
|
||||||
const sandHubReport = sandHubResponse["_doc"] || sandHubResponse;
|
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 =
|
const clientName =
|
||||||
sandHubReport?.CompanyName || sandHubReport?.LastCompanyName;
|
sandHubReport?.CompanyName || sandHubReport?.LastCompanyName;
|
||||||
@@ -8070,10 +8304,12 @@ export class RequestManagementService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// CAR_BODY specific insurance info
|
// CAR_BODY specific insurance info
|
||||||
const carBodyInquiry = await this.sandHubService.getCarBodyInquiry({
|
const carBodyInquiry = firstInquirySubmission.participants.legacy
|
||||||
nationalCodeOfInsurer: firstPartyPlate.nationalCodeOfInsurer,
|
? await this.sandHubService.getCarBodyInquiry({
|
||||||
plate: firstPartyPlate.plate,
|
nationalCodeOfInsurer: firstPartyPlate.nationalCodeOfInsurer,
|
||||||
} as any);
|
plate: firstPartyPlate.plate,
|
||||||
|
} as any)
|
||||||
|
: await this.getCarBodyPlateInquiry(firstInquirySubmission);
|
||||||
const carBodyInfo = carBodyInquiry.mapped as any;
|
const carBodyInfo = carBodyInquiry.mapped as any;
|
||||||
|
|
||||||
firstPartyDetails.firstPartyCarBodyInsuranceDetail = {
|
firstPartyDetails.firstPartyCarBodyInsuranceDetail = {
|
||||||
@@ -8085,6 +8321,35 @@ export class RequestManagementService {
|
|||||||
raw: carBodyInquiry.raw,
|
raw: carBodyInquiry.raw,
|
||||||
source: carBodyInquiry.source,
|
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 =
|
firstPartyDetails.firstPartyClient.clientId =
|
||||||
await this.resolveCarBodyPolicyClientId(carBodyInfo);
|
await this.resolveCarBodyPolicyClientId(carBodyInfo);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user