reporter
This commit is contained in:
2
.idea/Medevio.iml
generated
2
.idea/Medevio.iml
generated
@@ -4,7 +4,7 @@
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.12 (Medevio)" jdkType="Python SDK" />
|
||||
<orderEntry type="jdk" jdkName="Python 3.13 (Medevio)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -3,5 +3,5 @@
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.12 (Medevio)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 (Medevio)" project-jdk-type="Python SDK" />
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (Medevio)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
@@ -8,6 +8,18 @@ from datetime import datetime, timezone
|
||||
import time
|
||||
from dateutil import parser
|
||||
|
||||
# Force UTF-8 output even under Windows Task Scheduler
|
||||
import sys
|
||||
try:
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
sys.stderr.reconfigure(encoding='utf-8')
|
||||
except AttributeError:
|
||||
# Python < 3.7 fallback (not needed for you, but safe)
|
||||
import io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
|
||||
|
||||
|
||||
# ================================
|
||||
# 🔧 CONFIGURATION
|
||||
# ================================
|
||||
|
||||
@@ -6,13 +6,41 @@ import requests
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from dateutil import parser
|
||||
import sys
|
||||
|
||||
# Force UTF-8 output even under Windows Task Scheduler
|
||||
import sys
|
||||
try:
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
sys.stderr.reconfigure(encoding='utf-8')
|
||||
except AttributeError:
|
||||
# Python < 3.7 fallback (not needed for you, but safe)
|
||||
import io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
|
||||
|
||||
# ================================
|
||||
# 🛡 SAFE PRINT FOR CP1250 / Emoji
|
||||
# ================================
|
||||
def safe_print(text: str):
|
||||
enc = sys.stdout.encoding or ""
|
||||
if not enc.lower().startswith("utf"):
|
||||
# strip emoji + characters outside BMP
|
||||
text = ''.join(ch for ch in text if ord(ch) < 65536)
|
||||
try:
|
||||
print(text)
|
||||
except UnicodeEncodeError:
|
||||
# final fallback to ASCII only
|
||||
text = ''.join(ch for ch in text if ord(ch) < 128)
|
||||
print(text)
|
||||
|
||||
|
||||
# ================================
|
||||
# 🔧 CONFIGURATION
|
||||
# ================================
|
||||
TOKEN_PATH = Path("token.txt")
|
||||
CLINIC_SLUG = "mudr-buzalkova"
|
||||
LIMIT = 300 # stáhneme posledních 300 ukončených požadavků
|
||||
LIMIT = 300
|
||||
|
||||
DB_CONFIG = {
|
||||
"host": "192.168.1.76",
|
||||
@@ -24,7 +52,7 @@ DB_CONFIG = {
|
||||
"cursorclass": pymysql.cursors.DictCursor,
|
||||
}
|
||||
|
||||
# ⭐ Ověřený dotaz s lastMessage
|
||||
# ⭐ GraphQL query
|
||||
GRAPHQL_QUERY = r"""
|
||||
query ClinicRequestList2(
|
||||
$clinicSlug: String!,
|
||||
@@ -71,33 +99,31 @@ def read_token(path: Path) -> str:
|
||||
return tok.split(" ", 1)[1]
|
||||
return tok
|
||||
|
||||
|
||||
# ================================
|
||||
# DATETIME PARSER (UTC → MySQL)
|
||||
# DATETIME PARSER
|
||||
# ================================
|
||||
def to_mysql_dt(iso_str):
|
||||
if not iso_str:
|
||||
return None
|
||||
try:
|
||||
dt = parser.isoparse(iso_str) # ISO8601 → aware datetime (UTC)
|
||||
dt = dt.astimezone() # převede na lokální čas (CET/CEST)
|
||||
dt = parser.isoparse(iso_str)
|
||||
dt = dt.astimezone()
|
||||
return dt.strftime("%Y-%m-%d %H:%M:%S")
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
# ================================
|
||||
# UPSERT WITH MERGED UPDATED TIME
|
||||
# UPSERT
|
||||
# ================================
|
||||
def upsert(conn, r):
|
||||
p = r.get("extendedPatient") or {}
|
||||
|
||||
# API pole
|
||||
api_updated = to_mysql_dt(r.get("updatedAt"))
|
||||
|
||||
# poslední zpráva
|
||||
last_msg = r.get("lastMessage") or {}
|
||||
msg_at = to_mysql_dt(last_msg.get("createdAt"))
|
||||
|
||||
# vybereme novější čas
|
||||
def max_dt(a, b):
|
||||
if a and b:
|
||||
return max(a, b)
|
||||
@@ -137,6 +163,7 @@ def upsert(conn, r):
|
||||
|
||||
conn.commit()
|
||||
|
||||
|
||||
# ================================
|
||||
# FETCH LAST 300 DONE REQUESTS
|
||||
# ================================
|
||||
@@ -162,6 +189,7 @@ def fetch_done(headers):
|
||||
data = r.json()["data"]["requestsResponse"]
|
||||
return data.get("patientRequests", [])
|
||||
|
||||
|
||||
# ================================
|
||||
# MAIN
|
||||
# ================================
|
||||
@@ -175,17 +203,18 @@ def main():
|
||||
|
||||
conn = pymysql.connect(**DB_CONFIG)
|
||||
|
||||
print(f"\n=== Downloading last {LIMIT} DONE requests @ {datetime.now():%Y-%m-%d %H:%M:%S} ===")
|
||||
safe_print(f"\n=== Downloading last {LIMIT} DONE requests @ {datetime.now():%Y-%m-%d %H:%M:%S} ===")
|
||||
|
||||
requests_list = fetch_done(headers)
|
||||
print(f"📌 Requests returned: {len(requests_list)}")
|
||||
safe_print(f"📌 Requests returned: {len(requests_list)}")
|
||||
|
||||
for r in requests_list:
|
||||
upsert(conn, r)
|
||||
|
||||
conn.close()
|
||||
print("\n✅ DONE - latest closed requests synced.\n")
|
||||
safe_print("\n\u2705 DONE - latest closed requests synced.\n")
|
||||
|
||||
|
||||
# ================================
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -12,6 +12,35 @@ import pymysql
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
import time
|
||||
import sys
|
||||
|
||||
# Force UTF-8 output even under Windows Task Scheduler
|
||||
import sys
|
||||
try:
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
sys.stderr.reconfigure(encoding='utf-8')
|
||||
except AttributeError:
|
||||
# Python < 3.7 fallback (not needed for you, but safe)
|
||||
import io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
|
||||
|
||||
|
||||
# ==============================
|
||||
# 🛡 SAFE PRINT FOR CP1250 / EMOJI
|
||||
# ==============================
|
||||
def safe_print(text: str):
|
||||
enc = sys.stdout.encoding or ""
|
||||
if not enc.lower().startswith("utf"):
|
||||
# strip emoji + anything above BMP
|
||||
text = ''.join(ch for ch in text if ord(ch) < 65536)
|
||||
try:
|
||||
print(text)
|
||||
except UnicodeEncodeError:
|
||||
# final ASCII fallback
|
||||
text = ''.join(ch for ch in text if ord(ch) < 128)
|
||||
print(text)
|
||||
|
||||
|
||||
# ==============================
|
||||
# 🔧 CONFIGURATION
|
||||
@@ -31,29 +60,30 @@ DB_CONFIG = {
|
||||
}
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
# ==============================
|
||||
# 🕒 DATETIME FIXER
|
||||
# ==============================
|
||||
def fix_datetime(dt_str):
|
||||
"""Convert ISO 8601 string with 'Z' or ms into MySQL DATETIME format."""
|
||||
if not dt_str:
|
||||
return None
|
||||
try:
|
||||
# Remove trailing Z and parse flexible ISO format
|
||||
return datetime.fromisoformat(dt_str.replace("Z", "").replace("+00:00", ""))
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
# ✅ Optional: limit which requests to process
|
||||
CREATED_AFTER = "2025-01-01" # set "" to disable
|
||||
|
||||
# Optional filter
|
||||
CREATED_AFTER = "2025-01-01"
|
||||
|
||||
|
||||
# ==============================
|
||||
# 🧮 HELPERS
|
||||
# ==============================
|
||||
def read_token(p: Path) -> str:
|
||||
"""Read Bearer token from file."""
|
||||
tok = p.read_text(encoding="utf-8").strip()
|
||||
if tok.startswith("Bearer "):
|
||||
tok = tok.split(" ", 1)[1]
|
||||
return tok.split(" ", 1)[1]
|
||||
return tok
|
||||
|
||||
|
||||
@@ -101,7 +131,7 @@ def fetch_questionnaire(headers, request_id, clinic_slug):
|
||||
}
|
||||
r = requests.post(GRAPHQL_URL, json=payload, headers=headers, timeout=40)
|
||||
if r.status_code != 200:
|
||||
print(f"❌ HTTP {r.status_code} for {request_id}: {r.text}")
|
||||
safe_print(f"❌ HTTP {r.status_code} for {request_id}: {r.text}")
|
||||
return None
|
||||
return r.json().get("data", {}).get("request")
|
||||
|
||||
@@ -118,23 +148,24 @@ def insert_questionnaire(cur, req):
|
||||
updated_at = fix_datetime(req.get("updatedAt"))
|
||||
|
||||
cur.execute("""
|
||||
INSERT INTO medevio_questionnaires (
|
||||
request_id, created_at, updated_at, user_note, ecrf_json
|
||||
)
|
||||
VALUES (%s,%s,%s,%s,%s)
|
||||
INSERT INTO medevio_questionnaires (
|
||||
request_id, created_at, updated_at, user_note, ecrf_json
|
||||
)
|
||||
VALUES (%s,%s,%s,%s,%s)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
updated_at = VALUES(updated_at),
|
||||
user_note = VALUES(user_note),
|
||||
ecrf_json = VALUES(ecrf_json),
|
||||
updated_local = NOW()
|
||||
""", (
|
||||
req.get("id"),
|
||||
created_at,
|
||||
updated_at,
|
||||
req.get("userNote"),
|
||||
json.dumps(ecrf_data, ensure_ascii=False),
|
||||
))
|
||||
print(f" 💾 Stored questionnaire for {patient.get('surname','')} {patient.get('name','')}")
|
||||
req.get("id"),
|
||||
created_at,
|
||||
updated_at,
|
||||
req.get("userNote"),
|
||||
json.dumps(ecrf_data, ensure_ascii=False),
|
||||
))
|
||||
|
||||
safe_print(f" 💾 Stored questionnaire for {patient.get('surname','')} {patient.get('name','')}")
|
||||
|
||||
|
||||
# ==============================
|
||||
@@ -149,6 +180,8 @@ def main():
|
||||
}
|
||||
|
||||
conn = pymysql.connect(**DB_CONFIG)
|
||||
|
||||
# load list of requests
|
||||
with conn.cursor() as cur:
|
||||
sql = """
|
||||
SELECT id, pacient_jmeno, pacient_prijmeni, createdAt, updatedAt, questionnaireprocessed
|
||||
@@ -163,26 +196,30 @@ def main():
|
||||
|
||||
rows = cur.fetchall()
|
||||
|
||||
print(f"📋 Found {len(rows)} requests needing questionnaire check.")
|
||||
safe_print(f"📋 Found {len(rows)} requests needing questionnaire check.")
|
||||
|
||||
# process each one
|
||||
for i, row in enumerate(rows, 1):
|
||||
req_id = row["id"]
|
||||
print(f"\n[{i}/{len(rows)}] 🔍 Fetching questionnaire for {req_id} ...")
|
||||
safe_print(f"\n[{i}/{len(rows)}] 🔍 Fetching questionnaire for {req_id} ...")
|
||||
|
||||
req = fetch_questionnaire(headers, req_id, CLINIC_SLUG)
|
||||
if not req:
|
||||
print(" ⚠️ No questionnaire data found.")
|
||||
safe_print(" ⚠️ No questionnaire data found.")
|
||||
continue
|
||||
|
||||
with conn.cursor() as cur:
|
||||
insert_questionnaire(cur, req)
|
||||
cur.execute("UPDATE pozadavky SET questionnaireprocessed = NOW() WHERE id = %s", (req_id,))
|
||||
cur.execute(
|
||||
"UPDATE pozadavky SET questionnaireprocessed = NOW() WHERE id = %s",
|
||||
(req_id,)
|
||||
)
|
||||
conn.commit()
|
||||
|
||||
time.sleep(0.6) # polite pacing
|
||||
time.sleep(0.6)
|
||||
|
||||
conn.close()
|
||||
print("\n✅ Done! All questionnaires stored in MySQL table `medevio_questionnaires`.")
|
||||
safe_print("\n✅ Done! All questionnaires stored in MySQL table `medevio_questionnaires`.")
|
||||
|
||||
|
||||
# ==============================
|
||||
|
||||
@@ -15,6 +15,34 @@ import pymysql
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
import time
|
||||
import sys
|
||||
|
||||
# Force UTF-8 output even under Windows Task Scheduler
|
||||
import sys
|
||||
try:
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
sys.stderr.reconfigure(encoding='utf-8')
|
||||
except AttributeError:
|
||||
# Python < 3.7 fallback (not needed for you, but safe)
|
||||
import io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
|
||||
|
||||
# ==============================
|
||||
# 🛡 SAFE PRINT FOR CP1250 / EMOJI
|
||||
# ==============================
|
||||
def safe_print(text: str):
|
||||
enc = sys.stdout.encoding or ""
|
||||
if not enc or not enc.lower().startswith("utf"):
|
||||
# strip emoji + characters outside BMP for Task Scheduler (CP1250)
|
||||
text = ''.join(ch for ch in text if ord(ch) < 65536)
|
||||
try:
|
||||
print(text)
|
||||
except UnicodeEncodeError:
|
||||
# fallback pure ASCII
|
||||
text = ''.join(ch for ch in text if ord(ch) < 128)
|
||||
print(text)
|
||||
|
||||
|
||||
# ==============================
|
||||
# 🔧 CONFIGURATION
|
||||
@@ -94,7 +122,7 @@ def fetch_messages(headers, request_id):
|
||||
|
||||
r = requests.post("https://api.medevio.cz/graphql", json=payload, headers=headers, timeout=30)
|
||||
if r.status_code != 200:
|
||||
print("❌ HTTP", r.status_code, "for request", request_id)
|
||||
safe_print(f"❌ HTTP {r.status_code} for request {request_id}")
|
||||
return []
|
||||
return r.json().get("data", {}).get("messages", []) or []
|
||||
|
||||
@@ -158,7 +186,7 @@ def insert_download(cur, req_id, msg, existing_ids):
|
||||
return
|
||||
|
||||
if attachment_id in existing_ids:
|
||||
return # skip duplicates
|
||||
return
|
||||
|
||||
url = mr.get("downloadUrl") or mr.get("url")
|
||||
if not url:
|
||||
@@ -169,7 +197,7 @@ def insert_download(cur, req_id, msg, existing_ids):
|
||||
r.raise_for_status()
|
||||
data = r.content
|
||||
except Exception as e:
|
||||
print("⚠️ Failed to download:", e)
|
||||
safe_print(f"⚠️ Failed to download: {e}")
|
||||
return
|
||||
|
||||
filename = url.split("/")[-1].split("?")[0]
|
||||
@@ -216,7 +244,7 @@ def main():
|
||||
cur.execute("SELECT attachment_id FROM medevio_downloads")
|
||||
existing_ids = {row["attachment_id"] for row in cur.fetchall()}
|
||||
|
||||
print(f"📦 Already downloaded attachments: {len(existing_ids)}\n")
|
||||
safe_print(f"📦 Already downloaded attachments: {len(existing_ids)}\n")
|
||||
|
||||
# ---- Select pozadavky needing message sync
|
||||
sql = """
|
||||
@@ -229,12 +257,12 @@ def main():
|
||||
cur.execute(sql)
|
||||
requests_to_process = cur.fetchall()
|
||||
|
||||
print(f"📋 Found {len(requests_to_process)} pozadavků requiring message sync.\n")
|
||||
safe_print(f"📋 Found {len(requests_to_process)} pozadavků requiring message sync.\n")
|
||||
|
||||
# ---- Process each pozadavek
|
||||
# ---- Process each record
|
||||
for idx, row in enumerate(requests_to_process, 1):
|
||||
req_id = row["id"]
|
||||
print(f"[{idx}/{len(requests_to_process)}] Processing {req_id} …")
|
||||
safe_print(f"[{idx}/{len(requests_to_process)}] Processing {req_id} …")
|
||||
|
||||
messages = fetch_messages(headers, req_id)
|
||||
|
||||
@@ -248,11 +276,11 @@ def main():
|
||||
cur.execute("UPDATE pozadavky SET messagesProcessed = NOW() WHERE id = %s", (req_id,))
|
||||
conn.commit()
|
||||
|
||||
print(f" ✅ {len(messages)} messages saved\n")
|
||||
safe_print(f" ✅ {len(messages)} messages saved\n")
|
||||
time.sleep(0.25)
|
||||
|
||||
conn.close()
|
||||
print("🎉 Done!")
|
||||
safe_print("🎉 Done!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -14,6 +14,36 @@ import pymysql
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
import time
|
||||
import sys
|
||||
|
||||
# Force UTF-8 output even under Windows Task Scheduler
|
||||
import sys
|
||||
try:
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
sys.stderr.reconfigure(encoding='utf-8')
|
||||
except AttributeError:
|
||||
# Python < 3.7 fallback (not needed for you, but safe)
|
||||
import io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
|
||||
|
||||
|
||||
# ==============================
|
||||
# 🛡 SAFE PRINT FOR CP1250 / EMOJI
|
||||
# ==============================
|
||||
def safe_print(text: str):
|
||||
enc = sys.stdout.encoding or ""
|
||||
if not enc or not enc.lower().startswith("utf"):
|
||||
# strip emoji + characters outside BMP
|
||||
text = ''.join(ch for ch in text if ord(ch) < 65536)
|
||||
|
||||
try:
|
||||
print(text)
|
||||
except UnicodeEncodeError:
|
||||
# ASCII fallback
|
||||
text = ''.join(ch for ch in text if ord(ch) < 128)
|
||||
print(text)
|
||||
|
||||
|
||||
# ==============================
|
||||
# 🔧 CONFIGURATION
|
||||
@@ -67,6 +97,7 @@ def read_token(p: Path) -> str:
|
||||
tok = p.read_text(encoding="utf-8").strip()
|
||||
return tok.split(" ", 1)[1] if tok.startswith("Bearer ") else tok
|
||||
|
||||
|
||||
# ==============================
|
||||
# 📡 FETCH ATTACHMENTS
|
||||
# ==============================
|
||||
@@ -78,42 +109,40 @@ def fetch_attachments(headers, request_id):
|
||||
}
|
||||
r = requests.post("https://api.medevio.cz/graphql", json=payload, headers=headers, timeout=30)
|
||||
if r.status_code != 200:
|
||||
print(f"❌ HTTP {r.status_code} for request {request_id}")
|
||||
safe_print(f"❌ HTTP {r.status_code} for request {request_id}")
|
||||
return []
|
||||
return r.json().get("data", {}).get("patientRequestMedicalRecords", [])
|
||||
|
||||
|
||||
# ==============================
|
||||
# 💾 SAVE TO MYSQL (clean version)
|
||||
# 💾 SAVE TO MYSQL
|
||||
# ==============================
|
||||
def insert_download(cur, req_id, a, m, created_date, existing_ids):
|
||||
|
||||
attachment_id = a.get("id")
|
||||
if attachment_id in existing_ids:
|
||||
print(f" ⏭️ Already downloaded {attachment_id}")
|
||||
safe_print(f" ⏭️ Already downloaded {attachment_id}")
|
||||
return False
|
||||
|
||||
url = m.get("downloadUrl")
|
||||
if not url:
|
||||
print(" ⚠️ Missing download URL")
|
||||
safe_print(" ⚠️ Missing download URL")
|
||||
return False
|
||||
|
||||
filename = extract_filename_from_url(url)
|
||||
|
||||
# Download file
|
||||
try:
|
||||
r = requests.get(url, timeout=30)
|
||||
r.raise_for_status()
|
||||
content = r.content
|
||||
except Exception as e:
|
||||
print(f" ⚠️ Download failed {url}: {e}")
|
||||
safe_print(f" ⚠️ Download failed {url}: {e}")
|
||||
return False
|
||||
|
||||
file_size = len(content)
|
||||
attachment_type = a.get("attachmentType")
|
||||
content_type = m.get("contentType")
|
||||
|
||||
# 🚨 CLEAN INSERT — no patient_jmeno/no patient_prijmeni
|
||||
cur.execute("""
|
||||
INSERT INTO medevio_downloads (
|
||||
request_id, attachment_id, attachment_type,
|
||||
@@ -136,7 +165,7 @@ def insert_download(cur, req_id, a, m, created_date, existing_ids):
|
||||
))
|
||||
|
||||
existing_ids.add(attachment_id)
|
||||
print(f" 💾 Saved {filename} ({file_size/1024:.1f} kB)")
|
||||
safe_print(f" 💾 Saved {filename} ({file_size/1024:.1f} kB)")
|
||||
return True
|
||||
|
||||
|
||||
@@ -152,11 +181,12 @@ def main():
|
||||
|
||||
conn = pymysql.connect(**DB_CONFIG)
|
||||
|
||||
# Load existing IDs
|
||||
# Load existing attachments
|
||||
with conn.cursor() as cur:
|
||||
cur.execute("SELECT attachment_id FROM medevio_downloads")
|
||||
existing_ids = {row["attachment_id"] for row in cur.fetchall()}
|
||||
print(f"✅ {len(existing_ids)} attachments already saved.")
|
||||
|
||||
safe_print(f"✅ {len(existing_ids)} attachments already saved.")
|
||||
|
||||
# Build query for pozadavky
|
||||
sql = """
|
||||
@@ -173,7 +203,7 @@ def main():
|
||||
cur.execute(sql, params)
|
||||
req_rows = cur.fetchall()
|
||||
|
||||
print(f"📋 Found {len(req_rows)} pozadavky to process.")
|
||||
safe_print(f"📋 Found {len(req_rows)} pozadavky to process.")
|
||||
|
||||
# Process each pozadavek
|
||||
for i, row in enumerate(req_rows, 1):
|
||||
@@ -182,12 +212,12 @@ def main():
|
||||
jmeno = row.get("pacient_jmeno") or ""
|
||||
created_date = row.get("createdAt") or datetime.now()
|
||||
|
||||
print(f"\n[{i}/{len(req_rows)}] 🧾 {prijmeni}, {jmeno} ({req_id})")
|
||||
safe_print(f"\n[{i}/{len(req_rows)}] 🧾 {prijmeni}, {jmeno} ({req_id})")
|
||||
|
||||
attachments = fetch_attachments(headers, req_id)
|
||||
|
||||
if not attachments:
|
||||
print(" ⚠️ No attachments found")
|
||||
safe_print(" ⚠️ No attachments found")
|
||||
with conn.cursor() as cur:
|
||||
cur.execute("UPDATE pozadavky SET attachmentsProcessed = NOW() WHERE id = %s", (req_id,))
|
||||
conn.commit()
|
||||
@@ -199,17 +229,16 @@ def main():
|
||||
insert_download(cur, req_id, a, m, created_date, existing_ids)
|
||||
conn.commit()
|
||||
|
||||
# Mark processed
|
||||
with conn.cursor() as cur:
|
||||
cur.execute("UPDATE pozadavky SET attachmentsProcessed = NOW() WHERE id = %s", (req_id,))
|
||||
conn.commit()
|
||||
|
||||
print(f" ✅ Done ({len(attachments)} attachments)")
|
||||
|
||||
safe_print(f" ✅ Done ({len(attachments)} attachments)")
|
||||
time.sleep(0.3)
|
||||
|
||||
conn.close()
|
||||
print("\n🎯 All attachments processed.")
|
||||
safe_print("\n🎯 All attachments processed.")
|
||||
|
||||
|
||||
# ==============================
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -10,6 +10,17 @@ from datetime import datetime
|
||||
import time
|
||||
import sys
|
||||
|
||||
# Force UTF-8 output even under Windows Task Scheduler
|
||||
import sys
|
||||
try:
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
sys.stderr.reconfigure(encoding='utf-8')
|
||||
except AttributeError:
|
||||
# Python < 3.7 fallback (not needed for you, but safe)
|
||||
import io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
|
||||
|
||||
# ==============================
|
||||
# 🛡 SAFE PRINT FOR CP1250 / EMOJI
|
||||
# ==============================
|
||||
@@ -92,17 +103,16 @@ safe_print("🔍 Loading metadata from DB (FAST)…")
|
||||
|
||||
cur_meta.execute("""
|
||||
SELECT d.id AS download_id,
|
||||
d.request_id,
|
||||
d.filename,
|
||||
d.created_at,
|
||||
p.updatedAt AS req_updated_at,
|
||||
p.pacient_jmeno AS jmeno,
|
||||
p.pacient_prijmeni AS prijmeni,
|
||||
p.displayTitle
|
||||
FROM medevio_downloads d
|
||||
JOIN pozadavky p ON d.request_id = p.id
|
||||
WHERE d.downloaded_at IS NULL
|
||||
ORDER BY p.updatedAt DESC
|
||||
d.request_id,
|
||||
d.filename,
|
||||
d.created_at,
|
||||
p.updatedAt AS req_updated_at,
|
||||
p.pacient_jmeno AS jmeno,
|
||||
p.pacient_prijmeni AS prijmeni,
|
||||
p.displayTitle
|
||||
FROM medevio_downloads d
|
||||
JOIN pozadavky p ON d.request_id = p.id
|
||||
ORDER BY p.updatedAt DESC
|
||||
""")
|
||||
|
||||
rows = cur_meta.fetchall()
|
||||
|
||||
@@ -15,7 +15,7 @@ Spustí všechny PRAVIDELNÉ skripty v daném pořadí:
|
||||
import time, socket
|
||||
for _ in range(30):
|
||||
try:
|
||||
socket.create_connection(("127.0.0.1", 3307), timeout=3).close()
|
||||
socket.create_connection(("192.168.1.76", 3307), timeout=3).close()
|
||||
break
|
||||
except OSError:
|
||||
time.sleep(10)
|
||||
|
||||
136
10ReadPozadavky/test.py
Normal file
136
10ReadPozadavky/test.py
Normal file
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Orchestrator for all PRAVIDELNE scripts in exact order.
|
||||
"""
|
||||
|
||||
import time, socket
|
||||
for _ in range(30):
|
||||
try:
|
||||
socket.create_connection(("192.168.1.76", 3307), timeout=3).close()
|
||||
break
|
||||
except OSError:
|
||||
time.sleep(10)
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
# =====================================================================
|
||||
# Import EXACT Functions.py from: C:\Reporting\Fio\Functions.py
|
||||
# This bypasses all other Functions.py files in the system.
|
||||
# =====================================================================
|
||||
|
||||
import importlib.util
|
||||
|
||||
FUNCTIONS_FILE = Path(r"C:\Reporting\Fio\Functions.py")
|
||||
|
||||
spec = importlib.util.spec_from_file_location("Functions_FIO", FUNCTIONS_FILE)
|
||||
Functions_FIO = importlib.util.module_from_spec(spec)
|
||||
sys.modules["Functions_FIO"] = Functions_FIO
|
||||
spec.loader.exec_module(Functions_FIO)
|
||||
|
||||
# correct WhatsApp function
|
||||
SendWhatsAppMessage = Functions_FIO.SendWhatsAppMessage
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# General Orchestrator Settings
|
||||
# =====================================================================
|
||||
|
||||
# folder where orchestrator + sub-scripts live
|
||||
BASE_DIR = Path(__file__).resolve().parent
|
||||
|
||||
SCRIPTS_IN_ORDER = [
|
||||
"PRAVIDELNE_0_READ_ALL_ACTIVE_POZADAVKY.py",
|
||||
"PRAVIDELNE_1_ReadLast300DonePozadavku.py",
|
||||
"PRAVIDELNE_2_ReadPoznamky.py",
|
||||
"PRAVIDELNE_3_StahniKomunikaci.py",
|
||||
"PRAVIDELNE_4_StahniPrilohyUlozDoMySQL.py",
|
||||
"PRAVIDELNE_5_SaveToFileSystem incremental.py",
|
||||
]
|
||||
|
||||
LOG_FILE = BASE_DIR / "PRAVIDELNE_log.txt"
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# Logging + WhatsApp wrappers
|
||||
# =====================================================================
|
||||
|
||||
def log(msg: str):
|
||||
ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
line = f"[{ts}] {msg}"
|
||||
print(line)
|
||||
try:
|
||||
with LOG_FILE.open("a", encoding="utf-8") as f:
|
||||
f.write(line + "\n")
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def whatsapp_notify(text: str):
|
||||
"""WhatsApp message wrapper — never allowed to crash orchestrator"""
|
||||
try:
|
||||
SendWhatsAppMessage(text)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# Main orchestrator
|
||||
# =====================================================================
|
||||
|
||||
def main():
|
||||
log("=== START pravidelného běhu ===")
|
||||
whatsapp_notify("🏁 *PRAVIDELNÉ skripty: START*")
|
||||
|
||||
for script_name in SCRIPTS_IN_ORDER:
|
||||
script_path = BASE_DIR / script_name
|
||||
|
||||
if not script_path.exists():
|
||||
err = f"❌ Skript nenalezen: {script_path}"
|
||||
log(err)
|
||||
whatsapp_notify(err)
|
||||
continue
|
||||
|
||||
log(f"▶ Spouštím: {script_path.name}")
|
||||
whatsapp_notify(f"▶ *Spouštím:* {script_path.name}")
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[sys.executable, str(script_path)],
|
||||
cwd=str(BASE_DIR),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="ignore",
|
||||
)
|
||||
except Exception as e:
|
||||
err = f"💥 Chyba při spouštění {script_path.name}: {e}"
|
||||
log(err)
|
||||
whatsapp_notify(err)
|
||||
continue
|
||||
|
||||
# return code
|
||||
rc_msg = f"↳ {script_path.name} return code: {result.returncode}"
|
||||
log(rc_msg)
|
||||
whatsapp_notify(rc_msg)
|
||||
|
||||
# stderr (warnings/errors)
|
||||
if result.stderr:
|
||||
err_msg = f"⚠ stderr v {script_path.name}:\n{result.stderr.strip()}"
|
||||
log(err_msg)
|
||||
whatsapp_notify(err_msg)
|
||||
|
||||
log("=== KONEC pravidelného běhu ===")
|
||||
whatsapp_notify("✅ *PRAVIDELNÉ skripty: KONEC*\n")
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# Entry point
|
||||
# =====================================================================
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user