YARA-1258

This commit is contained in:
SepehrYahyaee
2026-09-12 14:23:23 +03:30
parent 9e51fdcdaf
commit 7fd60df1d6
5 changed files with 300 additions and 21 deletions

View File

@@ -9,7 +9,12 @@ import {
InsurerFileReportSection,
InsurerFileReportViewModel,
} from "./case-expert-report.types";
import { PR, persianFieldPath, persianStatus } from "./persian-report-labels";
import {
PR,
persianAccidentCondition,
persianFieldPath,
persianStatus,
} from "./persian-report-labels";
const SKIP_FLATTEN_KEYS = new Set([
"_id",
@@ -65,6 +70,32 @@ function formatDateTime(value: unknown): string | undefined {
return `${d} ${t}`;
}
const PERSIAN_NUMBER_FORMATTER = new Intl.NumberFormat("fa-IR", {
maximumFractionDigits: 0,
});
function normalizeNumber(value: unknown): number | undefined {
if (typeof value === "number") {
return Number.isFinite(value) ? value : undefined;
}
if (typeof value !== "string" || !value.trim()) return undefined;
const normalized = value
.trim()
.replace(/[۰-۹]/g, (digit) => String("۰۱۲۳۴۵۶۷۸۹".indexOf(digit)))
.replace(/[٠-٩]/g, (digit) => String("٠١٢٣٤٥٦٧٨٩".indexOf(digit)))
.replace(/[٬,\s]/g, "");
const parsed = Number(normalized);
return Number.isFinite(parsed) ? parsed : undefined;
}
function formatToman(value: unknown): string | undefined {
if (value === undefined || value === null || value === "") return undefined;
const amount = normalizeNumber(value);
if (amount === undefined) return asString(value);
return `${PERSIAN_NUMBER_FORMATTER.format(amount)} تومان`;
}
function firstDefined(...values: unknown[]): string | undefined {
for (const value of values) {
const str = asString(value);
@@ -302,6 +333,23 @@ function resolveEvaluationReply(
);
}
function resolveEvaluationSubmittedAt(
claim: Record<string, unknown> | null | undefined,
reply: Record<string, unknown> | undefined,
): unknown {
if (reply?.submittedAt != null) return reply.submittedAt;
const history = Array.isArray(claim?.history) ? claim.history : [];
const submittedEvent = [...history]
.reverse()
.find((event) =>
["EXPERT_REPLY_SUBMITTED", "EXPERT_FINAL_REPLY_SUBMITTED"].includes(
String((event as Record<string, unknown>)?.type ?? ""),
),
) as Record<string, unknown> | undefined;
return submittedEvent?.timestamp;
}
function insuranceValueFromCandidates(
...values: unknown[]
): string | undefined {
@@ -650,7 +698,7 @@ function buildCaseTimelineSection(
},
{
label: PR.evaluationRegisteredAt,
value: formatDateTime(evaluationReply?.submittedAt),
value: formatDateTime(resolveEvaluationSubmittedAt(claim, evaluationReply)),
},
]);
}
@@ -723,7 +771,7 @@ function buildEvaluationSection(
},
{
label: PR.evaluationSubmittedAt,
value: formatDateTime(reply?.submittedAt),
value: formatDateTime(resolveEvaluationSubmittedAt(claim, reply)),
},
{
label: PR.evaluationResponse,
@@ -732,6 +780,66 @@ function buildEvaluationSection(
]);
}
function evaluationPartName(part: ReportRecord): string | undefined {
const damage = part.carPartDamage;
if (damage && typeof damage === "object" && !Array.isArray(damage)) {
const record = damage as ReportRecord;
return firstDefined(
record.label_fa,
record.name,
record.part,
record.label,
part.partId != null ? `${PR.part} ${part.partId}` : undefined,
);
}
return firstDefined(
damage,
part.partName,
part.partId != null ? `${PR.part} ${part.partId}` : undefined,
);
}
function evaluationDaghiValue(value: unknown): string | undefined {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return asString(value);
}
const daghi = value as ReportRecord;
const option = asString(daghi.option);
const price = formatToman(daghi.price);
return [option, price].filter(Boolean).join(" - ") || undefined;
}
function buildEvaluationPartsSection(
claim?: Record<string, unknown> | null,
): InsurerFileReportSection | undefined {
const reply = resolveEvaluationReply(claim);
const parts = Array.isArray(reply?.parts)
? (reply.parts as ReportRecord[])
: [];
if (!parts.length) return undefined;
const fields = parts.flatMap((part, index) => {
const prefix = `${PR.part} ${PERSIAN_NUMBER_FORMATTER.format(index + 1)}`;
return [
{ label: `${prefix} / ${PR.partName}`, value: evaluationPartName(part) },
{ label: `${prefix} / ${PR.damageType}`, value: asString(part.typeOfDamage) },
{ label: `${prefix} / ${PR.partPrice}`, value: formatToman(part.price) },
{ label: `${prefix} / ${PR.repairSalary}`, value: formatToman(part.salary) },
{ label: `${prefix} / ${PR.totalPayment}`, value: formatToman(part.totalPayment) },
{
label: `${prefix} / ${PR.factorNeeded}`,
value:
typeof part.factorNeeded === "boolean"
? persianStatus(part.factorNeeded)
: undefined,
},
{ label: `${prefix} / ${PR.daghi}`, value: evaluationDaghiValue(part.daghi) },
];
});
return buildSection(PR.evaluationPartsSection, fields, false);
}
function buildAccidentReportSection(
blame?: Record<string, unknown> | null,
claim?: Record<string, unknown> | null,
@@ -773,21 +881,24 @@ function buildAccidentReportSection(
},
{
label: PR.weather,
value:
asString(statement?.weatherCondition) ??
asString(snapshotAccident?.weatherCondition),
value: persianAccidentCondition(
"weather",
statement?.weatherCondition ?? snapshotAccident?.weatherCondition,
),
},
{
label: PR.road,
value:
asString(statement?.roadCondition) ??
asString(snapshotAccident?.roadCondition),
value: persianAccidentCondition(
"road",
statement?.roadCondition ?? snapshotAccident?.roadCondition,
),
},
{
label: PR.light,
value:
asString(statement?.lightCondition) ??
asString(snapshotAccident?.lightCondition),
value: persianAccidentCondition(
"light",
statement?.lightCondition ?? snapshotAccident?.lightCondition,
),
},
{
label: PR.blameStatus,
@@ -910,6 +1021,7 @@ export function buildInsurerFileReport(file: {
: undefined,
buildFanavaranCodesSection(claim),
buildEvaluationSection(claim),
buildEvaluationPartsSection(claim),
buildAccidentReportSection(blameContext, claim, damagedParty),
]);