notbook
This commit is contained in:
4
.idea/vcs.xml
generated
4
.idea/vcs.xml
generated
@@ -1,4 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings" defaultProject="true" />
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
205
010qrcodegenerator.py
Normal file
205
010qrcodegenerator.py
Normal file
@@ -0,0 +1,205 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
============================================
|
||||
QR Platba Generator – Fully Documented Version
|
||||
============================================
|
||||
|
||||
This script generates a valid Czech payment QR code (QR Platba)
|
||||
according to the official ČBA (Czech Banking Association) specification v1.2.
|
||||
|
||||
The script creates a correct SPD (Short Payment Descriptor) string,
|
||||
turns it into a QR code (PNG image), and saves it to disk.
|
||||
|
||||
✅ Works with all Czech banks (Fio, ČSOB, KB, Air Bank…)
|
||||
✅ Supports both IBAN or domestic account format (account/bankcode)
|
||||
✅ Automatically URL-encodes the message (so spaces and diacritics work)
|
||||
✅ Can handle optional VS, SS, KS, due date, and instant-payment flag
|
||||
|
||||
Usage example (in your terminal):
|
||||
---------------------------------
|
||||
python generate_qrplatba.py \
|
||||
--acc CZ7520100000002800046620 \
|
||||
--amount 1543.50 \
|
||||
--vs 7309208104 \
|
||||
--ss 123456 \
|
||||
--ks 0308 \
|
||||
--date 09.12.2025 \
|
||||
--msg "ahoj zlatíčko" \
|
||||
--out qr_ok.png
|
||||
"""
|
||||
|
||||
import argparse # For parsing command-line arguments
|
||||
import urllib.parse # For safe URL-encoding of message text
|
||||
from pathlib import Path # For easy file handling (cross-platform)
|
||||
import qrcode # For generating the QR code image
|
||||
from datetime import datetime # For date parsing and formatting
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# 🧩 Helper function: Normalize date into the required YYYYMMDD format
|
||||
# --------------------------------------------------------------------
|
||||
def normalize_date(date_str: str) -> str:
|
||||
"""
|
||||
Converts a user-supplied date string (various formats) into the
|
||||
standard YYYYMMDD format used by the QR Platba specification.
|
||||
|
||||
Acceptable input examples:
|
||||
"20251209"
|
||||
"09.12.2025"
|
||||
"2025-12-09"
|
||||
"09122025"
|
||||
|
||||
Returns:
|
||||
str: normalized date string in "YYYYMMDD" format
|
||||
or empty string "" if input is None or empty
|
||||
"""
|
||||
if not date_str:
|
||||
return ""
|
||||
s = date_str.strip()
|
||||
|
||||
# Already in correct 8-digit form?
|
||||
if len(s) == 8 and s.isdigit():
|
||||
return s
|
||||
|
||||
# Try several common formats
|
||||
for fmt in ("%d.%m.%Y", "%Y-%m-%d", "%d%m%Y"):
|
||||
try:
|
||||
dt = datetime.strptime(s, fmt)
|
||||
return dt.strftime("%Y%m%d")
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
# If all parsing attempts fail → raise an informative error
|
||||
raise ValueError(
|
||||
"Date must be in one of formats: YYYYMMDD, DD.MM.YYYY, YYYY-MM-DD, DDMMYYYY"
|
||||
)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# 🔧 Helper function: Build the SPD string (core of QR Platba)
|
||||
# --------------------------------------------------------------------
|
||||
def build_spayd(params: dict) -> str:
|
||||
"""
|
||||
Assembles a valid SPD (Short Payment Descriptor) string
|
||||
according to ČBA v1.2 specification.
|
||||
|
||||
Example output:
|
||||
SPD*1.0*ACC:CZ7520100000002800046620*AM:1543.50*CC:CZK*DT:20251209*
|
||||
X-VS:7309208104*X-SS:123456*X-KS:0308*MSG:ahoj%20zlaticko
|
||||
"""
|
||||
|
||||
# Start with fixed header
|
||||
parts = ["SPD*1.0*"]
|
||||
|
||||
# --- Required field: account number / IBAN ---
|
||||
acc = params.get("acc", "").strip()
|
||||
if not acc:
|
||||
raise ValueError("Missing required parameter: --acc")
|
||||
parts.append(f"ACC:{acc}*")
|
||||
|
||||
# --- Optional: amount ---
|
||||
amt = params.get("amount")
|
||||
if amt:
|
||||
parts.append(f"AM:{float(amt):.2f}*") # always two decimals
|
||||
|
||||
# --- Optional: currency (defaults to CZK) ---
|
||||
cc = params.get("cc") or "CZK"
|
||||
parts.append(f"CC:{cc}*")
|
||||
|
||||
# --- Optional: due date ---
|
||||
dt = params.get("dt")
|
||||
if dt:
|
||||
parts.append(f"DT:{dt}*")
|
||||
|
||||
# --- Optional: symbols (VS, SS, KS) ---
|
||||
for key in ("X-VS", "X-SS", "X-KS"):
|
||||
val = params.get(key.replace("-", "_").lower())
|
||||
if val:
|
||||
parts.append(f"{key}:{val}*")
|
||||
|
||||
# --- Optional: payment type (PT:IP = Instant Payment) ---
|
||||
pt = params.get("pt")
|
||||
if pt:
|
||||
parts.append(f"PT:{pt}*")
|
||||
|
||||
# --- Optional: message for recipient ---
|
||||
msg = params.get("msg") or ""
|
||||
if msg:
|
||||
# Encode to keep spaces and Czech letters valid
|
||||
safe_chars = "$%*+-.:/"
|
||||
encoded_msg = urllib.parse.quote(msg, safe=safe_chars)
|
||||
parts.append(f"MSG:{encoded_msg}")
|
||||
|
||||
# Combine everything into one string
|
||||
return "".join(parts)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# 🚀 Main program entry point
|
||||
# --------------------------------------------------------------------
|
||||
def main():
|
||||
# -------------------------------
|
||||
# Define all command-line options
|
||||
# -------------------------------
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generate a Czech QR Platba (payment QR code)."
|
||||
)
|
||||
parser.add_argument("--acc", required=True,
|
||||
help='Account: either "2800046620/2010" or IBAN "CZ..."')
|
||||
parser.add_argument("--amount", help="Payment amount (e.g. 1543.50)")
|
||||
parser.add_argument("--vs", help="Variable symbol (X-VS)")
|
||||
parser.add_argument("--ss", help="Specific symbol (X-SS)")
|
||||
parser.add_argument("--ks", help="Constant symbol (X-KS)")
|
||||
parser.add_argument("--date", help="Due date (YYYYMMDD or DD.MM.YYYY etc.)")
|
||||
parser.add_argument("--msg", help="Message for recipient (will be URL-encoded)")
|
||||
parser.add_argument("--cc", default="CZK", help="Currency (default CZK)")
|
||||
parser.add_argument("--pt", help="Payment type (e.g. IP for instant payment)")
|
||||
parser.add_argument("--out", default="qrplatba.png", help="Output PNG file name")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# -------------------------------
|
||||
# Normalize and prepare arguments
|
||||
# -------------------------------
|
||||
dt_norm = normalize_date(args.date) if args.date else ""
|
||||
|
||||
params = {
|
||||
"acc": args.acc,
|
||||
"amount": args.amount,
|
||||
"cc": args.cc,
|
||||
"dt": dt_norm,
|
||||
"x_vs": args.vs,
|
||||
"x_ss": args.ss,
|
||||
"x_ks": args.ks,
|
||||
"msg": args.msg,
|
||||
"pt": args.pt,
|
||||
}
|
||||
|
||||
# -------------------------------
|
||||
# Build the SPD string
|
||||
# -------------------------------
|
||||
spayd = build_spayd(params)
|
||||
|
||||
# -------------------------------
|
||||
# Generate QR code image
|
||||
# -------------------------------
|
||||
img = qrcode.make(spayd)
|
||||
output_path = Path(args.out)
|
||||
img.save(output_path)
|
||||
|
||||
# -------------------------------
|
||||
# Print results for verification
|
||||
# -------------------------------
|
||||
print("✅ QR Platba successfully generated")
|
||||
print("SPD string (you can verify at https://qr-platba.cz/test/):")
|
||||
print(spayd)
|
||||
print()
|
||||
print(f"📂 QR code image saved to: {output_path.resolve()}")
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# 🔘 Run when executed directly
|
||||
# --------------------------------------------------------------------
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
109
011 test.py
Normal file
109
011 test.py
Normal file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import urllib.parse
|
||||
import qrcode
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from PIL import Image, ImageTk
|
||||
import customtkinter as ctk
|
||||
from tkinter import messagebox
|
||||
|
||||
IBAN = "CZ7520100000002800046620"
|
||||
CURRENCY = "CZK"
|
||||
OUTPUT_DIR = Path("QRPlatby")
|
||||
OUTPUT_DIR.mkdir(exist_ok=True)
|
||||
|
||||
PRIJMENI = "Buzalka"
|
||||
JMENO = "Vladimír"
|
||||
RODCIS = "730928104"
|
||||
|
||||
ITEMS = {
|
||||
"Očkování chřipka Vaxigrip": 600.00,
|
||||
"Očkování chřipka Efluelda": 1300.00,
|
||||
}
|
||||
|
||||
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}"
|
||||
|
||||
class QRPlatbaApp(ctk.CTk):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.title("QR Platba – Ordinace MUDr. Buzalková")
|
||||
self.geometry("520x520")
|
||||
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=(10, 20))
|
||||
|
||||
patient = ctk.CTkFrame(frame, corner_radius=8)
|
||||
patient.pack(fill="x", pady=(0, 20), 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=2)
|
||||
|
||||
pay = ctk.CTkFrame(frame, corner_radius=8)
|
||||
pay.pack(fill="x", pady=(0, 20), padx=10)
|
||||
ctk.CTkLabel(pay, text="Vyberte položku k úhradě:",
|
||||
font=("Arial", 12, "bold")).pack(anchor="w", padx=10, pady=(10, 5))
|
||||
|
||||
self.selected_item = ctk.StringVar(value=list(ITEMS.keys())[0])
|
||||
self.combo = ctk.CTkOptionMenu(pay,
|
||||
variable=self.selected_item,
|
||||
values=list(ITEMS.keys()),
|
||||
font=("Arial", 12),
|
||||
command=self.update_amount)
|
||||
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=(5, 10))
|
||||
self.update_amount()
|
||||
|
||||
ctk.CTkButton(frame, text="Vytvořit QR Platbu",
|
||||
font=("Arial", 13, "bold"),
|
||||
height=40,
|
||||
command=self.generate_qr).pack(pady=10)
|
||||
|
||||
self.qr_label = ctk.CTkLabel(frame, text="")
|
||||
self.qr_label.pack(pady=15)
|
||||
|
||||
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))
|
||||
|
||||
def update_amount(self, _=None):
|
||||
item = self.selected_item.get()
|
||||
self.amount_label.configure(text=f"Částka: {ITEMS[item]:.2f} Kč")
|
||||
|
||||
def generate_qr(self):
|
||||
item = self.selected_item.get()
|
||||
spayd = create_spayd(IBAN, ITEMS[item], RODCIS, f"{PRIJMENI} {JMENO} – {item}", CURRENCY)
|
||||
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)
|
||||
|
||||
img_resized = img.resize((300, 300))
|
||||
qr_tk = ImageTk.PhotoImage(img_resized)
|
||||
self.qr_label.configure(image=qr_tk)
|
||||
self.qr_label.image = qr_tk
|
||||
|
||||
# 🔄 Adjust window height dynamically
|
||||
self.update_idletasks()
|
||||
self.geometry(f"{self.winfo_reqwidth()}x{self.winfo_reqheight()}")
|
||||
|
||||
messagebox.showinfo("QR Platba vytvořena",
|
||||
f"Soubor uložen jako:\n{out_path}\n\nSPD řetězec:\n{spayd}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QRPlatbaApp()
|
||||
app.mainloop()
|
||||
Reference in New Issue
Block a user