Versions Compared

Key

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

Table of Contents

Purpose

This method is designed to create a Person Request (as part of the process of creating a Person without a Declaration)

Specification

...

Link

...

https://ehealthmisapi1.docs.apiary.io/#reference/public.-medical-service-provider-integration-layer/person-requests/create/update-person-request

...

Resource

...

/api/person_requests

...

Scope

...

person_request:write

...

Components

...

Patient registry

...

Microservices

...

il/api

fe/admin-web

...

Protocol type

...

REST

...

Request type

...

POST

...

Sync/Async

...

Sync

...

Public/Private/Internal

...

Public

Logic

Patient

Table of Contents

Purpose

This method is designed to create or update Person Request (as part of the process of creating a Person without a Declaration)

Specification

Link

https://ehealthmisapi1.docs.apiary.io/#reference/public.-medical-service-provider-integration-layer/person-requests/create/update-person-request

Resource

/api/person_requests

Scope

person_request:write

Components

Patient registry

Microservices

il/api

fe/admin-web

Protocol type

REST

Request type

POST

Sync/Async

Sync

Public/Private/Internal

Public

Logic

Patient creation request statuses

...

Code Block
curl -X GET \
  {:host}/prm/api/global_parameters

Dictionaries

  • GENDER

  • DOCUMENT_TYPE

  • ADDRESS_TYPE

  • COUNTRY

  • SETTLEMENT_TYPE

  • STREET_TYPE

  • PHONE_TYPE

  • AUTHENTICATION_METHOD

  • CONFIDANT_PERSON_TYPE

  • PREFERRED_WAY_COMMUNICATION

  • DOCUMENT_RELATIONSHIP_TYPE

Request structure

See on Apiary

...

Expand
titleRequest example
Code Block
{
  "person": {
    "id": "13001c60-45a0-4b5a-b425-9505e1de18bd",
    "first_name": "Петро",
    "last_name": "Іванов",
    "second_name": "Миколайович",
    "birth_date": "2009-07-05",
    "birth_country": "Україна",
    "birth_settlement": "Вінниця",
    "gender": "MALE",
    "email": "email@example.com",
    "no_tax_id": false,
    "tax_id": "3999869394",
    "secret": "secret",
    "documents": [
      {
        "type": "BIRTH_CERTIFICATE",
        "number": "АА120518",
        "issued_by": "Рокитнянським РВ ГУ МВС Київської області",
        "issued_at": "2017-02-28",
        "expiration_date": "2027-02-28"
      }
    ],
    "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"
      }
    ],
    "authentication_methods": [
      {
        "type": "THIRD_PERSON",
        "phone_number": "+380508887700",
        "value": "c282f8a9-e709-40aa-94b4-dde1402bf4b6",
        "alias": "husband"
      }
    ],
    "unzr": "20090705-00011",
    "emergency_contact": {
      "first_name": "Петро",
      "last_name": "Іванов",
      "second_name": "Миколайович",
      "phones": [
        {
          "type": "MOBILE",
          "number": "+380503410870"
        }
      ]
    },
    "confidant_person": [
      {
        "relation_type": "PRIMARY",
        "first_name": "Петро",
        "last_name": "Іванов",
        "second_name": "Миколайович",
        "birth_date": "1972-10-26",
        "birth_country": "Україна",
        "birth_settlement": "Вінниця",
        "gender": "MALE",
        "tax_id": "2659719350",
        "secret": "secret",
        "unzr": "19900101-00099",
        "preferred_way_communication": "email",
        "documents_person": [
          {
            "type": "PASSPORT",
            "number": "АА120518",
            "expiration_date": "2021-02-28",
            "issued_by": "Рокитнянським РВ ГУ МВС Київської області",
            "issued_at": "2017-02-28"
          }
        ],
        "documents_relationship": [
          {
            "type": "BIRTH_CERTIFICATE",
            "number": "АА120518",
            "issued_by": "Рокитнянським РВ ГУ МВС Київської області",
            "issued_at": "2017-02-28"
          }
        ],
        "phones": [
          {
            "type": "MOBILE",
            "number": "+380503410870"
          }
        ],
        "email": "emaill@example.com"
      }
    ],
    "preferred_way_communication_way_communication": "email"
  },
  "patient_signed": false,
  "process_disclosure_data_consent": true,
  "authorize_with": "email"
  },
  "patient_signed": false,
  "process_disclosure_data_consent": true,
  "authorize_with": "cc949559-5dfe-420f-ac05-065e443b2cc6"
}

Authorize

...

Verify the validity of access token

...

Check user scope person_request:write in order to perform this action

validate client_id belongs to legal_entity with type in ('MSP', 'OUTPATIENT', 'EMERGENCY', 'PRIMARY_CARE')

...

cc949559-5dfe-420f-ac05-065e443b2cc6"
}

Authorize

  1. Verify the validity of access token

    1. Return (401, 'Invalid access token') in case of validation fails

  2. Verify that token is not expired

    1. in case of error - return (401, 'Invalid access token')

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

    • Return (403, 'Your scope does not allow to access this resource. Missing allowances: person_request:write') in case of invalid scope(s)

  4. validate client_id belongs to legal_entity with type in ('MSP', 'OUTPATIENT', 'EMERGENCY', 'PRIMARY_CARE')

    1. Return (401, 'Invalid legal entity type') in case of validation fails

  5. If BLOCK_UNVERIFIED_PARTY_USERS is true, then check party's data match following condition: verification_status != NOT_VERIFIED or (verification_status = NOT_VERIFIED and updated_at <= current_date - UNVERIFIED_PARTY_PERIOD_DAYS_ALLOWED):

    1. in case not match - return 403 ("Access denied. Party is not verified")

  6. If BLOCK_DECEASED_PARTY_USERS is true, check that party is not deceased (party_verification record does not equal to: dracs_death_verification_status = VERIFIED and dracs_death_verification_reason = MANUAL_CONFIRMED):

    1. in case of error - return 403 ("Access denied. Party is deceased")

  7. validate user belongs to employee with type in "Doctor, Specialist, Receptionist, Assistant"

    1. in case error return 409

Headers

Content-Type:application/json

...

Validate request using JSON schema

  • Check presence of extra parameters

    • In case of error - return 422 ('schema does not allow additional properties')

  • Check presence of required parameters

    • In case of error - return 422 ('required property %{property} was not present')

Expand
titleJSON Schema
Code Block
{
  "$schema": "http://json-schema.org/person_request/schema#",
  "definitions": {
    "phone": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "description": "Dictionary: PHONE_TYPE"
        },
        "number": {
          "type": "string",
          "pattern": "^\\+38[0-9]{10}$"
        }
      },
      "required": [
        "type",
        "number"
      ],
      "additionalProperties": false
    },
    "name": {
      "type": "string",
      "pattern": "^(?!.*[ЫЪЭЁыъэё@%&$^#])[a-zA-ZА-ЯҐЇІЄа-яґїіє0-9№\\\"!\\^\\*)\\]\\[(._-].*$"
    },
    "person_name": {
      "type": "string",
      "pattern": "^(?!.*[ЫЪЭЁыъэё@%&$^#])[А-ЯҐЇІЄа-яґїіє\\'\\-]+(\\s(?!.*[ЫЪЭЁыъэё@%&$^#])[А-ЯҐЇІЄа-яґїіє\\'\\-]+)*$",
      "minLength": 1,
      "maxLength": 255
    },
    "unzr": {
      "type": "string",
      "pattern": "^[0-9]{8}-[0-9]{5}$"
    },
    "tax_id": {
      "type": "string",
      "pattern": "^[0-9]{10}$",
      "minLength": 10,
      "maxLength": 255
    },
    "no_tax_id": {
      "type": "boolean",
      "description": "Status person refused tax_id"
    },
    "gender": {
      "type": "string",
      "description": "Dictionary: GENDER",
      "maxLength": 255
    },
    "address": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "description": "Dictionary: ADDRESS_TYPE"
        },
        "country": {
          "type": "string"
        },
        "area": {
          "$ref": "#/definitions/name"
        },
        "region": {
          "$ref": "#/definitions/name"
        },
        "settlement": {
          "$ref": "#/definitions/name"
        },
        "settlement_type": {
          "type": "string",
          "description": "settlement type Dictionary: SETTLEMENT_TYPE"
        },
        "settlement_id": {
          "type": "string",
          "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
        },
        "street_type": {
          "type": "string",
          "description": "street type Dictionary: STREET_TYPE"
        },
        "street": {
          "$ref": "#/definitions/name"
        },
        "building": {
          "type": "string",
          "pattern": "^[1-9]((?![ЫЪЭЁыъэё])()([А-ЯҐЇІЄа-яґїіє \\/\\'\\-0-9])){0,20}$"
        },
        "apartment": {
          "type": "string"
        },
        "zip": {
          "type": "string",
          "pattern": "^[0-9]{5}$"
        },
        "inserted_by": {
          "type": "string"
        },
        "updated_by": {
          "type": "string"
        },
        "inserted_at": {
          "type": "string"
        },
        "updated_at": {
          "type": "string"
        }
      },
      "required": [
        "type",
        "country",
        "area",
        "settlement",
        "settlement_type",
        "settlement_id",
        "inserted_by",
        "updated_by"
      ],
      "additionalProperties": false
    },
    "series_number_document": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "PASSPORT",
            "COMPLEMENTARY_PROTECTION_CERTIFICATE",
            "REFUGEE_CERTIFICATE",
            "TEMPORARY_CERTIFICATE"
          ],
          "description": "Dictionary: DOCUMENT_TYPE"
        },
        "number": {
          "type": "string",
          "pattern": "^((?![ЫЪЭЁ])([А-ЯҐЇІЄ])){2}[0-9]{6}$"
        },
        "issued_by": {
          "type": "string",
          "minLength": 1
        },
        "issued_at": {
          "type": "string",
          "format": "date"
        }
      },
      "required": [
        "type",
        "number"
      ],
      "additionalProperties": false
    },
    "number_document": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "BIRTH_CERTIFICATE",
            "TEMPORARY_PASSPORT"
          ],
          "description": "Dictionary: DOCUMENT_TYPE"
        },
        "number": {
          "type": "string",
          "pattern": "^(?![ЫЪЭЁыъэё@%&$^#`~:,.*|}{?!])[A-ZА-ЯҐЇІЄ0-9№\\/()-]+$",
          "minLength": 1,
          "maxLength": 255
        },
        "issued_by": {
          "type": "string",
          "minLength": 1
        },
        "issued_at": {
          "type": "string",
          "format": "date"
        }
      },
      "required": [
        "type",
        "number"
      ],
      "additionalProperties": false
    },
    "id_card": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "NATIONAL_ID"
          ],
          "description": "Dictionary: DOCUMENT_TYPE"
        },
        "number": {
          "type": "string",
          "pattern": "^[0-9]{9}$"
        },
        "issued_by": {
          "type": "string",
          "minLength": 1
        },
        "issued_at": {
          "type": "string",
          "format": "date"
        }
      },
      "required": [
        "type",
        "number"
      ],
      "additionalProperties": false
    },
    "document_relationship": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "description": "Dictionary: DOCUMENT_RELATIONSHIP_TYPE",
          "minLength": 1
        },
        "number": {
          "type": "string",
          "minLength": 1
        },
        "issued_by": {
          "type": "string",
          "minLength": 1
        },
        "issued_at": {
          "type": "string",
          "format": "date"
        }
      },
      "required": [
        "type",
        "number"
      ],
      "additionalProperties": false
    }
  },
  "type": "object",
  "properties": {
    "person": {
      "type": "object",
      "properties": {
        "first_name": {
          "type": "string"
        },
        "last_name": {
          "type": "string"
        },
        "second_name": {
          "type": "string"
        },
        "birth_date": {
          "type": "string"
        },
        "birth_country": {
          "type": "string"
        },
        "birth_settlement": {
          "type": "string"
        },
        "gender": {
          "enum": [
            "MALE",
            "FEMALE"
          ]
        },
        "email": {
          "type": "string"
        },
        "no_tax_id": {
          "type": "boolean"
        },
        "tax_id": {
          "type": "string"
        },
        "secret": {
          "type": "string"
        },
        "documents": {
          "type": "array"
        },
        "addresses": {
          "type": "array"
        },
        "phones": {
          "type": "array"
        },
        "authentication_methods": {
          "type": "array"
        },
        "unzr": {
          "type": "string"
        },
        "emergency_contact": {
          "type": "object",
          "properties": {
            "first_name": {
              "type": "string"
            },
            "last_name": {
              "type": "string"
            },
            "second_name": {
              "type": "string"
            },
            "phones": {
              "type": "array"
            }
          },
          "required": [
            "first_name",
            "last_name",
            "phones"
          ]
        },
        "confidant_person": {
          "type": "array"
        },
        "preferred_way_communication": {
          "enum": [
            "email",
            "phone"
          ]
        }
      },
      "required": [
        "first_name",
        "last_name",
        "birth_date",
        "birth_country",
        "birth_settlement",
        "gender",
        "no_tax_id",
        "tax_id",
        "secret",
        "documents",
        "addresses",
        "emergency_contact"
      ]
    },
    "patient_signed": {
      "type": "boolean"
    },
    "process_disclosure_data_consent": {
      "type": "boolean"
    }
  },
  "required": [
    "person",
    "patient_signed",
    "process_disclosure_data_consent"
  ]
}

Validate confidant person

...

  • Verify that person age < prm.global_parameters.no_self_auth_age check existence of confidant_personin case error return 422 - msg "

    • Return (422, 'Confidant person is mandatory for children

    "
    • ') in case of validation fails

  • Validate confidant person age >= prm.global_parameters.no_self_auth_age

...

  • in case error return 422 - msg "

    • Return (422, 'Incorrect person age for such an action

    "
    • ') in case of validation fails

Validate "tax_id"

  • tax_id has validation pattern - `^[0-9]{10}$`

    • if doesn't match, return error 422 "string does not match pattern ..."

...

  1. issued_at, issued_by is mandatory for documents

  2. Validate dates

    1. issued_at <= now() and issued_at => birth_date

      1.  in case `issued_at > now()` show error 422, "Document issued date should be in the past"

      2.  in case `issued_at < person.birth_date` show error 422, "Document issued date should greater than person.birth_date "

    2. expiration_date > now()

      1.  in case error show 422, "Document expiration_date should be in future"

      2. expiration_date is mandatory for document_type

        • NATIONAL_ID

        • COMPLEMENTARY_PROTECTION_CERTIFICATE

        • PERMANENT_RESIDENCE_PERMIT

        • REFUGEE_CERTIFICATE

        • TEMPORARY_CERTIFICATE

        • TEMPORARY_PASSPORT

      3. in case error return 422, "expiration_date is mandatory for document_type $.documents.type"

  3. Validate documents_type.number according to json schema 

    1. PASSPORT - `^((?![ЫЪЭЁ])([А-ЯҐЇІЄ])){2}[0-9]{6}$`

    2. NATIONAL_ID - `^[0-9]{9}$`

    3. BIRTH_CERTIFICATE - `^((?![ЫЪЭЁыъэё@%&$^#`~:,.*|}{?!])[A-ZА-ЯҐЇІЄ0-9№\\/()-]){2,25}$`

    4. COMPLEMENTARY_PROTECTION_CERTIFICATE - `^((?![ЫЪЭЁ])([А-ЯҐЇІЄ])){2}[0-9]{6}$`

    5. REFUGEE_CERTIFICATE - `^((?![ЫЪЭЁ])([А-ЯҐЇІЄ])){2}[0-9]{6}$`

    6. TEMPORARY_CERTIFICATE - `^(((?![ЫЪЭЁ])([А-ЯҐЇІЄ])){2}[0-9]{4,6}|[0-9]{9}|((?![ЫЪЭЁ])([А-ЯҐЇІЄ])){2}[0-9]{5}\\/[0-9]{5})$`

    7. TEMPORARY_PASSPORT - `^((?![ЫЪЭЁыъэё@%&$^#`~:,.*|}{?!])[A-ZА-ЯҐЇІЄ0-9№\\/()-]){2,25}$`

  4. if `unzr`exists unzr exists and is not null and matches , check pattern match "^[0-9]{8}-[0-9]{5}$" check if first 8 symbols = birth_date

    1. in case error return 422, msg "unzr or birthdate are not correct"'string does not match pattern \"%{pattern}\"'

  5. if documents.type=NATIONAL_ID

    1. check if unzr exists in request, in case error return 422, msg "unzr is mandatory for document type NATIONAL_ID"

  6. Document numbersmaxLength < 25 

...

  1. If person <prm.global_parameters.no_self_auth_age years, then person.auth_methods.type = third_person. Validate that third_person has auth method.type = OTP

  2. if third_person.auth_method.type = OFFLINE - error `THIRD PERSON can't have OFFLINE self auth method type`

  3. if third_person.auth_method.type doesn't have active auth method - error `THIRD PERSON doesn't have active valid authentication methods`

  4. If third person >= prm.global_parameters.no_self_auth_age years

    1. in case error return 422, msg "Incorrect person age for such an action"

Person.auth_methods.type = third_persont.id. But on get Person request or Person display third_person.auth_method.phone_number.

...

Each link is generated for one one-page document in .pdf, .jpg, .png, .bmp formatbmp format. Document should be no more than 20 MB. For each type of documents, if couple of rules worked - only one single link is generated.

  1. Validate flag no_tax_id, if $.person_request.person.no_tax_id = true:

    1. Generate URL with type person.no_tax_id

  2. Validate if $.person_request.person.tax_id is not empty and $.person_request.person.no_tax_id = false then

    1. If (GetBirthDateFromTaxId($.tax_id) != $.birth_date) or (GetGenderFromTaxId($.tax_id) != $.gender) or CheckValidity($.tax_id) = false (i.e. invalid checksum) then

      • Generate URL with type person.tax_id

  3. Validate block confidant person. If person.confidant is not null:

    1. Generate URL's with type confidant_person.{confidant_person.type}.{$.person_request.person.confidant_person.[:].documents_relationship.[:].type}

    2. Generate URL's with type confidant_person.{confidant_person.type}.{$.person_request.person.confidant_person.[:].documents_person.[:].type}

  4. Validate block of person documents. If one of the documents has document.type = BIRTH_CERTIFICATE_FOREIGN and there is no same document in {$.person_request.person.confidant_person.[:].documents_relationship.[:]}

    and age < no_self_auth_age then

    1. Generate URL with type person.{$.person_request.person.documents.[with type BIRTH_CERTIFICATE_FOREIGN].type}

  5. Validate block of person documents. If one of the documents has document.type = PERMANENT_RESIDENCE_PERMIT and age >= no_self_auth_age then

    1. Generate URL with type person.{$.person_request.person.documents.[with type PERMANENT_RESIDENCE_PERMIT].type}

  6. Validate authentication_method. If authentication method = OFFLINE or third_person (and this third_person.auth_method = OFFLINE) - 

    1. Generate URL's with type person.{$.person_request.person.documents.[:].type} (or Generate URL's with type third_person.{$.third_person.documents.[:].type})

  7. Validate unzr. If $.person_request.person.unzr is not empty and first 8 digits of $.person_request.person

    .documents.[:].type} (or Generate URL's with type third_person

    .unzr != $.person_request.person.birth_date then

    1. Generate URL with type person.{$.thirdperson_request.person.documents.[:].type})unzr}

Invoke Media Content Storage to generate upload URL for each document obtained by executing logic above

...

Expand
titleResponse example (code: 422)
Code Block
{
  "meta": {
    "code": "422",
    "url": "https://example.com/resource",
    "type": "object",
    "request_id": "6617aeec-15e2-4d6f-b9bd-53559c358f97#17810"
  },
  "error": {
    "type": "unverified",
    "message": "Unverified phone number"
  }
}

Update person request

To update the data of an existing person use an endpoint `Create/Update person request`.

...

  • validate person.id is UUID

    • in case error return 422

  • search person by person.id in MPI 

    • in case error return 422, "such person doesn't exist"

  • search persons in mpi (Пошук персон. Версія 3)

    • validate person be deduplication model (if score >  PERSON_ONLINE_DEDUPLICATION_UPDATE_SCORE, then add mpi_id to person request)

      • else return error 409, "such Such person can't be updated. Deduplication update score is lower than system value (less changes should be made)"New person should be created instead" 

Update person’s data with empty value of the second name is possible by setting second_name = null.

Authorize

  1. Verify the validity of access token

  2. Check user scope person_request:write in order to perform this action

...

Each link is generated for one one-page document in jpeg format. Document should be no more than 10MB. For each type of documents only one single link is generated.

  1. Validate flag no_tax_id, if $.person_request.person.no_tax_id = true:

    1. Generate URL with type person.no_tax_id

  2. Validate if $.person_request.person.tax_id is not empty and $.person_request.person.no_tax_id = false then

    1. If (GetBirthDateFromTaxId($.tax_id) != $.birth_date) or (GetGenderFromTaxId($.tax_id) != $.gender) or CheckValidity($.tax_id) = false (i.e. invalid checksum) then

      • Generate URL with type person.tax_id

  3. Validate block confidant person. If person.confidant is not null:

    1. Generate URLs with type confidant_person.{confidant_person.type}.{$.person_request.person.confidant_person.[:].documents_relationship.[:].type}

    2. Generate URLs with type confidant_person.{confidant_person.type}.{$.person_request.person.confidant_person.[:].documents_person.[:].type}

  4. Validate block of person documents. If one of the documents has document.type = BIRTH_CERTIFICATE_FOREIGN and there is no same document in {$.person_request.person.confidant_person.[:].documents_relationship.[:]}

    and age < no_self_auth_age then

    1. Generate URL with type person.{$.person_request.person.documents.[with type BIRTH_CERTIFICATE_FOREIGN].type}

  5. Validate block of person documents. If one of the documents has document.type = PERMANENT_RESIDENCE_PERMIT and age >= no_self_auth_age then

    1. Generate URL with type person.{$.person_request.person.documents.[with type PERMANENT_RESIDENCE_PERMIT].type}

  6. Validate authentication_method. If authentication method = OFFLINE or third_person (and this third_person.auth_method = OFFLINE) - 

    1. Generate URLs with type person.{$.person_request.person.documents.[:].type} (or Generate URL's with type third_person.{$.third_person.documents.[:].type})

  7. Validate unzr. If $.person_request.person.unzr is not empty and first 8 digits of $.person_request.person.unzr != $.person_request.person.birth_date then

    1. Generate URL with type person.{$.person_request.person.unzr}

Code Block
{
   "documents":[
      {
         "type":"person.no_tax_id",
         "url": "https://storage.googleapis.com/..."
      }
   ]
}

...

Code Block
curl -X POST \
  http://localhost:4000/verifications \
  -H 'content-type: application/json' \
  -d '{
  "phone_number": "+380958697084"
}'

HTTP status codes

HTTP status code

Message

What caused the error

201

 Response

 

409

Invalid legal entity type

Such person exists. Update this person

Such person can't be updated. Deduplication update score is lower than system value (less changes should be made)

Validation failed

422

Unverified phone number

Such a phone already exists more N times

Confidant person is mandatory for children

Incorrect person age for such an action

String does not match pattern ...

Required property patient_signed was not present

Value is not allowed in enum

Document issued date should be in the past

Document issued date should greater than person.birth_date

Document expiration_date should be in future

Expiration_date is mandatory for document_type $.documents.type

Unzr or birthdate are not correct

Unzr is mandatory for document type NATIONAL_ID

This phone number is present more then $.global_parameters.phone_number_auth_limit times in the system

Such person doesn't exist

Such authentication method doesn't exist

Cannot be confirmed by a method with type= NA. Use a different method.

Validation failed