curl -s "https://api.preskryptor.pl/cmd" --data-urlencode 'cmd={"rev":"2.0","customCmd":{"test":""}}'
To odwołanie powinno zwrócić bieżący czas serwera w formacie =>
{"test":"2024-04-12 09:20:01.11293+02"}
Jeśli to odwołanie nie działa – zbadaj jaka jest tego przyczyna. Jeśli to odwołanie nie działa próbowanie uruchomienia pozostałych odwołań przypuszczalnie nie ma sensu.Dla usprawnienia implementacji, dołączamy do pobrania przykłady implementacji połączenia z API - wraz z bibliotekami w językach Java, Python i PHP:
Dostarczamy także proste narzędzie do sprawdzania, czy przygotowane zapytanie API jest poprawne. Narzędzie napisane jest w języku programowania Java, dostępny jest kod źródłowy jak i skompilowana wersja z przykładami użycia:
USERID=2
USERPASSWD=YTRGHJKHGVFRTYUIKJHGFTYUIiuytgfhjkiuyhgtfgyuikjhy0987654567890
Proces autoryzacji jest dwuetapowy.curl -s "https://api.preskryptor.pl/cmd" --data-urlencode 'cmd={"rev":"2.0","customCmd":{"getToken":'2'}}'
W wyniku tego odwołania API zwraca token do realizacji kolejnych żądań. Zwrócony token jest ważny przez pewien czas od ostatniego wykorzystania. Następnie wygasa. Nie specyfikujemy ile wynosi „pewien czas”, ale możemy zapewnić, że to jest co najmniej kilka minut. Nie ma limitów na liczbę żądań tokenów. W przypadku jak istnieje ważny token dla danego użytkownika API w kolejnym wywołaniu może zwrócić już istniejący token.
{"token":{"token":{"id":27219,"token":"3946ec4424d7e5cd82267a9d62959a58","created":"2024-04-12 09:24:09.250281"}}}
W zwróconym wyniku znajdują się pola „id” oraz „token”. Na podstawie zwróconej zawartości pola „token” należy wygenerować łańcuch autoryzacyjny.
MD5 ( $token + '#hash#' + $USERPASSWD )
Dla danych widocznych powyżej będzie to =>
MD5 ( '3946ec4424d7e5cd82267a9d62959a58#hash#YTRGHJKHGVFRTYUIKJHGFTYUIiuytgfhjkiuyhgtfgyuikjhy0987654567890' ) = 2961c9d416f0d10c561e504766eee242
Następnie, mając już ciąg MD5 należy wygenerować ciasteczko autoryzacyjne o nazwie „auth” w postaci => 'token#$tokenid#$MD5', czyli dla danych powyżej jest to =>
token#27219#2961c9d416f0d10c561e504766eee242
Wszystkie kolejne odwołania do API powinny zawierać w odwołaniu ciasteczko w postaci =>
"auth=token#27219#2961c9d416f0d10c561e504766eee242"
curl -s https://api.preskryptor.pl/cmd --cookie 'auth=token#27219#2961c9d416f0d10c561e504766eee242' \
--data-urlencode 'cmd={"rev":"2.0","customCmd":{"api":{"source":{"selected":{"all":""}},"format":{"json":""}}}}'
Uwaga – w kwestii szczegółów interpretacji wyniku należy przeanalizować szczegółową dokumentację obiektów zwracanych przez API, która znajduje się TUTAJ.curl -s https://api.preskryptor.pl/cmd --cookie 'auth=token#27219#2961c9d416f0d10c561e504766eee242' \
--data-urlencode 'cmd={"rev":"2.0","customCmd":{"api":{"source":{"updated":{"date":"2024-02-01","source":{"all":""}}},"format":{"json":""}}}}'
Pobranie zmian w bazie leków od daty 2024-02-01, ale tylko obiekty typu priceKinds =>curl -s https://api.preskryptor.pl/cmd --cookie 'auth=token#27219#2961c9d416f0d10c561e504766eee242' \
--data-urlencode 'cmd={"rev":"2.0","customCmd":{"api":{"source":{"updated":{"date":"2024-02-01","source":{"priceKinds":""}}},"format":{"json":""}}}}'
refId : int– referencja do identyfikatora lekarza, który już powinien istnieć w systemie (po stronie API), czyli dane tego lekarza powinny zostać przesłane we wcześniejszych odwołaniach do API lub w bieżących odwołaniu, we wcześniejszych rekordach. W przypadku braku wskazanego id wystąpi błąd.
LogDoctor = record {
id : int – identyfikator (numeryczny, długi int) lekarza – to jest identyfikator z wnętrza systemu, to NIE jest i NIE MOŻE BYĆ PWZ lekarza
facility – powiązanie do placówki
}
W drugim przypadku, jeśli rekord lekarza o podanym id już istnieje w systemie, jego dane zostaną zaktualizowane (nie zostanie utworzony nowe, zduplikowany rekord, tylko zostaną nadpisane jego dane).refId : int,Opcja 2 =>
LogFacility = record {
id : int, - identyfikator (numeryczny, długi int) placówki – to jest identyfikator z wnętrza systemu, to nie może być żaden numer referencyjny, rejestrowy, pozwalający jakkolwiek zidentyfikować placówkę
zip : string, - pole kod pocztowy placówki → patrz komentarz poniżej.
city : string – pole miasto placówki → patrz komentarz poniżej.
}
W kwestii pól kodu pocztowego i miasta placówki zdecydowanie nie jest intencją, aby na ich podstawie próbować identyfikować placówki. Ten aspekt jest poza strefą zainteresowania systemu. Natomiast istotną z punktu widzenia systemu cechą jest jakaś forma geolokalizacji. Możemy przyjąć założenie, że gradacja poniżej powiatu nas zupełnie nie interesuje. Teoretycznie można by zatem przesyłać kod pocztowy miasta powiatowego. To jednak nie rozwiązuje problemu dużych miast, gdzie jest wiele kodów jak np. Warszawa. Oczywiście można spojrzeć na temat tak, że obiektywnie w jakiejś małej miejscowości jest dokładnie jedna placówka medyczna, więc podanie dla niej kodu pocztowego i miejscowości jednoznacznie ją zidentyfikuje. Reasumując, pozostawiamy otwartą decyzję jakie dane umieścić w tych polach.refId : int,Opcja 2 =>
LogPatient = record {
id : int, - identyfikator (numeryczny, długi int) placówki – to jest identyfikator z wnętrza systemu, to nie może być żaden numer referencyjny, PESEL, ani żaden inny numer pozwalające na identyfikację pacjenta
monthOfBirth : string, - miesiąc urodzenia w formacie RRRR-MM – do szacunkowego wyliczania wieku, w celu prowadzenia analiz związanych z wiekiem pacjentów
sex : LogSex = variant { male | female | other } - płeć pacjenta
}
Dane kodów ICD10 przypisanych do wizyty.
LogVisitIcd10 = record {
id : int, - identyfikator przypisany do rekordu w systemie źródłowym
main : bool, - bool, czy rozpoznanie główne przy wizycie czy nie
permenent : bool, - bool czy rozpoznanie przewlekłe, czy nie
icd10 : string – kod ICD10 w formie tekstowej – generalnie kody ICD10 muszą być w jednym z następujących formatów – A, A00, A00.0 – walidacja przebiega następująco – system najpierw usuwa z teksu wszystkie znaki, które nie są A-Z, a-z, 0-9. (znak . też jest usuwany). Następnie napis jest zamieniany na wielkie litery. I teraz jest sprawdzany format, czyli A lub A00 lub A000. Jeśli napis nie spełnia założeń jest odrzucany (uwaga, odrzucenie kodu icd10 oznacza tylko odrzucenie przypisania kodu do wizyty – nie wpływa na import danych wizyty i innych danych powiązanych). Następnie następuje sprawdzenie czy kod ICD10 istnieje w bazie leków. Jeśli nie istnieje jest odrzucany.
}
Dane recept przypisanych do wizyty.
LogVisitRecipe = record {
id : int, - identyfikator przypisany do rekordu w systemie źródłowym, to jest identyfikator wewnętrzny i nie może to być żadna referencja do recepty o znaczeniu zewnętrznym,
w szczególności to nie może być numer recepty
type : string, - pole tekstowe ogólnego przeznaczenia, bez nadanej semantyki, do wykorzystania w zależności od potrzeb i możliwości
state : string, - pole tekstowe ogólnego przeznaczenia, bez nadanej semantyki, do wykorzystania w zależności od potrzeb i możliwości
drugs – kolekcja danych leków przypisanych do danej recepty
}
Dane leków przypisanych do recepty.
LogVisitRecipeDrug = record {
id : int, – identyfikator przypisany do rekordu w systemie źródłowym, to jest identyfikator wewnętrzny i nie może to być żadna referencja do recepty
lub e-recepty o znaczeniu zewnętrznym
dosation : string, – pole testowe zawierające informację o tym co lekarz wpisać na recepcie – to jest pole, które standardowo powinno zawierać liczbę sztuk,
które przypisał lekarz, ale formalnie nie ma żadnych wytycznych ograniczających lekarza w tym, co może tu wpisać, dlatego pole jest tekstowe.
Strategia powinna być taka, że w tym polu umieszczamy to co wpisał lekarz „jak leci”, czyli np. „2 op.” albo „3 szt.” albo „10 amp.”.
Jeśli system źródłowy posiada bardziej szczegółowe informacje na temat tego co lekarz wybrał, wpisał, to należy te informacje przekazać w polu dosation_number.
dosation_number : LogDosationNumber = variant { – to pole powinno zawierać szczegółowe informacja na temat liczby leku przypisanej przez lekarza – o ile takie informacje są
dostępne w systemie źródłowym
piecies : int – to jest wariant, który zawiera liczbę sztuk, opakowań, elementów, które przypisał lekarz.
| other – to jest wariant, który powinien być przekazany jeśli nie wiadomo jaką wartość wpisał lekarz
}, - uwaga jest taka, że program źródłowy nie powinien próbować w magiczny sposób odgadywać, co lekarz miał na myśli – jeśli system źródłowy obiektywnie nie posiada informacji
ile sztuk przypisał lekarz, to nie powinien tej informacji umieszczać.
source : string, – to jest pole, które powinno zawierać informację, w jaki sposób dany lek trafił na receptę – zawartość tego pola zależy od specyfiki programu źródłowego
i powinno zostać ustalone w ramach integracji. Zawartość tego pola standardowo może zależeć od tego, jak działa program i w jaki sposób pozwala na utworzenie recepty.
Chyba w każdym programie standardową opcją jest jakaś forma wyszukiwarki leków i tworzenie recepty przez lekarza poprzez wyszukiwanie leków za pomocą wyszukiwarki.
Można jednak sobie wyobrazić inne możliwości jak np. kopiowanie poprzednich recept lub dodawanie leków na receptę z leków stałych pacjenta, leków poprzednich pacjenta.
Można sobie też wyobrazić, że pacjenta zamawia recepty przez internet lub innym tego typu kanałem. Reasumując, semantyka pola powinna zostać ustalone w fazie integracji.
searchPhase : string, - intencją tego pola jest przekazywanie informacji, jaka była fraza szukana przez lekarza w momencie jak wybrał dany lek na receptę.
drug – dane przypisanego leku
}
Dane leku przypisanego do recepty =>refId : int,- referencja do bazy leków – to jest opcja, która jest ZDECYDOWANIE polecana. Id w tym miejscu użyty jest referencją do rekordu version z bazy leków (pole version.id). To pozwala na jasne, jednoznacznej zidentyfikowanie leków.
drug : LogDrug = record {
id : int, - wewnętrzny identyfikator leku po stronie systemu źródłowego
name : string, - nazwa leku – pełnotekstowo (np. Apap)
kind : string, - postać leku, pełnotekstowo (np. tabl.)
dose : string, - dawka leku, pełnotekstowo (np. 100 mg)
box : string, - zawartość opakowania (np. 28 szt.)
ean : string – EAN leku – to pole jest kluczowe i koniecznie powinno być wypełnione
}
W przypadku podania danych w tej formie system będzie przyjmował zgłoszenia a następnie będzie w tle próbował rozwiązywać nieznane referencje poprzez przypisanie ich do bazy leków.
curl -s https://api.preskryptor.pl/cmd --cookie 'auth=token#27219#2961c9d416f0d10c561e504766eee242' --data-urlencode cmd={"rev":"2.0","customCmd":{
"log":{"visits":[ (...) ] }}}
gdzie (...) w visits to:
{
"visits": [
{
"id": 10000,
"date": "2024-02-05",
"state": "State",
"kind": "Kind",
"doctor": {
"doctor": {
"id": 2000,
"facility": {
"facility": {
"id": 30000,
"zip": "00-123",
"city": "Warszawa"
}
}
}
},
"patient": {
"patient": {
"id": 4000,
"monthOfBirth": "1990-01",
"sex": { "other": "" }
}
},
"icd10s": [
{
"id": 1,
"main": 0,
"permenent": 0,
"icd10": "A"
},
{
"id": 2,
"main": 0,
"permenent": 1,
"icd10": "A00"
},
{
"id": 3,
"main": 1,
"permenent": 0,
"icd10": "A00.0"
},
{
"id": 4,
"main": 1,
"permenent": 1,
"icd10": "Z"
}
],
"recipies": [
{
"id": 90000,
"type": "Recepta",
"state": "Gotowa",
"drugs": [
{
"id": 88000,
"dosation": "3 op",
"dosation_number": { "piecies": 3 },
"source": "P",
"searchPhase": "",
"drug": { "refId": 981937 }
},
{
"id": 88001,
"dosation": "1 op",
"dosation_number": { "other": "" },
"source": "R",
"searchPhase": "",
"drug": {
"drug": {
"id": 99,
"name": "Apap",
"kind": "tabl.",
"dose": "100 mg",
"box": "28 szt",
"ean": "05909990296026"
}
}
},
{
"id": 88002,
"dosation": "2 op",
"dosation_number": { "piecies": 2 },
"source": "S",
"searchPhase": "",
"drug": { "refId": 1 }
}
]
},
{
"id": 90001,
"type": "Recepta",
"state": "Robocza",
"drugs": [
{
"id": 88010,
"dosation": "3 op",
"dosation_number": { "piecies": 3 },
"source": "P",
"searchPhase": "",
"drug": { "refId": 26039970 }
},
{
"id": 88011,
"dosation": "1 op",
"dosation_number": { "other": "" },
"source": "R",
"searchPhase": "",
"drug": {
"drug": {
"id": 99,
"name": "Ibufen® Baby",
"kind": "czopki doodbytnicze",
"dose": "60 mg",
"box": "5 szt",
"ean": "5909990922550"
}
}
}
]
},
{
"id": 90002,
"type": "Receptura",
"state": "Robocza",
"drugs": []
}
]
},{
"id": 10001,
"date": "2024-03-05",
"state": "State",
"kind": "Kind",
"doctor": {
"refId": 2000
},
"patient": {
"refId": 4000
},
"icd10s": [
{
"id": 1,
"main": 0,
"permenent": 0,
"icd10": "A"
}
],
"recipies": [
{
"id": 90010,
"type": "Recepta",
"state": "Gotowa",
"drugs": []
}
]
}
]
}
curl -s https://api.preskryptor.pl/cmd --cookie 'auth=token#27219#2961c9d416f0d10c561e504766eee242' \
--data-urlencode 'cmd={"rev":"2.0","customCmd":{"advert":{"source":{"all":""},"format":{"json":""}}}}'
Możliwe jest także pobieranie każdego z elementów oddzielnie, np. =>curl -s https://api.preskryptor.pl/cmd --cookie 'auth=token#27219#2961c9d416f0d10c561e504766eee242' \
--data-urlencode 'cmd={"rev":"2.0","customCmd":{"advert":{"source":{"actions":""},"format":{"json":""}}}}'
Baza mechanizmów reklamowych nie udostępnia opcji filtrowania zmian – za każdym razem trzeba pobrać pełną specyfikację.
"actions": [
{
"id": 27247,
"state": { "active": "" },
"name": "Tylko dla lekarzy",
"icd10Prefix": "",
"user": { "doctor": "" },
"minAge": 0,
"maxAge": 200,
"pregnancy": { "any": "" },
"sex": { "any": "" }
}, - ten zbiór pasuje do dowolnej sytuacji (czyli emisja mechanizmu przypisanego do tego zbioru parametrów akcji może nastąpić w dowolnej sytuacji, w dowolnym miejscu programu) o ile jest zalogowany użytkownik i ten użytkownik jest lekarzem..
{
"id": 27249,
"state": { "active": "" },
"name": "Nadciśnienie",
"icd10Prefix": "I10",
"user": { "doctor": "" },
"minAge": 20,
"maxAge": 200,
"pregnancy": { "any": "" },
"sex": { "any": "" }
},
- ten zbiór pasuje do sytuacji, w której jest w programie prowadzona, edytowana wizyta (bieżąca wizyta) i do tej wizyty jest przypisane rozpoznanie I10 lub jakieś inne rozpoznanie zaczynające się od I10 (np. I10.1) i dodatkowo bieżący, zalogowany użytkownik jest lekarzem.
{
"id": 27250,
"state": { "active": "" },
"name": "Kobieta w ciąży",
"icd10Prefix": "",
"user": { "anyPersonel": "" },
"minAge": 18,
"maxAge": 200,
"pregnancy": { "pregnant": "" },
"sex": { "female": "" }
} - ten zbiór pasuje do sytuacji, w której jest w programie prowadzona, edytowana wizyta (bieżąca wizyta) i na tej wizycie przypisanym pacjentem jest kobieta w wieku co najmniej 18 lat, ma ustawioną flagę, że jest w ciąży i dodatkowo jest zalogowany jakikolwiek użytkownik (trudno sobie wyobrazić, aby taką wizytę mógł zobaczyć, przeglądać użytkownik system bez zalogowania, ale formalnie taki sens tych parametrów).
]
"images": [
{
"id": 27274,
"state": { "active": "" },
"resource": {
"id": 27273,
"name": "Banner testowy",
"descr": "",
"path": "2d97ebc8-9040-4232-9348-eae5336a94f9_demo_logo.png"
},
"kind": { "id": 2, "name": "Work", "descr": "Banner w trakcie pracy" },
"url": "",
"startDate": "2024-04-01",
"endDate": "2024-12-31",
"actions": [ 27247 ]
}
]
Powyższy wpis stanowi definicję jednego banera. Baner jest w stanie aktywnym (state = active) i przeznaczonym do emisji w okresie od 2024-04-01 do 2024-12-31. Baner nie jest ma podanego url, więc nie powinien być do niczego podlinkowany – po prostu prezentacja banera. Jest możliwe, że pole url będzie zawierało jakiś adres. Pole kind specyfikuje rodzaj banera, miejsce, w którym baner powinien być prezentowany. Nie jest określone jakie miejsca są w ogóle dostępne w programie, więc wartość tego pola nie definiuje semantyki. W trakcie wdrożenia powinno zostać ustalone jaką semantykę nadajemy konkretnym wartościom tego pola. Katalog możliwych wartości jest otwarty, więc w przypadku takiej potrzeby można zdefiniować nowe pola. Ostatnie pole to resource, które określa referencję do zasobu graficznego, który ma być prezentowany. Do odwołania do plików zawierających grafiki służy pole path. Linki powinny być tworzone poprzez dodanie prefiksu https://preskryptor.pl/resources/. Czyli pełna ścieżka ma postać https://preskryptor.pl/resources/2d97ebc8-9040-4232-9348-eae5336a94f9_demo_logo.png. Dostęp do plików jest otwarty – nie jest konieczna żadna autoryzacja, więc pliki można osadzać bezpośrednio w programie docelowym u klienta.
"recipies": [
{
"id": 27101,
"state": {
"active": ""
},
"inn": {
"id": 225,
"name": "Cefuroxime axetil",
"namePl": "Aksetyl cefuroksymu"
},
"group": {
"id": 44042973,
"name": "Bioracef®"
},
"level": 1,
"prefix": "",
"startDate": "2024-04-01",
"endDate": ""
}
]
F1(string) = { F(string) + { F(string) → array of Cure → array of Inn → recipies.group }
Czyli do wyniku standardowe wyszukiwania za pomocą funkcji F dodajemy dodatkowo te grupy, które są powiązane z pewnymi wynikami F poprzez powiązanie group – inn, inn – recipe i recipe – group.