forked from Yara724/api
Merge pull request 'YARA-1241' (#276) from s.yahyaee/yara724-api:main into main
Reviewed-on: Yara724/api#276
This commit is contained in:
183
src/case-expert-report/case-expert-report.builder.spec.ts
Normal file
183
src/case-expert-report/case-expert-report.builder.spec.ts
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
import { buildInsurerFileReport } from "./case-expert-report.builder";
|
||||||
|
import { PR } from "./persian-report-labels";
|
||||||
|
import { toJalaliDateAndTime } from "../helpers/date-jalali";
|
||||||
|
|
||||||
|
describe("buildInsurerFileReport", () => {
|
||||||
|
const getFieldValue = (
|
||||||
|
report: ReturnType<typeof buildInsurerFileReport>,
|
||||||
|
sectionTitle: string,
|
||||||
|
fieldLabel: string,
|
||||||
|
) => {
|
||||||
|
const section = report.sections.find((item) => item.title === sectionTitle);
|
||||||
|
expect(section).toBeDefined();
|
||||||
|
const field = section?.fields.find((item) => item.label === fieldLabel);
|
||||||
|
expect(field).toBeDefined();
|
||||||
|
return field?.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
it("separates insurance blocks and exposes Fanavaran/timeline/evaluation data", () => {
|
||||||
|
const fileCreatedAt = new Date("2026-08-10T09:53:23.588Z");
|
||||||
|
const evaluationSubmittedAt = new Date("2026-08-10T12:30:45.000Z");
|
||||||
|
const [fileDate, fileTime] = toJalaliDateAndTime(fileCreatedAt);
|
||||||
|
const [evaluationDate, evaluationTime] =
|
||||||
|
toJalaliDateAndTime(evaluationSubmittedAt);
|
||||||
|
|
||||||
|
const report = buildInsurerFileReport({
|
||||||
|
overview: {
|
||||||
|
publicId: "A00010",
|
||||||
|
requestNo: "REQ-10",
|
||||||
|
createdAt: fileCreatedAt,
|
||||||
|
},
|
||||||
|
blame: {
|
||||||
|
type: "THIRD_PARTY",
|
||||||
|
blameStatus: "AGREED",
|
||||||
|
createdAt: fileCreatedAt,
|
||||||
|
parties: [
|
||||||
|
{
|
||||||
|
role: "FIRST",
|
||||||
|
person: {
|
||||||
|
userId: "guilty-user-id",
|
||||||
|
fullName: "مقصر نمونه",
|
||||||
|
phoneNumber: "09120000000",
|
||||||
|
clientId: "client-guilty",
|
||||||
|
},
|
||||||
|
statement: { admitsGuilt: true },
|
||||||
|
insurance: {
|
||||||
|
policyNumber: "TP-GUILTY-001",
|
||||||
|
company: "بیمه ثالث مقصر",
|
||||||
|
startDate: "1405/01/01",
|
||||||
|
endDate: "1406/01/01",
|
||||||
|
financialCeiling: "900000000",
|
||||||
|
carBodyInsurance: {
|
||||||
|
policyNumber: "CB-GUILTY-001",
|
||||||
|
insurerCompany: "بیمه بدنه مقصر",
|
||||||
|
startDate: "1405/02/01",
|
||||||
|
endDate: "1406/02/01",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: "SECOND",
|
||||||
|
person: {
|
||||||
|
userId: "damaged-user-id",
|
||||||
|
fullName: "زیان دیده نمونه",
|
||||||
|
phoneNumber: "09121111111",
|
||||||
|
nationalCodeOfInsurer: "1234567890",
|
||||||
|
clientId: "client-damaged",
|
||||||
|
insurerBirthday: 13700101,
|
||||||
|
},
|
||||||
|
statement: {
|
||||||
|
claimsDamage: true,
|
||||||
|
description: "توضیحات زیاندیده",
|
||||||
|
accidentDate: "2026-08-10",
|
||||||
|
accidentTime: "13:23",
|
||||||
|
},
|
||||||
|
insurance: {
|
||||||
|
policyNumber: "TP-DAMAGED-001",
|
||||||
|
company: "بیمه ثالث زیاندیده",
|
||||||
|
startDate: "1405/03/01",
|
||||||
|
endDate: "1406/03/01",
|
||||||
|
financialCeiling: "700000000",
|
||||||
|
carBodyInsurance: {
|
||||||
|
policyNumber: "CB-DAMAGED-001",
|
||||||
|
insurerCompany: "بیمه بدنه زیاندیده",
|
||||||
|
startDate: "1405/04/01",
|
||||||
|
endDate: "1406/04/01",
|
||||||
|
coverages: ["سرقت", "آتشسوزی"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
vehicle: {
|
||||||
|
carName: "207",
|
||||||
|
carModel: "1402",
|
||||||
|
plate: {
|
||||||
|
leftDigits: 12,
|
||||||
|
centerAlphabet: "ب",
|
||||||
|
centerDigits: 345,
|
||||||
|
ir: 11,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
expert: {
|
||||||
|
decision: {
|
||||||
|
guiltyPartyId: "guilty-user-id",
|
||||||
|
description: "مقصر شناخته شد",
|
||||||
|
fields: {
|
||||||
|
accidentWay: { label: "از جلو" },
|
||||||
|
accidentReason: { label: "عدم رعایت فاصله" },
|
||||||
|
accidentType: { label: "برخورد" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
claim: {
|
||||||
|
claimStatus: "APPROVED",
|
||||||
|
claimNo: 111,
|
||||||
|
claimId: 222,
|
||||||
|
dmgCaseId: 333,
|
||||||
|
expertiseId: 444,
|
||||||
|
owner: { fullName: "زیان دیده نمونه" },
|
||||||
|
vehicle: {
|
||||||
|
carName: "207",
|
||||||
|
carModel: "1402",
|
||||||
|
carType: "sedan",
|
||||||
|
},
|
||||||
|
fanavaranSync: {
|
||||||
|
baseClaim: {
|
||||||
|
policyId: 555,
|
||||||
|
driverId: 666,
|
||||||
|
vehicleKindId: 777,
|
||||||
|
insuranceCorpId: 888,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
evaluation: {
|
||||||
|
damageExpertReplyFinal: {
|
||||||
|
submittedAt: evaluationSubmittedAt,
|
||||||
|
description: "نیاز به تعویض سپر جلو",
|
||||||
|
actorDetail: { actorName: "کارشناس خسارت نمونه" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
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.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.timelineSection, PR.fileRegisteredAt)).toBe(
|
||||||
|
`${fileDate} ${fileTime}`,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
getFieldValue(report, PR.timelineSection, PR.evaluationRegisteredAt),
|
||||||
|
).toBe(`${evaluationDate} ${evaluationTime}`);
|
||||||
|
|
||||||
|
expect(getFieldValue(report, PR.evaluationSection, PR.evaluationResult)).toBe(
|
||||||
|
"تأیید شده",
|
||||||
|
);
|
||||||
|
expect(getFieldValue(report, PR.evaluationSection, PR.evaluationExpert)).toBe(
|
||||||
|
"کارشناس خسارت نمونه",
|
||||||
|
);
|
||||||
|
expect(getFieldValue(report, PR.evaluationSection, PR.evaluationResponse)).toBe(
|
||||||
|
"نیاز به تعویض سپر جلو",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
import { resolveDamagedPartyRow } from "src/helpers/blame-damaged-party";
|
import {
|
||||||
|
resolveClaimOwnerParty,
|
||||||
|
resolveDamagedPartyRow,
|
||||||
|
} from "src/helpers/blame-damaged-party";
|
||||||
import { toJalaliDateAndTime } from "src/helpers/date-jalali";
|
import { toJalaliDateAndTime } from "src/helpers/date-jalali";
|
||||||
import { PartyRole } from "src/request-management/entities/schema/partyRole.enum";
|
import { PartyRole } from "src/request-management/entities/schema/partyRole.enum";
|
||||||
import {
|
import {
|
||||||
@@ -15,8 +18,20 @@ const SKIP_FLATTEN_KEYS = new Set([
|
|||||||
"workflow",
|
"workflow",
|
||||||
"evidence",
|
"evidence",
|
||||||
"confirmation",
|
"confirmation",
|
||||||
|
"inquiries",
|
||||||
|
"raw",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
type ReportRecord = Record<string, unknown>;
|
||||||
|
type ReportParty = ReportRecord & {
|
||||||
|
role?: string;
|
||||||
|
person?: ReportRecord;
|
||||||
|
insurance?: ReportRecord & { carBodyInsurance?: ReportRecord };
|
||||||
|
vehicle?: ReportRecord;
|
||||||
|
statement?: ReportRecord;
|
||||||
|
location?: { lat?: number; lon?: number };
|
||||||
|
};
|
||||||
|
|
||||||
function asString(value: unknown): string | undefined {
|
function asString(value: unknown): string | undefined {
|
||||||
if (value === undefined || value === null || value === "") return undefined;
|
if (value === undefined || value === null || value === "") return undefined;
|
||||||
if (value instanceof Date) {
|
if (value instanceof Date) {
|
||||||
@@ -42,6 +57,30 @@ function formatBirthDate(value: unknown): string | undefined {
|
|||||||
return raw;
|
return raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (Number.isNaN(date.getTime())) return asString(value);
|
||||||
|
const [d, t] = toJalaliDateAndTime(date);
|
||||||
|
return `${d} ${t}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function firstDefined(...values: unknown[]): string | undefined {
|
||||||
|
for (const value of values) {
|
||||||
|
const str = asString(value);
|
||||||
|
if (str) return str;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeListValue(value: unknown): string | undefined {
|
||||||
|
if (!Array.isArray(value) || !value.length) return undefined;
|
||||||
|
const items = value
|
||||||
|
.map((item) => asString(item) ?? JSON.stringify(item))
|
||||||
|
.filter(Boolean);
|
||||||
|
return items.length ? items.join("، ") : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
function flattenObject(
|
function flattenObject(
|
||||||
obj: unknown,
|
obj: unknown,
|
||||||
prefix = "",
|
prefix = "",
|
||||||
@@ -53,13 +92,10 @@ function flattenObject(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(obj)) {
|
if (Array.isArray(obj)) {
|
||||||
if (!obj.length) return [];
|
const value = normalizeListValue(obj);
|
||||||
return [
|
return value
|
||||||
{
|
? [{ label: persianFieldPath(prefix || "items"), value }]
|
||||||
label: persianFieldPath(prefix || "items"),
|
: [];
|
||||||
value: obj.map((item) => asString(item) ?? JSON.stringify(item)).join("، "),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof obj !== "object") {
|
if (typeof obj !== "object") {
|
||||||
@@ -70,6 +106,7 @@ function flattenObject(
|
|||||||
const objRecord = obj as Record<string, unknown>;
|
const objRecord = obj as Record<string, unknown>;
|
||||||
const hasMapped =
|
const hasMapped =
|
||||||
objRecord.mapped != null && typeof objRecord.mapped === "object";
|
objRecord.mapped != null && typeof objRecord.mapped === "object";
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(objRecord)) {
|
for (const [key, value] of Object.entries(objRecord)) {
|
||||||
if (SKIP_FLATTEN_KEYS.has(key)) continue;
|
if (SKIP_FLATTEN_KEYS.has(key)) continue;
|
||||||
if (key === "raw" && hasMapped) continue;
|
if (key === "raw" && hasMapped) continue;
|
||||||
@@ -86,9 +123,49 @@ function flattenObject(
|
|||||||
rows.push({ label: persianFieldPath(path), value: asString(value) });
|
rows.push({ label: persianFieldPath(path), value: asString(value) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function dedupeFields(fields: InsurerFileReportField[]): InsurerFileReportField[] {
|
||||||
|
const seen = new Set<string>();
|
||||||
|
const out: InsurerFileReportField[] = [];
|
||||||
|
|
||||||
|
for (const field of fields) {
|
||||||
|
const value = asString(field.value);
|
||||||
|
if (!value) continue;
|
||||||
|
const key = `${field.label}::${value}`;
|
||||||
|
if (seen.has(key)) continue;
|
||||||
|
seen.add(key);
|
||||||
|
out.push({ label: field.label, value });
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterEmptySections(
|
||||||
|
sections: Array<InsurerFileReportSection | undefined>,
|
||||||
|
): InsurerFileReportSection[] {
|
||||||
|
return sections.filter(
|
||||||
|
(section): section is InsurerFileReportSection => !!section && section.fields.length > 0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildSection(
|
||||||
|
title: string,
|
||||||
|
fields: InsurerFileReportField[],
|
||||||
|
withPlaceholder = true,
|
||||||
|
): InsurerFileReportSection {
|
||||||
|
const deduped = dedupeFields(fields);
|
||||||
|
return {
|
||||||
|
title,
|
||||||
|
fields:
|
||||||
|
deduped.length || !withPlaceholder
|
||||||
|
? deduped
|
||||||
|
: [{ label: PR.data, value: PR.empty }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function expertNameFromSnapshot(snapshot?: {
|
function expertNameFromSnapshot(snapshot?: {
|
||||||
firstName?: string;
|
firstName?: string;
|
||||||
lastName?: string;
|
lastName?: string;
|
||||||
@@ -146,7 +223,6 @@ function inquiryRoleData(
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Prefer mapped Tejarat fields; avoid duplicating the entire raw blob in PDF. */
|
|
||||||
function pickInquiryReportPayload(
|
function pickInquiryReportPayload(
|
||||||
inquiry?: Record<string, unknown>,
|
inquiry?: Record<string, unknown>,
|
||||||
): Record<string, unknown> | undefined {
|
): Record<string, unknown> | undefined {
|
||||||
@@ -159,184 +235,420 @@ function pickInquiryReportPayload(
|
|||||||
return Object.keys(rest).length ? rest : inquiry;
|
return Object.keys(rest).length ? rest : inquiry;
|
||||||
}
|
}
|
||||||
|
|
||||||
function licenseFieldsFromInquiry(
|
function resolveReportBlameContext(
|
||||||
inquiry?: Record<string, unknown>,
|
blame?: Record<string, unknown> | null,
|
||||||
): { licenseType?: string; licenseDate?: string } {
|
claim?: Record<string, unknown> | null,
|
||||||
if (!inquiry) return {};
|
): Record<string, unknown> | null {
|
||||||
const candidates = [
|
if (blame) return blame;
|
||||||
inquiry.LicenseType,
|
const snapshot = claim?.snapshot as Record<string, unknown> | undefined;
|
||||||
inquiry.licenseType,
|
if (!snapshot) return null;
|
||||||
inquiry.Type,
|
|
||||||
inquiry.type,
|
|
||||||
inquiry.LicenseCategory,
|
|
||||||
inquiry.licenseCategory,
|
|
||||||
];
|
|
||||||
const licenseType = candidates.find((v) => v != null && v !== "");
|
|
||||||
const dateCandidates = [
|
|
||||||
inquiry.IssueDate,
|
|
||||||
inquiry.issueDate,
|
|
||||||
inquiry.LicenseIssueDate,
|
|
||||||
inquiry.licenseIssueDate,
|
|
||||||
inquiry.ExpireDate,
|
|
||||||
inquiry.expireDate,
|
|
||||||
];
|
|
||||||
const licenseDate = dateCandidates.find((v) => v != null && v !== "");
|
|
||||||
return {
|
return {
|
||||||
licenseType: asString(licenseType),
|
type:
|
||||||
licenseDate: asString(licenseDate),
|
(claim?.blameFileContext as Record<string, unknown> | undefined)
|
||||||
|
?.blameRequestType ??
|
||||||
|
(snapshot.accident as Record<string, unknown> | undefined)?.type,
|
||||||
|
blameStatus: (claim?.blameFileContext as Record<string, unknown> | undefined)
|
||||||
|
?.blameStatus,
|
||||||
|
parties: snapshot.parties,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPartyRole(party: ReportParty | null | undefined): string | undefined {
|
||||||
|
const role = party?.role;
|
||||||
|
return typeof role === "string" ? role : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sameParty(
|
||||||
|
first: ReportParty | null | undefined,
|
||||||
|
second: ReportParty | null | undefined,
|
||||||
|
): boolean {
|
||||||
|
if (!first || !second) return false;
|
||||||
|
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;
|
||||||
|
return getPartyRole(first) === getPartyRole(second);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveEvaluationReply(
|
||||||
|
claim?: Record<string, unknown> | null,
|
||||||
|
): Record<string, unknown> | undefined {
|
||||||
|
const evaluation = claim?.evaluation as Record<string, unknown> | undefined;
|
||||||
|
return (
|
||||||
|
(evaluation?.damageExpertReplyFinal as Record<string, unknown> | undefined) ??
|
||||||
|
(evaluation?.damageExpertReply as Record<string, unknown> | undefined)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function insuranceValueFromCandidates(
|
||||||
|
...values: unknown[]
|
||||||
|
): string | undefined {
|
||||||
|
for (const value of values) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
const listValue = normalizeListValue(value);
|
||||||
|
if (listValue) return listValue;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const str = asString(value);
|
||||||
|
if (str) return str;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildThirdPartyInsuranceFields(
|
||||||
|
party: ReportParty | null | undefined,
|
||||||
|
blame?: Record<string, unknown> | null,
|
||||||
|
claim?: Record<string, unknown> | null,
|
||||||
|
): InsurerFileReportField[] {
|
||||||
|
const role = getPartyRole(party);
|
||||||
|
const direct = (party?.insurance ?? {}) as Record<string, unknown>;
|
||||||
|
const blameInquiry = pickInquiryReportPayload(
|
||||||
|
inquiryRoleData(blame?.inquiries as Record<string, unknown> | undefined, "thirdParty", role),
|
||||||
|
);
|
||||||
|
const claimInquiry = pickInquiryReportPayload(
|
||||||
|
inquiryRoleData(claim?.inquiries as Record<string, unknown> | undefined, "thirdParty", role),
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: PR.policyNumber,
|
||||||
|
value: insuranceValueFromCandidates(
|
||||||
|
direct.policyNumber,
|
||||||
|
blameInquiry?.policyNumber,
|
||||||
|
blameInquiry?.PolicyNumber,
|
||||||
|
claimInquiry?.policyNumber,
|
||||||
|
claimInquiry?.PolicyNumber,
|
||||||
|
blameInquiry?.ThirdPolicyCode,
|
||||||
|
claimInquiry?.ThirdPolicyCode,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.insuranceCompany,
|
||||||
|
value: insuranceValueFromCandidates(
|
||||||
|
direct.company,
|
||||||
|
direct.insurerCompany,
|
||||||
|
blameInquiry?.company,
|
||||||
|
blameInquiry?.CompanyName,
|
||||||
|
claimInquiry?.company,
|
||||||
|
claimInquiry?.CompanyName,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.policyStartDate,
|
||||||
|
value: insuranceValueFromCandidates(
|
||||||
|
direct.startDate,
|
||||||
|
blameInquiry?.startDate,
|
||||||
|
blameInquiry?.PolicyStartDate,
|
||||||
|
blameInquiry?.SatrtDate,
|
||||||
|
claimInquiry?.startDate,
|
||||||
|
claimInquiry?.PolicyStartDate,
|
||||||
|
claimInquiry?.SatrtDate,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.policyEndDate,
|
||||||
|
value: insuranceValueFromCandidates(
|
||||||
|
direct.endDate,
|
||||||
|
blameInquiry?.endDate,
|
||||||
|
blameInquiry?.PolicyEndDate,
|
||||||
|
blameInquiry?.EndDate,
|
||||||
|
claimInquiry?.endDate,
|
||||||
|
claimInquiry?.PolicyEndDate,
|
||||||
|
claimInquiry?.EndDate,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.financialCeiling,
|
||||||
|
value: insuranceValueFromCandidates(
|
||||||
|
direct.financialCeiling,
|
||||||
|
blameInquiry?.financialCeiling,
|
||||||
|
blameInquiry?.FinancialCvrCptl,
|
||||||
|
blameInquiry?.FnCvrCptl,
|
||||||
|
claimInquiry?.financialCeiling,
|
||||||
|
claimInquiry?.FinancialCvrCptl,
|
||||||
|
claimInquiry?.FnCvrCptl,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.coverages,
|
||||||
|
value: insuranceValueFromCandidates(
|
||||||
|
direct.coverages,
|
||||||
|
blameInquiry?.coverages,
|
||||||
|
claimInquiry?.coverages,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCarBodyInsuranceFields(
|
||||||
|
party: ReportParty | null | undefined,
|
||||||
|
blame?: Record<string, unknown> | null,
|
||||||
|
claim?: Record<string, unknown> | null,
|
||||||
|
): InsurerFileReportField[] {
|
||||||
|
const role = getPartyRole(party);
|
||||||
|
const direct = (party?.insurance?.carBodyInsurance ??
|
||||||
|
party?.insurance?.carBody ??
|
||||||
|
{}) as Record<string, unknown>;
|
||||||
|
const blameInquiry = pickInquiryReportPayload(
|
||||||
|
inquiryRoleData(blame?.inquiries as Record<string, unknown> | undefined, "carBody", role),
|
||||||
|
);
|
||||||
|
const claimInquiry = pickInquiryReportPayload(
|
||||||
|
inquiryRoleData(claim?.inquiries as Record<string, unknown> | undefined, "carBody", role),
|
||||||
|
);
|
||||||
|
const legacy = (blame?.carBodyInsuranceDetail ?? {}) as Record<string, unknown>;
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: PR.policyNumber,
|
||||||
|
value: insuranceValueFromCandidates(
|
||||||
|
direct.policyNumber,
|
||||||
|
legacy.policyNumber,
|
||||||
|
blameInquiry?.policyNumber,
|
||||||
|
blameInquiry?.PolicyNumber,
|
||||||
|
claimInquiry?.policyNumber,
|
||||||
|
claimInquiry?.PolicyNumber,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.insuranceCompany,
|
||||||
|
value: insuranceValueFromCandidates(
|
||||||
|
direct.insurerCompany,
|
||||||
|
direct.company,
|
||||||
|
legacy.insurerCompany,
|
||||||
|
blameInquiry?.company,
|
||||||
|
blameInquiry?.CompanyName,
|
||||||
|
claimInquiry?.company,
|
||||||
|
claimInquiry?.CompanyName,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.policyStartDate,
|
||||||
|
value: insuranceValueFromCandidates(
|
||||||
|
direct.startDate,
|
||||||
|
legacy.startDate,
|
||||||
|
blameInquiry?.startDate,
|
||||||
|
blameInquiry?.PolicyStartDate,
|
||||||
|
claimInquiry?.startDate,
|
||||||
|
claimInquiry?.PolicyStartDate,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.policyEndDate,
|
||||||
|
value: insuranceValueFromCandidates(
|
||||||
|
direct.endDate,
|
||||||
|
legacy.endDate,
|
||||||
|
blameInquiry?.endDate,
|
||||||
|
blameInquiry?.PolicyEndDate,
|
||||||
|
claimInquiry?.endDate,
|
||||||
|
claimInquiry?.PolicyEndDate,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.coverages,
|
||||||
|
value: insuranceValueFromCandidates(
|
||||||
|
direct.coverages,
|
||||||
|
legacy.coverages,
|
||||||
|
blameInquiry?.coverages,
|
||||||
|
claimInquiry?.coverages,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
function buildOwnerSection(
|
function buildOwnerSection(
|
||||||
damagedParty: ReturnType<typeof resolveDamagedPartyRow>,
|
damagedParty: ReportParty | null,
|
||||||
claim?: Record<string, unknown> | null,
|
claim?: Record<string, unknown> | null,
|
||||||
): InsurerFileReportSection {
|
): InsurerFileReportSection {
|
||||||
const person = damagedParty?.person;
|
const person = damagedParty?.person as ReportRecord | undefined;
|
||||||
const money = claim?.money as
|
const money = claim?.money as
|
||||||
| { sheba?: string; nationalCodeOfInsurer?: string }
|
| { sheba?: string; nationalCodeOfInsurer?: string }
|
||||||
| undefined;
|
| undefined;
|
||||||
const claimOwner = claim?.owner as { fullName?: string } | undefined;
|
const claimOwner = claim?.owner as { fullName?: string } | undefined;
|
||||||
|
|
||||||
return {
|
return buildSection(PR.ownerSection, [
|
||||||
title: PR.ownerSection,
|
{ label: PR.name, value: firstDefined(person?.fullName, claimOwner?.fullName) },
|
||||||
fields: [
|
{ label: PR.phone, value: asString(person?.phoneNumber) },
|
||||||
{ label: PR.name, value: person?.fullName ?? claimOwner?.fullName },
|
|
||||||
{ label: PR.phone, value: person?.phoneNumber },
|
|
||||||
{
|
{
|
||||||
label: PR.nationalCode,
|
label: PR.nationalCode,
|
||||||
value: person?.nationalCodeOfInsurer ?? money?.nationalCodeOfInsurer,
|
value: firstDefined(person?.nationalCodeOfInsurer, money?.nationalCodeOfInsurer),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: PR.birthDate,
|
label: PR.birthDate,
|
||||||
value: formatBirthDate(person?.insurerBirthday ?? person?.birthday),
|
value: formatBirthDate(person?.insurerBirthday ?? person?.birthday),
|
||||||
},
|
},
|
||||||
{ label: PR.sheba, value: money?.sheba },
|
{ label: PR.sheba, value: money?.sheba },
|
||||||
],
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function licenseFieldsFromInquiry(
|
||||||
|
inquiry?: Record<string, unknown>,
|
||||||
|
): { licenseType?: string; licenseDate?: string } {
|
||||||
|
if (!inquiry) return {};
|
||||||
|
return {
|
||||||
|
licenseType: firstDefined(
|
||||||
|
inquiry.LicenseType,
|
||||||
|
inquiry.licenseType,
|
||||||
|
inquiry.Type,
|
||||||
|
inquiry.type,
|
||||||
|
inquiry.LicenseCategory,
|
||||||
|
inquiry.licenseCategory,
|
||||||
|
),
|
||||||
|
licenseDate: firstDefined(
|
||||||
|
inquiry.IssueDate,
|
||||||
|
inquiry.issueDate,
|
||||||
|
inquiry.LicenseIssueDate,
|
||||||
|
inquiry.licenseIssueDate,
|
||||||
|
inquiry.ExpireDate,
|
||||||
|
inquiry.expireDate,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildDriverSection(
|
function buildDriverSection(
|
||||||
damagedParty: ReturnType<typeof resolveDamagedPartyRow>,
|
damagedParty: ReportParty | null,
|
||||||
blame?: Record<string, unknown> | null,
|
blame?: Record<string, unknown> | null,
|
||||||
): InsurerFileReportSection | undefined {
|
): InsurerFileReportSection | undefined {
|
||||||
const person = damagedParty?.person;
|
const person = damagedParty?.person as ReportRecord | undefined;
|
||||||
if (!person || person.driverIsInsurer !== false) return undefined;
|
if (!person || person.driverIsInsurer !== false) return undefined;
|
||||||
|
|
||||||
const role = damagedParty?.role ?? PartyRole.FIRST;
|
const role = damagedParty?.role ?? PartyRole.FIRST;
|
||||||
const licenseInquiry = inquiryRoleData(
|
const licenseInquiry = inquiryRoleData(
|
||||||
blame?.inquiries as Record<string, unknown> | undefined,
|
blame?.inquiries as Record<string, unknown> | undefined,
|
||||||
"drivingLicence",
|
"drivingLicence",
|
||||||
role,
|
String(role),
|
||||||
);
|
);
|
||||||
const { licenseType, licenseDate } = licenseFieldsFromInquiry(licenseInquiry);
|
const { licenseType, licenseDate } = licenseFieldsFromInquiry(licenseInquiry);
|
||||||
|
|
||||||
return {
|
return buildSection(PR.driverSection, [
|
||||||
title: PR.driverSection,
|
{ label: PR.name, value: asString(person.fullName) },
|
||||||
fields: [
|
|
||||||
{ label: PR.name, value: person.fullName },
|
|
||||||
{
|
{
|
||||||
label: PR.licenseType,
|
label: PR.licenseType,
|
||||||
value: licenseType ?? (person.driverLicense ? PR.driverLicense : undefined),
|
value: licenseType ?? (person.driverLicense ? PR.driverLicense : undefined),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: PR.licenseDate,
|
label: PR.licenseDate,
|
||||||
value: licenseDate ?? person.driverLicense,
|
value: licenseDate ?? asString(person.driverLicense),
|
||||||
},
|
},
|
||||||
{ label: PR.phone, value: person.phoneNumber },
|
{ label: PR.phone, value: asString(person.phoneNumber) },
|
||||||
{ label: PR.nationalCode, value: person.nationalCodeOfDriver },
|
{ label: PR.nationalCode, value: asString(person.nationalCodeOfDriver) },
|
||||||
{ label: PR.birthDate, value: formatBirthDate(person.driverBirthday) },
|
{ label: PR.birthDate, value: formatBirthDate(person.driverBirthday) },
|
||||||
{ label: PR.licenseNumber, value: person.driverLicense },
|
{ label: PR.licenseNumber, value: asString(person.driverLicense) },
|
||||||
],
|
]);
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildInsuranceSection(
|
|
||||||
damagedParty: ReturnType<typeof resolveDamagedPartyRow>,
|
|
||||||
blame?: Record<string, unknown> | null,
|
|
||||||
claim?: Record<string, unknown> | null,
|
|
||||||
): InsurerFileReportSection {
|
|
||||||
const role = damagedParty?.role ?? PartyRole.FIRST;
|
|
||||||
const insurance = damagedParty?.insurance ?? {};
|
|
||||||
const carBodyLegacy = blame?.carBodyInsuranceDetail as
|
|
||||||
| Record<string, unknown>
|
|
||||||
| undefined;
|
|
||||||
|
|
||||||
const thirdPartyInquiry = inquiryRoleData(
|
|
||||||
blame?.inquiries as Record<string, unknown> | undefined,
|
|
||||||
"thirdParty",
|
|
||||||
role,
|
|
||||||
);
|
|
||||||
const carBodyInquiry = inquiryRoleData(
|
|
||||||
blame?.inquiries as Record<string, unknown> | undefined,
|
|
||||||
"carBody",
|
|
||||||
role,
|
|
||||||
);
|
|
||||||
const claimThirdParty = inquiryRoleData(
|
|
||||||
claim?.inquiries as Record<string, unknown> | undefined,
|
|
||||||
"thirdParty",
|
|
||||||
role,
|
|
||||||
);
|
|
||||||
const claimCarBody = inquiryRoleData(
|
|
||||||
claim?.inquiries as Record<string, unknown> | undefined,
|
|
||||||
"carBody",
|
|
||||||
role,
|
|
||||||
);
|
|
||||||
|
|
||||||
const fields: InsurerFileReportField[] = [
|
|
||||||
...flattenObject(insurance, "party.insurance"),
|
|
||||||
...flattenObject(
|
|
||||||
(insurance as { carBodyInsurance?: unknown }).carBodyInsurance,
|
|
||||||
"party.insurance.carBodyInsurance",
|
|
||||||
),
|
|
||||||
...flattenObject(
|
|
||||||
pickInquiryReportPayload(thirdPartyInquiry),
|
|
||||||
"inquiry.thirdParty",
|
|
||||||
),
|
|
||||||
...flattenObject(pickInquiryReportPayload(carBodyInquiry), "inquiry.carBody"),
|
|
||||||
...flattenObject(
|
|
||||||
pickInquiryReportPayload(claimThirdParty),
|
|
||||||
"claim.inquiry.thirdParty",
|
|
||||||
),
|
|
||||||
...flattenObject(
|
|
||||||
pickInquiryReportPayload(claimCarBody),
|
|
||||||
"claim.inquiry.carBody",
|
|
||||||
),
|
|
||||||
...flattenObject(carBodyLegacy, "blame.carBodyInsuranceDetail"),
|
|
||||||
];
|
|
||||||
|
|
||||||
const deduped = dedupeFields(fields);
|
|
||||||
return {
|
|
||||||
title: PR.insuranceSection,
|
|
||||||
fields: deduped.length ? deduped : [{ label: PR.data, value: PR.empty }],
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildVehicleSection(
|
function buildVehicleSection(
|
||||||
damagedParty: ReturnType<typeof resolveDamagedPartyRow>,
|
damagedParty: ReportParty | null,
|
||||||
claim?: Record<string, unknown> | null,
|
claim?: Record<string, unknown> | null,
|
||||||
): InsurerFileReportSection {
|
): InsurerFileReportSection {
|
||||||
const partyVehicle = damagedParty?.vehicle;
|
const partyVehicle = damagedParty?.vehicle;
|
||||||
const claimVehicle = claim?.vehicle as Record<string, unknown> | undefined;
|
const claimVehicle = claim?.vehicle as Record<string, unknown> | undefined;
|
||||||
|
|
||||||
const fields = dedupeFields([
|
return buildSection(PR.vehicleSection, [
|
||||||
...flattenObject(claimVehicle, "claim.vehicle"),
|
...flattenObject(claimVehicle, "claim.vehicle"),
|
||||||
...flattenObject(partyVehicle, "party.vehicle"),
|
...flattenObject(partyVehicle, "party.vehicle"),
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
function buildCaseTimelineSection(
|
||||||
title: PR.vehicleSection,
|
overview?: Record<string, unknown> | null,
|
||||||
fields: fields.length ? fields : [{ label: PR.data, value: PR.empty }],
|
claim?: Record<string, unknown> | null,
|
||||||
};
|
): InsurerFileReportSection {
|
||||||
|
const evaluationReply = resolveEvaluationReply(claim);
|
||||||
|
return buildSection(PR.timelineSection, [
|
||||||
|
{
|
||||||
|
label: PR.fileRegisteredAt,
|
||||||
|
value: formatDateTime(overview?.createdAt),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.evaluationRegisteredAt,
|
||||||
|
value: formatDateTime(evaluationReply?.submittedAt),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildFanavaranCodesSection(
|
||||||
|
claim?: Record<string, unknown> | null,
|
||||||
|
): InsurerFileReportSection | undefined {
|
||||||
|
if (!claim) return undefined;
|
||||||
|
const sync = (claim.fanavaranSync as Record<string, unknown> | undefined) ?? {};
|
||||||
|
const baseClaim = (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, [
|
||||||
|
{
|
||||||
|
label: PR.fanavaranClaimNo,
|
||||||
|
value: firstDefined(claim.claimNo, baseClaim.claimNo),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.fanavaranClaimId,
|
||||||
|
value: firstDefined(claim.claimId, baseClaim.claimId),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.fanavaranDamageCaseId,
|
||||||
|
value: firstDefined(claim.dmgCaseId, damageCase.dmgCaseId, expertise.dmgCaseId),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.fanavaranExpertiseId,
|
||||||
|
value: firstDefined(claim.expertiseId, expertise.expertiseId),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.fanavaranPolicyId,
|
||||||
|
value: firstDefined(baseClaim.policyId),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.fanavaranDriverId,
|
||||||
|
value: firstDefined(baseClaim.driverId),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.fanavaranVehicleKindId,
|
||||||
|
value: firstDefined(baseClaim.vehicleKindId),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.fanavaranInsuranceCorpId,
|
||||||
|
value: firstDefined(baseClaim.insuranceCorpId),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildEvaluationSection(
|
||||||
|
claim?: Record<string, unknown> | null,
|
||||||
|
): InsurerFileReportSection | undefined {
|
||||||
|
if (!claim) return undefined;
|
||||||
|
const reply = resolveEvaluationReply(claim);
|
||||||
|
const actorDetail = reply?.actorDetail as { actorName?: string } | undefined;
|
||||||
|
const snapshotName = expertNameFromSnapshot(
|
||||||
|
reply?.expertProfileSnapshot as
|
||||||
|
| { firstName?: string; lastName?: string }
|
||||||
|
| undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
return buildSection(PR.evaluationSection, [
|
||||||
|
{
|
||||||
|
label: PR.evaluationResult,
|
||||||
|
value: persianStatus(claim.claimStatus),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.evaluationExpert,
|
||||||
|
value: actorDetail?.actorName ?? snapshotName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.evaluationSubmittedAt,
|
||||||
|
value: formatDateTime(reply?.submittedAt),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: PR.evaluationResponse,
|
||||||
|
value: asString(reply?.description),
|
||||||
|
},
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildAccidentReportSection(
|
function buildAccidentReportSection(
|
||||||
blame?: Record<string, unknown> | null,
|
blame?: Record<string, unknown> | null,
|
||||||
claim?: Record<string, unknown> | null,
|
claim?: Record<string, unknown> | null,
|
||||||
damagedParty?: ReturnType<typeof resolveDamagedPartyRow>,
|
damagedParty?: ReportParty | null,
|
||||||
): InsurerFileReportSection {
|
): InsurerFileReportSection {
|
||||||
const statement = damagedParty?.statement as
|
const statement = damagedParty?.statement as ReportRecord | undefined;
|
||||||
| Record<string, unknown>
|
|
||||||
| undefined;
|
|
||||||
const location = damagedParty?.location;
|
const location = damagedParty?.location;
|
||||||
const snapshotAccident = (
|
const snapshotAccident = (
|
||||||
claim?.snapshot as { accident?: Record<string, unknown> } | undefined
|
claim?.snapshot as { accident?: Record<string, unknown> } | undefined
|
||||||
@@ -344,22 +656,21 @@ function buildAccidentReportSection(
|
|||||||
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;
|
|
||||||
|
|
||||||
const accidentDate =
|
return buildSection(PR.accidentSection, [
|
||||||
|
{
|
||||||
|
label: PR.accidentDate,
|
||||||
|
value:
|
||||||
asString(statement?.accidentDate) ??
|
asString(statement?.accidentDate) ??
|
||||||
asString(snapshotAccident?.date) ??
|
asString(snapshotAccident?.date) ??
|
||||||
asString(blame?.createdAtFormatted) ??
|
asString(blame?.createdAtFormatted) ??
|
||||||
asString(blame?.createdAt);
|
formatDateTime(blame?.createdAt),
|
||||||
|
},
|
||||||
const accidentTime =
|
{
|
||||||
asString(statement?.accidentTime) ?? asString(snapshotAccident?.time);
|
label: PR.accidentTime,
|
||||||
|
value: asString(statement?.accidentTime) ?? asString(snapshotAccident?.time),
|
||||||
const fields: InsurerFileReportField[] = [
|
},
|
||||||
{ label: PR.date, value: accidentDate },
|
|
||||||
{ label: PR.time, value: accidentTime },
|
|
||||||
{
|
{
|
||||||
label: PR.experts,
|
label: PR.experts,
|
||||||
value: collectExpertNames(blame, claim),
|
value: collectExpertNames(blame, claim),
|
||||||
@@ -412,8 +723,7 @@ function buildAccidentReportSection(
|
|||||||
{
|
{
|
||||||
label: PR.accidentReason,
|
label: PR.accidentReason,
|
||||||
value: asString(
|
value: asString(
|
||||||
(decisionFields?.accidentReason as { label?: string } | undefined)
|
(decisionFields?.accidentReason as { label?: string } | undefined)?.label ??
|
||||||
?.label ??
|
|
||||||
(
|
(
|
||||||
snapshotAccident?.classification as {
|
snapshotAccident?.classification as {
|
||||||
accidentReason?: { label?: string };
|
accidentReason?: { label?: string };
|
||||||
@@ -432,82 +742,61 @@ function buildAccidentReportSection(
|
|||||||
)?.accidentType?.label,
|
)?.accidentType?.label,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: PR.damageExpertDate,
|
|
||||||
value: asString(
|
|
||||||
(
|
|
||||||
(claim?.evaluation as Record<string, unknown> | undefined)
|
|
||||||
?.damageExpertReplyFinal as Record<string, unknown> | undefined
|
|
||||||
)?.submittedAt ??
|
|
||||||
(
|
|
||||||
(claim?.evaluation as Record<string, unknown> | undefined)
|
|
||||||
?.damageExpertReply as Record<string, unknown> | undefined
|
|
||||||
)?.submittedAt,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: PR.damageExpertNotes,
|
|
||||||
value: asString(
|
|
||||||
(
|
|
||||||
(claim?.evaluation as Record<string, unknown> | undefined)
|
|
||||||
?.damageExpertReplyFinal as Record<string, unknown> | undefined
|
|
||||||
)?.description ??
|
|
||||||
(
|
|
||||||
(claim?.evaluation as Record<string, unknown> | undefined)
|
|
||||||
?.damageExpertReply as Record<string, unknown> | undefined
|
|
||||||
)?.description,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: PR.partyDescription,
|
label: PR.partyDescription,
|
||||||
value: asString(statement?.description),
|
value: asString(statement?.description),
|
||||||
},
|
},
|
||||||
];
|
]);
|
||||||
|
|
||||||
return {
|
|
||||||
title: PR.accidentSection,
|
|
||||||
fields: dedupeFields(fields),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function dedupeFields(fields: InsurerFileReportField[]): InsurerFileReportField[] {
|
export function buildInsurerFileReport(file: {
|
||||||
const seen = new Set<string>();
|
|
||||||
const out: InsurerFileReportField[] = [];
|
|
||||||
for (const field of fields) {
|
|
||||||
const value = asString(field.value);
|
|
||||||
if (!value) continue;
|
|
||||||
const key = `${field.label}::${value}`;
|
|
||||||
if (seen.has(key)) continue;
|
|
||||||
seen.add(key);
|
|
||||||
out.push({ label: field.label, value });
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildInsurerFileReport(
|
|
||||||
file: {
|
|
||||||
overview?: Record<string, unknown>;
|
overview?: Record<string, unknown>;
|
||||||
blame?: Record<string, unknown>;
|
blame?: Record<string, unknown>;
|
||||||
claim?: Record<string, unknown>;
|
claim?: Record<string, unknown>;
|
||||||
},
|
}): InsurerFileReportViewModel {
|
||||||
): InsurerFileReportViewModel {
|
|
||||||
const overview = file.overview ?? {};
|
const overview = file.overview ?? {};
|
||||||
const blame = file.blame ?? null;
|
|
||||||
const claim = file.claim ?? null;
|
const claim = file.claim ?? null;
|
||||||
const damagedParty = blame ? resolveDamagedPartyRow(blame) : null;
|
const blame = file.blame ?? null;
|
||||||
|
const blameContext = resolveReportBlameContext(blame, claim);
|
||||||
|
const damagedParty = blameContext
|
||||||
|
? (resolveDamagedPartyRow(blameContext as any) as ReportParty | null)
|
||||||
|
: null;
|
||||||
|
const guiltyParty = blameContext
|
||||||
|
? (resolveClaimOwnerParty(blameContext as any) as ReportParty | null)
|
||||||
|
: null;
|
||||||
|
const isCarBody =
|
||||||
|
String((blameContext?.type as string | undefined) ?? "") === "CAR_BODY";
|
||||||
|
const includeGuiltySections = !!guiltyParty && !(isCarBody && sameParty(damagedParty, guiltyParty));
|
||||||
|
|
||||||
const sections: InsurerFileReportSection[] = [
|
const sections = filterEmptySections([
|
||||||
|
buildCaseTimelineSection(overview, claim),
|
||||||
buildOwnerSection(damagedParty, claim),
|
buildOwnerSection(damagedParty, claim),
|
||||||
];
|
buildDriverSection(damagedParty, blameContext),
|
||||||
|
buildSection(
|
||||||
const driverSection = buildDriverSection(damagedParty, blame);
|
PR.damagedThirdPartyInsuranceSection,
|
||||||
if (driverSection) sections.push(driverSection);
|
buildThirdPartyInsuranceFields(damagedParty, blameContext, claim),
|
||||||
|
),
|
||||||
sections.push(
|
buildSection(
|
||||||
buildInsuranceSection(damagedParty, blame, claim),
|
PR.damagedCarBodyInsuranceSection,
|
||||||
|
buildCarBodyInsuranceFields(damagedParty, blameContext, claim),
|
||||||
|
),
|
||||||
|
includeGuiltySections
|
||||||
|
? buildSection(
|
||||||
|
PR.guiltyThirdPartyInsuranceSection,
|
||||||
|
buildThirdPartyInsuranceFields(guiltyParty, blameContext, claim),
|
||||||
|
)
|
||||||
|
: undefined,
|
||||||
|
includeGuiltySections
|
||||||
|
? buildSection(
|
||||||
|
PR.guiltyCarBodyInsuranceSection,
|
||||||
|
buildCarBodyInsuranceFields(guiltyParty, blameContext, claim),
|
||||||
|
)
|
||||||
|
: undefined,
|
||||||
buildVehicleSection(damagedParty, claim),
|
buildVehicleSection(damagedParty, claim),
|
||||||
buildAccidentReportSection(blame, claim, damagedParty),
|
buildFanavaranCodesSection(claim),
|
||||||
);
|
buildEvaluationSection(claim),
|
||||||
|
buildAccidentReportSection(blameContext, claim, damagedParty),
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: PR.reportTitle,
|
title: PR.reportTitle,
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export class CaseExpertReportInsurerController {
|
|||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
summary: "Get insurer file report data",
|
summary: "Get insurer file report data",
|
||||||
description:
|
description:
|
||||||
"Returns the structured report data for the given publicId (blame + claim combined): damaged owner, driver when different, insurance, vehicle, and accident report sections. The front-end uses this data to render and generate the PDF.",
|
"Returns structured insurer PDF data for the given publicId (blame + claim combined), including separated guilty/damaged insurance blocks, third-party/body policy details, Fanavaran codes, case/evaluation timestamps, and the evaluation result with expert response.",
|
||||||
})
|
})
|
||||||
@ApiParam({ name: "publicId" })
|
@ApiParam({ name: "publicId" })
|
||||||
@ApiResponse({ status: 200, description: "Report data" })
|
@ApiResponse({ status: 200, description: "Report data" })
|
||||||
|
|||||||
@@ -5,8 +5,14 @@ export const PR = {
|
|||||||
empty: "-",
|
empty: "-",
|
||||||
ownerSection: "مالک خودروی زیان دیده",
|
ownerSection: "مالک خودروی زیان دیده",
|
||||||
driverSection: "راننده خودروی زیان دیده",
|
driverSection: "راننده خودروی زیان دیده",
|
||||||
insuranceSection: "اطلاعات بیمه (بدنه و شخص ثالث)",
|
damagedThirdPartyInsuranceSection: "بیمه شخص ثالث زیاندیده",
|
||||||
|
damagedCarBodyInsuranceSection: "بیمه بدنه زیاندیده",
|
||||||
|
guiltyThirdPartyInsuranceSection: "بیمه شخص ثالث مقصر",
|
||||||
|
guiltyCarBodyInsuranceSection: "بیمه بدنه مقصر",
|
||||||
vehicleSection: "اطلاعات خودرو",
|
vehicleSection: "اطلاعات خودرو",
|
||||||
|
timelineSection: "زمانبندی پرونده",
|
||||||
|
fanavaranSection: "کدهای فناوران",
|
||||||
|
evaluationSection: "نتیجه ارزیابی",
|
||||||
accidentSection: "گزارش حادثه",
|
accidentSection: "گزارش حادثه",
|
||||||
name: "نام",
|
name: "نام",
|
||||||
phone: "شماره تلفن",
|
phone: "شماره تلفن",
|
||||||
@@ -17,9 +23,31 @@ export const PR = {
|
|||||||
licenseDate: "تاریخ گواهینامه",
|
licenseDate: "تاریخ گواهینامه",
|
||||||
licenseNumber: "شماره گواهینامه",
|
licenseNumber: "شماره گواهینامه",
|
||||||
driverLicense: "گواهینامه راننده",
|
driverLicense: "گواهینامه راننده",
|
||||||
|
insuranceCompany: "شرکت بیمه",
|
||||||
|
policyNumber: "شماره بیمهنامه",
|
||||||
|
policyStartDate: "تاریخ شروع بیمهنامه",
|
||||||
|
policyEndDate: "تاریخ پایان بیمهنامه",
|
||||||
|
financialCeiling: "سقف تعهد مالی",
|
||||||
|
coverages: "پوششها",
|
||||||
|
fileRegisteredAt: "تاریخ و ساعت ثبت پرونده",
|
||||||
|
evaluationRegisteredAt: "تاریخ و ساعت ثبت نتیجه ارزیابی",
|
||||||
|
fanavaranClaimNo: "شماره پرونده فناوران",
|
||||||
|
fanavaranClaimId: "کد پرونده فناوران",
|
||||||
|
fanavaranDamageCaseId: "کد کیس خسارت فناوران",
|
||||||
|
fanavaranExpertiseId: "کد کارشناسی فناوران",
|
||||||
|
fanavaranPolicyId: "کد بیمهنامه فناوران",
|
||||||
|
fanavaranDriverId: "کد راننده فناوران",
|
||||||
|
fanavaranVehicleKindId: "کد نوع خودرو فناوران",
|
||||||
|
fanavaranInsuranceCorpId: "کد شرکت بیمه فناوران",
|
||||||
|
evaluationResult: "نتیجه ارزیابی",
|
||||||
|
evaluationExpert: "کارشناس ارزیاب",
|
||||||
|
evaluationSubmittedAt: "تاریخ و ساعت ثبت ارزیابی",
|
||||||
|
evaluationResponse: "پاسخ / توضیحات کارشناس",
|
||||||
data: "اطلاعات",
|
data: "اطلاعات",
|
||||||
date: "تاریخ",
|
date: "تاریخ",
|
||||||
time: "زمان",
|
time: "زمان",
|
||||||
|
accidentDate: "تاریخ حادثه",
|
||||||
|
accidentTime: "ساعت حادثه",
|
||||||
experts: "کارشناس(ان)",
|
experts: "کارشناس(ان)",
|
||||||
location: "موقعیت (عرض و طول جغرافیایی)",
|
location: "موقعیت (عرض و طول جغرافیایی)",
|
||||||
weather: "وضعیت آب و هوا",
|
weather: "وضعیت آب و هوا",
|
||||||
|
|||||||
Reference in New Issue
Block a user