diff --git a/Medevio/80 Pacienti/analyze_extras.py b/Medevio/80 Pacienti/analyze_extras.py new file mode 100644 index 0000000..6815585 --- /dev/null +++ b/Medevio/80 Pacienti/analyze_extras.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Analýza 129 extra pacientů v Medeviu (nejsou v Medicusu): +- Mají účet v Medeviu? +- Jaké jsou jejich statusy? +""" + +import sys +try: + sys.stdout.reconfigure(encoding="utf-8") + sys.stderr.reconfigure(encoding="utf-8") +except AttributeError: + import io + sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") + sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8") + +sys.path.insert(0, 'U:/OrdinaceProjekt') + +import pymysql +from Knihovny.medicus_db import get_medicus_db + +DB_CONFIG = { + "host": "192.168.1.76", + "port": 3306, + "user": "root", + "password": "Vlado9674+", + "database": "medevio", + "charset": "utf8mb4", + "cursorclass": pymysql.cursors.DictCursor, +} + +def main(): + # Načti registrované v Medicusu + db = get_medicus_db() + rows = db.get_active_registered_patients() + medicus_rc = {r[0].strip() for r in rows if r[0]} + db.close() + + # Najdi všechny ACTIVE v Medeviu, co nejsou v Medicusu + conn = pymysql.connect(**DB_CONFIG) + with conn.cursor() as cur: + cur.execute(""" + SELECT patient_id, name, surname, identification_number, user_id, status + FROM medevio_pacient + WHERE status = 'ACTIVE' + AND identification_number IS NOT NULL + ORDER BY surname, name + """) + all_active = cur.fetchall() + conn.close() + + # Filtruj ty mimo Medicus + extras = [ + r for r in all_active + if r["identification_number"] not in medicus_rc + ] + + print(f"{'=' * 80}") + print(f"EXTRA PACIENTI V MEDEVIU (mimo Medicus): {len(extras)}") + print(f"{'=' * 80}\n") + + # Rozdělení podle user_id + with_account = [r for r in extras if r["user_id"]] + without_account = [r for r in extras if not r["user_id"]] + + print(f"S účtem (user_id NOT NULL): {len(with_account)}") + print(f"Bez účtu (user_id IS NULL): {len(without_account)}\n") + + if without_account: + print("─" * 80) + print("BEZ ÚČTU — KANDIDÁTI NA REMOVE:") + print("─" * 80) + for r in without_account[:10]: # První 10 + print(f" {r['surname']} {r['name']} RC: {r['identification_number']}") + if len(without_account) > 10: + print(f" ... a dalších {len(without_account) - 10}") + + if with_account: + print("\n" + "─" * 80) + print("S ÚČTEM — NORMÁLNÍ PACIENTI (nejsou v Medicusu, ale mají Medevio účet):") + print("─" * 80) + for r in with_account[:10]: # První 10 + print(f" {r['surname']} {r['name']} RC: {r['identification_number']}") + if len(with_account) > 10: + print(f" ... a dalších {len(with_account) - 10}") + + print(f"\n{'=' * 80}") + +if __name__ == "__main__": + main() diff --git a/Medevio/80 Pacienti/check_kurajda.py b/Medevio/80 Pacienti/check_kurajda.py new file mode 100644 index 0000000..2736237 --- /dev/null +++ b/Medevio/80 Pacienti/check_kurajda.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import sys +try: + sys.stdout.reconfigure(encoding="utf-8") + sys.stderr.reconfigure(encoding="utf-8") +except AttributeError: + import io + sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") + sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8") + +sys.path.insert(0, 'U:/OrdinaceProjekt') + +import pymysql +import fdb +from pathlib import Path + +DB_CONFIG = { + "host": "192.168.1.76", + "port": 3306, + "user": "root", + "password": "Vlado9674+", + "database": "medevio", + "charset": "utf8mb4", + "cursorclass": pymysql.cursors.DictCursor, +} + +RC = "8206694232" + +print("=" * 80) +print(f"KONTROLA PACIENTA: Kurajda Martin (RC: {RC})") +print("=" * 80) + +# --- V Medeviu (MySQL) --- +print("\n[Medevio — MySQL]") +conn = pymysql.connect(**DB_CONFIG) +with conn.cursor() as cur: + cur.execute(""" + SELECT name, surname, status, user_id, identification_number + FROM medevio_pacient + WHERE identification_number = %s + """, (RC,)) + medevio_rows = cur.fetchall() +conn.close() + +if medevio_rows: + for r in medevio_rows: + print(f" Jméno: {r['surname']} {r['name']}") + print(f" Status: {r['status']}") + print(f" User ID: {r['user_id']}") +else: + print(" NENALEZEN") + +# --- V Medicusu (Firebird) --- +print("\n[Medicus — Firebird]") +dsn = r"localhost:c:\medicus 3\data\medicus.fdb" +conn_fb = fdb.connect(dsn=dsn, user="SYSDBA", password="masterkey", charset="win1250") +cur_fb = conn_fb.cursor() + +# Najdi pacienta podle RC +cur_fb.execute(""" + SELECT idpac, prijmeni, jmeno, vyrazen + FROM kar + WHERE rodcis = ? +""", (RC,)) +kar_rows = cur_fb.fetchall() + +if kar_rows: + for kar in kar_rows: + idpac, prijmeni, jmeno, vyrazen = kar + print(f" Jméno: {prijmeni} {jmeno}") + print(f" Vyrazen: {vyrazen}") + + # Zjisti registraci + cur_fb.execute(""" + SELECT r.idpac, r.datum, r.datum_zruseni, r.priznak + FROM registr r + WHERE r.idpac = ? AND r.idicp = ( + SELECT i.idicp FROM icp i + WHERE i.icp = '09305001' AND i.odb = '001' + ) + ORDER BY r.datum DESC + """, (idpac,)) + reg_rows = cur_fb.fetchall() + + if reg_rows: + print(f" Registrace (posledních {len(reg_rows)}):") + for r in reg_rows[:3]: # Poslední 3 + idpac2, datum, datum_zruseni, priznak = r + zrusena = "ANO" if datum_zruseni else "NE" + print(f" Datum: {datum}, Zrušena: {zrusena}, Příznak: {priznak}") + else: + print(f" Žádná registrace u našeho doktora") +else: + print(" NENALEZEN") + +conn_fb.close() +print("\n" + "=" * 80) diff --git a/Medevio/80 Pacienti/check_removed_status.py b/Medevio/80 Pacienti/check_removed_status.py new file mode 100644 index 0000000..afa4a39 --- /dev/null +++ b/Medevio/80 Pacienti/check_removed_status.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Kontrola statusu pacientů po remove skriptu: +- Kolik je označeno jako REMOVED? +- Kolik zbývá ACTIVE bez účtu a bez registrace v Medicusu? +""" + +import sys +try: + sys.stdout.reconfigure(encoding="utf-8") + sys.stderr.reconfigure(encoding="utf-8") +except AttributeError: + import io + sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") + sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8") + +sys.path.insert(0, 'U:/OrdinaceProjekt') + +import pymysql +from Knihovny.medicus_db import get_medicus_db + +# ==================== CONFIG ==================== + +DB_CONFIG = { + "host": "192.168.1.76", + "port": 3306, + "user": "root", + "password": "Vlado9674+", + "database": "medevio", + "charset": "utf8mb4", + "cursorclass": pymysql.cursors.DictCursor, +} + +# ==================== MAIN ==================== + +def main(): + print("=" * 70) + print("KONTROLA STATUSU PACIENTŮ V MEDEVIO") + print("=" * 70) + + # --- Medevio (MySQL) --- + print("\n[Medevio — MySQL]") + conn = pymysql.connect(**DB_CONFIG) + + with conn.cursor() as cur: + cur.execute("SELECT COUNT(*) as cnt FROM medevio_pacient WHERE status = 'ACTIVE'") + active = cur.fetchone()["cnt"] + + cur.execute("SELECT COUNT(*) as cnt FROM medevio_pacient WHERE status = 'REMOVED'") + removed = cur.fetchone()["cnt"] + + cur.execute(""" + SELECT COUNT(*) as cnt FROM medevio_pacient + WHERE status = 'ACTIVE' AND user_id IS NULL + """) + active_no_account = cur.fetchone()["cnt"] + + conn.close() + + print(f" ACTIVE pacientů: {active}") + print(f" REMOVED pacientů: {removed}") + print(f" ACTIVE bez účtu (user_id NULL): {active_no_account}") + + # --- Medicus (Firebird) --- + print("\n[Medicus — Firebird]") + db = get_medicus_db() + rows = db.get_active_registered_patients() + medicus_registered = len(rows) + medicus_rc = {r[0].strip() for r in rows if r[0]} + db.close() + print(f" Registrovaní pacienti: {medicus_registered}") + + # --- Kandidáti na REMOVED --- + print("\n[Analýza]") + print(f" ACTIVE bez účtu: {active_no_account}") + + # Zjisti, kolik z těch ACTIVE bez účtu nejsou v Medicusu + conn = pymysql.connect(**DB_CONFIG) + with conn.cursor() as cur: + cur.execute(""" + SELECT patient_id, name, surname, identification_number + FROM medevio_pacient + WHERE status = 'ACTIVE' + AND user_id IS NULL + AND identification_number IS NOT NULL + """) + candidates_raw = cur.fetchall() + conn.close() + + candidates_not_in_medicus = [ + r for r in candidates_raw + if r["identification_number"] not in medicus_rc + ] + + print(f" Z toho mimo Medicus (kandidáti na REMOVED): {len(candidates_not_in_medicus)}") + + print("\n" + "=" * 70) + +if __name__ == "__main__": + main() diff --git a/Medevio/80 Pacienti/check_sync_counts.py b/Medevio/80 Pacienti/check_sync_counts.py new file mode 100644 index 0000000..065cd73 --- /dev/null +++ b/Medevio/80 Pacienti/check_sync_counts.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Porovnání počtu pacientů: + - ACTIVE v Medevio (MySQL) + - registrovaní v Medicusu (Firebird) +""" + +import sys +try: + sys.stdout.reconfigure(encoding="utf-8") + sys.stderr.reconfigure(encoding="utf-8") +except AttributeError: + import io + sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") + sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8") + +sys.path.insert(0, 'U:/OrdinaceProjekt') + +import pymysql +from Knihovny.medicus_db import get_medicus_db + +# ==================== CONFIG ==================== + +DB_CONFIG = { + "host": "192.168.1.76", + "port": 3306, + "user": "root", + "password": "Vlado9674+", + "database": "medevio", + "charset": "utf8mb4", + "cursorclass": pymysql.cursors.DictCursor, +} + +# ==================== MAIN ==================== + +def main(): + print("=" * 70) + print("KONTROLA SYNCHRONIZACE PACIENTŮ") + print("=" * 70) + + # --- Medevio (MySQL) --- + print("\n[Medevio — MySQL]") + conn = pymysql.connect(**DB_CONFIG) + with conn.cursor() as cur: + cur.execute("SELECT COUNT(*) as cnt FROM medevio_pacient WHERE status = 'ACTIVE'") + medevio_active = cur.fetchone()["cnt"] + conn.close() + print(f" ACTIVE pacienti: {medevio_active}") + + # --- Medicus (Firebird) --- + print("\n[Medicus — Firebird]") + db = get_medicus_db() + rows = db.get_active_registered_patients() + medicus_registered = len(rows) + db.close() + print(f" Registrovaní pacienti: {medicus_registered}") + + # --- Porovnání --- + print("\n" + "=" * 70) + diff = medevio_active - medicus_registered + if diff == 0: + print(f"✓ SHODUJE SE! ({medevio_active} = {medicus_registered})") + elif diff > 0: + print(f"⚠ Medevio má {diff} VÍCE pacientů ({medevio_active} vs {medicus_registered})") + print(f" → Jsou to možná pacienti bez účtu v Medicusu, kandidáti na REMOVED") + else: + print(f"⚠ Medicús má {-diff} VÍCE pacientů ({medicus_registered} vs {medevio_active})") + print(f" → V Medicusu jsou pacienti, co nejsou v Medevio") + print("=" * 70) + + +if __name__ == "__main__": + main() diff --git a/Medevio/80 Pacienti/check_vymetalova.py b/Medevio/80 Pacienti/check_vymetalova.py new file mode 100644 index 0000000..e54ed78 --- /dev/null +++ b/Medevio/80 Pacienti/check_vymetalova.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import sys +try: + sys.stdout.reconfigure(encoding="utf-8") + sys.stderr.reconfigure(encoding="utf-8") +except AttributeError: + import io + sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") + sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8") + +sys.path.insert(0, 'U:/OrdinaceProjekt') + +import pymysql +import fdb + +DB_CONFIG = { + "host": "192.168.1.76", + "port": 3306, + "user": "root", + "password": "Vlado9674+", + "database": "medevio", + "charset": "utf8mb4", + "cursorclass": pymysql.cursors.DictCursor, +} + +RC = "9054260083" + +print("=" * 80) +print(f"KONTROLA PACIENTA: Vymětalová Kristýna (RC: {RC})") +print("=" * 80) + +# --- V Medeviu (MySQL) --- +print("\n[Medevio — MySQL]") +conn = pymysql.connect(**DB_CONFIG) +with conn.cursor() as cur: + cur.execute(""" + SELECT name, surname, status, user_id, identification_number + FROM medevio_pacient + WHERE identification_number = %s + """, (RC,)) + medevio_rows = cur.fetchall() +conn.close() + +if medevio_rows: + for r in medevio_rows: + print(f" Jméno: {r['surname']} {r['name']}") + print(f" Status: {r['status']}") + print(f" User ID: {r['user_id']}") +else: + print(" NENALEZENA") + +# --- V Medicusu (Firebird) --- +print("\n[Medicus — Firebird]") +dsn = r"localhost:c:\medicus 3\data\medicus.fdb" +conn_fb = fdb.connect(dsn=dsn, user="SYSDBA", password="masterkey", charset="win1250") +cur_fb = conn_fb.cursor() + +# Najdi pacienta podle RC +cur_fb.execute(""" + SELECT idpac, prijmeni, jmeno, vyrazen + FROM kar + WHERE rodcis = ? +""", (RC,)) +kar_rows = cur_fb.fetchall() + +if kar_rows: + print(f" NALEZENA v Medicusu!") + for kar in kar_rows: + idpac, prijmeni, jmeno, vyrazen = kar + print(f" Jméno: {prijmeni} {jmeno}") + print(f" Vyrazen: {vyrazen}") + + # Zjisti registraci + cur_fb.execute(""" + SELECT r.datum, r.datum_zruseni, r.priznak + FROM registr r + WHERE r.idpac = ? AND r.idicp = ( + SELECT i.idicp FROM icp i + WHERE i.icp = '09305001' AND i.odb = '001' + ) + ORDER BY r.datum DESC + """, (idpac,)) + reg_rows = cur_fb.fetchall() + + if reg_rows: + print(f" Registrace (posledních {len(reg_rows)}):") + for r in reg_rows[:3]: + datum, datum_zruseni, priznak = r + zrusena = "ANO" if datum_zruseni else "NE" + print(f" Datum: {datum}, Zrušena: {zrusena}, Příznak: {priznak}") + else: + print(f" ŽÁDNÁ registrace u našeho doktora!") +else: + print(f" NENALEZENA v Medicusu!") + +conn_fb.close() +print("\n" + "=" * 80) diff --git a/Medevio/80 Pacienti/debug_vymetalova.py b/Medevio/80 Pacienti/debug_vymetalova.py new file mode 100644 index 0000000..b63695f --- /dev/null +++ b/Medevio/80 Pacienti/debug_vymetalova.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import sys +try: + sys.stdout.reconfigure(encoding="utf-8") + sys.stderr.reconfigure(encoding="utf-8") +except AttributeError: + import io + sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") + sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8") + +sys.path.insert(0, 'U:/OrdinaceProjekt') + +import fdb + +dsn = r"localhost:c:\medicus 3\data\medicus.fdb" +conn = fdb.connect(dsn=dsn, user="SYSDBA", password="masterkey", charset="win1250") +cur = conn.cursor() + +RC = "9054260083" + +# Zjisti podrobně +cur.execute(""" + SELECT + kar.rodcis, + kar.prijmeni, + kar.jmeno, + kar.vyrazen, + r.idpac, + r.datum, + r.datum_zruseni, + r.priznak, + i.icp, + i.odb + FROM kar + LEFT JOIN registr r ON kar.idpac = r.idpac + LEFT JOIN icp i ON r.idicp = i.idicp + WHERE kar.rodcis = ? + ORDER BY r.datum DESC +""", (RC,)) + +rows = cur.fetchall() +print(f"Vymětalová Kristýna — podrobnosti:\n") +for r in rows: + print(f"RC: {r[0]}") + print(f"Jméno: {r[2]} {r[1]}") + print(f"Vyrazen: {r[3]}") + print(f"ID pacienta: {r[4]}") + print(f"Registrace datum: {r[5]}") + print(f"Registrace zrušena: {r[6]}") + print(f"Příznak: {r[7]}") + print(f"ICP: {r[8]}") + print(f"Odb: {r[9]}") + print() + +conn.close() diff --git a/Medevio/80 Pacienti/list_extras.py b/Medevio/80 Pacienti/list_extras.py new file mode 100644 index 0000000..864530d --- /dev/null +++ b/Medevio/80 Pacienti/list_extras.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import sys +try: + sys.stdout.reconfigure(encoding="utf-8") + sys.stderr.reconfigure(encoding="utf-8") +except AttributeError: + import io + sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") + sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8") + +sys.path.insert(0, 'U:/OrdinaceProjekt') + +import pymysql +from Knihovny.medicus_db import get_medicus_db + +DB_CONFIG = { + "host": "192.168.1.76", + "port": 3306, + "user": "root", + "password": "Vlado9674+", + "database": "medevio", + "charset": "utf8mb4", + "cursorclass": pymysql.cursors.DictCursor, +} + +# Načti registrované v Medicusu +db = get_medicus_db() +rows = db.get_active_registered_patients() +medicus_rc = {r[0].strip() for r in rows if r[0]} +db.close() + +# Najdi všechny ACTIVE s účtem mimo Medicus +conn = pymysql.connect(**DB_CONFIG) +with conn.cursor() as cur: + cur.execute(""" + SELECT name, surname, identification_number, user_id + FROM medevio_pacient + WHERE status = 'ACTIVE' + AND user_id IS NOT NULL + AND identification_number IS NOT NULL + ORDER BY surname, name + """) + all_with_account = cur.fetchall() +conn.close() + +# Filtruj ty mimo Medicus +extras = [ + r for r in all_with_account + if r["identification_number"] not in medicus_rc +] + +print(f"PACIENTI S MEDEVIO ÚČTEM MIMO MEDICUS ({len(extras)}):\n") +for i, r in enumerate(extras, 1): + print(f"{i:2d}. {r['surname']} {r['name']} (RC: {r['identification_number']})") diff --git a/Medevio/80 Pacienti/stats_user_id.py b/Medevio/80 Pacienti/stats_user_id.py new file mode 100644 index 0000000..67e71b4 --- /dev/null +++ b/Medevio/80 Pacienti/stats_user_id.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import sys +try: + sys.stdout.reconfigure(encoding="utf-8") + sys.stderr.reconfigure(encoding="utf-8") +except AttributeError: + import io + sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") + sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8") + +sys.path.insert(0, 'U:/OrdinaceProjekt') + +import pymysql +from Knihovny.medicus_db import get_medicus_db + +DB_CONFIG = { + "host": "192.168.1.76", + "port": 3306, + "user": "root", + "password": "Vlado9674+", + "database": "medevio", + "charset": "utf8mb4", + "cursorclass": pymysql.cursors.DictCursor, +} + +# Načti registrované v Medicusu +db = get_medicus_db() +rows = db.get_active_registered_patients() +medicus_rc = {r[0].strip() for r in rows if r[0]} +db.close() +print(f"Registrovaní v Medicusu: {len(medicus_rc)}\n") + +# Načti všechny pacienty z MySQL +conn = pymysql.connect(**DB_CONFIG) +with conn.cursor() as cur: + cur.execute("SELECT status, user_id, identification_number FROM medevio_pacient ORDER BY status, user_id") + all_rows = cur.fetchall() +conn.close() + +# Analýza +stats = {} +for r in all_rows: + status = r['status'] + has_user_id = "S user_id" if r['user_id'] else "BEZ user_id" + + key = f"{status} — {has_user_id}" + if key not in stats: + stats[key] = {"total": 0, "in_medicus": 0, "out_medicus": 0} + + stats[key]["total"] += 1 + + if r['identification_number']: + if r['identification_number'] in medicus_rc: + stats[key]["in_medicus"] += 1 + else: + stats[key]["out_medicus"] += 1 + +print("=" * 90) +print("STATISTIKA user_id v Medeviu") +print("=" * 90) + +for key in sorted(stats.keys()): + s = stats[key] + print(f"\n{key:40s}") + print(f" Celkem: {s['total']:5d}") + print(f" V Medicusu: {s['in_medicus']:5d}") + print(f" MIMO Medicus: {s['out_medicus']:5d}") + +print("\n" + "=" * 90) +print("SHRNUTÍ:") +print("=" * 90) + +with_user = sum(s['total'] for k, s in stats.items() if "S user_id" in k) +without_user = sum(s['total'] for k, s in stats.items() if "BEZ user_id" in k) + +print(f"\nCelkem S user_id: {with_user}") +print(f"Celkem BEZ user_id: {without_user}") +print(f"CELKEM: {with_user + without_user}") + +# Vztah k Medicusu +active_with_user_out = sum(s['out_medicus'] for k, s in stats.items() if "ACTIVE" in k and "S user_id" in k) +active_without_user_out = sum(s['out_medicus'] for k, s in stats.items() if "ACTIVE" in k and "BEZ user_id" in k) + +print(f"\nACTIVE S user_id mimo Medicus: {active_with_user_out}") +print(f"ACTIVE BEZ user_id mimo Medicus: {active_without_user_out}") +print("=" * 90) diff --git a/Medevio/80 Pacienti/sync_patients_to_mysql.py b/Medevio/80 Pacienti/sync_patients_to_mysql.py index 2399c9d..f56c968 100644 --- a/Medevio/80 Pacienti/sync_patients_to_mysql.py +++ b/Medevio/80 Pacienti/sync_patients_to_mysql.py @@ -21,15 +21,18 @@ import json import time import pymysql import requests +import threading from pathlib import Path from datetime import datetime from dateutil import parser as dtparser, tz +from concurrent.futures import ThreadPoolExecutor, as_completed # ==================== CONFIG ==================== GRAPHQL_URL = "https://api.medevio.cz/graphql" CLINIC_SLUG = "mudr-buzalkova" -PAGE_SIZE = 50 +PAGE_SIZE = 500 DELAY_BETWEEN_REQUESTS = 0.3 +MAX_WORKERS = 5 # Počet paralelních threadů pro stahování detailů TOKEN_PATH = Path(__file__).resolve().parent.parent / "token.txt" @@ -245,6 +248,56 @@ def fetch_patient_detail(headers, patient_id): return None +# ==================== RATE LIMITER ==================== + +class RateLimiter: + """Globální rate limiter pro API requesty.""" + def __init__(self, delay_seconds): + self.delay = delay_seconds + self.last_call = 0 + self.lock = threading.Lock() + + def wait(self): + with self.lock: + elapsed = time.time() - self.last_call + if elapsed < self.delay: + time.sleep(self.delay - elapsed) + self.last_call = time.time() + + +rate_limiter = RateLimiter(DELAY_BETWEEN_REQUESTS) + + +def fetch_patient_detail_safe(headers, patient_id): + """Stáhne detail s globálním rate limitem.""" + rate_limiter.wait() + return fetch_patient_detail(headers, patient_id) + + +def fetch_all_details_threaded(headers, patients): + """Stáhne detaily všech pacientů paralelně.""" + detailed = [] + errors = 0 + + with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor: + futures = { + executor.submit(fetch_patient_detail_safe, headers, p["id"]): p + for p in patients + } + + for i, future in enumerate(as_completed(futures)): + detail = future.result() + if detail: + detailed.append(detail) + else: + errors += 1 + + if (i + 1) % 50 == 0: + print(f" Detail {i + 1}/{len(patients)}...") + + return detailed, errors + + def patient_to_row(p): """Převede patient dict na tuple pro UPSERT.""" insurance = p.get("insuranceCompanyObject") or {} @@ -308,20 +361,9 @@ def main(): conn.close() return - # --- Krok 2: pro každého stáhni detail --- - print(f"\nStahuji detaily pro {len(patients)} pacientu...") - detailed = [] - errors = 0 - for i, p in enumerate(patients): - detail = fetch_patient_detail(headers, p["id"]) - if detail: - detailed.append(detail) - else: - errors += 1 - - if (i + 1) % 50 == 0: - print(f" Detail {i + 1}/{len(patients)}...") - time.sleep(DELAY_BETWEEN_REQUESTS) + # --- Krok 2: pro každého stáhni detail (paralelně) --- + print(f"\nStahuji detaily pro {len(patients)} pacientu ({MAX_WORKERS} threadů)...") + detailed, errors = fetch_all_details_threaded(headers, patients) # --- Krok 3: upsert do MySQL --- count = upsert_patients(conn, detailed) diff --git a/mcp_firebird.py b/mcp_firebird.py new file mode 100644 index 0000000..fcc262d --- /dev/null +++ b/mcp_firebird.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 +""" +MCP server pro Firebird/Medicus — používá oficiální MCP SDK (FastMCP) +Spustit: python mcp_firebird.py +""" + +import sys +import fdb +import traceback +from typing import Optional +from mcp.server.fastmcp import FastMCP + +FB_CONFIG = { + 'dsn': r'localhost:c:\medicus 3\data\medicus.fdb', + 'user': 'SYSDBA', + 'password': 'masterkey', + 'charset': 'win1250', + 'port': 3070, +} + +# Všechny logy MUSÍ jít na stderr — stdout je rezervován pro JSON-RPC +def log(msg: str): + print(msg, file=sys.stderr, flush=True) + + +# Připojení k Firebirdu +try: + conn = fdb.connect(**FB_CONFIG) + log("✓ Připojeno k Firebirdu (Medicus)") +except Exception as e: + log(f"✗ Chyba připojení k Firebirdu: {e}") + sys.exit(1) + + +def rows_to_json(rows, description): + """Převede fdb rows na JSON-serializovatelný formát""" + import datetime + import decimal + + def convert(val): + if isinstance(val, (datetime.date, datetime.datetime)): + return val.isoformat() + if isinstance(val, decimal.Decimal): + return float(val) + if isinstance(val, bytes): + return val.decode('win1250', errors='replace') + return val + + cols = [d[0].strip() for d in description] + return [dict(zip(cols, [convert(v) for v in row])) for row in rows] + + +# MCP server +mcp = FastMCP("medicus-firebird") + + +@mcp.tool() +def execute_query(sql: str, params: Optional[list] = None) -> dict: + """Spusť SQL dotaz na Medicus databázi. + Pro SELECT vrátí columns + rows. Pro INSERT/UPDATE/DELETE vrátí rowcount. + """ + try: + cur = conn.cursor() + if params: + cur.execute(sql, params) + else: + cur.execute(sql) + + if sql.strip().upper().startswith('SELECT'): + rows = rows_to_json(cur.fetchall(), cur.description or []) + return { + 'rowcount': len(rows), + 'rows': rows + } + else: + conn.commit() + return { + 'rowcount': cur.rowcount, + 'message': f'Dotaz proveden: {cur.rowcount} řádků ovlivněno' + } + except Exception as e: + log(f"execute_query chyba: {traceback.format_exc()}") + raise + + +@mcp.tool() +def list_tables() -> list[str]: + """Vrátí seznam všech uživatelských tabulek v Medicus databázi.""" + try: + cur = conn.cursor() + cur.execute(""" + SELECT TRIM(RDB$RELATION_NAME) + FROM RDB$RELATIONS + WHERE RDB$SYSTEM_FLAG = 0 + ORDER BY RDB$RELATION_NAME + """) + return [row[0] for row in cur.fetchall()] + except Exception as e: + log(f"list_tables chyba: {traceback.format_exc()}") + raise + + +@mcp.tool() +def get_table_columns(table_name: str) -> list[str]: + """Vrátí seznam sloupců dané tabulky.""" + try: + cur = conn.cursor() + cur.execute(""" + SELECT TRIM(RDB$FIELD_NAME) + FROM RDB$RELATION_FIELDS + WHERE TRIM(RDB$RELATION_NAME) = ? + ORDER BY RDB$FIELD_POSITION + """, [table_name.upper()]) + return [row[0] for row in cur.fetchall()] + except Exception as e: + log(f"get_table_columns chyba: {traceback.format_exc()}") + raise + + +@mcp.tool() +def get_schema() -> dict: + """Vrátí kompletní schéma DB — všechny tabulky a jejich sloupce.""" + try: + cur = conn.cursor() + cur.execute(""" + SELECT r.RDB$RELATION_NAME, f.RDB$FIELD_NAME + FROM RDB$RELATIONS r + LEFT JOIN RDB$RELATION_FIELDS f ON r.RDB$RELATION_NAME = f.RDB$RELATION_NAME + WHERE r.RDB$SYSTEM_FLAG = 0 + ORDER BY r.RDB$RELATION_NAME, f.RDB$FIELD_POSITION + """) + + schema = {} + for tbl_name, col_name in cur.fetchall(): + tbl = tbl_name.strip() if tbl_name else 'unknown' + col = col_name.strip() if col_name else '' + if tbl not in schema: + schema[tbl] = [] + if col: + schema[tbl].append(col) + + return { + 'table_count': len(schema), + 'tables': list(schema.keys()), + 'schema': schema + } + except Exception as e: + log(f"get_schema chyba: {traceback.format_exc()}") + raise + + +if __name__ == '__main__': + log("MCP Firebird server spuštěn (FastMCP)") + mcp.run() diff --git a/test_mcp.json b/test_mcp.json new file mode 100644 index 0000000..7a8a455 --- /dev/null +++ b/test_mcp.json @@ -0,0 +1 @@ +{"method": "get_schema"} diff --git a/test_reporter_fdb.py b/test_reporter_fdb.py new file mode 100644 index 0000000..892e99f --- /dev/null +++ b/test_reporter_fdb.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Test pripojeni k Firebird databazi na REPORTER""" + +import sys + +print("=== Test pripojeni k Firebird na REPORTER ===\n") + +# 1. Zkontroluj fdb +try: + import fdb + print("+ fdb je nainstalovan") +except ImportError as e: + print(f"- fdb neni nainstalovan: {e}") + print(" Instalace: pip install fdb") + sys.exit(1) + +# 2. Zkus pripojeni +print("\nPokus o pripojeni k databazi...") +print(" dsn: reporter:c:\\medicus\\medicus.fdb") +print(" user: SYSDBA") +print(" charset: win1250\n") + +try: + conn = fdb.connect( + dsn=r'reporter:c:\medicus\medicus.fdb', + user='SYSDBA', + password='masterkey', + charset='win1250' + ) + print("+ Pripojeni se podarilo!") + + # Testovaci SELECT + cursor = conn.cursor() + + # Jednoducky test - zjisti verzi Firebirdu + cursor.execute("SELECT RDB$GET_CONTEXT('SYSTEM', 'ENGINE_VERSION') FROM RDB$DATABASE") + version = cursor.fetchone()[0] + print(f"+ Firebird verze: {version}") + + # Zjisti kolik je tabulek + cursor.execute("SELECT COUNT(*) FROM RDB$RELATIONS WHERE RDB$SYSTEM_FLAG = 0") + table_count = cursor.fetchone()[0] + print(f"+ Pocet uzivatelskych tabulek: {table_count}") + + conn.close() + + print("\n" + "="*60) + print("SUCCESS: Databaze na REPORTER je dostupna a funguje!") + print("="*60) + print("\nMuzete pouzit:") + print(" conn = fdb.connect(") + print(" dsn=r'reporter:c:\\medicus\\medicus.fdb',") + print(" user='SYSDBA',") + print(" password='masterkey',") + print(" charset='win1250'") + print(" )") + +except Exception as e: + print(f"\n- Chyba: {type(e).__name__}") + print(f" {e}") + import traceback + traceback.print_exc() + sys.exit(1)