tricc-oo 1.5.13__py3-none-any.whl → 1.6.8__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 +20 -28
- tests/test_build.py +260 -0
- tests/test_cql.py +48 -109
- tests/to_ocl.py +15 -17
- tricc_oo/__init__.py +0 -6
- tricc_oo/converters/codesystem_to_ocl.py +51 -40
- tricc_oo/converters/cql/cqlLexer.py +1 -0
- tricc_oo/converters/cql/cqlListener.py +1 -0
- tricc_oo/converters/cql/cqlParser.py +1 -0
- tricc_oo/converters/cql/cqlVisitor.py +1 -0
- tricc_oo/converters/cql_to_operation.py +129 -123
- tricc_oo/converters/datadictionnary.py +45 -54
- tricc_oo/converters/drawio_type_map.py +146 -65
- tricc_oo/converters/tricc_to_xls_form.py +58 -28
- tricc_oo/converters/utils.py +4 -4
- tricc_oo/converters/xml_to_tricc.py +296 -235
- tricc_oo/models/__init__.py +2 -1
- tricc_oo/models/base.py +333 -305
- tricc_oo/models/calculate.py +66 -51
- tricc_oo/models/lang.py +26 -27
- tricc_oo/models/ocl.py +146 -161
- tricc_oo/models/ordered_set.py +15 -19
- tricc_oo/models/tricc.py +149 -89
- tricc_oo/parsers/xml.py +15 -30
- tricc_oo/serializers/planuml.py +4 -6
- tricc_oo/serializers/xls_form.py +110 -153
- tricc_oo/strategies/input/base_input_strategy.py +28 -32
- tricc_oo/strategies/input/drawio.py +59 -71
- tricc_oo/strategies/output/base_output_strategy.py +151 -65
- tricc_oo/strategies/output/dhis2_form.py +908 -0
- tricc_oo/strategies/output/fhir_form.py +377 -0
- tricc_oo/strategies/output/html_form.py +224 -0
- tricc_oo/strategies/output/openmrs_form.py +694 -0
- tricc_oo/strategies/output/spice.py +106 -127
- tricc_oo/strategies/output/xls_form.py +322 -244
- tricc_oo/strategies/output/xlsform_cdss.py +627 -142
- tricc_oo/strategies/output/xlsform_cht.py +252 -125
- tricc_oo/strategies/output/xlsform_cht_hf.py +13 -24
- tricc_oo/visitors/tricc.py +1424 -1033
- tricc_oo/visitors/utils.py +16 -16
- tricc_oo/visitors/xform_pd.py +91 -89
- {tricc_oo-1.5.13.dist-info → tricc_oo-1.6.8.dist-info}/METADATA +128 -84
- tricc_oo-1.6.8.dist-info/RECORD +52 -0
- tricc_oo-1.6.8.dist-info/licenses/LICENSE +373 -0
- {tricc_oo-1.5.13.dist-info → tricc_oo-1.6.8.dist-info}/top_level.txt +0 -0
- tricc_oo-1.5.13.dist-info/RECORD +0 -46
- {tricc_oo-1.5.13.dist-info → tricc_oo-1.6.8.dist-info}/WHEEL +0 -0
|
@@ -2,7 +2,7 @@ import datetime
|
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
4
|
import shutil
|
|
5
|
-
import
|
|
5
|
+
import subprocess
|
|
6
6
|
import pandas as pd
|
|
7
7
|
|
|
8
8
|
from tricc_oo.models.lang import SingletonLangClass
|
|
@@ -24,24 +24,26 @@ logger = logging.getLogger("default")
|
|
|
24
24
|
|
|
25
25
|
class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
26
26
|
def process_export(self, start_pages, **kwargs):
|
|
27
|
-
diags = []
|
|
28
27
|
self.activity_export(start_pages[self.processes[0]], **kwargs)
|
|
29
28
|
# self.add_tab_breaks_choice()
|
|
30
|
-
cht_header = pd.DataFrame(columns=SURVEY_MAP.keys())
|
|
31
29
|
cht_input_df = self.get_cht_input(start_pages, **kwargs)
|
|
32
|
-
self.df_survey = self.df_survey[
|
|
33
|
-
~self.df_survey["name"].isin(cht_input_df["name"])
|
|
34
|
-
]
|
|
30
|
+
self.df_survey = self.df_survey[~self.df_survey["name"].isin(cht_input_df["name"])]
|
|
35
31
|
self.df_survey.reset_index(drop=True, inplace=True)
|
|
36
32
|
|
|
37
|
-
self.df_survey = pd.concat(
|
|
38
|
-
|
|
39
|
-
)
|
|
33
|
+
self.df_survey = pd.concat([cht_input_df, self.df_survey, self.get_cht_summary()], ignore_index=True)
|
|
34
|
+
|
|
35
|
+
self.inject_version()
|
|
36
|
+
|
|
37
|
+
def get_empty_label(self):
|
|
38
|
+
return "NO_LABEL"
|
|
40
39
|
|
|
41
40
|
def get_cht_input(self, start_pages, **kwargs):
|
|
42
41
|
empty = langs.get_trads("", force_dict=True)
|
|
43
42
|
df_input = pd.DataFrame(columns=SURVEY_MAP.keys())
|
|
44
|
-
# [ #type, '',#name ''#label, '',#hint '',#help '',#default '',#'appearance',
|
|
43
|
+
# [ #type, '',#name ''#label, '',#hint '',#help '',#default '',#'appearance',
|
|
44
|
+
# '',#'constraint', '',#'constraint_message' '',#'relevance' '',#'disabled'
|
|
45
|
+
# '',#'required' '',#'required message' '',#'read only' '',#'expression' '',#
|
|
46
|
+
# 'repeat_count' ''#'image' ],
|
|
45
47
|
df_input.loc[len(df_input)] = [
|
|
46
48
|
"begin_group",
|
|
47
49
|
"inputs",
|
|
@@ -61,6 +63,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
61
63
|
"",
|
|
62
64
|
"",
|
|
63
65
|
"",
|
|
66
|
+
"",
|
|
64
67
|
]
|
|
65
68
|
df_input.loc[len(df_input)] = [
|
|
66
69
|
"hidden",
|
|
@@ -81,6 +84,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
81
84
|
"",
|
|
82
85
|
"",
|
|
83
86
|
"",
|
|
87
|
+
"",
|
|
84
88
|
]
|
|
85
89
|
df_input.loc[len(df_input)] = [
|
|
86
90
|
"hidden",
|
|
@@ -101,6 +105,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
101
105
|
"",
|
|
102
106
|
"",
|
|
103
107
|
"",
|
|
108
|
+
"",
|
|
104
109
|
]
|
|
105
110
|
|
|
106
111
|
df_input.loc[len(df_input)] = [
|
|
@@ -122,6 +127,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
122
127
|
"",
|
|
123
128
|
"",
|
|
124
129
|
"",
|
|
130
|
+
"",
|
|
125
131
|
]
|
|
126
132
|
df_input.loc[len(df_input)] = [
|
|
127
133
|
"string",
|
|
@@ -142,6 +148,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
142
148
|
"",
|
|
143
149
|
"",
|
|
144
150
|
"",
|
|
151
|
+
"",
|
|
145
152
|
]
|
|
146
153
|
df_input.loc[len(df_input)] = [
|
|
147
154
|
"string",
|
|
@@ -162,6 +169,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
162
169
|
"",
|
|
163
170
|
"",
|
|
164
171
|
"",
|
|
172
|
+
"",
|
|
165
173
|
]
|
|
166
174
|
df_input.loc[len(df_input)] = [
|
|
167
175
|
"string",
|
|
@@ -182,6 +190,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
182
190
|
"",
|
|
183
191
|
"",
|
|
184
192
|
"",
|
|
193
|
+
"",
|
|
185
194
|
]
|
|
186
195
|
df_input.loc[len(df_input)] = [
|
|
187
196
|
"end_group",
|
|
@@ -202,6 +211,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
202
211
|
"",
|
|
203
212
|
"",
|
|
204
213
|
"",
|
|
214
|
+
"",
|
|
205
215
|
]
|
|
206
216
|
df_input.loc[len(df_input)] = [
|
|
207
217
|
"begin_group",
|
|
@@ -222,11 +232,12 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
222
232
|
"",
|
|
223
233
|
"",
|
|
224
234
|
"",
|
|
235
|
+
"",
|
|
225
236
|
]
|
|
226
237
|
inputs = self.export_inputs(start_pages[self.processes[0]], **kwargs)
|
|
227
238
|
for input in inputs:
|
|
228
239
|
df_input.loc[len(df_input)] = get_input_line(input)
|
|
229
|
-
self.get_contact_inputs(df_input)
|
|
240
|
+
self.get_contact_inputs(df_input)
|
|
230
241
|
df_input.loc[len(df_input)] = [
|
|
231
242
|
"hidden",
|
|
232
243
|
"external_id",
|
|
@@ -246,6 +257,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
246
257
|
"",
|
|
247
258
|
"",
|
|
248
259
|
"",
|
|
260
|
+
"",
|
|
249
261
|
]
|
|
250
262
|
|
|
251
263
|
df_input.loc[len(df_input)] = [
|
|
@@ -267,6 +279,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
267
279
|
"",
|
|
268
280
|
"",
|
|
269
281
|
"",
|
|
282
|
+
"",
|
|
270
283
|
]
|
|
271
284
|
|
|
272
285
|
df_input.loc[len(df_input)] = [
|
|
@@ -288,6 +301,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
288
301
|
"",
|
|
289
302
|
"",
|
|
290
303
|
"",
|
|
304
|
+
"",
|
|
291
305
|
]
|
|
292
306
|
|
|
293
307
|
df_input.loc[len(df_input)] = [
|
|
@@ -309,6 +323,29 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
309
323
|
"",
|
|
310
324
|
"",
|
|
311
325
|
"",
|
|
326
|
+
"",
|
|
327
|
+
]
|
|
328
|
+
|
|
329
|
+
df_input.loc[len(df_input)] = [
|
|
330
|
+
"hidden",
|
|
331
|
+
"data_load",
|
|
332
|
+
*list(langs.get_trads("NO_LABEL", force_dict=True).values()),
|
|
333
|
+
*list(empty.values()),
|
|
334
|
+
*list(empty.values()),
|
|
335
|
+
"",
|
|
336
|
+
"hidden",
|
|
337
|
+
"",
|
|
338
|
+
*list(empty.values()),
|
|
339
|
+
"",
|
|
340
|
+
"",
|
|
341
|
+
"",
|
|
342
|
+
*list(empty.values()),
|
|
343
|
+
"",
|
|
344
|
+
"",
|
|
345
|
+
"",
|
|
346
|
+
"",
|
|
347
|
+
"",
|
|
348
|
+
"",
|
|
312
349
|
]
|
|
313
350
|
self.get_contact_inputs_calculate(df_input)
|
|
314
351
|
df_input.loc[len(df_input)] = [
|
|
@@ -318,17 +355,18 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
318
355
|
*list(empty.values()), # hint
|
|
319
356
|
*list(empty.values()), # help
|
|
320
357
|
"", # default
|
|
321
|
-
"", #'appearance', clean_name
|
|
322
|
-
"", #'constraint',
|
|
323
|
-
*list(empty.values()), #'constraint_message'
|
|
324
|
-
"", #'relevance'
|
|
325
|
-
"", #'disabled'
|
|
326
|
-
"", #'required'
|
|
327
|
-
*list(empty.values()), #'required message'
|
|
328
|
-
"", #'read only'
|
|
329
|
-
"../inputs/user/contact_id", #'expression'
|
|
330
|
-
"",
|
|
331
|
-
"", #'
|
|
358
|
+
"", # 'appearance', clean_name
|
|
359
|
+
"", # 'constraint',
|
|
360
|
+
*list(empty.values()), # 'constraint_message'
|
|
361
|
+
"", # 'relevance'
|
|
362
|
+
"", # 'disabled'
|
|
363
|
+
"", # 'required'
|
|
364
|
+
*list(empty.values()), # 'required message'
|
|
365
|
+
"", # 'read only'
|
|
366
|
+
"../inputs/user/contact_id", # 'expression'
|
|
367
|
+
"",
|
|
368
|
+
"", # 'repeat_count'
|
|
369
|
+
"", # 'image'
|
|
332
370
|
"", # choice filter
|
|
333
371
|
]
|
|
334
372
|
df_input.loc[len(df_input)] = [
|
|
@@ -338,17 +376,18 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
338
376
|
*list(empty.values()), # hint
|
|
339
377
|
*list(empty.values()), # help
|
|
340
378
|
"", # default
|
|
341
|
-
"", #'appearance', clean_name
|
|
342
|
-
"", #'constraint',
|
|
343
|
-
*list(empty.values()), #'constraint_message'
|
|
344
|
-
"", #'relevance'
|
|
345
|
-
"", #'disabled'
|
|
346
|
-
"", #'required'
|
|
347
|
-
*list(empty.values()), #'required message'
|
|
348
|
-
"", #'read only'
|
|
349
|
-
"../inputs/user/facility_id", #'expression'
|
|
350
|
-
"",
|
|
351
|
-
"", #'
|
|
379
|
+
"", # 'appearance', clean_name
|
|
380
|
+
"", # 'constraint',
|
|
381
|
+
*list(empty.values()), # 'constraint_message'
|
|
382
|
+
"", # 'relevance'
|
|
383
|
+
"", # 'disabled'
|
|
384
|
+
"", # 'required'
|
|
385
|
+
*list(empty.values()), # 'required message'
|
|
386
|
+
"", # 'read only'
|
|
387
|
+
"../inputs/user/facility_id", # 'expression'
|
|
388
|
+
"",
|
|
389
|
+
"", # 'repeat_count'
|
|
390
|
+
"", # 'image'
|
|
352
391
|
"", # choice filter
|
|
353
392
|
]
|
|
354
393
|
df_input.loc[len(df_input)] = [
|
|
@@ -358,17 +397,18 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
358
397
|
*list(empty.values()), # hint
|
|
359
398
|
*list(empty.values()), # help
|
|
360
399
|
"", # default
|
|
361
|
-
"", #'appearance', clean_name
|
|
362
|
-
"", #'constraint',
|
|
363
|
-
*list(empty.values()), #'constraint_message'
|
|
364
|
-
"", #'relevance'
|
|
365
|
-
"", #'disabled'
|
|
366
|
-
"", #'required'
|
|
367
|
-
*list(empty.values()), #'required message'
|
|
368
|
-
"", #'read only'
|
|
369
|
-
"../inputs/user/name", #'expression'
|
|
370
|
-
"",
|
|
371
|
-
"", #'
|
|
400
|
+
"", # 'appearance', clean_name
|
|
401
|
+
"", # 'constraint',
|
|
402
|
+
*list(empty.values()), # 'constraint_message'
|
|
403
|
+
"", # 'relevance'
|
|
404
|
+
"", # 'disabled'
|
|
405
|
+
"", # 'required'
|
|
406
|
+
*list(empty.values()), # 'required message'
|
|
407
|
+
"", # 'read only'
|
|
408
|
+
"../inputs/user/name", # 'expression'
|
|
409
|
+
"",
|
|
410
|
+
"", # 'repeat_count'
|
|
411
|
+
"", # 'image'
|
|
372
412
|
"", # choice filter
|
|
373
413
|
]
|
|
374
414
|
df_input.loc[len(df_input)] = [
|
|
@@ -378,17 +418,18 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
378
418
|
*list(empty.values()), # hint
|
|
379
419
|
*list(empty.values()), # help
|
|
380
420
|
"", # default
|
|
381
|
-
"", #'appearance', clean_name
|
|
382
|
-
"", #'constraint',
|
|
383
|
-
*list(empty.values()), #'constraint_message'
|
|
384
|
-
"", #'relevance'
|
|
385
|
-
"", #'disabled'
|
|
386
|
-
"", #'required'
|
|
387
|
-
*list(empty.values()), #'required message'
|
|
388
|
-
"", #'read only'
|
|
389
|
-
"../inputs/contact/_id", #'expression'
|
|
390
|
-
"",
|
|
391
|
-
"", #'
|
|
421
|
+
"", # 'appearance', clean_name
|
|
422
|
+
"", # 'constraint',
|
|
423
|
+
*list(empty.values()), # 'constraint_message'
|
|
424
|
+
"", # 'relevance'
|
|
425
|
+
"", # 'disabled'
|
|
426
|
+
"", # 'required'
|
|
427
|
+
*list(empty.values()), # 'required message'
|
|
428
|
+
"", # 'read only'
|
|
429
|
+
"../inputs/contact/_id", # 'expression'
|
|
430
|
+
"",
|
|
431
|
+
"", # 'repeat_count'
|
|
432
|
+
"", # 'image'
|
|
392
433
|
"", # choice filter
|
|
393
434
|
]
|
|
394
435
|
|
|
@@ -399,17 +440,18 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
399
440
|
*list(empty.values()), # hint
|
|
400
441
|
*list(empty.values()), # help
|
|
401
442
|
"", # default
|
|
402
|
-
"", #'appearance', clean_name
|
|
403
|
-
"", #'constraint',
|
|
404
|
-
*list(empty.values()), #'constraint_message'
|
|
405
|
-
"", #'relevance'
|
|
406
|
-
"", #'disabled'
|
|
407
|
-
"", #'required'
|
|
408
|
-
*list(empty.values()), #'required message'
|
|
409
|
-
"", #'read only'
|
|
410
|
-
"../inputs/source_id", #'expression'
|
|
411
|
-
"",
|
|
412
|
-
"", #'
|
|
443
|
+
"", # 'appearance', clean_name
|
|
444
|
+
"", # 'constraint',
|
|
445
|
+
*list(empty.values()), # 'constraint_message'
|
|
446
|
+
"", # 'relevance'
|
|
447
|
+
"", # 'disabled'
|
|
448
|
+
"", # 'required'
|
|
449
|
+
*list(empty.values()), # 'required message'
|
|
450
|
+
"", # 'read only'
|
|
451
|
+
"../inputs/source_id", # 'expression'
|
|
452
|
+
"",
|
|
453
|
+
"", # 'repeat_count'
|
|
454
|
+
"", # 'image'
|
|
413
455
|
"", # choice filter
|
|
414
456
|
]
|
|
415
457
|
df_input.loc[len(df_input)] = [
|
|
@@ -419,39 +461,20 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
419
461
|
*list(empty.values()), # hint
|
|
420
462
|
*list(empty.values()), # help
|
|
421
463
|
"", # default
|
|
422
|
-
"", #'appearance', clean_name
|
|
423
|
-
"", #'constraint',
|
|
424
|
-
*list(empty.values()), #'constraint_message'
|
|
425
|
-
"", #'relevance'
|
|
426
|
-
"", #'disabled'
|
|
427
|
-
"", #'required'
|
|
428
|
-
*list(empty.values()), #'required message'
|
|
429
|
-
"", #'read only'
|
|
430
|
-
"../inputs/user/facility_id", #'expression'
|
|
431
|
-
"",
|
|
432
|
-
"", #'
|
|
464
|
+
"", # 'appearance', clean_name
|
|
465
|
+
"", # 'constraint',
|
|
466
|
+
*list(empty.values()), # 'constraint_message'
|
|
467
|
+
"", # 'relevance'
|
|
468
|
+
"", # 'disabled'
|
|
469
|
+
"", # 'required'
|
|
470
|
+
*list(empty.values()), # 'required message'
|
|
471
|
+
"", # 'read only'
|
|
472
|
+
"../inputs/user/facility_id", # 'expression'
|
|
473
|
+
"",
|
|
474
|
+
"", # 'repeat_count'
|
|
475
|
+
"", # 'image'
|
|
433
476
|
"", # choice filter
|
|
434
477
|
]
|
|
435
|
-
df_input.loc[len(df_input)] = [
|
|
436
|
-
"hidden",
|
|
437
|
-
"data_load",
|
|
438
|
-
*list(langs.get_trads("NO_LABEL", force_dict=True).values()),
|
|
439
|
-
*list(empty.values()),
|
|
440
|
-
*list(empty.values()),
|
|
441
|
-
"",
|
|
442
|
-
"hidden",
|
|
443
|
-
"",
|
|
444
|
-
*list(empty.values()),
|
|
445
|
-
"",
|
|
446
|
-
"",
|
|
447
|
-
"",
|
|
448
|
-
*list(empty.values()),
|
|
449
|
-
"",
|
|
450
|
-
"",
|
|
451
|
-
"",
|
|
452
|
-
"",
|
|
453
|
-
"",
|
|
454
|
-
]
|
|
455
478
|
|
|
456
479
|
for input in inputs:
|
|
457
480
|
df_input.loc[len(df_input)] = get_input_calc_line(input)
|
|
@@ -460,7 +483,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
460
483
|
|
|
461
484
|
def get_contact_inputs(self, df_input):
|
|
462
485
|
empty = langs.get_trads("", force_dict=True)
|
|
463
|
-
if not len(df_input[df_input[
|
|
486
|
+
if not len(df_input[df_input["name"] == "sex"]):
|
|
464
487
|
df_input.loc[len(df_input)] = [
|
|
465
488
|
"hidden",
|
|
466
489
|
"sex",
|
|
@@ -480,8 +503,9 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
480
503
|
"",
|
|
481
504
|
"",
|
|
482
505
|
"",
|
|
506
|
+
"",
|
|
483
507
|
]
|
|
484
|
-
if not len(df_input[df_input[
|
|
508
|
+
if not len(df_input[df_input["name"] == "date_of_birth"]):
|
|
485
509
|
df_input.loc[len(df_input)] = [
|
|
486
510
|
"hidden",
|
|
487
511
|
"date_of_birth",
|
|
@@ -501,11 +525,11 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
501
525
|
"",
|
|
502
526
|
"",
|
|
503
527
|
"",
|
|
528
|
+
"",
|
|
504
529
|
]
|
|
505
530
|
|
|
506
531
|
return df_input
|
|
507
532
|
|
|
508
|
-
|
|
509
533
|
def get_contact_inputs_calculate(self, df_input):
|
|
510
534
|
empty = langs.get_trads("", force_dict=True)
|
|
511
535
|
df_input.loc[len(df_input)] = [
|
|
@@ -527,6 +551,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
527
551
|
"",
|
|
528
552
|
"",
|
|
529
553
|
"",
|
|
554
|
+
"",
|
|
530
555
|
]
|
|
531
556
|
df_input.loc[len(df_input)] = [
|
|
532
557
|
"calculate",
|
|
@@ -547,18 +572,13 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
547
572
|
"",
|
|
548
573
|
"",
|
|
549
574
|
"",
|
|
575
|
+
"",
|
|
550
576
|
]
|
|
551
577
|
|
|
552
578
|
return df_input
|
|
553
579
|
|
|
554
580
|
def get_cht_summary(self):
|
|
555
581
|
df_summary = pd.DataFrame(columns=SURVEY_MAP.keys())
|
|
556
|
-
# [ #type, '',#name ''#label, '',#hint '',#help '',#default '',#'appearance', '',#'constraint', '',#'constraint_message' '',#'relevance' '',#'disabled' '',#'required' '',#'required message' '',#'read only' '',#'expression' '',#'repeat_count' ''#'image' ],
|
|
557
|
-
# df_summary.loc[len(df_summary)] = [ 'begin group', 'group_summary' , 'Summary', '', '', '', 'field-list summary', '', '', '', '', '', '', '', '', '', '' ]
|
|
558
|
-
# df_summary.loc[len(df_summary)] = [ 'note', 'r_patient_info', '**${patient_name}** ID: ${patient_id}', '', '', '', '', '', '', '', '', '', '', '', '', '', '' ]
|
|
559
|
-
# df_summary.loc[len(df_summary)] = [ 'note', 'r_followup', 'Follow Up <i class=“fa fa-flag”></i>', '', '', '', '', '', '','', '', '', '', '', '', '', '' ]
|
|
560
|
-
# df_summary.loc[len(df_summary)] = [ 'note', 'r_followup_note' ,'FOLLOWUP instruction', '', '', '', '', '', '', '','', '', '', '', '', '', '' ]
|
|
561
|
-
# df_summary.loc[len(df_summary)] = [ 'end group', '' ,'', '', '', '', '', '', '', '', '', '', '', '', '','', '' ]
|
|
562
582
|
return df_summary
|
|
563
583
|
|
|
564
584
|
def get_last_prev_index(self, df, e, depth=0):
|
|
@@ -573,7 +593,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
573
593
|
latest = index[-1]
|
|
574
594
|
if latest is None and depth > 5:
|
|
575
595
|
for p in e.prev_nodes:
|
|
576
|
-
index = get_last_prev_index(df, e, depth + 1)
|
|
596
|
+
index = self.get_last_prev_index(df, e, depth + 1)
|
|
577
597
|
if not latest and index and index > latest:
|
|
578
598
|
latest = index
|
|
579
599
|
return latest
|
|
@@ -597,6 +617,9 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
597
617
|
newpath = os.path.join(self.output_path, newfilename)
|
|
598
618
|
media_path = os.path.join(self.output_path, form_id + "-media")
|
|
599
619
|
|
|
620
|
+
# Track all generated XLS files for validation
|
|
621
|
+
generated_files = [newpath]
|
|
622
|
+
|
|
600
623
|
settings = {
|
|
601
624
|
"form_title": title,
|
|
602
625
|
"form_id": form_id,
|
|
@@ -606,10 +629,6 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
606
629
|
}
|
|
607
630
|
df_settings = pd.DataFrame(settings, index=indx)
|
|
608
631
|
df_settings.head()
|
|
609
|
-
if len(self.df_survey[self.df_survey["name"] == "version"]):
|
|
610
|
-
self.df_survey.loc[self.df_survey["name"] == "version", "label"] = (
|
|
611
|
-
f"v{version}"
|
|
612
|
-
)
|
|
613
632
|
# create a Pandas Excel writer using XlsxWriter as the engine
|
|
614
633
|
writer = pd.ExcelWriter(newpath, engine="xlsxwriter")
|
|
615
634
|
self.df_survey.to_excel(writer, sheet_name="survey", index=False)
|
|
@@ -621,8 +640,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
621
640
|
for p in self.project.pages.values():
|
|
622
641
|
p_ends = list(
|
|
623
642
|
filter(
|
|
624
|
-
lambda x: issubclass(x.__class__, TriccNodeEnd)
|
|
625
|
-
and getattr(x, "process", "") == "pause",
|
|
643
|
+
lambda x: issubclass(x.__class__, TriccNodeEnd) and getattr(x, "process", "") == "pause",
|
|
626
644
|
p.nodes.values(),
|
|
627
645
|
)
|
|
628
646
|
)
|
|
@@ -640,14 +658,13 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
640
658
|
)
|
|
641
659
|
)
|
|
642
660
|
else:
|
|
643
|
-
logger.critical(
|
|
644
|
-
f"impossible to get last index before pause: {e.get_name()}"
|
|
645
|
-
)
|
|
661
|
+
logger.critical(f"impossible to get last index before pause: {e.get_name()}")
|
|
646
662
|
forms = [form_id]
|
|
647
663
|
for i, e in ends_prev:
|
|
648
664
|
new_form_id = f"{form_id}_{clean_name(e.name)}"
|
|
649
665
|
newfilename = f"{new_form_id}.xlsx"
|
|
650
666
|
newpath = os.path.join(self.output_path, newfilename)
|
|
667
|
+
generated_files.append(newpath) # Track additional XLS files
|
|
651
668
|
settings = {
|
|
652
669
|
"form_title": title,
|
|
653
670
|
"form_id": f"{new_form_id}",
|
|
@@ -657,9 +674,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
657
674
|
}
|
|
658
675
|
df_settings = pd.DataFrame(settings, index=indx)
|
|
659
676
|
df_settings.head()
|
|
660
|
-
task_df, hidden_names = make_breakpoints(
|
|
661
|
-
self.df_survey, i, e.name, replace_dots=True
|
|
662
|
-
)
|
|
677
|
+
task_df, hidden_names = make_breakpoints(self.df_survey, i, e.name, replace_dots=True)
|
|
663
678
|
# deactivate the end node
|
|
664
679
|
task_df.loc[task_df["name"] == get_export_name(e), "calculation"] = 0
|
|
665
680
|
# print fileds
|
|
@@ -688,9 +703,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
688
703
|
|
|
689
704
|
media_path_tmp = os.path.join(self.output_path, "media-tmp")
|
|
690
705
|
if os.path.isdir(media_path_tmp):
|
|
691
|
-
if os.path.isdir(
|
|
692
|
-
media_path
|
|
693
|
-
): # check if it exists, because if it does, error will be raised
|
|
706
|
+
if os.path.isdir(media_path): # check if it exists, because if it does, error will be raised
|
|
694
707
|
shutil.rmtree(media_path)
|
|
695
708
|
# (later change to make folder complaint to CHT)
|
|
696
709
|
os.mkdir(media_path)
|
|
@@ -700,19 +713,133 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
|
|
|
700
713
|
shutil.move(os.path.join(media_path_tmp, file_name), media_path)
|
|
701
714
|
shutil.rmtree(media_path_tmp)
|
|
702
715
|
|
|
716
|
+
return generated_files
|
|
717
|
+
|
|
718
|
+
def execute(self):
|
|
719
|
+
"""Override execute to handle multiple output files from CHT strategy."""
|
|
720
|
+
version = datetime.datetime.now().strftime("%Y%m%d%H%M")
|
|
721
|
+
logger.info(f"build version: {version}")
|
|
722
|
+
if "main" in self.project.start_pages:
|
|
723
|
+
self.process_base(self.project.start_pages, pages=self.project.pages, version=version)
|
|
724
|
+
else:
|
|
725
|
+
logger.critical("Main process required")
|
|
726
|
+
|
|
727
|
+
logger.info("generate the relevance based on edges")
|
|
728
|
+
|
|
729
|
+
# create relevance Expression
|
|
730
|
+
|
|
731
|
+
# create calculate Expression
|
|
732
|
+
self.process_calculate(self.project.start_pages, pages=self.project.pages)
|
|
733
|
+
logger.info("generate the export format")
|
|
734
|
+
# create calculate Expression
|
|
735
|
+
self.process_export(self.project.start_pages, pages=self.project.pages)
|
|
736
|
+
|
|
737
|
+
logger.info("print the export")
|
|
738
|
+
|
|
739
|
+
# Export returns list of generated files for CHT strategy
|
|
740
|
+
generated_files = self.export(self.project.start_pages, version=version)
|
|
741
|
+
|
|
742
|
+
logger.info("validate the output")
|
|
743
|
+
self.validate(generated_files)
|
|
744
|
+
|
|
745
|
+
def validate(self, generated_files=None):
|
|
746
|
+
"""Validate the generated XLS form(s) using xls2xform-medic."""
|
|
747
|
+
if generated_files is None:
|
|
748
|
+
# Fallback for single file validation
|
|
749
|
+
if self.project.start_pages["main"].root.form_id is not None:
|
|
750
|
+
form_id = str(self.project.start_pages["main"].root.form_id)
|
|
751
|
+
generated_files = [os.path.join(self.output_path, form_id + ".xlsx")]
|
|
752
|
+
else:
|
|
753
|
+
logger.error("Form ID not found for validation")
|
|
754
|
+
return False
|
|
755
|
+
|
|
756
|
+
# Ensure xls2xform-medic is available
|
|
757
|
+
medic_tool = self._ensure_xls2xform_medic()
|
|
758
|
+
if not medic_tool:
|
|
759
|
+
logger.error("xls2xform-medic tool not available, skipping CHT validation")
|
|
760
|
+
return False
|
|
761
|
+
|
|
762
|
+
all_valid = True
|
|
763
|
+
for xls_file in generated_files:
|
|
764
|
+
if not os.path.exists(xls_file):
|
|
765
|
+
logger.error(f"XLS file not found: {xls_file}")
|
|
766
|
+
all_valid = False
|
|
767
|
+
continue
|
|
768
|
+
|
|
769
|
+
try:
|
|
770
|
+
# Run xls2xform-medic validation
|
|
771
|
+
result = subprocess.run(
|
|
772
|
+
[medic_tool, xls_file],
|
|
773
|
+
capture_output=True,
|
|
774
|
+
text=True,
|
|
775
|
+
cwd=self.output_path
|
|
776
|
+
)
|
|
777
|
+
|
|
778
|
+
if result.returncode == 0:
|
|
779
|
+
logger.info(f"CHT XLSForm validation successful: {os.path.basename(xls_file)}")
|
|
780
|
+
else:
|
|
781
|
+
logger.error(f"CHT XLSForm validation failed for {os.path.basename(xls_file)}: {result.stderr}")
|
|
782
|
+
all_valid = False
|
|
783
|
+
|
|
784
|
+
except Exception as e:
|
|
785
|
+
logger.error(f"CHT XLSForm validation error for {os.path.basename(xls_file)}: {str(e)}")
|
|
786
|
+
all_valid = False
|
|
787
|
+
|
|
788
|
+
return all_valid
|
|
789
|
+
|
|
790
|
+
def _ensure_xls2xform_medic(self):
|
|
791
|
+
"""Ensure xls2xform-medic tool is available."""
|
|
792
|
+
# Check if it's in PATH
|
|
793
|
+
medic_tool = shutil.which("xls2xform-medic")
|
|
794
|
+
if medic_tool:
|
|
795
|
+
return medic_tool
|
|
796
|
+
|
|
797
|
+
# Check if we need to download it
|
|
798
|
+
medic_path = os.path.join(os.path.dirname(__file__), "xls2xform-medic")
|
|
799
|
+
if os.path.exists(medic_path):
|
|
800
|
+
return medic_path
|
|
801
|
+
|
|
802
|
+
# Try to download from the provided URL
|
|
803
|
+
try:
|
|
804
|
+
import urllib.request
|
|
805
|
+
medic_url = "https://github.com/medic/pyxform/releases/download/v4.0.0-medic/xls2xform-medic"
|
|
806
|
+
logger.info(f"Downloading xls2xform-medic from {medic_url}")
|
|
807
|
+
urllib.request.urlretrieve(medic_url, medic_path)
|
|
808
|
+
# Make executable
|
|
809
|
+
os.chmod(medic_path, 0o755)
|
|
810
|
+
return medic_path
|
|
811
|
+
except Exception as e:
|
|
812
|
+
logger.error(f"Failed to download xls2xform-medic: {str(e)}")
|
|
813
|
+
return None
|
|
814
|
+
|
|
703
815
|
def tricc_operation_zscore(self, ref_expressions):
|
|
704
816
|
y, ll, m, s = self.get_zscore_params(ref_expressions)
|
|
705
817
|
# return ((Math.pow((y / m), l) - 1) / (s * l));
|
|
706
|
-
return f"cht:extension-lib('{
|
|
818
|
+
return f"""cht:extension-lib('{
|
|
819
|
+
ref_expressions[0][1:-1]
|
|
820
|
+
}.js',{
|
|
821
|
+
self.clean_coalesce(ref_expressions[1])
|
|
822
|
+
} ,{
|
|
823
|
+
self.clean_coalesce(ref_expressions[2])
|
|
824
|
+
} ,{
|
|
825
|
+
self.clean_coalesce(ref_expressions[3])
|
|
826
|
+
})"""
|
|
707
827
|
|
|
708
828
|
def tricc_operation_izscore(self, ref_expressions):
|
|
709
829
|
z, ll, m, s = self.get_zscore_params(ref_expressions)
|
|
710
830
|
# return (m * (z*s*l-1)^(1/l));
|
|
711
|
-
return f"cht:extension-lib('{
|
|
831
|
+
return f"""cht:extension-lib('{
|
|
832
|
+
ref_expressions[0][1:-1]
|
|
833
|
+
}.js',{
|
|
834
|
+
self.clean_coalesce(ref_expressions[1])
|
|
835
|
+
} ,{
|
|
836
|
+
self.clean_coalesce(ref_expressions[2])
|
|
837
|
+
} ,{
|
|
838
|
+
self.clean_coalesce(ref_expressions[3])
|
|
839
|
+
}, true)"""
|
|
712
840
|
|
|
713
841
|
def tricc_operation_drug_dosage(self, ref_expressions):
|
|
714
842
|
# drug name
|
|
715
843
|
# age
|
|
716
844
|
# weight
|
|
717
845
|
return f"cht:extension-lib('drugs.js',{','.join(map(self.clean_coalesce, ref_expressions))})"
|
|
718
|
-
|