#!/usr/bin/env python3 # -*- coding: utf-8 -*- import sys import urllib.parse import qrcode import fdb from pathlib import Path from datetime import datetime from PIL import Image, ImageTk import customtkinter as ctk from tkinter import messagebox # ================================ # ⚙️ Default Configuration # ================================ ACCOUNTS = { "2100046291/2010": "CZ1720100000002100046291", "2800046620/2010": "CZ7520100000002800046620", } CURRENCY = "CZK" OUTPUT_DIR = Path("QRPlatby") OUTPUT_DIR.mkdir(exist_ok=True) # Firebird připojení DB_DSN = r'localhost:c:\medicus 3\data\medicus.fdb' DB_USER = 'SYSDBA' DB_PASSWORD = 'masterkey' DB_CHARSET = 'win1250' # Default values (can be overridden by arguments) PRIJMENI = "Buzalka" JMENO = "Vladimír" RODCIS = "730928104" # ================================ # 💬 Argument Handling # ================================ if len(sys.argv) >= 4: JMENO = sys.argv[1] PRIJMENI = sys.argv[2] RODCIS = sys.argv[3] elif len(sys.argv) == 2 and sys.argv[1] in ("-h", "--help"): print("Usage: QRPlatbaApp.py JMENO PRIJMENI RODCIS") sys.exit(0) # ================================ # 💉 Items to Pay – načteno z Medicusu # ================================ def nacti_polozky(): """Načte ceník z Medicusu seřazený podle KOD (pořadového čísla).""" try: conn = fdb.connect(dsn=DB_DSN, user=DB_USER, password=DB_PASSWORD, charset=DB_CHARSET) cur = conn.cursor() cur.execute("SELECT V.KOD, V.NAZEV, V.CENA FROM VLV_SEL(NULL, NULL, NULL) V ORDER BY V.KOD") rows = cur.fetchall() conn.close() # Vrátí OrderedDict: název -> cena (float) return {row[1].strip(): float(row[2]) for row in rows if row[2] is not None} except Exception as e: messagebox.showerror("Chyba databáze", f"Nepodařilo se načíst ceník z Medicusu:\n{e}") return {} ITEMS = nacti_polozky() # ================================ # 🧩 Helper # ================================ def create_spayd(iban, amount, vs, msg, currency="CZK"): msg_encoded = urllib.parse.quote(msg, safe="$%*+-.:/") return f"SPD*1.0*ACC:{iban}*AM:{amount:.2f}*CC:{currency}*X-VS:{vs}*MSG:{msg_encoded}" # ================================ # 🪟 GUI Class # ================================ class QRPlatbaApp(ctk.CTk): def __init__(self): super().__init__() self.title("QR Platba – Ordinace MUDr. Buzalková") self.geometry("520x680") self.minsize(480, 480) self.resizable(True, True) ctk.set_appearance_mode("light") ctk.set_default_color_theme("blue") frame = ctk.CTkFrame(self, corner_radius=10) frame.pack(expand=True, fill="both", padx=20, pady=20) ctk.CTkLabel(frame, text="Generátor QR Platby", font=("Arial", 20, "bold")).pack(pady=(8, 10)) # 👤 Patient Info patient = ctk.CTkFrame(frame, corner_radius=8) patient.pack(fill="x", pady=(0, 8), padx=10) for text in [f"Příjmení: {PRIJMENI}", f"Jméno: {JMENO}", f"Rodné číslo: {RODCIS}"]: ctk.CTkLabel(patient, text=text, font=("Arial", 12)).pack(anchor="w", padx=10, pady=1) # 💰 Payment Section pay = ctk.CTkFrame(frame, corner_radius=8) pay.pack(fill="x", pady=(0, 8), padx=10) ctk.CTkLabel(pay, text="Vyberte položku k úhradě:", font=("Arial", 12, "bold")).pack(anchor="w", padx=10, pady=(6, 3)) self.display_items = [f"{name} ({price:.0f} Kč)" for name, price in ITEMS.items()] self.item_map = {f"{name} ({price:.0f} Kč)": name for name, price in ITEMS.items()} self.selected_item = ctk.StringVar(value=self.display_items[0]) self.combo = ctk.CTkOptionMenu( pay, variable=self.selected_item, values=self.display_items, font=("Arial", 12), command=self.on_change ) self.combo.pack(fill="x", padx=10) self.amount_label = ctk.CTkLabel(pay, text="", font=("Arial", 12, "italic")) self.amount_label.pack(anchor="e", padx=10, pady=(3, 6)) # 🏦 Account Selection acc = ctk.CTkFrame(frame, corner_radius=8) acc.pack(fill="x", pady=(0, 8), padx=10) ctk.CTkLabel(acc, text="Číslo účtu:", font=("Arial", 12, "bold")).pack(anchor="w", padx=10, pady=(6, 3)) self.selected_account = ctk.StringVar(value=list(ACCOUNTS.keys())[0]) ctk.CTkOptionMenu( acc, variable=self.selected_account, values=list(ACCOUNTS.keys()), font=("Arial", 12), command=self.on_change ).pack(fill="x", padx=10, pady=(0, 6)) ctk.CTkButton(frame, text="Uložit QR kód", font=("Arial", 13, "bold"), height=40, command=self.ulozit_qr).pack(pady=6) self.qr_label = ctk.CTkLabel(frame, text="") self.qr_label.pack(pady=6) ctk.CTkLabel(frame, text="© Ordinace MUDr. Buzalková | QR Platba dle ČBA v1.2", font=("Arial", 10), text_color="#666").pack(side="bottom", pady=(10, 0)) self.center_window() # QR automaticky při startu self.after(100, self.refresh_qr) # ================================ # 🪟 Center Window # ================================ def center_window(self): self.update_idletasks() width = self.winfo_width() height = self.winfo_height() screen_width = self.winfo_screenwidth() screen_height = self.winfo_screenheight() x = int((screen_width / 2) - (width / 2)) y = int((screen_height / 2) - (height / 2)) self.geometry(f"{width}x{height}+{x}+{y}") # ================================ # 💸 Update and Generate # ================================ def _get_current(self): """Vrátí (item, iban, spayd) pro aktuální výběr.""" display_item = self.selected_item.get() item = self.item_map[display_item] iban = ACCOUNTS[self.selected_account.get()] spayd = create_spayd(iban, ITEMS[item], RODCIS, f"{PRIJMENI} {JMENO} – {item}", CURRENCY) return item, iban, spayd def on_change(self, _=None): """Při změně dropdownu – aktualizuj částku i QR.""" self.refresh_qr() def refresh_qr(self): """Zobrazí QR kód pro aktuální výběr (bez uložení).""" item, _, spayd = self._get_current() self.amount_label.configure(text=f"Částka: {ITEMS[item]:.2f} Kč") img = qrcode.make(spayd) img_resized = img.resize((200, 200), Image.LANCZOS) qr_tk = ImageTk.PhotoImage(img_resized) self.qr_label.configure(image=qr_tk) self.qr_label.image = qr_tk def ulozit_qr(self): """Uloží QR kód do souboru a informuje uživatele.""" item, _, spayd = self._get_current() img = qrcode.make(spayd) filename = f"{PRIJMENI}_{JMENO}_{datetime.now():%Y%m%d_%H%M%S}.png" out_path = OUTPUT_DIR / filename img.save(out_path) messagebox.showinfo("Uloženo", f"QR kód uložen:\n{out_path}") # ================================ # 🚀 Main # ================================ if __name__ == "__main__": app = QRPlatbaApp() app.mainloop()