feat: /api/v2/analiza/* endpoints - sport analytics backend

This commit is contained in:
Damir Radulic
2026-05-16 00:28:12 +02:00
parent 7ca5d7d94e
commit aca5051418
1355 changed files with 321891 additions and 4128 deletions
+152
View File
@@ -0,0 +1,152 @@
#!/usr/bin/env python3
"""
RNO Import — sve PGZ sport organizacije u DB
Filter: Županija=Primorsko-goranska, šifra djelatnosti sport (85,90,93)
"""
import psycopg2, psycopg2.extras, os, sys
from datetime import datetime
DSN = f"host=10.10.0.2 port=6432 dbname=rinet_v3 user=rinet password={os.environ['DB_PASSWORD']}"
DIR = "/opt/pgz-sport/_downloads/CSV"
LOG = "/opt/pgz-sport/logs/rno_import.log"
os.makedirs("/opt/pgz-sport/logs", exist_ok=True)
def log(msg):
ts = datetime.now().strftime("%H:%M:%S")
line = f"[{ts}] {msg}"
print(line, flush=True)
with open(LOG, "a") as f: f.write(line+"\n")
conn = psycopg2.connect(DSN)
conn.autocommit = True
cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
# Create table
cur.execute("""
CREATE TABLE IF NOT EXISTS pgz_sport.rno_organizacije (
rno_broj TEXT PRIMARY KEY,
datum_upisa DATE,
datum_brisanja DATE,
datum_izmjene DATE,
naziv TEXT NOT NULL,
naziv_kratki TEXT,
oib TEXT,
maticni_broj TEXT,
pravni_oblik TEXT,
adresa TEXT,
postanski_broj TEXT,
mjesto TEXT,
sifra_djelatnosti TEXT,
racun TEXT,
stat_oznaka TEXT,
osoba_kontakt TEXT,
zupanija TEXT,
telefon TEXT,
email TEXT,
web TEXT,
obveza_dvojnog BOOLEAN,
aktivna BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT now()
)
""")
log("Table created/exists")
# Parse Organizacija.txt
log("Parsing Organizacija.txt...")
pgz_sport = []
total = 0
skipped = 0
SPORT_CODES = {"9311","9312","9313","9319","9321","9329","931","932","93","8551","8552","9004","9001","8553"}
with open(f"{DIR}/Organizacija.txt", encoding="utf-16-le", errors="replace") as f:
headers = f.readline().strip("\ufeff").strip().split("$")
h = {v: i for i, v in enumerate(headers)}
for line in f:
cols = line.strip().split("$")
if len(cols) < 20:
continue
total += 1
def g(key):
idx = h.get(key)
return cols[idx].strip() if idx is not None and idx < len(cols) else ""
zupanija = g("20. Županija")
sifra = g("16. Šifra djelatnosti")
naziv = g("05. Naziv neprofitne organizacije")
# Filter: PGZ county + sport/physical activity djelatnost codes
is_pgz = "primorsko" in zupanija.lower() or "pgž" in zupanija.lower() or "goranska" in zupanija.lower()
is_sport = any(sifra.startswith(s) for s in ["93","855","930","855"])
# Also catch by name keywords
sport_keywords = ["sport","klup","klub","savez","planinar","ronilac","jedrilic","plivac","atletik","košark","rukom","odbojk","nogom","tenis","boksac","boksa","karate","judo","strijelj","bicikl","vater","plivali","strelichar","ribolov","lov","šah","šahovsk"]
is_sport_name = any(k in naziv.lower() for k in sport_keywords)
if is_pgz and (is_sport or is_sport_name):
def parse_date(s):
if not s or not s.strip(): return None
try:
parts = s.strip().rstrip(".").split(".")
if len(parts) == 3:
return f"{parts[2]}-{parts[1]}-{parts[0]}"
except: pass
return None
pgz_sport.append((
g("01. RNO broj"),
parse_date(g("02. Datum upisa u registar")),
parse_date(g("03. Datum brisanja iz registra")),
parse_date(g("04. Datum zadnje izmjene")),
naziv,
g("06. Skraćeni naziv neprofitne organizacije"),
g("07. OIB"),
g("08. Matični broj"),
g("09. Pravno ustrojbeni oblik"),
g("13. Adresa sjedišta"),
g("14. Poštanski broj"),
g("15. Mjesto"),
sifra,
g("17. Račun"),
g("18. Statistička oznaka grada/općine"),
g("19. Osoba za kontakt"),
zupanija,
g("21. Telefon"),
g("23. Email"),
g("24. Web stranica"),
g("03. Datum brisanja iz registra") == "", # aktivna
))
log(f"Parsed {total} rows, found {len(pgz_sport)} PGZ sport orgs")
# Insert
psycopg2.extras.execute_batch(cur, """
INSERT INTO pgz_sport.rno_organizacije
(rno_broj, datum_upisa, datum_brisanja, datum_izmjene, naziv, naziv_kratki,
oib, maticni_broj, pravni_oblik, adresa, postanski_broj, mjesto,
sifra_djelatnosti, racun, stat_oznaka, osoba_kontakt, zupanija,
telefon, email, web, aktivna)
VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
ON CONFLICT (rno_broj) DO UPDATE SET
datum_izmjene=EXCLUDED.datum_izmjene, naziv=EXCLUDED.naziv,
email=EXCLUDED.email, web=EXCLUDED.web, aktivna=EXCLUDED.aktivna
""", pgz_sport, page_size=500)
cur.execute("SELECT COUNT(*) as n FROM pgz_sport.rno_organizacije")
n = cur.fetchone()["n"]
log(f"✅ RNO done: {n} PGZ sport org u DB")
# Sample
cur.execute("""
SELECT naziv, oib, mjesto, sifra_djelatnosti
FROM pgz_sport.rno_organizacije
WHERE aktivna=true
ORDER BY naziv
LIMIT 10
""")
for row in cur.fetchall():
log(f" {row['naziv'][:40]} | {row['mjesto']} | {row['oib']}")
conn.close()