Files

112 lines
4.4 KiB
Python
Raw Permalink Normal View History

"""Import wholesalers from OpenStreetMap."""
from __future__ import annotations
import json
import time
import urllib.parse
import urllib.request
from typing import Any, Optional
from app.db import execute, fetch_one
OVERPASS_URL = "https://overpass.kumi.systems/api/interpreter"
WHOLESALE_BRANDS = [
"Sligro", "Hanos", "Makro", "Bidfood", "Metro", "Van Gelder",
"De Klok", "Hoogvliet Groothandel",
]
def _fetch(query: str) -> list[dict[str, Any]]:
data = urllib.parse.urlencode({"data": query}).encode()
req = urllib.request.Request(OVERPASS_URL, data=data, method="POST")
with urllib.request.urlopen(req, timeout=300) as resp:
payload = json.loads(resp.read().decode())
return payload.get("elements", [])
def _coords(el: dict[str, Any]) -> tuple[Optional[float], Optional[float]]:
if el.get("type") == "node":
return el.get("lat"), el.get("lon")
c = el.get("center") or {}
return c.get("lat"), c.get("lon")
def _normalize_pc(raw: Optional[str]) -> str:
if not raw:
return "0000AA"
c = raw.strip().upper().replace(" ", "")
return c if len(c) >= 6 else "0000AA"
def import_wholesalers() -> dict[str, Any]:
query = (
'[out:json][timeout:120];area["ISO3166-1"="NL"]->.nl;('
'node["shop"="wholesale"](area.nl);way["shop"="wholesale"](area.nl);'
'node["shop"="cash_and_carry"](area.nl);way["shop"="cash_and_carry"](area.nl);'
'node["wholesale"](area.nl);way["wholesale"](area.nl);'
');out center tags;'
)
elements: list[dict[str, Any]] = []
try:
elements = _fetch(query)
except Exception:
# Fallback: smaller per-brand queries
for brand in WHOLESALE_BRANDS[:4]:
q = (
f'[out:json][timeout:60];area["ISO3166-1"="NL"]->.nl;('
f'node["name"~"{brand}",i](area.nl);way["name"~"{brand}",i](area.nl);'
f');out center tags;'
)
try:
elements.extend(_fetch(q))
time.sleep(2)
except Exception:
continue
inserted = updated = 0
seen: set[str] = set()
for el in elements:
tags = el.get("tags") or {}
lat, lon = _coords(el)
if lat is None:
continue
external_id = f"osm:{el.get('type')}:{el.get('id')}"
if external_id in seen:
continue
seen.add(external_id)
name = tags.get("name") or tags.get("brand") or "Groothandel"
brand = tags.get("brand") or name.split()[0]
street = tags.get("addr:street") or ""
hn = tags.get("addr:housenumber") or ""
address = f"{street} {hn}".strip() or name
city = tags.get("addr:city") or tags.get("addr:town") or "Onbekend"
existing = fetch_one("SELECT id FROM wholesalers WHERE external_id = %s", (external_id,))
if existing:
execute(
"""UPDATE wholesalers SET name=%s, address=%s, postcode=%s, city=%s, province=%s,
latitude=%s, longitude=%s, phone=%s, email=%s, website=%s, last_updated=NOW()
WHERE external_id=%s""",
(
name[:255], address, _normalize_pc(tags.get("addr:postcode")), city[:100],
(tags.get("addr:province") or "")[:50], lat, lon,
(tags.get("phone") or "")[:20], (tags.get("email") or "")[:255],
(tags.get("website") or "")[:255], external_id,
),
)
updated += 1
else:
execute(
"""INSERT INTO wholesalers (external_id, name, address, postcode, city, province,
latitude, longitude, phone, email, website, data_source, product_categories)
VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,'openstreetmap',%s)""",
(
external_id, name[:255], address, _normalize_pc(tags.get("addr:postcode")),
city[:100], (tags.get("addr:province") or "")[:50], lat, lon,
(tags.get("phone") or "")[:20], (tags.get("email") or "")[:255],
(tags.get("website") or "")[:255], [brand],
),
)
inserted += 1
total = fetch_one("SELECT COUNT(*) AS n FROM wholesalers")
return {"fetched": len(elements), "inserted": inserted, "updated": updated, "total": int((total or {}).get("n") or 0)}