feat(vehicles): automatic Vinpin VIN-decode fallback (flag-gated, off by default)
When PL24/pcat/emex can't decode a Fiat VIN, decode it via the Vinpin ePER web catalog (warm-session Playwright worker, single seat, BullMQ concurrency 1), cache the exact vehicle in vinpin_decodes, match it to PL24's existing catalog_vehicle for that model, and serve the parts from there. Vinpin = decode oracle only; PL24 already holds the parts (e.g. Egea/Linea/Doblo). Strictly gated behind VINPIN_ENABLED (default false) + a Fiat-only brand allowlist: with the flag off, decodeVin behaviour is byte-identical and the queue is never touched (covered by tests). Coordinates/selectors in vinpin.constants.ts are marked TUNE-AGAINST-LIVE-PAID-SEAT. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
38
apps/api/src/integrations/vinpin/vinpin.parser.spec.ts
Normal file
38
apps/api/src/integrations/vinpin/vinpin.parser.spec.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { isUsableParse, parseVinpinModal } from "./vinpin.parser";
|
||||
|
||||
const SAMPLE =
|
||||
"MVS, найденные по vin NM435600006H43436 6J - TIPO - EGEA (2015-2021) 356G37001162 - 3V HIGH PLUS 1.6 120CV D5 CM E6 GS TR Двигатель: 8165300 Автомобиль: 279476 Prod. date: 2/8/2017 Vin: NM435600006H43436";
|
||||
|
||||
describe("parseVinpinModal", () => {
|
||||
it("parses the real ePER modal sample (TIPO-EGEA / 356G37001162 / 2017)", () => {
|
||||
const p = parseVinpinModal(SAMPLE);
|
||||
expect(p.model).toBe("TIPO-EGEA");
|
||||
expect(p.sincom).toBe("356G37001162");
|
||||
expect(p.modelYear).toBe("2017"); // from Prod. date, not the (2015-2021) range
|
||||
expect(p.engine).toBe("8165300");
|
||||
expect(p.trim).toContain("HIGH PLUS");
|
||||
expect(isUsableParse(p)).toBe(true);
|
||||
});
|
||||
|
||||
it("does not mistake the VIN or short engine number for a SINCOM code", () => {
|
||||
const p = parseVinpinModal(SAMPLE);
|
||||
expect(p.sincom).not.toContain("NM4356");
|
||||
expect(p.sincom).not.toBe("8165300");
|
||||
});
|
||||
|
||||
it("falls back to the year-range start when no production date is present", () => {
|
||||
const p = parseVinpinModal("9F - LINEA (2007-2017) 323A11005000 - 1.3 MJET");
|
||||
expect(p.model).toBe("LINEA");
|
||||
expect(p.sincom).toBe("323A11005000");
|
||||
expect(p.modelYear).toBe("2007");
|
||||
});
|
||||
|
||||
it("returns all-null for empty/garbage input and reports unusable", () => {
|
||||
const p = parseVinpinModal("");
|
||||
expect(p.model).toBeNull();
|
||||
expect(p.sincom).toBeNull();
|
||||
expect(isUsableParse(p)).toBe(false);
|
||||
expect(isUsableParse(parseVinpinModal(null))).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user