ЕСОЗ - публічна документація

RC_CSI-2483_PreQualify Medication request request

Purpose

This WS is designed to Pre-qualify data of Medication request Request (post) - check whether it's possible to use Medication request within the particular Medical program.

There are two types of medication request:

  • plan - The request represents an intention to ensure something occurs without providing an authorization for others to act. Medication request with type plan can't be dispensed and only provide the instruction to administer the medicine. It also can't be qualified

  • order - The request represents a request/demand and authorization for action. Medication request with type order can be dispensed

Specification

Apiary

Key points

  1. Only authenticated and authorized users with appropriate scope can invoke Prequalify Medication Request Request (MRR)

  2. This method simply returns the result of data validation within each submitted medical program, but not creates any entities in the system.

  3. Each Medical program may have its unique conditions for the medication dispense. It can be based on analysis of personal info, medications list, terms, locations and combinations of them.

  4. Any Medical program can have separate block of branching logic configured at medical program settings by NHS administrator.

  5. Сompatibility is checked only for programs which are available in payload (array).

  6. Successful invocation of the method returns decision for each program if it is valid or not to create Medication Request with submitted combination of parameters in the payload. If program status is invalid, the reason must be saved and returned in response.

Authorize

  1. Verify the validity of access token

    • in case of error - return 401 (“Invalid access token”) in case of validation fails

  2. Verify that token is not expired

    • in case of error - return 401 (“Invalid access token”)

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

    • return 403 (“Your scope does not allow to access this resource. Missing allowances: medication_request_request:write”) in case of invalid scope(s)

Validations

Validate container_dosage field

$.container_dosage - volume of a medication’s primary container, which is requested by a doctor or issuer of a medication request, to be dispensed to patient.

  1. Validate $.container_dosage field by schemata

    1. $.container_dosage.code and $.container_dosage.value should be both filled

      1. in case of error return 422 error ("required property %{property} was not present")

    2. $.container_dosage.system should be “MEDICATION_UNIT”

      1. in case of error return 422 error ("value is not allowed in enum")

Validate priority

  1. Check by schemata if $.priority is filled with the value of MEDICATION_REQUEST_PRIORITY dictionary

    1. in case of error return 422 error ("value is not allowed in enum")

Validate prior_prescription

  1. Check that $.prior_prescription is UUID, exists and belongs to this person:

    1. is_active = true, and the same person. 

      1. in case of error - return 422 (message: "Prior prescription is not found")

Validate medication request type

Only medication request with type (intent) order can be qualified.

  1. Check medication request intent is order

    1. in case intent == plan - return 409, "Plan can't be qualified"

Validate division

Validate it is exists and active, relates to current legal entity (client_id from token)

  • in case of error - return 422 error “Only employee of active divisions can create medication request!“

Validate dates:

  1. Check ended_at >= started_at

    1. in case of error - return 422 error “The end date should be equal to or greater than the start date.“

  2. Check started_at >= created_at, but not greater than (created_at + MEDICATION_REQUEST_REQUEST_EXTENDED_LIMIT_STARTED_AT_DAYS)

    1. in case of error - return 422 “The start date should be equal to or greater than the creation date, but the difference between them should be not exceed {{MEDICATION_REQUEST_REQUEST_EXTENDED_LIMIT_STARTED_AT_DAYS}} day(s).”

  3. Check started_at >= current date

    1. in case of error - return 422 “Started date must be >= Current date!”

  4. Check created_at >= (current date - MEDICATION_REQUEST_REQUEST_DELAY_INPUT)

    1. in case of error - return 422 “Create date must be >= Current date - MRR delay input!”

Validate dosage instructions

If dossage_instructions array submitted, each non-empty attribute must be valid and reference to appropriate dictionary or object

  1. Sequence must be unique within dosage instruction array

    1. in case of error  return (422, "Sequence must be unique")

  2. Additional instruction must refer to a valid dictionary

    1. $.dosage_instruction[*].additional_instruction.coding[*].system == "eHealth/SNOMED/additional_dosage_instructions"

    2. $.dosage_instruction[*].additional_instruction.coding[*].code is a valid entry in dictionary "eHealth/SNOMED/additional_dosage_instructions"

      1. in case of error return 409 "Incorrect additional instruction"

  3. Site must refer to a valid dictionary

    1. $.dosage_instruction[*].site.coding[*].system == "eHealth/SNOMED/anatomical_structure_administration_site_codes"

    2. $.dosage_instruction[*].site.coding[*].code is a valid entry in dictionary "eHealth/SNOMED/anatomical_structure_administration_site_codes"

      1. in case of error return 409 "Incorrect site"

  4. Route must refer to a valid dictionary

    1. $.dosage_instruction[*].route.coding[*].system == "eHealth/SNOMED/route_codes"

    2. $.dosage_instruction[*].route.coding[*].code is a valid entry in dictionary "eHealth/SNOMED/route_codes"

      1. in case of error return 409 "Incorrect route"

  5. Method must refer to a valid dictionary

    1. $.dosage_instruction[*].method.coding[*].system == "eHealth/SNOMED/administration_methods"

    2. $.dosage_instruction[*].method.coding[*].code is a valid entry in dictionary "eHealth/SNOMED/administration_methods"

      1. in case of error return 409 "Incorrect method"

  6. Dose and rate type must refer to a valid dictionary

    1. $.dosage_instruction[*].dose_and_rate.type.coding[*].system == "eHealth/SNOMED/dose_and_rate"

    2. $.dosage_instruction[*].dose_and_rate.type.coding[*].code is a valid entry in dictionary "eHealth/SNOMED/dose_and_rate"

      1. in case of error return 409 "Incorrect dose and rate type"

Validate compliance for programs

Some checks (below in the text) must be passed for the programs

  1. if passed - save the response by this program - status = VALID

  2. if not passed - save response by this program - status = INVALID

Check each medical program in the array is:

  1. is exists

    1. in case of error - return status = INVALID and reject reason = “Medical program not found”

  2. is_active = true

    1. in case of error - return status = INVALID and reject reason = “Medical program is not active”

1. Check INNM complience for the programs

There is a list of medications (BRANDs, which links to Innms)  which can be used for the program. It must be check whether there is at least one available medication (with `medication_request_allowed` == TRUE)  for the Innm for the particular program 

  1. Check compatibility of innm with medication list for the program

    1. if data is not found:

      1. add to response: status = INVALID

      2. add to response: rejection_reason = "Not found any medications allowed for create medication request for this medical program!"

SELECT m0.id, m2.id, m2.package_qty, m2.package_min_qty, m3.id, m3.name FROM medications AS m0 INNER JOIN ingredients AS i1 ON i1.medication_child_id = {$.medication_id} INNER JOIN medications AS m2 ON i1.parent_id = m2.id INNER JOIN medical_programs AS m3 ON m3.id = {$.medical_program_id} INNER JOIN program_medications AS p4 ON (m3.id = p4.medical_program_id) AND (p4.medication_id = m2.id) WHERE (i1.is_primary = TRUE) AND (m0.id = {$.medication_id}) AND (m0.type = 'INNM_DOSAGE') AND (m0.is_active = TRUE) AND (m2.is_active = TRUE) AND (m3.medication_request_allowed = TRUE) AND (p4.is_active = TRUE) AND (p4.medication_request_allowed = TRUE)
  1. Check if there is at list one record of Brand with requested primary container volume

a. if not exist - return 422 error (message: "Not found any appropriate medication with such container parameters")

  1. Check if there is at list one record medication_qty <= max_request_dosage or (max_request_dosage is null)
    a. if not exist - return 422 error (message: "Not found any appropriate medication complying with max_request_dosage limit")

  2. Check max allowed quantity for the treatment period:

  • Get non-null max_daily_dosage from all filtered above program medications

  • Define max value among max_daily_dosage as highest_max_daily_dosage

  • Get package_min_qty (or package_qty if PRM.program_medications.package_qty_divisible == false) from all related brands, connected to found program medications

  • Define min value among package_min_qty as lowest_package_min_qty (or lowest_package_qty if PRM.program_medications.package_qty_divisible == false)

a. Validate that remainder of the division: (highest_max_daily_dosage × (ended_at - started_at+1)) / one of package_min_qty is equal to 0

i. if true - check medication_qty <= (highest_max_daily_dosage × (ended_at - started_at+1))

  1. if case of error - return 422 “The amount of medications in medication request is greater than available maximum for the max_daily_dosage and treatment period limit” 

b. Validate: (medication_qty - (highest_max_daily_dosage × (ended_at - started_at+1))) < lowest_package_min_qty (or lowest_package_qty if PRM.program_medications.package_qty_divisible == false)

i. in case of error - return 422 “The amount of medications in medication request is not complying with max_daily_dosage and treatment period limit”

  1. Check compliance of medication quantity:

    1. if PRM.program_medications.package_qty_divisible == true:

      1. remainder of the division (medication_qty/package_min_qty) is equal to 0

        1. in case it is not equal to zero - return 422 “The amount of medications in medication request must be divisible to package minimum quantity“

    2. else:

      1. remainder of the division (medication_qty/package_qty) is equal to 0

        1. in case it is not equal to zero - return 422 “The amount of medications in medication request must be divisible to package quantity“

2. Check absence the same medications for the programs

It can be only 1 Medication request (ACTIVE, COMPLETED)  per one innm for the one patient at defined period of time.

Example validation: without crossing time

EP

 Preconditions # 1

Result validate #1 

 Preconditions #2

Result validate #2 

 Preconditions #3

Result validate #2 

EP

 Preconditions # 1

Result validate #1 

 Preconditions #2

Result validate #2 

 Preconditions #3

Result validate #2 

PreQualifyMedicationRequestRequest

No records in MedicationRequest

OK

Created record in MedicationRequest

Not valid

Medications request
dispensed (COMPLETED)

Not valid

QualifyMedicationRequestByID

No records in MedicationRequest

Not possible

Create record in MedicationRequest

OK

Medications request
dispensed (COMPLETED) 

Not valid

  1. For info - status charts: Medication_request

  2. Get `check_innm_id`

SELECT m0.id FROM medications AS m0 INNER JOIN ingredients AS i1 ON m0.id = i1.parent_id INNER JOIN (SELECT si2.id AS id FROM medications AS sm0 INNER JOIN ingredients AS si1 ON si1.parent_id = sm0.id INNER JOIN innms AS si2 ON si1.innm_child_id = si2.id WHERE (sm0.is_active = TRUE) AND (sm0.id = {$.medication_id}) AND (si1.is_primary = TRUE) AND (si2.is_active = TRUE)) AS s2 ON i1.innm_child_id = s2.id WHERE (m0.is_active = TRUE)

  1. Get Medication requests with their completed Medication dispense by person_id & check_innm_id

SELECT m0.started_at, m0.ended_at FROM medication_requests AS m0 WHERE (m0.medical_program_id = {$.medical_program_id}) AND (m0.medication_id = ANY ({$.medication_id})) AND (m0.status = ANY (ACTIVE,COMPLETED)) AND (m0.started_at <= {$.ended_at}) AND (m0.patient_id = {$.patient_id} OR m0.person_id = {$.person_id}) ORDER BY m0.ended_at DESC LIMIT 1

 

4. Validate exist (IF EXIST ()  - that is any crossing  calculating term (started_at + ended_at) for payload with terms selecting Medication requests (started_at + ended_at).

  1. if found   and medical program setting skip_treatment_period = false (absent):

    1. add to response: status = INVALID

    2. add to response: rejection_reason = "It can be only 1 active / completed medication request request or medication request per one innm for the same patient at the same period of time!"

  2. Fetch Medication Request by $

innm_dosge, $medical_program_id, $person_id and max(end_date). In case there is found Medication Request with ended_at>=current_date then next one  can be done in:

  1. if (ended_at - started_at) >= MEDICATION_REQUEST_REQUEST_STANDARD_DURATION chart param then
    created_at from prequalify request should be greater then (ended at - MEDICATION_REQUEST_MAX_RENEW_DAY) of the found MR

    1. in case of error return 422 error ('It's to early to create new medication request for such innm_dosage and medical_program_id')

  2. if (ended_at - started_at) < MEDICATION_REQUEST_REQUEST_STANDARD_DURATION chart param then
    created_at from prequalify request should be greater then (ended at - MEDICATION_REQUEST_MIN_RENEW_DAY) of the found MR

    1. in case of error return 422 error ('It's to early to create new medication request for such innm_dosage and medical_program_id')

3. Check that care plan is mandatory for programs

It is need to check if the medication request with a program need a care plan (with setting `care_plan_required` == TRUE) for a this program.

  1. Check if there is a based_on in the request

    1. Check care_plan_required in medical program setting

b. if care_plan_required true:

i. check based_on (reference on care_plan and it activity) in request comply with program

  1. in case based_on not found:

a. add to response: status = INVALID

b. add to response: rejection_reason = "Medical program from activity should be equal to medical program from request"

4. Check diagnosis comply with programs

It is needed to check if medication request with a program needed a context (encounter) with a specified diagnosis. 

  1. If program has CONDITIONS_ICD10_AM_ALLOWED parameter in medical_program_settings:

    1. Check if primary diagnosis from the encounter in context has code from eHealth/ICD10_AM/condition_codes dictionary

      1. Check diagnosis code in CONDITIONS_ICD10_AM_ALLOWED

        1. in case of error - return 200 with status = INVALID and rejection_reason = “Encounter in context has no primary diagnosis allowed for the medical program“ 

  2. If program has CONDITIONS_ICPC2_ALLOWED parameter in medical_program_settings:

    1. Check if primary diagnosis from the encounter in context has code from eHealth/ICPC2/condition_codes dictionary

      1. Check diagnosis code in CONDITIONS_ICPC2_ALLOWED

        1. in case of error - return 200 with status = INVALID and rejection_reason = “Encounter in context has no primary diagnosis allowed for the medical program“

5. Check employee

It is needed to check if medication request with a program allowed to create for specified employee.

  1. Invoke employee_id from request

  2. Validate employee

    1. Validate that exists

      1. in case invalid return 422 error with msg ("Employee not found")

    2. Validate that $.employees.status == APPROVED

      1. in case invalid return 409 error with msg ("Employee is not active")

    3. Validate that $.employees.legal_entity_id == client_id from token

      1. in case invalid return 422 error with msg ("Employee does not belong to legal entity from token")

    4. For each medical program, If medical program has medical_program_settings with skip_employee_validation == false (or absent), then validate <employee_type>:

      1. validate if employee_type is present in medical_program_settings employee_types_to_create_request variable

        1. in case invalid return 422 error with msg ("Employee type can't create medication request with medical program from request") 

        2. in case employee_type = SPECIALIST

          1. get $.employees.speciality.speciality(speciality_officio == true)

          2. validate that speciality present in $.medical_programs.medical_program_setting.speciality_types_allowed variable

            1. in case invalid return 422 error with msg ("Employee's specialty doesn't allow create medication request with medical program from request") 

        3. in case employee_type = MED_COORDINATOR

          1. skip validation that speciality present in $.medical_programs.medical_program_setting.speciality_types_allowed variable

      2. If medical program has medical_program_settings with medical_program_settings.skip_employee_validation == true or there is no medical_program_id in the request, any user who has a scope can create medication request

6. Check Care plan and Activity

It is needed to check if medication request with a program allowed to be created for specified care plan and activity.

If based_on submitted, check field has array with two values of Reference type: one is valid Care plan resource, another - Activity resource.

  1. Verify Care plan:

    1. It should belong to the same person as set in MRR

      1. in case of error return 422 with msg ("Care plan not found")

    2. It should be in active status

  2. Verify submitted Activity:

    1. It belongs to the Care plan.

      1. in case of error return 422 with msg ("Activity not found")

    2. It has activity.detail.kind=medication_request; activity.detail.product_reference=medication_id.

      1. in case of error return 422 with msg ("Invalid activity kind")

    3. It has scheduled, in_progress status

      1. in case of error return 422 with msg ("Invalid activity status")

    4. If it has quantity then calculate remaining quantity:

      1. validate $.activity.details.remaining_quantity_type:

        1. if $.activity.details.remaining_quantity_type = for_request than:

          1. select all MRR in status NEW which based on current activity

          2. select all MR in statuses ACTIVE based on current activity

          3. select all MD (medication dispenses) in status PROCESSED related to the Medication requests which are in status COMPLETE, REJECTED, EXPIRED

          4. calculate:

            1. reserved_qty as sum of medication_qty in the filtered MRR  and MR list

            2. dispensed_qty as sum of medication_qty in the filtered MD list

            3. current_qty as medication_qty from current MRR

          5. calculate remaining quantity by subtracting reserved_quantity, dispensed_qty, current_qty from activity quantity

        2. if $.activity.details.remaining_quantity_type = for_use than:

          1. select all MRR in status NEW which based on current activity

          2. select all MR in statuses ACTIVE, COMPLETED based on current activity

          3. calculate reserved at the moment medication quantity as sum of medication_qty in the filtered MRR  and MR list, including medication_qty from current MRR

          4. calculate remaining quantity by subtracting reserved quantity from activity quantity

      2. Check remaining quantity is greater then or equal to zero

        1. in case of error return 409 "The total amount of the prescribed medication quantity exceeds quantity in care plan activity"

    5. check that medical_program_id equal to $.activity[].program

      1. in case of error return 422 with msg ("Medical program from activity should be equal to medical program from request")

  3. Validate started_at/ended_at of Medication request Request: 

    1. if care plan activity has detail.scheduled_timing.repeat.bounds_period - validate started_at/ended_at within bounds_period

      1. in the case of started_at/ended_at is not within bounds_period return 422 with msg  ("Invalid activity period")

    2. if care plan activity has detail.scheduled_period - validate started_at/ended_at within scheduled_period

      1. in the case of started_at/ended_at is not within scheduled_period return 422 with msg  ("Invalid activity period")

    3. else - validate started_at/ended_at within care_plan.period

      1. in the case of started_at/ended_at is not within care_plan.period return 422 with msg  ("Invalid care plan period")

7. Check period

It is needed to check if medication request period does not exceed allowed maximum of days.

  1. If medication request has program with request_max_period_day in medical program setting:

    1. Check that medication request period (ended_at - started_at) less than or equal to medical program setting request_max_period_day parameter

      1. in case of error - return 200 with status = INVALID and rejection_reason = “Period length exceeds allowed value for the medical program“ 

  2. If medication request has program without request_max_period_day in medical program setting:

    1. Check that medication request period (ended_at - started_at) less than or equal to request_max_period_day parameter from charts

      1. in case of error - return 200 with status = INVALID and rejection_reason = “Period length exceeds default maximum value“

8. Check context

  1. Validate "context" is an active (not entered-in-error) encounter, that belongs to the current patient

    1. Validate there is an entity in collection $.data.context.identifier.type.coding[0].code with id == $.data.context.identifier.value that belongs to the current patient

      1.  in case of error - return 422 (“Entity not found“)

    2. Validate that entity is not in status "entered-in-error"

      1. in case of error - return 422 ("Entity in status "entered-in-error" can not be referenced")

    3. Validate context.identifier.type.coding[0].code = encounter

      1. in case of error return 422 ("value is not allowed in enum")

    4. encounter diagnosis is not empty in $.encounter.diagnosis

      1. in case of error return 422 ("Encounter without diagnosis can not be referenced")

    5. Validate employee_id in $.encounter.performer.identifier.value == $. data.employee_id

      1. in case of error return 422 ("Employee is not performer of encounter")

    6. Validate $.data.created_at is within $.encounter.period including borders

      1. in case of error return 422 ("Created_at must be within the encounter period")

9. Check person

It is needed to check if person has allowed verification status to get medication.

  1. Invoke Get patient by ID

  2. Validate person_id - mpi_id exists

    1. in case invalid return 422 (422 Person not found)

  3. Save temporary variables from: $.data.authentication_methods

  4. Validate Response $.data.is_active==TRUE

    1. if not found - return 422 error (message: "Only for active MPI record can be created medication request!")

  5. Validate person's verification status:

    1. If MRR has based_on with valid activity, then skip this validation.

    2. Else check patient's verification_status is not equal to NOT_VERIFIED.

      1. in case NOT_VERIFIED - return error 409, "Patient is not verified"

10. Check declaration for a program

It is needed to check specified params for each medical program.

In case medical program has medical_program_settings with skip_employee_validation == false (or absent), then validate <employee_type>:

  1. validate if employee_type is present in medical_program_settings employee_types_to_create_request variable

    1. in case invalid return 422 error with msg ("Employee type can't create medication request with medical program from request") 

    2. in case employee_type = DOCTOR

      1. if variable skip_request_employee_declaration_verify = false or null/absent

        1. then: get $.declarations by employee_id, person_id, status=ACTIVE

          1. if not found - return 422 error  "Only doctors with an active declaration with the patient can create medication request with medical program from request!"

        2. else skip declaration verification on employee level (if true)

      2. if variable skip_request_legal_entity_declaration_verify = false or null/absent

        1. then: get $.declarations by employee's legal_entity_id, person_id, status=ACTIVE

          1. if not found - return 422 error "Only legal entity with an active declaration with the patient can create medication request with medical program from request!"

        2. else skip declaration verification on legal entity level (if true)

      3. else if both are true - skip declaration verification at all

11. Check provision for a programs

It is needed to check if medical program can be provided by pharmacies.

  1. If the medical program has no setting skip_contract_provision_verify or it is equal to false/null:

    1. If medical program has funding_source = LOCAL:

      1. Check there is exists any active medical program provision with msp_legal_entity_id equal to employee's legal entity for the program

        1. in case of error - return 200 with status = INVALID and rejection_reason = "Medical program is not provided for legal entity specified in the medication request"

12. Check authorize with

It is needed to check submitted persons authentication method.

  1. Check that authentication method with type = ‘THIRD_PERSON’ is submitted in $.authorize_with for person that must be authorized by confidant person using following logic:

    1. persons age < no_self_registration_age global parameter;

    2. persons age between no_self_registration_age and person_full_legal_capacity_age global parameters and person does not have document with type from PERSON_LEGAL_CAPACITY_DOCUMENT_TYPES config parameter;

    3. persons age > person_full_legal_capacity_age global parameter and exists at least one active and approved confidant person relationship for person (using following process https://e-health-ua.atlassian.net/wiki/spaces/CSI/pages/17667883028 with person_id = person_id from request - expected :ok, :approved response)

      1. in case of error - return 422 ('Authentication method with type THIRD_PERSON must be submitted for this person')

  2. Check that $.authorize_with is a valid uuid

    1. in case error - return 422 ('string does not match pattern') with uuid regexp

  3. Check that authentication method exists in MPI database, person_authentication_methods table (with is_active = true), belongs to person_id from request, is active (ended_at > now() or ended_at is null) and type != NA

    1. in case error - return 422 ('Authentication method doesn't exist, is inactive or does not belong to this person')

  4. Get value of THIRD_PERSON_CONFIDANT_PERSON_RELATIONSHIP_CHECK config parameter, if it is set to true - for authentication method with type = ‘THIRD_PERSON’ check that person from value is an approved confidant for a person from request – exists active and approved confidant person relationship between person from request and person_id from authentication method value (using following logic: https://e-health-ua.atlassian.net/wiki/spaces/CSI/pages/17667883028 with person_id = person_id from request and confidant_person_id = value from auth method) - expected :ok, :approved response)

    1. in case of error - return 422 ('Authentication method doesn't exist, is inactive or does not belong to this person')

Generate structure for response

  1. Collect array for all programs in payload with status for each (VALID or INVALID) and rejection_reason

ЕСОЗ - публічна документація