@peopl-health/nexus 5.9.0-dev.921 → 6.0.0-dev.611
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/lib/clinical/AssistantProcessor.js +5 -34
- package/lib/clinical/config/divergenceConfig.js +1 -18
- package/lib/clinical/config/llmConfig.js +1 -9
- package/lib/clinical/context/ToolRuntimeContext.js +2 -1
- package/lib/clinical/helpers/divergenceHelper.js +0 -12
- package/lib/clinical/index.js +0 -2
- package/lib/clinical/memory/DefaultMemoryManager.js +9 -19
- package/lib/clinical/models/turnTraceModel.js +5 -18
- package/lib/clinical/providers/AnthropicProvider.js +29 -291
- package/lib/clinical/providers/BaseLLMProvider.js +24 -113
- package/lib/clinical/providers/GatewayProvider.js +3 -3
- package/lib/clinical/providers/OpenAIResponsesProvider.js +4 -46
- package/lib/clinical/services/divergenceService.js +5 -22
- package/lib/clinical/services/promptComposerService.js +15 -46
- package/lib/clinical/services/shadowMessageService.js +12 -28
- package/lib/clinical/services/shadowService.js +3 -12
- package/lib/clinical/stores/CtcaeCatalog.js +0 -20
- package/lib/config/airtableConfig.js +0 -3
- package/lib/core/BatchingManager.js +3 -10
- package/lib/core/NexusMessaging.js +13 -31
- package/lib/eval/EvalProvider.js +2 -3
- package/lib/fhir/config/fhirConfig.js +3 -34
- package/lib/fhir/constants/projectionSlugs.js +1 -41
- package/lib/fhir/helpers/elementHelper.js +0 -21
- package/lib/fhir/helpers/fhirHelper.js +2 -5
- package/lib/fhir/index.js +0 -24
- package/lib/fhir/models/envelopeModel.js +0 -5
- package/lib/fhir/projections/registerProjectors.js +0 -16
- package/lib/fhir/resources/Condition.js +2 -107
- package/lib/fhir/resources/Observation.js +1 -73
- package/lib/fhir/resources/Procedure.js +2 -34
- package/lib/fhir/resources/Provenance.js +2 -93
- package/lib/fhir/services/fhirService.js +2 -2
- package/lib/helpers/twilioHelper.js +1 -9
- package/lib/index.d.ts +0 -16
- package/lib/index.js +0 -9
- package/lib/models/messageModel.js +0 -6
- package/lib/routes/index.js +1 -21
- package/lib/services/airtableService.js +1 -2
- package/lib/shared/dtos/ContingencySafetyNet.js +3 -10
- package/lib/shared/dtos/DispatchedEscalation.js +8 -3
- package/lib/shared/dtos/Reminder.js +2 -2
- package/lib/storage/MongoStorage.js +0 -2
- package/package.json +1 -1
- package/lib/clinical/config/cohortConfig.js +0 -68
- package/lib/clinical/config/composerConfig.js +0 -42
- package/lib/clinical/config/subAgentsConfig.js +0 -44
- package/lib/clinical/flags/bridgeConfig.js +0 -14
- package/lib/clinical/flags/composerFlags.js +0 -14
- package/lib/clinical/helpers/clinicalFactsHelper.js +0 -108
- package/lib/clinical/helpers/clinicalMentionHelper.js +0 -68
- package/lib/clinical/helpers/cohortHelper.js +0 -22
- package/lib/clinical/helpers/gradeEstimateHelper.js +0 -29
- package/lib/clinical/helpers/resultsHelper.js +0 -34
- package/lib/clinical/helpers/safetyFlagsHelper.js +0 -10
- package/lib/clinical/services/bridgeService.js +0 -55
- package/lib/clinical/services/clinicalAirtableService.js +0 -162
- package/lib/clinical/services/clinicalExtractionService.js +0 -112
- package/lib/clinical/services/composerService.js +0 -59
- package/lib/clinical/services/dispatcherService.js +0 -137
- package/lib/clinical/services/reminderDispatchService.js +0 -36
- package/lib/clinical/services/skillService.js +0 -44
- package/lib/clinical/tools/analyzeSymptomPatternsTool.js +0 -279
- package/lib/clinical/tools/deliverPatientMessageTool.js +0 -202
- package/lib/clinical/tools/extractClinicalInfoTool.js +0 -167
- package/lib/clinical/tools/getActiveSymptomLandscapeTool.js +0 -141
- package/lib/clinical/tools/getPatientHistoryTool.js +0 -235
- package/lib/clinical/tools/getPatientRiskProfileTool.js +0 -71
- package/lib/clinical/tools/getRouterContextBundleTool.js +0 -93
- package/lib/clinical/tools/lookupCtcaeEntryTool.js +0 -35
- package/lib/clinical/tools/openClusterHypothesisTool.js +0 -160
- package/lib/clinical/tools/openConditionTool.js +0 -136
- package/lib/clinical/tools/recordClinicalImpressionTool.js +0 -251
- package/lib/clinical/tools/recordInterventionTool.js +0 -140
- package/lib/clinical/tools/registerClinicalTools.js +0 -39
- package/lib/clinical/tools/reportCrisisTool.js +0 -211
- package/lib/clinical/tools/reportMedicalEscalationTool.js +0 -187
- package/lib/clinical/tools/reportResultsReceivedTool.js +0 -153
- package/lib/clinical/tools/reportUnresolvedRequestv2Tool.js +0 -177
- package/lib/clinical/tools/schedulePatientReminderTool.js +0 -149
- package/lib/clinical/tools/setContingencyPlanTool.js +0 -176
- package/lib/clinical/tools/skillTool.js +0 -67
- package/lib/clinical/tools/submitRoutingDecisionTool.js +0 -291
- package/lib/clinical/tools/updateClusterHypothesisTool.js +0 -159
- package/lib/controllers/cohortController.js +0 -16
- package/lib/controllers/traceController.js +0 -26
- package/lib/core/workflowRunner.js +0 -35
- package/lib/fhir/config/fhirTablesConfig.js +0 -9
- package/lib/fhir/constants/severityPriority.js +0 -8
- package/lib/fhir/helpers/compositeHelper.js +0 -88
- package/lib/fhir/helpers/fhirReadHelper.js +0 -42
- package/lib/fhir/helpers/terminologyHelper.js +0 -260
- package/lib/fhir/projections/clusterProjection.js +0 -24
- package/lib/fhir/projections/contingencyProjection.js +0 -36
- package/lib/fhir/projections/dispatchedEscalationProjection.js +0 -25
- package/lib/fhir/projections/interventionProjection.js +0 -42
- package/lib/fhir/projections/proctcaeProjection.js +0 -179
- package/lib/fhir/projections/reminderProjection.js +0 -20
- package/lib/fhir/projections/riskProjection.js +0 -16
- package/lib/fhir/projections/routingProjection.js +0 -48
- package/lib/fhir/projections/symptomCaseProjection.js +0 -65
- package/lib/fhir/resources/CarePlan.js +0 -93
- package/lib/fhir/resources/ClinicalImpression.js +0 -118
- package/lib/fhir/resources/Communication.js +0 -65
- package/lib/fhir/resources/CommunicationRequest.js +0 -182
- package/lib/fhir/resources/Device.js +0 -24
- package/lib/fhir/resources/Patient.js +0 -18
- package/lib/fhir/resources/Questionnaire.js +0 -23
- package/lib/fhir/resources/QuestionnaireResponse.js +0 -29
- package/lib/fhir/resources/RequestOrchestration.js +0 -46
- package/lib/fhir/resources/RiskAssessment.js +0 -99
- package/lib/fhir/resources/Task.js +0 -106
- package/lib/fhir/resources/interventionExtensions.js +0 -28
- package/lib/fhir/services/clusterService.js +0 -77
- package/lib/fhir/services/contingencyService.js +0 -117
- package/lib/fhir/services/interventionService.js +0 -149
- package/lib/fhir/services/resultObservationService.js +0 -52
- package/lib/fhir/services/riskService.js +0 -101
- package/lib/fhir/services/routingService.js +0 -147
- package/lib/fhir/services/snapshotService.js +0 -28
- package/lib/fhir/services/symptomCaseService.js +0 -139
- package/lib/fhir/services/terminologyService.js +0 -58
- package/lib/fhir/services/triageService.js +0 -57
- package/lib/fhir/utils/normalizeUtils.js +0 -33
- package/lib/shared/dtos/GradedSymptom.js +0 -23
- package/lib/shared/dtos/TriageResponse.js +0 -35
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
const { fhirId } = require('../helpers/fhirHelper');
|
|
2
|
-
const { ClinicalImpression } = require('../resources/ClinicalImpression');
|
|
3
|
-
const { Communication } = require('../resources/Communication');
|
|
4
|
-
const { CommunicationRequest } = require('../resources/CommunicationRequest');
|
|
5
|
-
const { Task } = require('../resources/Task');
|
|
6
|
-
const { RequestOrchestration } = require('../resources/RequestOrchestration');
|
|
7
|
-
const { CarePlan } = require('../resources/CarePlan');
|
|
8
|
-
const { Provenance } = require('../resources/Provenance');
|
|
9
|
-
|
|
10
|
-
const PROJECTOR_NAME = 'routing';
|
|
11
|
-
const ACTIVITY_TEXT = 'routing-decision';
|
|
12
|
-
|
|
13
|
-
const DISPOSITION_BY_KIND = {
|
|
14
|
-
communication: Communication,
|
|
15
|
-
communication_request: CommunicationRequest,
|
|
16
|
-
task: Task,
|
|
17
|
-
orchestration: RequestOrchestration,
|
|
18
|
-
care_plan: CarePlan,
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
function projectRoutingDecision(routingDecision) {
|
|
22
|
-
const { decisionId, committedAt, assessment, disposition, provenance } = routingDecision;
|
|
23
|
-
const impression = ClinicalImpression.fromRoutingAssessment({
|
|
24
|
-
assessment,
|
|
25
|
-
decisionId,
|
|
26
|
-
committedAt,
|
|
27
|
-
deferredItems: disposition.deferredItems,
|
|
28
|
-
primaryCaseId: disposition.primaryCaseId,
|
|
29
|
-
});
|
|
30
|
-
const resourceClass = DISPOSITION_BY_KIND[disposition.kind];
|
|
31
|
-
if (!resourceClass) throw new Error(`unknown routing-disposition kind: ${disposition.kind}`);
|
|
32
|
-
const dispositionResource = resourceClass.fromRoutingDisposition({ disposition });
|
|
33
|
-
const provenanceResource = Provenance.fromRoutingDecision({
|
|
34
|
-
provenanceId: `${assessment.assessmentId}-prov`,
|
|
35
|
-
targetRefs: [
|
|
36
|
-
{ reference: `ClinicalImpression/${fhirId(assessment.assessmentId)}` },
|
|
37
|
-
{ reference: `${dispositionResource.resourceType}/${fhirId(disposition.dispositionId)}` },
|
|
38
|
-
],
|
|
39
|
-
provenance,
|
|
40
|
-
activityText: ACTIVITY_TEXT,
|
|
41
|
-
});
|
|
42
|
-
return [impression, dispositionResource, provenanceResource];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
module.exports = {
|
|
46
|
-
projectRoutingDecision,
|
|
47
|
-
PROJECTOR_NAME,
|
|
48
|
-
};
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
const { fhirId } = require('../helpers/fhirHelper');
|
|
2
|
-
const { ClinicalImpression } = require('../resources/ClinicalImpression');
|
|
3
|
-
const { Condition } = require('../resources/Condition');
|
|
4
|
-
const { Observation } = require('../resources/Observation');
|
|
5
|
-
const { Provenance } = require('../resources/Provenance');
|
|
6
|
-
|
|
7
|
-
const PROJECTOR_NAME = 'symptomCase';
|
|
8
|
-
const ACTIVITY_TEXT = 'symptom-management';
|
|
9
|
-
const PLACEHOLDER_DECISION_POSTURE = 'pending_initial_assessment';
|
|
10
|
-
|
|
11
|
-
function assessmentResources(assessment, dropPreviousTo) {
|
|
12
|
-
const grade = assessment.grade;
|
|
13
|
-
const hasGradeSignal = grade.bestEstimate !== null
|
|
14
|
-
|| grade.possibleRange !== null
|
|
15
|
-
|| Boolean(grade.confidence)
|
|
16
|
-
|| Boolean(grade.reasoning)
|
|
17
|
-
|| Boolean(assessment.gradeThresholdClause);
|
|
18
|
-
const out = [ClinicalImpression.fromSymptomAssessment({ assessment, dropPreviousTo, hasGradeSignal })];
|
|
19
|
-
if (hasGradeSignal) out.push(Observation.fromSymptomGrade({ assessment }));
|
|
20
|
-
return out;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function projectSymptomCase(managedSymptom) {
|
|
24
|
-
const { condition, latestAssessment, priorAssessments } = managedSymptom;
|
|
25
|
-
const allAssessments = [latestAssessment, ...priorAssessments];
|
|
26
|
-
const placeholderIds = new Set(
|
|
27
|
-
allAssessments.filter((a) => a.decisionPosture === PLACEHOLDER_DECISION_POSTURE).map((a) => a.assessmentId),
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
const fhirCondition = Condition.fromSymptomCase({
|
|
31
|
-
condition,
|
|
32
|
-
verification: latestAssessment.gradeVerification,
|
|
33
|
-
headAssessmentId: latestAssessment.assessmentId,
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
const out = [fhirCondition, ...assessmentResources(latestAssessment, placeholderIds)];
|
|
37
|
-
const provenanceTargets = [
|
|
38
|
-
{ reference: `Condition/${fhirId(condition.conditionId)}` },
|
|
39
|
-
{ reference: `ClinicalImpression/${fhirId(latestAssessment.assessmentId)}` },
|
|
40
|
-
];
|
|
41
|
-
out.push(Provenance.fromSymptomCase({
|
|
42
|
-
provenanceId: `${condition.conditionId}-prov`,
|
|
43
|
-
targetRefs: provenanceTargets,
|
|
44
|
-
recordedAt: latestAssessment.performedAt,
|
|
45
|
-
activityText: ACTIVITY_TEXT,
|
|
46
|
-
}));
|
|
47
|
-
|
|
48
|
-
for (const prior of priorAssessments) {
|
|
49
|
-
if (placeholderIds.has(prior.assessmentId)) continue;
|
|
50
|
-
out.push(...assessmentResources(prior, placeholderIds));
|
|
51
|
-
out.push(Provenance.fromSymptomCase({
|
|
52
|
-
provenanceId: `${prior.assessmentId}-prov`,
|
|
53
|
-
targetRefs: [{ reference: `ClinicalImpression/${fhirId(prior.assessmentId)}` }],
|
|
54
|
-
recordedAt: prior.performedAt,
|
|
55
|
-
activityText: ACTIVITY_TEXT,
|
|
56
|
-
}));
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return out;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
module.exports = {
|
|
63
|
-
projectSymptomCase,
|
|
64
|
-
PROJECTOR_NAME,
|
|
65
|
-
};
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
const { fhirId } = require('../helpers/fhirHelper');
|
|
2
|
-
const {
|
|
3
|
-
identifier,
|
|
4
|
-
patientReference,
|
|
5
|
-
reference,
|
|
6
|
-
codeableConcept,
|
|
7
|
-
extension,
|
|
8
|
-
toIso,
|
|
9
|
-
} = require('../helpers/elementHelper');
|
|
10
|
-
const { CONTINGENCY_PLAN_SLUG, ROUTING_DISPOSITION_SLUG } = require('../constants/projectionSlugs');
|
|
11
|
-
|
|
12
|
-
const CONTINGENCY_STATUS_TO_FHIR = {
|
|
13
|
-
armed: 'active',
|
|
14
|
-
fired_reminder: 'active',
|
|
15
|
-
fired_team: 'active',
|
|
16
|
-
auto_resolved: 'completed',
|
|
17
|
-
cancelled: 'revoked',
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
class CarePlan {
|
|
21
|
-
constructor(payload) {
|
|
22
|
-
Object.assign(this, payload);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
static fromContingency({ carePlan }) {
|
|
26
|
-
const payload = {
|
|
27
|
-
resourceType: 'CarePlan',
|
|
28
|
-
id: fhirId(carePlan.planId),
|
|
29
|
-
identifier: [identifier(CONTINGENCY_PLAN_SLUG, carePlan.planId)],
|
|
30
|
-
status: CONTINGENCY_STATUS_TO_FHIR[carePlan.status],
|
|
31
|
-
intent: 'plan',
|
|
32
|
-
subject: patientReference(carePlan.patientId),
|
|
33
|
-
created: toIso(carePlan.createdAt),
|
|
34
|
-
period: contingencyPeriod(carePlan),
|
|
35
|
-
};
|
|
36
|
-
if (carePlan.concern) payload.description = carePlan.concern;
|
|
37
|
-
if (carePlan.relatedCaseId) {
|
|
38
|
-
payload.addresses = [{ reference: reference('Condition', carePlan.relatedCaseId) }];
|
|
39
|
-
}
|
|
40
|
-
if (carePlan.relatedClusterId) {
|
|
41
|
-
payload.supportingInfo = [reference('ClinicalImpression', carePlan.relatedClusterId)];
|
|
42
|
-
}
|
|
43
|
-
const ext = contingencyExtensions(carePlan);
|
|
44
|
-
if (ext.length) payload.extension = ext;
|
|
45
|
-
return new CarePlan(payload);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
static fromRoutingDisposition({ disposition }) {
|
|
49
|
-
const payload = {
|
|
50
|
-
resourceType: 'CarePlan',
|
|
51
|
-
id: fhirId(disposition.dispositionId),
|
|
52
|
-
identifier: [identifier(ROUTING_DISPOSITION_SLUG, disposition.dispositionId)],
|
|
53
|
-
status: 'active',
|
|
54
|
-
intent: 'plan',
|
|
55
|
-
category: [codeableConcept(disposition.primaryAction)],
|
|
56
|
-
subject: patientReference(disposition.patientId),
|
|
57
|
-
created: toIso(disposition.authoredAt),
|
|
58
|
-
description: disposition.primaryReason,
|
|
59
|
-
};
|
|
60
|
-
if (disposition.primaryCaseId) {
|
|
61
|
-
payload.addresses = [{ reference: reference('Condition', disposition.primaryCaseId) }];
|
|
62
|
-
}
|
|
63
|
-
return new CarePlan(payload);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function contingencyPeriod(carePlan) {
|
|
68
|
-
const period = { start: toIso(carePlan.createdAt) };
|
|
69
|
-
if (carePlan.resolvedAt) period.end = toIso(carePlan.resolvedAt);
|
|
70
|
-
return period;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function contingencyExtensions(carePlan) {
|
|
74
|
-
const out = [extension('contingency-status', { valueString: carePlan.status })];
|
|
75
|
-
if (carePlan.awaitingCharacterization) {
|
|
76
|
-
out.push(extension('contingency-awaiting-characterization', { valueString: carePlan.awaitingCharacterization }));
|
|
77
|
-
}
|
|
78
|
-
if (carePlan.whyThisMatters) {
|
|
79
|
-
out.push(extension('contingency-why-this-matters', { valueString: carePlan.whyThisMatters }));
|
|
80
|
-
}
|
|
81
|
-
if (carePlan.creationReasoning) {
|
|
82
|
-
out.push(extension('contingency-creation-reasoning', { valueString: carePlan.creationReasoning }));
|
|
83
|
-
}
|
|
84
|
-
if (carePlan.resolvedReason) {
|
|
85
|
-
out.push(extension('contingency-resolved-reason', { valueString: carePlan.resolvedReason }));
|
|
86
|
-
}
|
|
87
|
-
return out;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
module.exports = {
|
|
91
|
-
CarePlan,
|
|
92
|
-
CONTINGENCY_STATUS_TO_FHIR,
|
|
93
|
-
};
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
const { fhirId } = require('../helpers/fhirHelper');
|
|
2
|
-
const { identifier, reference, patientReference, codeableConcept, extension, toIso } = require('../helpers/elementHelper');
|
|
3
|
-
const { SYMPTOM_ASSESSMENT_SLUG, CLUSTER_IMPRESSION_SLUG, CLUSTER_LABEL_SLUG, ROUTING_ASSESSMENT_SLUG } = require('../constants/projectionSlugs');
|
|
4
|
-
|
|
5
|
-
const CLUSTER_STATUS_TO_FHIR = { active: 'in-progress', dissolved: 'completed' };
|
|
6
|
-
const CLUSTER_LIST_SEPARATOR = '; ';
|
|
7
|
-
|
|
8
|
-
class ClinicalImpression {
|
|
9
|
-
constructor(payload) {
|
|
10
|
-
Object.assign(this, payload);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
static fromClusterImpression({ cluster }) {
|
|
14
|
-
const epistemicExts = [
|
|
15
|
-
extension('clusterHypothesisType', { valueString: cluster.hypothesisType }),
|
|
16
|
-
extension('clusterHypothesisConfidence', { valueString: cluster.confidence }),
|
|
17
|
-
extension('clusterClinicalSignificance', { valueString: cluster.clinicalSignificance }),
|
|
18
|
-
];
|
|
19
|
-
if (cluster.strengthensIf.length) {
|
|
20
|
-
epistemicExts.push(extension('clusterStrengthensIf', { valueString: cluster.strengthensIf.join(CLUSTER_LIST_SEPARATOR) }));
|
|
21
|
-
}
|
|
22
|
-
if (cluster.weakensIf.length) {
|
|
23
|
-
epistemicExts.push(extension('clusterWeakensIf', { valueString: cluster.weakensIf.join(CLUSTER_LIST_SEPARATOR) }));
|
|
24
|
-
}
|
|
25
|
-
const lifecycleExts = [extension('cluster-status', { valueString: cluster.status })];
|
|
26
|
-
if (cluster.consultationId) lifecycleExts.push(extension('cluster-consultation-id', { valueString: cluster.consultationId }));
|
|
27
|
-
if (cluster.dissolveReason) lifecycleExts.push(extension('cluster-dissolve-reason', { valueString: cluster.dissolveReason }));
|
|
28
|
-
|
|
29
|
-
const identifiers = [identifier(CLUSTER_IMPRESSION_SLUG, cluster.clusterId)];
|
|
30
|
-
if (cluster.label) identifiers.push(identifier(CLUSTER_LABEL_SLUG, cluster.label));
|
|
31
|
-
|
|
32
|
-
const payload = {
|
|
33
|
-
resourceType: 'ClinicalImpression',
|
|
34
|
-
id: fhirId(cluster.clusterId),
|
|
35
|
-
identifier: identifiers,
|
|
36
|
-
status: CLUSTER_STATUS_TO_FHIR[cluster.status],
|
|
37
|
-
subject: patientReference(cluster.patientId),
|
|
38
|
-
problem: cluster.memberCaseIds.map((caseId) => reference('Condition', caseId)),
|
|
39
|
-
extension: [...epistemicExts, ...lifecycleExts],
|
|
40
|
-
};
|
|
41
|
-
if (cluster.relationshipModel) payload.summary = cluster.relationshipModel;
|
|
42
|
-
if (cluster.openingReasoning) payload.description = cluster.openingReasoning;
|
|
43
|
-
if (cluster.dissolvedAt) {
|
|
44
|
-
// toIso normalizes to Z; a non-Z openedAt/dissolvedAt does not byte-for-byte round-trip (known loss).
|
|
45
|
-
payload.effectivePeriod = { start: toIso(cluster.openedAt), end: toIso(cluster.dissolvedAt) };
|
|
46
|
-
} else {
|
|
47
|
-
payload.effectiveDateTime = toIso(cluster.openedAt);
|
|
48
|
-
}
|
|
49
|
-
if (cluster.dissolveCategory) payload.statusReason = codeableConcept(cluster.dissolveCategory);
|
|
50
|
-
return new ClinicalImpression(payload);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
static fromSymptomAssessment({ assessment, dropPreviousTo = null, hasGradeSignal = false }) {
|
|
54
|
-
const extensions = [];
|
|
55
|
-
if (assessment.trajectory) extensions.push(extension('trajectory', { valueString: assessment.trajectory }));
|
|
56
|
-
if (assessment.decisionPosture) extensions.push(extension('decision-posture', { valueString: assessment.decisionPosture }));
|
|
57
|
-
if (assessment.postureReason) extensions.push(extension('posture-reason', { valueString: assessment.postureReason }));
|
|
58
|
-
if (assessment.reasoning) extensions.push(extension('assessment-reasoning', { valueString: assessment.reasoning }));
|
|
59
|
-
const payload = {
|
|
60
|
-
resourceType: 'ClinicalImpression',
|
|
61
|
-
id: fhirId(assessment.assessmentId),
|
|
62
|
-
identifier: [identifier(SYMPTOM_ASSESSMENT_SLUG, assessment.assessmentId)],
|
|
63
|
-
status: 'completed',
|
|
64
|
-
subject: patientReference(assessment.patientId),
|
|
65
|
-
effectiveDateTime: toIso(assessment.performedAt),
|
|
66
|
-
problem: [reference('Condition', assessment.conditionId)],
|
|
67
|
-
extension: extensions,
|
|
68
|
-
};
|
|
69
|
-
if (hasGradeSignal) {
|
|
70
|
-
payload.finding = [{ item: { reference: reference('Observation', `${assessment.assessmentId}-grade`) } }];
|
|
71
|
-
}
|
|
72
|
-
if (assessment.problemRepresentation) payload.summary = assessment.problemRepresentation;
|
|
73
|
-
if (assessment.previousId && !(dropPreviousTo && dropPreviousTo.has(assessment.previousId))) {
|
|
74
|
-
payload.previous = reference('ClinicalImpression', assessment.previousId);
|
|
75
|
-
}
|
|
76
|
-
return new ClinicalImpression(payload);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
static fromRoutingAssessment({ assessment, decisionId, committedAt, deferredItems = [], primaryCaseId = null }) {
|
|
80
|
-
const extensions = [
|
|
81
|
-
extension('routing-turn-id', { valueString: assessment.turnId }),
|
|
82
|
-
extension('routing-decision-id', { valueString: decisionId }),
|
|
83
|
-
extension('routing-committed-at', { valueDateTime: toIso(committedAt) }),
|
|
84
|
-
];
|
|
85
|
-
if (primaryCaseId) extensions.push(extension('routing-primary-case-id', { valueString: primaryCaseId }));
|
|
86
|
-
for (const deferred of deferredItems) {
|
|
87
|
-
extensions.push(extension('routing-deferred-item', { valueString: deferred.item }));
|
|
88
|
-
extensions.push(extension('routing-deferred-reason', { valueString: deferred.deferReason }));
|
|
89
|
-
}
|
|
90
|
-
const payload = {
|
|
91
|
-
resourceType: 'ClinicalImpression',
|
|
92
|
-
id: fhirId(assessment.assessmentId),
|
|
93
|
-
identifier: [identifier(ROUTING_ASSESSMENT_SLUG, assessment.assessmentId)],
|
|
94
|
-
status: 'completed',
|
|
95
|
-
subject: patientReference(assessment.patientId),
|
|
96
|
-
effectiveDateTime: toIso(assessment.performedAt),
|
|
97
|
-
finding: assessment.findings.map((finding) => ({
|
|
98
|
-
item: reference('Condition', finding.caseId),
|
|
99
|
-
extension: [
|
|
100
|
-
extension('routing-finding-case-id', { valueString: finding.caseId }),
|
|
101
|
-
extension('routing-finding-reasoning', { valueString: finding.clinicalReasoning }),
|
|
102
|
-
extension('routing-finding-action', { valueString: finding.decisionAction }),
|
|
103
|
-
],
|
|
104
|
-
})),
|
|
105
|
-
extension: extensions,
|
|
106
|
-
};
|
|
107
|
-
if (assessment.summary) payload.summary = assessment.summary;
|
|
108
|
-
if (assessment.previousId) payload.previous = reference('ClinicalImpression', assessment.previousId);
|
|
109
|
-
if (assessment.notes.length) payload.note = assessment.notes.map((text) => ({ text }));
|
|
110
|
-
return new ClinicalImpression(payload);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
module.exports = {
|
|
115
|
-
ClinicalImpression,
|
|
116
|
-
CLUSTER_STATUS_TO_FHIR,
|
|
117
|
-
CLUSTER_LIST_SEPARATOR,
|
|
118
|
-
};
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
const { fhirId, codeSystemUrl } = require('../helpers/fhirHelper');
|
|
2
|
-
const {
|
|
3
|
-
identifier,
|
|
4
|
-
reference,
|
|
5
|
-
patientReference,
|
|
6
|
-
recipientReference,
|
|
7
|
-
codeableConcept,
|
|
8
|
-
notes,
|
|
9
|
-
toIso,
|
|
10
|
-
} = require('../helpers/elementHelper');
|
|
11
|
-
const {
|
|
12
|
-
INTERVENTION_SLUG,
|
|
13
|
-
INTERVENTION_KIND_SLUG,
|
|
14
|
-
ROUTING_DISPOSITION_SLUG,
|
|
15
|
-
} = require('../constants/projectionSlugs');
|
|
16
|
-
const { interventionExtensions } = require('./interventionExtensions');
|
|
17
|
-
|
|
18
|
-
class Communication {
|
|
19
|
-
constructor(payload) {
|
|
20
|
-
Object.assign(this, payload);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
static fromIntervention({ intervention }) {
|
|
24
|
-
const payload = {
|
|
25
|
-
resourceType: 'Communication',
|
|
26
|
-
id: fhirId(intervention.interventionId),
|
|
27
|
-
identifier: [identifier(INTERVENTION_SLUG, intervention.interventionId)],
|
|
28
|
-
status: 'completed',
|
|
29
|
-
category: [codeableConcept(intervention.kind, { code: intervention.kind, system: codeSystemUrl(INTERVENTION_KIND_SLUG) })],
|
|
30
|
-
subject: patientReference(intervention.patientId),
|
|
31
|
-
reason: [{ reference: reference('Condition', intervention.caseId) }],
|
|
32
|
-
sent: toIso(intervention.deliveredAt),
|
|
33
|
-
payload: [{ contentCodeableConcept: codeableConcept(intervention.interventionLabel) }],
|
|
34
|
-
recipient: [recipientReference({
|
|
35
|
-
patientId: intervention.patientId,
|
|
36
|
-
recipientKind: intervention.recipientKind,
|
|
37
|
-
recipientRefId: intervention.recipientRefId,
|
|
38
|
-
})],
|
|
39
|
-
extension: interventionExtensions(intervention),
|
|
40
|
-
};
|
|
41
|
-
const note = notes(intervention.rationale, intervention.outcomeNotes);
|
|
42
|
-
if (note) payload.note = note;
|
|
43
|
-
return new Communication(payload);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
static fromRoutingDisposition({ disposition }) {
|
|
47
|
-
const payload = {
|
|
48
|
-
resourceType: 'Communication',
|
|
49
|
-
id: fhirId(disposition.dispositionId),
|
|
50
|
-
identifier: [identifier(ROUTING_DISPOSITION_SLUG, disposition.dispositionId)],
|
|
51
|
-
status: 'completed',
|
|
52
|
-
category: [codeableConcept(disposition.primaryAction)],
|
|
53
|
-
subject: patientReference(disposition.patientId),
|
|
54
|
-
sent: toIso(disposition.authoredAt),
|
|
55
|
-
payload: [{ contentCodeableConcept: codeableConcept(disposition.primaryReason) }],
|
|
56
|
-
recipient: [patientReference(disposition.patientId)],
|
|
57
|
-
};
|
|
58
|
-
if (disposition.primaryCaseId) {
|
|
59
|
-
payload.reason = [{ reference: reference('Condition', disposition.primaryCaseId) }];
|
|
60
|
-
}
|
|
61
|
-
return new Communication(payload);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
module.exports = { Communication };
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
const { getOrganizationId } = require('../config/fhirConfig');
|
|
2
|
-
const { fhirId, codeSystemUrl } = require('../helpers/fhirHelper');
|
|
3
|
-
const {
|
|
4
|
-
identifier,
|
|
5
|
-
reference,
|
|
6
|
-
patientReference,
|
|
7
|
-
recipientReference,
|
|
8
|
-
codeableConcept,
|
|
9
|
-
extension,
|
|
10
|
-
notes,
|
|
11
|
-
toIso,
|
|
12
|
-
} = require('../helpers/elementHelper');
|
|
13
|
-
const {
|
|
14
|
-
ESCALATION_SLUG,
|
|
15
|
-
ESCALATION_KIND_SLUG,
|
|
16
|
-
REMINDER_SLUG,
|
|
17
|
-
REMINDER_KIND_SLUG,
|
|
18
|
-
COMMUNICATION_CHANNEL_SLUG,
|
|
19
|
-
CONTINGENCY_STEP_SLUG,
|
|
20
|
-
INTERVENTION_SLUG,
|
|
21
|
-
INTERVENTION_KIND_SLUG,
|
|
22
|
-
ROUTING_DISPOSITION_SLUG,
|
|
23
|
-
} = require('../constants/projectionSlugs');
|
|
24
|
-
const { SEVERITY_TO_PRIORITY } = require('../constants/severityPriority');
|
|
25
|
-
const { CONTINGENCY_STATUS_TO_FHIR } = require('./CarePlan');
|
|
26
|
-
|
|
27
|
-
const CONTINGENCY_PRIORITY_CROSSWALK = {
|
|
28
|
-
critical: 'stat',
|
|
29
|
-
high: 'urgent',
|
|
30
|
-
medium: 'routine',
|
|
31
|
-
low: 'routine',
|
|
32
|
-
routine: 'routine',
|
|
33
|
-
urgent: 'urgent',
|
|
34
|
-
asap: 'asap',
|
|
35
|
-
stat: 'stat',
|
|
36
|
-
};
|
|
37
|
-
const { interventionExtensions } = require('./interventionExtensions');
|
|
38
|
-
|
|
39
|
-
const NOTIFY_STATUS_TO_CR_STATUS = {
|
|
40
|
-
queued: 'active',
|
|
41
|
-
sent: 'active',
|
|
42
|
-
acknowledged: 'completed',
|
|
43
|
-
failed: 'revoked',
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const REMINDER_STATUS_TO_CR_STATUS = {
|
|
47
|
-
scheduled: 'active',
|
|
48
|
-
cancelled: 'revoked',
|
|
49
|
-
expired: 'revoked',
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
class CommunicationRequest {
|
|
53
|
-
constructor(payload) {
|
|
54
|
-
Object.assign(this, payload);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
static fromNotifyEscalation({ notify }) {
|
|
58
|
-
const payload = {
|
|
59
|
-
resourceType: 'CommunicationRequest',
|
|
60
|
-
id: fhirId(notify.eventId),
|
|
61
|
-
identifier: [identifier(ESCALATION_SLUG, notify.eventId)],
|
|
62
|
-
status: NOTIFY_STATUS_TO_CR_STATUS[notify.status],
|
|
63
|
-
intent: 'plan',
|
|
64
|
-
priority: SEVERITY_TO_PRIORITY[notify.severity] || 'routine',
|
|
65
|
-
category: [codeableConcept(notify.kind, { code: notify.kind, system: codeSystemUrl(ESCALATION_KIND_SLUG) })],
|
|
66
|
-
subject: patientReference(notify.patientId),
|
|
67
|
-
authoredOn: toIso(notify.createdAt),
|
|
68
|
-
};
|
|
69
|
-
if (notify.reason) payload.reason = [{ concept: codeableConcept(notify.reason) }];
|
|
70
|
-
if (typeof notify.recipient === 'string' && /^[A-Za-z]+\/[A-Za-z0-9._-]+$/.test(notify.recipient)) {
|
|
71
|
-
payload.recipient = [{ reference: notify.recipient }];
|
|
72
|
-
}
|
|
73
|
-
if (notify.requiresAck) {
|
|
74
|
-
payload.extension = [extension('requires-ack', { valueBoolean: true })];
|
|
75
|
-
}
|
|
76
|
-
if (notify.fireAt) payload.occurrenceDateTime = toIso(notify.fireAt);
|
|
77
|
-
if (notify.followupPurpose) {
|
|
78
|
-
(payload.extension || (payload.extension = [])).push(
|
|
79
|
-
extension('followup-purpose', { valueString: notify.followupPurpose }),
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
return new CommunicationRequest(payload);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
static fromReminder({ reminder }) {
|
|
86
|
-
const payload = {
|
|
87
|
-
resourceType: 'CommunicationRequest',
|
|
88
|
-
id: fhirId(reminder.reminderId),
|
|
89
|
-
identifier: [identifier(REMINDER_SLUG, reminder.reminderId)],
|
|
90
|
-
status: REMINDER_STATUS_TO_CR_STATUS[reminder.status],
|
|
91
|
-
intent: 'plan',
|
|
92
|
-
category: [codeableConcept(reminder.kind, { code: reminder.kind, system: codeSystemUrl(REMINDER_KIND_SLUG) })],
|
|
93
|
-
medium: [codeableConcept(reminder.channel, { code: reminder.channel, system: codeSystemUrl(COMMUNICATION_CHANNEL_SLUG) })],
|
|
94
|
-
subject: patientReference(reminder.patientId),
|
|
95
|
-
recipient: [recipientReference({
|
|
96
|
-
patientId: reminder.patientId,
|
|
97
|
-
recipientKind: reminder.recipientKind,
|
|
98
|
-
recipientRefId: reminder.recipientRefId,
|
|
99
|
-
})],
|
|
100
|
-
payload: [{ contentCodeableConcept: codeableConcept(reminder.message) }],
|
|
101
|
-
occurrenceDateTime: toIso(reminder.fireAt),
|
|
102
|
-
authoredOn: toIso(reminder.authoredAt),
|
|
103
|
-
};
|
|
104
|
-
if (reminder.cancelReason) payload.statusReason = codeableConcept(reminder.cancelReason);
|
|
105
|
-
return new CommunicationRequest(payload);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
static fromContingencyStep({ step, planId, patientId, createdAt, parentStatus }) {
|
|
109
|
-
const stepId = `${planId}-${step.recipient}`;
|
|
110
|
-
const payload = {
|
|
111
|
-
resourceType: 'CommunicationRequest',
|
|
112
|
-
id: fhirId(stepId),
|
|
113
|
-
identifier: [identifier(CONTINGENCY_STEP_SLUG, stepId)],
|
|
114
|
-
status: CONTINGENCY_STATUS_TO_FHIR[parentStatus],
|
|
115
|
-
intent: 'plan',
|
|
116
|
-
category: [codeableConcept(`contingency-${step.recipient}`)],
|
|
117
|
-
subject: patientReference(patientId),
|
|
118
|
-
recipient: [step.recipient === 'patient'
|
|
119
|
-
? patientReference(patientId)
|
|
120
|
-
: { reference: `Organization/${fhirId(getOrganizationId())}` }],
|
|
121
|
-
payload: [{ contentCodeableConcept: codeableConcept(step.message) }],
|
|
122
|
-
authoredOn: toIso(createdAt),
|
|
123
|
-
basedOn: [{ reference: `CarePlan/${fhirId(planId)}` }],
|
|
124
|
-
};
|
|
125
|
-
const priority = step.priority ? CONTINGENCY_PRIORITY_CROSSWALK[step.priority] || 'routine' : null;
|
|
126
|
-
if (priority) payload.priority = priority;
|
|
127
|
-
const ext = [];
|
|
128
|
-
if (step.priority) ext.push(extension('contingency-step-priority', { valueString: step.priority }));
|
|
129
|
-
if (step.actionRequested) ext.push(extension('contingency-action-requested', { valueString: step.actionRequested }));
|
|
130
|
-
if (step.firesAfterSilenceMinutes !== null && step.firesAfterSilenceMinutes !== undefined) {
|
|
131
|
-
ext.push(extension('fires-after-silence-minutes', { valueInteger: step.firesAfterSilenceMinutes }));
|
|
132
|
-
}
|
|
133
|
-
if (ext.length) payload.extension = ext;
|
|
134
|
-
return new CommunicationRequest(payload);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
static fromIntervention({ intervention }) {
|
|
138
|
-
const payload = {
|
|
139
|
-
resourceType: 'CommunicationRequest',
|
|
140
|
-
id: fhirId(intervention.interventionId),
|
|
141
|
-
identifier: [identifier(INTERVENTION_SLUG, intervention.interventionId)],
|
|
142
|
-
status: intervention.outcome === 'pending' ? 'active' : 'completed',
|
|
143
|
-
intent: 'plan',
|
|
144
|
-
category: [codeableConcept(intervention.kind, { code: intervention.kind, system: codeSystemUrl(INTERVENTION_KIND_SLUG) })],
|
|
145
|
-
subject: patientReference(intervention.patientId),
|
|
146
|
-
reason: [{ reference: reference('Condition', intervention.caseId) }],
|
|
147
|
-
payload: [{ contentCodeableConcept: codeableConcept(intervention.interventionLabel) }],
|
|
148
|
-
recipient: [recipientReference({
|
|
149
|
-
patientId: intervention.patientId,
|
|
150
|
-
recipientKind: intervention.recipientKind,
|
|
151
|
-
recipientRefId: intervention.recipientRefId,
|
|
152
|
-
})],
|
|
153
|
-
occurrenceDateTime: toIso(intervention.deliveredAt),
|
|
154
|
-
authoredOn: toIso(intervention.deliveredAt),
|
|
155
|
-
extension: interventionExtensions(intervention),
|
|
156
|
-
};
|
|
157
|
-
const note = notes(intervention.rationale, intervention.outcomeNotes);
|
|
158
|
-
if (note) payload.note = note;
|
|
159
|
-
return new CommunicationRequest(payload);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
static fromRoutingDisposition({ disposition }) {
|
|
163
|
-
const payload = {
|
|
164
|
-
resourceType: 'CommunicationRequest',
|
|
165
|
-
id: fhirId(disposition.dispositionId),
|
|
166
|
-
identifier: [identifier(ROUTING_DISPOSITION_SLUG, disposition.dispositionId)],
|
|
167
|
-
status: 'active',
|
|
168
|
-
intent: 'plan',
|
|
169
|
-
category: [codeableConcept(disposition.primaryAction)],
|
|
170
|
-
subject: patientReference(disposition.patientId),
|
|
171
|
-
authoredOn: toIso(disposition.authoredAt),
|
|
172
|
-
payload: [{ contentCodeableConcept: codeableConcept(disposition.primaryReason) }],
|
|
173
|
-
recipient: [patientReference(disposition.patientId)],
|
|
174
|
-
};
|
|
175
|
-
if (disposition.primaryCaseId) {
|
|
176
|
-
payload.reason = [{ reference: reference('Condition', disposition.primaryCaseId) }];
|
|
177
|
-
}
|
|
178
|
-
return new CommunicationRequest(payload);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
module.exports = { CommunicationRequest };
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
const { fhirId } = require('../helpers/fhirHelper');
|
|
2
|
-
const { identifier, codeableConcept } = require('../helpers/elementHelper');
|
|
3
|
-
|
|
4
|
-
class Device {
|
|
5
|
-
constructor(payload) {
|
|
6
|
-
Object.assign(this, payload);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
static fromTriageProjection({ deviceId, compositeTableHash }) {
|
|
10
|
-
const version = [{ value: 'pro-ctcae-composite' }];
|
|
11
|
-
if (compositeTableHash) version.push({ type: { text: 'composite-table' }, value: `sha256:${compositeTableHash}` });
|
|
12
|
-
return new Device({
|
|
13
|
-
resourceType: 'Device',
|
|
14
|
-
id: fhirId(deviceId),
|
|
15
|
-
identifier: [identifier('device', deviceId)],
|
|
16
|
-
status: 'active',
|
|
17
|
-
name: [{ value: 'PRO-CTCAE composite → CTCAE grade estimator', type: 'user-friendly-name' }],
|
|
18
|
-
type: [codeableConcept('Software / clinical algorithm')],
|
|
19
|
-
version,
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
module.exports = { Device };
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
const { fhirId } = require('../helpers/fhirHelper');
|
|
2
|
-
const { identifier } = require('../helpers/elementHelper');
|
|
3
|
-
|
|
4
|
-
class Patient {
|
|
5
|
-
constructor(payload) {
|
|
6
|
-
Object.assign(this, payload);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
static fromTriageProjection({ patientId }) {
|
|
10
|
-
return new Patient({
|
|
11
|
-
resourceType: 'Patient',
|
|
12
|
-
id: fhirId(String(patientId)),
|
|
13
|
-
identifier: [identifier('patient', String(patientId))],
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
module.exports = { Patient };
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const { getQuestionnaireCanonicalUrl, getProctcaeVersion } = require('../config/fhirConfig');
|
|
2
|
-
const { fhirId } = require('../helpers/fhirHelper');
|
|
3
|
-
|
|
4
|
-
class Questionnaire {
|
|
5
|
-
constructor(payload) {
|
|
6
|
-
Object.assign(this, payload);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
static fromProctcaeCatalog({ items }) {
|
|
10
|
-
return new Questionnaire({
|
|
11
|
-
resourceType: 'Questionnaire',
|
|
12
|
-
id: fhirId(`pro-ctcae-${getProctcaeVersion()}`),
|
|
13
|
-
url: getQuestionnaireCanonicalUrl(),
|
|
14
|
-
version: getProctcaeVersion(),
|
|
15
|
-
status: 'active',
|
|
16
|
-
name: 'PROCTCAE',
|
|
17
|
-
subjectType: ['Patient'],
|
|
18
|
-
item: items,
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
module.exports = { Questionnaire };
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
const { getQuestionnaireCanonicalUrl, getProctcaeVersion } = require('../config/fhirConfig');
|
|
2
|
-
const { fhirId } = require('../helpers/fhirHelper');
|
|
3
|
-
const { identifier, patientReference, toIso } = require('../helpers/elementHelper');
|
|
4
|
-
|
|
5
|
-
class QuestionnaireResponse {
|
|
6
|
-
constructor(payload) {
|
|
7
|
-
Object.assign(this, payload);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
static fromTriageProjection({ qr, items }) {
|
|
11
|
-
const tid = String(qr.triageId);
|
|
12
|
-
const identifiers = [identifier('triage', tid)];
|
|
13
|
-
if (qr.questionnaireId) identifiers.push(identifier('questionnaire-week', String(qr.questionnaireId)));
|
|
14
|
-
const payload = {
|
|
15
|
-
resourceType: 'QuestionnaireResponse',
|
|
16
|
-
id: fhirId(`triage-${tid}`),
|
|
17
|
-
identifier: identifiers,
|
|
18
|
-
questionnaire: `${getQuestionnaireCanonicalUrl()}|${getProctcaeVersion()}`,
|
|
19
|
-
status: (qr.completed ?? true) ? 'completed' : 'in-progress',
|
|
20
|
-
subject: patientReference(qr.patientId),
|
|
21
|
-
source: patientReference(qr.patientId),
|
|
22
|
-
};
|
|
23
|
-
if (qr.authored) payload.authored = toIso(qr.authored);
|
|
24
|
-
if (items.length) payload.item = items;
|
|
25
|
-
return new QuestionnaireResponse(payload);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
module.exports = { QuestionnaireResponse };
|