@peopl-health/nexus 6.4.0-dev.18777 → 6.4.0-dev.18778
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.
|
@@ -1,95 +1,9 @@
|
|
|
1
|
-
const { httpError } = require('../../utils/httpErrorUtils');
|
|
2
1
|
const { oneLineOf } = require('../../utils/coercionUtils');
|
|
3
|
-
const { PLAN_FOLLOW_UPS } = require('../../models/escalationReviewModel');
|
|
4
2
|
|
|
5
|
-
const DEFAULT_FOLLOW_UP_HOURS = { check_in: 24, vigilancia: 48 };
|
|
6
|
-
const FIRST_LINE = '1L';
|
|
7
|
-
const MAX_ENTRIES = 10;
|
|
8
|
-
const MAX_FIELD_LENGTH = 300;
|
|
9
|
-
const MAX_NOTE_LENGTH = 1000;
|
|
10
|
-
const MAX_INSTRUCTIONS_LENGTH = 4000;
|
|
11
|
-
const MAX_DAYS = 90;
|
|
12
|
-
const MAX_FOLLOW_UP_HOURS = 168;
|
|
3
|
+
const DEFAULT_FOLLOW_UP_HOURS = Object.freeze({ check_in: 24, vigilancia: 48 });
|
|
13
4
|
// A route is not a dose: the doctor still says how many tablets.
|
|
14
5
|
const ROUTE_ONLY = /^(vo|v[ií]a oral|oral)$/i;
|
|
15
6
|
|
|
16
|
-
const textOf = (value, name, max = MAX_FIELD_LENGTH) => {
|
|
17
|
-
if (value != null && typeof value !== 'string') throw httpError(400, `${name} must be text`);
|
|
18
|
-
const text = oneLineOf(value);
|
|
19
|
-
if (text.length > max) throw httpError(400, `${name} exceeds ${max} characters`);
|
|
20
|
-
return text || null;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const neededText = (value, name) => {
|
|
24
|
-
const text = textOf(value, name);
|
|
25
|
-
if (!text) throw httpError(400, `${name} is required`);
|
|
26
|
-
return text;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const isPlainObject = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
30
|
-
|
|
31
|
-
// Only a number or a string of digits: `true`, `[5]` and `'1e1'` are not days.
|
|
32
|
-
const wholeNumber = (value, name, max) => {
|
|
33
|
-
const number = typeof value === 'number' || (typeof value === 'string' && /^\d+$/.test(value.trim())) ? Number(value) : NaN;
|
|
34
|
-
if (!Number.isInteger(number) || number < 1 || number > max) throw httpError(400, `${name} must be a whole number from 1 to ${max}`);
|
|
35
|
-
return number;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
const listOf = (value, name) => {
|
|
39
|
-
if (value == null) return [];
|
|
40
|
-
if (!Array.isArray(value)) throw httpError(400, `${name} must be a list`);
|
|
41
|
-
if (value.length > MAX_ENTRIES) throw httpError(400, `${name} allows at most ${MAX_ENTRIES} entries`);
|
|
42
|
-
return value;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
function itemOf(item, index) {
|
|
46
|
-
const name = `plan.items[${index}]`;
|
|
47
|
-
const position = textOf(item?.position, `${name}.position`);
|
|
48
|
-
const reason = textOf(item?.reason, `${name}.reason`);
|
|
49
|
-
// An alternative to the first line has to say why the first line does not fit.
|
|
50
|
-
if (position && position !== FIRST_LINE && !reason) throw httpError(400, `${name}.reason is required for a drug that is not first line`);
|
|
51
|
-
return {
|
|
52
|
-
drug: neededText(item?.drug, `${name}.drug`),
|
|
53
|
-
strength: textOf(item?.strength, `${name}.strength`),
|
|
54
|
-
dose: neededText(item?.dose, `${name}.dose`),
|
|
55
|
-
frequency: neededText(item?.frequency, `${name}.frequency`),
|
|
56
|
-
days: wholeNumber(item?.days, `${name}.days`, MAX_DAYS),
|
|
57
|
-
position,
|
|
58
|
-
reason,
|
|
59
|
-
formularyKey: textOf(item?.formularyKey, `${name}.formularyKey`),
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function followUpOf(value) {
|
|
64
|
-
if (value != null && !isPlainObject(value)) throw httpError(400, 'plan.followUp must be an object with a kind');
|
|
65
|
-
const kind = value?.kind ?? 'none';
|
|
66
|
-
if (!PLAN_FOLLOW_UPS.includes(kind)) throw httpError(400, `plan.followUp.kind must be one of: ${PLAN_FOLLOW_UPS.join(', ')}`);
|
|
67
|
-
if (kind === 'none') return { kind, hours: null };
|
|
68
|
-
return { kind, hours: wholeNumber(value?.hours ?? DEFAULT_FOLLOW_UP_HOURS[kind], 'plan.followUp.hours', MAX_FOLLOW_UP_HOURS) };
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// The plan as the doctor approved it, refused whole when any line is incomplete.
|
|
72
|
-
function planOf(input) {
|
|
73
|
-
if (!isPlainObject(input)) throw httpError(400, 'plan is required');
|
|
74
|
-
const plan = {
|
|
75
|
-
items: listOf(input.items, 'plan.items').map((item, index) => {
|
|
76
|
-
if (!isPlainObject(item)) throw httpError(400, `plan.items[${index}] must be an object`);
|
|
77
|
-
return itemOf(item, index);
|
|
78
|
-
}),
|
|
79
|
-
studies: listOf(input.studies, 'plan.studies').map((study, index) => ({
|
|
80
|
-
name: neededText(study?.name, `plan.studies[${index}].name`),
|
|
81
|
-
instructions: textOf(study?.instructions, `plan.studies[${index}].instructions`),
|
|
82
|
-
})),
|
|
83
|
-
homeCare: listOf(input.homeCare, 'plan.homeCare').map((entry, index) => neededText(entry, `plan.homeCare[${index}]`)),
|
|
84
|
-
note: textOf(input.note, 'plan.note', MAX_NOTE_LENGTH),
|
|
85
|
-
followUp: followUpOf(input.followUp),
|
|
86
|
-
};
|
|
87
|
-
if (!plan.items.length && !plan.studies.length && !plan.homeCare.length && !plan.note) {
|
|
88
|
-
throw httpError(400, 'plan needs a drug, a study, a home care measure or a note');
|
|
89
|
-
}
|
|
90
|
-
return plan;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
7
|
const needsPrescriber = (plan) => plan.items.length > 0 || plan.studies.length > 0;
|
|
94
8
|
|
|
95
9
|
const daysText = (days) => (days === 1 ? '1 día' : `${days} días`);
|
|
@@ -139,15 +53,6 @@ function prescriptionText(plan) {
|
|
|
139
53
|
return lines.join('\n');
|
|
140
54
|
}
|
|
141
55
|
|
|
142
|
-
// The doctor's edit wins; with none, the instructions follow the plan.
|
|
143
|
-
function approvedInstructions(plan, edited) {
|
|
144
|
-
if (edited != null && typeof edited !== 'string') throw httpError(400, 'instructions must be text');
|
|
145
|
-
if (!edited?.trim()) return { instructions: planInstructions(plan), instructionsEdited: false };
|
|
146
|
-
const instructions = edited.trim();
|
|
147
|
-
if (instructions.length > MAX_INSTRUCTIONS_LENGTH) throw httpError(400, `instructions exceed ${MAX_INSTRUCTIONS_LENGTH} characters`);
|
|
148
|
-
return { instructions, instructionsEdited: instructions !== planInstructions(plan) };
|
|
149
|
-
}
|
|
150
|
-
|
|
151
56
|
// «1 tableta cada 24 horas por 5 días; además, …» → dose, frequency, days and the rest; what does not match is left for the doctor.
|
|
152
57
|
function dosingOf(instructions) {
|
|
153
58
|
const text = oneLineOf(instructions);
|
|
@@ -181,13 +86,6 @@ function proposedPlanOf(draft) {
|
|
|
181
86
|
return { items, studies: [], homeCare: [], note: rests.join('. ') || null, followUp: { kind: 'check_in', hours: DEFAULT_FOLLOW_UP_HOURS.check_in } };
|
|
182
87
|
}
|
|
183
88
|
|
|
184
|
-
const plain = (text) => String(text ?? '').normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase();
|
|
185
|
-
const URGENCY_WORDS = /\b(urgencias?|urgente|de inmediato|inmediatamente|emergencias?|911|lo antes posible|cuanto antes|no esperes)\b/g;
|
|
186
|
-
const numbersIn = (text, pattern) => new Set([...plain(text).matchAll(pattern)].map((match) => match[1].replace(',', '.')));
|
|
187
|
-
const HOURS = /cada\s+(\d+)\s*h(?:rs?|oras?)?\b/g;
|
|
188
|
-
const DAYS = /por\s+(\d+)\s+dias?/g;
|
|
189
|
-
const MG = /(\d+(?:[.,]\d+)?)\s*mg\b/g;
|
|
190
|
-
|
|
191
89
|
// The plan's own words, so what the doctor wrote anywhere in it is never flagged.
|
|
192
90
|
const plannedTextOf = (plan) => [
|
|
193
91
|
...plan.items.flatMap((item) => [item.drug, item.strength, item.dose, item.frequency, `por ${item.days} dias`]),
|
|
@@ -196,37 +94,13 @@ const plannedTextOf = (plan) => [
|
|
|
196
94
|
plan.note,
|
|
197
95
|
].filter(Boolean).join('\n');
|
|
198
96
|
|
|
199
|
-
// What in the assistant's reply strays from the plan, for the team to check; `unplannedDrugs` are the formulary drugs it names beyond the plan.
|
|
200
|
-
function replyIssues(plan, reply, unplannedDrugs = []) {
|
|
201
|
-
const text = plain(reply);
|
|
202
|
-
if (!text) return ['no se pudo leer el mensaje enviado'];
|
|
203
|
-
const planned = plannedTextOf(plan);
|
|
204
|
-
const issues = [];
|
|
205
|
-
for (const item of plan.items) {
|
|
206
|
-
const name = plain(item.drug).split(/[\s/]/)[0];
|
|
207
|
-
if (name && !text.includes(name)) issues.push(`no menciona ${item.drug}`);
|
|
208
|
-
}
|
|
209
|
-
const strays = (pattern) => [...numbersIn(reply, pattern)].filter((value) => !numbersIn(planned, pattern).has(value));
|
|
210
|
-
for (const value of strays(HOURS)) issues.push(`dice «cada ${value} horas», que no está en el plan`);
|
|
211
|
-
for (const value of strays(DAYS)) issues.push(`dice «por ${value} días», que no está en el plan`);
|
|
212
|
-
for (const value of strays(MG)) issues.push(`dice «${value} mg», que no está en el plan`);
|
|
213
|
-
for (const name of unplannedDrugs) issues.push(`menciona ${name}, que el médico no indicó`);
|
|
214
|
-
const plannedWords = new Set([...plain(planned).matchAll(URGENCY_WORDS)].map((match) => match[1]));
|
|
215
|
-
for (const word of new Set([...text.matchAll(URGENCY_WORDS)].map((match) => match[1]))) {
|
|
216
|
-
if (!plannedWords.has(word)) issues.push(`usa «${word}», que el médico no indicó`);
|
|
217
|
-
}
|
|
218
|
-
return issues;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
97
|
module.exports = {
|
|
222
|
-
|
|
98
|
+
DEFAULT_FOLLOW_UP_HOURS,
|
|
223
99
|
assistantInstructionsOf,
|
|
224
100
|
needsPrescriber,
|
|
225
101
|
planInstructions,
|
|
226
|
-
planOf,
|
|
227
102
|
planSummary,
|
|
103
|
+
plannedTextOf,
|
|
228
104
|
prescriptionText,
|
|
229
105
|
proposedPlanOf,
|
|
230
|
-
plannedTextOf,
|
|
231
|
-
replyIssues,
|
|
232
106
|
};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
const { DEFAULT_FOLLOW_UP_HOURS, planInstructions, plannedTextOf } = require('../helpers/doctorPlanHelper');
|
|
2
|
+
const { httpError } = require('../../utils/httpErrorUtils');
|
|
3
|
+
const { oneLineOf } = require('../../utils/coercionUtils');
|
|
4
|
+
const { PLAN_FOLLOW_UPS } = require('../../models/escalationReviewModel');
|
|
5
|
+
const { unplannedDrugsIn } = require('./treatmentProposalService');
|
|
6
|
+
|
|
7
|
+
const FIRST_LINE = '1L';
|
|
8
|
+
const MAX_ENTRIES = 10;
|
|
9
|
+
const MAX_FIELD_LENGTH = 300;
|
|
10
|
+
const MAX_NOTE_LENGTH = 1000;
|
|
11
|
+
const MAX_INSTRUCTIONS_LENGTH = 4000;
|
|
12
|
+
const MAX_DAYS = 90;
|
|
13
|
+
const MAX_FOLLOW_UP_HOURS = 168;
|
|
14
|
+
|
|
15
|
+
const textOf = (value, name, max = MAX_FIELD_LENGTH) => {
|
|
16
|
+
if (value != null && typeof value !== 'string') throw httpError(400, `${name} must be text`);
|
|
17
|
+
const text = oneLineOf(value);
|
|
18
|
+
if (text.length > max) throw httpError(400, `${name} exceeds ${max} characters`);
|
|
19
|
+
return text || null;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const neededText = (value, name) => {
|
|
23
|
+
const text = textOf(value, name);
|
|
24
|
+
if (!text) throw httpError(400, `${name} is required`);
|
|
25
|
+
return text;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const isPlainObject = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
29
|
+
|
|
30
|
+
// Only a number or a string of digits: `true`, `[5]` and `'1e1'` are not days.
|
|
31
|
+
const wholeNumber = (value, name, max) => {
|
|
32
|
+
const number = typeof value === 'number' || (typeof value === 'string' && /^\d+$/.test(value.trim())) ? Number(value) : NaN;
|
|
33
|
+
if (!Number.isInteger(number) || number < 1 || number > max) throw httpError(400, `${name} must be a whole number from 1 to ${max}`);
|
|
34
|
+
return number;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const listOf = (value, name) => {
|
|
38
|
+
if (value == null) return [];
|
|
39
|
+
if (!Array.isArray(value)) throw httpError(400, `${name} must be a list`);
|
|
40
|
+
if (value.length > MAX_ENTRIES) throw httpError(400, `${name} allows at most ${MAX_ENTRIES} entries`);
|
|
41
|
+
return value;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
function itemOf(item, index) {
|
|
45
|
+
const name = `plan.items[${index}]`;
|
|
46
|
+
const position = textOf(item?.position, `${name}.position`);
|
|
47
|
+
const reason = textOf(item?.reason, `${name}.reason`);
|
|
48
|
+
// An alternative to the first line has to say why the first line does not fit.
|
|
49
|
+
if (position && position !== FIRST_LINE && !reason) throw httpError(400, `${name}.reason is required for a drug that is not first line`);
|
|
50
|
+
return {
|
|
51
|
+
drug: neededText(item?.drug, `${name}.drug`),
|
|
52
|
+
strength: textOf(item?.strength, `${name}.strength`),
|
|
53
|
+
dose: neededText(item?.dose, `${name}.dose`),
|
|
54
|
+
frequency: neededText(item?.frequency, `${name}.frequency`),
|
|
55
|
+
days: wholeNumber(item?.days, `${name}.days`, MAX_DAYS),
|
|
56
|
+
position,
|
|
57
|
+
reason,
|
|
58
|
+
formularyKey: textOf(item?.formularyKey, `${name}.formularyKey`),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function followUpOf(value) {
|
|
63
|
+
if (value != null && !isPlainObject(value)) throw httpError(400, 'plan.followUp must be an object with a kind');
|
|
64
|
+
const kind = value?.kind ?? 'none';
|
|
65
|
+
if (!PLAN_FOLLOW_UPS.includes(kind)) throw httpError(400, `plan.followUp.kind must be one of: ${PLAN_FOLLOW_UPS.join(', ')}`);
|
|
66
|
+
if (kind === 'none') return { kind, hours: null };
|
|
67
|
+
return { kind, hours: wholeNumber(value?.hours ?? DEFAULT_FOLLOW_UP_HOURS[kind], 'plan.followUp.hours', MAX_FOLLOW_UP_HOURS) };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// The plan as the doctor approved it, refused whole when any line is incomplete.
|
|
71
|
+
function planOf(input) {
|
|
72
|
+
if (!isPlainObject(input)) throw httpError(400, 'plan is required');
|
|
73
|
+
const plan = {
|
|
74
|
+
items: listOf(input.items, 'plan.items').map((item, index) => {
|
|
75
|
+
if (!isPlainObject(item)) throw httpError(400, `plan.items[${index}] must be an object`);
|
|
76
|
+
return itemOf(item, index);
|
|
77
|
+
}),
|
|
78
|
+
studies: listOf(input.studies, 'plan.studies').map((study, index) => ({
|
|
79
|
+
name: neededText(study?.name, `plan.studies[${index}].name`),
|
|
80
|
+
instructions: textOf(study?.instructions, `plan.studies[${index}].instructions`),
|
|
81
|
+
})),
|
|
82
|
+
homeCare: listOf(input.homeCare, 'plan.homeCare').map((entry, index) => neededText(entry, `plan.homeCare[${index}]`)),
|
|
83
|
+
note: textOf(input.note, 'plan.note', MAX_NOTE_LENGTH),
|
|
84
|
+
followUp: followUpOf(input.followUp),
|
|
85
|
+
};
|
|
86
|
+
if (!plan.items.length && !plan.studies.length && !plan.homeCare.length && !plan.note) {
|
|
87
|
+
throw httpError(400, 'plan needs a drug, a study, a home care measure or a note');
|
|
88
|
+
}
|
|
89
|
+
return plan;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// The doctor's edit wins; with none, the instructions follow the plan.
|
|
93
|
+
function approvedInstructions(plan, edited) {
|
|
94
|
+
if (edited != null && typeof edited !== 'string') throw httpError(400, 'instructions must be text');
|
|
95
|
+
if (!edited?.trim()) return { instructions: planInstructions(plan), instructionsEdited: false };
|
|
96
|
+
const instructions = edited.trim();
|
|
97
|
+
if (instructions.length > MAX_INSTRUCTIONS_LENGTH) throw httpError(400, `instructions exceed ${MAX_INSTRUCTIONS_LENGTH} characters`);
|
|
98
|
+
return { instructions, instructionsEdited: instructions !== planInstructions(plan) };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const plain = (text) => String(text ?? '').normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase();
|
|
102
|
+
const URGENCY_WORDS = /\b(urgencias?|urgente|de inmediato|inmediatamente|emergencias?|911|lo antes posible|cuanto antes|no esperes)\b/g;
|
|
103
|
+
const numbersIn = (text, pattern) => new Set([...plain(text).matchAll(pattern)].map((match) => match[1].replace(',', '.')));
|
|
104
|
+
const HOURS = /cada\s+(\d+)\s*h(?:rs?|oras?)?\b/g;
|
|
105
|
+
const DAYS = /por\s+(\d+)\s+dias?/g;
|
|
106
|
+
const MG = /(\d+(?:[.,]\d+)?)\s*mg\b/g;
|
|
107
|
+
|
|
108
|
+
// What in the assistant's reply strays from the plan, for the team to check.
|
|
109
|
+
function replyIssues(plan, reply) {
|
|
110
|
+
const text = plain(reply);
|
|
111
|
+
if (!text) return ['no se pudo leer el mensaje enviado'];
|
|
112
|
+
const planned = plannedTextOf(plan);
|
|
113
|
+
const unplannedDrugs = unplannedDrugsIn(reply, planned);
|
|
114
|
+
const issues = [];
|
|
115
|
+
for (const item of plan.items) {
|
|
116
|
+
const name = plain(item.drug).split(/[\s/]/)[0];
|
|
117
|
+
if (name && !text.includes(name)) issues.push(`no menciona ${item.drug}`);
|
|
118
|
+
}
|
|
119
|
+
const strays = (pattern) => [...numbersIn(reply, pattern)].filter((value) => !numbersIn(planned, pattern).has(value));
|
|
120
|
+
for (const value of strays(HOURS)) issues.push(`dice «cada ${value} horas», que no está en el plan`);
|
|
121
|
+
for (const value of strays(DAYS)) issues.push(`dice «por ${value} días», que no está en el plan`);
|
|
122
|
+
for (const value of strays(MG)) issues.push(`dice «${value} mg», que no está en el plan`);
|
|
123
|
+
for (const name of unplannedDrugs) issues.push(`menciona ${name}, que el médico no indicó`);
|
|
124
|
+
const plannedWords = new Set([...plain(planned).matchAll(URGENCY_WORDS)].map((match) => match[1]));
|
|
125
|
+
for (const word of new Set([...text.matchAll(URGENCY_WORDS)].map((match) => match[1]))) {
|
|
126
|
+
if (!plannedWords.has(word)) issues.push(`usa «${word}», que el médico no indicó`);
|
|
127
|
+
}
|
|
128
|
+
return issues;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
module.exports = { approvedInstructions, planOf, replyIssues };
|
|
@@ -31,11 +31,10 @@ const { generateEscalationDraft } = require('../clinical/services/escalationDraf
|
|
|
31
31
|
const { conversationLink, readGroupMessageId, writeUnresolvedRequest } = require('../clinical/services/clinicalAirtableService');
|
|
32
32
|
const { doctorAlertHeadline, doctorAlertOpener, renderDoctorMessage, templateSummary, withIdentity } = require('../clinical/helpers/doctorReviewMessageHelper');
|
|
33
33
|
const { generateKeyQuestions } = require('../clinical/services/escalationQuestionsService');
|
|
34
|
-
const { drugsNamedIn
|
|
34
|
+
const { drugsNamedIn } = require('../clinical/services/treatmentProposalService');
|
|
35
35
|
const { characterizationSeedOf } = require('../clinical/helpers/reviewUpdateHelper');
|
|
36
|
-
const {
|
|
37
|
-
|
|
38
|
-
} = require('../clinical/helpers/doctorPlanHelper');
|
|
36
|
+
const { assistantInstructionsOf, needsPrescriber, planInstructions, planSummary, prescriptionText, proposedPlanOf } = require('../clinical/helpers/doctorPlanHelper');
|
|
37
|
+
const { approvedInstructions, planOf, replyIssues } = require('../clinical/services/doctorPlanService');
|
|
39
38
|
const { readNoteFacts, assertionOf } = require('../clinical/services/escalationNoteFactsService');
|
|
40
39
|
const { humanReplyFilter } = require('../clinical/config/safetyNetConfig');
|
|
41
40
|
const {
|
|
@@ -2219,8 +2218,7 @@ async function sendPlanThroughAssistant({ claimed, claim, decisionNumber, plan,
|
|
|
2219
2218
|
const queued = outcome === 'queued';
|
|
2220
2219
|
const prescriptionRecordId = prescriberEmail ? await issuePrescription(claimed, plan, prescriberEmail) : null;
|
|
2221
2220
|
const prescriptionFailed = Boolean(prescriberEmail) && !prescriptionRecordId;
|
|
2222
|
-
const
|
|
2223
|
-
const issues = [...replyIssues(plan, reply, unplanned), ...(prescriptionFailed ? ['no se pudo crear la receta'] : [])];
|
|
2221
|
+
const issues = [...replyIssues(plan, reply), ...(prescriptionFailed ? ['no se pudo crear la receta'] : [])];
|
|
2224
2222
|
const record = {
|
|
2225
2223
|
decisionNumber, messageId: delivery.messageId || null, status: delivery.status || null, transport: 'assistant', deferred: queued, sentBy: operator,
|
|
2226
2224
|
...(prescriptionRecordId && { prescriptionRecordId }),
|