Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
build =144
build =671
Binary file added bundle.json.zip
Binary file not shown.
6 changes: 3 additions & 3 deletions conf.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"processor":{
"inputFile":"/home/delcpa/switchdrive/DHU/DHU Projects/WHO DAK/merged/xls_form_iraq_v1.xlsx",
"inputFile":"/home/delcpa/Development/smart-emcare-irq/input/l2/xls_form_iraq_v1.xlsx",
"manual_content":"/home/delcpa/Development/smart-emcare/manual",
"outputPath":"/home/delcpa/Development/smart-emcare/input",
"outputPath":"/home/delcpa/Development/smart-emcare-irq/input",
"cql_translator": "https://fhir.cql-translator.dk.swisstph-mis.ch/cql/translator",
"mapping_translator": "https://fhir.dk.swisstph-mis.ch/matchbox/fhir/StructureMap",
"fhirpath_validator":"https://fhirpath.dk.swisstph-mis.ch/validate",
Expand All @@ -20,7 +20,7 @@
},
"fhir":{
"version": "4.0.1",
"lib_version": "1.0.1.rc12.build.144",
"lib_version": "1.0.1.rc12.build.671",
"canonicalBase" : "https://fhir.dk.swisstph-mis.ch/matchbox/fhir/",
"guideBase":"http://fhir.org/guides/who/emc-cds/",
"activity":{
Expand Down
2 changes: 1 addition & 1 deletion pyfhirsdc/converters/extensionsConverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ def convert_reference_to_fhirpath(expression, df_questions):
matches = re.findall(pattern = r'(?P<op> *!?<< *| *!?= *)?"(?P<linkid>[^"]+)"(?:\.(?P<sufix>\w+))?(?P<op2> *!= *(?:true|false))?', string = str(expression))

for match in matches:
null_or_path = None
fpath = []
path = ''
Iscode = False
Expand Down Expand Up @@ -441,7 +442,6 @@ def convert_reference_to_fhirpath(expression, df_questions):
for elm in fpath:
path= ".repeat(item).where(linkId='{}')".format(elm) +path
path += ".answer"
null_or_path= None
if len(null_or)>0:
null_or_path = path + ".empty() "
if sufix not in FHIRPATH_FUNCTION:
Expand Down
11 changes: 10 additions & 1 deletion pyfhirsdc/converters/libraryConverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,14 @@ def convert_reference_to_cql(cql_exp, df, list_inputs):
for match in matches:
replacement = "ToInteger(Coalesce({},false))".format(match[1])
logger.debug('rework {0} to {1}'.format(match[0],replacement))
out = out.replace( match[0], replacement)
out = out.replace( match[0], replacement)
matches = re.findall(r"= val\.",out)

# ~ required to test code against codeableconcept
for match in matches:
replacement = "~ val."
logger.debug('rework = val to ~ val')
out = out.replace( match, replacement)
return out

def get_input(profile,code,valueType,desc=''):
Expand Down Expand Up @@ -472,6 +479,8 @@ def writeGetObs(list_inputs):
return ret




def get_cql_define(name, row, expression_column, df_actions, list_inputs):
prefix = ROW_EXPRESSIONS[expression_column]['prefix']
cql_exp_raw = get_cql_raw_action(row['id'], row, expression_column, df_actions )
Expand Down
96 changes: 57 additions & 39 deletions pyfhirsdc/converters/mapHelpers/custom/mHObservations.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ def get_obs_valueset_str_rules(df_valueset):
for index, concept in df_valueset.iterrows():
rules_main.append(
MappingRule(
expression = "a where value = '{}', a.value as val".format(concept['display']),
expression = "a where value = '{}'".format(concept['display']),
rules = [ MappingRule(
expression="val -> tgt.value = create('CodeableConcept') as cc, cc.coding = create('Coding') as c, c.code={}, c.system= '{}', tgt.status = 'final'".format(concept['code'], get_custom_codesystem_url())
expression="a -> tgt.value = create('CodeableConcept') as cc, cc.coding = create('Coding') as c, c.code='{}', c.system= '{}', tgt.status = 'final'".format(concept['code'], get_custom_codesystem_url())
)])
)

Expand Down Expand Up @@ -84,6 +84,15 @@ def get_obs_value_rules(question_id, df_questions_item,none_name):
)])])]


def SetObservationCodeObs(mode, profile, question_id,df_questions_item, *args):
if mode == 'groups':
none_name = args[0] if len(args)>1 else 'none'
code = question_id
rule_name = clean_group_name(question_id)
return [set_generic_observation_v2( profile, rule_name, code, get_obs_value_rules(code,df_questions_item, none_name))]
elif mode == 'docs':
return get_base_obs_docs(question_id, 'Boolean', df_questions_item)




Expand Down Expand Up @@ -202,26 +211,33 @@ def get_obs_bool_code_rules(question_id, df_questions_item):
####### SetObservationMultiple : works only with valueset, will generate an obs for all, cancelled is not selected but for the one with value none ######
# args[0] : valueSet name
def SetObservationMultiple(mode, profile, question_id, df_questions, *args):
if len(args)!= 1:
logger.error('SetObservation must have 1 parameters')
return SetObservationMultipleBase(mode, profile, question_id, df_questions, False, *args)

def SetObservationMultipleConcat(mode, profile, question_id, df_questions, *args):
return SetObservationMultipleBase(mode, profile, question_id, df_questions, True, *args)

def SetObservationMultipleBase(mode, profile, question_id, df_questions, concat, *args):
if len(args)!= 1 and len(args)!= 2 :
logger.error('SetObservation must have 1 or 2 parameters')
return None
df_valueset = get_valueset_df(args[0], True)
df_valueset = get_valueset_df(args[0], True)
none_code = args[1] if len(args) == 2 else None
if mode == 'rules':
return get_base_obs_muli_rules(profile, question_id,df_questions,df_valueset)
return get_base_obs_muli_rules(profile, question_id,df_questions,df_valueset, none_code, concat)
elif mode == 'groups':
return get_base_obs_muli_groups(profile, question_id,df_valueset)
return get_base_obs_muli_groups(profile, question_id,df_valueset, none_code,concat)
elif mode == 'docs':
return get_docs_obs_muli(question_id,df_valueset, df_questions)
return get_docs_obs_muli(question_id,df_valueset, df_questions, none_code,concat)


def get_docs_obs_muli(question_id,df_valueset, df_questions_item):
def get_docs_obs_muli(question_id,df_valueset, df_questions_item, none_code, concat = True):
docs = []
for index, row in df_valueset.iterrows():
if "map" in row and pd.notna(row["map"]) and row['map'].lower().startswith('obs'):
if "map" in row and pd.notna(row["map"]) and row['map'].lower().startswith('obs') and row['code'] != none_code:
docs.append(
{
'type' : 'Observation',
'code' : question_id+ "&" + row['code'],
'code' : question_id+ "&" + row['code'] if concat else row['code'],
'valueType' : 'boolean',
'description': '{}:{}'.format(
df_questions_item[df_questions_item.id==question_id].iloc[0]['label'],
Expand All @@ -234,44 +250,45 @@ def get_docs_obs_muli(question_id,df_valueset, df_questions_item):



def get_base_obs_muli_rules(profile, question_id,df_questions,df_valueset):
def get_base_obs_muli_rules(profile, question_id,df_questions,df_valueset, none_code = None, concat = True):
rules = []



for index, row in df_valueset.iterrows():
if "map" in row and pd.notna(row["map"]) and row['map'].lower().startswith('obs'):
row_id = row['code']
code =question_id+ "&" + row_id
rule_name = clean_group_name( profile + code + 't')
rules.append(MappingRule(
expression = "src where src.item.where(linkId='{0}').answer.where(value.code = '{1}') ".format(question_id, row_id),
rules = [wrapin_entry_create( profile, question_id,df_questions,[MappingRule(expression = 'src then {}(src,tgt)'.format(rule_name) )])]
))

rule_name = clean_group_name( profile + code+ 'f')
rules.append(MappingRule(
expression = "src where src.item.where(linkId='{0}').exists() and src.item.where(linkId='{0}').answer.where(value.code = '{1}').empty() ".format(question_id, row_id),
rules = [wrapin_entry_create(profile, question_id,df_questions, [MappingRule(expression = 'src then {}(src,tgt)'.format(rule_name) )])]
))
row_id = row['code']
if none_code is None or row_id != none_code:
code =question_id+ "&" + row_id if concat else row_id
rule_name = clean_group_name( profile + code + 't')
rules.append(MappingRule(
expression = "src where src.item.where(linkId='{0}').answer.where(value.code = '{1}') ".format(question_id, row_id),
rules = [wrapin_entry_create( profile, question_id,df_questions,[MappingRule(expression = 'src then {}(src,tgt)'.format(rule_name) )])]
))

rule_name = clean_group_name( profile + code+ 'f')
rules.append(MappingRule(
expression = "src where src.item.where(linkId='{0}').exists() and src.item.where(linkId='{0}').answer.where(value.code = '{1}').empty() ".format(question_id, row_id),
rules = [wrapin_entry_create(profile, question_id,df_questions, [MappingRule(expression = 'src then {}(src,tgt)'.format(rule_name) )])]
))

return rules


def get_base_obs_muli_groups(profile, question_id,df):
def get_base_obs_muli_groups(profile, question_id,df,none_code = None, concat = True):
groups = []

for index, row in df.iterrows():
if "map" in row and pd.notna(row["map"]) and row['map'].lower().startswith('obs'):
row_id = row['code']
code =question_id+ "&" + row_id
rule_name = clean_group_name( profile + code + 't')
groups.append(
set_generic_observation_v2(profile, rule_name, code, [MappingRule(expression = "src -> tgt.status = 'final', tgt.value = true")],'t')
)
rule_name = clean_group_name( profile + code+ 'f')
groups.append(
set_generic_observation_v2(profile, rule_name, code, [MappingRule(expression = "src -> tgt.status = 'cancelled',tgt.value = false",)],'f')
)
if none_code is None or row_id != none_code:
code =question_id+ "&" + row_id if concat else row_id
rule_name = clean_group_name( profile + code + 't')
groups.append(
set_generic_observation_v2(profile, rule_name, code, [MappingRule(expression = "src -> tgt.status = 'final', tgt.value = true")],'t')
)
rule_name = clean_group_name( profile + code+ 'f')
groups.append(
set_generic_observation_v2(profile, rule_name, code, [MappingRule(expression = "src -> tgt.status = 'cancelled',tgt.value = false",)],'f')
)
return groups

def set_generic_observation_v2(profile, rule_name, code ,spe_rules, sufix = ''):
Expand All @@ -291,4 +308,5 @@ def set_generic_observation_v2(profile, rule_name, code ,spe_rules, sufix = ''):
MappingRule(name = 'patient', expression = "src.subject as subject -> tgt.subject = subject "),
*spe_rules
]
)
)

4 changes: 2 additions & 2 deletions test/test_cql.http
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

@rootemcare=/home/delcpa/Development/smart-emcare


#@host=https://cloud.alphora.com/sandbox/r4/cqm/fhir

POST {{host}} HTTP/1.1
Content-Type: application/json
Expand Down Expand Up @@ -113,7 +113,7 @@ POST {{host}}/Library/emcarecombineddataelements/$evaluate?subject=/Patient/a122
# emcareb23classification
#emcareobservation
@file = emcarebase
@lib = emcaredt01
@lib = emcarezscore
PUT {{host}}/Library/{{lib}}
content-type: application/json

Expand Down