import json from collections import defaultdict import sqlite3 import json from collections import defaultdict from data import ( ClosureInterval, ClosureSummary, ClosureUser, ClosureVAT, ClosureReportOut, ) def compute_closure_report(conn, table_ucty: str, table_clsrep: str | None=None, ucislo_st: str | None=None, ucislo_end: str | None=None, id_kas: str="") -> ClosureReportOut | None: if not table_clsrep: table_clsrep = table_ucty.replace("_ucty", "_clsrep") cur = conn.cursor() # ===================================================== # 1️⃣ URČENÍ STARTU # ===================================================== if not ucislo_st: # zjisti poslední uzávěrku cur.execute(f""" SELECT ucislo_end FROM "{table_clsrep}" WHERE id_kas=? ORDER BY clsrep_id DESC LIMIT 1 """, (id_kas,)) row = cur.fetchone() if row and row[0]: # další účet po poslední uzávěrce ucislo_st = row[0] else: # žádná uzávěrka → vezmi první existující účet cur.execute(f""" SELECT MIN(ucislo) FROM "{table_ucty}" WHERE id_kas=? AND closed_at IS NOT NULL AND TRIM(ucislo) != '' """, (id_kas,)) row = cur.fetchone() ucislo_st = row[0] if row else None # ===================================================== # 2️⃣ URČENÍ KONCE # ===================================================== if not ucislo_end: cur.execute(f""" SELECT MAX(ucislo) FROM "{table_ucty}" WHERE id_kas=? AND closed_at IS NOT NULL AND TRIM(ucislo) != '' """, (id_kas,)) row = cur.fetchone() ucislo_end = row[0] if row else None if not ucislo_st or not ucislo_end: return None # ===================================================== # 3️⃣ NAČTENÍ ÚČTŮ # ===================================================== cur.execute(f""" SELECT ucislo, closed_at, data FROM "{table_ucty}" WHERE id_kas=? AND closed_at IS NOT NULL AND TRIM(ucislo) != '' AND ucislo>=? AND ucislo<=? ORDER BY ucislo """, (id_kas, ucislo_st, ucislo_end)) rows = cur.fetchall() if not rows: return None # --- interval --- ucislo_first, closed_first, _ = rows[0] ucislo_last, closed_last, _ = rows[-1] # ===================================================== # 4️⃣ AGREGACE (stejná jako předtím) # ===================================================== by_payment = defaultdict(float) by_user_total = defaultdict(float) by_user_cash = defaultdict(float) by_vat = defaultdict(lambda: {"zaklad": 0.0, "dan": 0.0}) total_base = 0.0 total_payments = 0.0 count = 0 for ucislo, closed_at, data_json in rows: if not data_json: continue try: u = json.loads(data_json) except Exception: continue if not u.get("ucislo"): continue count += 1 autor = u.get("autor") or "UNKNOWN" base_val = u.get("total_base_currency") or 0.0 total_base += base_val by_user_total[autor] += base_val for p in u.get("platby", []) or []: code = p.get("code") or "UNKNOWN" suma = p.get("suma_czk") or 0.0 by_payment[code] += suma total_payments += suma if code == "CASH": by_user_cash[autor] += suma for d in u.get("dane", []) or []: rate = str(d.get("rate")) zaklad = d.get("zaklad") or 0.0 try: r = float(rate) dan = zaklad * (r - 1) except Exception: dan = 0.0 by_vat[rate]["zaklad"] += zaklad by_vat[rate]["dan"] += dan # ===================================================== # 5️⃣ SLOŽENÍ MODELU # ===================================================== interval = ClosureInterval( ucislo_od=ucislo_first, ucislo_do=ucislo_last, closed_at_od=closed_first, closed_at_do=closed_last, ) summary = ClosureSummary( pocet_uctu=count, total_base_currency=round(total_base, 2), total_payments=round(total_payments, 2), difference=round(total_base - total_payments, 2), ) users = { user: ClosureUser( total_base_currency=round(by_user_total[user], 2), hotovost=round(by_user_cash[user], 2), ) for user in by_user_total } vat = { rate: ClosureVAT( zaklad=round(v["zaklad"], 2), dan=round(v["dan"], 2), celkem=round(v["zaklad"] + v["dan"], 2), ) for rate, v in by_vat.items() } return ClosureReportOut( blocked_by="", clsrep_no=None, created_at=None, interval=interval, summary=summary, platby={k: round(v, 2) for k, v in by_payment.items()}, uzivatele=users, dph=vat, ) import sqlite3 from kivy.app import App from kivy.uix.boxlayout import BoxLayout import kivy_printer class TestApp(App): def build(self): with sqlite3.connect("testVIII.db") as conn: rep = compute_closure_report( conn, table_ucty="00001_ucty", #table_clsrep="00001_clsrep", #ucislo_st="01000435", #ucislo_end="01000500", id_kas="01" ) if rep: print(rep.model_dump_json(indent=4, ensure_ascii=False)) kivy_printer.show_clsrep_preview(rep.model_dump()) else: print("Uzávěrka je prázdná.") return BoxLayout() # dummy root if __name__ == "__main__": TestApp().run()