fix: KoePi verwandte Ketten (Netto Marken-/Getraenke-Discount) werden jetzt gemeinsam durchsucht
This commit is contained in:
@@ -62,10 +62,20 @@ function addressesMatch(a, b) {
|
|||||||
// aktuellen und kürzlich abgelaufenen Prospekte GENAU dieser Kette, ganz ohne
|
// aktuellen und kürzlich abgelaufenen Prospekte GENAU dieser Kette, ganz ohne
|
||||||
// Umkreis-Raten. addressMatch bestimmt, welche der (ggf. mehreren
|
// Umkreis-Raten. addressMatch bestimmt, welche der (ggf. mehreren
|
||||||
// bundesweiten) Filialen dieser Kette tatsächlich eure ist.
|
// bundesweiten) Filialen dieser Kette tatsächlich eure ist.
|
||||||
|
// Manche Ketten teilen sich bei marktguru offenbar denselben Datentopf — ein
|
||||||
|
// Prospekt kann unter der "falschen" uniqueName auftauchen (z.B. das
|
||||||
|
// Getränke-Discount-Prospekt bei "netto-marken-discount" statt bei
|
||||||
|
// "netto-getraenke-discount"). Für solche Familien wird beim Auflösen die
|
||||||
|
// gesamte Gruppe gemeinsam durchsucht, nicht nur die eigene Liste.
|
||||||
|
const RETAILER_FAMILIES = {
|
||||||
|
'netto-marken-discount': ['netto-marken-discount', 'netto-getraenke-discount'],
|
||||||
|
'netto-getraenke-discount':['netto-marken-discount', 'netto-getraenke-discount'],
|
||||||
|
};
|
||||||
|
|
||||||
const LOCAL_STORE_TARGETS = [
|
const LOCAL_STORE_TARGETS = [
|
||||||
{ retailer: 'Netto Marken-Discount', uniqueName: 'netto-marken-discount', addressMatch: 'Im Bonnefeld 19' },
|
{ retailer: 'Netto Marken-Discount', uniqueName: 'netto-marken-discount', addressMatch: 'Im Bonnefeld 19' },
|
||||||
{ retailer: 'Netto Getränke-Discount', uniqueName: 'netto-getraenke-discount', addressMatch: 'Im Bonnefeld 21' },
|
{ retailer: 'Netto Getränke-Discount', uniqueName: 'netto-getraenke-discount', addressMatch: 'Im Bonnefeld 21' },
|
||||||
{ retailer: 'trinkgut', uniqueName: 'trinkgut-discount', addressMatch: 'Keniastraße 39' },
|
{ retailer: 'trinkgut', uniqueName: 'trinkgut', addressMatch: 'Keniastraße 39' },
|
||||||
{ retailer: 'REWE', uniqueName: 'rewe', addressMatch: 'Fischerstr. 110-112' },
|
{ retailer: 'REWE', uniqueName: 'rewe', addressMatch: 'Fischerstr. 110-112' },
|
||||||
{ retailer: 'Kaufland', uniqueName: 'kaufland', addressMatch: 'Auf der Höhe 20' },
|
{ retailer: 'Kaufland', uniqueName: 'kaufland', addressMatch: 'Auf der Höhe 20' },
|
||||||
{ retailer: 'Penny', uniqueName: 'penny', addressMatch: 'Sittardsberger Allee 10' },
|
{ retailer: 'Penny', uniqueName: 'penny', addressMatch: 'Sittardsberger Allee 10' },
|
||||||
@@ -249,9 +259,20 @@ async function resolveLocalStores() {
|
|||||||
const cache = new Map();
|
const cache = new Map();
|
||||||
let resolved = 0;
|
let resolved = 0;
|
||||||
|
|
||||||
|
// Alle benötigten uniqueNames einmal laden (Mehrfachabrufe vermeiden, falls
|
||||||
|
// mehrere Ziele/Familien sich eine uniqueName teilen)
|
||||||
|
const uniqueNames = [...new Set(LOCAL_STORE_TARGETS.map(t => t.uniqueName))];
|
||||||
|
const leafletsByUniqueName = new Map();
|
||||||
|
for (const uniqueName of uniqueNames) {
|
||||||
|
leafletsByUniqueName.set(uniqueName, await fetchLeafletsForRetailer(uniqueName));
|
||||||
|
}
|
||||||
|
|
||||||
for (const target of LOCAL_STORE_TARGETS) {
|
for (const target of LOCAL_STORE_TARGETS) {
|
||||||
const leaflets = await fetchLeafletsForRetailer(target.uniqueName);
|
// Bei verwandten Ketten (siehe RETAILER_FAMILIES) alle Prospekte der
|
||||||
console.log(`🍺 KöPi: "${target.retailer}" (${target.uniqueName}) — ${leaflets.length} Prospekt(e) gefunden`);
|
// ganzen Familie gemeinsam durchsuchen, sonst nur die eigene Liste
|
||||||
|
const familyNames = RETAILER_FAMILIES[target.uniqueName] || [target.uniqueName];
|
||||||
|
const leaflets = familyNames.flatMap(name => leafletsByUniqueName.get(name) || []);
|
||||||
|
console.log(`🍺 KöPi: "${target.retailer}" (${target.uniqueName}) — ${leaflets.length} Prospekt(e) durchsucht${familyNames.length>1?` (Familie: ${familyNames.join(', ')})`:''}`);
|
||||||
let found = null;
|
let found = null;
|
||||||
for (const l of leaflets) {
|
for (const l of leaflets) {
|
||||||
if (!l.mainLeafletId) continue;
|
if (!l.mainLeafletId) continue;
|
||||||
@@ -617,11 +638,21 @@ async function scrapeProspekte() {
|
|||||||
}).map(({ rawName, ...rest }) => rest); // rawName war nur intern nötig
|
}).map(({ rawName, ...rest }) => rest); // rawName war nur intern nötig
|
||||||
const targeted = withoutSondermagazin.filter(b => b.isTarget);
|
const targeted = withoutSondermagazin.filter(b => b.isTarget);
|
||||||
|
|
||||||
// Chronologisch in "aktuell laufend" und "kommend" trennen
|
// Chronologisch in "aktuell laufend" und "kommend" trennen — WICHTIG: in
|
||||||
const todayIso = new Date().toISOString().slice(0, 10);
|
// lokaler Zeit vergleichen, nicht per rohem UTC-Substring. "22:00 UTC" ist
|
||||||
|
// bei uns lokal schon der nächste Tag (z.B. "2026-07-19T22:00:00Z" = lokal
|
||||||
|
// 20.07., 00:00 Uhr) — ein reiner String-Schnitt hätte das um einen Tag
|
||||||
|
// verschoben.
|
||||||
|
const localDateStr = isoOrDate => {
|
||||||
|
const d = isoOrDate instanceof Date ? isoOrDate : new Date(isoOrDate);
|
||||||
|
if (Number.isNaN(d.getTime())) return '';
|
||||||
|
const pad = n => String(n).padStart(2, '0');
|
||||||
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
||||||
|
};
|
||||||
|
const todayIso = localDateStr(new Date());
|
||||||
const isCurrent = b => {
|
const isCurrent = b => {
|
||||||
const from = (b.validFrom || '').slice(0, 10);
|
const from = localDateStr(b.validFrom);
|
||||||
const to = (b.validTo || '').slice(0, 10);
|
const to = localDateStr(b.validTo);
|
||||||
if (!from) return true; // ohne Datum lieber anzeigen als verstecken
|
if (!from) return true; // ohne Datum lieber anzeigen als verstecken
|
||||||
if (from > todayIso) return false; // startet erst noch
|
if (from > todayIso) return false; // startet erst noch
|
||||||
if (to && to < todayIso) return false; // schon abgelaufen
|
if (to && to < todayIso) return false; // schon abgelaufen
|
||||||
|
|||||||
Reference in New Issue
Block a user