@andes/fhir 1.12.0 → 1.12.1-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -674
- package/README.md +2 -2
- package/{src → dist}/data/patient.json +192 -192
- package/dist/helpers/patientFactory.d.ts +26 -0
- package/dist/{src/helpers → helpers}/patientFactory.js +35 -31
- package/dist/index.d.ts +15 -0
- package/dist/index.js +55 -52
- package/dist/lib/allergyIntolerance.d.ts +29 -0
- package/dist/{src/lib → lib}/allergyIntolerance.js +39 -40
- package/dist/lib/bundle.d.ts +14 -0
- package/dist/{src/lib → lib}/bundle.js +25 -26
- package/dist/lib/composition.d.ts +47 -0
- package/dist/{src/lib → lib}/composition.js +152 -152
- package/dist/lib/condition.d.ts +53 -0
- package/dist/{src/lib → lib}/condition.js +79 -80
- package/dist/lib/config.d.ts +9 -0
- package/dist/{src/lib → lib}/config.js +27 -21
- package/dist/lib/config.test.d.ts +1 -0
- package/dist/lib/config.test.js +19 -0
- package/dist/lib/device.d.ts +22 -0
- package/dist/{src/lib → lib}/device.js +38 -39
- package/dist/lib/device.test.d.ts +1 -0
- package/dist/lib/device.test.js +9 -0
- package/dist/lib/document-reference.d.ts +71 -0
- package/dist/{src/lib → lib}/document-reference.js +106 -107
- package/dist/lib/immunization.d.ts +44 -0
- package/dist/{src/lib → lib}/immunization.js +67 -68
- package/dist/lib/medication.d.ts +25 -0
- package/{src/lib/medication.ts → dist/lib/medication.js} +64 -61
- package/dist/lib/medicationRequest.d.ts +42 -0
- package/{src/lib/medicationRequest.ts → dist/lib/medicationRequest.js} +103 -100
- package/dist/lib/medicationStatement.d.ts +47 -0
- package/dist/{src/lib → lib}/medicationStatement.js +55 -56
- package/dist/lib/organization.d.ts +6 -0
- package/dist/lib/organization.js +93 -0
- package/dist/lib/patient.d.ts +14 -0
- package/dist/lib/patient.js +465 -0
- package/dist/lib/patient.test.d.ts +1 -0
- package/dist/{src/lib → lib}/patient.test.js +132 -113
- package/dist/lib/practitioner.d.ts +6 -0
- package/dist/lib/practitioner.js +186 -0
- package/dist/types/andes/organization.types.d.ts +39 -0
- package/dist/types/andes/organization.types.js +2 -0
- package/dist/types/andes/patient.types.d.ts +57 -0
- package/dist/types/andes/patient.types.js +2 -0
- package/dist/types/andes/practitioner.types.d.ts +72 -0
- package/dist/types/andes/practitioner.types.js +3 -0
- package/package.json +56 -45
- package/.circleci/config.yml +0 -72
- package/.editorconfig +0 -14
- package/.env.example +0 -2
- package/.gitattributes +0 -1
- package/.github/CODEOWNERS +0 -1
- package/.github/labeler.yml +0 -11
- package/.github/pull_request_template.md +0 -28
- package/.github/workflows/build_test.yml +0 -14
- package/.github/workflows/has_conflicts.yml +0 -13
- package/.vscode/settings.json +0 -2
- package/CHANGELOG.md +0 -351
- package/coverage/clover.xml +0 -209
- package/coverage/coverage-final.json +0 -5
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/config.ts.html +0 -136
- package/coverage/lcov-report/device.ts.html +0 -193
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/helpers/index.html +0 -116
- package/coverage/lcov-report/helpers/patientFactory.ts.html +0 -124
- package/coverage/lcov-report/index.html +0 -131
- package/coverage/lcov-report/lib/config.ts.html +0 -136
- package/coverage/lcov-report/lib/device.ts.html +0 -193
- package/coverage/lcov-report/lib/index.html +0 -146
- package/coverage/lcov-report/lib/patient.ts.html +0 -1318
- package/coverage/lcov-report/patient.ts.html +0 -1207
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -210
- package/coverage/lcov.info +0 -425
- package/dist/index.js.map +0 -1
- package/dist/src/data/patient.json +0 -192
- package/dist/src/helpers/patientFactory.js.map +0 -1
- package/dist/src/lib/allergyIntolerance.js.map +0 -1
- package/dist/src/lib/bundle.js.map +0 -1
- package/dist/src/lib/composition.js.map +0 -1
- package/dist/src/lib/condition.js.map +0 -1
- package/dist/src/lib/config.js.map +0 -1
- package/dist/src/lib/config.test.js +0 -13
- package/dist/src/lib/config.test.js.map +0 -1
- package/dist/src/lib/device.js.map +0 -1
- package/dist/src/lib/device.test.js +0 -10
- package/dist/src/lib/device.test.js.map +0 -1
- package/dist/src/lib/document-reference.js.map +0 -1
- package/dist/src/lib/immunization.js.map +0 -1
- package/dist/src/lib/medication.js +0 -65
- package/dist/src/lib/medication.js.map +0 -1
- package/dist/src/lib/medicationRequest.js +0 -103
- package/dist/src/lib/medicationRequest.js.map +0 -1
- package/dist/src/lib/medicationStatement.js.map +0 -1
- package/dist/src/lib/organization.js +0 -91
- package/dist/src/lib/organization.js.map +0 -1
- package/dist/src/lib/patient.js +0 -397
- package/dist/src/lib/patient.js.map +0 -1
- package/dist/src/lib/patient.test.js.map +0 -1
- package/dist/src/lib/practitioner.js +0 -161
- package/dist/src/lib/practitioner.js.map +0 -1
- package/index.ts +0 -30
- package/jest.config.js +0 -12
- package/release.config.js +0 -74
- package/src/helpers/patientFactory.ts +0 -13
- package/src/lib/allergyIntolerance.ts +0 -36
- package/src/lib/bundle.ts +0 -19
- package/src/lib/composition.ts +0 -153
- package/src/lib/condition.ts +0 -80
- package/src/lib/config.test.ts +0 -13
- package/src/lib/config.ts +0 -17
- package/src/lib/device.test.ts +0 -9
- package/src/lib/device.ts +0 -36
- package/src/lib/document-reference.ts +0 -102
- package/src/lib/immunization.ts +0 -64
- package/src/lib/medicationStatement.ts +0 -52
- package/src/lib/organization.ts +0 -89
- package/src/lib/patient.test.ts +0 -101
- package/src/lib/patient.ts +0 -411
- package/src/lib/practitioner.ts +0 -157
- package/tsconfig.test.json +0 -18
- package/tslint.json +0 -139
package/src/lib/organization.ts
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { getDominio, makeUrl } from './config';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Encode a organization from ANDES to FHIR
|
|
5
|
-
* @param {} organization
|
|
6
|
-
*/
|
|
7
|
-
export function encode(organization) {
|
|
8
|
-
let data = organization;
|
|
9
|
-
if (data) {
|
|
10
|
-
let identificadores: any[] = data.codigo.sisa ? [{
|
|
11
|
-
assigner: 'sisa',
|
|
12
|
-
value: data.codigo.sisa
|
|
13
|
-
}] : [];
|
|
14
|
-
if (data.codigo.cuie) {
|
|
15
|
-
identificadores.push({
|
|
16
|
-
assigner: 'cuie',
|
|
17
|
-
value: data.codigo.cuie
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
if (data.codigo.remediar) {
|
|
21
|
-
identificadores.push({
|
|
22
|
-
assigner: 'remediar',
|
|
23
|
-
value: data.codigo.remediar
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
if (data.codigo.sips) {
|
|
27
|
-
identificadores.push({
|
|
28
|
-
assigner: 'sips',
|
|
29
|
-
value: data.codigo.sips
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
identificadores.push({
|
|
33
|
-
system: makeUrl('Organization'),
|
|
34
|
-
value: data._id
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
let contactos = data.contacto ? data.contacto.map(unContacto => {
|
|
38
|
-
let cont = {
|
|
39
|
-
resourceType: 'ContactPoint',
|
|
40
|
-
value: unContacto.valor,
|
|
41
|
-
rank: unContacto.ranking,
|
|
42
|
-
};
|
|
43
|
-
switch (unContacto.tipo) {
|
|
44
|
-
case 'fijo':
|
|
45
|
-
cont['system'] = 'phone';
|
|
46
|
-
break;
|
|
47
|
-
case 'celular':
|
|
48
|
-
cont['system'] = 'phone';
|
|
49
|
-
break;
|
|
50
|
-
case 'email':
|
|
51
|
-
cont['system'] = 'email';
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
return cont;
|
|
55
|
-
}) : [];
|
|
56
|
-
// Parsea direcciones
|
|
57
|
-
let direcciones = data.direccion ? [{
|
|
58
|
-
resourceType: 'Address',
|
|
59
|
-
postalCode: data.direccion.codigoPostal ? data.direccion.codigoPostal : '',
|
|
60
|
-
line: [data.direccion.valor],
|
|
61
|
-
city: data.direccion.ubicacion.localidad ? data.direccion.ubicacion.localidad.nombre : '',
|
|
62
|
-
state: data.direccion.ubicacion.provincia ? data.direccion.ubicacion.provincia.nombre : '',
|
|
63
|
-
country: data.direccion.ubicacion.pais ? data.direccion.ubicacion.pais.nombre : '',
|
|
64
|
-
}] : [];
|
|
65
|
-
|
|
66
|
-
// Armamos la organizacion FHIR
|
|
67
|
-
let organizacionFHIR = {
|
|
68
|
-
id: data.id,
|
|
69
|
-
resourceType: 'Organization',
|
|
70
|
-
identifier: identificadores,
|
|
71
|
-
active: data.activo ? data.activo : null,
|
|
72
|
-
type: [{
|
|
73
|
-
resourceType: 'CodeableConcept',
|
|
74
|
-
text: data.tipoEstablecimiento ? data.tipoEstablecimiento.nombre : null,
|
|
75
|
-
}],
|
|
76
|
-
name: data.nombre ? data.nombre : null, // Name used for the organization
|
|
77
|
-
};
|
|
78
|
-
if (contactos.length > 0) { // A contact detail for the organization
|
|
79
|
-
organizacionFHIR['telecom'] = contactos;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (direcciones) { // An address for the organization
|
|
83
|
-
organizacionFHIR['address'] = direcciones;
|
|
84
|
-
}
|
|
85
|
-
return organizacionFHIR;
|
|
86
|
-
} else {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
}
|
package/src/lib/patient.test.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import * as patient from '../data/patient.json';
|
|
2
|
-
import { decode, encode } from './patient';
|
|
3
|
-
import { createPatient } from '../helpers/patientFactory';
|
|
4
|
-
|
|
5
|
-
const pacienteFhir = encode(patient);
|
|
6
|
-
|
|
7
|
-
describe('encode patient from ANDES to FHIR R4', () => {
|
|
8
|
-
test('Verify basic data', () => {
|
|
9
|
-
expect(pacienteFhir.resourceType).toBe('Patient');
|
|
10
|
-
const ident = pacienteFhir.identifier;
|
|
11
|
-
const id = ident?.find(t => t.system === 'http://www.renaper.gob.ar/dni');
|
|
12
|
-
expect(id?.value).toBe('42910660');
|
|
13
|
-
expect(id?.system).toBe('http://www.renaper.gob.ar/dni');
|
|
14
|
-
expect(pacienteFhir.active).toBe(true);
|
|
15
|
-
expect(pacienteFhir.name[0].use).toBe('official');
|
|
16
|
-
expect(pacienteFhir.name[0].resourceType).toBe('HumanName');
|
|
17
|
-
expect(pacienteFhir.name[0].family).toContain('PERINGA');
|
|
18
|
-
expect(pacienteFhir.name[0].family).toContain('PONCE');
|
|
19
|
-
expect(pacienteFhir.name[0].given).toContain('AGUSTIN');
|
|
20
|
-
expect(pacienteFhir.name[0].text).toBe('HUGO AGUSTIN PERINGA PONCE');
|
|
21
|
-
expect(pacienteFhir.gender).toBe('male');
|
|
22
|
-
expect(pacienteFhir.birthDate).toBe('1979-11-14');
|
|
23
|
-
});
|
|
24
|
-
test('Verify patient with contact information', () => {
|
|
25
|
-
// Phone;
|
|
26
|
-
expect(pacienteFhir.telecom[0].resourceType).toBe('ContactPoint');
|
|
27
|
-
expect(pacienteFhir.telecom[0].value).toBe('4462221');
|
|
28
|
-
expect(pacienteFhir.telecom[0].system).toBe('phone');
|
|
29
|
-
// Address;
|
|
30
|
-
expect(pacienteFhir.address[0].resourceType).toBe('Address');
|
|
31
|
-
expect(pacienteFhir.address[0].postalCode).toBe('8300');
|
|
32
|
-
expect(pacienteFhir.address[0].line).toContain('Enrique Santos Discepolo 1856');
|
|
33
|
-
expect(pacienteFhir.address[0].city).toBe('NEUQUEN');
|
|
34
|
-
expect(pacienteFhir.address[0].state).toBe('Neuquén');
|
|
35
|
-
expect(pacienteFhir.address[0].country).toBe('Argentina');
|
|
36
|
-
});
|
|
37
|
-
test('Verify patient with relationships', () => {
|
|
38
|
-
expect(pacienteFhir.contact[0].relationship[0].text).toBe('hijo/a');
|
|
39
|
-
expect(pacienteFhir.contact[0].name.resourceType).toBe('HumanName');
|
|
40
|
-
expect(pacienteFhir.contact[0].name.family).toContain('PERINGA');
|
|
41
|
-
expect(pacienteFhir.contact[0].name.given).toContain('JOSEFINA');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test('Maneja paciente con estado validado', () => {
|
|
45
|
-
const paciente = createPatient({ estado: 'validado' });
|
|
46
|
-
const fhir = encode(paciente);
|
|
47
|
-
expect(fhir.extension?.some(t => t.valueCode === 'validado')).toBeTruthy();
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
test('Maneja paciente con estado temporal', () => {
|
|
51
|
-
const paciente = createPatient({ estado: 'temporal' });
|
|
52
|
-
const fhir = encode(paciente);
|
|
53
|
-
expect(fhir.extension?.some(t => t.valueCode === 'temporal')).toBeTruthy();
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
test('Maneja paciente con estado nulo', () => {
|
|
57
|
-
const paciente = createPatient({ estado: null });
|
|
58
|
-
const fhir = encode(paciente);
|
|
59
|
-
expect(fhir.extension?.some(t => t.valueCode === 'temporal')).toBeTruthy();
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('Verifica organización que crea paciente', () => {
|
|
63
|
-
const fhir = pacienteFhir;
|
|
64
|
-
expect(fhir.managingOrganization.display).toContain('LABORATORIO');
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('Verifica dni extranjero', () => {
|
|
68
|
-
const paciente = createPatient({ tipoIdentificacion: 'dni extranjero', numeroIdentificacion: 'ABC123' });
|
|
69
|
-
const fhir = encode(paciente);
|
|
70
|
-
const id = fhir.identifier?.find(t => t.system === 'andes.gob.ar/sid/foreign-id');
|
|
71
|
-
expect(id?.value).toBe('ABC123');
|
|
72
|
-
expect(id?.system).toBe('andes.gob.ar/sid/foreign-id');
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('Verifica pasaporte', () => {
|
|
76
|
-
const paciente = createPatient({ tipoIdentificacion: 'pasaporte', numeroIdentificacion: 'ABC123CD' });
|
|
77
|
-
const fhir = encode(paciente);
|
|
78
|
-
const id = fhir.identifier?.find(t => t.system === 'andes.gob.ar/sid/passport');
|
|
79
|
-
expect(id?.value).toBe('ABC123CD');
|
|
80
|
-
expect(id?.system).toBe('andes.gob.ar/sid/passport');
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
describe('decode patient from FHIR R4 to ANDES', () => {
|
|
85
|
-
it('Verifica dni extranjero', () => {
|
|
86
|
-
const paciente = createPatient({ tipoIdentificacion: 'dni extranjero', numeroIdentificacion: 'ABC123' });
|
|
87
|
-
const fhirEncode = encode(paciente);
|
|
88
|
-
const fhirDecode = decode(fhirEncode);
|
|
89
|
-
expect(fhirDecode?.tipoIdentificacion).toBe('dni extranjero');
|
|
90
|
-
expect(fhirDecode?.numeroIdentificacion).toBe('ABC123');
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('Verifica pasaporte', () => {
|
|
94
|
-
const paciente = createPatient({ tipoIdentificacion: 'pasaporte', numeroIdentificacion: 'ABC123CD' });
|
|
95
|
-
const fhirEncode = encode(paciente);
|
|
96
|
-
const fhirDecode = decode(fhirEncode);
|
|
97
|
-
expect(fhirDecode?.tipoIdentificacion).toBe('pasaporte');
|
|
98
|
-
expect(fhirDecode?.numeroIdentificacion).toBe('ABC123CD');
|
|
99
|
-
expect(fhirDecode?.estado).toBe('temporal');
|
|
100
|
-
});
|
|
101
|
-
});
|
package/src/lib/patient.ts
DELETED
|
@@ -1,411 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { getDominio, makeUrl } from './config';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Encode a patient from ANDES to FHIR
|
|
6
|
-
* @param {} patient
|
|
7
|
-
*/
|
|
8
|
-
export function encode(patient) {
|
|
9
|
-
if (patient) {
|
|
10
|
-
const identificadores: any = [];
|
|
11
|
-
identificadores.push({
|
|
12
|
-
system: getDominio(),
|
|
13
|
-
value: patient._id
|
|
14
|
-
});
|
|
15
|
-
if (patient.documento) {
|
|
16
|
-
identificadores.push({
|
|
17
|
-
system: 'http://www.renaper.gob.ar/dni',
|
|
18
|
-
value: patient.documento
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
if (patient.cuil) {
|
|
22
|
-
identificadores.push({
|
|
23
|
-
system: 'http://www.renaper.gob.ar/cuil',
|
|
24
|
-
value: patient.cuil
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
if (patient.numeroIdentificacion) {
|
|
28
|
-
if (patient.tipoIdentificacion === 'dni extranjero') {
|
|
29
|
-
identificadores.push({
|
|
30
|
-
system: 'andes.gob.ar/sid/foreign-id',
|
|
31
|
-
value: patient.numeroIdentificacion
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
if (patient.tipoIdentificacion === 'pasaporte') {
|
|
35
|
-
identificadores.push({
|
|
36
|
-
system: 'andes.gob.ar/sid/passport',
|
|
37
|
-
value: patient.numeroIdentificacion
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
// Parsea contactos
|
|
42
|
-
let contactos = patient.contacto ? patient.contacto.filter(c => c.valor).map(unContacto => {
|
|
43
|
-
let cont = {
|
|
44
|
-
resourceType: 'ContactPoint',
|
|
45
|
-
value: unContacto.valor,
|
|
46
|
-
rank: unContacto.ranking,
|
|
47
|
-
};
|
|
48
|
-
switch (unContacto.tipo) {
|
|
49
|
-
case 'fijo':
|
|
50
|
-
cont['system'] = 'phone';
|
|
51
|
-
break;
|
|
52
|
-
case 'celular':
|
|
53
|
-
cont['system'] = 'phone';
|
|
54
|
-
break;
|
|
55
|
-
case 'email':
|
|
56
|
-
cont['system'] = 'email';
|
|
57
|
-
break;
|
|
58
|
-
}
|
|
59
|
-
return cont;
|
|
60
|
-
}) : [];
|
|
61
|
-
// Parsea direcciones
|
|
62
|
-
let direcciones = patient.direccion ? patient.direccion.filter(dir => dir.ubicacion.localidad).map(unaDireccion => {
|
|
63
|
-
let direc = {
|
|
64
|
-
resourceType: 'Address',
|
|
65
|
-
postalCode: unaDireccion.codigoPostal ? unaDireccion.codigoPostal : '',
|
|
66
|
-
line: [unaDireccion.valor],
|
|
67
|
-
city: unaDireccion.ubicacion.localidad ? unaDireccion.ubicacion.localidad.nombre : '',
|
|
68
|
-
state: unaDireccion.ubicacion.provincia ? unaDireccion.ubicacion.provincia.nombre : '',
|
|
69
|
-
country: unaDireccion.ubicacion.pais ? unaDireccion.ubicacion.pais.nombre : '',
|
|
70
|
-
};
|
|
71
|
-
return direc;
|
|
72
|
-
}) : [];
|
|
73
|
-
// Parsea relaciones
|
|
74
|
-
let relaciones = patient.relaciones ? patient.relaciones.filter(r => !!r.relacion).map(unaRelacion => {
|
|
75
|
-
let relacion = {
|
|
76
|
-
relationship: [{
|
|
77
|
-
text: unaRelacion.relacion.nombre
|
|
78
|
-
}], // The kind of relationship
|
|
79
|
-
name: {
|
|
80
|
-
resourceType: 'HumanName',
|
|
81
|
-
family: unaRelacion.apellido.split(' '), // Family name (often called 'Surname')
|
|
82
|
-
given: unaRelacion.nombre.split(' '), // Given names (not always 'first'). Includes middle names
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
return relacion;
|
|
86
|
-
}) : [];
|
|
87
|
-
let genero;
|
|
88
|
-
switch (patient.genero) {
|
|
89
|
-
case 'femenino':
|
|
90
|
-
genero = 'female';
|
|
91
|
-
break;
|
|
92
|
-
case 'masculino':
|
|
93
|
-
genero = 'male';
|
|
94
|
-
break;
|
|
95
|
-
case 'otro':
|
|
96
|
-
genero = 'other';
|
|
97
|
-
break;
|
|
98
|
-
}
|
|
99
|
-
let pacienteFHIR: any = {
|
|
100
|
-
resourceType: 'Patient',
|
|
101
|
-
id: patient._id,
|
|
102
|
-
identifier: identificadores,
|
|
103
|
-
active: patient.activo ? patient.activo : null, // Whether this patient's record is in active use
|
|
104
|
-
name: [{
|
|
105
|
-
use: 'official',
|
|
106
|
-
resourceType: 'HumanName',
|
|
107
|
-
family: patient.apellido.split(' '),
|
|
108
|
-
given: patient.nombre.split(' '),
|
|
109
|
-
text: `${patient.nombre} ${patient.apellido}`
|
|
110
|
-
}],
|
|
111
|
-
gender: genero, // male | female | other | unknown
|
|
112
|
-
birthDate: patient.fechaNacimiento ? typeof patient.fechaNacimiento === 'string' ? new Date(patient.fechaNacimiento).toISOString().slice(0, 10) : patient.fechaNacimiento.toISOString().slice(0, 10) : null,
|
|
113
|
-
extension: [{
|
|
114
|
-
url: 'andes.gob.ar/fhir/StructureDefinition/patient-status',
|
|
115
|
-
valueCode: patient.estado ? patient.estado : 'temporal' // validado | temporal
|
|
116
|
-
}]
|
|
117
|
-
};
|
|
118
|
-
if (patient.fechaFallecimiento) {
|
|
119
|
-
pacienteFHIR.deceasedDateTime = typeof patient.fechaFallecimiento === 'string' ? new Date(patient.fechaFallecimiento.toISOString().slice(0, 10)) : patient.fechaFallecimiento.toISOString().slice(0, 10);
|
|
120
|
-
}
|
|
121
|
-
if (patient.estadoCivil) {
|
|
122
|
-
let estadoCivil;
|
|
123
|
-
switch (patient.estadoCivil) {
|
|
124
|
-
case 'casado':
|
|
125
|
-
estadoCivil = 'Married';
|
|
126
|
-
break;
|
|
127
|
-
case 'divorciado':
|
|
128
|
-
estadoCivil = 'Divorced';
|
|
129
|
-
break;
|
|
130
|
-
case 'viudo':
|
|
131
|
-
estadoCivil = 'Widowed';
|
|
132
|
-
break;
|
|
133
|
-
case 'soltero':
|
|
134
|
-
estadoCivil = 'unmarried';
|
|
135
|
-
break;
|
|
136
|
-
default:
|
|
137
|
-
estadoCivil = 'unknown';
|
|
138
|
-
break;
|
|
139
|
-
}
|
|
140
|
-
pacienteFHIR['maritalStatus'] = {
|
|
141
|
-
text: estadoCivil
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
if (patient.foto) {
|
|
145
|
-
pacienteFHIR['photo'] = [{
|
|
146
|
-
patient: patient.foto
|
|
147
|
-
}];
|
|
148
|
-
}
|
|
149
|
-
if (contactos.length > 0) { // A contact detail for the individual
|
|
150
|
-
pacienteFHIR['telecom'] = contactos;
|
|
151
|
-
}
|
|
152
|
-
if (direcciones.length > 0) { // Addresses for the individual
|
|
153
|
-
pacienteFHIR['address'] = direcciones;
|
|
154
|
-
}
|
|
155
|
-
if (relaciones.length > 0) { // A contact party (e.g. guardian, partner, friend) for the patient
|
|
156
|
-
pacienteFHIR['contact'] = relaciones;
|
|
157
|
-
}
|
|
158
|
-
let managingOrganization = {
|
|
159
|
-
reference: patient.createdBy.organizacion.id,
|
|
160
|
-
display: patient.createdBy.organizacion.nombre
|
|
161
|
-
};
|
|
162
|
-
pacienteFHIR['managingOrganization'] = managingOrganization;
|
|
163
|
-
return pacienteFHIR;
|
|
164
|
-
} else {
|
|
165
|
-
return null;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Decode a patient from FHIR to ANDES
|
|
171
|
-
* @param {} patient
|
|
172
|
-
*/
|
|
173
|
-
export function decode(patient) {
|
|
174
|
-
let genero: string;
|
|
175
|
-
let sexo: string;
|
|
176
|
-
// Cuando el paciente viene por FHIR suponemos el valor del genero tanto para nuestro field genero como sexo
|
|
177
|
-
switch (patient.gender) {
|
|
178
|
-
case 'female':
|
|
179
|
-
genero = 'femenino';
|
|
180
|
-
sexo = 'femenino';
|
|
181
|
-
break;
|
|
182
|
-
case 'male':
|
|
183
|
-
genero = 'masculino';
|
|
184
|
-
sexo = 'masculino';
|
|
185
|
-
break;
|
|
186
|
-
case 'other':
|
|
187
|
-
genero = 'otro';
|
|
188
|
-
sexo = 'otro';
|
|
189
|
-
break;
|
|
190
|
-
}
|
|
191
|
-
function getValue(items, key) {
|
|
192
|
-
const element = items.find(el => el.system === key);
|
|
193
|
-
if (element) {
|
|
194
|
-
return element.value;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
const tiposIdentificacion = ['andes.gob.ar/sid/foreign-id', 'andes.gob.ar/sid/passport'];
|
|
198
|
-
const tipoAndes = ['dni extranjero', 'pasaporte'];
|
|
199
|
-
let tipoIdentificacion;
|
|
200
|
-
let numeroIdentificacion;
|
|
201
|
-
for (let i = 0; i < tiposIdentificacion.length; i++) {
|
|
202
|
-
if (getValue(patient.identifier, tiposIdentificacion[i])) {
|
|
203
|
-
tipoIdentificacion = tipoAndes[i];
|
|
204
|
-
numeroIdentificacion = getValue(patient.identifier, tiposIdentificacion[i]);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
let pacienteAndes = {
|
|
208
|
-
id: getValue(patient.identifier, makeUrl('Patient')),
|
|
209
|
-
documento: getValue(patient.identifier, 'http://www.renaper.gob.ar/dni'),
|
|
210
|
-
tipoIdentificacion,
|
|
211
|
-
numeroIdentificacion,
|
|
212
|
-
nombre: patient.name[0].given.join().replace(',', ' '),
|
|
213
|
-
apellido: Array.isArray(patient.name[0].family) ? patient.name[0].family.join().replace(',', ' ') : patient.name[0].family,
|
|
214
|
-
fechaNacimiento: patient.birthDate,
|
|
215
|
-
genero,
|
|
216
|
-
sexo,
|
|
217
|
-
estado: 'temporal', // Todos los pacientes que recibimos por Fhir son considerados temporales en su conversión.
|
|
218
|
-
createdBy: null
|
|
219
|
-
};
|
|
220
|
-
let contactos = patient.telecom ? patient.telecom.map(unContacto => {
|
|
221
|
-
let cont = {
|
|
222
|
-
valor: unContacto.value,
|
|
223
|
-
ranking: unContacto.rank
|
|
224
|
-
};
|
|
225
|
-
switch (unContacto.system) {
|
|
226
|
-
case 'phone':
|
|
227
|
-
cont['tipo'] = 'celular';
|
|
228
|
-
break;
|
|
229
|
-
case 'email':
|
|
230
|
-
cont['tipo'] = 'email';
|
|
231
|
-
break;
|
|
232
|
-
}
|
|
233
|
-
return cont;
|
|
234
|
-
}) : [];
|
|
235
|
-
|
|
236
|
-
let relaciones = patient.contact ? patient.contact.map(aContact => {
|
|
237
|
-
let relacion = {
|
|
238
|
-
relacion: {
|
|
239
|
-
nombre: aContact.relationship[0].text
|
|
240
|
-
},
|
|
241
|
-
nombre: aContact.name.given.join().replace(',', ' '),
|
|
242
|
-
apellido: aContact.name.family
|
|
243
|
-
};
|
|
244
|
-
return relacion;
|
|
245
|
-
}) : [];
|
|
246
|
-
|
|
247
|
-
if (patient.maritalStatus) {
|
|
248
|
-
let estadoCivil;
|
|
249
|
-
switch (patient.maritalStatus['text']) {
|
|
250
|
-
case 'Married':
|
|
251
|
-
estadoCivil = 'casado';
|
|
252
|
-
break;
|
|
253
|
-
case 'Divorced':
|
|
254
|
-
estadoCivil = 'divorciado';
|
|
255
|
-
break;
|
|
256
|
-
case 'Widowed':
|
|
257
|
-
estadoCivil = 'viudo';
|
|
258
|
-
break;
|
|
259
|
-
case 'unmarried':
|
|
260
|
-
estadoCivil = 'soltero';
|
|
261
|
-
break;
|
|
262
|
-
default:
|
|
263
|
-
estadoCivil = 'otro';
|
|
264
|
-
break;
|
|
265
|
-
}
|
|
266
|
-
pacienteAndes['estadoCivil'] = estadoCivil;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
let direcciones = patient.address ? patient.address.map(unaDireccion => {
|
|
270
|
-
let dir = {
|
|
271
|
-
activo: true,
|
|
272
|
-
valor: unaDireccion.line,
|
|
273
|
-
codigoPostal: unaDireccion.postalCode,
|
|
274
|
-
// TODO: En un MATETIME ver si la información de pais, provincia, localidad
|
|
275
|
-
// se delega en el insert o update. Y este decoder sólo guarda la info tal cual viene.
|
|
276
|
-
ubicacion: {
|
|
277
|
-
pais: unaDireccion.country,
|
|
278
|
-
provincia: unaDireccion.state,
|
|
279
|
-
localidad: unaDireccion.city
|
|
280
|
-
}
|
|
281
|
-
};
|
|
282
|
-
return dir;
|
|
283
|
-
}) : [];
|
|
284
|
-
|
|
285
|
-
pacienteAndes['direccion'] = direcciones;
|
|
286
|
-
|
|
287
|
-
if (patient.active) {
|
|
288
|
-
pacienteAndes['activo'] = patient.active;
|
|
289
|
-
}
|
|
290
|
-
if (contactos.length > 0) {
|
|
291
|
-
pacienteAndes['contacto'] = contactos;
|
|
292
|
-
}
|
|
293
|
-
if (patient.photo) { // Image of the patient
|
|
294
|
-
pacienteAndes['foto'] = patient.photo[0].data;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
if (patient.contact) {
|
|
298
|
-
pacienteAndes['relaciones'] = relaciones;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
if (patient.managingOrganization) {
|
|
302
|
-
pacienteAndes['createdBy'] = {
|
|
303
|
-
organizacion: {
|
|
304
|
-
id: patient.managingOrganization.reference,
|
|
305
|
-
nombre: patient.managingOrganization.display
|
|
306
|
-
}
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
return pacienteAndes;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* Verify if a patient has a FHIR format
|
|
315
|
-
* @param {*} patient
|
|
316
|
-
*/
|
|
317
|
-
export function verify(patient) {
|
|
318
|
-
let respuesta = true;
|
|
319
|
-
let fieldVerified = Object.keys(patient).every(pacienteFHIRFields);
|
|
320
|
-
// Verificamos que las key esten contenidas en los conjuntos mínimos pacienteFHIRField
|
|
321
|
-
if (fieldVerified) {
|
|
322
|
-
respuesta = ('resourceType' in patient) && patient.resourceType === 'Patient';
|
|
323
|
-
respuesta = respuesta && ('identifier' in patient);
|
|
324
|
-
if (patient.identifier.length > 0) {
|
|
325
|
-
patient.identifier.forEach(anIdentifier => respuesta = respuesta && Object.keys(anIdentifier).every(identifierFields));
|
|
326
|
-
}
|
|
327
|
-
patient.name.forEach(aName => respuesta = respuesta && validName(aName));
|
|
328
|
-
if (patient.active) {
|
|
329
|
-
respuesta = respuesta && (typeof patient.active === 'boolean');
|
|
330
|
-
}
|
|
331
|
-
if (patient.telecom) {
|
|
332
|
-
patient.telecom.forEach(aTelecom => respuesta = respuesta && Object.keys(aTelecom).every(telecomFields));
|
|
333
|
-
}
|
|
334
|
-
if (patient.gender) {
|
|
335
|
-
respuesta = respuesta && patient.gender.match('male|female|other|unknown') != null;
|
|
336
|
-
}
|
|
337
|
-
if (patient.birthDate) {
|
|
338
|
-
respuesta = respuesta && typeof patient.birthDate === 'string'; // TODO: Algun control de que tenga formato Date
|
|
339
|
-
}
|
|
340
|
-
if (patient.deceasedDateTime) {
|
|
341
|
-
respuesta = respuesta && typeof patient.deceasedDateTime === 'string'; // TODO: Algun control de que tenga formato DateTime
|
|
342
|
-
}
|
|
343
|
-
if (patient.address) {
|
|
344
|
-
patient.address.forEach(anAddress => respuesta = respuesta && Object.keys(anAddress).every(addressFields));
|
|
345
|
-
}
|
|
346
|
-
if (patient.maritalStatus && patient.maritalStatus.text) {
|
|
347
|
-
respuesta = respuesta && Object.keys(patient.maritalStatus).every(codingFields)
|
|
348
|
-
&& typeof patient.maritalStatus.text === 'string'
|
|
349
|
-
&& patient.maritalStatus.text.match('Married|Divorced|Widowed|unmarried|unknown') != null;
|
|
350
|
-
}
|
|
351
|
-
if (patient.photo) {
|
|
352
|
-
patient.photo.forEach(aPhoto => respuesta = respuesta && Object.keys(aPhoto).every(photoFields));
|
|
353
|
-
}
|
|
354
|
-
if (patient.contact) {
|
|
355
|
-
patient.contact.forEach(aContact => {
|
|
356
|
-
if (aContact.relationship) {
|
|
357
|
-
aContact.relationship.forEach(aRelation => respuesta = respuesta && Object.keys(aRelation).every(codingFields));
|
|
358
|
-
}
|
|
359
|
-
if (aContact.name) {
|
|
360
|
-
respuesta = respuesta && validName(aContact.name);
|
|
361
|
-
}
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
} else {
|
|
365
|
-
respuesta = fieldVerified; // No cumple con los campos estandar de FHIR
|
|
366
|
-
}
|
|
367
|
-
return respuesta;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
function pacienteFHIRFields(elem) {
|
|
371
|
-
return elem.match('resourceType|identifier|active|name|telecom|gender|birthDate|deceasedBoolean|deceasedDateTime|address|maritalStatus|photo|contact') != null;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
function identifierFields(elem) {
|
|
375
|
-
return elem.match('use|type|system|value|period|assigner') != null;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
function nameFields(elem) {
|
|
379
|
-
return elem.match('resourceType|family|given') != null;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
function telecomFields(elem) {
|
|
383
|
-
return elem.match('resourceType|system|value|use|rank|period') != null;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
function addressFields(elem) {
|
|
387
|
-
return elem.match('resourceType|use|type|text|line|city|district|state|postalCode|country|period') != null;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
function codingFields(elem) {
|
|
391
|
-
return elem.match('coding|text') != null;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
function photoFields(elem) {
|
|
395
|
-
return elem.match('contentType|language|data|url|size|hash|title|creation') != null;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
function contactFields(elem) {
|
|
399
|
-
return elem.match('relationship|name|telecom|address|gender|organization|period') != null;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
function validName(aName) {
|
|
403
|
-
return Object.keys(aName).every(nameFields) && ('resourceType' in aName) && aName.resourceType === 'HumanName' &&
|
|
404
|
-
('family' in aName) && Array.isArray(aName.family) && aName.family.every(areStrings) &&
|
|
405
|
-
('given' in aName) && Array.isArray(aName.given) && aName.given.every(areStrings);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
function areStrings(elem) {
|
|
409
|
-
return typeof elem === 'string';
|
|
410
|
-
}
|
|
411
|
-
|