fix(part-prices): araç-marka etiketlerini de orijinal say (FORD/GM/BMW/Mercedes/VW)
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
Kullanıcı düzeltmesi: kokpit tur ham araç-marka etiketlerini "yansanayi" sayıyordu — yanlış. FORD/GM/BMW/Mercedes/Volkswagen/Renault… OE etiketidir. Orijinal tespiti artık kokpit tur='orjinal' setine değil, OE aile üyeliğine dayanır: OE_SUPPLY_LABELS OE_FAMILIES'ten TÜRETİLİR (+ jenerik ORJINAL), böylece OE-tespiti ile aile-filtresi drift etmez ve tüm araç markaları orijinal sayılır. Gerçek yan sanayi PARÇA markaları (Bosch/Febi/Valeo/TRW) hiçbir ailede yok → orijinal değil. GM Opel ailesine eklendi (TR'de Opel OE'si). Redis v3→v4 (eski "miss" değerleri bayat). kokpit'e DOKUNULMADI. Ölçülen etki (dev): grafikli kod %0,77→%0,84; artış sase kataloğu ile takip beslemesinin bu markalardaki kod kesişimiyle sınırlı (ör. takip'te 4.859 Ford- stokta koddan 335'i sase kataloğunda). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
isOeSupplyLabel,
|
||||
istanbulToday,
|
||||
normPartCode,
|
||||
oeFamilyOf,
|
||||
percentile,
|
||||
reconstructDailySeries,
|
||||
selectOeOffers,
|
||||
@@ -246,31 +247,69 @@ describe("filterOffersForBrand", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("isOeSupplyLabel / selectOeOffers (kaynak: kokpit tur='orjinal')", () => {
|
||||
describe("isOeSupplyLabel / selectOeOffers (OE aileleri + jenerik ORJINAL)", () => {
|
||||
it("dağıtıcı ve orijinal etiketleri tanır", () => {
|
||||
expect(isOeSupplyLabel("MAIS")).toBe(true); // Renault dağıtıcısı
|
||||
expect(isOeSupplyLabel("OPAR")).toBe(true); // Fiat/Tofaş
|
||||
expect(isOeSupplyLabel("PSA")).toBe(true);
|
||||
expect(isOeSupplyLabel("ORJINAL")).toBe(true); // kokpit tur='orjinal'
|
||||
expect(isOeSupplyLabel("ORJINAL")).toBe(true); // jenerik orijinal
|
||||
expect(isOeSupplyLabel("VECO")).toBe(true); // Iveco OE alias'ı
|
||||
});
|
||||
|
||||
it("kokpit'in yansanayi/esdeger saydığı etiketler orijinal DEĞİL", () => {
|
||||
// kokpit ham FORD/GM/BMW/Mercedes/VW etiketlerini yansanayi sayar.
|
||||
expect(isOeSupplyLabel("FORD")).toBe(false);
|
||||
expect(isOeSupplyLabel("GM")).toBe(false);
|
||||
expect(isOeSupplyLabel("BOSCH")).toBe(false); // esdeger
|
||||
expect(isOeSupplyLabel("FEBI")).toBe(false); // esdeger
|
||||
it("ham araç-marka etiketleri de ORİJİNALDİR (kokpit'in yansanayi demesi yanlış)", () => {
|
||||
// 2026-07-14 kullanıcı düzeltmesi: FORD/GM/BMW/Mercedes/VW OE etiketidir.
|
||||
expect(isOeSupplyLabel("FORD")).toBe(true);
|
||||
expect(isOeSupplyLabel("GM")).toBe(true); // Opel OE'si
|
||||
expect(isOeSupplyLabel("BMW")).toBe(true);
|
||||
expect(isOeSupplyLabel("MERCEDES")).toBe(true);
|
||||
expect(isOeSupplyLabel("VOLKSWAGEN")).toBe(true);
|
||||
expect(isOeSupplyLabel("RENAULT")).toBe(true);
|
||||
});
|
||||
|
||||
it("gerçek yan sanayi PARÇA markaları orijinal DEĞİL", () => {
|
||||
expect(isOeSupplyLabel("BOSCH")).toBe(false);
|
||||
expect(isOeSupplyLabel("FEBI")).toBe(false);
|
||||
expect(isOeSupplyLabel("VALEO")).toBe(false);
|
||||
expect(isOeSupplyLabel("TRW")).toBe(false);
|
||||
expect(isOeSupplyLabel("")).toBe(false);
|
||||
});
|
||||
|
||||
it("selectOeOffers karma havuzdan yalnız orijinalleri seçer", () => {
|
||||
it("GM Opel ailesine, FORD kendi ailesine eşlenir", () => {
|
||||
expect(oeFamilyOf("GM")).toBe("OPEL");
|
||||
expect(oeFamilyOf("FORD")).toBe("FORD");
|
||||
expect(oeFamilyOf("MERCEDES")).toBe("MERCEDES");
|
||||
});
|
||||
|
||||
it("selectOeOffers karma havuzdan orijinalleri (araç markaları dahil) seçer", () => {
|
||||
const out = selectOeOffers([
|
||||
{ brandNorm: "OPAR", price: 767 },
|
||||
{ brandNorm: "FORD", price: 480 },
|
||||
{ brandNorm: "IBR", price: 909 },
|
||||
{ brandNorm: "FORD", price: 480 }, // artık orijinal
|
||||
{ brandNorm: "IBR", price: 909 }, // İbraş = yan sanayi
|
||||
]);
|
||||
expect(out).toEqual([{ brandNorm: "OPAR", price: 767 }]);
|
||||
expect(out.map((o) => o.brandNorm).sort()).toEqual(["FORD", "OPAR"]);
|
||||
});
|
||||
|
||||
it("Ford kodu araç markası FORD → FORD teklifi gelir", () => {
|
||||
const offers = [
|
||||
{ brandNorm: "FORD", price: 480 },
|
||||
{ brandNorm: "BOSCH", price: 300 },
|
||||
];
|
||||
expect(filterOffersForBrand(offers, "FORD", "1234567890")).toEqual([
|
||||
{ brandNorm: "FORD", price: 480 },
|
||||
]);
|
||||
});
|
||||
|
||||
it("Opel kodu → OPEL + GM aynı aile, ikisi de gelir; PSA farklı aile elenir", () => {
|
||||
const offers = [
|
||||
{ brandNorm: "GM", price: 500 },
|
||||
{ brandNorm: "OPEL", price: 520 },
|
||||
{ brandNorm: "PSA", price: 610 },
|
||||
];
|
||||
expect(
|
||||
filterOffersForBrand(offers, "OPEL", "9827622780")
|
||||
.map((o) => o.brandNorm)
|
||||
.sort(),
|
||||
).toEqual(["GM", "OPEL"]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -31,91 +31,29 @@ export function normPartCode(code: string): string {
|
||||
// süzülür. Tedarikçiler markayı kısaltarak yazar (BCH/B→Bosch, BLP→Blue
|
||||
// Print, IBR→İbraş) — eşleşme önek VEYA sıralı-altdizi ile yapılır.
|
||||
|
||||
// ─── Orijinal (OE/dağıtıcı) etiketleri ─────────────────────────────────────
|
||||
// Markasız bağlam (OEM detayın ana kodu) yalnız ORİJİNAL teklifleri gösterir:
|
||||
// orijinal + yan sanayi tek havuzda medyanlanınca hiçbir gerçek ürünün fiyatı
|
||||
// olmayan "hayalet fiyat" çıkar ve marka stok girip-çıkması fiyat değişmeden
|
||||
// sahte sıçrama çizer (2026-07-14 ölçümü: 9827622780 → pg p50 4.495₺ = PSA
|
||||
// 5.531 ile OPAR 3.459'un ortası).
|
||||
// ─── Orijinal (OE) etiketleri ve marka aileleri ────────────────────────────
|
||||
// Markasız/araç-markalı bağlam (OEM detay kartı) yalnız ORİJİNAL teklifleri
|
||||
// gösterir: orijinal + yan sanayi tek havuzda medyanlanınca hiçbir gerçek
|
||||
// ürünün fiyatı olmayan "hayalet fiyat" çıkar (2026-07-14: 9827622780 →
|
||||
// 4.495₺ = PSA 5.531 ile OPAR 3.459'un ortası).
|
||||
//
|
||||
// OTORİTE = kokpit (otoyedekparca.co) marka `tur` sınıflaması: orjinal /
|
||||
// esdeger / yansanayi. Aşağıdaki set = tur='orjinal' markalarının normalize
|
||||
// adları (39 marka), 2026-07-14 çekimi. Yenilemek için (kokpit_center PG):
|
||||
// SELECT UPPER(regexp_replace(name,'[^A-Za-z0-9]','','g'))
|
||||
// FROM product_service_manufacturers WHERE is_deleted=false AND tur='orjinal';
|
||||
// NOT: kokpit Türkiye pazarını yansıtır — orijinal = DAĞITICI etiketi
|
||||
// (Mais=Renault, Opar=Fiat, Psa, Opel) + ithal-araç OE markaları. Ham FORD/
|
||||
// GM/BMW/MERCEDES/VOLKSWAGEN etiketleri kokpit'te 'yansanayi'dir, bilinçli
|
||||
// dışarıda. Runtime kokpit bağımlılığı YOK (statik liste; P entegrasyonu gibi
|
||||
// fail-open değil, çekirdek mantık) — kokpit listesi değişince buradan yenile.
|
||||
const OE_SUPPLY_LABELS: ReadonlySet<string> = new Set([
|
||||
"AUDI",
|
||||
"BERCITROEN",
|
||||
"BUICK",
|
||||
"CHEVROLET",
|
||||
"CHRYSLER",
|
||||
"DACIA",
|
||||
"DAEWOO",
|
||||
"DAIHATSU",
|
||||
"DFM",
|
||||
"DODGE",
|
||||
"HONDA",
|
||||
"JEEP",
|
||||
"KIA",
|
||||
"LADA",
|
||||
"LEXUS",
|
||||
"LINCOLN",
|
||||
"MAIS",
|
||||
"MAZDA",
|
||||
"MINI",
|
||||
"NISSAN",
|
||||
"OEVECO",
|
||||
"OPAR",
|
||||
"OPEL",
|
||||
"ORJINAL",
|
||||
"PORSCHE",
|
||||
"PROTON",
|
||||
"PSA",
|
||||
"RANGE",
|
||||
"ROVER",
|
||||
"SAAB",
|
||||
"SEAT",
|
||||
"SKODA",
|
||||
"SSANGYONG",
|
||||
"TATA",
|
||||
"TESLA",
|
||||
"TOGG",
|
||||
"TOYOTA",
|
||||
"TOYOTAORJINAL",
|
||||
"VOLVO",
|
||||
// Alias: takip verisi Iveco OE'sini "VECO" olarak etiketliyor; kokpit
|
||||
// karşılığı "Oe-İveco" (OEVECO). Aynı fiziksel orijinal → dahil.
|
||||
"VECO",
|
||||
]);
|
||||
|
||||
/** Teklifin etiketi orijinal (OE/dağıtıcı) mı — kokpit `tur='orjinal'` setine göre. */
|
||||
export function isOeSupplyLabel(brandNorm: string): boolean {
|
||||
return OE_SUPPLY_LABELS.has(brandNorm);
|
||||
}
|
||||
|
||||
/** Yalnız orijinal (OE/dağıtıcı) etiketli teklifler. */
|
||||
export function selectOeOffers<T extends { brandNorm: string }>(offers: T[]): T[] {
|
||||
return offers.filter((o) => isOeSupplyLabel(o.brandNorm));
|
||||
}
|
||||
|
||||
// ─── Marka → OE dağıtıcı ailesi ────────────────────────────────────────────
|
||||
// Bir OEM kodu tek bir araç markasına aittir; teklifleri o markanın OE
|
||||
// ailesine süzeriz. Böylece aynı koda düşen FARKLI dağıtıcılar (PSA ₺5.531 vs
|
||||
// OPAR ₺3.459 — Stellantis) tek havuza karışıp anlamsız medyan üretmez:
|
||||
// Peugeot kodu = PSA ailesi, Fiat kodu = FIAT ailesi (2026-07-14 kullanıcı
|
||||
// talebi). Hem araç markası adları (istek tarafı: sase brands) hem dağıtıcı
|
||||
// etiketleri (teklif tarafı: takip) aynı aileye eşlenir. `family → üyeler`
|
||||
// olarak yazılır, yükleme anında etiket→aile map'ine çevrilir.
|
||||
// Bir OEM kodu tek bir araç markasına aittir → teklifleri o markanın OE
|
||||
// ailesine süzeriz (aynı koda düşen PSA vs OPAR karışmaz). `family → üyeler`;
|
||||
// üyeler hem araç markası adları (istek/sase brands) hem dağıtıcı etiketleridir
|
||||
// (teklif/takip: MAIS=Renault, OPAR=Fiat, PSA, VECO=Iveco, GM=Opel).
|
||||
//
|
||||
// ORİJİNAL TESPİTİ: bir teklif etiketi orijinal sayılır ancak bir OE ailesinin
|
||||
// üyesiyse ya da jenerik "ORJINAL" ise. Kaynak = sase araç markaları + Türkiye
|
||||
// OE-dağıtıcı etiketleri. NOT (2026-07-14 kullanıcı düzeltmesi): ham araç-marka
|
||||
// etiketleri (FORD, GM, BMW, MERCEDES, VOLKSWAGEN, RENAULT, FIAT…) ORİJİNALDİR
|
||||
// — kokpit `tur` bunları 'yansanayi' sayıyordu, bu YANLIŞ; burada aileleriyle
|
||||
// birlikte orijinal kabul edilir. Gerçek yan sanayi PARÇA markaları (Bosch/
|
||||
// Febi/Valeo/TRW…) hiçbir ailede değildir → orijinal sayılmaz.
|
||||
const OE_FAMILIES: Readonly<Record<string, readonly string[]>> = {
|
||||
RENAULT: ["RENAULT", "DACIA", "ALPINE", "MAIS"],
|
||||
FIAT: ["FIAT", "ALFAROMEO", "LANCIA", "ABARTH", "OPAR", "TOFAS"],
|
||||
PSA: ["PEUGEOT", "CITROEN", "DS", "PSA"],
|
||||
OPEL: ["OPEL", "VAUXHALL"],
|
||||
OPEL: ["OPEL", "VAUXHALL", "GM"], // GM = General Motors, TR'de Opel OE'si
|
||||
VAG: ["VOLKSWAGEN", "VW", "AUDI", "SEAT", "SKODA", "CUPRA", "BENTLEY"],
|
||||
FORD: ["FORD"],
|
||||
BMW: ["BMW", "MINI"],
|
||||
@@ -134,8 +72,7 @@ const OE_FAMILIES: Readonly<Record<string, readonly string[]>> = {
|
||||
SUBARU: ["SUBARU"],
|
||||
SUZUKI: ["SUZUKI"],
|
||||
IVECO: ["IVECO", "VECO", "OEVECO"],
|
||||
// kokpit orjinal setinde olup sase araç listesinde olmayanlar — kendi
|
||||
// ailelerine (isteğe gelirse kendileriyle eşleşsinler).
|
||||
// sase araç listesinde olmayan ama teklif/istek olarak gelebilecek markalar.
|
||||
CHRYSLER: ["CHRYSLER", "DODGE", "JEEP", "MOPAR", "LINCOLN", "BUICK"],
|
||||
CHEVROLET: ["CHEVROLET"],
|
||||
DAEWOO: ["DAEWOO"],
|
||||
@@ -163,11 +100,30 @@ export function oeFamilyOf(brandNorm: string): string | null {
|
||||
return OE_FAMILY_OF.get(brandNorm) ?? null;
|
||||
}
|
||||
|
||||
// Orijinal etiket seti = tüm OE aile üyeleri + jenerik "ORJINAL" (orijinal ama
|
||||
// aile-belirsiz: markasız/taban görünümde sayılır, aile filtresinde elenir).
|
||||
// Aileden TÜRETİLİR → OE-tespiti ile aile-filtresi asla drift etmez; yeni bir
|
||||
// marka eklemek için tek yer OE_FAMILIES.
|
||||
const OE_SUPPLY_LABELS: ReadonlySet<string> = new Set([
|
||||
...Object.values(OE_FAMILIES).flat(),
|
||||
"ORJINAL",
|
||||
]);
|
||||
|
||||
/** Teklifin etiketi orijinal mi (bir OE ailesinin üyesi ya da jenerik ORJINAL). */
|
||||
export function isOeSupplyLabel(brandNorm: string): boolean {
|
||||
return OE_SUPPLY_LABELS.has(brandNorm);
|
||||
}
|
||||
|
||||
/** Yalnız orijinal (OE) etiketli teklifler. */
|
||||
export function selectOeOffers<T extends { brandNorm: string }>(offers: T[]): T[] {
|
||||
return offers.filter((o) => isOeSupplyLabel(o.brandNorm));
|
||||
}
|
||||
|
||||
// ─── Redis cache anahtarları ───────────────────────────────────────────────
|
||||
// Service ve worker processor'ı AYNI üreticileri kullanır (literal kopya
|
||||
// drift'i olmasın). v3 = markasız/araç-markalı görünümler OE-only süzgece
|
||||
// geçti; v2 karma-havuz değerleri bayat.
|
||||
export const PART_PRICE_CACHE_VERSION = "v3";
|
||||
// drift'i olmasın). v4 = OE seti araç-marka etiketlerini (FORD/GM/BMW/MERCEDES/
|
||||
// VW…) de kapsayacak şekilde genişledi → v3'teki "miss" değerleri bayat.
|
||||
export const PART_PRICE_CACHE_VERSION = "v4";
|
||||
export const partPriceSeriesCacheKey = (codeNorm: string, brandNorm: string) =>
|
||||
`partprice:series:${PART_PRICE_CACHE_VERSION}:${codeNorm}::${brandNorm}`;
|
||||
export const partPriceCurrentCacheKey = (codeNorm: string, brandNorm: string) =>
|
||||
|
||||
Reference in New Issue
Block a user