Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

Table of Contents

Purpose

This method is designed to create hold (reservation) on medication in order to prevent multiple dispenses under the same Medication Request. This hold lasts certain time (configuration parameter MEDICATION_DISPENSE_EXPIRATION) after with it goes to EXPIRED status

...

Dispense details - several medications of different manufacturers with the same substance can be dispensed at a time. Total of medication_qty should be less or equal to medication quantity specified in Medication Request

...

Status Charts (reimbursement)

Specification

Apiary

WS logic

Authorize user

  1. Verify the validity of access token
    1. Return 401 in case validation fails
  2. Check user scopes in order to perform this action (scope = 'medication_dispense:write')
    1. Return 403 in case invalid scope(s)

Validate request

Schema validation

  1. Validate request according to JSON Schema
    • Return 422 with list of validation errors in case validation fails (422 EView)

Validate program medication

In case medications are dispensed to patient under specific medical program, program medication id must be provided provided by client or calculated by the system

In case program medication id exists in request:

  1. Check that this program medication id relates to provided medical program and relates to provided medication
    1. In case of error - return 422 (Invalid program medication id)

Calculate program medication id if it is absent in request:

  1. Get last program_medication_id related to medical program and medication
    1. In case of error - return 422 (There are no active program medications for this program and medication)

Get legal entity from token

  1. Extract legal_entity_id (client_id) from token

Get Party from token

  1. Extract party_user (user_id) from token.

Validate FK

1. Validate legal_entity_id - legal_entity_id exists

In case error - return 422 error:

Code Block
languageerl
{:error, [{%{
        description: "Legal entity not found",
        params: [],
        rule: :invalid
      }, "$.legal_entity_id"}]}

2. Validate medication_request_id - medication_request_id exists

Code Block
languageerl
{:error, [{%{
        description: "Medication request not found",
        params: [],
        rule: :invalid
      }, "$.medication_request_id"}]}

3. Validate party_id - party_id exists

Code Block
languageerl
{:error, [{%{
        description: "Party not found",
        params: [],
        rule: :invalid
      }, "$.party_id"}]}

4. Validate division_id - division_id exists

Code Block
languageerl
{:error, [{%{
        description: "Division not found",
        params: [],
        rule: :invalid
      }, "$.division_id"}]}

5. Validate medical_program_id - medical_program_id exists

Code Block
languageerl
{:error, [{%{
        description: "Medical program not found",
        params: [],
        rule: :invalid
      }, "$.medical_program_id"}]}

5.1 Validate there is a contract in PRM.contracts that meets following requirements:

...

Contract dates: start_date <= current_date & end_date >= current_date

...

In  case of error 409 - "Program cannot be used - no active contract exists"

Validate all medication_id (brand_id) - brand_id exists

...

languageerl

...

Table of Contents

Purpose

This method is designed to create a hold (reservation) on medication in order to prevent multiple dispenses under the same Medication Request. This hold lasts certain time (configuration parameter MEDICATION_DISPENSE_EXPIRATION) after which it goes to EXPIRED status.

Key features

  1. Dispense of medication is possible only under Medication Request and during the period specified in Medication Request (dispense_valid_from,dispense_valid_to).

  2. Dispense details - several medications of different manufacturers with the same substance can be dispensed at a time. The total of medication_qty should be less or equal to the medication quantity specified in the Medication Request.

Status Charts (reimbursement).

Specification

Page Properties

Link

https://ehealthmisapi1.docs.apiary.io/#reference/public.-reimbursement/medication-dispense/create-medication-dispense

Посилання на Apiary або Swagger

Resource

/api/medication_dispenses

Посилання на ресурс, наприклад: /api/persons/create

Scope

medication_dispense:write

Scope для доступу

Components

ePrescription

Зазначається перелік бізнес компонентів, які використовують цей метод, наприклад: ePrescription

Microservices

API paragraph not found

Перелік мікросервісів, які використовує метод API, наприклад: Auth, ABAC

Protocol type

REST

Тип протоколу, який використовується запитом, наприклад: SOAP | REST

Request type

POST

Тип запиту API, наприклад: GET, POST, PATCH…

Sync/Async

Sync

Метод є синхронним чи асинхронним?

Public/Private/Internal

Public

Logic

  1. Get skip_medication_dispense_sign from medical program settings.

  2. If skip_medication_dispense_sign = false or absent:

          2.1. Check payment_id, payment_amount is present in the request.

in case if absent - return 422 with path: $.<field_name>  and message "schema does not allow additional properties"

          2.2. Add record to medication_dispenses table:

Parameter

Source

Description

id

UUID

Autogenerated

payment_id

NULL

NULL for new records

payment_amount

NULL

NULL for new records.

status

Const: NEW

NEW skip_medication_dispense_sign = false

See: Medication dispense status model

is_active

Const: TRUE

Alwayls TRUE for new records

inserted_at

Timestamp: now()

Get current date-time

inserted_by

Token: user_id

Extract user from token

updated_at

Timestamp: now()

Get current date-time

updated_by

Token: user_id

Extract user from token

          2.3. Add records to medication_dispense_details table:

Parameter

Source

Description

id

UUID

Autogenerated

medication_dispense_id

FK: medication_dispense

 

reimbursement_amount

Reimbursement

 

          2.4. Add records to medication_2d_codes table (for each 2d code object in array):

Parameter

Source

Description

id

UUID

Autogenerated

medication_dispense_id

FK: medication_dispense

 

medication_2d_code

Request: medication_2d_codes

 

inserted_at

Timestamp: now()

Get current date-time

  1. If skip_medication_dispense_sign =

true:

             3.1. Check if payment_amount in the request.

  • in case is absent - return 422 with path: $.payment_amount and message "required property payment_amount was not present"

             3.1. Call Process Medication Dispense by Pharmacy User process, but without validation of the previously created (NEW) medication dispense, digital sign and storage signed content to the bucket.

             3.2. Add records as described on steps 2.2-2.4, but with following differences: 

             medication_dispenses table

Parameter

Source

Description

payment_id

Request: payment_id

optional parameter

payment_amount

Request: payment_amount

optional parameter

status

Const: PROCESSED

PROCESSED skip_medication_dispense_sign = true
See: Medication dispense status model

Preconditions

No

Global and configurable parameters

No

Input parameters

No

Filters

Filter

Values

Type

Description

Example

code

Optional

3114

Request structure

Example:

Expand
titleRequest example
Code Block
{
  "medication_dispense": {
    "medication_request_id": "f08ba3a3-157a-4adc-b65d-737f24f3a1f4",
    "dispensed_at": "2017-08-17",
    "dispensed_by": "Іванов Іван Іванович",
    "division_id": "2fc70f30-08dc-493c-8d08-925905d7b1e8",
    "medical_program_id": "6ee844fd-9f4d-4457-9eda-22aa506be4c4",
    "dispense_details": [
      {
        "program_medication_id": "64c06ebc-0266-4645-85f0-7a6900d7dfbe",
        "medication_id": "787b6ef1-1d3a-4129-849c-87716c9a2130",
        "medication_qty": 10.34,
        "sell_price": 18.65,
        "sell_amount": 186.5,
        "discount_amount": 150,
        "medication_2d_codes": [
          {
            "medication_2d_code": "0104820005161713171812001022431115 211XV82HPV"
          }
        ]
      }
    ],
    "payment_id": "1239804",
    "payment_amount": 50
  }
}

Authorize

  1. Verify the validity of access token

    1. return 401 in case validation fails.

  2. Check user scopes in order to perform this action (scope = 'medication_dispense:write')

    1. return 403 in case invalid scope(s).

Headers

Content-Type:application/json

Authorization:Bearer c2778f3064753ea70de870a53795f5c9

Validate request

API paragraph not found

Request data validation

Schema validation

  1. Validate request according to JSON Schema

    • Return 422 with list of validation errors in case validation fails (422 EView).

Validate program medication

In case medications are dispensed to patient under specific medical program, program medication id must be provided provided by client or calculated by the system.

In case program medication id exists in request:

  1. Check that this program medication id relates to provided medical program and relates to provided medication

    1. In case of error - return 422 (Invalid program medication id).

Calculate program medication id if it is absent in request:

  1. Get last program_medication_id related to medical program and medication

    1. In case of error - return 422 (There are no active program medications for this program and medication).

Get legal entity from token

  1. Extract legal_entity_id (client_id) from token.

Get Party from token

  1. Extract party_user (user_id) from token.

Validate FK

  1. Validate 

legal_entity_id - legal_entity_id exists

In case error - return 422 error:

Code Block
{:error, [{%{
        description: "Legal entity not found",
        params: [],
        rule: :invalid
      }, "$.legal_entity_id"}]}

2. Validate 

medication_request_id - medication_request_id exists

Code Block
{:error, [{%{
        description: "Medication request not found",
        params: [],
        rule: :invalid
      }, "$.medication_request_id"}]}

3. Validate 

party_id - party_id exists

Code Block
{:error, [{%{
        description: "Party not found",
        params: [],
        rule: :invalid
      }, "$.party_id"}]}

4. Validate 

division_id - division_id exists

Code Block
{:error, [{%{
        description: "Division not found",
        params: [],
        rule: :invalid
      }, "$.division_id"}]}

5. Validate 

medical_program_id - medical_program_id exists

Code Block
{:error, [{%{
        description: "Medical program not found",
        params: [],
        rule: :invalid
      }, "$.medical_program_id"}]}

6. Validate all medication_id (brand_id) - brand_id exists

Code Block
{:error, [{%{
        description: "Medication not found",
        params: [],
        rule: :invalid
      }, "$.dispense_details[:index].medication_id"}]}

Validate code

  1. Check that code in request is equal to code in medication_request (or both is empty)

    1. In case code exists in request - it should match with code in medication_request

      1. Return 401 in case code doesn't match (message = "Incorrect code").

    2. In case code is missing in request - check that code in medication_request is NULL

      1. Return 401 in case code in medication_request is not NULL (message = "Missing or Invalid code").

Validate related Care plan

If (medication_request.based_on is present and not null) AND medication_program is absent:

  1. Verify Care plan:

    1. It should be in active status

      1. in case of error - return 409 (message: "Invalid care plan status").

    2. Care plan's period end (if exist) should be greater than current date or equal

      1. in case of error - return 409 (message: “Care plan expired“).

  2. Verify care plan Activity:

    1. It has scheduled, in_progress status

      1. in case of error - return 409 (message: "Invalid activity status").

Validate division

If division_id submitted:

  1. Validate division is active

    1. in case of error - return 409 ("Division is not active").

  2. Validate division belongs to user's legal entity

    1. in case of error - return 409 ("Division does not belong to user's legal entity").

  3. If chart parameter DISPENSE_DIVISION_DLS_VERIFY is on, then validate division is DLS verified (dls_verified=true)

    1. in case of error - return 409 "Division is not verified in DLS".

  4. Get license_types_allowed parameter from settings of medical program from request $.medical_program_id:

    1. if it is exists and not empty, get list of all license types from parameter.
      Check that division has active healthcare services with following parameters:

      1. legal_entity_id = client_id from access token

      2. division_id = division_id from request

      3. status = 'ACTIVE'

      4. licensed_healthcare_service.status = 'ACTIVE'

      5. healthcare_service.license_id is not null and licenses.type = value from license_types_allowed parameter

        1. in case of error - return 409 ('Division must have active licenses to dispense medication request').

Validate Medical Program

Get medical_program_change_on_dispense_allowed parameter from settings of medical program from medication request:

  • if it is false (absent), medical program in dispense must be the same as medical program in medication request (request.medical_program_id = medication_requests.medical_program_id)

    • in case of error - return 409 (`Medical program in dispense doesn't match the one in medication request`).

Qualify medication request

Important: This validation must be done only if medical_program exists in request:

  1. Check that medication request is valid and available for dispense

    1. Get medical_program_id from request of the medication dispense.

    2. Invoke Qualify method with medical_program_id.

    3. Check that program_medication_id is in Qualify response.

Medication request is prohibited for dispense in case $.data[?(@.program_id=medication_requests.medical_program_id)].status = 'INVALID' or program_medication_id is absent in qualify response:

Code Block
{
    "meta": {
        "url": "http://dev.ehealth.world/api/medication_requests/ed56699a-4a6d-427c-9b93-33a4a8d0b7b0/actions/qualify",
        "type": "list",
        "request_id": "unrbcrs34t0cinqpe8fb6nu7oem17qim",
        "code": 200
    },
    "data": [
        {
            "status": "INVALID",
            "rejection_reason": "For the patient at the same term there can be only 1 dispensed medication request per one and the same innm!",
            "program_name": "Доступні ліки",
            "program_id": "3c7d7a7f-82c2-4f5c-806e-f1f5b55164a2",
            "participants": []
        }
    ]
}

In case of error - return 409 error (message = "Medication request can not be dispensed. Invoke qualify medication request API to get detailed info").

Dispense is allowed

Medication request is allowed for dispense in case $.data[?(@.program_id=medication_requests.medical_program_id)].status = 'VALID' and program_medication_id is present in qualify response:

Code Block
{
    "meta": {
        "url": "http://dev.ehealth.world/api/medication_requests/ed56699a-4a6d-427c-9b93-33a4a8d0b7b0/actions/qualify",
        "type": "list",
        "request_id": "unrbcrs34t0cinqpe8fb6nu7oem17qim",
        "code": 200
    },
    "data": [
        {
            "status": "VALID",
            "program_name": "Доступні ліки",
            "program_id": "3c7d7a7f-82c2-4f5c-806e-f1f5b55164a2",
            "participants": []
        }
    ]
}

Validate statuses

  1. Legal entity should be active in order to dispense medication

    • is_active = true

    • status = 'ACTIVE'

    • type in pharmacy_allowed_transactions_le_types

    • mis_verified = `VERIFIED`.

  2. Medication request should be active in order to dispense medication

    • is_active = true

    • status = 'ACTIVE'

    • started_at <= current_date() and ended_at >= current_date().

  3. Party should refer to active employee in current legal_entity

    • employees.is_active = true

    • employees.status = 'APPROVED'

    • employees.legal_entity_id = client_id (context).

  4. Division should be active and refers to current legal_entity

    • is_active = true

    • status = 'ACTIVE'

    • divisions.legal_entity_id = client_id (context).

  5. Medical Program should be active in order to dispense medication under this program 

    • is_active = true.

  6. Medication (brand) medication should be active

    1. medications.is_active = true

    2. medications.type = 'BRAND'

    3. ingredients.medication_child_id = medication_request.medication_id and ingredients.is_primary = true

    4. medication_id exists in program_medications (is_active = true).

Validate Medication request is_blocked flag

  • Get Medication request by $.medication_request_id from OPS DB. Check that Medication request is not blocked (is_blocked = false or null)

    • in case of error - return 409 ("Medication request is blocked").

Validate division license

Division must have active pharmacy license in order to dispense medications

  1. Check division parameters

    1. division.dls_verified must be true

      1. otherwise - return 409 error ('Invalid division dls status').

Validate dispense period

  1. Check that dispense date is in period specified in Medication Request

    • dispense_valid_from <= current_date()

    • dispense_valid_to >= current_date().

Check other Medication Dispenses

  1. Check all connected medication dispenses

  • sum of medication_qty of all connected medication dispenses < medication_request.medication_qty

  • medictaion dispenses status in ('NEW', 'PROCESSED').

In case of error - return 403 error (message = "No more medication dispense could be done with this medication request").

Validate medication quantity

  1. Get multi_medication_dispense_allowed parameter from medical program settings:

    1. if it is true - check that requested medication quantity less or equal to medication quantity in Medication Request

      1. sum(:medication_qty) <= medication_request.medication_qty

        1. in case of error - return 422 "Dispensed medication quantity must be lower or equal to medication quantity in Medication Request. Available quantity is #{available_qty}".

    2. if it is false (absent) - check that requested medication quantity equal to medication quantity in Medication Request

      1. medication_qty = medication_request.medication_qty

        1. in case of error - return 422 "Dispensed medication quantity must be equal to medication quantity in Medication Request".

Validate medication multiplicity

  1. Check that requested medication quantity in dispense for all medications is multiplier of package_min_qty for this medications.id

    •  Mod($medication_qty, medications.package_min_qty) = 0

In case of error (if at least one of medication don't pass verification) - return 422 error:

Code Block
{:error, [{%{
        description: "Requested medication brand quantity is not a multiplier of package minimal quantity",
        params: [],
        rule: :invalid
      }, "$.dispense_details[:index].medication_qty"}]}

Validate medication discount amount

  1. Define reimbursement_type (get from program_medications by program_medication_id).

  2. Validate percentage discount price.
    Check if reimbursement_type == percentage and percentage_reimbursement_amount = 0
    (the way how to calculate percentage_reimbursement_amount is following:
    percentage_reimbursement_amount = sell_price (from request) * percentage_discount (from program_medications) /100)

    • In case if discount_amount != 0 - return 422 ("Requested discount price must be equal to 0")

    • Else (if discount_amount = 0)  - finish validation (do not validate 3, 4).

  3. Validate allowed reimbursement amount.
    Check that requested discount price is less or equal to allowed reimbursement amount for the requested medication quantity
    (the way how to calculate allowed reimbursement amount is below.
    for type == percentage use percentage_reimbursement_amount, for fixed = use reimbusement_amount from program_medications):
           discount_amount <= reimbursement_amount * (medication_qty/package_qty)

    • In case of error - return 422 ("Requested discount price must be less or equal to allowed reimbursement amount").

  4. Validate the ratio of discount price to reimbursement amount.
    Check that the ratio of requested discount price to allowed reimbursement amount is more or equal to allowed rule (including deviation) for the requested medication quantity
    (the way how to calculate allowed reimbursement amount is below.
    for type = percentage use percentage_reimbursement_amount, for fixed - use reimbusement_amount from program_medications):
           discount_amount/ (reimbursement_amount * (medication_qty/package_qty)) >= 1 - deviation

    • In case of error - return 422 ("The ratio of requested discount price to allowed reimbursement amount must be greater or equal to <1 - deviation>").

Validate 2d codes

Important: This validation must be done only if medication_2d_codes field exists in request.

  • Check that medication_2d_codes array contains at least one element (array is not empty)

    • in case of error - return 422 ('Expected a minimum of %{min} items but got %{actual}').

  • For all objects in array check that string 'medication_2d_code' is not null or empty

    • in case of error - return 422 ('Not allowed to save empty 2d code').

Get reimbursement amount

There are two types of calculation of reimbursement amount:

  • FIXED - reimbursement rate defined here for package_qty without any calculations 

  • EXTERNAL - reimbursement rate or amount should be calculated via API external call

Important: Only FIXED type is allowed during first phase

  1. Get reimbursement amount for this medication_id according to medical_program_id

    1. Determine calculation channel (FIXED, EXTERNAL)/

    2. Calculate reimbursement amount for the requested quantity of medications:

      1. Get the reimbursement_amount from program_medications.reimbursement.reimbursement_amount (for the package).

      2. Based on it,  package_min_qty and requested medication_qty calculate the ratio and allowed reimbursement amount ((reimbursement_amount/package_qty)*medication_qt.

Parameters that are used when processing the request

Configuration parameters

Access to the method is defined by the scope medication_dispense:write. Permission for this scope is determined by the System administrator by configuring scopes in the context of clients and roles.

Dictionaries

API paragraph not found

Processing

  1. Get skip_medication_dispense_sign from medical program settings.

  2. If skip_medication_dispense_sign = false or absent:

          2.1. Check payment_id, payment_amount is absent in the request.

  • in case if present - return 422 with path: $.<field_name>  and message "schema does not allow additional properties"

          2.2. Add record to medication_dispenses table:

Parameter

Source

Description

id

UUID

Autogenerated

payment_id

NULL

NULL for new records

payment_amount

NULL

NULL for new records.

status

Const: NEW

NEW skip_medication_dispense_sign = false

See: Status Charts (Reimbursement)

is_active

Const: TRUE

Alwayls TRUE for new records

inserted_at

Timestamp: now()

Get current date-time

inserted_by

Token: user_id

Extract user from token

updated_at

Timestamp: now()

Get current date-time

updated_by

Token: user_id

Extract user from token

          2.3. Add records to medication_dispense_details table:

Parameter

Source

Description

id

UUID

Autogenerated

medication_dispense_id

FK: medication_dispense

reimbursement_amount

Reimbursement

          2.4. Add records to medication_2d_codes table (for each 2d code object in array):

Parameter

Source

Description

id

UUID

Autogenerated

medication_dispense_id

FK: medication_dispense

medication_2d_code

Request: medication_2d_codes

inserted_at

Timestamp: now()

Get current date-time

  1. If skip_medication_dispense_sign = true:

             3.1. Check if payment_amount in the request

  • in case is absent - return 422 with path: $.payment_amount and message "required property payment_amount was not present"

             3.2. Call Process Medication Dispense process, but without validation of the previously created (NEW) medication dispense, digital sign and storage signed content to the bucket.

             3.3. Add records as described on steps 2.2-2.4, but with following differences: 

             medication_dispenses table:

Parameter

Source

Description

payment_id

Request: payment_id

optional parameter

payment_amount

Request: payment_amount

required parameter

status

Const: PROCESSED

PROCESSED skip_medication_dispense_sign = true
See: Status Charts (reimbursement)

Response structure

Example:

Expand
titleResponse example
Code Block
{
  "meta": {
    "code": 201,
    "url": "https://example.com/resource",
    "type": "object",
    "request_id": "req-adasdoijasdojsda"
  },
  "data": {
    "id": "b075f148-7f93-4fc2-b2ec-2d81b19a9b7b",
    "medication_request": {
      "id": "b075f148-7f93-4fc2-b2ec-2d81b19a9b7b",
      "status": "ACTIVE",
      "request_number": "0000-243P-1X53-EH38",
      "created_at": "2017-08-17",
      "started_at": "2017-08-17",
      "ended_at": "2017-09-16",
      "dispense_valid_from": "2017-08-17",
      "dispense_valid_to": "2017-09-16",
      "legal_entity": {
        "id": "b075f148-7f93-4fc2-b2ec-2d81b19a9b7b",
        "name": "Клініка Ноунейм",
        "short_name": "Ноунейм",
        "public_name": "Клініка Ноунейм",
        "type": "MSP",
        "edrpou": "5432345432",
        "status": "ACTIVE"
      },
      "division": {
        "id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
        "legal_entity_id": "c8aadb87-ecb9-41ca-9ad4-ffdfe1dd89c9",
        "name": "Бориспільське відділення Клініки Ноунейм",
        "addresses": [
          {
            "type": "RESIDENCE",
            "country": "UA",
            "area": "Житомирська",
            "region": "Бердичівський",
            "settlement": "Київ",
            "settlement_type": "CITY",
            "settlement_id": "b075f148",
            "street_type": "STREET",
            "street": "вул. Ніжинська",
            "building": "15",
            "apartment": "23",
            "zip": "02090"
          }
        ],
        "phones": [
          {
            "type": "MOBILE",
            "number": "+380503410870"
          }
        ],
        "email": "email@example.com",
        "working_hours": {
          "mon": [
            [
              "08.00",
              "12.00"
            ],
            [
              "14.00",
              "18.00"
            ]
          ],
          "tue": [
            [
              "08.00",
              "12.00"
            ]
          ],
          "wed": [
            [
              "08.00",
              "12.00"
            ]
          ],
          "thu": [
            [
              "08.00",
              "12.00"
            ]
          ],
          "fri": [
            [
              "08.00",
              "12.00"
            ]
          ]
        },
        "type": "CLINIC",
        "external_id": "3213213",
        "location": {
          "latitude": 30.1233,
          "longitude": 50.32423
        },
        "dls_id": "2872985",
        "dls_verified": true
      },
      "employee": {
        "id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
        "position": "P6",
        "party": {
          "id": "b075f148-7f93-4fc2-b2ec-2d81b19a9b7b",
          "no_tax_id": true,
          "first_name": "Петро",
          "last_name": "Іванов",
          "second_name": "Миколайович",
          "email": "email@example.com",
          "phones": [
            {
              "type": "MOBILE",
              "number": "+380503410870"
            }
          ]
        }
      },
      "person": {
        "id": "b075f148-7f93-4fc2-b2ec-2d81b19a9b7b",
        "short_name": "Петро І. І.",
        "age": 35
      },
      "medication_info": {
        "medication_id": "4a63b858-c138-4921-9341-ae9e384bcbd6",
        "medication_name": "Аміодарон 200мг таблетки",
        "form": "PILL",
        "dosage": {
          "numerator_unit": "MG",
          "numerator_value": 200,
          "denumerator_unit": "PILL",
          "denumerator_value": 1
        },
        "ingredients": [
          {
            "id": "1349a693-4db1-4a3f-9ac6-8c2f9e541982",
            "name": "Інсулін деглюдек",
            "name_original": "Insulin degludec",
            "sctid": "52574003",
            "dosage": {
              "numerator_unit": "MG",
              "numerator_value": 200,
              "denumerator_unit": "PILL",
              "denumerator_value": 1
            },
            "is_primary": true
          }
        ],
        "medication_qty": 10.34
      },
      "medical_program": {
        "id": "c7d52544-0bd4-4129-97b0-2d72633e0490",
        "name": "Доступні ліки",
        "medical_program_settings": {
          "care_plan_required": true,
          "employee_types_to_create_medication_request": [
            "SPECIALIST",
            "DOCTOR"
          ],
          "skip_mnn_in_treatment_period": true,
          "skip_employee_validation": true,
          "speciality_types_allowed": [
            "ENDOCRINOLOGY",
            "PEDIATRIC_NEUROLOGY"
          ],
          "conditions_icd10_am_allowed": [
            "A00.0",
            "A00.1"
          ],
          "conditions_icpc2_allowed": [
            "A01",
            "A02"
          ],
          "providing_conditions_allowed": [
            "INPATIENT",
            "OUTPATIENT"
          ],
          "medication_request_max_period_day": 90,
          "skip_medication_request_employee_declaration_verify": true,
          "skip_medication_request_legal_entity_declaration_verify": true,
          "multi_medication_dispense_allowed": true,
          "skip_medication_dispense_sign": true,
          "medication_request_notification_disabled": true,
          "skip_contract_provision_verify": true,
          "medication_dispense_period_day": 90
        },
        "medical_program_settings_text": "Some text",
        "is_active": true,
        "medication_dispense_allowed": true,
        "medication_dispense_allowed_text": "Some text",
        "medication_request_allowed": true,
        "medication_request_allowed_text": "Some text",
        "type": "MEDICATION",
        "funding_source": "NHS",
        "mr_blank_type": "F-1",
        "inserted_at": "2017-04-20T19:14:13Z",
        "inserted_by": "e1453f4c-1077-4e85-8c98-c13ffca0063e",
        "updated_at": "2017-04-20T19:14:13Z",
        "updated_by": "2922a240-63db-404e-b730-09222bfeb2dd"
      },
      "intent": "plan",
      "category": "community",
      "based_on": [
        {
          "identifier": {
            "type": {
              "coding": [
                {
                  "system": "eHealth/resources",
                  "code": "care_plan"
                }
              ]
            },
            "value": "9183a36b-4d45-4244-9339-63d81cd08d9c"
          }
        },
        {
          "identifier": {
            "type": {
              "coding": [
                {
                  "system": "eHealth/resources",
                  "code": "activity"
                }
              ]
            },
            "value": "9183a36b-4d45-4244-9339-63d81cd08d9c"
          }
        }
      ],
      "context": {
        "identifier": {
          "type": {
            "coding": [
              {
                "system": "eHealth/resources",
                "code": "encounter"
              }
            ]
          },
          "value": "9183a36b-4d45-4244-9339-63d81cd08d9c"
        }
      },
      "dosage_instruction": [
        {
          "sequence": 1,
          "text": "0.25mg PO every 6-12 hours as needed for menses from Jan 15-20, 2015.  Do not exceed more than 4mg per day",
          "additional_instruction": [
            {
              "coding": [
                {
                  "system": "eHealth/SNOMED/additional_dosage_instructions",
                  "code": "311504000"
                }
              ]
            }
          ],
          "patient_instruction": "0.25mg PO every 6-12 hours as needed for menses from Jan 15-20, 2015.  Do not exceed more than 4mg per day",
          "timing": {
            "event": [
              "2017-04-20T19:14:13Z"
            ],
            "repeat": {
              "bounds_duration": {
                "value": 10,
                "unit": "days",
                "system": "eHealth/ucum/units",
                "code": "d"
              },
              "count": 2,
              "count_max": 4,
              "duration": 4,
              "duration_max": 6,
              "duration_unit": "d",
              "frequency": 1,
              "frequency_max": 2,
              "period": 4,
              "period_max": 6,
              "period_unit": "d",
              "day_of_week": [
                "mon"
              ],
              "time_of_day": [
                "2017-04-20T19:14:13Z"
              ],
              "when": [
                "WAKE"
              ],
              "offset": 4
            },
            "code": {
              "coding": [
                {
                  "system": "TIMING_ABBREVIATIONS",
                  "code": "patient"
                }
              ]
            }
          },
          "as_needed_boolean": true,
          "site": {
            "coding": [
              {
                "system": "eHealth/SNOMED/anatomical_structure_administration_site_codes",
                "code": "344001"
              }
            ]
          },
          "route": {
            "coding": [
              {
                "system": "eHealth/SNOMED/route_codes",
                "code": "46713006"
              }
            ]
          },
          "method": {
            "coding": [
              {
                "system": "eHealth/SNOMED/administration_methods",
                "code": "419747000"
              }
            ]
          },
          "dose_and_rate": {
            "type": {
              "coding": [
                {
                  "system": "eHealth/dose_and_rate",
                  "code": "'ordered'"
                }
              ]
            },
            "dose_range": {
              "low": {
                "value": 0,
                "unit": "mg",
                "system": "eHealth/ucum/units",
                "code": "mg"
              },
              "high": {
                "value": 0,
                "unit": "mg",
                "system": "eHealth/ucum/units",
                "code": "mg"
              }
            },
            "rate_ratio": {
              "numerator": {
                "value": 0,
                "unit": "mg",
                "system": "eHealth/ucum/units",
                "code": "mg"
              },
              "denominator": {
                "value": 0,
                "unit": "mg",
                "system": "eHealth/ucum/units",
                "code": "mg"
              }
            }
          },
          "max_dose_per_period": {
            "numerator": {
              "value": 0,
              "unit": "mg",
              "system": "eHealth/ucum/units",
              "code": "mg"
            },
            "denominator": {
              "value": 0,
              "unit": "mg",
              "system": "eHealth/ucum/units",
              "code": "mg"
            }
          },
          "max_dose_per_administration": {
            "value": 0,
            "unit": "mg",
            "system": "eHealth/ucum/units",
            "code": "mg"
          },
          "max_dose_per_lifetime": {
            "value": 0,
            "unit": "mg",
            "system": "eHealth/ucum/units",
            "code": "mg"
          }
        }
      ],
      "rejected_at": "2022-01-28",
      "rejected_by": "e8e5a969-74d8-4620-8496-f5e41f2e8312",
      "reject_reason": "Incompatible drugs",
      "reject_reason_code": "PATIENT_REJECT",
      "is_blocked": false,
      "block_reason": "Підозра на фрод",
      "block_reason_code": "WRONG_QTY_DRUG",
      "priority": "routine",
      "prior_prescription": {
        "identifier": {
          "type": {
            "coding": [
              {
                "system": "eHealth/resources",
                "code": "medication_request"
              }
            ]
          },
          "value": "9183a36b-4d45-4244-9339-63d81cd08d9c"
        }
      },
      "container_dosage": {
        "system": "MEDICATION_UNIT",
        
params
"code": 
[]
"ML",
        
rule
"value": 
:invalid
4
      }
, "$.dispense_details[:index].medication_id"}]}

Validate code

  1. Check that code in request is equal to code in medication_request (or both is empty)
    1. In case code exists in request - it should match with code in medication_request
      1. Return 401 in case code doesn't match (message = "Incorrect code")
    2. In case code is missing in request - check that code in medication_request is NULL
      1. Return 401 in case code in medication_request is not NULL (message = "Missing or Invalid code")

Qualify medication request

Important: This validation must be done only if medical_program exists in request

  1. Check that medication request is valid and available for dispense
    1. Invoke Qualify method
    2. Use medication_requests.medical_program_id as program for qualify
    3. Check that program_medication_id is in Qualify response

Dispense prohibited

Medication request is prohibited for dispense in case $.data[?(@.program_id=medication_requests.medical_program_id)].status = 'INVALID' or program_medication_id is absent in qualify response

Code Block
languageerl
{ "meta": { "url": "http://dev.ehealth.world/api/medication_requests/ed56699a-4a6d-427c-9b93-33a4a8d0b7b0/actions/qualify",

    },
    "dispensed_at": "2017-08-17",
    "dispensed_by": "Іванов Іван Іванович",
    "party": {
      "id": "b075f148-7f93-4fc2-b2ec-2d81b19a9b7b",
      "first_name": "Петро",
      "last_name": "Іванов",
      "second_name": "Миколайович"
    },
    "legal_entity": {
      "id": "b075f148-7f93-4fc2-b2ec-2d81b19a9b7b",
      "name": "Клініка Ноунейм",
      "short_name": "Ноунейм",
      "public_name": "Клініка Ноунейм",
      "type": "MSP",
      "edrpou": "5432345432",
      "status": "ACTIVE"
    },
    "division": {
      "id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
      "name": "Бориспільське відділення Клініки Ноунейм",
      "legal_entity_id": "d290f1ee",
      "type": "CLINIC",
      "
type
status": "
list
ACTIVE",
      "mountain_group": false,
      "
request
dls_id": "
unrbcrs34t0cinqpe8fb6nu7oem17qim
2872985",

      "
code
dls_verified": 
200
true
    },
    "
data
medical_program": {
[
      "id": "c7d52544-0bd4-4129-97b0-2d72633e0490",
  
{
    "name": "Доступні ліки",
      "
status
medical_program_settings": 
"INVALID",
{
        "care_plan_required": true,
        
"rejection_reason
"employee_types_to_create_medication_request": 
"For
[
  
the
 
patient
 
at
 
the
 
same
 
term
 
there
 
can
 
be
"SPECIALIST",
only
 
1
 
dispensed
 
medication
 
request
 
per
 
one
 
and
 
the
 
same
 
innm!",
"DOCTOR"
        ],
       
"program_name
 "skip_mnn_in_treatment_period": 
"Доступні ліки",
true,
        
"
program
skip_employee_
id
validation": 
"3c7d7a7f-82c2-4f5c-806e-f1f5b55164a2",
true,
        
"
participants
speciality_types_allowed": [
]

          
}
"ENDOCRINOLOGY",
    
]
 
}

In case of error - return 409 error (message = "Medication request can not be dispensed. Invoke qualify medication request API to get detailed info")

Dispense is allowed

Medication request is allowed for dispense in case $.data[?(@.program_id=medication_requests.medical_program_id)].status = 'VALID' and program_medication_id is present in qualify response

Code Block
languageerl
{
     "
meta
PEDIATRIC_NEUROLOGY"
:

{
        
"url": "http://dev.ehealth.world/api/medication_requests/ed56699a-4a6d-427c-9b93-33a4a8d0b7b0/actions/qualify"
],
        "
type
conditions_icd10_am_allowed": 
"list",
[
         
"request_id":
 "
unrbcrs34t0cinqpe8fb6nu7oem17qim
A00.0",
          "
code": 200
A00.1"
        
}
],
    
"data
    "conditions_icpc2_allowed": [
        
{
  "A01",
          "
status": "VALID",
A02"
        ],
        "
program
providing_conditions_
name
allowed": 
"Доступні
[
ліки",
          
"program_id": "3c7d7a7f-82c2-4f5c-806e-f1f5b55164a2"
"INPATIENT",
          "OUTPATIENT"
 
"participants":
 
[]
      ],
  
}
     
] }

Validate statuses

  1. Legal entity should be active in order to dispense medication
    • is_active = true
    • status = 'ACTIVE'
    • type in pharmacy_allowed_transactions_le_types
    • mis_verified = `VERIFIED`
  2. Medication request should be active in order to dispense medication
    • is_active = true
    • status = 'ACTIVE'
    • started_at <= current_date() and ended_at >= current_date()
  3. Party should refer to active employee in current legal_entity
    • employees.is_active = true
    • employees.status = 'APPROVED'
    • employees.legal_entity_id = client_id (context)
  4. Division should be active and refers to current legal_entity
    • is_active = true
    • status = 'ACTIVE'
    • divisions.legal_entity_id = client_id (context)
  5. Medical Program should be active in order to dispense medication under this program and the same as medical program in medication request
    • is_active = true
    • request.medical_program_id = medication_requests.medical_program_id
      • in case of error return 409 Error (`Medical program in dispense doesn't match the one in medication request`)
  6. Medication (brand) medication should be active
    1. medications.is_active = true
    2. medications.type = 'BRAND'
    3. ingredients.medication_child_id = medication_request.medication_id and ingredients.is_primary = true
    4. medication_id exists in program_medications (is_active = true)

Validate division license

Division must have active pharmacy license in order to dispense medications

  1. Check division parameters
    1. division.dls_verified must be true
      1. otherwise - return 409 error ('Invalid division dls status')

Validate dispense period

  1. Check that dispense date is in period specified in Medication Request
    • dispense_valid_from <= current_date()
    • dispense_valid_to >= current_date()

Check other Medication Dispenses

1. Check all connected medication dispenses

  • sum of medication_qty of all connected medication dispenses <= medication_request.medication_qty
  • medication dispenses status in ('NEW', 'PROCESSED')

In case of error - return 403 error (message = "No more medication dispense could be done with this medication request")

Validate medication quantity

  1. Check that requested medication quantity less or equal to medication quantity in Medication Request
    • sum(:medication_qty) <= medication_request.medication_qty

Validate medication multiplicity

  1. Check that requested medication quantity in dispense for all medications is multiplier of package_min_qty for this medications.id
    •  Mod($medication_qty, medications.package_min_qty) = 0

In case of error (if at least one of medication don't pass verification) - return 422 error

Code Block
languageerl
{:error, [{%{ description: "Requested medication brand quantity is not a multiplier of package minimal quantity",
 "medication_request_max_period_day": 90,
        "skip_medication_request_employee_declaration_verify": true,
        "skip_medication_request_legal_entity_declaration_verify": true,
        "multi_medication_dispense_allowed": true,
        "skip_medication_dispense_sign": true,
        "medication_request_notification_disabled": true,
        "skip_contract_provision_verify": true,
        "medication_dispense_period_day": 90
      },
      "medical_program_settings_text": "Some text",
      "is_active": true,
      "medication_dispense_allowed": true,
      "medication_dispense_allowed_text": "Some text",
      "medication_request_allowed": true,
      "medication_request_allowed_text": "Some text",
      "type": "MEDICATION",
      "funding_source": "NHS",
      "mr_blank_type": "F-1",
      "inserted_at": "2017-04-20T19:14:13Z",
      "inserted_by": "e1453f4c-1077-4e85-8c98-c13ffca0063e",
      "updated_at": "2017-04-20T19:14:13Z",
      "updated_by": "2922a240-63db-404e-b730-09222bfeb2dd"
    },
    "details": [
      {
        
params
"medication": 
[],
{
          
rule
"name": 
:invalid
"Амідарон",
         
},
 "
$.dispense_details[:index].medication_qty"}]}

Validate medication discount amount

Note: There are two different validation rules depending on medication package quantity and min quantity

If min quantity is equal to package quantity - there shouldn't be any tolerance during calculation. 

Validation 1: Min package quantity is equal to package quantity

  1. Check that requested discount price is equal to allowed reimbursement amount for the requested medication quantity (the way how to calculate allowed reimbursement amount is below)
  • discount_amount = reimbursement_amount * (medication_qty/package_qty)

Validation 2: Min package quantity is not equal to package quantity

  1. Check that requested discount price less or equal to allowed reimbursement amount (including deviation) for the requested medication quantity (the way how to calculate allowed reimbursement amount is below)
  • 1 > = discount_amount/ (((reimbursement_amount/package_qty)*medication_qty)) >= 1 - deviation

In case of error - return 422 error

Code Block
languageerl
{:error, [{%{
type": "MEDICATION",
          "manufacturer": {
            "name": "ПАТ \"Київський вітамінний завод\"",
            
description
"country": "
Requested discount price doesn't not satisfy allowed reimbursement amount",
UA"
          },
          "form": "PILL",
          
params: [],
"container": {
            "numerator_unit": "PILL",
  
rule:
  
:invalid
       
},
 "
$.dispense_details[:index].discount_amount"}]}

Medication dispense in a multi attempts

Validate medication multiplicity

  1. Check that requested medication quantity in dispense for all medications is multiplier of package_min_qty for this medications.id
    •  Mod($medication_qty, medications.package_min_qty) = 0

In case of error - return 422 error

Code Block
languageerl
{:error, [{%{
numerator_value": 1,
            
description
"denumerator_unit": "
Requested
PILL",
  
medication
 
brand
 
quantity
 
is
 
not
 
a
 
multiplier
 
of
 
package
 
minimal
 
quantity"
"denumerator_value": 1
          },
        
params: []
  "form_pharm": "DISPERSIBLE_TABLET"
        },
        
rule: :invalid
"program_medication_id": "64c06ebc-0266-4645-85f0-7a6900d7dfbe",
       
},
 
"$.dispense_details[:index].medication_qty
"
}]}

Note: The medication_qty with each attempt can be divided only by an integer.

Validate medication quantity

  1. Check that medication_qty on medication dispense should not exceed the sum of medication_qty already dispensed under this medication request.
    • Find existing medication dispenses by its medication_request_id
    • Count the amount of medication_qty dispensed for this medication request
      1. $.medication_dispense.medication_request_id = $.medication_request.id
      2. $.medication_dispense.status = PROCESSED
      3. $.medication_dispense.medication_qty <= sumpreviously processed(medication_dispense_details.medication_qty)

In case of error - return 422 error

Add records to medication_dispense_details

...

Code Block
languageerl
{:error, [{%{ description: "No more medication dispense could be done with this medication request
medication_qty": 0,
        "sell_price": 18.65,
        "sell_amount": 186.5,
        "discount_amount": 150,
        "reimbursement_amount": 450,
        "medication_2d_codes": [
          {
            "medication_2d_code": "0104820005161713171812001022431115 211XV82HPV"
          }
        ]
      }
    ],
    "payment_id": "1239804",
    "payment_amount": 50,
    "status": "NEW",
    "inserted_at": "2017-04-20T19:14:13Z",
    "inserted_by": "e1453f4c-1077-4e85-8c98-c13ffca0063e",
  
params: []
  "updated_at": "2017-04-20T19:14:13Z",
    
rule: :invalid
"updated_by": "2922a240-63db-404e-b730-09222bfeb2dd"
  
}
,

"$.dispense_details[:index].medication_qty"}]
}

...

There are two types of calculation of reimbursement amount:

  • FIXED - reimbursement rate defined here for package_qty without any calculations 
  • EXTERNAL - reimbursement rate or amount should be calculated via API external call

Important: Only FIXED type is allowed during first phase

  1. Get reimbursement amount for this medication_id according to medical_program_id
    1. Determine calculation channel (FIXED, EXTERNAL)
    2. Calculate reimbursement amount for the requested quantity of medications:
      1. Get the reimbursement_amount from program_medications.reimbursement.reimbursement_amount (for the package)
      2. Based on it,  package_min_qty and requested medication_qty calculate the ratio and allowed reimbursement amount ((reimbursement_amount/package_qty)*medication_qty)

Create new entities

Add record to medication_dispenses

...

Always NEW for new records

See: Status Charts (reimbursement)

...

Post-processing processes

No

HTTP status codes

HTTP status code

Message

What caused the error

201

Response

 

401

  • Invalid access token

  • Incorrect code

  • Missing or Invalid code

  • Access token validation failed

  • Code doesn't match

  • Code in medication_request is not NULL

403

  • Invalid scope

  • No more medication dispense could be done with this medication request

409

  • Program cannot be used - no active contract exists

  • Invalid care plan status

  • Care plan expired

  • Invalid activity status

  • Division is not active

  • Division does not belong to user's legal entity

  • Division is not verified in DLS

  • Division must have active licenses to dispense medication request

  • Medication request can not be dispensed. Invoke qualify medication request API to get detailed info

  • Medical program in dispense doesn't match the one in medication request

  • Medication request is blocked

  • Invalid division dls status

422

  • Invalid program medication id

  • There are no active program medications for this program and medication

  • Legal entity not found

  • Dispensed medication quantity must be lower or equal to medication quantity in Medication Request. Available quantity is #{available_qty}

  • Requested medication brand quantity is not a multiplier of package minimal quantity

  • Requested discount price must be less or equal to allowed reimbursement amount

  • Dispensed medication quantity must be equal to medication quantity in Medication Request

  • Requested discount price must be equal to 0

  • The ratio of requested discount price to allowed reimbursement amount must be greater or equal to <1 - deviation>

  • Expected a minimum of %{min} items but got %{actual}

  • Not allowed to save empty 2d code

  • schema does not allow additional properties

  • required property payment_amount was not present

Backward compatibility

API paragraph not found