fix(pl24): Volvo vin-image-board BOM parts + decode subgroup name entities
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled

Volvo's vin-image-board.action ships its BOM inline as partno= tc-data-row
rows (no pncHierCode / json-vin-bom-detail), so the Ford VIN-BOM parser
returned 0 parts. Fall back to parsePsaBomParts (partno= rows) when no pnc
rows are found. Also decode HTML entities (Ö " …) in scraped Volvo
subgroup names. Completes the Volvo chain: group1→group2→illustration→parts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-02 02:30:54 +03:00
parent c46695d320
commit 00f7edbc15

View File

@@ -159,6 +159,17 @@ export class PL24FordLegacyService {
const name = m[2]
.replace(/<[^>]+>/g, " ")
.replace(/&nbsp;/g, " ")
.replace(/&Ouml;/g, "Ö")
.replace(/&ouml;/g, "ö")
.replace(/&Auml;/g, "Ä")
.replace(/&auml;/g, "ä")
.replace(/&Uuml;/g, "Ü")
.replace(/&uuml;/g, "ü")
.replace(/&szlig;/g, "ß")
.replace(/&quot;/g, '"')
.replace(/&#39;/g, "'")
.replace(/&amp;/g, "&")
.replace(/&#(\d+);/g, (_, n) => String.fromCharCode(Number(n)))
.replace(/\s+/g, " ")
.trim()
.replace(/^\d+\s+/, "");
@@ -355,11 +366,18 @@ export class PL24FordLegacyService {
let parts: PL24Part[];
const isVinImageBoard = linkPath.includes("vin-image-board.action");
if (isVinImageBoard) {
// Ford/Volvo VIN flow: rows have pncHierCode + jsonUrl pointing to
// Ford VIN flow: rows have pncHierCode + jsonUrl pointing to
// json-vin-bom-detail.action. Each detail JSON can return MULTIPLE
// valid partno entries (e.g. left/right variant) — keep all of them.
const pncRows = this.parseFordVinPncRows(html);
parts = await this.fetchFordVinBomParts(pncRows, serviceName);
if (pncRows.length > 0) {
parts = await this.fetchFordVinBomParts(pncRows, serviceName);
} else {
// Volvo vin-image-board ships its BOM inline as partno= tc-data-row
// rows (no pncHierCode / json-vin-bom-detail secondary fetch), same
// shape the PSA parser handles.
parts = this.parsePsaBomParts(html);
}
} else if (isImageBoard) {
// Try Hyundai/Kia/Nissan format: pnc= rows with json-bom-detail.action
const pncRows = this.parseHyundaiPncRows(html);