The goal of the project is to have tool like pyxform but for fhir structure data capture
Clone the repository from the GitHub repositroy to your local computer
git clone https://github.com/SwissTPH/pyfhirsdc
Create a python virtual environment to install your dependencies
cd pyfhirsdc
python -m venv venv
bash venv/bin/activate.sh
Install the python dependencies needed to run pyfhirsdc
python -m pip install .
python -m main -[options]
The config file is a json with two main section, the data within the JSON file will be used to generate the IG using pyFHIR.
"processor":{
"inputFile":"/home/<>/WHO DAK/merged/xls_form_iraq.xlsx",
"manual_content":"/home/<>/smart-emcare/manual",
"outputPath":"/home/<>/smart-emcare/input",
"cql_translator": "https://fhir.cql-translator.dk.swisstph-mis.ch/cql/translator",
"mapping_translator": "https://fhir.dk.swisstph-mis.ch/matchbox/fhir/StructureMap",
"default_resource_path":"./default_resources",
"excudedWorksheets":[
],
"scope":"EmCare",
"encoding":"json",
"generateElm" : false,
"environment": "dev",
"layoutMode": "DIRECTORY"
},
Parameter | Description |
---|---|
inputFile | Path to the the input file, it is an xlsx file with several mandatory sheets |
manual_content | Path to manual content to be integrated into the IG that is not automatically generated by pyFHIR |
outputPath | Output path of the generated IG content |
cql_translator | URL to cql translator |
mapping_translator | URL to mapping translator |
environment | Whether the current environment is development or production, accepted values dev or prod |
"fhir":{
"version": "4.0.1",
"lib_version": "0.99.99",
"canonicalBase" : "https://fhir.dk.swisstph-mis.ch/matchbox/fhir/",
"guideBase":"http://fhir.org/guides/who/emc-cds/",
"activity":{
"CodeSystem": "http://fhir.org/guides/who/anc-cds/CodeSystem/activity-codes"
},
"external_libraries" : {
"FHIRHelpers" : "http://fhir.org/guides/who/anc-cds/Library/FHIRHelpers"
}
,
"usageContext":{
"CodeSystem": "http://terminology.hl7.org/CodeSystem/usage-context-type",
"Code": "task",
"Display": "Workflow Task"
}
}
this sheet defined how the questionnaires are sequences using multiple plan definition, in the cql-tooling it was based on Decision Tables. Here each row will be, an action, that belongs to a main action with a decision ID. If an ID is provided in one row, this will be assumed as main action and the following rows will be assumed as sub actions of this action. If two following rows have the same action, they will be merged into one, joining the inputs with "OR". The delimiter to separate inputs in one action (row) is the pipe (|).
id of the main action
- Describe the action to be taken
- Will be mapped to the textEquivalent in the FHIR resource.
- The title of the action.
- If this column is filled, the condition mapped with have applicability as type
- If this column is filled, the condition mapped with have start as type
- If this column is filled, the condition mapped with have stop as type
use to create http://hl7.org/fhir/StructureDefinition/questionnaire-constraint with constraintExpression if not MinMax
must have this structure
human::requirements
* human: string: A free text expression of the rule to display to the user if the rule is violated.
* requirements: string: An explanation of why this extension is required (for documentation purposes).
can be MinMax::min value::max value
https://hl7.org/fhir/extensions/StructureDefinition-minValue.html
Simple Extension of type date, dateTime, time, decimal, integer, Quantity: The inclusive lower bound on the range of allowed values for the data element.
https://hl7.org/fhir/extensions/StructureDefinition-maxValue.html
Simple Extension of type date, dateTime, time, decimal, integer, Quantity: The inclusive upper bound on the range of allowed values for the data element.
else it must have this structure:
expression::severity
* severity: code: Indicates how serious violating the invariant is. (error or warning: http://hl7.org/fhir/R5/valueset-constraint-severity.html )
* expression: string: The FHIRPath expression of the rule for computable interpretation.
content in constraintDescription is mandatory
it will create http://hl7.org/fhir/StructureDefinition/questionnaire-constraint
Complex Extension: An invariant that must be satisfied before responses to the questionnaire can be considered "complete".
- The action that will result
- What will trigger this decision. Must only be specified at the mainAction level
- Type of the trigger (named-event | periodic | data-changed | data-accessed | data-access-ended )
- Business Rule of the decision
- Reference for the specific action
- The outcome of performing such an action
will create a library, same way and fields as the questionnaire
will work like a questionnaire with those diference
question type condition is added, thise create the activity definition based on the enableWhenCode
question type postcoordination is created, MUST be a child item of a condition, enableWhen logic is use to generate CQL that will populate the postcoordination extension in the task generated by the activityDefinition
TODO: THIS should create a questionnaire as fallback activity
thoses sheets are containing the questionnaires, and the required information to de the fihr mapping via structureMap (to be confirmed) and the CQL to find back the answers based on their "label" the format is inpired by the pyxform 'survey' sheet but addapted to fhir SDC questionnaires
Mandatory, used as linkid
can be set to {{library}} to speficy the questionnaires libraries dependencies
will follow the structure [type] [option]
- all fhir type but choice : use one of the basic type
- note, equivalen to text
- select_one option : choice when only one selection is possible
- select_multile option : choice when multiple selections are possible
- select_condition create a list with all the classification mapped in the questionnaire
- select_boolean quesiton with only one checkbox
- mapping : will not apprear on the questionnaire, just to document mapping information
- group will start a question group, an ID is mandatory, several levels are possible
- variable : add a variable in the questionnaire, on the questionnaire level if no parentId is specified, else on the question where id == parentId, the expression MUST be in calcualtedExpression column
- [valueSet] valueSet defined in the valueSet tab
- url::[valueSetUrl] link to a remote value set
- candidateExpression:: will fetch the result via the , then will display the result based on the data attached to the in the choiceColum sheet
set to True to make sure the question is required
can be a list separated by || (double pipe)
-
dropdown : only for select_one / select_multiple
-
checkbox: only for select_multiple
-
horizonal: show answers in an horizontal manner (automatically added for boolean)
-
sytle: define a Css style (no yet supported by android)
-
background-color: with xkcd color name or color code #ff00ff
-
Choice only for select_one
-
hidden : hide the question
-
candidateExpression : to use the candidate expression defined in the valueset
-
unit::code # code from that value set https://build.fhir.org/valueset-http://unitsofmeasure.org
-
toggle::code::expression this will create http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-answerOptionsToggleExpression
code can can be compose of system-url|code or code
used to add subItem or/and cql details
content for the help extension
Expression can be written on several lines to clarify the sub line must refer to the parent line through the parentId column
several line with the same parentId will be joined with an OR each set of subline is joined to the parent with an AND only the first line may not have expression but then it must have '{{cql}}' in it in order to triger the conversion to library
the type of the subline should be '{{cql}}'
fhirpath/CQL code that will be executed by the api with the $populate opearation
When writing the CQL please note:
- all observations (i.e. questions mapped to Observation) can be access via their label or id
Cql identifier (label) must only use ascii
fhirpath code that will be added on the SDC enableWhenExpression extension
fhirpath code that will be added on the SDC calculatedExpression extension
Will be used to implicitly flag a necessary extension. Additional information will be used to create the extension structure definition that will be referenced in the resource profile. Has the format:
Path :: min :: max
- The id of the extension will be created by concatenating the path of the extension with the slice name
- The value type of the extension will be derived from the type of the question
- The reference will be derived from the map_profile column
- For the slicing name, the question label will be used
- Min will default to 0 and max will default * unless defined otherwise
List of Map rules,
Some usefull complex mapping are defined on the code level
SetObservation -> for observation code or quantity SetObservationBoolean ->
to generate
src.a2 as a where a2.length <= 20 -> tgt.a2 = a 'rulename1'; // ignore it if it's longer than 20 characters
src.a2 as a check a2.length <= 20 -> tgt.a2 = a 'rulename2' ; // error if it's longer than 20 characters
this will be needed
where a2.length <= 20 -> tgt.a2 = a||check a2.length <= 20 -> tgt.a2 = a
use the create custom profiles and to create the structure map Questionnaire - Profile the details of the profile to the mapped will be in the profile tab
the based profile will be deducted from the profile, this means that the profile name MUST include the base profile name
if the base profile is Observation then the question code will be defined from the label in the {{scope}}observation library
if the base profile is condition then the question code will be defined from the label in the {{scope}}condition library
to avoid complex code in the XLSX, snippet/function could be defined in mapHelpers/custom Mapping function
id = {{library}} description = [name]::[alias]::[version] e.g FHIRHelper::FHIRHelper::4.01 version can be {{LIB_VERSION}} or {{FHIR_VERSION}} this will ne updated base on the configuration file type = mapping
maturitiy:2
this sheet define the the valuset concept that need to be defined in the project scope the format is inpired by the pyxform 'choice' sheet
the minimal definiton is scope , valueSet and display (a code system URL), all of the concept from that codesystem will be option with {{include}} in code (to be developped, should replace url::[valueSetUrl] in the quesiton type)
the simple definition is one row per concept (those concept will be added in the custom codesystem)
Only
but "additionnal" inforamation can be added when keyword are used in the code
- {{title}} : will set the valuesset title [display] and description [definition]
- {{exclude}}: define the code system to be excluded [definition] , the [display] can be used to set a name to link the element to be exculde (concepts to exclude will share this name in the valueSet column)
- {{include}}: define the code system to be include [definition] , the [display] can be used to set a name to link the element to be exculde (concepts to exclude will share this name in the valueSet column)
- {{choiceColumn}} : Only for candidteExpression, the choice column details will be defined as a json [definition] : {"path":".last_name", "width": "30", "forDisplay":"1"}
- {{choiceColumn}} : Only for candidteExpression, will define the URL including the query parameters
this sheet list the additionnal CQL required
for the IG, two different profile type might be usefull
- FHIR or WHO existing profiles
- [scope] profile in case there is extension to be added to an existing profile
Defining a profile can be used also to create event, for example a QuestionnaireResponse profile can be created for a specific quesitonnaire.
Different profile will need to be generated:
- [scope] Patient
- [scope] Encounter
- [scope] Measure: to define in which conditions some measure must be done
- [scope] Conditions: either one per condition or per group of condition like "Emergency Conditions", "Mild Condition", "chronic conditon" etc
- [scope] Activity: to trigger a questionnaire (CPG collectWhith) with a task (TBC)
This approach have limits,
- an extension cannot yet be reuse in 2 profiles
- Cardinality of the values is set to 1:1
create a recipient for extention
extention to add on a profile
only use for Extention, define the resource on which this extenion need to be added
cannonical url of the based profile
cardinalliy of the extention in the profile
THis column requires the same information that extensions need but for non extension elements.
Path :: min :: max
- The id of the element
- The value type of the element will be derived from the type of the question
- The reference will be derived from the map_profile column
- Min will default to 0 and max will default * unless defined otherwise
the output file structure should follow the cqf-tooling structure
this tool was started to answer WHO EmCare project needs
pyxform project cqf-tooling project