notebookvb
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
@@ -0,0 +1,176 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
from pathlib import Path
|
||||
from datetime import date
|
||||
import customtkinter as ctk
|
||||
from tkinter import messagebox
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent.parent
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from Knihovny.vzpb2b_client import VZPB2BClient
|
||||
from Knihovny.EmailMessagingGraph import send_mail
|
||||
|
||||
EMAIL_CHYBY = "vladimir.buzalka@buzalka.cz"
|
||||
|
||||
def _zpracuj_chybu(exc: BaseException):
|
||||
"""Zobrazí chybový dialog a pošle email. Nikdy nevyhodí výjimku."""
|
||||
detail = traceback.format_exc()
|
||||
try:
|
||||
root = ctk.CTk()
|
||||
root.withdraw()
|
||||
messagebox.showerror("Chyba — KdoJeLekarApp",
|
||||
f"Nastala chyba:\n{exc}\n\nByla odeslána na email.")
|
||||
root.destroy()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
send_mail(
|
||||
to=EMAIL_CHYBY,
|
||||
subject=f"KdoJeLekarApp — chyba ({date.today().isoformat()})",
|
||||
body=(f"Pacient: {PRIJMENI} {JMENO} / RC: {RODCIS}\n\n{detail}"),
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ── KONFIGURACE ───────────────────────────────────────────────────────────────
|
||||
|
||||
PFX_PATH = PROJECT_ROOT / "Insurance" / "Certificates" / "picka.pfx"
|
||||
PFX_PASS = "Vlado7309208104+"
|
||||
|
||||
ODBORNOSTI_NAZVY = {
|
||||
"001": "Praktický lékař",
|
||||
"002": "Gynekolog",
|
||||
"014": "Stomatolog",
|
||||
}
|
||||
|
||||
# Default hodnoty (přepíší argumenty z Medicusu)
|
||||
JMENO = "Michaela"
|
||||
PRIJMENI = "Buzalková"
|
||||
RODCIS = "7155111821"
|
||||
|
||||
# ── ARGUMENTY Z MEDICUSU ─────────────────────────────────────────────────────
|
||||
|
||||
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: KdoJeLekarApp.py JMENO PRIJMENI RODCIS")
|
||||
sys.exit(0)
|
||||
|
||||
# ── VZP DOTAZ ────────────────────────────────────────────────────────────────
|
||||
|
||||
def zjisti_lekare(rodcis: str) -> list[dict]:
|
||||
vzp = VZPB2BClient("prod", str(PFX_PATH), PFX_PASS)
|
||||
xml = vzp.registrace_lekare(rc=rodcis, k_datu=date.today().isoformat())
|
||||
return vzp.parse_registrace_lekare(xml)
|
||||
|
||||
# ── GUI ───────────────────────────────────────────────────────────────────────
|
||||
|
||||
class KdoJeLekarApp(ctk.CTk):
|
||||
def __init__(self, zaznamy: list[dict]):
|
||||
super().__init__()
|
||||
self.title("Registrující lékař — VZP B2B")
|
||||
self.geometry("560x560")
|
||||
self.minsize(480, 380)
|
||||
self.resizable(True, True)
|
||||
|
||||
ctk.set_appearance_mode("light")
|
||||
ctk.set_default_color_theme("blue")
|
||||
|
||||
outer = ctk.CTkFrame(self, corner_radius=10)
|
||||
outer.pack(expand=True, fill="both", padx=20, pady=20)
|
||||
outer.columnconfigure(0, weight=1)
|
||||
|
||||
ctk.CTkLabel(outer, text="Registrující lékaři",
|
||||
font=("Arial", 20, "bold")).grid(row=0, column=0, pady=(10, 8))
|
||||
|
||||
# Pacient
|
||||
poj = zaznamy[0].get("poj_zkratka", "") if zaznamy else ""
|
||||
pac = ctk.CTkFrame(outer, corner_radius=8)
|
||||
pac.grid(row=1, column=0, sticky="ew", padx=10, pady=(0, 8))
|
||||
ctk.CTkFrame(pac, height=6, fg_color="transparent").pack()
|
||||
for label, value in [
|
||||
("Příjmení:", PRIJMENI),
|
||||
("Jméno:", JMENO),
|
||||
("Rodné číslo:", RODCIS),
|
||||
("Pojišťovna:", poj),
|
||||
]:
|
||||
row = ctk.CTkFrame(pac, fg_color="transparent")
|
||||
row.pack(fill="x", padx=12, pady=0)
|
||||
ctk.CTkLabel(row, text=label, font=("Arial", 12, "bold"),
|
||||
width=100, anchor="w", height=20).pack(side="left", pady=0)
|
||||
ctk.CTkLabel(row, text=value, font=("Arial", 12),
|
||||
anchor="w", height=20).pack(side="left", pady=0)
|
||||
ctk.CTkFrame(pac, height=4, fg_color="transparent").pack()
|
||||
|
||||
# Karty lékařů
|
||||
cards = ctk.CTkFrame(outer, corner_radius=0, fg_color="transparent")
|
||||
cards.grid(row=2, column=0, sticky="ew", padx=10)
|
||||
|
||||
if not zaznamy:
|
||||
ctk.CTkLabel(cards, text="VZP neeviduje žádného registrujícího lékaře.",
|
||||
font=("Arial", 13), text_color="#c0392b").pack(pady=20)
|
||||
else:
|
||||
for z in zaznamy:
|
||||
self._render_zaznam(cards, z)
|
||||
|
||||
ctk.CTkLabel(outer,
|
||||
text=f"Dotaz k datu: {date.today().isoformat()} | © Ordinace MUDr. Buzalková",
|
||||
font=("Arial", 10), text_color="#888").grid(row=3, column=0, pady=(4, 6))
|
||||
|
||||
self._autosize()
|
||||
|
||||
def _render_zaznam(self, parent, z: dict):
|
||||
kod = z.get("kod_odbornosti", "")
|
||||
nazev_odb = ODBORNOSTI_NAZVY.get(kod, f"Odbornost {kod}")
|
||||
lekar = z.get("nazev_zzz") or "—"
|
||||
pracoviste = z.get("nazev_lekare") or "—"
|
||||
od = z.get("datum_zahajeni") or "?"
|
||||
do = z.get("datum_ukonceni") or "?"
|
||||
|
||||
card = ctk.CTkFrame(parent, corner_radius=8, fg_color="#eaf4fb")
|
||||
card.pack(fill="x", pady=4)
|
||||
|
||||
ctk.CTkLabel(card, text=f" {nazev_odb} ({kod})",
|
||||
font=("Arial", 13, "bold"), text_color="#1a5276").pack(anchor="w", padx=10, pady=(6, 1))
|
||||
|
||||
for label, value in [
|
||||
("Lékař:", lekar),
|
||||
("Pracoviště:", pracoviste),
|
||||
("ICZ / ICP:", f"{z.get('ICZ') or '—'} / {z.get('ICP') or '—'}"),
|
||||
("Registrace:", z.get("datum_registrace") or "?"),
|
||||
("Platí od:", od),
|
||||
("Platí do:", "bez omezení" if do == "3000-01-01" else do),
|
||||
]:
|
||||
row = ctk.CTkFrame(card, fg_color="transparent")
|
||||
row.pack(fill="x", padx=14, pady=0)
|
||||
ctk.CTkLabel(row, text=label, font=("Arial", 11, "bold"),
|
||||
width=90, anchor="w", height=20).pack(side="left", pady=0)
|
||||
ctk.CTkLabel(row, text=value, font=("Arial", 11),
|
||||
anchor="w", height=20).pack(side="left", pady=0)
|
||||
ctk.CTkFrame(card, height=4, fg_color="transparent").pack()
|
||||
|
||||
|
||||
def _autosize(self):
|
||||
self.update_idletasks()
|
||||
w = 560
|
||||
h = self.winfo_reqheight()
|
||||
sw, sh = self.winfo_screenwidth(), self.winfo_screenheight()
|
||||
self.geometry(f"{w}x{h}+{(sw-w)//2}+{(sh-h)//2}")
|
||||
|
||||
|
||||
# ── MAIN ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
zaznamy = zjisti_lekare(RODCIS)
|
||||
app = KdoJeLekarApp(zaznamy)
|
||||
app.mainloop()
|
||||
except Exception as exc:
|
||||
_zpracuj_chybu(exc)
|
||||
sys.exit(1)
|
||||
@@ -0,0 +1,38 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
a = Analysis(
|
||||
['KdoJeLekarApp.py'],
|
||||
pathex=[r'U:\OrdinaceProjekt'],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=['customtkinter', 'msal', 'requests_pkcs12'],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='KdoJeLekarApp',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon=['KdoJeLekarApp.ico'],
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,260 @@
|
||||
|
||||
This file lists modules PyInstaller was not able to find. This does not
|
||||
necessarily mean these modules are required for running your program. Both
|
||||
Python's standard library and 3rd-party Python packages often conditionally
|
||||
import optional modules, some of which may be available only on certain
|
||||
platforms.
|
||||
|
||||
Types of import:
|
||||
* top-level: imported at the top-level - look at these first
|
||||
* conditional: imported within an if-statement
|
||||
* delayed: imported within a function
|
||||
* optional: imported within a try-except-statement
|
||||
|
||||
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
|
||||
tracking down the missing module yourself. Thanks!
|
||||
|
||||
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional), http.server (delayed, optional), netrc (delayed, conditional), getpass (delayed)
|
||||
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional)
|
||||
missing module named _posixsubprocess - imported by subprocess (conditional), multiprocessing.util (delayed)
|
||||
missing module named fcntl - imported by subprocess (optional)
|
||||
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
missing module named urllib.quote_plus - imported by urllib (optional), msal.oauth2cli.oauth2 (optional)
|
||||
missing module named urllib.urlencode - imported by urllib (optional), msal.oauth2cli.oauth2 (optional), msal.oauth2cli.authcode (optional)
|
||||
missing module named posix - imported by os (conditional, optional), shutil (conditional), importlib._bootstrap_external (conditional), posixpath (optional)
|
||||
missing module named resource - imported by posix (top-level)
|
||||
missing module named _posixshmem - imported by multiprocessing.resource_tracker (conditional), multiprocessing.shared_memory (conditional)
|
||||
missing module named _scproxy - imported by urllib.request (conditional)
|
||||
missing module named termios - imported by tty (top-level), getpass (optional)
|
||||
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.get_context - imported by multiprocessing (top-level), multiprocessing.pool (top-level), multiprocessing.managers (top-level), multiprocessing.sharedctypes (top-level)
|
||||
missing module named multiprocessing.TimeoutError - imported by multiprocessing (top-level), multiprocessing.pool (top-level)
|
||||
missing module named multiprocessing.set_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named multiprocessing.get_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named pyimod02_importers - imported by C:\Python312\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed)
|
||||
missing module named cryptography.x509.UnsupportedExtension - imported by cryptography.x509 (optional), urllib3.contrib.pyopenssl (optional)
|
||||
missing module named bcrypt - imported by cryptography.hazmat.primitives.serialization.ssh (optional)
|
||||
missing module named 'OpenSSL.crypto' - imported by urllib3.contrib.pyopenssl (delayed, conditional)
|
||||
missing module named OpenSSL - imported by urllib3.contrib.pyopenssl (top-level)
|
||||
missing module named chardet - imported by requests (optional)
|
||||
missing module named asyncio.DefaultEventLoopPolicy - imported by asyncio (delayed, conditional), asyncio.events (delayed, conditional)
|
||||
missing module named annotationlib - imported by typing_extensions (conditional)
|
||||
missing module named 'pyodide.ffi' - imported by urllib3.contrib.emscripten.fetch (delayed, optional)
|
||||
missing module named pyodide - imported by urllib3.contrib.emscripten.fetch (top-level)
|
||||
missing module named js - imported by urllib3.contrib.emscripten.fetch (top-level)
|
||||
missing module named 'h2.events' - imported by urllib3.http2.connection (top-level)
|
||||
missing module named 'h2.connection' - imported by urllib3.http2.connection (top-level)
|
||||
missing module named h2 - imported by urllib3.http2.connection (top-level)
|
||||
missing module named zstandard - imported by urllib3.util.request (optional), urllib3.response (optional)
|
||||
missing module named compression - imported by urllib3.util.request (optional), urllib3.response (optional)
|
||||
missing module named brotli - imported by urllib3.util.request (optional), urllib3.response (optional)
|
||||
missing module named brotlicffi - imported by urllib3.util.request (optional), urllib3.response (optional)
|
||||
missing module named socks - imported by urllib3.contrib.socks (optional)
|
||||
missing module named dummy_threading - imported by requests.cookies (optional)
|
||||
missing module named simplejson - imported by requests.compat (conditional, optional)
|
||||
missing module named vms_lib - imported by platform (delayed, optional)
|
||||
missing module named 'java.lang' - imported by platform (delayed, optional)
|
||||
missing module named java - imported by platform (delayed)
|
||||
missing module named _winreg - imported by platform (delayed, optional)
|
||||
missing module named BaseHTTPServer - imported by msal.oauth2cli.authcode (optional)
|
||||
missing module named urlparse - imported by msal.oauth2cli.oauth2 (optional), msal.oauth2cli.authcode (optional), msal.authority (optional), msal.mex (optional), msal.cloudshell (optional), msal.auth_scheme (optional)
|
||||
missing module named collections.MutableMapping - imported by collections (optional), msal.individual_cache (optional)
|
||||
missing module named pymsalruntime - imported by msal.broker (optional), msal.application (delayed, conditional)
|
||||
missing module named msal_extensions - imported by msal.application (delayed, optional)
|
||||
missing module named _dummy_thread - imported by numpy._core.arrayprint (optional)
|
||||
missing module named 'numpy_distutils.cpuinfo' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
|
||||
missing module named 'numpy_distutils.fcompiler' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
|
||||
missing module named 'numpy_distutils.command' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
|
||||
missing module named numpy_distutils - imported by numpy.f2py.diagnose (delayed, optional)
|
||||
missing module named psutil - imported by numpy.testing._private.utils (delayed, optional)
|
||||
missing module named readline - imported by cmd (delayed, conditional, optional), code (delayed, conditional, optional), pdb (delayed, optional)
|
||||
missing module named win32pdh - imported by numpy.testing._private.utils (delayed, conditional)
|
||||
missing module named _typeshed - imported by numpy.random.bit_generator (top-level)
|
||||
missing module named numpy.random.RandomState - imported by numpy.random (top-level), numpy.random._generator (top-level)
|
||||
missing module named threadpoolctl - imported by numpy.lib._utils_impl (delayed, optional)
|
||||
missing module named numpy._core.zeros - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.vstack - imported by numpy._core (top-level), numpy.lib._shape_base_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.void - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.vecmat - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.vecdot - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.ushort - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.unsignedinteger - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ulonglong - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ulong - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.uintp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.uintc - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.uint64 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.uint32 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.uint16 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.uint - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ubyte - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.trunc - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.true_divide - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.transpose - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._function_base_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.trace - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.timedelta64 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.tensordot - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.tanh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.tan - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.swapaxes - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.sum - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.subtract - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.str_ - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.square - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.sqrt - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.spacing - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.sort - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.sinh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.single - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.signedinteger - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.signbit - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.sign - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.short - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.rint - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.right_shift - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.result_type - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.remainder - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.reciprocal - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.radians - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.rad2deg - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.prod - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.power - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.positive - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.pi - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.outer - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.ones - imported by numpy._core (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.object_ - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.number - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.not_equal - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.newaxis - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.negative - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ndarray - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy.lib._utils_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.multiply - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.moveaxis - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.modf - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.mod - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.minimum - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.maximum - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.max - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.matvec - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.matrix_transpose - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.matmul - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.longlong - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.longdouble - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.long - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logical_xor - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logical_or - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logical_not - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logical_and - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logaddexp2 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logaddexp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.log2 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.log1p - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.log - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.linspace - imported by numpy._core (top-level), numpy.lib._index_tricks_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.less_equal - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.less - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.left_shift - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ldexp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.lcm - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.isscalar - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.isnat - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional)
|
||||
missing module named numpy._core.isnan - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.isfinite - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.intp - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.integer - imported by numpy._core (conditional), numpy (conditional), numpy.fft._helper (top-level)
|
||||
missing module named numpy._core.intc - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.int64 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.int32 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.int16 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.int8 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.inf - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.inexact - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.iinfo - imported by numpy._core (top-level), numpy.lib._twodim_base_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.hypot - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.hstack - imported by numpy._core (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.heaviside - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.half - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.greater_equal - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.greater - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.gcd - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.frompyfunc - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.frexp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.fmod - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.fmin - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.fmax - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.floor_divide - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.floor - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.floating - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.float_power - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.float32 - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.float16 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.finfo - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.fabs - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.expm1 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.exp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.euler_gamma - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.errstate - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.equal - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.empty_like - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.empty - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy.fft._helper (top-level)
|
||||
missing module named numpy._core.e - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.double - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.dot - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.divmod - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.divide - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.diagonal - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.degrees - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.deg2rad - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.datetime64 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.csingle - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.cross - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.count_nonzero - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.cosh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.cos - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.copysign - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.conjugate - imported by numpy._core (conditional), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.conj - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.complexfloating - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.complex64 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.clongdouble - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.character - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ceil - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.cdouble - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.cbrt - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bytes_ - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.byte - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bool_ - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bitwise_xor - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bitwise_or - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bitwise_count - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bitwise_and - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.atleast_3d - imported by numpy._core (top-level), numpy.lib._shape_base_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.atleast_2d - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.atleast_1d - imported by numpy._core (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.asarray - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._array_utils_impl (top-level), numpy (conditional), numpy.fft._helper (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.asanyarray - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.array_repr - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional)
|
||||
missing module named numpy._core.array2string - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.array - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.argsort - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.arctanh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arctan2 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arctan - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arcsinh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arcsin - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arccosh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arccos - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arange - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy.fft._helper (top-level)
|
||||
missing module named numpy._core.amin - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.amax - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.all - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.add - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named yaml - imported by numpy.__config__ (delayed)
|
||||
missing module named numpy._distributor_init_local - imported by numpy (optional), numpy._distributor_init (optional)
|
||||
missing module named olefile - imported by PIL.FpxImagePlugin (top-level), PIL.MicImagePlugin (top-level)
|
||||
missing module named defusedxml - imported by PIL.Image (optional)
|
||||
missing module named PyObjCTools - imported by darkdetect._mac_detect (optional)
|
||||
missing module named Foundation - imported by darkdetect._mac_detect (optional)
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,141 @@
|
||||
# QRPlatbaApp – QR kód pro platby
|
||||
|
||||
## Přehled
|
||||
|
||||
Aplikace **QRPlatbaApp** generuje QR kódy pro platby pacientů v ordinaci. Údaje o pacientovi jsou předávány z Medicusu, aplikace zobrazí okno s výběrem položky k úhradě a generuje QR kód ve formátu **SPAYD** (Czech Payment Standard).
|
||||
|
||||
## Soubory
|
||||
|
||||
- `QRPlatbaApp.py` — hlavní Python skript (customtkinter GUI)
|
||||
- `dist/QRPlatbaApp.exe` — kompilovaný spustitelný soubor (bez CMD okna)
|
||||
|
||||
## Technologie
|
||||
|
||||
- **Python 3.x** (nutný pouze pro vývoj, EXE běží bez Pythonu)
|
||||
- **customtkinter** — moderní GUI
|
||||
- **qrcode** — generování QR kódů
|
||||
- **pillow (PIL)** — manipulace s obrázky
|
||||
- **fdb** — připojení na Firebird DB (Medicus)
|
||||
|
||||
## Jak to funguje
|
||||
|
||||
### 1. Spouštění z Medicusu
|
||||
|
||||
Medicus předá údaje pacienta přes příkazový řádek do EXE:
|
||||
```
|
||||
QRPlatbaApp.exe %JMENO% %PRIJMENI% %RODCIS%
|
||||
```
|
||||
|
||||
### 2. Načtení ceníku
|
||||
|
||||
Skript se připojí na Medicus DB a načte ceník ze stored procedure `VLV_SEL`:
|
||||
```python
|
||||
cur.execute("SELECT V.KOD, V.NAZEV, V.CENA FROM VLV_SEL(NULL, NULL, NULL) V ORDER BY V.KOD")
|
||||
```
|
||||
|
||||
### 3. GUI okno
|
||||
|
||||
Zobrazí se okno s:
|
||||
- Údaji pacienta (jméno, příjmení, rodné číslo)
|
||||
- Výběrem položky k úhradě (dropdown)
|
||||
- Výběrem bankovního účtu (2 možnosti: Fio 2100046291/2010 nebo 2800046620/2010)
|
||||
- Tlačítko "Uložit QR kód"
|
||||
- QR kód (200x200px, SPAYD formát)
|
||||
|
||||
### 4. SPAYD formát
|
||||
|
||||
QR kód obsahuje:
|
||||
```
|
||||
SPD*1.0*ACC:CZ7520100000002800046620*AM:500.00*CC:CZK*X-VS:7309281045*MSG:Buzalka%20Vladimír%20–%20Poplatek
|
||||
```
|
||||
|
||||
- `ACC` — IBAN bankovního účtu
|
||||
- `AM` — částka (Kč)
|
||||
- `CC` — měna (CZK)
|
||||
- `X-VS` — variabilní symbol (rodné číslo pacienta)
|
||||
- `MSG` — zpráva (jméno + položka)
|
||||
|
||||
### 5. Uložení QR
|
||||
|
||||
Po kliknutí na "Uložit QR kód" se PNG vygeneruje do adresáře:
|
||||
```
|
||||
U:\OrdinaceProjekt\Medicus\QRCode\QRPlatby\Buzalka_Vladimír_20260510_143025.png
|
||||
```
|
||||
|
||||
## Konfigurace v Medicusu
|
||||
|
||||
V menu **Konfigurace > Externí programy** přidej nový záznam:
|
||||
|
||||
| Položka | Hodnota |
|
||||
|---------|---------|
|
||||
| **Kategorie** | Ostatní |
|
||||
| **Typ programu** | Externí program |
|
||||
| **Program** | `U:\OrdinaceProjekt\Medicus\QRCode\dist\QRPlatbaApp.exe` |
|
||||
| **Příkazový řádek** | `"U:\OrdinaceProjekt\Medicus\QRCode\dist\QRPlatbaApp.exe" %JMENO% %PRIJMENI% %RODCIS%` |
|
||||
| **Pacient** | ✓ (vyžaduje vybraného pacienta) |
|
||||
| **Menu** | QR Platba |
|
||||
|
||||
## Firebird DB připojení
|
||||
|
||||
```python
|
||||
DB_DSN = r'localhost:c:\medicus 3\data\medicus.fdb'
|
||||
DB_USER = 'SYSDBA'
|
||||
DB_PASSWORD = 'masterkey'
|
||||
DB_CHARSET = 'win1250'
|
||||
```
|
||||
|
||||
## Bankovní účty
|
||||
|
||||
```python
|
||||
ACCOUNTS = {
|
||||
"2100046291/2010": "CZ1720100000002100046291",
|
||||
"2800046620/2010": "CZ7520100000002800046620",
|
||||
}
|
||||
```
|
||||
|
||||
Oba účty jsou u Fio banky.
|
||||
|
||||
## Spouštění bez CMD okna
|
||||
|
||||
EXE soubor se zkompiloval pomocí PyInstalleru s parametrem `--windowed`, což zajistí spuštění bez zobrazení CMD okna. GUI se zobrazí přímo bez blikání.
|
||||
|
||||
## Příjmání argumentů
|
||||
|
||||
Python skript přijímá argumenty přesně z příkazového řádku:
|
||||
```python
|
||||
if len(sys.argv) >= 4:
|
||||
JMENO = sys.argv[1] # arg 1 z Medicusu (%JMENO%)
|
||||
PRIJMENI = sys.argv[2] # arg 2 z Medicusu (%PRIJMENI%)
|
||||
RODCIS = sys.argv[3] # arg 3 z Medicusu (%RODCIS%)
|
||||
```
|
||||
|
||||
## Ladění a opravy
|
||||
|
||||
Při chybách se informace vypíší v GUI (messagebox).
|
||||
|
||||
Pokud potřebuješ upravit zdrojový kód, edituj `QRPlatbaApp.py` a znovu zkompiluj EXE.
|
||||
|
||||
## Výstup
|
||||
|
||||
Generované QR kódy PNG se ukládají do:
|
||||
```
|
||||
U:\OrdinaceProjekt\Medicus\QRCode\QRPlatby\
|
||||
├── Buzalka_Vladimír_20260510_143025.png
|
||||
├── Buzalka_Vladimír_20260510_144030.png
|
||||
└── ...
|
||||
```
|
||||
|
||||
## PyInstaller kompilace
|
||||
|
||||
EXE soubor byl zkompilován příkazem:
|
||||
```bash
|
||||
pyinstaller --onefile --windowed --icon=qrcode.ico QRPlatbaApp.py
|
||||
```
|
||||
|
||||
Výsledný EXE se nachází v `dist/QRPlatbaApp.exe` a je schopen běžet na počítačích bez Pythonu.
|
||||
|
||||
Při potřebě znovu kompilovat po změně kódu:
|
||||
```bash
|
||||
cd U:\OrdinaceProjekt\Medicus\QRCode
|
||||
C:\Python312\Scripts\pyinstaller.exe --onefile --windowed --icon=qrcode.ico --clean QRPlatbaApp.py
|
||||
```
|
||||
@@ -0,0 +1,208 @@
|
||||
#!/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(r"U:\OrdinaceProjekt\Medicus\Externi\QRCode\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()
|
||||
@@ -0,0 +1,39 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
a = Analysis(
|
||||
['QRPlatbaApp.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='QRPlatbaApp',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon=['qrcode.ico'],
|
||||
)
|
||||
BIN
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
Reference in New Issue
Block a user