feat(pl24): enrich P5 decode for non-VAG OEMs (SEV-2)
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
parseVehicleResponse only read VAG/BMW vinfoBasic labels, so Jaguar/Land Rover/Toyota/MAN/Suzuki dropped engine+transmission and Mitsubishi's model showed an internal chassis code. - engine/transmission: read brand labels (JLR Motor Tipi/Vites Kutusu, Toyota ENGINE 1/ATM,MTM + parens engine code, MAN Yedek motor/Şanzıman, Suzuki Motor No./Şanzıman numarası). - Mitsubishi model: prefer Araç/description (L200), not the internal Model code (KB4T 2500DIESEL...). - value normalize: unescape literal \- + collapse whitespace (was prNr-only) → fixes 'XJ 2010 \- 2019', '2005\-07', 'COROLLA (TUP)'. VAG/BMW/Mercedes/Fiat unchanged. 40/40 pl24 specs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,8 @@ const p = svc as unknown as {
|
||||
series: string | null;
|
||||
bodyType: string | null;
|
||||
engineCode: string | null;
|
||||
engineType: string | null;
|
||||
transmission: string | null;
|
||||
catalogInfo?: { mainGroupsPath?: string };
|
||||
};
|
||||
};
|
||||
@@ -178,3 +180,148 @@ describe("PL24Service.parseVehicleResponse — p5daimler (year from 'Teslimat ta
|
||||
expect(r.model).toBe("C 180 KOMPRESSOR Sedan");
|
||||
});
|
||||
});
|
||||
|
||||
// SEV-2: non-VAG P5 OEMs label engine/transmission differently and emit "\-" escapes /
|
||||
// padded model strings. The shared parser must read those labels + normalize the values.
|
||||
describe("PL24Service.parseVehicleResponse — p5jlr (Jaguar/LandRover engine+trans, \\- cleanup)", () => {
|
||||
const jlrData = {
|
||||
resultStatus: "VEHICLE_IDENTIFIED",
|
||||
description: "XJ 2010 - 2019 (X351)",
|
||||
link: {
|
||||
path: "/p5jlr/extern/groups/vin_main?lang=tr&serviceName=jaguar_parts&vin=SAJAA10MXDPV41100",
|
||||
},
|
||||
segments: {
|
||||
vinfoBasic: {
|
||||
records: [
|
||||
{ values: { description: "Sasi numarasi", value: "SAJAA10MXDPV41100" } },
|
||||
{ values: { description: "Model", value: "XJ 2010 \\- 2019 (X351)" } },
|
||||
{ values: { description: "Üretim tarihi", value: "18 Eyl 2012" } },
|
||||
{ values: { description: "Motor Tipi", value: "2.0L 16V TIVCT T/C 240PS Petrol" } },
|
||||
{ values: { description: "Vites Kutusu", value: "8 Speed Auto Trans ZF 8HP70 2WD" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
it("unescapes \\- in the model and reads the JLR engine/transmission labels", () => {
|
||||
const r = p.parseVehicleResponse("SAJAA10MXDPV41100", jlrData as never, "jaguar_parts");
|
||||
expect(r.model).toBe("XJ 2010 - 2019 (X351)");
|
||||
expect(r.engineType).toBe("2.0L 16V TIVCT T/C 240PS Petrol");
|
||||
expect(r.transmission).toBe("8 Speed Auto Trans ZF 8HP70 2WD");
|
||||
expect(r.year).toBe(2012);
|
||||
});
|
||||
});
|
||||
|
||||
describe("PL24Service.parseVehicleResponse — p5toyota (parens engine code + whitespace collapse)", () => {
|
||||
const toyotaData = {
|
||||
resultStatus: "VEHICLE_IDENTIFIED",
|
||||
description: "COROLLA (TUP)",
|
||||
link: {
|
||||
path: "/p5toyota/extern/groups/vin/maingroups?lang=tr&serviceName=toyota_parts&vin=NMTBD3BEX0R033932",
|
||||
},
|
||||
segments: {
|
||||
vinfoBasic: {
|
||||
records: [
|
||||
{ values: { description: "Sasi numarasi", value: "NMTBD3BEX0R033932" } },
|
||||
{ values: { description: "Model", value: "COROLLA (TUP)" } },
|
||||
{ values: { description: "Üretim tarihi", value: "2023\\-11\\-29" } },
|
||||
{ values: { description: "ENGINE 1", value: "1800CC 16\\-VALVE DOHC EFI (2ZRFXE)" } },
|
||||
{
|
||||
values: { description: "ATM,MTM", value: "CONTINUOUSLY VARIABLE TRANSMISSION (CVT)" },
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
it("collapses padded whitespace and extracts the engine code from parens", () => {
|
||||
const r = p.parseVehicleResponse("NMTBD3BEX0R033932", toyotaData as never, "toyota_parts");
|
||||
expect(r.model).toBe("COROLLA (TUP)");
|
||||
expect(r.engineType).toBe("1800CC 16-VALVE DOHC EFI (2ZRFXE)");
|
||||
expect(r.engineCode).toBe("2ZRFXE");
|
||||
expect(r.transmission).toBe("CONTINUOUSLY VARIABLE TRANSMISSION (CVT)");
|
||||
expect(r.productionDate).toBe("2023-11-29");
|
||||
expect(r.year).toBe(2023);
|
||||
});
|
||||
});
|
||||
|
||||
describe("PL24Service.parseVehicleResponse — p5man / p5suzuki (brand engine/transmission labels)", () => {
|
||||
const manData = {
|
||||
resultStatus: "VEHICLE_IDENTIFIED",
|
||||
description: "TGS 44T 8X4 BB C3",
|
||||
link: {
|
||||
path: "/p5man/extern/groups/main-vin?lang=tr&serviceName=man_parts&vin=WMA39EZZ8NP178144",
|
||||
},
|
||||
segments: {
|
||||
vinfoBasic: {
|
||||
records: [
|
||||
{ values: { description: "Araç tip tanımı", value: "TGS 44T 8X4 BB C3" } },
|
||||
{ values: { description: "Sasi numarasi", value: "WMA39EZZ8NP178144" } },
|
||||
{ values: { description: "Yedek motor", value: "D 2676 LF80" } },
|
||||
{ values: { description: "Şanzıman", value: "939271" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
it("reads MAN 'Yedek motor' + 'Şanzıman'", () => {
|
||||
const r = p.parseVehicleResponse("WMA39EZZ8NP178144", manData as never, "man_parts");
|
||||
expect(r.model).toBe("TGS 44T 8X4 BB C3");
|
||||
expect(r.engineType).toBe("D 2676 LF80");
|
||||
expect(r.transmission).toBe("939271");
|
||||
});
|
||||
|
||||
const suzukiData = {
|
||||
resultStatus: "VEHICLE_IDENTIFIED",
|
||||
description: "VITARA (APK416)",
|
||||
link: {
|
||||
path: "/p5suzuki/extern/groups/vin/maingroups?lang=tr&serviceName=suzuki_parts&vin=TSMLYE21S00413589",
|
||||
},
|
||||
segments: {
|
||||
vinfoBasic: {
|
||||
records: [
|
||||
{ values: { description: "Sasi numarasi", value: "TSMLYE21S00413589" } },
|
||||
{ values: { description: "Model", value: "VITARA (APK416)" } },
|
||||
{ values: { description: "Üretim tarihi", value: "2017\\-09" } },
|
||||
{ values: { description: "Motor No.", value: "M16A\\-2195122" } },
|
||||
{ values: { description: "Şanzıman numarası", value: "17F4556996" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
it("reads Suzuki 'Motor No.' + 'Şanzıman numarası' and unescapes the date", () => {
|
||||
const r = p.parseVehicleResponse("TSMLYE21S00413589", suzukiData as never, "suzuki_parts");
|
||||
expect(r.model).toBe("VITARA (APK416)");
|
||||
expect(r.engineType).toBe("M16A-2195122");
|
||||
expect(r.transmission).toBe("17F4556996");
|
||||
expect(r.productionDate).toBe("2017-09");
|
||||
expect(r.year).toBe(2017);
|
||||
});
|
||||
});
|
||||
|
||||
describe("PL24Service.parseVehicleResponse — p5mitsubishi (model from 'Araç', not the internal code)", () => {
|
||||
const mmcData = {
|
||||
resultStatus: "VEHICLE_IDENTIFIED",
|
||||
description: "L200(EUR/MMTH)",
|
||||
link: {
|
||||
path: "/p5mitsubishi/extern/groups/vinMainGroups?lang=tr&serviceName=mmc_parts&vin=MMBJNKB407D031498",
|
||||
},
|
||||
segments: {
|
||||
vinfoBasic: {
|
||||
records: [
|
||||
{ values: { description: "Sasi numarasi", value: "MMBJNKB407D031498" } },
|
||||
{ values: { description: "Araç", value: "L200(EUR/MMTH)" } },
|
||||
{ values: { description: "Model", value: "KB4T 2500DIESEL/4WD(TRUCK)" } },
|
||||
{ values: { description: "Üretim tarihi", value: "15.07.2006" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
it("uses 'Araç' (L200), not the internal 'Model' code (KB4T …)", () => {
|
||||
const r = p.parseVehicleResponse("MMBJNKB407D031498", mmcData as never, "mmc_parts");
|
||||
expect(r.model).toBe("L200");
|
||||
expect(r.year).toBe(2006);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1014,7 +1014,17 @@ export class PL24Service {
|
||||
const value = (v.key !== undefined ? v.description : v.value) || "";
|
||||
if (!label) continue;
|
||||
const key = label.toLowerCase().replace(/[\s\/]+/g, "_");
|
||||
if (!(key in vehicleData)) vehicleData[key] = value.replace(/\r?\n/g, " ").trim();
|
||||
if (!(key in vehicleData)) {
|
||||
// Normalize like prNr col3: newlines→space, unescape the literal "\-" some P5
|
||||
// backends emit (JLR "XJ 2010 \- 2019", Toyota/Suzuki dates "2023\-11\-29"/"2005\-07"),
|
||||
// and collapse runs of whitespace (Toyota "COROLLA (TUP)"). Otherwise the raw
|
||||
// escape/padding leaks straight to the UI.
|
||||
vehicleData[key] = value
|
||||
.replace(/\r?\n/g, " ")
|
||||
.replace(/\\-/g, "-")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
}
|
||||
}
|
||||
|
||||
// Helper: look up by multiple possible keys (EN + TR)
|
||||
@@ -1046,11 +1056,24 @@ export class PL24Service {
|
||||
.replace("?", "?scope=F&subAggregate=n-r&");
|
||||
}
|
||||
|
||||
// Engine code: vinfoBasic "Motor kodu" / "Engine code"
|
||||
// Engine code: VAG/BMW "Motor kodu" / "Engine code".
|
||||
const engineCode = lookup("motor_kodu", "engine_code");
|
||||
// Non-VAG P5 OEMs label the engine differently and give a description (sometimes with a
|
||||
// code in parens): JLR "Motor Tipi", Toyota "ENGINE 1", MAN "Yedek motor", Suzuki "Motor No.".
|
||||
const engineLabel = lookup("motor_tipi", "engine_1", "yedek_motor", "motor_no.");
|
||||
|
||||
// Transmission code: vinfoBasic "Şanzıman kodu" / "Transmission code"
|
||||
const transmissionCode = lookup("şanzıman_kodu", "sanzıman_kodu", "transmission_code");
|
||||
// Transmission: VAG "Şanzıman kodu"; other OEMs use their own labels — JLR "Vites Kutusu",
|
||||
// Toyota "ATM,MTM" (key "atm,mtm" — only spaces/slashes are underscored), MAN "Şanzıman",
|
||||
// Suzuki "Şanzıman numarası".
|
||||
const transmissionCode = lookup(
|
||||
"şanzıman_kodu",
|
||||
"sanzıman_kodu",
|
||||
"transmission_code",
|
||||
"vites_kutusu",
|
||||
"atm,mtm",
|
||||
"şanzıman",
|
||||
"şanzıman_numarası",
|
||||
);
|
||||
|
||||
// Build body type from prNr K8* (Kaporta formları); brands without a prNr segment
|
||||
// (e.g. BMW) carry it in vinfoBasic "Karoseri" ("Limousine").
|
||||
@@ -1075,10 +1098,16 @@ export class PL24Service {
|
||||
// Friendly model. p5fiat uses "Model bilgisi" ("Panda POP 1.2 …"); most P5 backends use
|
||||
// "Model". BMW's "Model" is only the trim ("520i") with the chassis/generation in "Seri"
|
||||
// ("5 G30") — fold the generation in so parts aren't ambiguous across chassis (E60/F10/G30).
|
||||
const baseModel =
|
||||
lookup("model_bilgisi", "model")?.trim() ||
|
||||
(data.description as string)?.split(" - ")[0]?.trim() ||
|
||||
"";
|
||||
// Mitsubishi's "Model" is an internal chassis/engine code ("KB4T 2500DIESEL/4WD(TRUCK)");
|
||||
// the friendly name is in "Araç" / description ("L200(EUR/MMTH)") — strip the region suffix.
|
||||
const isMitsubishi = getServiceApiPath(serviceName) === "/p5mitsubishi";
|
||||
const baseModel = isMitsubishi
|
||||
? (lookup("araç") || (data.description as string) || lookup("model") || "")
|
||||
.replace(/\s*\([^)]*\)\s*$/, "")
|
||||
.trim()
|
||||
: lookup("model_bilgisi", "model")?.trim() ||
|
||||
(data.description as string)?.split(" - ")[0]?.trim() ||
|
||||
"";
|
||||
// "Seri" is "{line} {chassis} [{variant}]" ("5 G30", "X3 G01", "5 E60 MUE"). The trim already
|
||||
// implies the line ("520i"→5, "X3 sDrive20i"→X3), so drop the leading line token and append
|
||||
// only the chassis(+variant) → "520i G30", "X3 sDrive20i G01" (avoids a redundant "X3 X3").
|
||||
@@ -1108,8 +1137,12 @@ export class PL24Service {
|
||||
0,
|
||||
series: lookup("seri", "satis_tipi", "sales_type"),
|
||||
bodyType,
|
||||
engineCode: engineCode || (engineDesc ? engineDesc.split("/")[0]?.trim() : null),
|
||||
engineType: engineDesc,
|
||||
engineCode:
|
||||
engineCode ||
|
||||
engineLabel?.match(/\(([A-Za-z0-9]{3,})\)/)?.[1] || // Toyota "1800CC … (2ZRFXE)"
|
||||
(engineDesc ? engineDesc.split("/")[0]?.trim() : null) ||
|
||||
null,
|
||||
engineType: engineDesc || engineLabel,
|
||||
engineVolume: null,
|
||||
transmission: transmissionCode || transmissionDesc,
|
||||
driveType,
|
||||
|
||||
Reference in New Issue
Block a user