diff --git a/docs/CSV_Templates.xlsx b/docs/CSV_Templates.xlsx
index 1d187b35..48c205cd 100755
Binary files a/docs/CSV_Templates.xlsx and b/docs/CSV_Templates.xlsx differ
diff --git a/docs/ctc-adverse-event.csv b/docs/ctc-adverse-event.csv
index 09bc9d44..272acee8 100644
--- a/docs/ctc-adverse-event.csv
+++ b/docs/ctc-adverse-event.csv
@@ -1,4 +1,4 @@
-mrn,adverseEventId,adverseEventCode,adverseEventCodeSystem,adverseEventCodeVersion,adverseEventDisplayText,adverseEventText,suspectedCauseId,suspectedCauseType,seriousness,seriousnessCodeSystem,seriousnessDisplayText,category,categoryCodeSystem,categoryDisplayText,studyId,effectiveDate,recordedDate,grade,expectation,resolvedDate,seriousnessOutcome
-mrn-full-example,example-id-1,event-code,code-system,code-version,code-display,event-text,cause-id,resourceType,seriousness-code,code-system,seriousness-display,category-code,code-system,category-dislpay,id,1994-12-09,1994-12-09,1,expectation-code,YYYY-MM-DD,seriousness-outcome-code
-mrn-two-category-example,example-id-2,event-code,code-system,code-version,code-display,event-text,cause-id,resourceType,seriousness-code,code-system,seriousness-display,category-code,code-system,category-dislpay,id,1994-12-09,1994-12-09,1,expectation-code,YYYY-MM-DD,seriousness-outcome-code
-mrn-minimal-example,,code-from-default-system,,,,,,,,,,,,,1994-12-09,,1,,,,,
+mrn,adverseEventId,adverseEventCode,adverseEventCodeSystem,adverseEventCodeVersion,adverseEventDisplayText,adverseEventText,suspectedCauseId,suspectedCauseType,seriousness,seriousnessCodeSystem,seriousnessDisplayText,category,categoryCodeSystem,categoryDisplayText,studyId,effectiveDate,recordedDate,grade,expectation,resolvedDate,seriousnessOutcome,actor,functionCode
+mrn-full-example,example-id-1,event-code,code-system,code-version,code-display,event-text,cause-id,resourceType,seriousness-code,code-system,seriousness-display,category-code,code-system,category-dislpay,id,1994-12-09,1994-12-09,1,expectation-code,YYYY-MM-DD,seriousness-outcome-code,practitioner-id,function-code
+mrn-two-category-example,example-id-2,event-code,code-system,code-version,code-display,event-text,cause-id,resourceType,seriousness-code,code-system,seriousness-display,category-code,code-system,category-dislpay,id,1994-12-09,1994-12-09,1,expectation-code,YYYY-MM-DD,seriousness-outcome-code,practitioner-id,
+mrn-minimal-example,,code-from-default-system,,,,,,,,,,,,,1994-12-09,,1,,,,,,
diff --git a/src/extractors/CSVCTCAdverseEventExtractor.js b/src/extractors/CSVCTCAdverseEventExtractor.js
index 6657a709..6fd941cc 100644
--- a/src/extractors/CSVCTCAdverseEventExtractor.js
+++ b/src/extractors/CSVCTCAdverseEventExtractor.js
@@ -34,10 +34,14 @@ function formatData(adverseEventData, patientId) {
expectation,
resolveddate: resolvedDate,
seriousnessoutcome: seriousnessOutcome,
+ actor,
+ functioncode: functionCode,
} = data;
if (!(adverseEventCode && effectiveDate && grade)) {
throw new Error('The adverse event is missing an expected attribute. Adverse event code, effective date, and grade are all required.');
+ } else if (functionCode && !actor) {
+ throw new Error('The adverse event is missing an expected attribute. Adverse event actor is a required element when a functionCode value is included.');
}
const categoryCodes = category.split('|');
@@ -90,6 +94,16 @@ function formatData(adverseEventData, patientId) {
'http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl',
),
},
+ actor,
+ functionCode: !functionCode ? null : {
+ code: functionCode,
+ system: 'http://terminology.hl7.org/CodeSystem/v3-ParticipationType',
+ display: getDisplayFromConcept(
+ path.resolve(__dirname, '..', 'helpers', 'valueSets', 'adverse-event-participant-function-value-set.json'),
+ functionCode,
+ 'http://terminology.hl7.org/CodeSystem/v3-ParticipationType',
+ ),
+ },
};
});
}
diff --git a/src/helpers/valueSets/adverse-event-participant-function-value-set.json b/src/helpers/valueSets/adverse-event-participant-function-value-set.json
new file mode 100644
index 00000000..7b895e92
--- /dev/null
+++ b/src/helpers/valueSets/adverse-event-participant-function-value-set.json
@@ -0,0 +1,67 @@
+{
+ "resourceType": "ValueSet",
+ "id": "adverse-event-participant-function-value-set",
+ "text": {
+ "status": "extensions",
+ "div": "
- Include these codes as defined in
http://terminology.hl7.org/CodeSystem/v3-ParticipationType| Code | Display | Definition |
| INF | Informant | A source of reported information (e.g., a next of kin who answers questions about the patient's history). For history questions, the patient is logically an informant, yet the informant of history questions is implicitly the subject. |
| PART | Participation | Indicates that the target of the participation is involved in some manner in the act, but does not qualify how. |
| WIT | Witness | Only with service events. A person witnessing the action happening without doing anything. A witness is not necessarily aware, much less approves of anything stated in the service event. Example for a witness is students watching an operation or an advanced directive witness. |
| AUT | Author (originator) | **Definition:** A party that originates the Act and therefore has responsibility for the information given in the Act and ownership of this Act.
**Example:** the report writer, the person writing the act definition, the guideline author, the placer of an order, the EKG cart (device) creating a report etc. Every Act should have an author. Authorship is regardless of mood always actual authorship.
Examples of such policies might include:
* The author and anyone they explicitly delegate may update the report; * All administrators within the same clinic may cancel and reschedule appointments created by other administrators within that clinic;
A party that is neither an author nor a party who is extended authorship maintenance rights by policy, may only amend, reverse, override, replace, or follow up in other ways on this Act, whereby the Act remains intact and is linked to another Act authored by that other party. |
| AUTHEN | Authenticator | A verifier who attests to the accuracy of an act, but who does not have privileges to legally authenticate the act. An example would be a resident physician who sees a patient and dictates a note, then later signs it. Their signature constitutes an authentication. |
"
+ },
+ "url": "http://hl7.org/fhir/us/ctcae/ValueSet/adverse-event-participant-function-value-set",
+ "version": "0.0.1",
+ "name": "AdverseEventParticipantFunctionVS",
+ "title": "Adverse Event Participant Function",
+ "status": "active",
+ "date": "2021-12-03T16:46:43+00:00",
+ "publisher": "HL7 International Clinical Interoperability Council",
+ "contact": [
+ {
+ "name": "HL7 International Clinical Interoperability Council",
+ "telecom": [
+ {
+ "system": "url",
+ "value": "http://www.mcodeinitiative.org"
+ }
+ ]
+ }
+ ],
+ "description": "This value set includes codes that describe the type of involvement of the actor in the adverse event",
+ "jurisdiction": [
+ {
+ "coding": [
+ {
+ "system": "urn:iso:std:iso:3166",
+ "code": "US",
+ "display": "United States of America"
+ }
+ ]
+ }
+ ],
+ "compose": {
+ "include": [
+ {
+ "system": "http://terminology.hl7.org/CodeSystem/v3-ParticipationType",
+ "concept": [
+ {
+ "code": "INF",
+ "display": "Informant"
+ },
+ {
+ "code": "PART",
+ "display": "Participation"
+ },
+ {
+ "code": "WIT",
+ "display": "Witness"
+ },
+ {
+ "code": "AUT",
+ "display": "Author (originator)"
+ },
+ {
+ "code": "AUTHEN",
+ "display": "Authenticator"
+ }
+ ]
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/src/templates/CTCAdverseEventTemplate.js b/src/templates/CTCAdverseEventTemplate.js
index fb0fd1ea..02619cfb 100644
--- a/src/templates/CTCAdverseEventTemplate.js
+++ b/src/templates/CTCAdverseEventTemplate.js
@@ -102,13 +102,47 @@ function seriousnessOutcomeTemplate(seriousnessOutcome) {
};
}
+function participantFunctionTemplate(functionCode) {
+ return {
+ url: 'function',
+ valueCodeableConcept: {
+ coding: [
+ coding(functionCode),
+ ],
+ },
+ };
+}
+
+function participantActorTemplate(actor) {
+ return {
+ url: 'actor',
+ valueReference: {
+ ...reference({ id: actor }),
+ },
+ };
+}
+
+function participantTemplate(actor, functionCode) {
+ return {
+ url: 'http://hl7.org/fhir/us/ctcae/StructureDefinition/adverse-event-participant',
+ ...extensionArr(
+ functionCode ? participantFunctionTemplate(functionCode) : null,
+ participantActorTemplate(actor),
+ ),
+ };
+}
+
function CTCAdverseEventTemplate({
id, subjectId, code, system, version, display, text, suspectedCauseId, suspectedCauseType, seriousnessCode, seriousnessCodeSystem, seriousnessDisplayText, category,
- studyId, effectiveDateTime, recordedDateTime, grade, resolvedDate, expectation, seriousnessOutcome,
+ studyId, effectiveDateTime, recordedDateTime, grade, resolvedDate, expectation, seriousnessOutcome, actor, functionCode,
}) {
if (!(subjectId && code && system && effectiveDateTime && grade)) {
- throw Error('Trying to render an AdverseEventTemplate, but a required argument is messing; ensure that subjectId, code, system, grade, and effectiveDateTime are all present');
+ throw Error('Trying to render an AdverseEventTemplate, but a required argument is missing; ensure that subjectId, code, system, grade, and effectiveDateTime are all present');
+ }
+
+ if (functionCode && !actor) {
+ throw Error('Trying to render an AdverseEventTemplate, but a required argument is missing; actor is a required value when functionCode is included');
}
return {
@@ -119,6 +153,7 @@ function CTCAdverseEventTemplate({
resolvedDate ? resolvedDateTemplate(resolvedDate) : null,
expectation ? expectationTemplate(expectation) : null,
seriousnessOutcome ? seriousnessOutcomeTemplate(seriousnessOutcome) : null,
+ actor ? participantTemplate(actor, functionCode) : null,
),
subject: reference({ id: subjectId, resourceType: 'Patient' }),
...ifSomeArgs(eventTemplate)({ code, system, version, display }, text),
diff --git a/test/extractors/CSVCTCAdverseEventextractor.test.js b/test/extractors/CSVCTCAdverseEventextractor.test.js
index 39c0d259..352108e6 100644
--- a/test/extractors/CSVCTCAdverseEventextractor.test.js
+++ b/test/extractors/CSVCTCAdverseEventextractor.test.js
@@ -36,6 +36,7 @@ describe('CSVCTCAdverseEventExtractor', () => {
test('should join data appropriately and throw errors when missing required properties', () => {
const expectedErrorString = 'The adverse event is missing an expected attribute. Adverse event code, effective date, and grade are all required.';
const expectedCategoryErrorString = 'A category attribute on the adverse event is missing a corresponding categoryCodeSystem or categoryDisplayText value.';
+ const expectedActorErrorString = 'The adverse event is missing an expected attribute. Adverse event actor is a required element when a functionCode value is included.';
const localData = _.cloneDeep(exampleCTCCSVAdverseEventModuleResponse);
const patientId = getPatientFromContext(MOCK_CONTEXT).id;
@@ -60,6 +61,15 @@ describe('CSVCTCAdverseEventExtractor', () => {
localData[0].categorydisplaytext = 'Product Use Error|';
expect(formatData(localData, patientId)).toEqual(expect.anything());
+ // Test that deleting the actor value but leaving functionCode will throw an error
+ delete localData[0].actor;
+ expect(() => formatData(localData, patientId)).toThrow(new Error(expectedActorErrorString));
+
+ // Test that deleting the functionCode value works fine
+ localData[0].actor = 'practitioner-id';
+ delete localData[0].functioncode;
+ expect(formatData(localData, patientId)).toEqual(expect.anything());
+
// Test that deleting a mandatory value throws an error
delete localData[0].grade;
expect(() => formatData(localData, patientId)).toThrow(new Error(expectedErrorString));
diff --git a/test/extractors/fixtures/csv-ctc-adverse-event-bundle.json b/test/extractors/fixtures/csv-ctc-adverse-event-bundle.json
index 339a2c81..53097112 100644
--- a/test/extractors/fixtures/csv-ctc-adverse-event-bundle.json
+++ b/test/extractors/fixtures/csv-ctc-adverse-event-bundle.json
@@ -47,6 +47,29 @@
}
]
}
+ },
+ {
+ "url": "http://hl7.org/fhir/us/ctcae/StructureDefinition/adverse-event-participant",
+ "extension": [
+ {
+ "url": "function",
+ "valueCodeableConcept": {
+ "coding": [
+ {
+ "system": "http://terminology.hl7.org/CodeSystem/v3-ParticipationType",
+ "code": "INF",
+ "display": "Informant"
+ }
+ ]
+ }
+ },
+ {
+ "url": "actor",
+ "valueReference": {
+ "reference": "urn:uuid:practitioner-id"
+ }
+ }
+ ]
}
],
"subject": {
diff --git a/test/extractors/fixtures/csv-ctc-adverse-event-module-response.json b/test/extractors/fixtures/csv-ctc-adverse-event-module-response.json
index 0d3bfa6f..b156f157 100644
--- a/test/extractors/fixtures/csv-ctc-adverse-event-module-response.json
+++ b/test/extractors/fixtures/csv-ctc-adverse-event-module-response.json
@@ -21,6 +21,8 @@
"grade": "1",
"resolveddate": "2021-12-01",
"seriousnessoutcome": "C113380",
- "expectation": "C41333"
+ "expectation": "C41333",
+ "actor": "practitioner-id",
+ "functioncode": "INF"
}
]
\ No newline at end of file
diff --git a/test/sample-client-data/ctc-adverse-event-information.csv b/test/sample-client-data/ctc-adverse-event-information.csv
index 794c1ee9..a767ad39 100644
--- a/test/sample-client-data/ctc-adverse-event-information.csv
+++ b/test/sample-client-data/ctc-adverse-event-information.csv
@@ -1,4 +1,4 @@
-mrn,adverseEventId,adverseEventCode,adverseEventCodeSystem,adverseEventCodeVersion,adverseEventDisplayText,adverseEventText,suspectedCauseId,suspectedCauseType,seriousness,seriousnessCodeSystem,seriousnessDisplayText,category,categoryCodeSystem,categoryDisplayText,studyId,effectiveDate,recordedDate,grade,expectation,resolvedDate,seriousnessOutcome
-123,adverseEventId-1,10012174,http://terminology.hl7.org/CodeSystem/MDRAE,20.0,Dehydration,DHN IV given,procedure-id,Procedure,serious,http://terminology.hl7.org/CodeSystem/adverse-event-seriousness,Serious,product-use-error|product-quality|wrong-rate,http://terminology.hl7.org/CodeSystem/adverse-event-category|http://snomed.info/sct|http://terminology.hl7.org/CodeSystem/adverse-event-category,Product Use Error|Product Quality|Wrong Rate,researchId-1,12-09-1994,12-09-1994,1,C41333,2021-12-01,C113380
-456,adverseEventId-2,C143283,http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl,20.0,Anemia,AIHA NGTD,medicationId-1,Medication,non-serious,http://terminology.hl7.org/CodeSystem/adverse-event-seriousness,Non-serious,product-quality|wrong-rate,http://terminology.hl7.org/CodeSystem/adverse-event-category|,Product Quality|,researchId-2,12-10-1995,12-10-1995,2,C41333,2020-10-02,C113380
-789,adverseEventId-3,150003,,,,,,,,,,product-use-error,,,,12-09-1994,,3,,,
\ No newline at end of file
+mrn,adverseEventId,adverseEventCode,adverseEventCodeSystem,adverseEventCodeVersion,adverseEventDisplayText,adverseEventText,suspectedCauseId,suspectedCauseType,seriousness,seriousnessCodeSystem,seriousnessDisplayText,category,categoryCodeSystem,categoryDisplayText,studyId,effectiveDate,recordedDate,grade,expectation,resolvedDate,seriousnessOutcome,actor,functionCode
+123,adverseEventId-1,10012174,http://terminology.hl7.org/CodeSystem/MDRAE,20.0,Dehydration,DHN IV given,procedure-id,Procedure,serious,http://terminology.hl7.org/CodeSystem/adverse-event-seriousness,Serious,product-use-error|product-quality|wrong-rate,http://terminology.hl7.org/CodeSystem/adverse-event-category|http://snomed.info/sct|http://terminology.hl7.org/CodeSystem/adverse-event-category,Product Use Error|Product Quality|Wrong Rate,researchId-1,12-09-1994,12-09-1994,1,C41333,2021-12-01,C113380,practitioner-1,PART
+456,adverseEventId-2,C143283,http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl,20.0,Anemia,AIHA NGTD,medicationId-1,Medication,non-serious,http://terminology.hl7.org/CodeSystem/adverse-event-seriousness,Non-serious,product-quality|wrong-rate,http://terminology.hl7.org/CodeSystem/adverse-event-category|,Product Quality|,researchId-2,12-10-1995,12-10-1995,2,C41333,2020-10-02,C113380,practitioner-2,
+789,adverseEventId-3,150003,,,,,,,,,,product-use-error,,,,12-09-1994,,3,,,,,
\ No newline at end of file
diff --git a/test/templates/ctcAdverseEvent.test.js b/test/templates/ctcAdverseEvent.test.js
index 625cadd1..efbf6207 100644
--- a/test/templates/ctcAdverseEvent.test.js
+++ b/test/templates/ctcAdverseEvent.test.js
@@ -33,6 +33,12 @@ const VALID_DATA = {
system: 'http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl',
display: 'Expected Adverse Event',
},
+ actor: 'practitioner-id',
+ functionCode: {
+ code: 'PART',
+ system: 'http://terminology.hl7.org/CodeSystem/v3-ParticipationType',
+ display: 'Participation',
+ },
};
const MINIMAL_DATA = {
@@ -90,6 +96,12 @@ const INVALID_DATA = {
system: 'http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl',
display: 'Expected Adverse Event',
},
+ actor: 'practitioner-id',
+ functionCode: {
+ code: 'PART',
+ system: 'http://terminology.hl7.org/CodeSystem/v3-ParticipationType',
+ display: 'Participation',
+ },
};
describe('test Adverse Event template', () => {
@@ -97,6 +109,7 @@ describe('test Adverse Event template', () => {
const generatedAdverseEvent = CTCAdverseEventTemplate(VALID_DATA);
expect(generatedAdverseEvent).toEqual(maximalValidExampleAdverseEvent);
+
expect(isValidFHIR(generatedAdverseEvent)).toBeTruthy();
});
@@ -137,4 +150,9 @@ describe('test Adverse Event template', () => {
test('invalid data should throw an error', () => {
expect(() => CTCAdverseEventTemplate(INVALID_DATA)).toThrow(Error);
});
+
+ test('Otherwise valid data including the functionCode but not an actor should throw an error', () => {
+ delete VALID_DATA.actor;
+ expect(() => CTCAdverseEventTemplate(VALID_DATA)).toThrow(Error);
+ });
});
diff --git a/test/templates/fixtures/maximal-ctc-adverse-event-resource.json b/test/templates/fixtures/maximal-ctc-adverse-event-resource.json
index 21e40a8a..1ea37982 100644
--- a/test/templates/fixtures/maximal-ctc-adverse-event-resource.json
+++ b/test/templates/fixtures/maximal-ctc-adverse-event-resource.json
@@ -45,6 +45,29 @@
}
]
}
+ },
+ {
+ "url": "http://hl7.org/fhir/us/ctcae/StructureDefinition/adverse-event-participant",
+ "extension": [
+ {
+ "url": "function",
+ "valueCodeableConcept": {
+ "coding": [
+ {
+ "system": "http://terminology.hl7.org/CodeSystem/v3-ParticipationType",
+ "code": "PART",
+ "display": "Participation"
+ }
+ ]
+ }
+ },
+ {
+ "url": "actor",
+ "valueReference": {
+ "reference": "urn:uuid:practitioner-id"
+ }
+ }
+ ]
}
],
"event": {