113 lines
5.2 KiB
Python
113 lines
5.2 KiB
Python
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()))
|