#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ medevio_recept.py — vytvoření požadavku "Recept na léky" v Medeviu pro pacienta. Určeno k volání z e-mailového agenta (recepty_agent.py): jakmile agent správně identifikuje pacienta a co chce, založí mu v Medeviu požadavek, aby ho lékař viděl (e-mail kontrolujeme zřídka, Medevio pořád). Hlavní funkce: vytvor_recept(rodne_cislo, nazev_leku, poznamka) -> request_id Co dělá (vše ověřeno/odchyceno 2026-06-13 na testovacím pacientovi Vladko): 1. RČ -> patient UUID (MySQL medevio.medevio_pacient) 2. fillECRFForm -> ecrfFill.id (prázdný formulář) 3. createPatientRequestWithoutReservation -> založí "Recept na léky" 4. createClinicPatientRequestNote -> obě pole do INTERNÍ POZNÁMKY 5. assignTagToPatientRequest -> štítek CLAUDE POZOR: lékařský (klinický) přístup neumí vyplnit pacientský dotazník smysluplně, proto obsah ("Název léků" + "Poznámka") jde do interní poznámky, ne do dotazníku. Auth: Bearer token z Medevio/token.txt (dlouhodobý API token). """ import sys import re from pathlib import Path import requests import pymysql from pymysql.cursors import DictCursor try: sys.stdout.reconfigure(encoding="utf-8") except Exception: pass # ============================================================ # Konstanty odchycené z Medevia (klinika mudr-buzalkova) # ============================================================ CLINIC_SLUG = "mudr-buzalkova" GRAPHQL_URL = "https://api.medevio.cz/graphql" RECEPT_USER_ECRF_ID = "79488e86-e9e5-47e3-8b19-7e5229427f23" # typ "Recept na léky" RECEPT_SID = "ERECEPT_SIMPLEST_BEZ_DAVKOVANI" RECEPT_STEP_ID = "erecept-gp-request" CLAUDE_TAG_ID = "c136aeca-0625-4c43-b81f-fc3949ec6ba6" # štítek CLAUDE TOKEN_PATH = Path(__file__).resolve().parent.parent / "Medevio" / "token.txt" # MySQL je na různých strojích na různém portu — zkusíme kandidáty po řadě. _MYSQL_BASE = dict(user="root", password="Vlado9674+", database="medevio") _MYSQL_CANDIDATES = [ dict(host="192.168.1.76", port=3306), dict(host="192.168.1.76", port=3307), dict(host="127.0.0.1", port=3307), dict(host="127.0.0.1", port=3306), ] # ============================================================ # GraphQL operace (přesně jak je posílá web Medevia) # ============================================================ M_FILL_ECRF = r""" mutation ClinicRequestCreateModal_FillECRFForm($input: FillECRFFormInput!) { ecrfFill: fillECRFForm(input: $input) { id } } """ M_CREATE_REQUEST = r""" mutation ClinicRequestCreateModal_CreateRequest($clinicSlug: String!, $input: CreatePatientRequestWithoutReservationInput!) { patientRequest: createPatientRequestWithoutReservation(clinicSlug: $clinicSlug, input: $input) { id } } """ M_CREATE_NOTE = r""" mutation ClinicRequestNotes_Create($noteInput: CreateClinicPatientRequestNoteInput!) { createClinicPatientRequestNote(noteInput: $noteInput) { id } } """ M_ASSIGN_TAG = r""" mutation TagRequestEditModal_AssignTagToRequest($clinicSlug: String!, $requestId: UUID!, $tagId: UUID!) { tagRequest: assignTagToPatientRequest(clinicSlug: $clinicSlug, patientRequestId: $requestId, tagId: $tagId) { id } } """ # ============================================================ # Pomocné funkce # ============================================================ def _read_token() -> str: t = TOKEN_PATH.read_text(encoding="utf-8").strip() return t[7:].strip() if t.lower().startswith("bearer ") else t def _gql(query: str, variables: dict, token: str) -> dict: headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json", "Accept": "application/json", } r = requests.post(GRAPHQL_URL, json={"query": query, "variables": variables}, headers=headers, timeout=30) r.raise_for_status() data = r.json() if data.get("errors"): raise RuntimeError(f"GraphQL chyba: {data['errors']}") return data["data"] def _mysql(): last = None for cand in _MYSQL_CANDIDATES: try: return pymysql.connect(**cand, **_MYSQL_BASE, cursorclass=DictCursor, connect_timeout=4) except Exception as e: last = e raise RuntimeError(f"MySQL (medevio) nedostupné na žádném kandidátovi: {last}") def najdi_uuid_dle_rc(rodne_cislo: str) -> dict: """RČ (s lomítkem i bez) -> řádek pacienta z medevio_pacient. Vyhazuje LookupError když pacient není nalezen nebo je nejednoznačný.""" rc = re.sub(r"\D", "", rodne_cislo or "") if not rc: raise ValueError("Prázdné / neplatné rodné číslo.") conn = _mysql() try: with conn.cursor() as cur: cur.execute( "SELECT patient_id, name, surname, status, user_id " "FROM medevio_pacient " "WHERE REPLACE(identification_number, '/', '') = %s", (rc,), ) rows = cur.fetchall() finally: conn.close() if not rows: raise LookupError(f"Pacient s RČ {rc} není v Medevio databázi (medevio_pacient).") if len(rows) > 1: raise LookupError(f"RČ {rc} odpovídá více pacientům — nejednoznačné, řeš ručně.") return rows[0] def _format_note(nazev_leku: str, poznamka: str) -> str: return ( "Žádost o recept (zpracováno e-mailovým agentem).\n\n" f"Název léků:\n{(nazev_leku or '').strip() or '—'}\n\n" f"Poznámka:\n{(poznamka or '').strip() or '—'}" ) # ============================================================ # Hlavní funkce # ============================================================ def vytvor_recept(rodne_cislo: str = None, nazev_leku: str = "", poznamka: str = "", *, patient_uuid: str = None, pridat_stitek: bool = True, token: str = None, verbose: bool = True) -> str: """ Založí pacientovi požadavek "Recept na léky" + interní poznámku + štítek CLAUDE. Parametry: rodne_cislo – RČ pacienta (s lomítkem i bez); přeloží se na UUID přes MySQL. nazev_leku – text 1. pole ("Název léků"). poznamka – text 2. pole ("Poznámka"). patient_uuid – volitelně rovnou UUID pacienta (obejde lookup dle RČ; pro testy). pridat_stitek – True = přiřadí štítek CLAUDE. token – volitelně Bearer token; jinak se načte z token.txt. Vrací: request_id založeného požadavku (str). """ token = token or _read_token() if patient_uuid: uuid = patient_uuid kdo = f"UUID {uuid}" else: pac = najdi_uuid_dle_rc(rodne_cislo) uuid = pac["patient_id"] kdo = f"{pac['surname']} {pac['name']} (RČ {rodne_cislo}, status {pac['status']})" if verbose: print(f"→ Pacient: {kdo}") # 1) prázdný ECRF fill fill = _gql(M_FILL_ECRF, {"input": { "byDoctor": True, "fields": [], "patientId": uuid, "sid": RECEPT_SID, "stepId": RECEPT_STEP_ID, }}, token) ecrf_fill_id = fill["ecrfFill"]["id"] # 2) vytvoř požadavek "Recept na léky" created = _gql(M_CREATE_REQUEST, {"clinicSlug": CLINIC_SLUG, "input": { "patientId": uuid, "userECRFId": RECEPT_USER_ECRF_ID, "ecrfFillIds": [ecrf_fill_id], "createdByDoctor": True, "shouldInvitePatient": False, }}, token) request_id = created["patientRequest"]["id"] if verbose: print(f"✓ Požadavek vytvořen: {request_id}") # 3) interní poznámka s oběma poli _gql(M_CREATE_NOTE, {"noteInput": { "requestId": request_id, "content": _format_note(nazev_leku, poznamka), }}, token) if verbose: print("✓ Interní poznámka zapsána") # 4) štítek CLAUDE if pridat_stitek: _gql(M_ASSIGN_TAG, { "clinicSlug": CLINIC_SLUG, "requestId": request_id, "tagId": CLAUDE_TAG_ID, }, token) if verbose: print("✓ Štítek CLAUDE přiřazen") return request_id # ============================================================ # Test (na testovacím pacientovi Vladko) # ============================================================ if __name__ == "__main__": VLADKO_UUID = "0210db7b-8fb0-4b47-b1d8-ec7a10849a63" # Vladko - testovací aplikace rid = vytvor_recept( patient_uuid=VLADKO_UUID, nazev_leku="Euthyrox 100 µg (TEST z medevio_recept.py)", poznamka="Testovací požadavek z funkce vytvor_recept — možno zavřít.", ) print(f"\nHOTOVO. request_id = {rid}") print(f"https://my.medevio.cz/mudr-buzalkova/klinika/pacienti?pozadavek={rid}")