forked from Yara724/api
Fixed damagedParts unified structure and resend problems
This commit is contained in:
@@ -62,7 +62,9 @@ export function findCatalogItemByPersianLabel(
|
||||
|
||||
/** Non-catalog lines (expert-added interior / free-text); never use catalog numeric ids. */
|
||||
export function isInternalDamageSide(side: string): boolean {
|
||||
const s = String(side ?? "").trim().toLowerCase();
|
||||
const s = String(side ?? "")
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
if (!s || s === "internal" || s === "other") return true;
|
||||
return !SIDE_SET.has(s);
|
||||
}
|
||||
@@ -120,7 +122,9 @@ const SIDE_LABEL_FA: Record<string, string> = {
|
||||
[OuterPartSideV2.TOP]: "بالا",
|
||||
};
|
||||
|
||||
function outerCatalogListForItem(item: OuterPartCatalogItem): OuterPartCatalogItem[] {
|
||||
function outerCatalogListForItem(
|
||||
item: OuterPartCatalogItem,
|
||||
): OuterPartCatalogItem[] {
|
||||
for (const list of Object.values(OUTER_PARTS_BY_CAR_TYPE)) {
|
||||
if (list.some((x) => x.key === item.key || x.id === item.id)) {
|
||||
return list;
|
||||
@@ -165,9 +169,10 @@ function findCatalogItemByKey(key: string): OuterPartCatalogItem | undefined {
|
||||
}
|
||||
|
||||
/** Strip leading `left_|right_|…` when present so `name` is side-agnostic for clients. */
|
||||
export function splitCatalogKeyToNameAndSide(
|
||||
fullKey: string,
|
||||
): { name: string; side: string } {
|
||||
export function splitCatalogKeyToNameAndSide(fullKey: string): {
|
||||
name: string;
|
||||
side: string;
|
||||
} {
|
||||
const t = String(fullKey ?? "").trim();
|
||||
const i = t.indexOf("_");
|
||||
if (i <= 0) return { name: t, side: "" };
|
||||
@@ -329,7 +334,8 @@ export function normalizeDamageSelectedParts(
|
||||
let catItem: OuterPartCatalogItem | undefined;
|
||||
if (catalog && byCatalogKey) {
|
||||
if (ck) catItem = byCatalogKey.get(ck);
|
||||
if (!catItem && id != null) catItem = catalog.find((c) => c.id === id);
|
||||
if (!catItem && id != null)
|
||||
catItem = catalog.find((c) => c.id === id);
|
||||
if (!catItem && side && name) {
|
||||
catItem = byCatalogKey.get(catalogLikeKeyFromPart({ side, name }));
|
||||
}
|
||||
@@ -377,7 +383,9 @@ export function normalizeDamageSelectedParts(
|
||||
const cat =
|
||||
byCatalogKey?.get(k) ??
|
||||
findCatalogItemByKey(k) ??
|
||||
(toNum(o.id) != null ? CATALOG_ITEM_BY_ID.get(toNum(o.id)!) : undefined);
|
||||
(toNum(o.id) != null
|
||||
? CATALOG_ITEM_BY_ID.get(toNum(o.id)!)
|
||||
: undefined);
|
||||
if (cat) {
|
||||
const list = catalog ?? outerCatalogListForItem(cat);
|
||||
out.push(catalogItemToSelectedPart(cat, list));
|
||||
@@ -581,7 +589,9 @@ export function catalogPartIdFromCarPartDamage(
|
||||
export const partIdentityKeyFromCarPartDamage = catalogPartIdFromCarPartDamage;
|
||||
|
||||
function normPartSegment(s: string): string {
|
||||
return String(s ?? "").replace(/[^a-z0-9]/gi, "").toLowerCase();
|
||||
return String(s ?? "")
|
||||
.replace(/[^a-z0-9]/gi, "")
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
function looseCatalogNameMatch(
|
||||
@@ -601,9 +611,13 @@ export function findCatalogItemFromLegacyExpertPart(
|
||||
side: string,
|
||||
carType?: ClaimVehicleTypeV2,
|
||||
): OuterPartCatalogItem | undefined {
|
||||
const s = String(side ?? "").toLowerCase().trim();
|
||||
const s = String(side ?? "")
|
||||
.toLowerCase()
|
||||
.trim();
|
||||
const lists = carType
|
||||
? [OUTER_PARTS_BY_CAR_TYPE[carType]].filter(Boolean) as OuterPartCatalogItem[][]
|
||||
? ([OUTER_PARTS_BY_CAR_TYPE[carType]].filter(
|
||||
Boolean,
|
||||
) as OuterPartCatalogItem[][])
|
||||
: (Object.values(OUTER_PARTS_BY_CAR_TYPE) as OuterPartCatalogItem[][]);
|
||||
for (const catalog of lists) {
|
||||
if (!catalog?.length) continue;
|
||||
@@ -615,7 +629,9 @@ export function findCatalogItemFromLegacyExpertPart(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function selectedPartToStoredRecord(p: DamageSelectedPartV2): Record<string, unknown> {
|
||||
function selectedPartToStoredRecord(
|
||||
p: DamageSelectedPartV2,
|
||||
): Record<string, unknown> {
|
||||
const r: Record<string, unknown> = {
|
||||
name: p.name,
|
||||
side: String(p.side || "").toLowerCase(),
|
||||
@@ -780,9 +796,7 @@ export function isDamagedPartsMediaArray(data: unknown): boolean {
|
||||
return Array.isArray(data);
|
||||
}
|
||||
|
||||
function getLegacyMapRecord(
|
||||
data: unknown,
|
||||
): Record<string, unknown> | null {
|
||||
function getLegacyMapRecord(data: unknown): Record<string, unknown> | null {
|
||||
if (data == null) return null;
|
||||
if (data instanceof Map) {
|
||||
return Object.fromEntries((data as Map<string, unknown>).entries());
|
||||
@@ -819,11 +833,9 @@ export function migrateLegacyDamagedPartsMapToArray(
|
||||
selected: DamageSelectedPartV2[],
|
||||
): Record<string, unknown>[] {
|
||||
return selected.map((sp) => {
|
||||
const keysTry = [
|
||||
sp.catalogKey,
|
||||
catalogLikeKeyFromPart(sp),
|
||||
sp.name,
|
||||
].filter(Boolean) as string[];
|
||||
const keysTry = [sp.catalogKey, catalogLikeKeyFromPart(sp), sp.name].filter(
|
||||
Boolean,
|
||||
) as string[];
|
||||
let blob: unknown;
|
||||
for (const k of keysTry) {
|
||||
blob = getCaptureBlobLoose(legacyMap, k);
|
||||
@@ -887,12 +899,14 @@ export function resolvePartCaptureIndex(
|
||||
if (!raw) return -1;
|
||||
|
||||
if (selected.length) {
|
||||
// Pass 1: exact matches on catalogKey and catalogLikeKey
|
||||
for (let i = 0; i < selected.length; i++) {
|
||||
const sp = selected[i];
|
||||
if (sp.catalogKey === raw) return i;
|
||||
if (catalogLikeKeyFromPart(sp) === raw) return i;
|
||||
}
|
||||
|
||||
// Pass 2: numeric id or array index
|
||||
if (/^\d+$/.test(raw)) {
|
||||
const n = Number(raw);
|
||||
const byId = selected.findIndex((p) => p.id === n);
|
||||
@@ -901,31 +915,35 @@ export function resolvePartCaptureIndex(
|
||||
if (!hasIdCollision && n >= 0 && n < selected.length) return n;
|
||||
}
|
||||
|
||||
// Pass 3: loose normalized match (handles spaces, underscores, case)
|
||||
const loose = raw.toLowerCase().replace(/[\s_-]/g, "");
|
||||
for (let i = 0; i < selected.length; i++) {
|
||||
const sp = selected[i];
|
||||
const cand = [
|
||||
const candidates = [
|
||||
sp.catalogKey,
|
||||
catalogLikeKeyFromPart(sp),
|
||||
sp.name,
|
||||
].filter(Boolean) as string[];
|
||||
for (const c of cand) {
|
||||
for (const c of candidates) {
|
||||
if (c.toLowerCase().replace(/[\s_-]/g, "") === loose) return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (damagedPartsArray && damagedPartsArray.length) {
|
||||
for (let i = 0; i < damagedPartsArray.length; i++) {
|
||||
const row = damagedPartsArray[i];
|
||||
if (!row || typeof row !== "object") continue;
|
||||
const id = toNum((row as { id?: unknown }).id);
|
||||
if (id != null && String(id) === raw) return i;
|
||||
const ck = String((row as { catalogKey?: unknown }).catalogKey || "");
|
||||
if (ck && ck === raw) return i;
|
||||
const name = String((row as { name?: unknown }).name || "");
|
||||
const side = String((row as { side?: unknown }).side || "");
|
||||
if (side && name && `${side}_${name}` === raw) return i;
|
||||
// Pass 4: suffix match — handles car-type-prefixed catalog keys
|
||||
// e.g. "sedan_front_hood" should match sp.catalogKey="front_hood"
|
||||
// or normalizeResendPartKeys output "sedan_front_hood" vs stored "front_hood"
|
||||
for (let i = 0; i < selected.length; i++) {
|
||||
const sp = selected[i];
|
||||
const candidates = [
|
||||
sp.catalogKey,
|
||||
catalogLikeKeyFromPart(sp),
|
||||
sp.name,
|
||||
].filter(Boolean) as string[];
|
||||
for (const c of candidates) {
|
||||
const cLoose = c.toLowerCase().replace(/[\s_-]/g, "");
|
||||
// raw ends with the candidate (prefix stripped)
|
||||
if (loose.endsWith(cLoose) || cLoose.endsWith(loose)) return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -939,7 +957,11 @@ export function mediaRowOrLegacyHasCapture(
|
||||
): boolean {
|
||||
if (damagedPartsData == null) return false;
|
||||
if (Array.isArray(damagedPartsData)) {
|
||||
const idx = resolvePartCaptureIndex(partKey, selected, damagedPartsData as any[]);
|
||||
const idx = resolvePartCaptureIndex(
|
||||
partKey,
|
||||
selected,
|
||||
damagedPartsData as any[],
|
||||
);
|
||||
if (idx < 0) return false;
|
||||
return mediaRowHasCapture((damagedPartsData as unknown[])[idx]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user