fix(pl24): Volvo subgroup drilling via vin-group.action HTML
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled

Volvo's VIN catalog is a 3-level vin-group.action?group1=…[&group2=…] HTML
tree; PL24's json-vin-*-group.action JSON endpoints now 404. Add HTML
subgroup extraction (keep links one group-level deeper than the current
path) in ford-legacy fetchSubGroupsByPath, and route vin-group.action?group1=
nodes through getChildren (drill-first, fall back to parts) in
getCategoryWithParts. Recovers Volvo group1→group2 navigation. Leaf parts
handled separately.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-02 02:08:12 +03:00
parent 316a5e014c
commit d792bf0efb
2 changed files with 80 additions and 3 deletions

View File

@@ -895,6 +895,34 @@ export class CategoriesService {
: { ...base, loadError: true };
}
// Volvo VIN-indexed catalog: vin-group.action?group1=…[&group2=…] nodes are
// parents whose subgroups live in the same HTML (PL24's old JSON
// json-vin-main-group.action path now 404s). They carry no link_wid, so the
// group-node branch above misses them. Drill: if subgroups come back it's a
// parent; if none, fall through to the leaf parts path (the deepest group
// level carries an image-board + parts).
if (
category.source === "pl24" &&
category.linkPath?.includes("vin-group.action") &&
category.linkPath?.includes("group1=") &&
category.vehicleId
) {
const volvoChildren = await this.getChildren(categoryId);
if (volvoChildren.length > 0) {
return {
id: category.id,
name: category.name,
description: category.nameOriginal || null,
parentId: category.parentId || null,
parts: [],
schemaPics: [],
hotspots: [],
children: volvoChildren,
};
}
// No subgroups → leaf; fall through to the parts path below.
}
// Leaf category — get or fetch parts
let loadError = false;
let discoveredChildren: any[] = [];
@@ -996,7 +1024,11 @@ export class CategoriesService {
}));
if (allParts.length > 0) {
dbParts = await this.db.insert(parts).values(allParts).returning();
dbParts = await this.db
.insert(parts)
.values(allParts)
.onConflictDoNothing()
.returning();
this.logger.log(
`Stored ${dbParts.length} PartsCatalogs parts for category ${categoryId}`,
);
@@ -1146,7 +1178,11 @@ export class CategoriesService {
};
});
dbParts = await this.db.insert(parts).values(insertData).returning();
dbParts = await this.db
.insert(parts)
.values(insertData)
.onConflictDoNothing()
.returning();
this.logger.log(`Stored ${dbParts.length} EMEX parts for category ${categoryId}`);
}
@@ -1242,7 +1278,11 @@ export class CategoriesService {
source: "pl24" as const,
}));
dbParts = await this.db.insert(parts).values(insertData).returning();
dbParts = await this.db
.insert(parts)
.values(insertData)
.onConflictDoNothing()
.returning();
}
// Store schema image if available