fix(pl24): enrich BMW decode — chassis/generation, body, drive from vinfoBasic

BMW (p5bmw) decode was weak: model was just the trim ("520i") with no
chassis/generation, body_type empty, because BMW has NO prNr segment and keeps
that data in distinct vinfoBasic labels the shared parser ignored. Live-verified
fields: "Seri"="5 G30" (chassis), "Karoseri"="Limousine" (body), "Tahrik"="RWD".

- model: fold the generation ("Seri"/"Model tanimi") into the model when present
  and not already included → "520i 5 G30" (disambiguates E60/F10/G30 for parts).
- bodyType: fall back to vinfoBasic "Karoseri" when there's no prNr K8*.
- series: read "Seri"; driveType: read "Tahrik".
Year already comes from "Üretim tarihi" (P5 year fallback). VW/Audi (prNr) and
Mercedes ("Piyasa adı", no seri/karoseri) verified unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-04 23:45:51 +03:00
parent aaa96d82e3
commit d3ff19ad6a
2 changed files with 61 additions and 11 deletions

View File

@@ -1052,9 +1052,12 @@ export class PL24Service {
// Transmission code: vinfoBasic "Şanzıman kodu" / "Transmission code"
const transmissionCode = lookup("şanzıman_kodu", "sanzıman_kodu", "transmission_code");
// Build body type from prNr K8* (Kaporta formları)
// Build body type from prNr K8* (Kaporta formları); brands without a prNr segment
// (e.g. BMW) carry it in vinfoBasic "Karoseri" ("Limousine").
const bodyType =
Object.entries(prNrByCode).find(([code]) => code.startsWith("K8"))?.[1] || null;
Object.entries(prNrByCode).find(([code]) => code.startsWith("K8"))?.[1] ||
lookup("karoseri", "body", "body_type") ||
null;
// Engine description from prNr D3* (Motor nitelikleri)
const engineDesc =
@@ -1064,19 +1067,27 @@ export class PL24Service {
const transmissionDesc =
Object.entries(prNrByCode).find(([code]) => code.startsWith("G0"))?.[1] || null;
// Drive type from prNr 1X* (Tahrik türü)
// Drive type from prNr 1X* (Tahrik türü); BMW carries it in vinfoBasic "Tahrik" (RWD/xDrive).
const driveType =
Object.entries(prNrByCode).find(([code]) => code.startsWith("1X"))?.[1] ||
lookup("aks_tahrigi_tanimi", "axle_drive");
lookup("tahrik", "aks_tahrigi_tanimi", "axle_drive");
// 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() ||
"";
const generation = lookup("seri", "model_tanimi");
const model =
generation && baseModel && !baseModel.toLowerCase().includes(generation.toLowerCase())
? `${baseModel} ${generation}`
: baseModel;
return {
brand: SERVICE_TO_BRAND[serviceName] || serviceName.replace("_parts", ""),
// p5fiat carries the friendly model in "Model bilgisi" ("Panda POP 1.2 8V 69CV 5M E6");
// its plain "Model" is a numeric code. Other P5 backends only have "model".
model:
lookup("model_bilgisi", "model")?.trim() ||
(data.description as string)?.split(" - ")[0]?.trim() ||
"",
model,
// p5fiat has no plain model-year field; derive it from "MY" ("… = 2014 YILI") or the
// production date ("05/09/2014"). Other P5 backends use a plain model_yili/year number.
year:
@@ -1087,7 +1098,7 @@ export class PL24Service {
) ||
extractModelYear(vin) ||
0,
series: lookup("satis_tipi", "sales_type"),
series: lookup("seri", "satis_tipi", "sales_type"),
bodyType,
engineCode: engineCode || (engineDesc ? engineDesc.split("/")[0]?.trim() : null),
engineType: engineDesc,