import hashlib import re from flask import current_app from .http import get_json LEGAL_SUFFIXES = re.compile(r"\b(SPÓŁKA|SPÓŁKA AKCYJNA|SP\. ?Z ?O\. ?O\.|S\. ?A\.|ODDZIAŁ|SPÓŁKA EUROPEJSKA)\b.*$", re.I) def fetch_ure_stations(): payload = get_json(current_app.config["URE_STATIONS_URL"], timeout_key="URE_TIMEOUT_SECONDS") if isinstance(payload, list): return payload if isinstance(payload, dict): for key in ("items", "results", "data", "value"): if isinstance(payload.get(key), list): return payload[key] raise ValueError("Nieprawidłowa odpowiedź API URE") def _clean(value): return " ".join(str(value or "").strip().split()) def infer_brand(company_name, station_name=""): combined = f"{_clean(company_name)} {_clean(station_name)}".upper() aliases = current_app.config.get("STATION_BRAND_ALIASES", {}) # Najpierw szukamy marki w nazwie konkretnej stacji, później w przedsiębiorcy. for token, label in sorted(aliases.items(), key=lambda item: len(item[0]), reverse=True): if token.upper() in combined: return label normalized = _clean(company_name) shortened = LEGAL_SUFFIXES.sub("", normalized).strip(" ,-\"") return shortened or normalized or "Nieznana sieć" def _address_parts(row): return [ _clean(row.get("infraUlica")), _clean(row.get("infraNrLokalu")), _clean(row.get("infraKod")) or _clean(row.get("kod")), _clean(row.get("infraPoczta")) or _clean(row.get("miejscowosc")) or _clean(row.get("poczta")), _clean(row.get("wojewodztwo")).lower(), ] def _point_key(row, index): address = "|".join(x.casefold() for x in _address_parts(row) if x) station_name = _clean(row.get("nazwaStacji")).casefold() raw = address or f"{station_name}|{index}" digest = hashlib.sha1(raw.encode("utf-8")).hexdigest()[:16] dkn = _clean(row.get("dkn")) storage_key = f"{dkn or 'no-dkn'}:{digest}" return raw, storage_key def _merge_point(target, source): for field in ("station_name", "street", "street_number", "postal_code", "city", "region", "coordinates"): if not target.get(field) and source.get(field): target[field] = source[field] for field in ("has_petrol", "has_diesel", "has_lpg"): target[field] = bool(target.get(field) or source.get(field)) def aggregate_ure_companies(rows): grouped = {} aliases = {label.casefold() for label in current_app.config.get("STATION_BRAND_ALIASES", {}).values()} for index, row in enumerate(rows, start=1): nip, regon = _clean(row.get("nip")), _clean(row.get("regon")) company_name = _clean(row.get("nazwa")) or "Nieznana firma" station_name = _clean(row.get("nazwaStacji")) brand = infer_brand(company_name, station_name) # Rozpoznane sieci agregujemy jako jedną markę, niezależnie od operatora/franczyzobiorcy. if brand.casefold() in aliases: key = f"brand:{brand.casefold()}" else: key = f"nip:{nip}" if nip else (f"regon:{regon}" if regon else f"name:{company_name.casefold()}") item = grouped.setdefault(key, { "ure_key": key, "brand_name": brand, "company_name": brand if key.startswith("brand:") else company_name, "nip": None if key.startswith("brand:") else (nip or None), "regon": None if key.startswith("brand:") else (regon or None), "station_names": set(), "regions": set(), "has_petrol": False, "has_diesel": False, "has_lpg": False, "points": {}, }) if station_name: item["station_names"].add(station_name) region = _clean(row.get("wojewodztwo")).lower() if region: item["regions"].add(region) item["has_petrol"] |= bool(row.get("benzynySilnikowe")) item["has_diesel"] |= bool(row.get("olejeNapedowe")) item["has_lpg"] |= bool(row.get("gazPlynnyLPG")) point_key, stored_dkn = _point_key(row, index) point = { "ure_dkn": stored_dkn, "station_name": station_name or brand, "street": _clean(row.get("infraUlica")), "street_number": _clean(row.get("infraNrLokalu")), "postal_code": _clean(row.get("infraKod")) or _clean(row.get("kod")), "city": _clean(row.get("infraPoczta")) or _clean(row.get("miejscowosc")) or _clean(row.get("poczta")), "region": region, "coordinates": _clean(row.get("wspolrzedne")), "has_petrol": bool(row.get("benzynySilnikowe")), "has_diesel": bool(row.get("olejeNapedowe")), "has_lpg": bool(row.get("gazPlynnyLPG")), } existing = item["points"].get(point_key) _merge_point(existing, point) if existing else item["points"].__setitem__(point_key, point) result = [] for item in grouped.values(): item["points"] = list(item["points"].values()) item["station_count"] = len(item["points"]) item["station_names"] = "|".join(sorted(item["station_names"], key=str.casefold)) item["regions"] = "|".join(sorted(item["regions"], key=str.casefold)) result.append(item) return sorted(result, key=lambda x: (x["brand_name"].casefold(), x["company_name"].casefold()))