notebook vb
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
- Zatím: úspěšně čteme i zapisujeme do DB, rozumíme RTF formátu
|
||||
- **2026-03-17**: Obnovena session – Claude si přečetl poznámky, připraven pokračovat
|
||||
- **2026-03-18**: Obnovena session – Claude si přečetl poznámky, připraven pokračovat. Průběžně zapisuje do tohoto souboru.
|
||||
- **2026-03-20**: Obnovena session – merge logika z `test_import_single.py` integrována do `s03soubory.py`. Import pipeline kompletní.
|
||||
|
||||
## Bezpečnost
|
||||
- Pracujeme na **místní kopii** – poškození DB nevadí, obnova = 5 minut
|
||||
@@ -333,16 +334,30 @@ Správný RTF formát klikacího odkazu:
|
||||
|
||||
### Stav testování (2026-03-18)
|
||||
- `test_import_3files.py` ✅ ověřeno – klikací odkazy fungují, "Vložené přílohy:" správně
|
||||
- `test_import_merge.py` – připraveno, nespuštěno
|
||||
- `test_import_single.py` – připraveno, nespuštěno
|
||||
- `test_import_merge.py` ✅ připraveno – merge 3 souborů do dnešního dekurzu (bez sekce)
|
||||
- `test_import_single.py` ✅ připraveno – přidání 1 souboru DO existující sekce přílohy
|
||||
|
||||
### TODO – integrace do s03soubory.py
|
||||
- Přidat `najdi_posledni_dekurs_dnes()` do s03soubory.py
|
||||
- Přidat `pridat_do_sekce_prilohy()` a `merge_rtf_prepend()` do s03soubory.py
|
||||
- Nahradit přímý INSERT DEKURS rozhodovací logikou (3 případy)
|
||||
- Pozn: s03soubory.py má starý `prvnibookmark=True` blok – odstranit (relikt)
|
||||
### Stav s03soubory.py (2026-03-20) – KOMPLETNÍ ✅
|
||||
- Merge logika plně integrována z `test_import_single.py`
|
||||
- Přidány konstanty `PRILOHY_HEADER`, `PRILOHY_CLOSING`
|
||||
- Přidány funkce: `najdi_posledni_dekurs_dnes()`, `ma_sekci_prilohy()`, `pridat_do_sekce_prilohy()`, `merge_rtf_prepend()`
|
||||
- RTF šablona přesunuta do konstanty `RTF_TEMPLATE`
|
||||
- Odstraněn dead code: `prvnibookmark`, staré šablony, nepoužívané `convert_to1250`
|
||||
- `pridat_do_sekce_prilohy()` podporuje **více souborů najednou** (oproti test_import_single.py, kde byl jen 1)
|
||||
- `idpac` se bere z prvního záznamu skupiny (čistěji než z `row` po skončení loopu)
|
||||
|
||||
### Rozhodovací logika s03soubory.py – 3 případy
|
||||
1. Dnešní dekurs **má** sekci `Vložené přílohy` → soubory přidány **dovnitř** sekce (`pridat_do_sekce_prilohy`)
|
||||
2. Dnešní dekurs **nemá** sekci příloh → nová sekce vložena **na začátek** (`merge_rtf_prepend`)
|
||||
3. Žádný dnešní dekurs → **nový** záznam (INSERT)
|
||||
|
||||
### Stav testovacích skriptů
|
||||
- `test_import_3files.py` ✅ ověřeno – klikací odkazy fungují
|
||||
- `test_import_merge.py` ✅ otestováno – merge 3 souborů (jen 2 případy, bez detekce sekce)
|
||||
- `test_import_single.py` ✅ otestováno – všechny 3 případy, základ pro s03soubory.py
|
||||
|
||||
## Další postup (nápady)
|
||||
- Otestovat `s03soubory.py` na Windows se skutečnými soubory (všechny 3 případy)
|
||||
- Napsat `rtf_to_text()` pro extrakci čistého textu z dekurzů
|
||||
- Prozkoumat tabulky: LECH/LECD (léky?), POU (poukazy?), AMBULEKY (výkony?)
|
||||
- První report – domluvit s uživatelem co chce vidět
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,233 +1,323 @@
|
||||
import os,shutil,fdb,time
|
||||
import re,datetime,funkce,funkce_ext
|
||||
import os, shutil, fdb, time
|
||||
import re, datetime, funkce, funkce_ext
|
||||
|
||||
# Connect to the Firebird database
|
||||
conn = fdb.connect(
|
||||
dsn=r'localhost:c:\medicus 3\data\medicus.fdb', # Database path
|
||||
user='SYSDBA', # Username
|
||||
password="masterkey", # Password,
|
||||
dsn=r'localhost:c:\medicus 3\data\medicus.fdb',
|
||||
user='SYSDBA',
|
||||
password="masterkey",
|
||||
charset="win1250")
|
||||
|
||||
# cesta=r"u:\Dropbox\!!!Days\Downloads Z230\Dokumentace"
|
||||
cesta=r"u:\NextcloudOrdinace\Dokumentace_ke_zpracování"
|
||||
# cestazpracovana=r"u:\Dropbox\!!!Days\Downloads Z230\Dokumentacezpracovaná"
|
||||
cestazpracovana=r"u:\NextcloudOrdinace\Dokumentace_zpracovaná"
|
||||
cesta = r"u:\NextcloudOrdinace\Dokumentace_ke_zpracování"
|
||||
cestazpracovana = r"u:\NextcloudOrdinace\Dokumentace_zpracovaná"
|
||||
|
||||
# Konstanty pro detekci sekce Vložené přílohy (RTF kódování win1250)
|
||||
PRILOHY_HEADER = r"Vlo\'9een\'e9 p\'f8\'edlohy:"
|
||||
PRILOHY_CLOSING = r'\pard\s10\plain\cs15\f0\fs20 \par'
|
||||
|
||||
# ─── Helper funkce ────────────────────────────────────────────────────────────
|
||||
|
||||
def restore_files_for_import(retezec):
|
||||
drop=r"u:\Dropbox\!!!Days\Downloads Z230\Dokumentace"
|
||||
next=r"u:\NextcloudOrdinace\Dokumentace_ke_zpracování"
|
||||
|
||||
# Check if the directory exists
|
||||
drop = r"u:\Dropbox\!!!Days\Downloads Z230\Dokumentace"
|
||||
next = r"u:\NextcloudOrdinace\Dokumentace_ke_zpracování"
|
||||
if not os.path.exists(drop):
|
||||
print(f"The directory '{drop}' does not exist.")
|
||||
return
|
||||
|
||||
# Iterate over all files and subdirectories in the directory
|
||||
for item in os.listdir(drop):
|
||||
item_path = os.path.join(drop, item)
|
||||
|
||||
# If it's a file or a symbolic link, delete it
|
||||
if os.path.isfile(item_path) or os.path.islink(item_path):
|
||||
os.unlink(item_path)
|
||||
print(f"Deleted file: {item_path}")
|
||||
|
||||
# If it's a directory, delete it recursively
|
||||
elif os.path.isdir(item_path):
|
||||
shutil.rmtree(item_path)
|
||||
print(f"Deleted directory: {item_path}")
|
||||
|
||||
for item in os.listdir(next):
|
||||
item_path = os.path.join(next, item)
|
||||
# If it's a file finished with PDF, copy it
|
||||
if os.path.isfile(item_path) and item_path.endswith(".pdf") and retezec in item_path:
|
||||
shutil.copy(item_path,os.path.join(drop,item))
|
||||
shutil.copy(item_path, os.path.join(drop, item))
|
||||
print(f"Copied file: {item_path}")
|
||||
|
||||
|
||||
def kontrola_rc(rc,connection):
|
||||
def kontrola_rc(rc, connection):
|
||||
cur = connection.cursor()
|
||||
cur.execute("select count(*),idpac from kar where rodcis=? group by idpac",(rc,))
|
||||
cur.execute("select count(*),idpac from kar where rodcis=? group by idpac", (rc,))
|
||||
row = cur.fetchone()
|
||||
if row:
|
||||
return row[1]
|
||||
else:
|
||||
return False
|
||||
|
||||
def kontrola_struktury(souborname,connection):
|
||||
|
||||
def kontrola_struktury(souborname, connection):
|
||||
if souborname.endswith('.pdf'):
|
||||
#kontrola struktury
|
||||
pattern=re.compile(r'(^\d{9,10}) (\d{4}-\d{2}-\d{2}) (\w+, \w.+?) \[(.+?)\] \[(.*?)\]')
|
||||
match=pattern.search(souborname)
|
||||
# print(souborname)
|
||||
vpohode=True
|
||||
if match and len(match.groups())==5:
|
||||
datum=match.group(2)
|
||||
pattern = re.compile(r'(^\d{9,10}) (\d{4}-\d{2}-\d{2}) (\w+, \w.+?) \[(.+?)\] \[(.*?)\]')
|
||||
match = pattern.search(souborname)
|
||||
vpohode = True
|
||||
if match and len(match.groups()) == 5:
|
||||
datum = match.group(2)
|
||||
try:
|
||||
datum_object = datetime.datetime.strptime(datum,"%Y-%m-%d").date()
|
||||
# print(datum_object)
|
||||
datetime.datetime.strptime(datum, "%Y-%m-%d").date()
|
||||
except:
|
||||
vpohode=False
|
||||
vpohode = False
|
||||
return vpohode
|
||||
cur = connection.cursor()
|
||||
cur.execute("select count(*) from kar where rodcis=?", (match.group(1),))
|
||||
row = cur.fetchone()[0]
|
||||
if row!=1:
|
||||
if row != 1:
|
||||
vpohode = False
|
||||
return vpohode
|
||||
else:
|
||||
vpohode=False
|
||||
vpohode = False
|
||||
return vpohode
|
||||
else:
|
||||
vpohode=False
|
||||
vpohode = False
|
||||
return vpohode
|
||||
return vpohode
|
||||
|
||||
|
||||
def vrat_info_o_souboru(souborname, connection):
|
||||
pattern = re.compile(r'(^\d{9,10}) (\d{4}-\d{2}-\d{2}) (\w+, \w.+?) \[(.+?)\] \[(.*?)\]')
|
||||
match = pattern.search(souborname)
|
||||
rc = match.group(1)
|
||||
datum = datetime.datetime.strptime(match.group(2), "%Y-%m-%d").date()
|
||||
jmeno = match.group(3)
|
||||
rc = match.group(1)
|
||||
datum = datetime.datetime.strptime(match.group(2), "%Y-%m-%d").date()
|
||||
jmeno = match.group(3)
|
||||
prvnizavorka = match.group(4)
|
||||
druhazavorka = match.group(5)
|
||||
cur=connection.cursor()
|
||||
cur.execute("select idpac from kar where rodcis=?",(rc,))
|
||||
cur = connection.cursor()
|
||||
cur.execute("select idpac from kar where rodcis=?", (rc,))
|
||||
idpac = cur.fetchone()[0]
|
||||
datumsouboru = datetime.datetime.fromtimestamp(os.path.getctime(os.path.join(cesta,souborname)))
|
||||
return (rc,idpac,datum,jmeno,prvnizavorka,druhazavorka,souborname,datumsouboru)
|
||||
datumsouboru = datetime.datetime.fromtimestamp(os.path.getctime(os.path.join(cesta, souborname)))
|
||||
return (rc, idpac, datum, jmeno, prvnizavorka, druhazavorka, souborname, datumsouboru)
|
||||
|
||||
def prejmenuj_chybny_soubor(souborname,cesta):
|
||||
if souborname[0]!="♥":
|
||||
|
||||
def prejmenuj_chybny_soubor(souborname, cesta):
|
||||
if souborname[0] != "♥":
|
||||
soubornovy = "♥" + souborname
|
||||
os.rename(os.path.join(cesta,souborname),os.path.join(cesta,soubornovy))
|
||||
os.rename(os.path.join(cesta, souborname), os.path.join(cesta, soubornovy))
|
||||
|
||||
|
||||
def najdi_posledni_dekurs_dnes(conn, idpac, datum_vlozeni):
|
||||
"""Vrátí (id, rtf) posledního dekurzu pacienta pokud je z dnešního dne, jinak None."""
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
SELECT FIRST 1 ID, DATUM, DEKURS FROM DEKURS
|
||||
WHERE IDPAC = ?
|
||||
ORDER BY ID DESC
|
||||
""", (idpac,))
|
||||
row = cur.fetchone()
|
||||
if row is None:
|
||||
return None
|
||||
dekurs_id, dekurs_datum, dekurs_rtf = row
|
||||
print(f" Poslední dekurs: ID={dekurs_id}, datum={dekurs_datum}")
|
||||
if dekurs_datum == datum_vlozeni:
|
||||
print(f" → dnešní den ({datum_vlozeni}) ✓")
|
||||
return (dekurs_id, dekurs_rtf)
|
||||
else:
|
||||
print(f" → jiný den ({dekurs_datum} ≠ {datum_vlozeni}), vytvoříme nový")
|
||||
return None
|
||||
|
||||
# print(kontrola_struktury(ss))
|
||||
# info=vrat_info_o_souboru(ss)
|
||||
# print(kontrola_rc(info[0],conn))
|
||||
|
||||
# restore_files_for_import("")
|
||||
# restore_files_for_import("346204097")
|
||||
def ma_sekci_prilohy(rtf):
|
||||
return PRILOHY_HEADER in rtf
|
||||
|
||||
info=[]
|
||||
|
||||
def pridat_do_sekce_prilohy(rtf, bookmark_list, filenameforbookmark_list):
|
||||
"""Přidá více souborů do EXISTUJÍCÍ sekce 'Vložené přílohy'.
|
||||
|
||||
Postup:
|
||||
1. Spočítá počet Files: odkazů = N → nové indexy začínají od N
|
||||
2. Vloží nové \\pard řádky před uzavírací prázdný řádek sekce
|
||||
3. Přidá nové bookmarky na konec {\\info{\\bookmarks ...}}
|
||||
"""
|
||||
# 1. Počet existujících Files: odkazů
|
||||
bkm_match = re.search(r'\{\\info\{\\bookmarks ([^}]*)\}\}', rtf)
|
||||
if bkm_match:
|
||||
bkm_entries = [e for e in bkm_match.group(1).split(';') if e.strip()]
|
||||
n_files = sum(1 for e in bkm_entries if '"Files:' in e)
|
||||
else:
|
||||
n_files = 0
|
||||
print(f" Počet existujících Files odkazů: {n_files}, přidávám {len(bookmark_list)} nových")
|
||||
|
||||
# 2. Vložit nové \pard řádky před PRILOHY_CLOSING
|
||||
prilohy_pos = rtf.find(PRILOHY_HEADER)
|
||||
closing_pos = rtf.find(PRILOHY_CLOSING, prilohy_pos)
|
||||
if closing_pos == -1:
|
||||
raise RuntimeError("Nenalezen uzavírací řádek sekce Vložené přílohy!")
|
||||
|
||||
new_pards = ''
|
||||
for i, fname in enumerate(filenameforbookmark_list):
|
||||
idx = n_files + i
|
||||
new_pards += (r'\pard\s10{\*\bkmkstart ' + str(idx) + r'}'
|
||||
r'\plain\cs32\f0\ul\fs20\cf1 ' + fname
|
||||
+ r'{\*\bkmkend ' + str(idx) + r'}\par' + '\n')
|
||||
|
||||
rtf = rtf[:closing_pos] + new_pards + rtf[closing_pos:]
|
||||
|
||||
# 3. Přidat nové bookmarky na konec {\info{\bookmarks ...}}
|
||||
def append_bookmarks(m):
|
||||
entries = [e for e in m.group(1).split(';') if e.strip()]
|
||||
entries.extend(bookmark_list)
|
||||
return '{\\info{\\bookmarks ' + ';'.join(entries) + '}}'
|
||||
|
||||
rtf = re.sub(r'\{\\info\{\\bookmarks ([^}]*)\}\}', append_bookmarks, rtf)
|
||||
return rtf
|
||||
|
||||
|
||||
def merge_rtf_prepend(existing_rtf, new_bkm_list, new_body_pards, n_new):
|
||||
"""Vloží novou sekci příloh na ZAČÁTEK stávajícího dekurzu (sekce tam ještě není)."""
|
||||
rtf = existing_rtf
|
||||
rtf = re.sub(r'\\bkmkstart (\d+)',
|
||||
lambda m: '\\bkmkstart ' + str(int(m.group(1)) + n_new), rtf)
|
||||
rtf = re.sub(r'\\bkmkend (\d+)',
|
||||
lambda m: '\\bkmkend ' + str(int(m.group(1)) + n_new), rtf)
|
||||
|
||||
new_bkm_str = ';'.join(new_bkm_list)
|
||||
|
||||
def merge_bkm(m):
|
||||
existing = m.group(1).strip()
|
||||
combined = new_bkm_str + (';' + existing if existing else '')
|
||||
return '{\\info{\\bookmarks ' + combined + '}}'
|
||||
|
||||
if re.search(r'\{\\info\{\\bookmarks', rtf):
|
||||
rtf = re.sub(r'\{\\info\{\\bookmarks ([^}]*)\}\}', merge_bkm, rtf)
|
||||
else:
|
||||
rtf = re.sub(r'(\\deflang\d+)',
|
||||
r'\1{\\info{\\bookmarks ' + new_bkm_str + '}}', rtf, count=1)
|
||||
|
||||
match = re.search(r'\\uc1\\pard', rtf)
|
||||
if match:
|
||||
pos = match.start()
|
||||
rtf = rtf[:pos] + new_body_pards + '\n' + rtf[pos:]
|
||||
return rtf
|
||||
|
||||
|
||||
# Šablona RTF pro nový dekurs
|
||||
RTF_TEMPLATE = r"""{\rtf1\ansi\ansicpg1250\uc1\deff0\deflang1029{\info{\bookmarks BOOKMARKNAMES}}{\fonttbl{\f0\fnil\fcharset238 Arial;}{\f5\fnil\fcharset238 Symbol;}}
|
||||
{\colortbl ;\red0\green0\blue255;\red0\green128\blue0;\red0\green0\blue0;}
|
||||
{\stylesheet{\s10\fi0\li0\ql\ri0\sb0\sa0 Vlevo;}{\*\cs15\f0\fs20 Norm\'e1ln\'ed;}{\*\cs20\f0\i\fs20 Z\'e1hlav\'ed;}{\*\cs32\f0\ul\fs20\cf1 Odkaz;}}
|
||||
BOOKMARKSTEXT
|
||||
\pard\s10\plain\cs15\f0\fs20 \par
|
||||
}"""
|
||||
|
||||
# ─── Hlavní tělo skriptu ──────────────────────────────────────────────────────
|
||||
|
||||
info = []
|
||||
for soubor in os.listdir(cesta):
|
||||
if os.path.isfile(os.path.join(cesta,soubor)):
|
||||
if os.path.isfile(os.path.join(cesta, soubor)):
|
||||
print(soubor)
|
||||
if kontrola_struktury(soubor,conn):
|
||||
info.append(vrat_info_o_souboru(soubor,conn))
|
||||
# os.remove(os.path.join(cesta,soubor))
|
||||
if kontrola_struktury(soubor, conn):
|
||||
info.append(vrat_info_o_souboru(soubor, conn))
|
||||
else:
|
||||
prejmenuj_chybny_soubor(soubor,cesta)
|
||||
prejmenuj_chybny_soubor(soubor, cesta)
|
||||
|
||||
info = sorted(info, key=lambda x: (x[0], x[1]))
|
||||
print(info)
|
||||
|
||||
skupiny={}
|
||||
skupiny = {}
|
||||
for row in info:
|
||||
skupiny[row[0]]=[]
|
||||
skupiny[row[0]] = []
|
||||
for row in info:
|
||||
skupiny[row[0]].append(row)
|
||||
# print(skupiny)
|
||||
|
||||
# rtf = r"""{\rtf1\ansi\ansicpg1250\uc1\deff0\deflang1029{\info{\bookmarks BOOKMARKNAMES }}{\fonttbl{\f0\fnil\fcharset238 Arial;}{\f5\fnil\fcharset238 Symbol;}}
|
||||
# {\colortbl ;\red0\green0\blue255;\red0\green128\blue0;\red0\green0\blue0;}
|
||||
# {\stylesheet{\s10\fi0\li0\ql\ri0\sb0\sa0 Vlevo;}{\*\cs15\f0\fs20 Norm\'e1ln\'ed;}{\*\cs20\f0\i\fs20 Z\'e1hlav\'ed;}{\*\cs22\f0\ul\fs20\cf1 Odkaz;}}
|
||||
# \uc1\pard\s10\plain\cs20\f0\i\fs20 P\'f8\'edlohy:\par
|
||||
# \pard\s10{\*\bkmkstart 0}\plain\cs22\f0\ul\fs20\cf1 BOOKMARKNAMESTEXT{\*\bkmkend 0}\par
|
||||
# \pard\s10\plain\cs15\f0\fs20 \par
|
||||
# }"""
|
||||
|
||||
rtf = r"""{\rtf1\ansi\ansicpg1250\uc1\deff0\deflang1029{\info{\bookmarks BOOKMARKNAMES }}{\fonttbl{\f0\fnil\fcharset238 Arial;}{\f5\fnil\fcharset238 Symbol;}}
|
||||
{\colortbl ;\red0\green0\blue255;\red0\green128\blue0;\red0\green0\blue0;}
|
||||
{\stylesheet{\s10\fi0\li0\ql\ri0\sb0\sa0 Vlevo;}{\*\cs15\f0\fs20 Norm\'e1ln\'ed;}{\*\cs20\f0\i\fs20 Z\'e1hlav\'ed;}{\*\cs22\f0\ul\fs20\cf1 Odkaz;}}
|
||||
\uc1\pard\s10\plain\cs20\f0\i\fs20 P\'f8\'edlohy:\par
|
||||
BOOKMARKSTEXT
|
||||
\pard\s10\plain\cs15\f0\fs20 \par
|
||||
}"""
|
||||
|
||||
for key in skupiny.keys():
|
||||
rtf = r"""{\rtf1\ansi\ansicpg1250\uc1\deff0\deflang1029{\info{\bookmarks BOOKMARKNAMES}}{\fonttbl{\f0\fnil\fcharset238 Arial;}{\f5\fnil\fcharset238 Symbol;}}
|
||||
{\colortbl ;\red0\green0\blue255;\red0\green128\blue0;\red0\green0\blue0;}
|
||||
{\stylesheet{\s10\fi0\li0\ql\ri0\sb0\sa0 Vlevo;}{\*\cs15\f0\fs20 Norm\'e1ln\'ed;}{\*\cs20\f0\i\fs20 Z\'e1hlav\'ed;}{\*\cs32\f0\ul\fs20\cf1 Odkaz;}}
|
||||
\uc1\pard\s10\plain\cs20\f0\i\fs20 Vlo\'9een\'e9 p\'f8\'edlohy:\par
|
||||
BOOKMARKSTEXT
|
||||
\pard\s10\plain\cs15\f0\fs20 \par
|
||||
}"""
|
||||
print(f"\n{'='*60}")
|
||||
print(f"RC: {key}, souborů: {len(skupiny[key])}")
|
||||
|
||||
cislo = 9
|
||||
poradi = 0
|
||||
bookmark_list = []
|
||||
filenameforbookmark_list = []
|
||||
bookmarks_body = ''
|
||||
idpac = skupiny[key][0][1]
|
||||
|
||||
# if key=="8257300425": #346204097
|
||||
if True:
|
||||
prvnibookmark=True
|
||||
print(key,len(skupiny[key]))
|
||||
cislo=9
|
||||
poradi=0
|
||||
bookmark=""
|
||||
bookmarks=""
|
||||
for row in skupiny[key]:
|
||||
# print(row)
|
||||
pacid=row[1]
|
||||
filename=row[6]
|
||||
fileid= funkce_ext.zapis_file_ext(vstupconnection=conn, idpac=row[1],
|
||||
cesta=cesta, souborname=row[6], prvnizavorka=row[4],
|
||||
soubordate=row[2], souborfiledate=row[7], poznamka=row[5])
|
||||
# ── Krok 1: vložit každý soubor do ext DB + přesunout do zpracovaných ────
|
||||
for row in skupiny[key]:
|
||||
fileid = funkce_ext.zapis_file_ext(
|
||||
vstupconnection=conn, idpac=row[1],
|
||||
cesta=cesta, souborname=row[6], prvnizavorka=row[4],
|
||||
soubordate=row[2], souborfiledate=row[7], poznamka=row[5])
|
||||
print(f" → FILES.ID = {fileid} ({row[6]})")
|
||||
|
||||
for attempt in range(3):
|
||||
try:
|
||||
# Replace this with the command that might raise an error
|
||||
if not os.path.exists(os.path.join(cestazpracovana,row[6])):
|
||||
shutil.move(os.path.join(cesta,row[6]), os.path.join(cestazpracovana,row[6]))
|
||||
print("Command succeeded!")
|
||||
break # Exit the loop if the command succeeds
|
||||
else:
|
||||
now = datetime.datetime.now()
|
||||
datetime_string = now.strftime("%Y-%m-%d %H-%M-%S")
|
||||
print(os.path.join(cestazpracovana,row[6][:-4]+" "+datetime_string+".pdf"))
|
||||
shutil.move(os.path.join(cesta,row[6]),os.path.join(cestazpracovana,row[6][:-4]+" "+datetime_string+".pdf"))
|
||||
print("Command succeeded!")
|
||||
break # Exit the loop if the command succeeds
|
||||
except Exception as e:
|
||||
print(f"Attempt {attempt + 1} failed: {e}")
|
||||
if attempt < 3 - 1:
|
||||
print(f"Retrying in {5} seconds...")
|
||||
time.sleep(5)
|
||||
else:
|
||||
print("Max retries reached. Command failed.")
|
||||
# Přesun souboru do zpracovaných
|
||||
for attempt in range(3):
|
||||
try:
|
||||
dest = os.path.join(cestazpracovana, row[6])
|
||||
if not os.path.exists(dest):
|
||||
shutil.move(os.path.join(cesta, row[6]), dest)
|
||||
else:
|
||||
ts = datetime.datetime.now().strftime("%Y-%m-%d %H-%M-%S")
|
||||
shutil.move(os.path.join(cesta, row[6]),
|
||||
os.path.join(cestazpracovana, row[6][:-4] + " " + ts + ".pdf"))
|
||||
print(" Přesun OK!")
|
||||
break
|
||||
except Exception as e:
|
||||
print(f" Attempt {attempt + 1} failed: {e}")
|
||||
if attempt < 2:
|
||||
print(" Retrying in 5 seconds...")
|
||||
time.sleep(5)
|
||||
else:
|
||||
print(" Max retries reached. Command failed.")
|
||||
|
||||
filenameforbookmark = row[2].strftime('%Y-%m-%d') + ' ' + row[4] + ': ' + row[5]
|
||||
bookmark_list.append('"' + filenameforbookmark + '","Files:' + str(fileid) + '",' + str(cislo))
|
||||
filenameforbookmark_list.append(filenameforbookmark)
|
||||
cislo += 7
|
||||
|
||||
filename= funkce.convert_to1250(filename)
|
||||
print("Encodedfilename", filename)
|
||||
filenameforbookmark=row[2].strftime('%Y-%m-%d')+" "+row[4]+": "+row[5]
|
||||
bookmark=bookmark+'"'+filenameforbookmark+'","Files:'+str(fileid)+'",'+str(cislo)+";"
|
||||
cislo+=7
|
||||
# print(bookmark)
|
||||
bookmarks += r'\pard\s10{\*\bkmkstart ' + str(poradi) + r'}\plain\cs32\f0\ul\fs20\cf1 ' + filenameforbookmark + r'{\*\bkmkend ' + str(poradi) + r'}\par'
|
||||
poradi += 1
|
||||
bookmark=bookmark[:-1]
|
||||
# bookmarks=bookmarks[:-2]
|
||||
print(bookmark)
|
||||
print(bookmarks)
|
||||
bookmarks_body += (r'\pard\s10{\*\bkmkstart ' + str(poradi) + r'}'
|
||||
r'\plain\cs32\f0\ul\fs20\cf1 ' + filenameforbookmark
|
||||
+ r'{\*\bkmkend ' + str(poradi) + r'}\par')
|
||||
poradi += 1
|
||||
|
||||
rtf = rtf.replace("BOOKMARKNAMES", bookmark)
|
||||
rtf=rtf.replace("BOOKMARKSTEXT",bookmarks)
|
||||
print(rtf)
|
||||
dekursid = funkce.get_dekurs_id(conn)
|
||||
datumzapisu = datetime.datetime.now().date()
|
||||
caszapisu = datetime.datetime.now().time()
|
||||
cur=conn.cursor()
|
||||
cur.execute("insert into dekurs (id,iduzi,idprac,idodd,idpac,datum,cas,dekurs)"
|
||||
" values(?,?,?,?,?,?,?,?)",
|
||||
(dekursid,6,2,2, row[1],datumzapisu,caszapisu, rtf))
|
||||
# ── Krok 2: sestavit tělo nové sekce příloh ───────────────────────────────
|
||||
new_body = (r'\uc1\pard\s10\plain\cs20\f0\i\fs20 Vlo\'9een\'e9 p\'f8\'edlohy:\par' + '\n'
|
||||
+ bookmarks_body + '\n'
|
||||
+ r'\pard\s10\plain\cs15\f0\fs20 \par')
|
||||
|
||||
# ── Krok 3: rozhodovací logika (3 případy) ────────────────────────────────
|
||||
datumzapisu = datetime.datetime.now().date()
|
||||
caszapisu = datetime.datetime.now().time()
|
||||
cur = conn.cursor()
|
||||
|
||||
print(f"\n>>> Hledám poslední dekurs pro IDPAC={idpac}...")
|
||||
existujici = najdi_posledni_dekurs_dnes(conn, idpac, datumzapisu)
|
||||
|
||||
if existujici:
|
||||
dekurs_id, existing_rtf = existujici
|
||||
|
||||
if ma_sekci_prilohy(existing_rtf):
|
||||
# Případ 1: dnešní dekurs má sekci příloh → přidáme soubory dovnitř
|
||||
print(f"\n>>> Sekce 'Vložené přílohy' nalezena v DEKURS ID={dekurs_id}")
|
||||
print(">>> Přidávám soubory DO existující sekce...")
|
||||
merged_rtf = pridat_do_sekce_prilohy(existing_rtf, bookmark_list, filenameforbookmark_list)
|
||||
else:
|
||||
# Případ 2: dnešní dekurs existuje, ale sekci příloh nemá → prepend
|
||||
print(f"\n>>> DEKURS ID={dekurs_id} nemá sekci příloh → vkládám sekci na začátek...")
|
||||
merged_rtf = merge_rtf_prepend(existing_rtf, bookmark_list, new_body, len(skupiny[key]))
|
||||
|
||||
print("\n=== Výsledný RTF ===")
|
||||
print(merged_rtf)
|
||||
cur.execute("UPDATE DEKURS SET DEKURS = ? WHERE ID = ?", (merged_rtf, dekurs_id))
|
||||
conn.commit()
|
||||
# rtf = rtf.replace("FILEID", str(idfile))
|
||||
#Zde zapisujeme soubor
|
||||
# fileid=funkce.zapis_file(conn,row[1],cesta,row[6],row[4],row[2],row[7],row[5])
|
||||
# zapis_dekurs(vstupconnection, idpac, idodd, iduzi, idprac, idfile, filename, text, datumzpravy,datumsouboru)
|
||||
# return (rc, idpac, datum, jmeno, prvnizavorka, druhazavorka, souborname, datumsouboru)
|
||||
print(f"\n>>> UPDATE DEKURS ID={dekurs_id} – hotovo!")
|
||||
|
||||
# Zde zapisujeme dekurs
|
||||
# text=row[2].strftime("%Y-%m-%d")+" "+row[4].strip()+": "+row[5].strip()
|
||||
# funkce.zapis_dekurs(conn, row[1], 2, 6, 2, fileid, text, text, row[7], row[2])
|
||||
# os.remove(os.path.join(cesta, soubor))
|
||||
else:
|
||||
# Případ 3: žádný dnešní dekurs → vytvoříme nový
|
||||
print(f"\n>>> Žádný dekurs pro dnešek → vytvářím nový...")
|
||||
bookmark_str = ';'.join(bookmark_list)
|
||||
rtf = RTF_TEMPLATE.replace('BOOKMARKNAMES', bookmark_str)
|
||||
rtf = rtf.replace('BOOKMARKSTEXT', new_body)
|
||||
|
||||
print("\n=== Výsledný RTF ===")
|
||||
print(rtf)
|
||||
|
||||
dekursid = funkce.get_dekurs_id(conn)
|
||||
cur.execute(
|
||||
"INSERT INTO DEKURS (id, iduzi, idprac, idodd, idpac, datum, cas, dekurs)"
|
||||
" VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
(dekursid, 6, 2, 2, idpac, datumzapisu, caszapisu, rtf)
|
||||
)
|
||||
conn.commit()
|
||||
print(f"\n>>> Nový DEKURS ID={dekursid}")
|
||||
|
||||
print("\n=== HOTOVO ===")
|
||||
conn.close()
|
||||
|
||||
81
MedicusWithClaudeSelects/SELECTS.md
Normal file
81
MedicusWithClaudeSelects/SELECTS.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# MedicusWithClaudeSelects – SQL dotazy
|
||||
|
||||
## Registrovaní pacienti
|
||||
|
||||
Přesný select který Medicus používá pro záložku **Registrovaní** (zachycen přes FBScanner, dotaz č. 143).
|
||||
|
||||
### Počet registrovaných pacientů
|
||||
|
||||
```sql
|
||||
SELECT COUNT(*) FROM KAR
|
||||
WHERE (vyrazen = 'N')
|
||||
AND EXISTS (
|
||||
SELECT id FROM registr r
|
||||
JOIN icp i ON r.idicp = i.idicp
|
||||
WHERE r.idpac = kar.idpac
|
||||
AND (r.datum <= '2026-03-20')
|
||||
AND (r.datum_zruseni IS NULL OR r.datum_zruseni >= '2026-03-20')
|
||||
AND (r.priznak IN ('V','D','A'))
|
||||
AND (i.icp = '09305001')
|
||||
AND (i.odb = '001')
|
||||
)
|
||||
```
|
||||
|
||||
Vrátí: **1618 pacientů** (ověřit na Windows).
|
||||
|
||||
### Podmínky registrace – vysvětlení
|
||||
|
||||
- `vyrazen = 'N'` – pacient není vyřazen z kartotéky
|
||||
- `r.datum <= dnes` – registrace již začala
|
||||
- `r.datum_zruseni IS NULL OR r.datum_zruseni >= dnes` – registrace dosud platí
|
||||
- `r.priznak IN ('V','D','A')` – aktivní příznak (ne 'Z' = zrušen, ne 'N')
|
||||
- `i.icp = '09305001'` – IČP naší ordinace
|
||||
- `i.odb = '001'` – odbornost praktický lékař
|
||||
|
||||
### Skript pro Python
|
||||
|
||||
Viz `count_registrovani.py` v této složce – spustit na Windows.
|
||||
|
||||
### Plný select Medicusu (seznam pacientů s metadaty)
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
KAR.DATNAR,
|
||||
KAR.IDPAC,
|
||||
KAR.INFORMACE,
|
||||
KAR.INFORMACE_COL,
|
||||
KAR.JMENO,
|
||||
KAR.POHLAVI,
|
||||
GPP.POJ,
|
||||
KAR.POZNAMKA,
|
||||
KAR.PRIJMENI,
|
||||
KAR.PRIJMENI_UP,
|
||||
(SELECT DATUM_REGISTRACE FROM SP_GETREGDAT(kar.IDPAC)) AS REGDATUM,
|
||||
KAR.REGISTROVAL,
|
||||
(SELECT PRIZNAK FROM SP_GETREGDAT(kar.IDPAC)) AS REGPRIZNAK,
|
||||
KAR.RODCIS,
|
||||
KAR.ROZENA,
|
||||
KAR.TITUL,
|
||||
KAR.TITULZA,
|
||||
KAR.TRVOBEC,
|
||||
KAR.TRVPSC,
|
||||
KAR.TRVULICE,
|
||||
KAR.VYRAZEN
|
||||
FROM KAR
|
||||
LEFT JOIN GETPACPOJ(KAR.IDPAC, '2026-03-20') GPP ON GPP.IDPAC = KAR.IDPAC
|
||||
WHERE (vyrazen = 'N')
|
||||
AND EXISTS (
|
||||
SELECT id FROM registr r
|
||||
JOIN icp i ON r.idicp = i.idicp
|
||||
WHERE r.idpac = kar.idpac
|
||||
AND (r.datum <= '2026-03-20')
|
||||
AND (r.datum_zruseni IS NULL OR r.datum_zruseni >= '2026-03-20')
|
||||
AND (r.priznak IN ('V','D','A'))
|
||||
AND (i.icp = '09305001')
|
||||
AND (i.odb = '001')
|
||||
)
|
||||
ORDER BY KAR.PRIJMENI_UP ASC, KAR.RODCIS ASC
|
||||
```
|
||||
|
||||
Poznámka: `GETPACPOJ` a `SP_GETREGDAT` jsou uložené procedury Medicusu –
|
||||
fungují v kontextu Firebird připojení přes SYSDBA/masterkey.
|
||||
27
MedicusWithClaudeSelects/count_registrovani.py
Normal file
27
MedicusWithClaudeSelects/count_registrovani.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import fdb, datetime
|
||||
|
||||
conn = fdb.connect(
|
||||
dsn=r'localhost:c:\medicus 3\data\medicus.fdb',
|
||||
user='SYSDBA', password='masterkey', charset='win1250')
|
||||
|
||||
cur = conn.cursor()
|
||||
dnes = datetime.date.today().isoformat()
|
||||
|
||||
cur.execute("""
|
||||
SELECT COUNT(*) FROM KAR
|
||||
WHERE (vyrazen = 'N')
|
||||
AND EXISTS (
|
||||
SELECT id FROM registr r
|
||||
JOIN icp i ON r.idicp = i.idicp
|
||||
WHERE r.idpac = kar.idpac
|
||||
AND (r.datum <= ?)
|
||||
AND (r.datum_zruseni IS NULL OR r.datum_zruseni >= ?)
|
||||
AND (r.priznak IN ('V','D','A'))
|
||||
AND (i.icp = '09305001')
|
||||
AND (i.odb = '001')
|
||||
)
|
||||
""", (dnes, dnes))
|
||||
|
||||
pocet = cur.fetchone()[0]
|
||||
print(f'Registrovaných pacientů: {pocet}')
|
||||
conn.close()
|
||||
78
MedicusWithClaudeSelects/db_bridge_vm.py
Normal file
78
MedicusWithClaudeSelects/db_bridge_vm.py
Normal file
@@ -0,0 +1,78 @@
|
||||
"""db_bridge_vm.py – VM strana souborového mostu k Medicusu.
|
||||
|
||||
Použití z Linuxu:
|
||||
from db_bridge_vm import query
|
||||
rows, columns = query("SELECT COUNT(*) FROM KAR")
|
||||
print(columns, rows)
|
||||
"""
|
||||
import json, time, os, uuid
|
||||
|
||||
BRIDGE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
REQUEST = os.path.join(BRIDGE_DIR, 'query_request.json')
|
||||
RESPONSE = os.path.join(BRIDGE_DIR, 'query_response.json')
|
||||
|
||||
TIMEOUT_SEC = 30
|
||||
POLL_SEC = 0.3
|
||||
|
||||
|
||||
def query(sql, params=None, timeout=TIMEOUT_SEC):
|
||||
"""Pošle SQL dotaz přes souborový most a vrátí (rows, columns).
|
||||
|
||||
Raises:
|
||||
TimeoutError – watchdog neodpověděl do timeout sekund
|
||||
RuntimeError – Firebird vrátil chybu
|
||||
"""
|
||||
# Smaž případnou starou response
|
||||
if os.path.exists(RESPONSE):
|
||||
os.remove(RESPONSE)
|
||||
|
||||
req_id = uuid.uuid4().hex
|
||||
req = {'id': req_id, 'sql': sql, 'params': params or []}
|
||||
|
||||
with open(REQUEST, 'w', encoding='utf-8') as f:
|
||||
json.dump(req, f, ensure_ascii=False)
|
||||
|
||||
# Čekej na odpověď
|
||||
waited = 0.0
|
||||
while waited < timeout:
|
||||
time.sleep(POLL_SEC)
|
||||
waited += POLL_SEC
|
||||
if os.path.exists(RESPONSE):
|
||||
with open(RESPONSE, 'r', encoding='utf-8') as f:
|
||||
resp = json.load(f)
|
||||
os.remove(RESPONSE)
|
||||
if resp.get('status') == 'error':
|
||||
raise RuntimeError(f"DB chyba: {resp.get('error')}")
|
||||
return resp.get('rows', []), resp.get('columns', [])
|
||||
|
||||
# Timeout – smaž request aby watchdog nezpracoval zastaralý dotaz
|
||||
if os.path.exists(REQUEST):
|
||||
os.remove(REQUEST)
|
||||
raise TimeoutError(f'Watchdog neodpověděl do {timeout}s – běží db_bridge_windows.py?')
|
||||
|
||||
|
||||
def query_print(sql, params=None):
|
||||
"""Spustí dotaz a vypíše výsledek přehledně."""
|
||||
rows, cols = query(sql, params)
|
||||
if not cols:
|
||||
print('(žádné sloupce)')
|
||||
return rows, cols
|
||||
col_w = [max(len(str(c)), max((len(str(r[i])) for r in rows), default=0))
|
||||
for i, c in enumerate(cols)]
|
||||
sep = '+' + '+'.join('-' * (w + 2) for w in col_w) + '+'
|
||||
fmt = '|' + '|'.join(f' {{:<{w}}} ' for w in col_w) + '|'
|
||||
print(sep)
|
||||
print(fmt.format(*cols))
|
||||
print(sep)
|
||||
for row in rows:
|
||||
print(fmt.format(*[str(v) if v is not None else 'NULL' for v in row]))
|
||||
print(sep)
|
||||
print(f'{len(rows)} řádků')
|
||||
return rows, cols
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Rychlý test
|
||||
print('Testuji spojení...')
|
||||
rows, cols = query('SELECT COUNT(*) AS POCET FROM KAR')
|
||||
print(f'OK – pacientů v KAR: {rows[0][0]}')
|
||||
90
MedicusWithClaudeSelects/db_bridge_windows.py
Normal file
90
MedicusWithClaudeSelects/db_bridge_windows.py
Normal file
@@ -0,0 +1,90 @@
|
||||
"""db_bridge_windows.py – Windows watchdog pro dotazy z Linux VM.
|
||||
|
||||
Spusť jednou na Windows:
|
||||
python db_bridge_windows.py
|
||||
|
||||
Skript sleduje soubor query_request.json ve stejné složce.
|
||||
Jakmile ho najde, spustí SQL dotaz proti Medicusu a zapíše výsledek
|
||||
do query_response.json. Pak čeká na další dotaz.
|
||||
|
||||
Ukonči: Ctrl+C
|
||||
"""
|
||||
import fdb, json, time, os, traceback, datetime
|
||||
|
||||
# ── Konfigurace ───────────────────────────────────────────────────────────────
|
||||
DSN = r'localhost:c:\medicus 3\data\medicus.fdb'
|
||||
USER = 'SYSDBA'
|
||||
PASSWORD = 'masterkey'
|
||||
CHARSET = 'win1250'
|
||||
|
||||
BRIDGE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
REQUEST = os.path.join(BRIDGE_DIR, 'query_request.json')
|
||||
RESPONSE = os.path.join(BRIDGE_DIR, 'query_response.json')
|
||||
POLL_SEC = 0.5
|
||||
|
||||
# ── Pomocné funkce ────────────────────────────────────────────────────────────
|
||||
|
||||
def serialize(val):
|
||||
"""Převede Python hodnoty na JSON-serializovatelné typy."""
|
||||
if isinstance(val, (datetime.date, datetime.datetime)):
|
||||
return val.isoformat()
|
||||
if isinstance(val, datetime.time):
|
||||
return val.isoformat()
|
||||
if isinstance(val, bytes):
|
||||
return f'<bytes len={len(val)}>'
|
||||
return val
|
||||
|
||||
|
||||
def run_query(sql, params=None):
|
||||
conn = fdb.connect(dsn=DSN, user=USER, password=PASSWORD, charset=CHARSET)
|
||||
try:
|
||||
cur = conn.cursor()
|
||||
cur.execute(sql, params or [])
|
||||
columns = [d[0] for d in cur.description] if cur.description else []
|
||||
rows = [[serialize(v) for v in row] for row in cur.fetchall()]
|
||||
return {'status': 'ok', 'columns': columns, 'rows': rows, 'error': None}
|
||||
except Exception as e:
|
||||
return {'status': 'error', 'columns': [], 'rows': [], 'error': str(e)}
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
# ── Hlavní smyčka ─────────────────────────────────────────────────────────────
|
||||
print(f'DB Bridge spuštěn. Sleduju: {REQUEST}')
|
||||
print('Ukončení: Ctrl+C\n')
|
||||
|
||||
while True:
|
||||
try:
|
||||
if os.path.exists(REQUEST):
|
||||
print(f'[{datetime.datetime.now().strftime("%H:%M:%S")}] Přijat dotaz...')
|
||||
|
||||
with open(REQUEST, 'r', encoding='utf-8') as f:
|
||||
req = json.load(f)
|
||||
|
||||
os.remove(REQUEST)
|
||||
|
||||
sql = req.get('sql', '')
|
||||
params = req.get('params', [])
|
||||
req_id = req.get('id', '')
|
||||
|
||||
result = run_query(sql, params)
|
||||
result['id'] = req_id
|
||||
result['sql'] = sql
|
||||
|
||||
with open(RESPONSE, 'w', encoding='utf-8') as f:
|
||||
json.dump(result, f, ensure_ascii=False, indent=2)
|
||||
|
||||
if result['status'] == 'ok':
|
||||
print(f' → OK, {len(result["rows"])} řádků')
|
||||
else:
|
||||
print(f' → CHYBA: {result["error"]}')
|
||||
|
||||
time.sleep(POLL_SEC)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print('\nDB Bridge ukončen.')
|
||||
break
|
||||
except Exception as e:
|
||||
print(f'Neočekávaná chyba: {e}')
|
||||
traceback.print_exc()
|
||||
time.sleep(2)
|
||||
30
MedicusWithClaudeSelects/get_kar_sortby_idlist.py
Normal file
30
MedicusWithClaudeSelects/get_kar_sortby_idlist.py
Normal file
@@ -0,0 +1,30 @@
|
||||
"""get_kar_sortby_idlist.py – přečte definici stored procedure KAR_SORTBY_IDLIST z Firebirdu.
|
||||
Spustit na Windows.
|
||||
"""
|
||||
import fdb
|
||||
|
||||
conn = fdb.connect(
|
||||
dsn=r'localhost:c:\medicus 3\data\medicus.fdb',
|
||||
user='SYSDBA', password='masterkey', charset='win1250')
|
||||
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
SELECT RDB$PROCEDURE_SOURCE FROM RDB$PROCEDURES
|
||||
WHERE RDB$PROCEDURE_NAME = 'KAR_SORTBY_IDLIST'
|
||||
""")
|
||||
row = cur.fetchone()
|
||||
if row and row[0]:
|
||||
print(row[0])
|
||||
else:
|
||||
# Možná je to funkce (FUNCTION), ne procedure
|
||||
cur.execute("""
|
||||
SELECT RDB$FUNCTION_SOURCE FROM RDB$FUNCTIONS
|
||||
WHERE RDB$FUNCTION_NAME = 'KAR_SORTBY_IDLIST'
|
||||
""")
|
||||
row = cur.fetchone()
|
||||
if row and row[0]:
|
||||
print(row[0])
|
||||
else:
|
||||
print("Nenalezeno ani jako PROCEDURE ani jako FUNCTION.")
|
||||
|
||||
conn.close()
|
||||
2668
MedicusWithClaudeSelects/precti_log.txt
Normal file
2668
MedicusWithClaudeSelects/precti_log.txt
Normal file
File diff suppressed because one or more lines are too long
74
MedicusWithClaudeSelects/query_response.json
Normal file
74
MedicusWithClaudeSelects/query_response.json
Normal file
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"status": "ok",
|
||||
"columns": [
|
||||
"ID",
|
||||
"DATUM",
|
||||
"CAS",
|
||||
"UZIVATEL",
|
||||
"IDPAC",
|
||||
"TABULKA",
|
||||
"IDREC",
|
||||
"AKCE",
|
||||
"DETAIL"
|
||||
],
|
||||
"rows": [
|
||||
[
|
||||
2882053,
|
||||
"2026-03-20",
|
||||
"17:43:50.523000",
|
||||
"VBU ",
|
||||
3234,
|
||||
10000,
|
||||
3234,
|
||||
"V",
|
||||
null
|
||||
],
|
||||
[
|
||||
2882052,
|
||||
"2026-03-20",
|
||||
"17:43:46.435000",
|
||||
"VBU ",
|
||||
3234,
|
||||
10000,
|
||||
3234,
|
||||
"V",
|
||||
null
|
||||
],
|
||||
[
|
||||
2882051,
|
||||
"2026-03-20",
|
||||
"17:24:19.777000",
|
||||
"VBU ",
|
||||
4757,
|
||||
10000,
|
||||
4757,
|
||||
"V",
|
||||
null
|
||||
],
|
||||
[
|
||||
2882050,
|
||||
"2026-03-20",
|
||||
"17:24:15.866000",
|
||||
"VBU ",
|
||||
3234,
|
||||
10000,
|
||||
3234,
|
||||
"V",
|
||||
null
|
||||
],
|
||||
[
|
||||
2882049,
|
||||
"2026-03-20",
|
||||
"07:11:41.434000",
|
||||
"VBU ",
|
||||
4757,
|
||||
10000,
|
||||
4757,
|
||||
"V",
|
||||
null
|
||||
]
|
||||
],
|
||||
"error": null,
|
||||
"id": "11859d529a784bedb653030ba60131de",
|
||||
"sql": "SELECT FIRST 5 * FROM LOG ORDER BY ID DESC"
|
||||
}
|
||||
Reference in New Issue
Block a user