Table of Contents |
---|
Anchor | ||||
---|---|---|---|---|
|
Validate request using JSON schema
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{ "$schema": "http://json-schema.org/draft-04/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": "^(?!.*[ЫЪЭЁыъэё@%&$^#])[А-ЯҐЇІЄа-яґїіє\\'\\- ]+$", "minLength": 1, "maxLength": 255 }, "tax_id": { "type": "string", "pattern": "^[0-9]{10}$", "minLength": 10, "maxLength": 255 }, "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}$" } }, "required": [ "type", "country", "area", "settlement", "settlement_type", "settlement_id" ], "additionalProperties": false }, "document": { "type": "object", "properties": { "type": { "type": "string", "description": "Dictionary: DOCUMENT_TYPE" }, "number": { "type": "string", "minLength": 1, "maxLength": 255 }, "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 }, "authentication_method": { "type": "object", "properties": { "type": { "type": "string", "description": "Dictionary: AUTHENTICATION_METHOD" }, "phone_number": { "type": "string", "pattern": "^\\+38[0-9]{10}$" } }, "required": [ "type" ], "additionalProperties": false } }, "type": "object", "properties": { "declaration_request": { "type": "object", "properties": { "start_date": { "type": "string", "format": "date-time", "description": "Should be defined on the client side." }, "person": { "type": "object", "properties": { "first_name": { "type": "string", "$ref": "#/definitions/person_name" }, "last_name": { "type": "string", "$ref": "#/definitions/person_name" }, "second_name": { "type": "string", "$ref": "#/definitions/person_name" }, "birth_date": { "type": "string", "format": "date" }, "birth_country": { "type": "string", "minLength": 1, "maxLength": 255 }, "birth_settlement": { "type": "string", "$ref": "#/definitions/name", "minLength": 1, "maxLength": 255 }, "gender": { "$ref": "#/definitions/gender" }, "email": { "type": "string", "format": "email", "maxLength": 255 }, "tax_id": { "type": "string", "$ref": "#/definitions/tax_id" }, "invalid_tax_id": { "type": "boolean" }, "secret": { "type": "string", "$ref": "#/definitions/name", "minLength": 6, "maxLength": 20 }, "preferred_way_communication": { "type": "string", "enum": [ "email", "phone" ] }, "documents": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/document" } }, "addresses": { "type": "array", "items": { "$ref": "#/definitions/address" }, "minItems": 2 }, "phones": { "type": "array", "items": { "$ref": "#/definitions/phone" } }, "authentication_methods": { "type": "array", "items": { "$ref": "#/definitions/authentication_method" } }, "emergency_contact": { "type": "object", "properties": { "first_name": { "type": "string", "$ref": "#/definitions/person_name" }, "last_name": { "type": "string", "$ref": "#/definitions/person_name" }, "second_name": { "type": "string", "$ref": "#/definitions/person_name" }, "phones": { "type": "array", "items": { "$ref": "#/definitions/phone" }, "minItems": 1 } }, "required": [ "first_name", "last_name", "phones" ], "additionalProperties": false }, "confidant_person": { "type": "array", "items": { "type": "object", "properties": { "relation_type": { "type": "string", "enum": [ "PRIMARY", "SECONDARY" ] }, "first_name": { "type": "string", "$ref": "#/definitions/person_name" }, "last_name": { "type": "string", "$ref": "#/definitions/person_name" }, "second_name": { "type": "string", "$ref": "#/definitions/person_name" }, "birth_date": { "type": "string", "format": "date" }, "birth_country": { "type": "string", "minLength": 1 }, "birth_settlement": { "type": "string", "$ref": "#/definitions/name", "minLength": 1 }, "gender": { "$ref": "#/definitions/gender" }, "tax_id": { "type": "string", "$ref": "#/definitions/tax_id" }, "secret": { "type": "string", "$ref": "#/definitions/name", "minLength": 6 }, "documents_person": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/document" } }, "documents_relationship": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/document_relationship" } }, "phones": { "type": "array", "items": { "$ref": "#/definitions/phone" } } }, "required": [ "relation_type", "first_name", "last_name", "birth_date", "birth_country", "birth_settlement", "gender", "secret", "documents_person", "documents_relationship" ], "additionalProperties": false }, "description": "Should be set if this Person is disabled, underage, etc." }, "patient_signed": { "type": "boolean", "enum": [ false ] }, "process_disclosure_data_consent": { "type": "boolean", "enum": [ true ] } }, "required": [ "first_name", "last_name", "birth_date", "birth_country", "birth_settlement", "gender", "secret", "documents", "addresses", "authentication_methods", "emergency_contact", "patient_signed", "process_disclosure_data_consent" ], "additionalProperties": false, "description": "Object that described a Patient. Confidant person should be set for disabled persons, underage persons, etc." }, "employee_id": { "type": "string", "minLength": 36, "description": "Employee ID with `type=DOCTOR` selected from available Employees as a third contract party." }, "division_id": { "type": "string", "minLength": 36, "description": "Registered Medical Service Provider Division identifier." }, "scope": { "type": "string", "minLength": 1 }, "seed": { "type": "string" }, "overlimit": { "type": "boolean", "enum": [ false ] } }, "required": [ "person", "employee_id", "division_id", "scope" ], "additionalProperties": false } } } |
Authorize
- Verify the validity of access token
- Check user scope declaration_request:create in order to perform this action
Validate Legal Entity Type
Validate legal entity from token: legal_entities.type should be in DECLARATION_REQUEST_LEGAL_ENTITY_TYPES and legal_entities.status =='active'
Validate doctor
Get employee details
Invoke Get employee details
Validate Response $.data.employee_type == DOCTOR
Calculate patient age
Calculate patient age
Code Block | ||
---|---|---|
| ||
age = MONTHS_BETWEEN (now(), $.declaration_request.person.birth_date) / 12 |
Get global parameters
Invoke Global parameters to get following parameters:
...
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{ "meta": { "url": "http://api-svc.prm/api/global_parameters", "type": "object", "request_id": "ikff7hcf0hhto5c06irl9i976kc3s41m", "code": 200 }, "data": { "verification_request_expiration": "30", "employ_request_expiration": "30", "declaration_term": "30", "declaration_request_expiration": "30", "billing_date": "2", "adult_age": "18", "type": "global_parameter" } } |
Check that doctor speciality meets the patient age requirements
- Get doctor's speciality_officio (speciality object where speciality_officio == true)
- Check age requirements according to global parameters
Speciality officio | Age |
---|---|
FAMILY DOCTOR | All ages |
THERAPIST | Greater or equal to $.data.adult_age |
PEDIATRICIAN | Less than $.data.adult_age |
Check phone number
Invoke Check phone number WS in order to check phone number exists in DB.
...
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{ "meta": { "url": "http://dev.ehealth.world/verifications/+380936235986", "type": "object", "request_id": "b4adrhrj5og9ogqanb57dqj0v1qkbb9j", "code": 404 }, "error": { "type": "not_found" } } |
Search pending declaration requests
Search declarations in IL_DB.declaration_requests to prevent requests duplication:
...
Code Block |
---|
WHERE IL_DB.declaration_requests.data.person.documents.number = :($.declaration_request.person.documents.number) AND IL_DB.declaration_requests.data.person.first_name = :($.declaration_request.person.first_name) AND IL_DB.declaration_requests.data.person.last_name = :($.declaration_request.person.last_name) AND IL_DB.declaration_requests.status IN ('NEW', 'APPROVED') |
Cancel declaration requests
Change status of all found declarations:
Code Block | ||
---|---|---|
| ||
SET IL_DB.declaration_requests.status = 'CANCELED' WHERE IL_DB.declaration_requests.id IN (:LIST) |
Search pending declaration requests
Search persons request in IL_DB.person_requests to prevent requests duplication:
...
If found person request - don't create person request. Return error "This person already has a person request"
Calculate declaration end/start date
Declaration
Start date:
Code Block |
---|
start_date = Current_date() |
...
Code Block |
---|
if (person.age < 18)&(doctor.speciality = PEDIATRICIAN) { end_date = min(birth_date + 18y - 1d, start_date + declaration_term); } else { end_date = start_date + declaration_term; } |
Validate confidant person
If person age < 14 check existence of confidant_person
- in case error return 422 - msg "Confidant person is mandatory for children"
Save declaration request
Insert record to IL.declaration_request in status 'NEW'
Check "no_tax_id" flag
- If "no_tax_id"= true, tax_id field should be empty, in case error return 422
- If "no_tax_id"=false and age>14, tax_id should be present, in case error return 422
Validate person_id
USE_DEDUPLICATION_MODEL - is a flag in in ehealth.charts that turn on logic:
...
- search persons in mpi (Пошук персон. Версія 3)
- If we found person by tax_id and authentication_number
- return error 409, "such person exists. Update this person."
- In case authentication_method = OFFLINE, or don't found authentication_number, or we found authentication_number but tax_id don't match - We create pairs of new person with people from cluster and send to the model.
- in case deduplication model gave score < PERSON_ONLINE_DEDUPLICATION_MATCH_SCORE, create new person
- else return error 409, "such person exists. Update this person.
- If we found person by tax_id and authentication_number
Validate phone number limit
USE_PHONE_NUMBER_AUTH_LIMIT is a flag in ehealth.charts that shows whether we count phones or not.
- in case person is found, person_id will be saved to declaration_request, and person has the same authentication_methods.phone_number, we do not count phone numbers and do not compare the phone number with global_parameters.phone_number_auth_limit. So that we can update person, but still can not use phone over limit.
- In case person is not found
- Check if (SELECT count(*) from persons where authentication_methods::json->0->>'phone_number'='$.phone_number' and persons.status='active' and is_active=true)<global_parameters.phone_number_auth_limit
in case error return 422, msg "This phone number is present more then $.global_parameters.phone_number_auth_limit times in the system"
- Check if (SELECT count(*) from persons where authentication_methods::json->0->>'phone_number'='$.phone_number' and persons.status='active' and is_active=true)<global_parameters.phone_number_auth_limit
Validate declaration limit
Count all declarations in statusactive
where OPS.declarations.employee_id==$.declaration_request.employee_id1.1 If there is an active declaration with the current person, exclude it from the selection in order to let doctor resign declaration with current patientCount all declaration_requests in statusapproved
where IL.declaration_requests.data($.employee.id) ==$.declaration_request.employee_idGet all specialities of current doctorSelect speciality from PRM.employees where PRM.employees.party_id == (select PRM.employees.party_id where PRM.employees.id=$.declaration_request.employee_id)
Select config parameter for declarations_limit where speciality == select 3Compare the result of selections 1+2 with the lowest config parameter from select 4. In case count (declarations+declaration_requests )> config_parameter, return 409 "The employee has reached the declaration limit"
Validate person authentication phone
USE_DEDUPLICATION_MODEL - is a flag in in ehealth.charts that turn on logic:
If person have confidant_person, then person.auth_phone = person.confident_person.phone
- in case error return 422 - msg "Person must have same phone as the confidant person"
Validate person documents
- issued_at, issued_by is mandatory for documents
- Validate dates
- issued_at <= now() and issued_at => birth_date
- in case `issued_at > now()` show error 422, "Document issued date should be in the past"
- in case `issued_at < person.birth_date` show error 422, "Document issued date should greater than person.birth_date "
- expiration_date > now()
- in case error show 422, "Document expiration_date should be in future"
- expiration_date is mandatory for document_type
- NATIONAL_ID
- COMPLEMENTARY_PROTECTION_CERTIFICATE
- PERMANENT_RESIDENCE_PERMIT
- REFUGEE_CERTIFICATE
- TEMPORARY_CERTIFICATE
- TEMPORARY_PASSPORT
- in case error return 422, "expiration_date is mandatory for document_type $.documents.type"
- issued_at <= now() and issued_at => birth_date
- Validate documents_type.number according to json schema
- PASSPORT - `^((?![ЫЪЭЁ])([А-ЯҐЇІЄ])){2}[0-9]{6}$`
- NATIONAL_ID - `^[0-9]{9}$`
- BIRTH_CERTIFICATE - ` ^(?![ЫЪЭЁыъэё@%&$^#`~:,.*|}{?!])[A-ZА-ЯҐЇІЄ0-9№\\/()-]+$ `
- COMPLEMENTARY_PROTECTION_CERTIFICATE - `^((?![ЫЪЭЁ])([А-ЯҐЇІЄ])){2}[0-9]{6}$`
- PERMANENT_RESIDENCE_PERMIT - `^((?![ЫЪЭЁ])([А-ЯҐЇІЄ])){2}[0-9]{6}$`
- REFUGEE_CERTIFICATE - `^((?![ЫЪЭЁ])([А-ЯҐЇІЄ])){2}[0-9]{6}$`
- TEMPORARY_CERTIFICATE - `^((?![ЫЪЭЁ])([А-ЯҐЇІЄ])){2}[0-9]{6}$`
- TEMPORARY_PASSPORT - `` ^(?![ыъэ@%&$^#`~:,.*|}{?!])[А-ЯҐЇІЄа-яґїіє0-9 №\\\"()-]+$ `
- if `unzr`exists and is not null and matches "^[0-9]{8}-[0-9]{5}$" check if first 8 symbols = birth_date
- in case error return 422, msg "unzr or birthdate are not correct"
if documents.type=NATIONAL_ID
check if unzr exists in request, in case error return 422, msg "unzr is mandatory for document type NATIONAL_ID"
- Document numbersmaxLength < 25
Determine auth method
Determine Channel
- channel from url
- if url is for cabinet сhannel set declaration_request.сhannel = CABINET
- if not - set declaration_request.сhannel = MIS
- if url is for cabinet сhannel set declaration_request.сhannel = CABINET
Generate printout form
Invoke MAN to render print form.
...
Code Block | ||
---|---|---|
| ||
MANResponse.$.data |
Generate upload URL
Depending on the payload system generates list of signed urls for document scan-copies upload.
...
Each link is generated for one one-page document in jpeg format. Document should be no more than 10MB.
For On-line
- if no_tax_id = true
- Generate URL with type person.no_tax_id
For Offline
1. If $.declaration_request.person.tax_id not null:
...
Code Block | ||
---|---|---|
| ||
{ "documents":[ { "type":"person.tax_id", "url": "https://storage.googleapis.com/..." } ] } |
Save documents to DB.
Generate verification code
Invoke Initialize OTP to generate one time password and send it to client number.
...
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X POST \ http://localhost:4000/verifications \ -H 'content-type: application/json' \ -d '{ "phone_number": "+380936235985" }' |
Generate human readable declaration number
- Use algorithm to generate declaration_number
- Declaration number should consist of a 4 serial symbols and 8 number symbols and looks like XXXX-12H4-245D
- Add field to ops.declarations and il.declaration_requests - declaration_number
- Add declaration_number to print out form
...