1
0
forked from Yara724/api
Files
yara724-api/src/expert-claim/dto/claim-damaged-part.enricher.ts
SepehrYahyaee 6426233350 Fix links
2026-06-13 17:24:25 +03:30

181 lines
5.6 KiB
TypeScript

// claim-damaged-part.enricher.ts
import { resolveStoredFileUrl } from "src/helpers/urlCreator";
import {
DamagedPartCaptureStatus,
EnrichedDamagedPart,
} from "./claim-damaged-part.types";
export function buildEnrichedDamagedParts(params: {
selectedParts: any[];
damagedPartsData: any;
evaluationBlock: any;
expertAddedParts?: any[];
getDamagedPartCaptureBlob: (data: any, key: string, parts: any[]) => any;
hasDamagedPartCapture: (data: any, key: string, parts: any[]) => boolean;
catalogLikeKeyFromPart: (part: any) => string;
buildFileLink: (path: string) => string;
resolveStoredFileUrl?: (
stored?: { url?: string; path?: string } | null,
) => string | undefined;
}): EnrichedDamagedPart[] {
const {
selectedParts,
damagedPartsData,
evaluationBlock,
expertAddedParts = [],
getDamagedPartCaptureBlob,
hasDamagedPartCapture,
catalogLikeKeyFromPart,
buildFileLink,
resolveStoredFileUrl: resolveUrl = resolveStoredFileUrl,
} = params;
const priceDropLines: any[] = evaluationBlock?.priceDrop?.partLines ?? [];
// objectionParts stores { partId, carPartDamage, side } — not { id, name }
const objectionParts: any[] =
evaluationBlock?.objection?.objectionParts ?? [];
// newParts stores { partId, partName, side } — not { id, name }
const newObjectionParts: any[] = evaluationBlock?.objection?.newParts ?? [];
const damageExpertResend = evaluationBlock?.damageExpertResend;
const resendCarParts: any[] = damageExpertResend?.resendCarParts ?? [];
const resendFulfilledAt: Date | undefined = damageExpertResend?.fulfilledAt;
// Helpers that match against the ACTUAL stored field names
function partMatchesObjection(sp: any, objPart: any): boolean {
if (sp.id != null && objPart.partId != null && sp.id === objPart.partId)
return true;
const objName = objPart.carPartDamage ?? objPart.name ?? objPart.partName;
if (objName && (sp.name === objName || sp.label_fa === objName))
return true;
return false;
}
function partMatchesNewObjection(sp: any, newPart: any): boolean {
if (sp.id != null && newPart.partId != null && sp.id === newPart.partId)
return true;
const newName = newPart.partName ?? newPart.name;
if (newName && (sp.name === newName || sp.label_fa === newName))
return true;
return false;
}
function isPartInResend(sp: any): boolean {
return resendCarParts.some(
(r: any) =>
(sp.id != null && r.id === sp.id) ||
r.catalogKey === sp.catalogKey ||
r.name === sp.name,
);
}
function resolveOrigin(sp: any): EnrichedDamagedPart["origin"] {
if (newObjectionParts.some((p) => partMatchesNewObjection(sp, p))) {
return "added_by_objection";
}
if (
expertAddedParts.some((p: any) => p.id === sp.id || p.name === sp.name)
) {
return "added_by_expert";
}
return "user_selected";
}
function resolveCaptureStatus(
sp: any,
captured: boolean,
): DamagedPartCaptureStatus {
const inResend = isPartInResend(sp);
if (!captured) {
return inResend ? "resend_requested" : "pending";
}
return inResend && resendFulfilledAt ? "resent" : "uploaded";
}
return selectedParts.map((sp, index) => {
const ck = sp.catalogKey ?? catalogLikeKeyFromPart(sp);
const cap = getDamagedPartCaptureBlob(
damagedPartsData,
ck,
selectedParts,
) as { url?: string; path?: string } | undefined;
// Fallback: if id is null but media.damagedParts has a match by name
const captured =
hasDamagedPartCapture(damagedPartsData, ck, selectedParts) ||
(sp.id == null && Array.isArray(damagedPartsData)
? (damagedPartsData as any[]).some(
(d) => d.name === sp.name && d.side === sp.side && d.path,
)
: false);
const capUrl =
resolveUrl(cap) ||
(sp.id == null && Array.isArray(damagedPartsData)
? (() => {
const match = (damagedPartsData as any[]).find(
(d) => d.name === sp.name && d.side === sp.side && d.path,
);
return resolveUrl(match);
})()
: undefined);
const matchingPriceDrop = priceDropLines.find(
(line: any) =>
line.partId === sp.id ||
line.priceDropPartKey?.toLowerCase() === sp.name?.toLowerCase(),
);
const isObjected = objectionParts.some((p) => partMatchesObjection(sp, p));
const isNewlyAdded = newObjectionParts.some((p) =>
partMatchesNewObjection(sp, p),
);
const isNewByExpert = expertAddedParts.some(
(p: any) => p.id === sp.id || p.name === sp.name,
);
const inResend = isPartInResend(sp);
return {
index,
partId: sp.id ?? null,
id: sp.id ?? null,
name: sp.name,
side: sp.side,
label_fa: sp.label_fa,
...(sp.catalogKey ? { catalogKey: sp.catalogKey } : {}),
origin: resolveOrigin(sp),
captureStatus: resolveCaptureStatus(sp, captured),
captured,
url: capUrl,
objection: {
isObjected,
isNewlyAdded,
...(isNewlyAdded ? { addedBy: isNewByExpert ? "expert" : "user" } : {}),
},
resend: {
wasRequested: inResend,
isFulfilled: inResend && !!resendFulfilledAt,
...(inResend && damageExpertResend?.requestedAt
? { requestedAt: damageExpertResend.requestedAt }
: {}),
...(inResend && resendFulfilledAt
? { fulfilledAt: resendFulfilledAt }
: {}),
},
pricing: {
hasPriceDrop: !!matchingPriceDrop,
severity: matchingPriceDrop?.severity ?? null,
coefficient: matchingPriceDrop?.coefficient ?? null,
},
};
});
}