// 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, }, }; }); }