tricc-oo 1.6.5.dev1__tar.gz → 1.6.6__tar.gz
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.
- {tricc_oo-1.6.5.dev1/tricc_oo.egg-info → tricc_oo-1.6.6}/PKG-INFO +1 -1
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/pyproject.toml +1 -1
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/converters/tricc_to_xls_form.py +2 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/models/base.py +2 -2
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/serializers/xls_form.py +2 -2
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/strategies/output/dhis2_form.py +76 -27
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/strategies/output/xls_form.py +13 -4
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/strategies/output/xlsform_cht.py +3 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/visitors/tricc.py +78 -35
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6/tricc_oo.egg-info}/PKG-INFO +1 -1
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo.egg-info/top_level.txt +0 -1
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/LICENSE +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/README.md +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/setup.cfg +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tests/build.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tests/test_build.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tests/test_cql.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tests/to_ocl.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/__init__.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/converters/__init__.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/converters/codesystem_to_ocl.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/converters/cql/cqlLexer.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/converters/cql/cqlListener.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/converters/cql/cqlParser.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/converters/cql/cqlVisitor.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/converters/cql_to_operation.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/converters/datadictionnary.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/converters/drawio_type_map.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/converters/utils.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/converters/xml_to_tricc.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/models/__init__.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/models/calculate.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/models/lang.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/models/ocl.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/models/ordered_set.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/models/tricc.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/parsers/__init__.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/parsers/xml.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/serializers/__init__.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/serializers/planuml.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/strategies/__init__.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/strategies/input/__init__.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/strategies/input/base_input_strategy.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/strategies/input/drawio.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/strategies/output/base_output_strategy.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/strategies/output/fhir_form.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/strategies/output/html_form.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/strategies/output/openmrs_form.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/strategies/output/spice.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/strategies/output/xlsform_cdss.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/strategies/output/xlsform_cht_hf.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/visitors/__init__.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/visitors/utils.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo/visitors/xform_pd.py +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo.egg-info/SOURCES.txt +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo.egg-info/dependency_links.txt +0 -0
- {tricc_oo-1.6.5.dev1 → tricc_oo-1.6.6}/tricc_oo.egg-info/requires.txt +0 -0
|
@@ -43,6 +43,8 @@ def get_export_name(node, replace_dots=True):
|
|
|
43
43
|
value = node.name
|
|
44
44
|
elif isinstance(node, TriccStatic):
|
|
45
45
|
value = node.value
|
|
46
|
+
if isinstance(value, TriccNodeSelectOption):
|
|
47
|
+
value = value.name
|
|
46
48
|
else:
|
|
47
49
|
value = node
|
|
48
50
|
if isinstance(value, bool): # or r.value in ('true', 'false')
|
|
@@ -11,7 +11,7 @@ from tricc_oo.models.ordered_set import OrderedSet
|
|
|
11
11
|
|
|
12
12
|
logger = logging.getLogger("default")
|
|
13
13
|
|
|
14
|
-
Expression = Annotated[str, StringConstraints(pattern=r"
|
|
14
|
+
Expression = Annotated[str, StringConstraints(pattern=r".+")]
|
|
15
15
|
|
|
16
16
|
triccId = Annotated[str, StringConstraints(pattern=r"^[^\\/\: ]+$")]
|
|
17
17
|
|
|
@@ -274,7 +274,7 @@ class TriccNodeBaseModel(TriccBaseModel):
|
|
|
274
274
|
|
|
275
275
|
|
|
276
276
|
class TriccStatic(BaseModel):
|
|
277
|
-
value: Union[str, float, int, bool]
|
|
277
|
+
value: Union[str, float, int, bool, TriccNodeBaseModel]
|
|
278
278
|
|
|
279
279
|
def __init__(self, value):
|
|
280
280
|
super().__init__(value=value)
|
|
@@ -123,7 +123,7 @@ def start_group(
|
|
|
123
123
|
value = get_export_name(calc)
|
|
124
124
|
calc_values.append(value)
|
|
125
125
|
elif column == "calculation":
|
|
126
|
-
calc_values.append(strategy.get_tricc_operation_expression(calc.expression))
|
|
126
|
+
calc_values.append(f"number({strategy.get_tricc_operation_expression(calc.expression)}")
|
|
127
127
|
elif column == "relevance":
|
|
128
128
|
calc_values.append("")
|
|
129
129
|
else:
|
|
@@ -415,7 +415,7 @@ def get_more_info_select(strategy, node):
|
|
|
415
415
|
if column == "type":
|
|
416
416
|
values.append("select_one more_info")
|
|
417
417
|
elif column == "label":
|
|
418
|
-
values.append(
|
|
418
|
+
values.append(strategy.get_empty_label())
|
|
419
419
|
elif column == "name":
|
|
420
420
|
values.append(get_export_name(node) + "_optin")
|
|
421
421
|
elif column == "hint":
|
|
@@ -25,6 +25,8 @@ from tricc_oo.models.tricc import (
|
|
|
25
25
|
TriccNodeDisplayModel,
|
|
26
26
|
TriccNodeCalculateBase,
|
|
27
27
|
TriccNodeActivity,
|
|
28
|
+
TriccNodeSelect,
|
|
29
|
+
TriccNodeSelectYesNo,
|
|
28
30
|
)
|
|
29
31
|
from tricc_oo.models.calculate import TriccNodeDisplayCalculateBase
|
|
30
32
|
from tricc_oo.models.ordered_set import OrderedSet
|
|
@@ -66,18 +68,22 @@ class DHIS2Strategy(BaseOutPutStrategy):
|
|
|
66
68
|
|
|
67
69
|
def get_export_name(self, r):
|
|
68
70
|
if isinstance(r, TriccNodeSelectOption):
|
|
69
|
-
|
|
71
|
+
ret = self.get_option_value(r.name)
|
|
70
72
|
elif isinstance(r, str):
|
|
71
|
-
|
|
73
|
+
ret = self.get_option_value(r)
|
|
72
74
|
elif isinstance(r, TriccStatic):
|
|
73
75
|
if isinstance(r.value, str):
|
|
74
|
-
|
|
76
|
+
ret = self.get_option_value(r.value)
|
|
75
77
|
elif isinstance(r.value, bool):
|
|
76
|
-
|
|
78
|
+
ret = str(r.value).lower()
|
|
77
79
|
else:
|
|
78
|
-
|
|
80
|
+
ret = r.value
|
|
81
|
+
else:
|
|
82
|
+
ret = get_export_name(r)
|
|
83
|
+
if isinstance(ret, str):
|
|
84
|
+
return ret[:50]
|
|
79
85
|
else:
|
|
80
|
-
return
|
|
86
|
+
return ret
|
|
81
87
|
|
|
82
88
|
def generate_id(self, name):
|
|
83
89
|
"""Generate DHIS2-compliant UID: 1 letter + 10 alphanumeric characters"""
|
|
@@ -139,7 +145,15 @@ class DHIS2Strategy(BaseOutPutStrategy):
|
|
|
139
145
|
raise NotImplementedError(
|
|
140
146
|
f"This type of operation '{operation.operator}' is not supported in this strategy"
|
|
141
147
|
)
|
|
142
|
-
|
|
148
|
+
def get_display(self, node):
|
|
149
|
+
if hasattr(node, 'label') and node.label:
|
|
150
|
+
ret = node.label
|
|
151
|
+
elif hasattr(node, 'name') and node.name:
|
|
152
|
+
ret = node.name
|
|
153
|
+
else:
|
|
154
|
+
ret = str(node.id)
|
|
155
|
+
return ret.replace('\u00a0', ' ').strip()
|
|
156
|
+
|
|
143
157
|
def execute(self):
|
|
144
158
|
version = datetime.datetime.now().strftime("%Y%m%d%H%M")
|
|
145
159
|
logger.info(f"build version: {version}")
|
|
@@ -223,11 +237,13 @@ class DHIS2Strategy(BaseOutPutStrategy):
|
|
|
223
237
|
self.program_rule_actions.append(program_rule_action)
|
|
224
238
|
|
|
225
239
|
# Create program rule referencing the action
|
|
240
|
+
condition = self.simplify_expression(f"!({relevance_str})") # Negate for hide when true
|
|
241
|
+
condition = self.simplify_expression(condition)
|
|
226
242
|
self.program_rules.append({
|
|
227
243
|
"id": rule_id,
|
|
228
|
-
"name": f"Hide {
|
|
229
|
-
"description": f"Hide {
|
|
230
|
-
"condition":
|
|
244
|
+
"name": f"Hide `{self.get_export_name(node)}` when condition met",
|
|
245
|
+
"description": f"Hide `{self.get_display(node)}` based on relevance",
|
|
246
|
+
"condition": condition,
|
|
231
247
|
"programRuleActions": [{"id": action_id}]
|
|
232
248
|
})
|
|
233
249
|
return True
|
|
@@ -257,11 +273,15 @@ class DHIS2Strategy(BaseOutPutStrategy):
|
|
|
257
273
|
"id": de_id,
|
|
258
274
|
"name": self.get_export_name(node),
|
|
259
275
|
"shortName": node.name[:50],
|
|
260
|
-
"displayFormName":
|
|
276
|
+
"displayFormName":self.get_display(node),
|
|
277
|
+
"formName": self.get_display(node),
|
|
261
278
|
"valueType": value_type,
|
|
262
279
|
"domainType": "TRACKER",
|
|
263
280
|
"aggregationType": "NONE"
|
|
264
281
|
}
|
|
282
|
+
|
|
283
|
+
if issubclass(node.__class__, TriccNodeSelect) and not isinstance(node, TriccNodeSelectYesNo):
|
|
284
|
+
data_element["optionSetValue"] = True
|
|
265
285
|
|
|
266
286
|
# Only create optionSet for non-boolean select questions
|
|
267
287
|
if node.tricc_type in ['select_one', 'select_multiple'] and not is_boolean_question:
|
|
@@ -273,7 +293,7 @@ class DHIS2Strategy(BaseOutPutStrategy):
|
|
|
273
293
|
# Create the actual optionSet definition
|
|
274
294
|
option_set = {
|
|
275
295
|
"id": option_set_id,
|
|
276
|
-
"name": f"{node
|
|
296
|
+
"name": f"{self.get_export_name(node)} Options",
|
|
277
297
|
"shortName": f"{node.name}_opts"[:50],
|
|
278
298
|
"valueType": "TEXT",
|
|
279
299
|
"options": []
|
|
@@ -288,10 +308,10 @@ class DHIS2Strategy(BaseOutPutStrategy):
|
|
|
288
308
|
option_name = option_name.replace('\u00a0', ' ').strip()
|
|
289
309
|
elif isinstance(option_name, TriccStatic):
|
|
290
310
|
option_name = str(option_name.value)
|
|
291
|
-
# Create separate option
|
|
311
|
+
# Create separate option entityif
|
|
292
312
|
option_def = {
|
|
293
313
|
"id": option_id,
|
|
294
|
-
"name":
|
|
314
|
+
"name": self.get_display(option),
|
|
295
315
|
"shortName": option.name[:50],
|
|
296
316
|
"code": str(self.get_export_name(option))
|
|
297
317
|
}
|
|
@@ -303,6 +323,20 @@ class DHIS2Strategy(BaseOutPutStrategy):
|
|
|
303
323
|
self.option_sets[option_set_id] = option_set
|
|
304
324
|
|
|
305
325
|
self.data_elements[node.name] = data_element
|
|
326
|
+
|
|
327
|
+
# Create program rule variable for this data element
|
|
328
|
+
var_id = self.generate_id(f"var_{node.name}")
|
|
329
|
+
var_name = self.get_export_name(node)
|
|
330
|
+
program_rule_variable = {
|
|
331
|
+
"id": var_id,
|
|
332
|
+
"name": var_name,
|
|
333
|
+
"programRuleVariableSourceType": "DATAELEMENT_CURRENT_EVENT",
|
|
334
|
+
"dataElement": {"id": de_id},
|
|
335
|
+
"program": {"id": self.program_metadata["id"]}
|
|
336
|
+
}
|
|
337
|
+
self.program_rule_variables.append(program_rule_variable)
|
|
338
|
+
self.concept_map[node.name] = var_name # Store variable name for #{var_name} references
|
|
339
|
+
|
|
306
340
|
return data_element
|
|
307
341
|
return None
|
|
308
342
|
|
|
@@ -325,9 +359,10 @@ class DHIS2Strategy(BaseOutPutStrategy):
|
|
|
325
359
|
mock_node = MockNode(operation_datatype)
|
|
326
360
|
data_type = self.map_tricc_type_to_dhis2_value_type(mock_node)
|
|
327
361
|
|
|
362
|
+
var_name = self.get_export_name(node)
|
|
328
363
|
program_rule_variable = {
|
|
329
364
|
"id": var_id,
|
|
330
|
-
"name":
|
|
365
|
+
"name": var_name,
|
|
331
366
|
"programRuleVariableSourceType": "CALCULATED_VALUE",
|
|
332
367
|
"calculatedValueScript": expression_str,
|
|
333
368
|
"dataType": data_type,
|
|
@@ -336,7 +371,7 @@ class DHIS2Strategy(BaseOutPutStrategy):
|
|
|
336
371
|
}
|
|
337
372
|
self.program_rule_variables.append(program_rule_variable)
|
|
338
373
|
# Add to concept map for potential referencing
|
|
339
|
-
self.concept_map[node.name] =
|
|
374
|
+
self.concept_map[node.name] = var_name # Store variable name
|
|
340
375
|
return True
|
|
341
376
|
return False
|
|
342
377
|
|
|
@@ -674,7 +709,7 @@ class DHIS2Strategy(BaseOutPutStrategy):
|
|
|
674
709
|
if isinstance(r, TriccOperation):
|
|
675
710
|
return self.get_tricc_operation_expression(r)
|
|
676
711
|
elif isinstance(r, TriccReference):
|
|
677
|
-
# Use
|
|
712
|
+
# Use variable name from concept_map
|
|
678
713
|
node_id = self.concept_map.get(r.value.name, self.get_export_name(r.value))
|
|
679
714
|
return f"#{{{node_id}}}"
|
|
680
715
|
elif isinstance(r, TriccStatic):
|
|
@@ -696,25 +731,39 @@ class DHIS2Strategy(BaseOutPutStrategy):
|
|
|
696
731
|
return option
|
|
697
732
|
return f"'{option}'"
|
|
698
733
|
elif issubclass(r.__class__, TriccNodeDisplayCalculateBase):
|
|
699
|
-
# Use
|
|
700
|
-
node_id = self.
|
|
701
|
-
return f"#{node_id}"
|
|
734
|
+
# Use variable name from concept_map
|
|
735
|
+
node_id = self.get_export_name(r)
|
|
736
|
+
return f"#{{{node_id}}}"
|
|
737
|
+
elif issubclass(r.__class__, TriccNodeCalculateBase):
|
|
738
|
+
# Use variable name from concept_map
|
|
739
|
+
node_id = self.get_export_name(r)
|
|
740
|
+
return f"#{{{node_id}}}"
|
|
702
741
|
elif issubclass(r.__class__, TriccNodeInputModel):
|
|
703
|
-
# Use
|
|
704
|
-
node_id =
|
|
742
|
+
# Use variable name from concept_map
|
|
743
|
+
node_id = self.get_export_name(r)
|
|
705
744
|
return f"#{{{node_id}}}"
|
|
706
745
|
elif issubclass(r.__class__, TriccNodeBaseModel):
|
|
707
|
-
# Use
|
|
708
|
-
node_id =
|
|
746
|
+
# Use variable name from concept_map
|
|
747
|
+
node_id = self.get_export_name(r)
|
|
709
748
|
return f"#{{{node_id}}}"
|
|
710
749
|
else:
|
|
711
750
|
raise NotImplementedError(f"This type of node {r.__class__.__name__} is not supported within an operation")
|
|
712
751
|
|
|
752
|
+
def simplify_expression(self, expr):
|
|
753
|
+
while expr.startswith('!(!(') and expr.endswith('))'):
|
|
754
|
+
expr = expr[4:-2]
|
|
755
|
+
return expr
|
|
756
|
+
|
|
713
757
|
def convert_expression_to_string(self, expression):
|
|
714
758
|
if isinstance(expression, TriccOperation):
|
|
715
|
-
|
|
759
|
+
expr = self.get_tricc_operation_expression(expression)
|
|
716
760
|
else:
|
|
717
|
-
|
|
761
|
+
expr = self.get_tricc_operation_operand(expression)
|
|
762
|
+
|
|
763
|
+
# Simplify double negations
|
|
764
|
+
expr = self.simplify_expression(expr)
|
|
765
|
+
|
|
766
|
+
return expr
|
|
718
767
|
|
|
719
768
|
# Operation methods for DHIS2 expressions
|
|
720
769
|
def tricc_operation_equal(self, ref_expressions):
|
|
@@ -765,7 +814,7 @@ class DHIS2Strategy(BaseOutPutStrategy):
|
|
|
765
814
|
|
|
766
815
|
def tricc_operation_selected(self, ref_expressions):
|
|
767
816
|
# For DHIS2, check if value is selected in multi-select
|
|
768
|
-
return f"d2:
|
|
817
|
+
return f"d2:countIfValue({ref_expressions[0]}, {ref_expressions[1]})>0"
|
|
769
818
|
|
|
770
819
|
def tricc_operation_count(self, ref_expressions):
|
|
771
820
|
return f"d2:count({ref_expressions[0]})"
|
|
@@ -495,7 +495,12 @@ class XLSFormStrategy(BaseOutPutStrategy):
|
|
|
495
495
|
parts = []
|
|
496
496
|
for s in ref_expressions[1:]:
|
|
497
497
|
# for option with numeric value
|
|
498
|
-
|
|
498
|
+
if isinstance(s, str):
|
|
499
|
+
cleaned_s = s
|
|
500
|
+
elif isinstance(s, TriccNodeSelectOption):
|
|
501
|
+
cleaned_s = s.name
|
|
502
|
+
else:
|
|
503
|
+
cleaned_s = "'" + str(s) + "'"
|
|
499
504
|
parts.append(f"selected({self.clean_coalesce(ref_expressions[0])}, {cleaned_s})")
|
|
500
505
|
if len(parts) == 1:
|
|
501
506
|
return parts[0]
|
|
@@ -589,11 +594,14 @@ class XLSFormStrategy(BaseOutPutStrategy):
|
|
|
589
594
|
exp += ")"
|
|
590
595
|
return exp
|
|
591
596
|
|
|
597
|
+
def get_empty_label(self):
|
|
598
|
+
return "."
|
|
599
|
+
|
|
592
600
|
def tricc_operation_if(self, ref_expressions):
|
|
593
601
|
return f"if({ref_expressions[0]},{ref_expressions[1]},{ref_expressions[2]})"
|
|
594
602
|
|
|
595
603
|
def tricc_operation_contains(self, ref_expressions):
|
|
596
|
-
return f"contains(
|
|
604
|
+
return f"contains({self.clean_coalesce(ref_expressions[0])}, {self.clean_coalesce(ref_expressions[1])})"
|
|
597
605
|
|
|
598
606
|
def tricc_operation_exists(self, ref_expressions):
|
|
599
607
|
parts = []
|
|
@@ -721,11 +729,12 @@ class XLSFormStrategy(BaseOutPutStrategy):
|
|
|
721
729
|
# @param r reference to be translated
|
|
722
730
|
if isinstance(r, TriccOperation):
|
|
723
731
|
return self.get_tricc_operation_expression(r)
|
|
732
|
+
elif isinstance(r, (TriccStatic, str, int, float)):
|
|
733
|
+
return get_export_name(r)
|
|
724
734
|
elif isinstance(r, TriccReference):
|
|
725
735
|
logger.warning(f"reference `{r.value}` still used in a calculate")
|
|
726
736
|
return f"${{{get_export_name(r.value)}}}"
|
|
727
|
-
|
|
728
|
-
return get_export_name(r)
|
|
737
|
+
|
|
729
738
|
elif isinstance(r, TriccNodeSelectOption):
|
|
730
739
|
logger.debug(f"select option {r.get_name()} from {r.select.get_name()} was used as a reference")
|
|
731
740
|
return get_export_name(r)
|
|
@@ -33,6 +33,9 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
33
33
|
|
|
34
34
|
self.inject_version()
|
|
35
35
|
|
|
36
|
+
def get_empty_label(self):
|
|
37
|
+
return "NO_LABEL"
|
|
38
|
+
|
|
36
39
|
def get_cht_input(self, start_pages, **kwargs):
|
|
37
40
|
empty = langs.get_trads("", force_dict=True)
|
|
38
41
|
df_input = pd.DataFrame(columns=SURVEY_MAP.keys())
|
|
@@ -542,6 +542,32 @@ def generate_calculates(node, calculates, used_calculates, processed_nodes, proc
|
|
|
542
542
|
for calc in list_calc:
|
|
543
543
|
node.activity.nodes[calc.id] = calc
|
|
544
544
|
add_calculate(calculates, calc)
|
|
545
|
+
|
|
546
|
+
# Add CONTAINS calculations for each option in select multiple (except opt_none)
|
|
547
|
+
if isinstance(node, TriccNodeSelectMultiple):
|
|
548
|
+
for option in node.options.values():
|
|
549
|
+
if not option.name.startswith("opt_"):
|
|
550
|
+
calc_id = generate_id(f"contains_{node.id}_{option.name}")
|
|
551
|
+
expression = TriccOperation(TriccOperator.CONTAINS, [node, TriccStatic(option.name)])
|
|
552
|
+
calc_node = TriccNodeCalculate(
|
|
553
|
+
name=option.name,
|
|
554
|
+
id=calc_id,
|
|
555
|
+
group=node.group,
|
|
556
|
+
activity=node.activity,
|
|
557
|
+
label=f"contains: {node.get_name()} contains '{option.name}'",
|
|
558
|
+
path_len=node.path_len + 1,
|
|
559
|
+
last=True,
|
|
560
|
+
expression=expression,
|
|
561
|
+
)
|
|
562
|
+
node.activity.calculates.append(calc_node)
|
|
563
|
+
last_version = set_last_version_false(calc_node, processed_nodes)
|
|
564
|
+
if last_version:
|
|
565
|
+
calc_node.expression = merge_expression(calc_node.expression, last_version)
|
|
566
|
+
processed_nodes.add(calc_node)
|
|
567
|
+
list_calc.append(calc_node)
|
|
568
|
+
node.activity.nodes[calc_node.id] = calc_node
|
|
569
|
+
add_calculate(calculates, calc_node)
|
|
570
|
+
|
|
545
571
|
return list_calc
|
|
546
572
|
|
|
547
573
|
|
|
@@ -1711,6 +1737,7 @@ PARENT_GROUP_PRIORITY = 6000
|
|
|
1711
1737
|
ACTIVE_ACTIVITY_PRIORITY = 5000
|
|
1712
1738
|
NON_START_ACTIVITY_PRIORITY = 4000
|
|
1713
1739
|
ACTIVE_ACTIVITY_LOWER_PRIORITY = 3000
|
|
1740
|
+
FLOW_CALCULATE_NODE_PRIORITY = 6500
|
|
1714
1741
|
RHOMBUS_PRIORITY = 1000
|
|
1715
1742
|
DEFAULT_PRIORITY = 2000
|
|
1716
1743
|
|
|
@@ -1737,6 +1764,9 @@ def reorder_node_list(node_list, group, processed_nodes):
|
|
|
1737
1764
|
# Check for non main activities
|
|
1738
1765
|
elif activity and isinstance(activity.root, TriccNodeActivityStart):
|
|
1739
1766
|
priority += NON_START_ACTIVITY_PRIORITY
|
|
1767
|
+
# Check for display calculate and end nodes with prev_nodes
|
|
1768
|
+
elif (issubclass(node.__class__, TriccNodeDisplayCalculateBase) or isinstance(node, TriccNodeEnd)) and not isinstance(node, TriccNodeActivityEnd) and hasattr(node, 'prev_nodes') and len(node.prev_nodes) > 0:
|
|
1769
|
+
priority += FLOW_CALCULATE_NODE_PRIORITY
|
|
1740
1770
|
# Check for active activities (lower priority)
|
|
1741
1771
|
elif activity and activity in active_activities:
|
|
1742
1772
|
priority += ACTIVE_ACTIVITY_LOWER_PRIORITY
|
|
@@ -1998,7 +2028,7 @@ def get_accept_diagnostic_node(code, display, severity, priority, activity):
|
|
|
1998
2028
|
return node
|
|
1999
2029
|
|
|
2000
2030
|
|
|
2001
|
-
def get_diagnostic_node(code, display, severity, priority, activity):
|
|
2031
|
+
def get_diagnostic_node(code, display, severity, priority, activity, option):
|
|
2002
2032
|
node = TriccNodeCalculate(
|
|
2003
2033
|
id=generate_id("final." + code),
|
|
2004
2034
|
name="final." + code,
|
|
@@ -2009,7 +2039,7 @@ def get_diagnostic_node(code, display, severity, priority, activity):
|
|
|
2009
2039
|
expression_reference=or_join(
|
|
2010
2040
|
[
|
|
2011
2041
|
TriccOperation(TriccOperator.ISTRUE, [TriccReference("pre_final." + code)]),
|
|
2012
|
-
TriccOperation(TriccOperator.SELECTED, [TriccReference("tricc.manual.diag"), TriccStatic(
|
|
2042
|
+
TriccOperation(TriccOperator.SELECTED, [TriccReference("tricc.manual.diag"), TriccStatic(option)]),
|
|
2013
2043
|
]
|
|
2014
2044
|
),
|
|
2015
2045
|
)
|
|
@@ -2068,9 +2098,18 @@ def create_determine_diagnosis_activity(diags):
|
|
|
2068
2098
|
group=activity,
|
|
2069
2099
|
required=TriccStatic(False),
|
|
2070
2100
|
)
|
|
2101
|
+
options = []
|
|
2071
2102
|
for proposed in diags:
|
|
2103
|
+
option = TriccNodeSelectOption(
|
|
2104
|
+
id=generate_id(proposed.name),
|
|
2105
|
+
name=proposed.name,
|
|
2106
|
+
label=proposed.label,
|
|
2107
|
+
list_name=f.list_name,
|
|
2108
|
+
relevance=proposed.activity.applicability,
|
|
2109
|
+
select=f,
|
|
2110
|
+
)
|
|
2072
2111
|
d = get_accept_diagnostic_node(proposed.name, proposed.label, proposed.severity, proposed.priority, activity)
|
|
2073
|
-
c = get_diagnostic_node(proposed.name, proposed.label, proposed.severity, proposed.priority, activity)
|
|
2112
|
+
c = get_diagnostic_node(proposed.name, proposed.label, proposed.severity, proposed.priority, activity, option)
|
|
2074
2113
|
diags_conf.append(d)
|
|
2075
2114
|
r = TriccNodeRhombus(
|
|
2076
2115
|
path=start,
|
|
@@ -2095,17 +2134,7 @@ def create_determine_diagnosis_activity(diags):
|
|
|
2095
2134
|
activity.nodes[wait2.id] = wait2
|
|
2096
2135
|
# fallback
|
|
2097
2136
|
|
|
2098
|
-
|
|
2099
|
-
TriccNodeSelectOption(
|
|
2100
|
-
id=generate_id(d.name),
|
|
2101
|
-
name=d.name,
|
|
2102
|
-
label=d.label,
|
|
2103
|
-
list_name=f.list_name,
|
|
2104
|
-
relevance=d.activity.applicability,
|
|
2105
|
-
select=f,
|
|
2106
|
-
)
|
|
2107
|
-
for d in diags
|
|
2108
|
-
]
|
|
2137
|
+
|
|
2109
2138
|
f.options = dict(zip(range(0, len(options)), options))
|
|
2110
2139
|
activity.nodes[f.id] = f
|
|
2111
2140
|
set_prev_next_node(f, end, edge_only=False)
|
|
@@ -2213,10 +2242,22 @@ def get_count_terms(node, processed_nodes, get_overall_exp, negate=False, proces
|
|
|
2213
2242
|
return TriccOperation(TriccOperator.PLUS, [TriccOperation(TriccOperator.CAST_NUMBER, [term]) for term in terms])
|
|
2214
2243
|
|
|
2215
2244
|
|
|
2245
|
+
def get_none_option(node):
|
|
2246
|
+
if hasattr(node, "options"):
|
|
2247
|
+
for opt in node.options.values():
|
|
2248
|
+
if opt.name == "opt_none":
|
|
2249
|
+
return opt
|
|
2250
|
+
return None
|
|
2251
|
+
|
|
2252
|
+
|
|
2216
2253
|
def get_count_terms_details(prev_node, processed_nodes, get_overall_exp, negate=False, process=None):
|
|
2217
|
-
|
|
2254
|
+
opt_none = get_none_option(prev_node)
|
|
2255
|
+
if opt_none:
|
|
2256
|
+
operation_none = TriccOperation(TriccOperator.SELECTED, [prev_node, TriccStatic(opt_none)])
|
|
2257
|
+
else:
|
|
2258
|
+
operation_none = TriccOperation(TriccOperator.SELECTED, [prev_node, TriccStatic("opt_none")])
|
|
2218
2259
|
if isinstance(prev_node, TriccNodeSelectYesNo):
|
|
2219
|
-
return TriccOperation(TriccOperator.SELECTED, [prev_node, TriccStatic(prev_node.options[0]
|
|
2260
|
+
return TriccOperation(TriccOperator.SELECTED, [prev_node, TriccStatic(prev_node.options[0])])
|
|
2220
2261
|
elif issubclass(prev_node.__class__, TriccNodeSelect):
|
|
2221
2262
|
if negate:
|
|
2222
2263
|
return
|
|
@@ -2528,7 +2569,7 @@ def get_selected_option_expression_single(option_node, negate):
|
|
|
2528
2569
|
|
|
2529
2570
|
def get_selected_option_expression_multiple(option_node, negate):
|
|
2530
2571
|
|
|
2531
|
-
selected = TriccOperation(TriccOperator.SELECTED, [option_node.select, option_node])
|
|
2572
|
+
selected = TriccOperation(TriccOperator.SELECTED, [option_node.select, TriccStatic(option_node)])
|
|
2532
2573
|
|
|
2533
2574
|
if negate:
|
|
2534
2575
|
return TriccOperation(
|
|
@@ -2598,24 +2639,26 @@ def generate_base(node, processed_nodes, **kwargs):
|
|
|
2598
2639
|
# we don't overright if define in the diagram
|
|
2599
2640
|
if node.constraint is None:
|
|
2600
2641
|
if isinstance(node, TriccNodeSelectMultiple):
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2642
|
+
none_opt = get_none_option(node)
|
|
2643
|
+
if none_opt:
|
|
2644
|
+
node.constraint = or_join(
|
|
2645
|
+
[
|
|
2646
|
+
TriccOperation(
|
|
2647
|
+
TriccOperator.EQUAL,
|
|
2648
|
+
["$this", TriccStatic(none_opt)],
|
|
2649
|
+
),
|
|
2650
|
+
TriccOperation(
|
|
2651
|
+
TriccOperator.NOT,
|
|
2652
|
+
[
|
|
2653
|
+
TriccOperation(
|
|
2654
|
+
TriccOperator.SELECTED,
|
|
2655
|
+
["$this", TriccStatic(none_opt)],
|
|
2656
|
+
)
|
|
2657
|
+
],
|
|
2658
|
+
),
|
|
2659
|
+
]
|
|
2660
|
+
) # '.=\'opt_none\' or not(selected(.,\'opt_none\'))'
|
|
2661
|
+
node.constraint_message = "**None** cannot be selected together with choice."
|
|
2619
2662
|
elif node.tricc_type in (
|
|
2620
2663
|
TriccNodeType.integer,
|
|
2621
2664
|
TriccNodeType.decimal,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|