api.preskryptor.pl

– jesteś na stronie dotyczącej API systemu Preskryptor.

Aktualna wersja interfejsu: 2.0
Dokumentacja: rev.6, 2024-04-19.
Jeśli chcesz dowiedzieć się, czym ogólnie jest system Preskryptor – przejdź TUTAJ.

Jeśli chcesz przejrzeć szczegółową listę zawartości API – przejdź TUTAJ.

Poniżej znajduje się opis, jak krok po kroku zintegrować się z API.

Integracja z API

API Preskryptor dzieli się na 4 obszary:

1. Obszar autoryzacji.

2. Obszar bazy leków.

3. Obszar logowania zdarzeń.

4. Obszar specyfikacji działań marketingowych.

Informacje ogólne na temat sposobu komunikacji z API (założenia dotyczące JSON, sposób wysyłania żądań i inne) znajdują się TUTAJ.

Do komunikacji z API produkcyjnym służy URL => https://api.preskryptor.pl/cmd. Do komunikacji z bazą testową służy URL https://apidemo.preskryptor.pl/cmd.

Zanim zaczniesz cokolwiek testować sprawdź, czy działa odwołanie testowe do serwera. Odwołanie testowe ma postać =>

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:



1. Obszar Autoryzacji

Aby wysłać dowolnej żądanie do API konieczna jest autoryzacja. Każdy klient do autoryzacji można otrzymać dane, które będą go identyfikować. Tymi danymi jest para USERID i USERPASSWD. Wartość USERPASSWD jest poufna i nie powinna być nikomu udostępniana.

Wartości testowe (działające) to:
        USERID=2
        USERPASSWD=YTRGHJKHGVFRTYUIKJHGFTYUIiuytgfhjkiuyhgtfgyuikjhy0987654567890
        
Proces autoryzacji jest dwuetapowy.
Pierwszy etap polega na pobraniu tokena. Do pobrania tokena służy odwołanie =>
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.
Wynik zapytania powinien mieć postać =>
        {"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.
Łańcuch autoryzacyjny jest sumą md5 wygenerowaną z tekstu będącego złączeniem: otrzymanego tokenu, stałego tekstu ‘#hash#’ oraz własnego USERPASSWD.
Czyli =>

        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"
        



2. Obszar bazy leków.

API do bazy leków służy do pobierania informacji na temat bazy leków. API działa w dwóch trybach. Pierwszy zwraca kompletny bieżący stan bazy leków. Drugi zwraca tylko zmienione rekord od wskazanej daty. Zdecydowanie zalecamy, aby za każdym razem pobierać całość bazy. W ten sposób istotnie prościej uniknąć problemów z przeoczeniem zmian w bazie i baza będzie w ten sposób na pewno aktualna. W obu przypadkach API pozwala na wybór obiektów, które mają być zwrócone przez API. Jest możliwość wybrania wszystkich istniejących typów obiektów lub wskazania obiektów konkretnego typu. W bazie leków znajdują się następujące typu obiektów:

  1. versions to jest główna kolekcja zawierająca „pojedyncze” leki (wersje leków). Intuicja jest taka, że tu znajdują się unikalne EANy. Czyli jak jest np. Apap, który występuje w kilku wielkościach opakowań, to w tej tabelce będzie każda wielkość opakowania oddzielnie a Apap jako grupa będzie grupował te różne opakowania na poziomie kolekcji groups. Referencja do tych elementów powinna znaleźć się np. na recepcje.
  2. priceKindsoznaczenia cen specjalnych leków refundowanych. Tu znajdują się (na teraz) flagi senior, ciąża i dzieci, oraz oznaczenie 100%, które oznacza cenę urzędową leku bez refundacji.
  3. refundPricespowiązanie wersji leków z refundacjami (niezwiązanymi z chorobami), czyli ceny specjalne w refundacji (priceKinds
  4. diseaseslista chorób dla leków refundowanych – na liście znajduje się dodatkowa flaga, czy choroba powinna być traktowana jako „Wszystkie zarejestrowane wskazania” czy też nie.
  5. refundDiseasespowiązanie wersji leków z chorobami (diseases) i poziomami refundacji (levels), zawiera ceny leków refundowanych
  6. levelsoznaczenia poziomów refundacji, czyli (na teraz) 50%, 30%, ryczałt lub bezpłatny.
  7. psychotropics(...)
  8. statusesoznaczenia statusów leków, czyli Rx, OTC, WM i inne.
  9. registersoznaczenia miejsca rejestracji leku (np. MZ lub UE), ma znaczenie w powiązaniu z polem version.reg.
  10. routesoznaczenia dróg podania leków
  11. companiespodmioty odpowiedzialne przypisane do leków
  12. groupsgrupy leków, łączą wersje leków w grupy leków, które de facto są tym samym a różnią się np. wielkościami opakowań, leki wewnątrz jednej grupy mają ten sam podmiot odpowiedzialny, ten sam skład, ten sam opis i inne wspólne cechy
  13. innssubstancje czynne
  14. innGroupspowiązanie pomiędzy substancjami czynnymi a grupami leków
  15. icd10sklasyfikacja ICD10
Przykłady odwołań:

Pobranie bieżącego stanu bazy leków, wszystkie rodzaje obiektów =>
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.

Uwaga 2 – data musi być zawsze w formacie RRRR-MM-DD.

Pobranie zmian w bazie leków od daty 2024-02-01 we wszystkich obiektach =>
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":""}}}}'


3. Obszar logowania zdarzeń.

Koncepcje wstępne.

Funkcjonalność służy do logowania zdarzeń w placówkach medycznych. API nigdy w żadnym zakresie nie zawiera i nie może zawierać danych osobowych, wrażliwych lub jakichkolwiek innych, które pozwalałyby na identyfikację pacjenta lub lekarza. Jeśli są jakiekolwiek wątpliwości w zakresie przesyłanych danych – nie przesyłaj ich!
Obiektem podstawowym używanym przy logowaniu danych jest zawsze wizyta. Obiekty wizyty jest źródłem powiązań ze wszystkimi dodatkowymi danymi. Logowane są zawsze wizyty wraz z kompletem informacji dodatkowych.
Na przekazywane dane wizyty składa się:

  1. id : intidentyfikator (numeryczny, długi int) wizyty – UWAGA → patrz opis zarządzania identyfikatorami poniżej.
  2. date : stringdata wizyty w formacie RRRR-MM-DD.
  3. state : stringstan wizyty – pole do wykorzystania w zależności od funkcjonalności oprogramowania, system nie narzuca żadnej semantyki dla tego pola, semantyka do ustalenia, tu można wrzucić np. rozróżnienie „NFZ”, „prywatna” lub „zakończona”, „anulowana”, „nierozliczona”, lub jakąkolwiek inną semantykę wg ustaleń.
  4. kind : stringpole jw. semantyka do ustalenia
  5. doctorpowiązanie do lekarza realizującego wizytę
  6. patientpowiązanie do pacjenta realizującego wizytę
  7. icd10skolekcją kodów ICD10 w ramach wizyty
  8. recipieskolekcja recept przypisanych do wizyty
Dane lekarza =>

Są dwie opcje przekazania danych lekarza.

Opcja 1 =>
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.
Opcja 2 =>
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).

Dane placówki =>

Są dwie opcje przekazania danych placówki.

Opcja 1 – przez referencję, analogicznie jest dla lekarza.
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.

Dane pacjenta =>

Opcja 1 – referencja, analogicznie jak dla lekarza i placówki:
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.

Kody ICD10 są przypisane w formie kolekcji rekordów w formacie:
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.

Uwaga wstępna – nie interesują nas zupełnie leki niestandardowe, np. leki przygotowywane w aptekach wg receptur. Interesują nas tylko i wyłącznie leki z bazy. Natomiast nawet jeśli mamy receptę na leki, które nas nie interesują, to taka recepta może być przekazana do systemu z pustą listą przypisanych leków.

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 =>

Opcja 1 =>
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.

Opcja 2 =>
O ile opcja przez referencje jest zdecydowanie zalecana, to jesteśmy świadomi sytuacji, w których obiektywnie może nie być danych źródłowych, aby odwołać się do referencji.

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.

WAŻNE! Opis procesu zarządzania identyfikatorami w systemie logowania.

API zakłada, że dla danego konta użytkownika (pary USERID i USERPASSWD używanego do dostępu do API) jest jedna wspólna przestrzeń identyfikatorów obiektów. Oznacza to tyle, że w przypadku jak za pomocą jednego konta prześlemy w dwóch różnych odwołaniach do API dwóch pacjentów z tym samym id, to system potraktuje tych pacjentów jako jednego i tego samego pacjenta. Oznacza to, że jeśli masz kilka niezależnych instancji swojej aplikacji i te instancje mają zupełnie niezależne pule identyfikatorów (innymi słowy w różnych instancjach te same id mogą się powtarzać) to powinieneś używać oddzielnych kont użytkowników dla każdej instancji.

Przykłady.

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": []
        }
      ]
    }
  ]
}




4. Obszar specyfikacji działań marketingowych.

API dotyczące działań marketingowych służy do pobierania informacji, za pomocą których powinny zostać zrealizowane mechanizmy marketingowe w oprogramowaniu docelowym. API nie definiuje ani czy wszystkie mechanizmy powinny być zrealizowane ani tym bardziej w jaki sposób mechanizmy powinny być realizowane. API dostarcza dane do realizacji mechanizmów. To czy dany mechanizm może w ogóle zostać zrealizowany w oprogramowaniu docelowym oraz w jaki konkretny sposób miałby zostać zrealizowany w oprogramowaniu docelowym jest kwestią do ustalenia.

W ramach API jest możliwe pobieranie informacji o następujących elementach:
  1. a. Definicje parametrów akcji.
  2. b. Definicje bannerów.
  3. c. Definicje pozycjonowania wyszukiwania.

Do pobierania danych na temat mechanizmów reklamowych służy odwołanie =>

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ę.

W wyniku odpytania o listę mechanizmów otrzymujemy specyfikację każdego z mechanizmów.

Znaczenie danych jest następujące.

a. Definicje parametrów akcji.

Każdy element zwracanych parametrów akcji opisuje jakie parametry pasują do danej akcji. Na parametry składają się:
  1. wiek pacjentawartości min i max – wartości są wymagane i oznaczają wiek bieżącego pacjenta – intencja jest taka, że parametry są zawsze podane i tu mogą teoretycznie pojawić się wartości takie jak -1 lub 1000. Można sobie wyobrazić sytuację, w które po stronie oprogramowania wiek pacjenta będzie nieznany (bo w systemie nie ma tej dane) i wtedy sensowne byłoby założenie, że wartości min<=0 i max>=150 pasują do każdego pacjenta, także takiego, dla którego wiek jest nieznany.
  2. prefiks ICD10ten parametr pasuje do bieżącego pacjenta jeśli dla bieżącego pacjenta i bieżącej wizyty zadany prefiks pasuje do jakiegoś rozpoznania, które jest na bieżącej wizycie. W przypadku pustej wartości to pasuje do wszystkiego i każdej sytuacji (niezależnie od wizyty i pacjenta).
  3. userparametr jest określeniem warunku jaki musi spełniać bieżący użytkownik systemu końcowego (oprogramowania końcowego), aby pasował do parametrów. Możliwe wartości to doctor | nurse | anyPersonel | any. Te wartości powinny być w sensowny sposób zmapowane na opcje dostępne w systemie. Bardzo ważnym elementem jest sensowne mapowanie parametru doctor jako użytkownik, który jest lekarzem, ponieważ od tego zależą prawne aspekty możliwości emisji reklam leków na receptę. Intencją pozostałych parametrów są:
    nurse → pielęgniarka,
    anyPersonel → dowolny personel po zalogowaniu,
    any → wszystko do tego pasuje.
  4. pregnancyparametr określa status „ciąży” pacjenta. Możliwe wartości to pregnant | notPregnant | any
  5. sexoznacza płeć pacjenta – możliwe wartości to male | female | any.
          "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).
          ]
        

b. Definicje banneró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.

Ostatnim elementem jest kolekcja akcji, do których pasuje ten banner. Baner z przykładu jest przypisany do parametrów o ID=27247. Ten ID opisuje akcje „Tylko dla lekarzy”, czyli łącznie mamy tu baner, który powinien być emitowany zgodnie z typem emisji „Banner w trakcie pracy” (to trzeba zdefiniować, co to oznacza z punktu widzenia programu docelowego), powinien być emitowany od 2024-04-01 do 2024-12-31, bez żadnego linkowania, urla, z wykorzystaniem wskazanego pliku graficznego, ale tylko i wyłącznie dla lekarzy.

c. Definicje pozycjonowania wyszukiwania.

Zakres API dotyczący pozycjonowania wyszukiwania jest przeznaczony do definiowania, które leki powinny być wyróżnione podczas wyszukiwania. API nie definiuje w jaki sposób wykorzystać dane. Konkretny sposób ich wykorzystania w dużej mierze zależy od specyfiki oprogramowania, w którym jest zrealizowane wyszukiwanie leków. Nie mniej jednak ogólny sens danych jest następujący. W każdym rekordzie znajduje się pole group, które jest referencją do bazy leków (kolekcja groups) i oznacza grupę, która powinna być wyróżniona. Zakresem danych, dla którego powinno działać wyróżnienie jest pole inn, czyli substancja czynna (to pole także jest referencją do bazy leków do kolekcji inns). Konkretna para inn i group ma sens taki, że dla wszystkich leków zawierających wskazany inn wyróżnione powinny być leki z grupy group. Co do zasady group powinno być przypisane do tego inn, ale tu mogą się zdarzyć wyjątki. Dla przykładu istnieją substancje czynne, które występują w postaci różnych związków (np. chlorków, szczawianów) i zdarza się, że w takich przypadkach możemy chcieć wyróżniać lek poza jego dokładną substancją. W rekordzie znajdują się jeszcze dwa pola, na które warto zwrócić uwagę. Pierwsze z nich do pole prefix, które oznacza, że wyróżnianie ma działać tylko w przypadku jak wpisana przez lekarza w czasie wyszukiwania fraza zaczyna się od danego prefiksu. Ten mechanizm służy do zawężania mechanizmu wyróżniania dodatkowo tylko do leków o danym prefiksie. Ostatnie pole to level. Intencją tego pola jest dostarczenie dodatkowego mechanizmu, za pomocą którego można sortować reguły wyróżniania leków. Pole to adresuje problem, że w przypadku duże zbioru reguł i sytuacji w wyszukiwaniu, że do danej frazy wpisane przez lekarza pasuje wiele leków, trudno jest określić, które leki wyróżnione mają się pokazywać lub też które leki wyróżnione mają się pokazywać jako pierwsze. Dlatego zostało wprowadzone pole level, które może pomagać w tym wyborze. Pole nie posiada ścisłej, opisanej semantyki. Pole można wykorzystać wg własnego uznania.
          "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": ""
            }
          ]
        

Przykładowy sposób implementacji wyróżniania leków.

Załóżmy, że w oprogramowaniu istnieje funkcjonalność, która dla wpisanej przez lekarza frazy zwraca listę leków pasujących do tej frazy. Czyli powiedzmy, że istnieje funkcja F(string – fraza) → array of Cure, gdzie jako Cure rozumiemy pojedynczy wynik, który może być np. grupą leku lub wersją leku wg terminologii używanej w bazie leków. Niezależnie od tego czym jest Cure, to dla każdego Cure w bazie leków istnieje przypisanie Cure → array of Inn (zbiór substancji czynnych danego leku). Teraz dla każdego Inn możemy przyporządkować mu rekordy z recipies powyżej (powiązanie wg recipies.inn.id). Możemy zatem zmodyfikować funkcję wyszukującą F w następujący sposób:

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.

Dla tak określonego zbioru następnie trzeba ustalić kolejność prezentacji danych. Najprostszym mechanizmem mogłoby był założenie, że wszystkie leki niewyróżnione mają „wagę” zaś leki wyróżnione mają wagę równą wartości level z odpowiadającego rekordu z recipies. Przy takim podejściu warto zwrócić uwagę, że dla dużych zbiorów wynikowych (czyli dla sytuacji, że dla danej frazy funkcja F zwraca dużo wyników) liczba wyróżnionych leków może być duża, co może powodować efekt, że na początku listy będzie znajdować się dużo leków wyróżnionych, co z kolei może sprawiać wrażenie dla użytkownika, że wyszukiwanie nie działa. Dlatego też warto rozważyć podejście, które ograniczałoby ten efekt. Można np. ograniczać liczbę leków wyróżnionych poprzez założenie, że leków wyróżnionych może być maksymalnie 3-5. To jest rozsądne podejście biorąc pod uwagę, że celem lekarza w momencie wyszukiwania leku jest zazwyczaj znalezienie jednego konkretnego leku. W normalnym przypadku dane będą skonstruowane tak, że dla danego leku będą przypisane maksymalnie 2-3 leki wyróżnione. Zatem ograniczenie liczby prezentacji leków wyróżnionych przez sensowną stałą będzie spełniało główny cel programu.