tricc-oo 1.0.1__py3-none-any.whl → 1.4.15__py3-none-any.whl
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.
- tests/build.py +213 -0
- tests/test_cql.py +197 -0
- tests/to_ocl.py +51 -0
- {tricc → tricc_oo}/__init__.py +3 -1
- tricc_oo/converters/codesystem_to_ocl.py +169 -0
- tricc_oo/converters/cql/cqlLexer.py +822 -0
- tricc_oo/converters/cql/cqlListener.py +1632 -0
- tricc_oo/converters/cql/cqlParser.py +11204 -0
- tricc_oo/converters/cql/cqlVisitor.py +913 -0
- tricc_oo/converters/cql_to_operation.py +402 -0
- tricc_oo/converters/datadictionnary.py +115 -0
- tricc_oo/converters/drawio_type_map.py +222 -0
- tricc_oo/converters/tricc_to_xls_form.py +61 -0
- tricc_oo/converters/utils.py +65 -0
- tricc_oo/converters/xml_to_tricc.py +1003 -0
- tricc_oo/models/__init__.py +4 -0
- tricc_oo/models/base.py +732 -0
- tricc_oo/models/calculate.py +216 -0
- tricc_oo/models/ocl.py +281 -0
- tricc_oo/models/ordered_set.py +125 -0
- tricc_oo/models/tricc.py +418 -0
- tricc_oo/parsers/xml.py +138 -0
- tricc_oo/serializers/__init__.py +0 -0
- tricc_oo/serializers/xls_form.py +745 -0
- tricc_oo/strategies/__init__.py +0 -0
- tricc_oo/strategies/input/__init__.py +0 -0
- tricc_oo/strategies/input/base_input_strategy.py +111 -0
- tricc_oo/strategies/input/drawio.py +317 -0
- tricc_oo/strategies/output/base_output_strategy.py +148 -0
- tricc_oo/strategies/output/spice.py +365 -0
- tricc_oo/strategies/output/xls_form.py +697 -0
- tricc_oo/strategies/output/xlsform_cdss.py +189 -0
- tricc_oo/strategies/output/xlsform_cht.py +200 -0
- tricc_oo/strategies/output/xlsform_cht_hf.py +334 -0
- tricc_oo/visitors/__init__.py +0 -0
- tricc_oo/visitors/tricc.py +2198 -0
- tricc_oo/visitors/utils.py +17 -0
- tricc_oo/visitors/xform_pd.py +264 -0
- tricc_oo-1.4.15.dist-info/METADATA +219 -0
- tricc_oo-1.4.15.dist-info/RECORD +46 -0
- {tricc_oo-1.0.1.dist-info → tricc_oo-1.4.15.dist-info}/WHEEL +1 -1
- tricc_oo-1.4.15.dist-info/top_level.txt +2 -0
- tricc/converters/mc_to_tricc.py +0 -542
- tricc/converters/tricc_to_xls_form.py +0 -553
- tricc/converters/utils.py +0 -44
- tricc/converters/xml_to_tricc.py +0 -740
- tricc/models/tricc.py +0 -1093
- tricc/parsers/xml.py +0 -81
- tricc/serializers/xls_form.py +0 -364
- tricc/strategies/input/base_input_strategy.py +0 -80
- tricc/strategies/input/drawio.py +0 -246
- tricc/strategies/input/medalcreator.py +0 -168
- tricc/strategies/output/base_output_strategy.py +0 -92
- tricc/strategies/output/xls_form.py +0 -194
- tricc/strategies/output/xlsform_cdss.py +0 -46
- tricc/strategies/output/xlsform_cht.py +0 -106
- tricc/visitors/tricc.py +0 -375
- tricc_oo-1.0.1.dist-info/LICENSE +0 -78
- tricc_oo-1.0.1.dist-info/METADATA +0 -229
- tricc_oo-1.0.1.dist-info/RECORD +0 -26
- tricc_oo-1.0.1.dist-info/top_level.txt +0 -2
- venv/bin/vba_extract.py +0 -78
- {tricc → tricc_oo}/converters/__init__.py +0 -0
- {tricc → tricc_oo}/models/lang.py +0 -0
- {tricc/serializers → tricc_oo/parsers}/__init__.py +0 -0
- {tricc → tricc_oo}/serializers/planuml.py +0 -0
|
@@ -0,0 +1,745 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import hashlib
|
|
3
|
+
|
|
4
|
+
# from bs4 import BeautifulSoup
|
|
5
|
+
from tricc_oo.converters.tricc_to_xls_form import (
|
|
6
|
+
negate_term,
|
|
7
|
+
VERSION_SEPARATOR,
|
|
8
|
+
INSTANCE_SEPARATOR,
|
|
9
|
+
get_export_name,
|
|
10
|
+
)
|
|
11
|
+
from tricc_oo.converters.utils import clean_name, remove_html
|
|
12
|
+
from tricc_oo.models.lang import SingletonLangClass
|
|
13
|
+
from tricc_oo.models import *
|
|
14
|
+
import re
|
|
15
|
+
from tricc_oo.visitors.tricc import (
|
|
16
|
+
is_ready_to_process,
|
|
17
|
+
process_reference,
|
|
18
|
+
add_calculate,
|
|
19
|
+
TRICC_TRUE_VALUE,
|
|
20
|
+
TRICC_FALSE_VALUE,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger("default")
|
|
24
|
+
|
|
25
|
+
langs = SingletonLangClass()
|
|
26
|
+
TRICC_CALC_EXPRESSION = "${{{0}}}>0"
|
|
27
|
+
|
|
28
|
+
BOOLEAN_MAP = {
|
|
29
|
+
str(TRICC_TRUE_VALUE): 1,
|
|
30
|
+
str(TRICC_FALSE_VALUE): 0,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def start_group(
|
|
35
|
+
strategy, cur_group, groups, df_survey, df_calculate, relevance=False, **kwargs
|
|
36
|
+
):
|
|
37
|
+
name = get_export_name(cur_group)
|
|
38
|
+
|
|
39
|
+
if name in groups:
|
|
40
|
+
groups[name] += 1
|
|
41
|
+
name = name + "_" + str(groups[name])
|
|
42
|
+
|
|
43
|
+
else:
|
|
44
|
+
groups[name] = 0
|
|
45
|
+
is_activity = isinstance(cur_group, TriccNodeActivity)
|
|
46
|
+
relevance = (
|
|
47
|
+
relevance and cur_group.relevance is not None and cur_group.relevance != ""
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
group_calc_required = (
|
|
51
|
+
False and relevance and not is_activity and len(relevance) > 100
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
relevance_expression = cur_group.relevance
|
|
55
|
+
if not relevance:
|
|
56
|
+
relevance_expression = ""
|
|
57
|
+
elif isinstance(relevance_expression, TriccOperation):
|
|
58
|
+
relevance_expression = strategy.get_tricc_operation_expression(
|
|
59
|
+
relevance_expression
|
|
60
|
+
)
|
|
61
|
+
elif isinstance(relevance_expression, TriccStatic):
|
|
62
|
+
relevance_expression = str(relevance_expression.value)
|
|
63
|
+
|
|
64
|
+
# elif is_activity:
|
|
65
|
+
# relevance_expression = TRICC_CALC_EXPRESSION.format(get_export_name(cur_group.root))
|
|
66
|
+
elif group_calc_required:
|
|
67
|
+
relevance_expression = TRICC_CALC_EXPRESSION.format("gcalc_" + name)
|
|
68
|
+
|
|
69
|
+
## group
|
|
70
|
+
values = []
|
|
71
|
+
for column in SURVEY_MAP:
|
|
72
|
+
if column == "type":
|
|
73
|
+
values.append("begin group")
|
|
74
|
+
elif column == "name":
|
|
75
|
+
values.append(name)
|
|
76
|
+
elif column == "appearance":
|
|
77
|
+
values.append("field-list")
|
|
78
|
+
elif column == "relevance":
|
|
79
|
+
if relevance_expression is True:
|
|
80
|
+
values.append("")
|
|
81
|
+
else:
|
|
82
|
+
values.append(relevance_expression)
|
|
83
|
+
|
|
84
|
+
else:
|
|
85
|
+
values.append(get_xfrom_trad(strategy, cur_group, column, SURVEY_MAP))
|
|
86
|
+
df_survey.loc[len(df_survey)] = values
|
|
87
|
+
|
|
88
|
+
### calc
|
|
89
|
+
if (
|
|
90
|
+
group_calc_required
|
|
91
|
+
and len(df_calculate[df_calculate["name"] == "gcalc_" + name]) == 0
|
|
92
|
+
):
|
|
93
|
+
calc_values = []
|
|
94
|
+
for column in SURVEY_MAP:
|
|
95
|
+
if column == "type":
|
|
96
|
+
calc_values.append("calculate")
|
|
97
|
+
elif column == "name":
|
|
98
|
+
value = "gcalc_" + name
|
|
99
|
+
calc_values.append(value)
|
|
100
|
+
elif column == "calculation":
|
|
101
|
+
calc_values.append(
|
|
102
|
+
get_attr_if_exists(strategy, cur_group, "relevance", SURVEY_MAP)
|
|
103
|
+
)
|
|
104
|
+
elif column == "relevance":
|
|
105
|
+
calc_values.append("")
|
|
106
|
+
else:
|
|
107
|
+
calc_values.append(
|
|
108
|
+
get_xfrom_trad(strategy, cur_group, column, SURVEY_MAP)
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
df_calculate.loc[len(df_calculate)] = calc_values
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# def add_background_color(input_string, color):
|
|
115
|
+
# """
|
|
116
|
+
# Adds a background color to an HTML string or wraps a plain string in a <p> tag with the background color.
|
|
117
|
+
|
|
118
|
+
# Args:
|
|
119
|
+
# input_string (str): The input string, either plain text or HTML.
|
|
120
|
+
# color (str): The background color to apply (e.g., 'yellow', '#ffcc00').
|
|
121
|
+
|
|
122
|
+
# Returns:
|
|
123
|
+
# str: The resulting HTML string with the background color applied.
|
|
124
|
+
# """
|
|
125
|
+
# if not input_string:
|
|
126
|
+
# return input_string
|
|
127
|
+
# # Parse the input string using BeautifulSoup
|
|
128
|
+
# soup = BeautifulSoup(input_string, 'html.parser')
|
|
129
|
+
|
|
130
|
+
# # Check if the input is already an HTML structure
|
|
131
|
+
# if soup.find(): # If there are any tags in the input
|
|
132
|
+
# # Add the background color to the root element's style attribute
|
|
133
|
+
# root = soup.find() # Get the first (root) element
|
|
134
|
+
# existing_style = root.get('style', '')
|
|
135
|
+
# root['style'] = f"{existing_style} background-color: {color};".strip()
|
|
136
|
+
# else:
|
|
137
|
+
# # Wrap the plain text in a <p> tag with the background color
|
|
138
|
+
# soup = BeautifulSoup(f'<p style="background-color: {color};">{input_string}</p>', 'html.parser')
|
|
139
|
+
|
|
140
|
+
# return str(soup)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def end_group(strategy, cur_group, groups, df_survey, **kwargs):
|
|
144
|
+
values = []
|
|
145
|
+
for column in SURVEY_MAP:
|
|
146
|
+
if column == "type":
|
|
147
|
+
values.append("end group")
|
|
148
|
+
elif column == "relevance":
|
|
149
|
+
values.append("")
|
|
150
|
+
elif column in ("name"):
|
|
151
|
+
value = get_attr_if_exists(strategy, cur_group, column, SURVEY_MAP)
|
|
152
|
+
|
|
153
|
+
if get_export_name(cur_group) in groups:
|
|
154
|
+
value = value + "_" + str(groups[get_export_name(cur_group)]) + "_end"
|
|
155
|
+
values.append(value)
|
|
156
|
+
else:
|
|
157
|
+
values.append(get_xfrom_trad(strategy, cur_group, column, SURVEY_MAP))
|
|
158
|
+
df_survey.loc[len(df_survey)] = values
|
|
159
|
+
|
|
160
|
+
# waltk thought the node,
|
|
161
|
+
# if node has group, open the group (and parent group)
|
|
162
|
+
# check process the next_node with the same group first, then process the other
|
|
163
|
+
|
|
164
|
+
# if node has another group (not current) close the group
|
|
165
|
+
# if node is an activity close the group
|
|
166
|
+
|
|
167
|
+
# during tricc object building/ or par of the stategy
|
|
168
|
+
# static calculte node with same name:
|
|
169
|
+
# follow same approach as the dynamic
|
|
170
|
+
# if reference not in used_saves
|
|
171
|
+
# , then create calculate node reference_1 # and save is used_saves 'reference' : 1
|
|
172
|
+
# else create calculate node reference_(used_saves['reference']+1) # and update used_saves['reference'] += 1
|
|
173
|
+
# once done, walkthrough again and remame reference_(used_saves['reference']) to reference and create the other save
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
ODK_TRICC_TYPE_MAP = {
|
|
177
|
+
"note": "note",
|
|
178
|
+
"calculate": "calculate",
|
|
179
|
+
"select_multiple": "select_multiple",
|
|
180
|
+
"select_one": "select_one",
|
|
181
|
+
"decimal": "decimal",
|
|
182
|
+
"integer": "integer",
|
|
183
|
+
"text": "text",
|
|
184
|
+
"rhombus": "calculate",
|
|
185
|
+
"goto": "", #: start the linked activity within the target activity
|
|
186
|
+
"start": "",
|
|
187
|
+
"activity_start": "calculate",
|
|
188
|
+
"link_in": "",
|
|
189
|
+
"link_out": "",
|
|
190
|
+
"count": "calculate",
|
|
191
|
+
"add": "calculate",
|
|
192
|
+
"container_hint_media": "",
|
|
193
|
+
"activity": "",
|
|
194
|
+
"select_option": "",
|
|
195
|
+
"hint": "",
|
|
196
|
+
"help": "",
|
|
197
|
+
"exclusive": "calculate",
|
|
198
|
+
"end": "calculate",
|
|
199
|
+
"activity_end": "calculate",
|
|
200
|
+
"edge": "",
|
|
201
|
+
"page": "",
|
|
202
|
+
"bridge": "calculate",
|
|
203
|
+
"date": "date",
|
|
204
|
+
"diagnosis": "calculate",
|
|
205
|
+
"proposed_diagnosis": "calculate",
|
|
206
|
+
"input": "",
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
GROUP_TRICC_TYPE = [TriccNodeType.page, TriccNodeType.activity]
|
|
210
|
+
|
|
211
|
+
SURVEY_MAP = {
|
|
212
|
+
"type": ODK_TRICC_TYPE_MAP,
|
|
213
|
+
"name": "name",
|
|
214
|
+
**langs.get_trads_map("label"),
|
|
215
|
+
**langs.get_trads_map("hint"),
|
|
216
|
+
**langs.get_trads_map("help"),
|
|
217
|
+
"default": "default",
|
|
218
|
+
"appearance": "appearance",
|
|
219
|
+
"constraint": "constraint",
|
|
220
|
+
**langs.get_trads_map("constraint_message"),
|
|
221
|
+
"relevance": "relevance",
|
|
222
|
+
"disabled": "disabled",
|
|
223
|
+
"required": "required",
|
|
224
|
+
**langs.get_trads_map("required_message"),
|
|
225
|
+
"read only": "read only",
|
|
226
|
+
"calculation": "expression",
|
|
227
|
+
"repeat_count": "repeat_count",
|
|
228
|
+
"media::image": "image",
|
|
229
|
+
"choice_filter": "",
|
|
230
|
+
}
|
|
231
|
+
CHOICE_MAP = {
|
|
232
|
+
"list_name": "list_name",
|
|
233
|
+
"value": "name",
|
|
234
|
+
**langs.get_trads_map("label"),
|
|
235
|
+
"media::image": "image",
|
|
236
|
+
"choice_filter": "",
|
|
237
|
+
"y_min": "",
|
|
238
|
+
"y_max": "",
|
|
239
|
+
"l": "",
|
|
240
|
+
"s": "",
|
|
241
|
+
"m": "",
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
TRAD_MAP = ["label", "constraint_message", "required_message", "hint", "help"]
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def get_xfrom_trad(strategy, node, column, mapping, clean_html=False):
|
|
249
|
+
arr = column.split("::")
|
|
250
|
+
new_column = arr[0] if arr[0] != "media" else "::".join(arr[0:2])
|
|
251
|
+
trad = arr[-1] if new_column != column else None
|
|
252
|
+
value = get_attr_if_exists(strategy, node, new_column, mapping)
|
|
253
|
+
# the pattern is to look for if that define a string if(test>0, 'strin')
|
|
254
|
+
pattern = r"concat\(|[^\}] *, *'[^']"
|
|
255
|
+
if (
|
|
256
|
+
issubclass(node.__class__, TriccNodeDisplayCalculateBase)
|
|
257
|
+
and column == "calculation"
|
|
258
|
+
and isinstance(value, str)
|
|
259
|
+
and not value.startswith("number")
|
|
260
|
+
and getattr(node, "expression", None)
|
|
261
|
+
and node.expression.get_datatype() in ("number", "boolean")
|
|
262
|
+
):
|
|
263
|
+
value = f"number({value})" if str(value) not in ["0", "1"] else value
|
|
264
|
+
if clean_html and isinstance(value, str):
|
|
265
|
+
value = remove_html(value)
|
|
266
|
+
if column in TRAD_MAP:
|
|
267
|
+
value = langs.get_trads(value, trad=trad)
|
|
268
|
+
elif column == "appearance":
|
|
269
|
+
if (
|
|
270
|
+
isinstance(node, TriccNodeSelect)
|
|
271
|
+
and len(node.options) > 9
|
|
272
|
+
and not any(o.image or o.hint for o in node.options.values())
|
|
273
|
+
):
|
|
274
|
+
value = "autocomplete"
|
|
275
|
+
elif isinstance(node, TriccNodeNote) and "countdown-timer" in node.name:
|
|
276
|
+
value = "countdown-timer"
|
|
277
|
+
elif (
|
|
278
|
+
column == "appearance"
|
|
279
|
+
and isinstance(node, TriccNodeAcceptDiagnostic)
|
|
280
|
+
and node.severity
|
|
281
|
+
and not value
|
|
282
|
+
):
|
|
283
|
+
if node.severity == "severe":
|
|
284
|
+
value = "severe"
|
|
285
|
+
elif node.severity == "moderate":
|
|
286
|
+
value = "moderate"
|
|
287
|
+
elif node.severity == "light":
|
|
288
|
+
value == "light"
|
|
289
|
+
|
|
290
|
+
return value
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def gen_operation_hash(op):
|
|
294
|
+
if op:
|
|
295
|
+
h = hashlib.blake2b(digest_size=6)
|
|
296
|
+
h.update(str(op).encode("utf-8"))
|
|
297
|
+
return h.hexdigest()
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def generate_choice_filter(strategy, node):
|
|
301
|
+
if isinstance(node, TriccNodeSelectOption) and node.relevance:
|
|
302
|
+
return gen_operation_hash(node.relevance)
|
|
303
|
+
if not isinstance(node, (TriccNodeSelectMultiple, TriccNodeSelectOne)):
|
|
304
|
+
return
|
|
305
|
+
relevances = {}
|
|
306
|
+
option_filter = {}
|
|
307
|
+
for o in node.options.values():
|
|
308
|
+
if o.relevance:
|
|
309
|
+
key = gen_operation_hash(o.relevance)
|
|
310
|
+
if key not in relevances:
|
|
311
|
+
relevances[key] = o.relevance
|
|
312
|
+
if relevances:
|
|
313
|
+
basic = "string-length(choice_filter)=0"
|
|
314
|
+
# TODO remove when the bug regarding filter + image will be fixed
|
|
315
|
+
if any(i.image is not None for i in node.options.values()):
|
|
316
|
+
basic = TriccOperation(
|
|
317
|
+
TriccOperator.AND, ["string-length(choice_filter)=0", node.relevance]
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
choice_filter = TriccOperation(TriccOperator.OR, [basic])
|
|
321
|
+
for k, op in relevances.items():
|
|
322
|
+
choice_filter.append(
|
|
323
|
+
TriccOperation(
|
|
324
|
+
TriccOperator.AND,
|
|
325
|
+
[
|
|
326
|
+
TriccOperation(
|
|
327
|
+
TriccOperator.EQUAL,
|
|
328
|
+
[
|
|
329
|
+
"choice_filter",
|
|
330
|
+
TriccStatic(k),
|
|
331
|
+
],
|
|
332
|
+
),
|
|
333
|
+
op,
|
|
334
|
+
],
|
|
335
|
+
)
|
|
336
|
+
)
|
|
337
|
+
return strategy.get_tricc_operation_expression(choice_filter)
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def get_attr_if_exists(strategy, node, column, map_array):
|
|
341
|
+
if column in map_array:
|
|
342
|
+
mapping = map_array[column]
|
|
343
|
+
if (
|
|
344
|
+
isinstance(mapping, Dict)
|
|
345
|
+
and getattr(node, "tricc_type", None) in map_array[column]
|
|
346
|
+
):
|
|
347
|
+
tricc_type = map_array[column][node.tricc_type]
|
|
348
|
+
if tricc_type[:6] == "select":
|
|
349
|
+
return tricc_type + " " + node.list_name
|
|
350
|
+
else:
|
|
351
|
+
return tricc_type
|
|
352
|
+
elif hasattr(node, map_array[column]):
|
|
353
|
+
value = getattr(node, map_array[column])
|
|
354
|
+
if (
|
|
355
|
+
column == "calculation"
|
|
356
|
+
and len(node.prev_nodes) == 0
|
|
357
|
+
and value
|
|
358
|
+
and isinstance(
|
|
359
|
+
getattr(node, "applicability", None),
|
|
360
|
+
(TriccOperation, TriccStatic, TriccReference),
|
|
361
|
+
)
|
|
362
|
+
):
|
|
363
|
+
if value.get_datatype() == "boolean" and node.applicability.get_datatype() == "boolean":
|
|
364
|
+
value = and_join([node.applicability, value])
|
|
365
|
+
else:
|
|
366
|
+
value = TriccOperation(
|
|
367
|
+
TriccOperator.IF,
|
|
368
|
+
[
|
|
369
|
+
node.applicability,
|
|
370
|
+
value,
|
|
371
|
+
(
|
|
372
|
+
TriccStatic(False)
|
|
373
|
+
if node.applicability.get_datatype() == "boolean"
|
|
374
|
+
else TriccStatic("")
|
|
375
|
+
),
|
|
376
|
+
],
|
|
377
|
+
)
|
|
378
|
+
if column == "name":
|
|
379
|
+
if issubclass(value.__class__, (TriccNodeBaseModel)):
|
|
380
|
+
return get_export_name(value)
|
|
381
|
+
else:
|
|
382
|
+
return get_export_name(node)
|
|
383
|
+
# convert value to boolean
|
|
384
|
+
if column == "value" and str(value) in BOOLEAN_MAP:
|
|
385
|
+
return BOOLEAN_MAP[str(value)]
|
|
386
|
+
|
|
387
|
+
elif isinstance(value, (TriccOperation, TriccStatic, TriccReference)):
|
|
388
|
+
expression = strategy.get_tricc_operation_expression(value)
|
|
389
|
+
return (
|
|
390
|
+
expression.replace("$this", ".")
|
|
391
|
+
if isinstance(expression, str)
|
|
392
|
+
else expression
|
|
393
|
+
)
|
|
394
|
+
elif value is not None:
|
|
395
|
+
return str(value) if not isinstance(value, dict) else value
|
|
396
|
+
else:
|
|
397
|
+
return ""
|
|
398
|
+
elif column == "choice_filter":
|
|
399
|
+
return generate_choice_filter(strategy, node)
|
|
400
|
+
|
|
401
|
+
else:
|
|
402
|
+
return ""
|
|
403
|
+
elif hasattr(node, column) and getattr(node, column) is not None:
|
|
404
|
+
value = getattr(node, column)
|
|
405
|
+
return str(value) if not isinstance(value, dict) else value
|
|
406
|
+
else:
|
|
407
|
+
return ""
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def get_more_info_select(strategy, node):
|
|
411
|
+
values = []
|
|
412
|
+
for column in SURVEY_MAP:
|
|
413
|
+
if column == "type":
|
|
414
|
+
values.append("select_one more_info")
|
|
415
|
+
elif column == "label":
|
|
416
|
+
values.append("NO_LABEL")
|
|
417
|
+
elif column == "name":
|
|
418
|
+
values.append(get_export_name(node) + "_optin")
|
|
419
|
+
elif column == "hint":
|
|
420
|
+
print(get_xfrom_trad(strategy, node, column, SURVEY_MAP, clean_html=True))
|
|
421
|
+
values.append(
|
|
422
|
+
get_xfrom_trad(strategy, node, column, SURVEY_MAP, clean_html=True)
|
|
423
|
+
)
|
|
424
|
+
elif column == "relevance":
|
|
425
|
+
values.append(get_xfrom_trad(strategy, node.parent, column, SURVEY_MAP))
|
|
426
|
+
else:
|
|
427
|
+
values.append(get_xfrom_trad(strategy, None, column, SURVEY_MAP))
|
|
428
|
+
return values
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
def get_more_info_message(strategy, node):
|
|
432
|
+
values = []
|
|
433
|
+
for column in SURVEY_MAP:
|
|
434
|
+
if column == "type":
|
|
435
|
+
values.append("note")
|
|
436
|
+
elif column == "relevance":
|
|
437
|
+
values.append(f"${{{get_export_name(node)}_optin}} = 1")
|
|
438
|
+
elif column.startswith("hint"):
|
|
439
|
+
values.append(langs.get_trads("", trad=None))
|
|
440
|
+
else:
|
|
441
|
+
values.append(
|
|
442
|
+
get_xfrom_trad(strategy, node, column, SURVEY_MAP, clean_html=True)
|
|
443
|
+
)
|
|
444
|
+
return values
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
def get_more_info_choice(strategy):
|
|
448
|
+
values = []
|
|
449
|
+
for column in CHOICE_MAP:
|
|
450
|
+
if column == "list_name":
|
|
451
|
+
values.append("more_info")
|
|
452
|
+
elif column == "value":
|
|
453
|
+
values.append("1")
|
|
454
|
+
elif column.startswith("label"):
|
|
455
|
+
arr = column.split("::")
|
|
456
|
+
column = arr[0]
|
|
457
|
+
trad = arr[1] if len(arr) == 2 else None
|
|
458
|
+
values.append(langs.get_trads("More information", trad=trad))
|
|
459
|
+
else:
|
|
460
|
+
values.append(get_xfrom_trad(strategy, None, column, CHOICE_MAP, True))
|
|
461
|
+
return values
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def generate_xls_form_export(
|
|
465
|
+
strategy,
|
|
466
|
+
node,
|
|
467
|
+
processed_nodes,
|
|
468
|
+
stashed_nodes,
|
|
469
|
+
df_survey,
|
|
470
|
+
df_choice,
|
|
471
|
+
df_calculate,
|
|
472
|
+
cur_group,
|
|
473
|
+
calculates,
|
|
474
|
+
**kwargs,
|
|
475
|
+
):
|
|
476
|
+
# check that all prev nodes were processed
|
|
477
|
+
if is_ready_to_process(node, processed_nodes, strict=True) and process_reference(
|
|
478
|
+
node,
|
|
479
|
+
processed_nodes,
|
|
480
|
+
calculates,
|
|
481
|
+
replace_reference=False,
|
|
482
|
+
codesystems=kwargs.get("codesystems", None),
|
|
483
|
+
):
|
|
484
|
+
if node not in processed_nodes:
|
|
485
|
+
add_calculate(calculates, node)
|
|
486
|
+
if node.group != cur_group and not isinstance(node, TriccNodeSelectOption):
|
|
487
|
+
return False
|
|
488
|
+
if kwargs.get("warn", True):
|
|
489
|
+
logger.debug("printing node {}".format(node.get_name()))
|
|
490
|
+
# clean stashed node when processed
|
|
491
|
+
if node in stashed_nodes:
|
|
492
|
+
stashed_nodes.remove(node)
|
|
493
|
+
if kwargs.get("warn", True):
|
|
494
|
+
logger.debug(
|
|
495
|
+
"generate_xls_form_export: unstashing processed node{} ".format(
|
|
496
|
+
node.get_name()
|
|
497
|
+
)
|
|
498
|
+
)
|
|
499
|
+
if issubclass(
|
|
500
|
+
node.__class__, (TriccNodeDisplayCalculateBase, TriccNodeDisplayModel)
|
|
501
|
+
):
|
|
502
|
+
if isinstance(node, TriccNodeSelectOption):
|
|
503
|
+
values = []
|
|
504
|
+
for column in CHOICE_MAP:
|
|
505
|
+
values.append(
|
|
506
|
+
get_xfrom_trad(strategy, node, column, CHOICE_MAP, True)
|
|
507
|
+
)
|
|
508
|
+
# add only if not existing
|
|
509
|
+
if (
|
|
510
|
+
len(
|
|
511
|
+
df_choice[
|
|
512
|
+
(df_choice["list_name"] == node.list_name)
|
|
513
|
+
& (
|
|
514
|
+
df_choice["value"]
|
|
515
|
+
== BOOLEAN_MAP.get(str(node.name), node.name)
|
|
516
|
+
)
|
|
517
|
+
]
|
|
518
|
+
)
|
|
519
|
+
== 0
|
|
520
|
+
):
|
|
521
|
+
df_choice.loc[len(df_choice)] = values
|
|
522
|
+
elif isinstance(node, TriccNodeMoreInfo):
|
|
523
|
+
df_survey.loc[len(df_survey)] = get_more_info_select(strategy, node)
|
|
524
|
+
df_survey.loc[len(df_survey)] = get_more_info_message(
|
|
525
|
+
strategy, node
|
|
526
|
+
)
|
|
527
|
+
if len(df_choice[(df_choice["list_name"] == "more_info")]) == 0:
|
|
528
|
+
df_choice.loc[len(df_choice)] = get_more_info_choice(strategy)
|
|
529
|
+
elif (
|
|
530
|
+
node.tricc_type in ODK_TRICC_TYPE_MAP
|
|
531
|
+
and ODK_TRICC_TYPE_MAP[node.tricc_type] is not None
|
|
532
|
+
):
|
|
533
|
+
if ODK_TRICC_TYPE_MAP[node.tricc_type] == "calculate":
|
|
534
|
+
values = []
|
|
535
|
+
for column in SURVEY_MAP:
|
|
536
|
+
value = get_xfrom_trad(strategy, node, column, SURVEY_MAP)
|
|
537
|
+
if (
|
|
538
|
+
column == "default"
|
|
539
|
+
and issubclass(
|
|
540
|
+
node.__class__, TriccNodeDisplayCalculateBase
|
|
541
|
+
)
|
|
542
|
+
and value == ""
|
|
543
|
+
):
|
|
544
|
+
value = 0
|
|
545
|
+
values.append(value)
|
|
546
|
+
if (
|
|
547
|
+
len(
|
|
548
|
+
df_calculate[df_calculate.name == get_export_name(node)]
|
|
549
|
+
)
|
|
550
|
+
== 0
|
|
551
|
+
):
|
|
552
|
+
df_calculate.loc[len(df_calculate)] = values
|
|
553
|
+
else:
|
|
554
|
+
df_calculate.loc[len(df_calculate)] = values
|
|
555
|
+
logger.critical("name {} found twice".format(node.name))
|
|
556
|
+
elif ODK_TRICC_TYPE_MAP[node.tricc_type] != "":
|
|
557
|
+
values = []
|
|
558
|
+
for column in SURVEY_MAP:
|
|
559
|
+
values.append(
|
|
560
|
+
get_xfrom_trad(strategy, node, column, SURVEY_MAP)
|
|
561
|
+
)
|
|
562
|
+
df_survey.loc[len(df_survey)] = values
|
|
563
|
+
else:
|
|
564
|
+
logger.warning(
|
|
565
|
+
"node {} have an unmapped type {}".format(
|
|
566
|
+
node.get_name(), node.tricc_type
|
|
567
|
+
)
|
|
568
|
+
)
|
|
569
|
+
else:
|
|
570
|
+
logger.warning(
|
|
571
|
+
"node {} have an unsupported type {}".format(
|
|
572
|
+
node.get_name(), node.tricc_type
|
|
573
|
+
)
|
|
574
|
+
)
|
|
575
|
+
# continue walk °
|
|
576
|
+
return True
|
|
577
|
+
return False
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
def get_input_line(node, replace_dots=True):
|
|
581
|
+
label = langs.get_trads(node.label, force_dict=True)
|
|
582
|
+
empty = langs.get_trads("", force_dict=True)
|
|
583
|
+
return [
|
|
584
|
+
"hidden",
|
|
585
|
+
clean_name(node.name, replace_dots=True),
|
|
586
|
+
*list(empty.values()),
|
|
587
|
+
*list(empty.values()), # hint
|
|
588
|
+
*list(empty.values()), # help
|
|
589
|
+
"", # default
|
|
590
|
+
"hidden", #'appearance', clean_name
|
|
591
|
+
"", #'constraint',
|
|
592
|
+
*list(empty.values()), #'constraint_message'
|
|
593
|
+
"", #'relevance'
|
|
594
|
+
"", #'disabled'
|
|
595
|
+
"", #'required'
|
|
596
|
+
*list(empty.values()), #'required message'
|
|
597
|
+
"", #'read only'
|
|
598
|
+
"", #'expression'
|
|
599
|
+
"", #'repeat_count'
|
|
600
|
+
"", #'image'
|
|
601
|
+
"",
|
|
602
|
+
]
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
def get_input_calc_line(node, replace_dots=True):
|
|
606
|
+
label = langs.get_trads(node.label, force_dict=True)
|
|
607
|
+
empty = langs.get_trads("", force_dict=True)
|
|
608
|
+
return [
|
|
609
|
+
"calculate",
|
|
610
|
+
get_export_name(node),
|
|
611
|
+
*list(empty.values()),
|
|
612
|
+
*list(empty.values()), # hint
|
|
613
|
+
*list(empty.values()), # help
|
|
614
|
+
"", # default
|
|
615
|
+
"", #'appearance', clean_name
|
|
616
|
+
"", #'constraint',
|
|
617
|
+
*list(empty.values()), #'constraint_message'
|
|
618
|
+
"", #'relevance'
|
|
619
|
+
"", #'disabled'
|
|
620
|
+
"", #'required'
|
|
621
|
+
*list(empty.values()), #'required message'
|
|
622
|
+
"", #'read only'
|
|
623
|
+
"../inputs/contact/"
|
|
624
|
+
+ clean_name(node.name, replace_dots=replace_dots), #'expression'
|
|
625
|
+
"", #'repeat_count'
|
|
626
|
+
"", #'image'
|
|
627
|
+
"", # choice filter
|
|
628
|
+
]
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
def get_diagnostic_start_group_line():
|
|
632
|
+
label = langs.get_trads("List of diagnostics", force_dict=True)
|
|
633
|
+
empty = langs.get_trads("", force_dict=True)
|
|
634
|
+
return [
|
|
635
|
+
"begin group",
|
|
636
|
+
"l_diag_list25",
|
|
637
|
+
*list(label.values()),
|
|
638
|
+
*list(empty.values()), # hint
|
|
639
|
+
*list(empty.values()), # help
|
|
640
|
+
"", # default
|
|
641
|
+
"field-list", #'appearance',
|
|
642
|
+
"", #'constraint',
|
|
643
|
+
*list(empty.values()), #'constraint_message'
|
|
644
|
+
"", #'relevance'
|
|
645
|
+
"", #'disabled'
|
|
646
|
+
"", #'required'
|
|
647
|
+
*list(empty.values()), #'required message'
|
|
648
|
+
"", #'read only'
|
|
649
|
+
"", #'expression'
|
|
650
|
+
"", #'repeat_count'
|
|
651
|
+
"", #'image'
|
|
652
|
+
"",
|
|
653
|
+
]
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
def get_diagnostic_add_line(diags, df_choice):
|
|
657
|
+
for diag in diags:
|
|
658
|
+
df_choice.loc[len(df_choice)] = [
|
|
659
|
+
"tricc_diag_add",
|
|
660
|
+
get_export_name(diag),
|
|
661
|
+
*list(langs.get_trads(diag.label, True).values()),
|
|
662
|
+
"", # filter
|
|
663
|
+
"", # min y
|
|
664
|
+
"", # max Y
|
|
665
|
+
"", # l
|
|
666
|
+
"", # m
|
|
667
|
+
"", # s
|
|
668
|
+
]
|
|
669
|
+
label = langs.get_trads("Add a missing diagnostic", force_dict=True)
|
|
670
|
+
empty = langs.get_trads("", force_dict=True)
|
|
671
|
+
return [
|
|
672
|
+
"select_multiple tricc_diag_add",
|
|
673
|
+
"new_diag",
|
|
674
|
+
*list(label.values()),
|
|
675
|
+
*list(empty.values()), # hint
|
|
676
|
+
*list(empty.values()), # help
|
|
677
|
+
"", # default
|
|
678
|
+
"minimal", #'appearance',
|
|
679
|
+
"", #'constraint',
|
|
680
|
+
*list(empty.values()), #'constraint_message',
|
|
681
|
+
"", #'relevance'
|
|
682
|
+
"", #'disabled'
|
|
683
|
+
"", #'required'
|
|
684
|
+
*list(empty.values()), #'required message'
|
|
685
|
+
"", #'read only'
|
|
686
|
+
"", #'expression'
|
|
687
|
+
"", #'repeat_count'
|
|
688
|
+
"", #'image'
|
|
689
|
+
"",
|
|
690
|
+
]
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
def get_diagnostic_none_line(diags):
|
|
694
|
+
relevance = ""
|
|
695
|
+
for diag in diags:
|
|
696
|
+
relevance += TRICC_CALC_EXPRESSION.format(get_export_name(diag)) + " or "
|
|
697
|
+
label = langs.get_trads(
|
|
698
|
+
"Aucun diagnostic trouvé par l'outil mais cela ne veut pas dire que le patient est en bonne santé",
|
|
699
|
+
force_dict=True,
|
|
700
|
+
)
|
|
701
|
+
empty = langs.get_trads("", force_dict=True)
|
|
702
|
+
return [
|
|
703
|
+
"note",
|
|
704
|
+
"l_diag_none25",
|
|
705
|
+
*list(label.values()),
|
|
706
|
+
*list(empty.values()),
|
|
707
|
+
*list(empty.values()),
|
|
708
|
+
"", # default
|
|
709
|
+
"", #'appearance',
|
|
710
|
+
"", #'constraint',
|
|
711
|
+
*list(empty.values()),
|
|
712
|
+
f"not({relevance[:-4]})", #'relevance'
|
|
713
|
+
"", #'disabled'
|
|
714
|
+
"", #'required'
|
|
715
|
+
*list(empty.values()),
|
|
716
|
+
"", #'read only'
|
|
717
|
+
"", #'expression'
|
|
718
|
+
"", #'repeat_count'
|
|
719
|
+
"", #'image' TRICC_NEGATE
|
|
720
|
+
"",
|
|
721
|
+
]
|
|
722
|
+
|
|
723
|
+
|
|
724
|
+
def get_diagnostic_stop_group_line():
|
|
725
|
+
label = langs.get_trads("", force_dict=True)
|
|
726
|
+
return [
|
|
727
|
+
"end group",
|
|
728
|
+
"l_diag_list25",
|
|
729
|
+
*list(label.values()),
|
|
730
|
+
*list(label.values()),
|
|
731
|
+
*list(label.values()), # help
|
|
732
|
+
"", # default
|
|
733
|
+
"", #'appearance',
|
|
734
|
+
"", #'constraint',
|
|
735
|
+
*list(label.values()),
|
|
736
|
+
"", #'relevance'
|
|
737
|
+
"", #'disabled'
|
|
738
|
+
"", #'required'
|
|
739
|
+
*list(label.values()),
|
|
740
|
+
"", #'read only'
|
|
741
|
+
"", #'expression'
|
|
742
|
+
"", #'repeat_count'
|
|
743
|
+
"", #'image'
|
|
744
|
+
"",
|
|
745
|
+
]
|