z230
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
"""_process_batch_v0.py — DOČASNÉ: dávka 2 faktur (T-Mobile osobní, Perlička ordinace)."""
|
||||
import sys
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
sys.path.insert(0, r"U:\ordinaceprojekt")
|
||||
import dropbox, msal, requests
|
||||
from Knihovny.telegram_notify import zeptej_se_telegram, posli_telegram
|
||||
|
||||
today = date.today(); ddmmyy = today.strftime("%d%m%y"); fdate = today.strftime("%Y-%m-%d")
|
||||
|
||||
payments = [
|
||||
dict(name="T-Mobile", payer="2100046291", acct="19-2235210247", hal=60920,
|
||||
vs="9953395180", bank="0100", ks="0000", ss="", av="faktura T-Mobile 20MAY-19JUN2026",
|
||||
summary="T-Mobile 06-2026", mailbox="vladimir.buzalka@buzalka.cz",
|
||||
msg_id="AAMkADY2MzQ0N2JkLWE4NjAtNDNjYS05OTVlLTQxYjhkYWVlZmY1NQBGAAAAAACkV0glv2dZRLb1sPnwFvdvBwAzGo7b-cvrRoXjMGfWnzDsAAAAAAEMAAAzGo7b-cvrRoXjMGfWnzDsAALtAR6DAAA="),
|
||||
dict(name="Perlicka", payer="2800046620", acct="2603293964", hal=322000,
|
||||
vs="2026474", bank="2010", ks="0000", ss="", av="Perlicka fa 2026474",
|
||||
summary="Perlička fa 2026474", mailbox="ordinace@buzalka.cz",
|
||||
msg_id="AQMkADYxOTE5ZTYwLTg2MWItNDNmOC04MWE5LTczZjM0NmJmMTRlYwBGAAADlMSYEfdwGUe6ACarqZh2ygcAszvBQpZaWUKlscfbC8_jxwAAAgEMAAAAszvBQpZaWUKlscfbC8_jxwABaPXXzgAAAA=="),
|
||||
]
|
||||
|
||||
def build(p):
|
||||
ssfield = p["ss"] if p["ss"] else " "
|
||||
item = f"{p['acct']} {str(p['hal']).zfill(12)} {p['vs']} {p['bank']}{p['ks']} {ssfield} AV:{p['av']}"
|
||||
lines = ["UHL1"+ddmmyy+" "*20+"0"*28, "1 1501 000000 2010",
|
||||
f"2 000000-{p['payer']} {str(p['hal']).zfill(14)} {ddmmyy}", item, "3 +", "5 +"]
|
||||
return ("\r\n".join(lines)+"\r\n").encode("ascii")
|
||||
|
||||
for p in payments:
|
||||
p["data"] = build(p)
|
||||
p["fname"] = f"{fdate} KPC k platbě [{p['summary']}].kpc"
|
||||
print(f"=== {p['fname']} ({len(p['data'])} B) ===")
|
||||
print(p["data"].decode("ascii").replace("\r\n","\\r\\n\n"), end="")
|
||||
print()
|
||||
|
||||
msg = (
|
||||
"💳 Návrh plateb (KPC agent) — 2 faktury\n\n"
|
||||
"1) T-Mobile 609,20 Kč → 19-2235210247/0100, VS 9953395180 (z osobního)\n"
|
||||
"2) Perlička 3 220,00 Kč → 2603293964/2010, VS 2026474 (z ordinace)\n\n"
|
||||
"FIO: obojí nezaplaceno ✅ (Perlička = nový dodavatel)\n\n"
|
||||
"Vytvořit oba KPC a nahrát do Dropboxu? Odpověz: ano / ne"
|
||||
)
|
||||
print(">> Potvrzeno v chatu (ano) — pokračuji bez Telegram dotazu.")
|
||||
|
||||
# Dropbox + Graph
|
||||
env = {}
|
||||
for line in Path(r"U:\PythonProject\Janssen\EmailsImport\.env").read_text(encoding="utf-8").splitlines():
|
||||
line=line.strip()
|
||||
if "=" in line and not line.startswith("#"):
|
||||
k,v=line.split("=",1); env[k.strip()]=v.strip()
|
||||
dbx = dropbox.Dropbox(app_key=env["DROPBOX_APP_KEY"], app_secret=env["DROPBOX_APP_SECRET"],
|
||||
oauth2_refresh_token=env["DROPBOX_APP_REFRESH_TOKEN"])
|
||||
TENANT="7d269944-37a4-43a1-8140-c7517dc426e9"; CID="4b222bfd-78c9-4239-a53f-43006b3ed07f"
|
||||
SECRET="Txg8Q~MjhocuopxsJyJBhPmDfMxZ2r5WpTFj1dfk"
|
||||
app=msal.ConfidentialClientApplication(CID,authority=f"https://login.microsoftonline.com/{TENANT}",client_credential=SECRET)
|
||||
tok=app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"])
|
||||
H={"Authorization":f"Bearer {tok['access_token']}","Content-Type":"application/json"}
|
||||
out_dir = Path(__file__).parent/"output"; out_dir.mkdir(exist_ok=True)
|
||||
|
||||
for p in payments:
|
||||
(out_dir/p["fname"]).write_bytes(p["data"])
|
||||
res = dbx.files_upload(p["data"], f"/!!!Days/Downloads Z230/{p['fname']}",
|
||||
mode=dropbox.files.WriteMode.add, autorename=True)
|
||||
print(f"NAHRÁNO → {res.path_display}")
|
||||
rp = requests.patch(f"https://graph.microsoft.com/v1.0/users/{p['mailbox']}/messages/{p['msg_id']}",
|
||||
headers=H, json={"categories":["KPCzpracovánoClaudem"]}, timeout=30)
|
||||
print(f"PATCH {p['name']} ({p['mailbox']}): {rp.status_code}", "" if rp.ok else rp.text[:200])
|
||||
|
||||
posli_telegram("✅ KPC vytvořeno a nahráno (2):\n• T-Mobile 609,20 Kč (osobní)\n• Perlička 3 220 Kč (ordinace)\nV bankingu stačí podepsat.")
|
||||
print(">> HOTOVO.")
|
||||
@@ -0,0 +1,114 @@
|
||||
"""_process_ordinace_faktury_v0.py — DOČASNÉ: KPC per dodavatel z 8 ordinačních faktur.
|
||||
Z PDF vytáhne účet+VS (Claude), cross-check účtu proti FIO historii + částky proti názvu,
|
||||
sestaví per-dodavatel KPC (kpc_format) z ordinace a nahraje do Dropboxu.
|
||||
"""
|
||||
import importlib, json, os, re, subprocess, sys
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
for mod, pkg in (("fitz", "PyMuPDF"), ("requests", "requests"), ("dropbox", "dropbox")):
|
||||
try: importlib.import_module(mod)
|
||||
except ImportError: subprocess.check_call([sys.executable, "-m", "pip", "install", "--quiet", pkg])
|
||||
import fitz, requests, dropbox # noqa: E402
|
||||
sys.path.insert(0, r"U:\ordinaceprojekt\EmailAgent")
|
||||
import kpc_format # noqa: E402
|
||||
|
||||
def _load_env(p):
|
||||
p = Path(p)
|
||||
if p.exists():
|
||||
for line in p.read_text(encoding="utf-8").splitlines():
|
||||
line = line.strip()
|
||||
if "=" in line and not line.startswith("#"):
|
||||
k, v = line.split("=", 1); os.environ.setdefault(k.strip(), v.strip().strip('"').strip("'"))
|
||||
_load_env(r"U:\ordinaceprojekt\Medevio\.env")
|
||||
_load_env(r"U:\PythonProject\Janssen\EmailsImport\.env")
|
||||
|
||||
PAYER = "2800046620" # ordinace
|
||||
DIR = r"U:\Dropbox\Ordinace\!!MUDr. Michaela Buzalková s.r.o\Prosek\#040 Faktury přijaté"
|
||||
# (dodavatel, číslo faktury, částka z názvu, soubor)
|
||||
ENTRIES = [
|
||||
("MEDEVIO", "321799", 2497.58, "2026-06-22 Faktura MEDEVIO 321799 [Medevio tarif Ústředna Pokročilá Plus] [2497.58 CZK].pdf"),
|
||||
("Poliklinika Prosek", "91260794", 464.64, "2026-06-15 Faktura Poliklinika Prosek 91260794 [sterilizace, telefonní poplatek] [464.64 CZK].pdf"),
|
||||
("Ptáček", "202605002", 3632.10, "2026-06-12 Faktura Ptáček 202605002 [vakcína FSME-IMMUN 0.5 ml] [3632.10 CZK].pdf"),
|
||||
("Poliklinika Prosek", "96260214", 28363.00, "2026-06-01 Faktura Poliklinika Prosek 96260214 [nájemné a služby] [28363.00 CZK].pdf"),
|
||||
("Ptáček", "202604906", 1214.08, "2026-06-10 Faktura Ptáček 202604906 [vakcína ADACEL] [1214.08 CZK].pdf"),
|
||||
("QuickSeal", "110606255", 2620.00, "2026-06-01 Faktura QuickSeal 110606255 [VivaDiag Hydroxyvitamin D3 testy, poštovné] [2620.00 CZK].pdf"),
|
||||
("ASKER", "261103225", 339.00, "2026-06-01 Faktura ASKER 261103225 [kontejner Yannick 1.5 l] [339.00 CZK].pdf"),
|
||||
("Ptáček", "202604570", 9235.20, "2026-05-29 Faktura Ptáček 202604570 [vakcíny Adacel, Vaqta, Havrix] [9235.20 CZK].pdf"),
|
||||
]
|
||||
# Účty dodavatelů z FIO historie (cross-check proti záměně/chybě extrakce)
|
||||
FIO_ACCOUNTS = {
|
||||
"MEDEVIO": ("2701907026", "2010"),
|
||||
"Poliklinika Prosek": ("1387720540", "2700"),
|
||||
"Ptáček": ("220205630", "0300"),
|
||||
"QuickSeal": ("197638875", "0300"),
|
||||
"ASKER": ("2913796399", "0800"),
|
||||
}
|
||||
|
||||
PROMPT = """Z TEXTU faktury vytáhni BANKOVNÍ ÚDAJE K PLATBĚ. Vrať POUZE JSON:
|
||||
{"predcisli":"" nebo číslice, "cislo_uctu":"číslo účtu příjemce bez kódu banky",
|
||||
"smer_kod":"4místný kód banky", "vs":"variabilní symbol k platbě", "castka_kc":číslo,
|
||||
"ss":"specifický symbol nebo prázdné"}
|
||||
TEXT FAKTURY:
|
||||
%(t)s
|
||||
"""
|
||||
|
||||
def claude(text):
|
||||
r = requests.post("https://api.anthropic.com/v1/messages",
|
||||
headers={"x-api-key": os.environ["ANTHROPIC_API_KEY"], "anthropic-version": "2023-06-01",
|
||||
"content-type": "application/json"},
|
||||
json={"model": "claude-opus-4-8", "max_tokens": 400,
|
||||
"messages": [{"role": "user", "content": PROMPT % {"t": text[:14000]}}]}, timeout=90)
|
||||
r.raise_for_status()
|
||||
t = r.json()["content"][0]["text"]
|
||||
return json.loads(re.search(r"\{.*\}", t, re.S).group(0))
|
||||
|
||||
ddmmrr = date.today().strftime("%d%m%y")
|
||||
groups = {} # dodavatel -> [Polozka]
|
||||
report = []
|
||||
for dod, fakt, castka_nazev, fname in ENTRIES:
|
||||
txt = "".join(p.get_text() for p in fitz.open(str(Path(DIR) / fname)))
|
||||
d = claude(txt)
|
||||
ucet = re.sub(r"\D", "", str(d.get("cislo_uctu", "")))
|
||||
smer = str(d.get("smer_kod", "")).strip()
|
||||
vs = str(d.get("vs", "")).strip()
|
||||
castka = float(d.get("castka_kc") or 0)
|
||||
flags = []
|
||||
fio_u, fio_b = FIO_ACCOUNTS.get(dod, ("", ""))
|
||||
if fio_u and ucet != fio_u:
|
||||
flags.append(f"ÚČET ≠ FIO ({ucet} vs {fio_u})")
|
||||
if fio_b and smer != fio_b:
|
||||
flags.append(f"BANKA ≠ FIO ({smer} vs {fio_b})")
|
||||
if abs(castka - castka_nazev) > 0.01:
|
||||
flags.append(f"ČÁSTKA ≠ název ({castka} vs {castka_nazev})")
|
||||
status = "OK" if not flags else "FLAG: " + "; ".join(flags)
|
||||
report.append((dod, fakt, castka_nazev, ucet, smer, vs, status))
|
||||
if not flags:
|
||||
av = kpc_format._ascii(f"{dod} fa {fakt}")
|
||||
groups.setdefault(dod, []).append(kpc_format.Polozka(
|
||||
ucet=kpc_format.fmt_account(ucet, d.get("predcisli", "")),
|
||||
halere=round(castka_nazev * 100), vs=vs, smer_kod=smer,
|
||||
ks="0000", ss=str(d.get("ss") or ""), av=av))
|
||||
|
||||
print("=== EXTRAKCE + CROSS-CHECK ===")
|
||||
for dod, fakt, c, ucet, smer, vs, status in report:
|
||||
print(f"{dod:20} fa {fakt:11} {c:>10.2f} → {ucet}/{smer} VS {vs:12} [{status}]")
|
||||
|
||||
# Dropbox
|
||||
dbx = dropbox.Dropbox(app_key=os.environ["DROPBOX_APP_KEY"], app_secret=os.environ["DROPBOX_APP_SECRET"],
|
||||
oauth2_refresh_token=os.environ["DROPBOX_APP_REFRESH_TOKEN"])
|
||||
out_dir = Path(__file__).parent / "output"; out_dir.mkdir(exist_ok=True)
|
||||
fdate = date.today().strftime("%Y-%m-%d")
|
||||
|
||||
print("\n=== KPC PER DODAVATEL ===")
|
||||
for dod, items in groups.items():
|
||||
data = kpc_format.build_kpc(PAYER, items, ddmmrr=ddmmrr)
|
||||
summary = f"{dod}" + (f" {len(items)} faktury" if len(items) > 1 else f" fa {[e[1] for e in report if e[0]==dod][0]}")
|
||||
fname = f"{fdate} KPC k platbě [{summary}].kpc"
|
||||
(out_dir / fname).write_bytes(data)
|
||||
print(f"\n--- {fname} ---")
|
||||
print(data.decode("ascii").replace("\r\n", "\\r\\n\n"), end="")
|
||||
res = dbx.files_upload(data, f"/!!!Days/Downloads Z230/{fname}",
|
||||
mode=dropbox.files.WriteMode.add, autorename=True)
|
||||
print(f"NAHRÁNO → {res.path_display}")
|
||||
@@ -0,0 +1,6 @@
|
||||
UHL1220626 0000000000000000000000000000
|
||||
1 1501 000000 2010
|
||||
2 000000-2800046620 00000000322000 220626
|
||||
2603293964 000000322000 2026474 20100000 AV:Perlicka fa 2026474
|
||||
3 +
|
||||
5 +
|
||||
@@ -0,0 +1,6 @@
|
||||
UHL1220626 0000000000000000000000000000
|
||||
1 1501 000000 2010
|
||||
2 000000-2100046291 00000000060920 220626
|
||||
19-2235210247 000000060920 9953395180 01000000 AV:faktura T-Mobile 20MAY-19JUN2026
|
||||
3 +
|
||||
5 +
|
||||
@@ -0,0 +1,6 @@
|
||||
UHL1230626 0000000000000000000000000000
|
||||
1 1501 000000 2010
|
||||
2 000000-2800046620 00000000033900 230626
|
||||
2913796399 000000033900 261103225 08000000 AV:ASKER fa 261103225
|
||||
3 +
|
||||
5 +
|
||||
@@ -0,0 +1,6 @@
|
||||
UHL1230626 0000000000000000000000000000
|
||||
1 1501 000000 2010
|
||||
2 000000-2800046620 00000000249758 230626
|
||||
2701907026 000000249758 321799 20100000 AV:MEDEVIO fa 321799
|
||||
3 +
|
||||
5 +
|
||||
@@ -0,0 +1,7 @@
|
||||
UHL1230626 0000000000000000000000000000
|
||||
1 1501 000000 2010
|
||||
2 000000-2800046620 00000002882764 230626
|
||||
1387720540 000000046464 91260794 27000000 AV:Poliklinika Prosek fa 91260794
|
||||
1387720540 000002836300 10626 27000000 AV:Poliklinika Prosek fa 96260214
|
||||
3 +
|
||||
5 +
|
||||
@@ -0,0 +1,6 @@
|
||||
UHL1230626 0000000000000000000000000000
|
||||
1 1501 000000 2010
|
||||
2 000000-2800046620 00000001616540 230626
|
||||
1387720540 000001616540 91260763 27000000 AV:Poliklinika Prosek fa 91260763
|
||||
3 +
|
||||
5 +
|
||||
@@ -0,0 +1,6 @@
|
||||
UHL1230626 0000000000000000000000000000
|
||||
1 1501 000000 2010
|
||||
2 000000-2800046620 00000000019314 230626
|
||||
1387720540 000000019314 91260795 27000000 AV:Poliklinika Prosek fa 91260795
|
||||
3 +
|
||||
5 +
|
||||
@@ -0,0 +1,8 @@
|
||||
UHL1230626 0000000000000000000000000000
|
||||
1 1501 000000 2010
|
||||
2 000000-2800046620 00000001408138 230626
|
||||
220205630 000000363210 202605002 03000000 AV:Ptacek fa 202605002
|
||||
220205630 000000121408 202604906 03000000 AV:Ptacek fa 202604906
|
||||
220205630 000000923520 202604570 03000000 AV:Ptacek fa 202604570
|
||||
3 +
|
||||
5 +
|
||||
@@ -0,0 +1,6 @@
|
||||
UHL1230626 0000000000000000000000000000
|
||||
1 1501 000000 2010
|
||||
2 000000-2800046620 00000000262000 230626
|
||||
197638875 000000262000 110606255 03000000 AV:QuickSeal fa 110606255
|
||||
3 +
|
||||
5 +
|
||||
Reference in New Issue
Block a user