forked from Yara724/api
Merge pull request 'main' (#321) from s.hajizadeh/yara724api:main into main
Reviewed-on: Yara724/api#321
This commit is contained in:
@@ -49,6 +49,12 @@ import {
|
||||
pickStoredCarBodyPolicyId,
|
||||
type FanavaranClaimProduct,
|
||||
} from "./fanavaran-claim-product";
|
||||
import {
|
||||
hullExpertiseAssertFields,
|
||||
pickHullVehicleIdentity,
|
||||
toFanavaranHullExpertiseDmgSection,
|
||||
toFanavaranHullExpertisePayload,
|
||||
} from "./fanavaran-hull-expertise";
|
||||
import { BlameRequestDbService } from "src/request-management/entities/db-service/blame-request.db.service";
|
||||
import { CreateClaimFromBlameResponseDto } from "./dto/create-claim-v2.dto";
|
||||
import {
|
||||
@@ -6722,6 +6728,41 @@ export class ClaimRequestManagementService {
|
||||
input.claimCase?._id ? String(input.claimCase._id) : undefined,
|
||||
);
|
||||
|
||||
if (product === "car-body") {
|
||||
const blame = input.claimCase?.blameRequestId
|
||||
? await this.blameRequestDbService.findById(
|
||||
String(input.claimCase.blameRequestId),
|
||||
)
|
||||
: null;
|
||||
const hullSections = parts.map((part: any) =>
|
||||
toFanavaranHullExpertiseDmgSection({
|
||||
partId: part?.partId,
|
||||
desc: this.fanavaranPartLabel(part),
|
||||
wasteValue: this.fanavaranDaghiWasteValue(part?.daghi),
|
||||
amount:
|
||||
this.parseFanavaranMoney(part?.price) +
|
||||
this.parseFanavaranMoney(part?.salary),
|
||||
}),
|
||||
);
|
||||
return {
|
||||
replyKey: active?.replyKey,
|
||||
warnings,
|
||||
payload: toFanavaranHullExpertisePayload({
|
||||
claimExpertId,
|
||||
dmgAssessmentDate: this.convertToPersianDate(submittedAt),
|
||||
inspectionTime: this.getTime24Hour(submittedAt),
|
||||
wage: repairWage,
|
||||
componentReplacementCost,
|
||||
wasteValue,
|
||||
dropAmount: priceDropTotal || 0,
|
||||
vehicleCurrentValue:
|
||||
this.parseFanavaranMoney(priceDrop?.carPrice) || null,
|
||||
vehicle: pickHullVehicleIdentity(blame),
|
||||
dmgSections: hullSections,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
const payload: Record<string, unknown> = {
|
||||
ClaimExpertId: claimExpertId,
|
||||
ComponentReplacementCost: componentReplacementCost,
|
||||
@@ -6738,9 +6779,7 @@ export class ClaimRequestManagementService {
|
||||
this.parseFanavaranMoney(priceDrop?.carPrice) || null,
|
||||
DmgSections: dmgSections,
|
||||
};
|
||||
if (fanavaranHasDamageCaseStage(product)) {
|
||||
payload.DmgCaseId = input.claimCase.dmgCaseId ?? null;
|
||||
}
|
||||
payload.DmgCaseId = input.claimCase.dmgCaseId ?? null;
|
||||
|
||||
return {
|
||||
replyKey: active?.replyKey,
|
||||
@@ -6752,13 +6791,19 @@ export class ClaimRequestManagementService {
|
||||
private assertFanavaranExpertisePayloadReady(
|
||||
payload: Record<string, unknown>,
|
||||
warnings: string[],
|
||||
options?: { requireDmgCaseId?: boolean },
|
||||
options?: { requireDmgCaseId?: boolean; requireThirdPartyLookups?: boolean },
|
||||
): void {
|
||||
const sections = Array.isArray(payload.DmgSections)
|
||||
? payload.DmgSections
|
||||
: [];
|
||||
if (options?.requireDmgCaseId !== false && !payload.DmgCaseId)
|
||||
warnings.push("DmgCaseId is required.");
|
||||
if (options?.requireThirdPartyLookups !== false) {
|
||||
if (!payload.InspectionPlaceId)
|
||||
warnings.push("InspectionPlaceId is required.");
|
||||
if (!payload.DropAmountStatus)
|
||||
warnings.push("DropAmountStatus is required.");
|
||||
}
|
||||
if (!payload.InspectionPlaceId)
|
||||
warnings.push("InspectionPlaceId is required.");
|
||||
if (!payload.DropAmountStatus)
|
||||
@@ -6839,7 +6884,7 @@ export class ClaimRequestManagementService {
|
||||
FANAVARAN_EXPERTISE_MANUAL_OVERRIDE_KEYS,
|
||||
);
|
||||
this.assertFanavaranExpertisePayloadReady(payload, built.warnings, {
|
||||
requireDmgCaseId: fanavaranHasDamageCaseStage(product),
|
||||
...hullExpertiseAssertFields(product),
|
||||
});
|
||||
return await this.executeFanavaranExpertiseSubmit(
|
||||
claimCaseId,
|
||||
@@ -7035,7 +7080,7 @@ export class ClaimRequestManagementService {
|
||||
clientKey,
|
||||
});
|
||||
this.assertFanavaranExpertisePayloadReady(payload, warnings, {
|
||||
requireDmgCaseId: fanavaranHasDamageCaseStage(product),
|
||||
...hullExpertiseAssertFields(product),
|
||||
});
|
||||
|
||||
const fanavaranResponse = await this.executeFanavaranExpertiseSubmit(
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
fanavaranClaimsBaseUrl,
|
||||
fanavaranClaimStageUrl,
|
||||
fanavaranHasDamageCaseStage,
|
||||
fanavaranHullImportClaimsUrl,
|
||||
fanavaranPartyInquirySources,
|
||||
isFanavaranSubmitSupportedBlameType,
|
||||
pickCarBodyPolicyNationalCode,
|
||||
@@ -39,8 +40,15 @@ describe("fanavaran claim product", () => {
|
||||
expect(fanavaranClaimStageUrl("car-body", "expertise", 5023617)).toBe(
|
||||
"https://apimanager.iraneit.com/BimeApiManager/api/BimeApi/v2.0/car/vehicle-hull-claims/5023617/expertise",
|
||||
);
|
||||
expect(fanavaranClaimStageUrl("third-party", "damage-case", 1)).toBe(
|
||||
"https://apimanager.iraneit.com/BimeApiManager/api/BimeApi/v2.0/car/third-party-car-financial-claims/1/dmg-cases",
|
||||
expect(fanavaranClaimStageUrl("car-body", "culprits", 5023617)).toBe(
|
||||
"https://apimanager.iraneit.com/BimeApiManager/api/BimeApi/v2.0/car/vehicle-hull-claims/5023617/culprits",
|
||||
);
|
||||
expect(fanavaranClaimStageUrl("third-party", "culprits", 1)).toBeNull();
|
||||
expect(fanavaranHullImportClaimsUrl()).toBe(
|
||||
"https://apimanager.iraneit.com/BimeApiManager/api/BimeApi/v2.0/car/vehicle-hull-import-claims",
|
||||
);
|
||||
expect(fanavaranClaimsBaseUrl("car-body")).not.toContain(
|
||||
"vehicle-hull-import-claims",
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -46,18 +46,28 @@ export function fanavaranClaimsBaseUrl(
|
||||
return `${FANAVARAN_CLAIMS_HOST}/${fanavaranClaimsResourcePath(product)}`;
|
||||
}
|
||||
|
||||
export type FanavaranClaimStage = "damage-case" | "attachments" | "expertise";
|
||||
export type FanavaranClaimStage =
|
||||
| "damage-case"
|
||||
| "attachments"
|
||||
| "expertise"
|
||||
| "culprits";
|
||||
|
||||
/** Hull (بدنه) has no GEN.12 dmg-cases resource. Proven 2026-09-15: Feature:url(.../vehicle-hull-claims/{id}/dmg-cases) not found. Files and expertise do exist. */
|
||||
export const FANAVARAN_HULL_NO_DAMAGE_CASE_REASON =
|
||||
"Fanavaran vehicle-hull-claims has no dmg-cases resource. Hull is first-party (one damaged vehicle on the base claim). Continue with files and expertise.";
|
||||
|
||||
export const FANAVARAN_HULL_IMPORT_CLAIMS_PATH = "vehicle-hull-import-claims";
|
||||
|
||||
export function fanavaranHasDamageCaseStage(
|
||||
product: FanavaranClaimProduct,
|
||||
): boolean {
|
||||
return product === "third-party";
|
||||
}
|
||||
|
||||
export function fanavaranHullImportClaimsUrl(): string {
|
||||
return `${FANAVARAN_CLAIMS_HOST}/${FANAVARAN_HULL_IMPORT_CLAIMS_PATH}`;
|
||||
}
|
||||
|
||||
export function fanavaranClaimStageUrl(
|
||||
product: FanavaranClaimProduct,
|
||||
stage: FanavaranClaimStage,
|
||||
@@ -66,12 +76,17 @@ export function fanavaranClaimStageUrl(
|
||||
if (stage === "damage-case" && !fanavaranHasDamageCaseStage(product)) {
|
||||
return null;
|
||||
}
|
||||
if (stage === "culprits" && product !== "car-body") {
|
||||
return null;
|
||||
}
|
||||
const suffix =
|
||||
stage === "damage-case"
|
||||
? "dmg-cases"
|
||||
: stage === "attachments"
|
||||
? "files"
|
||||
: "expertise";
|
||||
: stage === "culprits"
|
||||
? "culprits"
|
||||
: "expertise";
|
||||
return `${fanavaranClaimsBaseUrl(product)}/${claimId}/${suffix}`;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
import { PartyRole } from "src/request-management/entities/schema/partyRole.enum";
|
||||
import {
|
||||
pickHullVehicleIdentity,
|
||||
toFanavaranHullExpertiseDmgSection,
|
||||
toFanavaranHullExpertisePayload,
|
||||
} from "./fanavaran-hull-expertise";
|
||||
|
||||
describe("fanavaran hull expertise", () => {
|
||||
it("maps car-body inquiry identity onto GEN.06 vehicle fields", () => {
|
||||
const vehicle = pickHullVehicleIdentity({
|
||||
parties: [
|
||||
{
|
||||
role: PartyRole.FIRST,
|
||||
insurance: {
|
||||
carBodyInsurance: {
|
||||
chassisNumber: "NAS431100K1050805",
|
||||
motorNumber: "M136251767",
|
||||
vin: "VIN123",
|
||||
},
|
||||
},
|
||||
vehicle: {
|
||||
inquiry: {
|
||||
carBody: {
|
||||
mapped: {
|
||||
platePartOne: "29",
|
||||
plateLetterTitle: "د",
|
||||
platePartThree: "782",
|
||||
plateSerialNumber: "60",
|
||||
builtYear: 1398,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(vehicle).toEqual({
|
||||
motorNo: "M136251767",
|
||||
chassisNo: "NAS431100K1050805",
|
||||
vin: "VIN123",
|
||||
plaqueNo: "29د782",
|
||||
plaqueSerial: "60",
|
||||
builtYear: 1398,
|
||||
});
|
||||
});
|
||||
|
||||
it("builds a GEN.06 payload without ثالث expertise fields", () => {
|
||||
const payload = toFanavaranHullExpertisePayload({
|
||||
claimExpertId: 29,
|
||||
dmgAssessmentDate: "1405/06/24",
|
||||
inspectionTime: "10:33",
|
||||
wage: 1000,
|
||||
componentReplacementCost: 2000,
|
||||
wasteValue: 0,
|
||||
dropAmount: 12,
|
||||
vehicleCurrentValue: 1900000000,
|
||||
vehicle: {
|
||||
motorNo: "M1",
|
||||
chassisNo: "C1",
|
||||
vin: null,
|
||||
plaqueNo: "695ط61",
|
||||
plaqueSerial: "87",
|
||||
builtYear: 1398,
|
||||
},
|
||||
dmgSections: [
|
||||
toFanavaranHullExpertiseDmgSection({
|
||||
partId: 9,
|
||||
desc: "bumper",
|
||||
wasteValue: 0,
|
||||
amount: 3000,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
expect(payload.Wage).toBe(1000);
|
||||
expect(payload.RepairWage).toBeUndefined();
|
||||
expect(payload.DmgCaseId).toBeUndefined();
|
||||
expect(payload.InspectionPlaceId).toBeUndefined();
|
||||
expect(payload.DropAmountStatus).toBeUndefined();
|
||||
expect(payload.DamagedVehicleCurrentPrice).toBeUndefined();
|
||||
expect(payload.ClaimExpertId).toBe(29);
|
||||
expect(payload.PlaqueNo).toBe("695ط61");
|
||||
expect(payload.DmgSections).toEqual([
|
||||
{
|
||||
Count: 1,
|
||||
Desc: "bumper",
|
||||
WasteValue: 0,
|
||||
AccessoryKindId: 9,
|
||||
DmgKindId: null,
|
||||
VehicleHullAccessoryId: null,
|
||||
DmgSectionCosts: [
|
||||
{ Caption: "bumper", Amount: 3000, DmgCostKindId: null },
|
||||
],
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
124
src/claim-request-management/fanavaran-hull-expertise.ts
Normal file
124
src/claim-request-management/fanavaran-hull-expertise.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import { parseFanavaranId } from "src/lookups/fanavaran-last-car-policy";
|
||||
import {
|
||||
fanavaranPartyInquirySources,
|
||||
type FanavaranClaimProduct,
|
||||
} from "./fanavaran-claim-product";
|
||||
|
||||
export type FanavaranHullVehicleIdentity = {
|
||||
motorNo: string | null;
|
||||
chassisNo: string | null;
|
||||
vin: string | null;
|
||||
plaqueNo: string | null;
|
||||
plaqueSerial: string | null;
|
||||
builtYear: number | null;
|
||||
};
|
||||
|
||||
export function pickHullVehicleIdentity(
|
||||
blame?: { parties?: unknown[] } | null,
|
||||
): FanavaranHullVehicleIdentity {
|
||||
const party = (blame?.parties ?? [])[0] as
|
||||
| Parameters<typeof fanavaranPartyInquirySources>[1]
|
||||
| undefined;
|
||||
const first =
|
||||
(blame?.parties ?? []).find(
|
||||
(row) => (row as { role?: string })?.role === "FIRST",
|
||||
) ?? party;
|
||||
const { mapped } = fanavaranPartyInquirySources(
|
||||
"car-body",
|
||||
first as Parameters<typeof fanavaranPartyInquirySources>[1],
|
||||
);
|
||||
const left = text(mapped.plk1 ?? mapped.Plk1);
|
||||
const letter = text(mapped.plk2 ?? mapped.Plk2);
|
||||
const right = text(mapped.plk3 ?? mapped.Plk3);
|
||||
const serial = text(mapped.plksrl ?? mapped.PlkSrl);
|
||||
const plaqueNo = [left, letter, right].filter(Boolean).join("") || null;
|
||||
return {
|
||||
motorNo: text(mapped.MtrNum),
|
||||
chassisNo: text(mapped.ShsNum),
|
||||
vin: text(mapped.VIN),
|
||||
plaqueNo,
|
||||
plaqueSerial: serial,
|
||||
builtYear: parseFanavaranId(mapped.PrdDte),
|
||||
};
|
||||
}
|
||||
|
||||
function text(value: unknown): string | null {
|
||||
if (value == null) return null;
|
||||
const next = String(value).trim();
|
||||
return next ? next : null;
|
||||
}
|
||||
|
||||
export function toFanavaranHullExpertisePayload(input: {
|
||||
claimExpertId: number;
|
||||
dmgAssessmentDate: string;
|
||||
inspectionTime: string;
|
||||
wage: number;
|
||||
componentReplacementCost: number;
|
||||
wasteValue: number;
|
||||
dropAmount: number;
|
||||
vehicleCurrentValue: number | null;
|
||||
vehicle: FanavaranHullVehicleIdentity;
|
||||
dmgSections: Record<string, unknown>[];
|
||||
}): Record<string, unknown> {
|
||||
return {
|
||||
ClaimExpertId: input.claimExpertId,
|
||||
DmgAssessmentDate: input.dmgAssessmentDate,
|
||||
InspectionTime: input.inspectionTime,
|
||||
MotorNo: input.vehicle.motorNo,
|
||||
ChassisNo: input.vehicle.chassisNo,
|
||||
BuiltYear: input.vehicle.builtYear,
|
||||
VIN: input.vehicle.vin,
|
||||
PlaqueNo: input.vehicle.plaqueNo,
|
||||
PlaqueSerial: input.vehicle.plaqueSerial,
|
||||
Wage: input.wage,
|
||||
ComponentReplacementCost: input.componentReplacementCost,
|
||||
WasteValue: input.wasteValue,
|
||||
CarryAndRescueCost: null,
|
||||
RepairDuration: null,
|
||||
VehicleCurrentValue: input.vehicleCurrentValue,
|
||||
WreckHighestValue: null,
|
||||
InspectionDeduction: null,
|
||||
DmgAndWasteDesc: null,
|
||||
WentDistanceByExpert: null,
|
||||
IsDestruction: null,
|
||||
DropAmount: input.dropAmount,
|
||||
ColorId: null,
|
||||
PlaqueDesignId: null,
|
||||
PlaqueCityId: null,
|
||||
AccidentPercent: null,
|
||||
TheftCases: [],
|
||||
DmgSections: input.dmgSections,
|
||||
};
|
||||
}
|
||||
|
||||
export function toFanavaranHullExpertiseDmgSection(input: {
|
||||
partId?: unknown;
|
||||
desc: string;
|
||||
wasteValue: number;
|
||||
amount: number;
|
||||
}): Record<string, unknown> {
|
||||
return {
|
||||
Count: 1,
|
||||
Desc: input.desc,
|
||||
WasteValue: input.wasteValue,
|
||||
AccessoryKindId: parseFanavaranId(input.partId),
|
||||
DmgKindId: null,
|
||||
VehicleHullAccessoryId: null,
|
||||
DmgSectionCosts: [
|
||||
{
|
||||
Caption: input.desc,
|
||||
Amount: input.amount,
|
||||
DmgCostKindId: null,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
export function hullExpertiseAssertFields(
|
||||
product: FanavaranClaimProduct,
|
||||
): { requireDmgCaseId: boolean; requireThirdPartyLookups: boolean } {
|
||||
if (product === "car-body") {
|
||||
return { requireDmgCaseId: false, requireThirdPartyLookups: false };
|
||||
}
|
||||
return { requireDmgCaseId: true, requireThirdPartyLookups: true };
|
||||
}
|
||||
Reference in New Issue
Block a user