@phenyxhealth/importer 1.1.7
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/package.json +22 -0
- package/src/controllers/doctors.js +26 -0
- package/src/controllers/global.js +84 -0
- package/src/controllers/linacs.js +34 -0
- package/src/controllers/login.js +15 -0
- package/src/index.js +47 -0
- package/src/scripts/clearPatients.js +20 -0
- package/src/scripts/importer-old.js +435 -0
- package/src/scripts/importer.js +346 -0
- package/src/services/phenyxApi.js +483 -0
- package/src/services/phenyxApiInstance.js +5 -0
- package/src/utils/ask.js +19 -0
- package/src/utils/colors.js +42 -0
- package/src/utils/dates.js +21 -0
- package/src/utils/text.js +85 -0
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@phenyxhealth/importer",
|
|
3
|
+
"version": "1.1.7",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Imports a Phenyx-compatible JSON file with patients into a PhenyxHealth instance.",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"main": "./src/index.js",
|
|
10
|
+
"bin": {
|
|
11
|
+
"importer": "./src/index.js"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"dev": "node ./src/index.js test/importer-config.json"
|
|
15
|
+
},
|
|
16
|
+
"author": "Diego M. Béjar",
|
|
17
|
+
"license": "ISC",
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@dmbejar/json-files": "^1.1.6",
|
|
20
|
+
"uuid": "13.0.0"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import ApiInstance from "../services/phenyxApiInstance.js";
|
|
2
|
+
|
|
3
|
+
const beSureDoctorExists = async (toBe) => {
|
|
4
|
+
const currentDoctors = await ApiInstance.getHumanResources();
|
|
5
|
+
|
|
6
|
+
for (const doctor of toBe) {
|
|
7
|
+
const doctorName = doctor.name;
|
|
8
|
+
const doctorTypeId = ApiInstance.getGlobalInfoElementId(ApiInstance.globalTypes.humanResources, ApiInstance.globalTypes.humanResources.values[doctor.hrGroup]);
|
|
9
|
+
const doctorExists = !!currentDoctors
|
|
10
|
+
.find(item => item.name === doctorName && item.typeId === doctorTypeId);
|
|
11
|
+
|
|
12
|
+
if (!doctorExists) {
|
|
13
|
+
console.log(`Adding ${doctor.name}...`);
|
|
14
|
+
await ApiInstance.createHumanResource({
|
|
15
|
+
name: doctor.name,
|
|
16
|
+
typeId: doctorTypeId,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return await ApiInstance.getHumanResources();
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export {
|
|
25
|
+
beSureDoctorExists,
|
|
26
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { v4 } from 'uuid';
|
|
2
|
+
import ApiInstance from '../services/phenyxApiInstance.js';
|
|
3
|
+
import { getContrastingColor } from '../utils/colors.js';
|
|
4
|
+
|
|
5
|
+
const checkGlobals = async (mustBe, extraValues = []) => {
|
|
6
|
+
const {
|
|
7
|
+
name,
|
|
8
|
+
values = {},
|
|
9
|
+
} = mustBe;
|
|
10
|
+
|
|
11
|
+
// Sacar los valores de global
|
|
12
|
+
const currentContent = ApiInstance.getGlobalInfo(mustBe);
|
|
13
|
+
|
|
14
|
+
if (!currentContent) throw new Error(`Global info ${name} not found`);
|
|
15
|
+
|
|
16
|
+
// Añadir los valores extra
|
|
17
|
+
for (const extraValue of extraValues) {
|
|
18
|
+
if (!values[extraValue]) {
|
|
19
|
+
values[extraValue] = extraValue;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Asegurarnos que existen los tipos especificadas
|
|
24
|
+
const valuesToCheck = [];
|
|
25
|
+
for (const key of Object.keys(values)) {
|
|
26
|
+
valuesToCheck.push(values[key]);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Meter la info
|
|
30
|
+
if (valuesToCheck.length) await beSureGlobalExists(currentContent, valuesToCheck);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const beSureGlobalExists = async (currentList, toBeList) => {
|
|
34
|
+
const {
|
|
35
|
+
id,
|
|
36
|
+
name,
|
|
37
|
+
elements,
|
|
38
|
+
} = currentList;
|
|
39
|
+
|
|
40
|
+
let listUpdated = false;
|
|
41
|
+
|
|
42
|
+
for (const element of currentList.elements) {
|
|
43
|
+
if (!element.modality) {
|
|
44
|
+
element.modality = '';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
for (const item of toBeList) {
|
|
49
|
+
const element = elements.find(element => element.name === item && !element.isDeleted);
|
|
50
|
+
|
|
51
|
+
if (!element) {
|
|
52
|
+
console.log(`Adding ${item} to ${name}...`);
|
|
53
|
+
const creationDate = new Date().toISOString();
|
|
54
|
+
elements.push({
|
|
55
|
+
id: v4(),
|
|
56
|
+
color: getContrastingColor(),
|
|
57
|
+
name: item,
|
|
58
|
+
createdAt: creationDate,
|
|
59
|
+
updatedAt: creationDate,
|
|
60
|
+
isDeleted: false,
|
|
61
|
+
modality: '',
|
|
62
|
+
})
|
|
63
|
+
listUpdated = true;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!element.color) {
|
|
68
|
+
element.color = getContrastingColor();
|
|
69
|
+
element.updatedAt = new Date().toISOString();
|
|
70
|
+
listUpdated = true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if(!element.modality) {
|
|
74
|
+
element.modality = '';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (listUpdated) await ApiInstance.updateGlobalInfo(id, currentList);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export {
|
|
82
|
+
checkGlobals,
|
|
83
|
+
beSureGlobalExists,
|
|
84
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import ApiInstance from '../services/phenyxApiInstance.js';
|
|
2
|
+
|
|
3
|
+
const beSureLinacsExists = async (toBe) => {
|
|
4
|
+
// Sacar todos los recursos
|
|
5
|
+
const resources = await ApiInstance.getResources();
|
|
6
|
+
// Sacar el typeId de LINAC
|
|
7
|
+
const linacsTypeId = (await ApiInstance.getResourcesTypes())
|
|
8
|
+
.find(type => type.name === 'LINAC')
|
|
9
|
+
.id;
|
|
10
|
+
|
|
11
|
+
// Sacar solo los LINACs
|
|
12
|
+
const existingLinacs = resources.filter(item => item.typeId === linacsTypeId);
|
|
13
|
+
|
|
14
|
+
// Crear los que falten
|
|
15
|
+
for (const linac of toBe) {
|
|
16
|
+
if (!existingLinacs.find(item => item.name === linac)) {
|
|
17
|
+
console.log(`Adding ${linac}...`);
|
|
18
|
+
await ApiInstance.createResource({
|
|
19
|
+
name: linac,
|
|
20
|
+
typeId: linacsTypeId,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const updatedLinacs = await ApiInstance.getResources();
|
|
26
|
+
|
|
27
|
+
const response = updatedLinacs.filter(item => item.typeId === linacsTypeId);
|
|
28
|
+
|
|
29
|
+
return response;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export {
|
|
33
|
+
beSureLinacsExists,
|
|
34
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import ApiInstance from '../services/phenyxApiInstance.js';
|
|
2
|
+
|
|
3
|
+
const login = (config) => {
|
|
4
|
+
const {
|
|
5
|
+
apiUrl: apiHost,
|
|
6
|
+
apiUser: user,
|
|
7
|
+
apiPwd: password,
|
|
8
|
+
} = config;
|
|
9
|
+
|
|
10
|
+
return ApiInstance.login({ apiHost, user, password });
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
login,
|
|
15
|
+
};
|
package/src/index.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { loadJson } from "@dmbejar/json-files";
|
|
5
|
+
import { ask } from "./utils/ask.js";
|
|
6
|
+
import { clearPatients } from "./scripts/clearPatients.js";
|
|
7
|
+
import { importer } from "./scripts/importer.js";
|
|
8
|
+
|
|
9
|
+
const work = async () => {
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
|
|
12
|
+
if (args.length === 0) {
|
|
13
|
+
console.log('No se proporcionaron argumentos.');
|
|
14
|
+
console.log('Uso: npx @phenyxhealth/importer <archivo.json>');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const configFileName = args[0];
|
|
19
|
+
const config = loadJson({ fileName: path.resolve(process.cwd(), configFileName) });
|
|
20
|
+
|
|
21
|
+
console.log('Leyendo configuración desde:', configFileName);
|
|
22
|
+
|
|
23
|
+
if (!config.ok) {
|
|
24
|
+
console.log(config.error);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (config.data.deleteExistingPatients) {
|
|
29
|
+
const verifyDelete = 'yes, delete all';
|
|
30
|
+
|
|
31
|
+
const deletePatients = await ask(`Want to delete all patients before importing? ¡This operation is irreversible! Write "${verifyDelete}" to confirm: `);
|
|
32
|
+
|
|
33
|
+
if (deletePatients.toLowerCase().trim() === verifyDelete) {
|
|
34
|
+
await clearPatients(config.data);
|
|
35
|
+
} else {
|
|
36
|
+
console.log('Skipping patients deletion');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const folder = configFileName.substring(0, configFileName.lastIndexOf('/'));
|
|
41
|
+
|
|
42
|
+
if(folder) process.chdir(folder);
|
|
43
|
+
|
|
44
|
+
await importer(config.data);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
work();
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import ApiInstance from '../services/phenyxApiInstance.js';
|
|
2
|
+
import { login } from '../controllers/login.js';
|
|
3
|
+
|
|
4
|
+
const clearPatients = async (config) => {
|
|
5
|
+
await login(config);
|
|
6
|
+
|
|
7
|
+
const allPatients = await ApiInstance.getPatients();
|
|
8
|
+
const allPatientsIds = allPatients.map(p => p.id);
|
|
9
|
+
|
|
10
|
+
for (const patientId of allPatientsIds) {
|
|
11
|
+
console.log(`Deleting patient ${patientId}`);
|
|
12
|
+
await ApiInstance.deletePatient(patientId);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
console.log('All patients deleted');
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
clearPatients,
|
|
20
|
+
}
|
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { loadJson } from '@dmbejar/json-files';
|
|
3
|
+
import ApiInstance from '../services/phenyxApiInstance.js';
|
|
4
|
+
import { login } from '../controllers/login.js';
|
|
5
|
+
import { lowerCaseList, getListFromColumn } from '../utils/text.js';
|
|
6
|
+
import { checkGlobals } from '../controllers/global.js';
|
|
7
|
+
import { beSureDoctorExists } from '../controllers/doctors.js';
|
|
8
|
+
import { today } from '../utils/dates.js';
|
|
9
|
+
import { beSureLinacsExists } from '../controllers/linacs.js';
|
|
10
|
+
|
|
11
|
+
const importer = async (config) => {
|
|
12
|
+
// Config
|
|
13
|
+
ApiInstance.showLogs(config.showLogs);
|
|
14
|
+
|
|
15
|
+
const {
|
|
16
|
+
inputFile,
|
|
17
|
+
} = config;
|
|
18
|
+
|
|
19
|
+
console.log(`Importing patients from "${inputFile}"...`);
|
|
20
|
+
|
|
21
|
+
const {
|
|
22
|
+
ok: loadOk,
|
|
23
|
+
error: patientsError,
|
|
24
|
+
data: patients,
|
|
25
|
+
} = loadJson({ fileName: path.resolve(process.cwd(), inputFile) });
|
|
26
|
+
|
|
27
|
+
if (!loadOk) {
|
|
28
|
+
console.error('Error loading input file:', patientsError);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
console.log('Verifying globals...');
|
|
33
|
+
|
|
34
|
+
await login(config);
|
|
35
|
+
|
|
36
|
+
// check globals
|
|
37
|
+
checkGlobals(ApiInstance.globalTypes.sendingDepartment, lowerCaseList(getListFromColumn(patients, 'sendingDepartment')));
|
|
38
|
+
checkGlobals(ApiInstance.globalTypes.cei9, getListFromColumn(patients, 'cei9'));
|
|
39
|
+
checkGlobals(ApiInstance.globalTypes.treatmentClass, lowerCaseList(getListFromColumn(patients, 'treatmentClass')));
|
|
40
|
+
checkGlobals(ApiInstance.globalTypes.treatmentSubClass, lowerCaseList(getListFromColumn(patients, 'treatmentSubClass')));
|
|
41
|
+
checkGlobals(ApiInstance.globalTypes.treatmentTechnique, getListFromColumn(patients, 'treatmentTechnique'));
|
|
42
|
+
checkGlobals(ApiInstance.globalTypes.ctSimProtocols, getListFromColumn(patients, 'simulationProtocol'));
|
|
43
|
+
|
|
44
|
+
// Dar de alta cada LINAC que no exista
|
|
45
|
+
const linacs = await beSureLinacsExists(getListFromColumn(patients, 'confirmedLinac'));
|
|
46
|
+
|
|
47
|
+
// Dar de alta cada médico que no exista
|
|
48
|
+
const radOncs = await beSureDoctorExists(getListFromColumn(patients, 'assignedRadOnc', 'peerReviewedDoctor'), ApiInstance.globalTypes.humanResources.values.RadOnc);
|
|
49
|
+
const medPhys = await beSureDoctorExists(getListFromColumn(patients, 'dosimetryMedPhys'), ApiInstance.globalTypes.humanResources.values.MedPhys);
|
|
50
|
+
|
|
51
|
+
// Verificar los defaults
|
|
52
|
+
const defaultCompatibleLinacs = ApiInstance.defaultCompatibleLinacs;
|
|
53
|
+
|
|
54
|
+
if (!defaultCompatibleLinacs.length) {
|
|
55
|
+
console.log('\n\nERROR: No default compatible linacs found');
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const defaultDuration = ApiInstance.defaultDuration;
|
|
60
|
+
if (!defaultDuration) {
|
|
61
|
+
console.log('\n\nERROR: No default duration found');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Los pacientes
|
|
66
|
+
const allPatients = await ApiInstance.getPatients();
|
|
67
|
+
const allPatientsIds = allPatients.map(p => p.patientId);
|
|
68
|
+
|
|
69
|
+
let contadorPacientes = 0;
|
|
70
|
+
const ignoredPatients = [];
|
|
71
|
+
|
|
72
|
+
console.log('Uploading patients...');
|
|
73
|
+
|
|
74
|
+
// Alta de los pacientes
|
|
75
|
+
for (const patientInfo of patients) {
|
|
76
|
+
const {
|
|
77
|
+
patientId,
|
|
78
|
+
registrationDate,
|
|
79
|
+
assignedRadOnc,
|
|
80
|
+
peerReviewedDoctor,
|
|
81
|
+
peerReviewedStatus,
|
|
82
|
+
sendingDepartment,
|
|
83
|
+
firstConsultDate,
|
|
84
|
+
cei9,
|
|
85
|
+
tnm,
|
|
86
|
+
stage,
|
|
87
|
+
treatmentClass,
|
|
88
|
+
treatmentSubClass,
|
|
89
|
+
treatmentTechnique,
|
|
90
|
+
sessionsCompleted,
|
|
91
|
+
sessionsTotal,
|
|
92
|
+
fractionationPattern,
|
|
93
|
+
ctAppDate,
|
|
94
|
+
notificationDate,
|
|
95
|
+
confirmedDate,
|
|
96
|
+
simulationProtocol,
|
|
97
|
+
qaCompletedDate,
|
|
98
|
+
confirmedLinac,
|
|
99
|
+
dosimetryMedPhys,
|
|
100
|
+
dosimetryQaInProgressDate,
|
|
101
|
+
dosimetryQaCompletedDate,
|
|
102
|
+
confirmedStartingDate,
|
|
103
|
+
treatmentStop,
|
|
104
|
+
linacAllocationCriteria,
|
|
105
|
+
sessionDurationCriteria,
|
|
106
|
+
groupRRHH,
|
|
107
|
+
patientName,
|
|
108
|
+
} = patientInfo;
|
|
109
|
+
|
|
110
|
+
if (allPatientsIds.includes(patientId)) {
|
|
111
|
+
console.log(`El paciente ${patientId} ya existe`);
|
|
112
|
+
ignoredPatients.push(patientId);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
console.log('Procesando paciente:', patientId);
|
|
117
|
+
|
|
118
|
+
// Convertir ciertos datos
|
|
119
|
+
const sendingDepartmentId = ApiInstance.getSendingDepartmentIdByName(sendingDepartment);
|
|
120
|
+
const cei9Id = ApiInstance.getGlobalInfoElementId(ApiInstance.globalTypes.cei9, cei9);
|
|
121
|
+
const treatmentClassId = ApiInstance.getGlobalInfoElementId(ApiInstance.globalTypes.treatmentClass, treatmentClass);
|
|
122
|
+
const treatmentSubClassId = ApiInstance.getGlobalInfoElementId(ApiInstance.globalTypes.treatmentSubClass, treatmentSubClass);
|
|
123
|
+
const linacAllocationCriteriaId = ApiInstance.getGlobalInfoElementId(ApiInstance.globalTypes.linacsAllocationCriteria, linacAllocationCriteria || 'Default');
|
|
124
|
+
const confirmedLinacId = linacs.find(linac => linac.name === confirmedLinac)?.id || '';
|
|
125
|
+
const sessionDurationCriteriaId = ApiInstance.getGlobalInfoElementId(ApiInstance.globalTypes.sessionDurationCriteria, sessionDurationCriteria || 'Default');
|
|
126
|
+
const treatmentTechniqueId = ApiInstance.getGlobalInfoElementId(ApiInstance.globalTypes.treatmentTechnique, treatmentTechnique);
|
|
127
|
+
const simulationProtocolId = ApiInstance.getGlobalInfoElementId(ApiInstance.globalTypes.ctSimProtocols, simulationProtocol);
|
|
128
|
+
const dosimetryMedPhysId = medPhys.find(med => med.name === dosimetryMedPhys)?.id || '';
|
|
129
|
+
const pendingSessions = sessionsTotal - sessionsCompleted;
|
|
130
|
+
const peerReviewedDoctorId = radOncs.find(radOnc => radOnc.name === peerReviewedDoctor)?.id || '';
|
|
131
|
+
|
|
132
|
+
const peerReviewedData = ApiInstance.getRewiewedStatus(peerReviewedStatus);
|
|
133
|
+
|
|
134
|
+
// Crear el formData
|
|
135
|
+
const formData = {
|
|
136
|
+
registration: {
|
|
137
|
+
patientId: patientId.trim() || `IM-${(i + 1).toString().padStart(6, '0')}`,
|
|
138
|
+
registrationDate: registrationDate,
|
|
139
|
+
firstConsultProposal: firstConsultDate,
|
|
140
|
+
assignedRadOnc: assignedRadOnc,
|
|
141
|
+
sendingDepartment: sendingDepartmentId,
|
|
142
|
+
},
|
|
143
|
+
consultation: {
|
|
144
|
+
cei: cei9Id,
|
|
145
|
+
tnm: tnm,
|
|
146
|
+
estadio: stage,
|
|
147
|
+
treatmentClass: treatmentClassId,
|
|
148
|
+
treatmentSubClass: treatmentSubClassId,
|
|
149
|
+
earlierStartDate: "",
|
|
150
|
+
latestStartDate: "",
|
|
151
|
+
mandatoryStartDate: "",
|
|
152
|
+
priority: "",
|
|
153
|
+
shift: "Morning",
|
|
154
|
+
treatmentType: "",
|
|
155
|
+
treatmentGoal: "",
|
|
156
|
+
noTreatment: false,
|
|
157
|
+
why: "",
|
|
158
|
+
state: "NOT_STARTED",
|
|
159
|
+
compatibleLinacs: defaultCompatibleLinacs,
|
|
160
|
+
firstSesionDuration: defaultDuration.firstSession,
|
|
161
|
+
regularSesionDuration: defaultDuration.regularSessions,
|
|
162
|
+
linacAllocationCriteria: linacAllocationCriteriaId,
|
|
163
|
+
sessionDurationCriteria: sessionDurationCriteriaId,
|
|
164
|
+
treatmentParticle: "",
|
|
165
|
+
treatmentTechnique: treatmentTechniqueId,
|
|
166
|
+
numberOfFractions: sessionsTotal,
|
|
167
|
+
fractionation: "",
|
|
168
|
+
fractionPattern: fractionationPattern,
|
|
169
|
+
weeklySessions: "",
|
|
170
|
+
daysBetweenSessions: "",
|
|
171
|
+
comments: "",
|
|
172
|
+
ctSim: "",
|
|
173
|
+
ctApplicationDate: ctAppDate,
|
|
174
|
+
stateChanges: []
|
|
175
|
+
},
|
|
176
|
+
onHold: {
|
|
177
|
+
items: [
|
|
178
|
+
{
|
|
179
|
+
id: 1,
|
|
180
|
+
start: "",
|
|
181
|
+
end: "",
|
|
182
|
+
motivation: "",
|
|
183
|
+
comments: ""
|
|
184
|
+
}
|
|
185
|
+
],
|
|
186
|
+
state: "NOT_STARTED",
|
|
187
|
+
stateChanges: []
|
|
188
|
+
},
|
|
189
|
+
treatmentSimulation: {
|
|
190
|
+
notificationDate: notificationDate,
|
|
191
|
+
confirmedDate: confirmedDate,
|
|
192
|
+
simulationProtocol: simulationProtocolId,
|
|
193
|
+
ctGuidelines: "",
|
|
194
|
+
comments: "",
|
|
195
|
+
state: "NOT_STARTED",
|
|
196
|
+
stateChanges: [],
|
|
197
|
+
atachedFiles: []
|
|
198
|
+
},
|
|
199
|
+
contouringOar: {
|
|
200
|
+
guidelines: "",
|
|
201
|
+
proposedRrhh: "",
|
|
202
|
+
rrhhId: "",
|
|
203
|
+
countouringTool: "",
|
|
204
|
+
oarTableId: "",
|
|
205
|
+
comments: "",
|
|
206
|
+
state: "NOT_STARTED",
|
|
207
|
+
stateChanges: []
|
|
208
|
+
},
|
|
209
|
+
contouringVolumes: {
|
|
210
|
+
guidelines: "",
|
|
211
|
+
proposedRrhh: "",
|
|
212
|
+
rrhhId: "",
|
|
213
|
+
countouringTool: "",
|
|
214
|
+
comments: "",
|
|
215
|
+
volumesDescription: [
|
|
216
|
+
{
|
|
217
|
+
id: 1,
|
|
218
|
+
name: "PTV1",
|
|
219
|
+
desc: "PTVASOC1"
|
|
220
|
+
}
|
|
221
|
+
],
|
|
222
|
+
volumesDose: [
|
|
223
|
+
{
|
|
224
|
+
ptv: "PTV1",
|
|
225
|
+
ptvAsoc: "PTVASOC1",
|
|
226
|
+
total: "100",
|
|
227
|
+
dose: 100,
|
|
228
|
+
fracPattern: "CMD"
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
ptv: "PTV1",
|
|
232
|
+
ptvAsoc: "PTVASOC1",
|
|
233
|
+
total: "100",
|
|
234
|
+
dose: 100,
|
|
235
|
+
fracPattern: "CMD"
|
|
236
|
+
}
|
|
237
|
+
],
|
|
238
|
+
state: "NOT_STARTED",
|
|
239
|
+
stateChanges: []
|
|
240
|
+
},
|
|
241
|
+
treatmentDefinition: {
|
|
242
|
+
compatibleLinacs: defaultCompatibleLinacs,
|
|
243
|
+
firstSesionDuration: defaultDuration.firstSession,
|
|
244
|
+
regularSesionDuration: defaultDuration.regularSessions,
|
|
245
|
+
linacAllocationCriteria: linacAllocationCriteriaId,
|
|
246
|
+
sessionDurationCriteria: sessionDurationCriteriaId,
|
|
247
|
+
treatmentParticle: "",
|
|
248
|
+
treatmentTechnique: treatmentTechniqueId,
|
|
249
|
+
numberOfFractions: sessionsTotal,
|
|
250
|
+
fractionation: "",
|
|
251
|
+
fractionPattern: fractionationPattern,
|
|
252
|
+
weeklySessions: "",
|
|
253
|
+
daysBetweenSessions: "",
|
|
254
|
+
comments: "",
|
|
255
|
+
peerReviewed: peerReviewedData,
|
|
256
|
+
oarAndPtvTables: [
|
|
257
|
+
{
|
|
258
|
+
ptv: "PTV1",
|
|
259
|
+
ptvasoc: "PTVASOC1"
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
ptv: "PTV1",
|
|
263
|
+
ptvasoc: "PTVASOC1"
|
|
264
|
+
}
|
|
265
|
+
],
|
|
266
|
+
checkListPeerReview: {
|
|
267
|
+
targetVolumes: false,
|
|
268
|
+
oarVolumes: false,
|
|
269
|
+
targetDoses: false,
|
|
270
|
+
oarToleranceTables: false,
|
|
271
|
+
treatmentTechnique: false,
|
|
272
|
+
fractionation: false
|
|
273
|
+
},
|
|
274
|
+
state: "NOT_STARTED",
|
|
275
|
+
stateChanges: []
|
|
276
|
+
},
|
|
277
|
+
dosimetry: {
|
|
278
|
+
proposedLinac: confirmedLinacId,
|
|
279
|
+
confirmedLinac: confirmedLinacId,
|
|
280
|
+
groupRrhh: groupRRHH,
|
|
281
|
+
idRrhh: dosimetryMedPhysId,
|
|
282
|
+
calculationMethod: "",
|
|
283
|
+
typeOfPlanning: "",
|
|
284
|
+
tpsUsed: "",
|
|
285
|
+
secondGroupRrhh: "",
|
|
286
|
+
secondIdRrhh: "",
|
|
287
|
+
secondCalculationMethod: "",
|
|
288
|
+
dosimetryComplete: false,
|
|
289
|
+
planDefinitionComplete: false,
|
|
290
|
+
dosimetricReportComplete: false,
|
|
291
|
+
state: "NOT_STARTED",
|
|
292
|
+
stateChanges: [],
|
|
293
|
+
dosimetricReportFiles: [],
|
|
294
|
+
treatmentPlanFiles: []
|
|
295
|
+
},
|
|
296
|
+
treatmentVerification: {
|
|
297
|
+
description: "",
|
|
298
|
+
comments: "",
|
|
299
|
+
verificationProtocol: "",
|
|
300
|
+
state: "NOT_STARTED",
|
|
301
|
+
stateChanges: [],
|
|
302
|
+
verificationReportFiles: [],
|
|
303
|
+
uploadFiles: []
|
|
304
|
+
},
|
|
305
|
+
treatmentDelivery: {
|
|
306
|
+
numberOfFractions: sessionsTotal,
|
|
307
|
+
confirmedLinac: confirmedLinacId,
|
|
308
|
+
treatmentTechnique: treatmentTechniqueId,
|
|
309
|
+
tentativeTreatmentStart: "",
|
|
310
|
+
confirmedTreatmentStart: confirmedStartingDate,
|
|
311
|
+
numberOfCompleteSessions: sessionsCompleted,
|
|
312
|
+
numberOfPendingSessions: pendingSessions,
|
|
313
|
+
startAssignedShift: "",
|
|
314
|
+
startConfirmedStartDate: "",
|
|
315
|
+
startWeeklyAssignedDays: [],
|
|
316
|
+
interruptedEstimatedEndDate: "",
|
|
317
|
+
interruAssignedShift: "",
|
|
318
|
+
interruptedConfirmedStartDate: "",
|
|
319
|
+
interruptedMotivation: "",
|
|
320
|
+
canceledMotivation: "",
|
|
321
|
+
stateChanges: []
|
|
322
|
+
},
|
|
323
|
+
nursing: {
|
|
324
|
+
rows: [
|
|
325
|
+
{
|
|
326
|
+
namefield: "value",
|
|
327
|
+
namefield2: "value2",
|
|
328
|
+
namefield3: "value2",
|
|
329
|
+
namefield4: "value2",
|
|
330
|
+
namefield5: "value2",
|
|
331
|
+
namefield6: "value2"
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
namefield: "value",
|
|
335
|
+
namefield2: "value2",
|
|
336
|
+
namefield3: "value2",
|
|
337
|
+
namefield4: "value2",
|
|
338
|
+
namefield5: "value2",
|
|
339
|
+
namefield6: "value2"
|
|
340
|
+
}
|
|
341
|
+
],
|
|
342
|
+
state: "NOT_STARTED",
|
|
343
|
+
stateChanges: []
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Guardar el paciente
|
|
348
|
+
const createdId = await ApiInstance.createPatient({ firstName: patientName.trim(), formData });
|
|
349
|
+
|
|
350
|
+
// Recuperar el cliente
|
|
351
|
+
const patient = await ApiInstance.getPatient(createdId);
|
|
352
|
+
|
|
353
|
+
// Ajustar estados
|
|
354
|
+
if (peerReviewedDoctorId) {
|
|
355
|
+
await ApiInstance.createPatientStateChanges({
|
|
356
|
+
formDataId: patient.formData.treatmentDefinition.id,
|
|
357
|
+
humanResourceId: peerReviewedDoctorId,
|
|
358
|
+
date: today(),
|
|
359
|
+
nextStateCode: 'PEER_REVIEWED',
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (qaCompletedDate) {
|
|
364
|
+
await ApiInstance.createPatientStateChanges({
|
|
365
|
+
formDataId: patient.formData.treatmentDefinition.id,
|
|
366
|
+
date: qaCompletedDate,
|
|
367
|
+
nextStateCode: 'COMPLETED',
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (dosimetryQaInProgressDate) {
|
|
372
|
+
await ApiInstance.createPatientStateChanges({
|
|
373
|
+
formDataId: patient.formData.dosimetry.id,
|
|
374
|
+
date: dosimetryQaInProgressDate,
|
|
375
|
+
nextStateCode: 'IN_PROGRESS',
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (dosimetryQaCompletedDate) {
|
|
380
|
+
await ApiInstance.createPatientStateChanges({
|
|
381
|
+
formDataId: patient.formData.dosimetry.id,
|
|
382
|
+
date: dosimetryQaCompletedDate,
|
|
383
|
+
nextStateCode: 'COMPLETED',
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (confirmedStartingDate && today() < confirmedStartingDate) {
|
|
388
|
+
await ApiInstance.createPatientStateChanges({
|
|
389
|
+
formDataId: patient.formData.treatmentDelivery.id,
|
|
390
|
+
date: confirmedStartingDate,
|
|
391
|
+
nextStateCode: 'START_CONFIRMED',
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (parseInt(sessionsCompleted)) {
|
|
396
|
+
await ApiInstance.createPatientStateChanges({
|
|
397
|
+
formDataId: patient.formData.treatmentDelivery.id,
|
|
398
|
+
date: confirmedStartingDate || today(),
|
|
399
|
+
nextStateCode: 'IN_PROGRESS',
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (treatmentStop.toUpperCase().startsWith('CANC')) {
|
|
404
|
+
await ApiInstance.createPatientStateChanges({
|
|
405
|
+
formDataId: patient.formData.treatmentDelivery.id,
|
|
406
|
+
date: today(),
|
|
407
|
+
nextStateCode: 'CANCELED',
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (treatmentStop.toUpperCase().startsWith('INT')) {
|
|
412
|
+
await ApiInstance.createPatientStateChanges({
|
|
413
|
+
formDataId: patient.formData.treatmentDelivery.id,
|
|
414
|
+
date: today(),
|
|
415
|
+
nextStateCode: 'INTERRUPTED',
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (!!sessionsCompleted && sessionsCompleted != 0 && sessionsCompleted === sessionsTotal) {
|
|
420
|
+
await ApiInstance.createPatientStateChanges({
|
|
421
|
+
formDataId: patient.formData.treatmentDelivery.id,
|
|
422
|
+
date: today(),
|
|
423
|
+
nextStateCode: 'COMPLETED',
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
contadorPacientes++;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (ignoredPatients.length) console.error('\n\nLos siguientes pacientes no se han podido importar porque ya existían en el sistema:', ignoredPatients.join(', '));
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
export {
|
|
434
|
+
importer,
|
|
435
|
+
};
|