tricc-oo 1.6.25__py3-none-any.whl → 1.7.0.dev1__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.
@@ -8,7 +8,6 @@ import logging
8
8
  import os
9
9
  import re
10
10
  import pandas as pd
11
- from pyxform import create_survey_from_xls
12
11
 
13
12
  from tricc_oo.converters.utils import clean_name
14
13
  from tricc_oo.models.base import (
@@ -19,16 +18,14 @@ from tricc_oo.models.ordered_set import OrderedSet
19
18
  from tricc_oo.models.calculate import (
20
19
  TriccNodeEnd,
21
20
  TriccNodeDisplayCalculateBase,
22
- TriccNodeActivityStart,
21
+
23
22
  )
24
23
  from tricc_oo.models.tricc import (
25
24
  TriccNodeCalculateBase,
26
25
  TriccNodeBaseModel,
27
26
  TriccNodeSelectOption,
28
- TriccNodeSelect,
29
27
  TriccNodeInputModel,
30
28
  TriccNodeDisplayModel,
31
- TriccNodeMainStart,
32
29
  TRICC_FALSE_VALUE,
33
30
  TRICC_TRUE_VALUE,
34
31
  )
@@ -51,8 +48,6 @@ from tricc_oo.serializers.xls_form import (
51
48
  SURVEY_MAP,
52
49
  end_group,
53
50
  generate_xls_form_export,
54
- get_export_group_name,
55
- get_export_group_required,
56
51
  start_group,
57
52
  )
58
53
  from tricc_oo.strategies.output.base_output_strategy import BaseOutPutStrategy
@@ -91,8 +86,6 @@ OPERATOR_COALESCE_FALLBACK = {
91
86
  TriccOperator.MORE_OR_EQUAL: -2147483648,
92
87
  TriccOperator.LESS: 2147483647,
93
88
  TriccOperator.LESS_OR_EQUAL: 2147483647,
94
- TriccOperator.CONTAINS: "''",
95
- TriccOperator.SELECTED: "''",
96
89
  }
97
90
 
98
91
 
@@ -380,14 +373,12 @@ class XLSFormStrategy(BaseOutPutStrategy):
380
373
 
381
374
  def get_tricc_operation_expression(self, operation):
382
375
  ref_expressions = []
383
- original_references = []
384
376
  if not hasattr(operation, "reference"):
385
377
  return self.get_tricc_operation_operand(operation)
386
378
 
387
379
  operator = getattr(operation, "operator", "")
388
380
  coalesce_fallback = OPERATOR_COALESCE_FALLBACK[operator] if operator in OPERATOR_COALESCE_FALLBACK else "''"
389
381
  for r in operation.reference:
390
- original_references.append(r)
391
382
  if isinstance(r, list):
392
383
  r_expr = [
393
384
  (
@@ -408,43 +399,43 @@ class XLSFormStrategy(BaseOutPutStrategy):
408
399
  # build lower level
409
400
  if hasattr(self, f"tricc_operation_{operation.operator}"):
410
401
  callable = getattr(self, f"tricc_operation_{operation.operator}")
411
- return callable(ref_expressions, original_references)
402
+ return callable(ref_expressions)
412
403
  else:
413
404
  raise NotImplementedError(
414
405
  f"This type of opreation '{operation.operator}' is not supported in this strategy"
415
406
  )
416
407
 
417
- def tricc_operation_count(self, ref_expressions, original_references=None):
408
+ def tricc_operation_count(self, ref_expressions):
418
409
  return f"count-selected({self.clean_coalesce(ref_expressions[0])})"
419
410
 
420
- def tricc_operation_multiplied(self, ref_expressions, original_references=None):
421
- return "*".join(map(str, ref_expressions))
411
+ def tricc_operation_multiplied(self, ref_expressions):
412
+ return "*".join(map(str,ref_expressions))
422
413
 
423
- def tricc_operation_divided(self, ref_expressions, original_references=None):
414
+ def tricc_operation_divided(self, ref_expressions):
424
415
  return f"{ref_expressions[0]} div {ref_expressions[1]}"
425
416
 
426
- def tricc_operation_modulo(self, ref_expressions, original_references=None):
417
+ def tricc_operation_modulo(self, ref_expressions):
427
418
  return f"{ref_expressions[0]} mod {ref_expressions[1]}"
428
419
 
429
- def tricc_operation_coalesce(self, ref_expressions, original_references=None):
420
+ def tricc_operation_coalesce(self, ref_expressions):
430
421
  return f"coalesce({','.join(map(self.clean_coalesce, ref_expressions))})"
431
422
 
432
- def tricc_operation_module(self, ref_expressions, original_references=None):
423
+ def tricc_operation_module(self, ref_expressions):
433
424
  return f"{ref_expressions[0]} mod {ref_expressions[1]}"
434
425
 
435
- def tricc_operation_minus(self, ref_expressions, original_references=None):
426
+ def tricc_operation_minus(self, ref_expressions):
436
427
  if len(ref_expressions) > 1:
437
428
  return " - ".join(map(str, ref_expressions))
438
429
  elif len(ref_expressions) == 1:
439
430
  return f"-{ref_expressions[0]}"
440
431
 
441
- def tricc_operation_plus(self, ref_expressions, original_references=None):
442
- return " + ".join(map(str, ref_expressions))
432
+ def tricc_operation_plus(self, ref_expressions):
433
+ return " + ".join(map(str,ref_expressions))
443
434
 
444
- def tricc_operation_not(self, ref_expressions, original_references=None):
435
+ def tricc_operation_not(self, ref_expressions):
445
436
  return f"not({ref_expressions[0]})"
446
437
 
447
- def tricc_operation_and(self, ref_expressions, original_references=None):
438
+ def tricc_operation_and(self, ref_expressions):
448
439
  if len(ref_expressions) == 1:
449
440
  return ref_expressions[0]
450
441
  if len(ref_expressions) > 1:
@@ -456,7 +447,7 @@ class XLSFormStrategy(BaseOutPutStrategy):
456
447
  else:
457
448
  return "1"
458
449
 
459
- def tricc_operation_or(self, ref_expressions, original_references=None):
450
+ def tricc_operation_or(self, ref_expressions):
460
451
  if len(ref_expressions) == 1:
461
452
  return ref_expressions[0]
462
453
  if len(ref_expressions) > 1:
@@ -468,7 +459,7 @@ class XLSFormStrategy(BaseOutPutStrategy):
468
459
  else:
469
460
  return "1"
470
461
 
471
- def tricc_operation_native(self, ref_expressions, original_references=None):
462
+ def tricc_operation_native(self, ref_expressions):
472
463
 
473
464
  if len(ref_expressions) > 0:
474
465
  if ref_expressions[0].startswith(("'", "`",)):
@@ -483,82 +474,77 @@ class XLSFormStrategy(BaseOutPutStrategy):
483
474
  return "0"
484
475
  # return f"jr:choice-name({','.join(ref_expressions[1:])})"
485
476
  else:
486
- return f"{ref_expressions[0]}({','.join(map(str, ref_expressions[1:]))})"
477
+ return f"{ref_expressions[0]}({','.join(map(str,ref_expressions[1:]))})"
487
478
 
488
- def tricc_operation_istrue(self, ref_expressions, original_references=None):
479
+ def tricc_operation_istrue(self, ref_expressions):
489
480
  if str(BOOLEAN_MAP[str(TRICC_TRUE_VALUE)]).isnumeric():
490
481
  return f"{ref_expressions[0]}>={BOOLEAN_MAP[str(TRICC_TRUE_VALUE)]}"
491
482
  else:
492
483
  return f"{ref_expressions[0]}={BOOLEAN_MAP[str(TRICC_TRUE_VALUE)]}"
493
484
 
494
- def tricc_operation_isfalse(self, ref_expressions, original_references=None):
485
+ def tricc_operation_isfalse(self, ref_expressions):
495
486
  if str(BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]).isnumeric():
496
487
  return f"{ref_expressions[0]}={BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]}"
497
488
  else:
498
489
  return f"{ref_expressions[0]}={BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]}"
499
490
 
500
- def tricc_operation_parenthesis(self, ref_expressions, original_references=None):
491
+ def tricc_operation_parenthesis(self, ref_expressions):
501
492
  return f"({ref_expressions[0]})"
502
493
 
503
- def tricc_operation_selected(self, ref_expressions, original_references=None):
494
+ def tricc_operation_selected(self, ref_expressions):
504
495
  parts = []
505
496
  for s in ref_expressions[1:]:
506
497
  # for option with numeric value
507
- if isinstance(s, str):
508
- cleaned_s = s
509
- elif isinstance(s, TriccNodeSelectOption):
510
- cleaned_s = s.name
511
- else:
512
- cleaned_s = "'" + str(s) + "'"
498
+ cleaned_s = s if isinstance(s, str) else "'" + str(s) + "'"
513
499
  parts.append(f"selected({self.clean_coalesce(ref_expressions[0])}, {cleaned_s})")
514
500
  if len(parts) == 1:
515
501
  return parts[0]
516
502
  else:
517
503
  return self.tricc_operation_or(parts)
518
504
 
519
- def tricc_operation_more_or_equal(self, ref_expressions, original_references=None):
505
+ def tricc_operation_more_or_equal(self, ref_expressions):
520
506
  return f"{ref_expressions[0]}>={ref_expressions[1]}"
521
507
 
522
- def tricc_operation_less_or_equal(self, ref_expressions, original_references=None):
508
+ def tricc_operation_less_or_equal(self, ref_expressions):
523
509
  return f"{ref_expressions[0]}<={ref_expressions[1]}"
524
510
 
525
- def tricc_operation_more(self, ref_expressions, original_references=None):
511
+ def tricc_operation_more(self, ref_expressions):
526
512
  return f"{ref_expressions[0]}>{ref_expressions[1]}"
527
513
 
528
- def tricc_operation_less(self, ref_expressions, original_references=None):
514
+ def tricc_operation_less(self, ref_expressions):
529
515
  return f"{ref_expressions[0]}<{ref_expressions[1]}"
530
516
 
531
- def tricc_operation_between(self, ref_expressions, original_references=None):
517
+ def tricc_operation_between(self, ref_expressions):
532
518
  return f"{ref_expressions[0]}>={ref_expressions[1]} and {ref_expressions[0]} < {ref_expressions[2]}"
533
519
 
534
- def tricc_operation_equal(self, ref_expressions, original_references=None):
520
+ def tricc_operation_equal(self, ref_expressions):
535
521
  return f"{ref_expressions[0]}={ref_expressions[1]}"
536
522
 
537
- def tricc_operation_not_equal(self, ref_expressions, original_references=None):
523
+ def tricc_operation_not_equal(self, ref_expressions):
538
524
  return f"{ref_expressions[0]}!={ref_expressions[1]}"
539
525
 
540
- def tricc_operation_isnull(self, ref_expressions, original_references=None):
526
+ def tricc_operation_isnull(self, ref_expressions):
541
527
  return f"{ref_expressions[0]}=''"
542
528
 
543
- def tricc_operation_isnotnull(self, ref_expressions, original_references=None):
529
+ def tricc_operation_isnotnull(self, ref_expressions):
544
530
  return f"{ref_expressions[0]}!=''"
545
531
 
546
- def tricc_operation_isnottrue(self, ref_expressions, original_references=None):
532
+ def tricc_operation_isnottrue(self, ref_expressions):
547
533
  if str(BOOLEAN_MAP[str(TRICC_TRUE_VALUE)]).isnumeric():
548
534
  return f"{ref_expressions[0]}<{BOOLEAN_MAP[str(TRICC_TRUE_VALUE)]}"
549
535
  else:
550
536
  return f"{ref_expressions[0]}!={BOOLEAN_MAP[str(TRICC_TRUE_VALUE)]}"
551
537
 
552
- def tricc_operation_isnotfalse(self, ref_expressions, original_references=None):
538
+ def tricc_operation_isnotfalse(self, ref_expressions):
553
539
  if str(BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]).isnumeric():
554
540
  return f"{ref_expressions[0]}>{BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]}"
555
541
  else:
556
542
  return f"{ref_expressions[0]}!={BOOLEAN_MAP[str(TRICC_FALSE_VALUE)]}"
557
543
 
558
- def tricc_operation_notexist(self, ref_expressions, original_references=None):
544
+ def tricc_operation_notexist(self, ref_expressions):
559
545
  return f"{ref_expressions[0]}=''"
560
546
 
561
- def tricc_operation_case(self, ref_expressions, original_references=None):
547
+ def tricc_operation_case(self, ref_expressions):
562
548
  ifs = 0
563
549
  parts = []
564
550
  else_found = False
@@ -581,7 +567,7 @@ class XLSFormStrategy(BaseOutPutStrategy):
581
567
  exp += ")"
582
568
  return exp
583
569
 
584
- def tricc_operation_ifs(self, ref_expressions, original_references=None):
570
+ def tricc_operation_ifs(self, ref_expressions):
585
571
  ifs = 0
586
572
  parts = []
587
573
  else_found = False
@@ -606,19 +592,19 @@ class XLSFormStrategy(BaseOutPutStrategy):
606
592
  def get_empty_label(self):
607
593
  return "."
608
594
 
609
- def tricc_operation_if(self, ref_expressions, original_references=None):
595
+ def tricc_operation_if(self, ref_expressions):
610
596
  return f"if({ref_expressions[0]},{ref_expressions[1]},{ref_expressions[2]})"
611
597
 
612
- def tricc_operation_contains(self, ref_expressions, original_references=None):
598
+ def tricc_operation_contains(self, ref_expressions):
613
599
  return f"contains({self.clean_coalesce(ref_expressions[0])}, {self.clean_coalesce(ref_expressions[1])})"
614
600
 
615
- def tricc_operation_exists(self, ref_expressions, original_references=None):
601
+ def tricc_operation_exists(self, ref_expressions):
616
602
  parts = []
617
603
  for ref in ref_expressions:
618
604
  parts.append(self.tricc_operation_not_equal([self.tricc_operation_coalesce([ref, "''"]), "''"]))
619
605
  return self.tricc_operation_and(parts)
620
606
 
621
- def tricc_operation_cast_number(self, ref_expressions, original_references=None):
607
+ def tricc_operation_cast_number(self, ref_expressions):
622
608
  if isinstance(
623
609
  ref_expressions[0],
624
610
  (
@@ -645,7 +631,7 @@ class XLSFormStrategy(BaseOutPutStrategy):
645
631
  else:
646
632
  return f"number({ref_expressions[0]})"
647
633
 
648
- def tricc_operation_cast_integer(self, ref_expressions, original_references=None):
634
+ def tricc_operation_cast_integer(self, ref_expressions):
649
635
  if isinstance(
650
636
  ref_expressions[0],
651
637
  (
@@ -672,18 +658,18 @@ class XLSFormStrategy(BaseOutPutStrategy):
672
658
  else:
673
659
  return f"int({ref_expressions[0]})"
674
660
 
675
- def tricc_operation_zscore(self, ref_expressions, original_references=None):
661
+ def tricc_operation_zscore(self, ref_expressions):
676
662
  y, ll, m, s = self.get_zscore_params(ref_expressions)
677
663
  # return ((Math.pow((y / m), l) - 1) / (s * l));
678
664
  return f"(pow({y} div ({m}), {ll}) -1) div (({s}) div ({ll}))"
679
665
 
680
- def tricc_operation_datetime_to_decimal(self, ref_expressions, original_references=None):
666
+ def tricc_operation_datetime_to_decimal(self, ref_expressions):
681
667
  return f"decimal-date-time({ref_expressions[0]})"
682
668
 
683
- def tricc_operation_round(self, ref_expressions, original_references=None):
669
+ def tricc_operation_round(self, ref_expressions):
684
670
  return f"round({ref_expressions[0]})"
685
671
 
686
- def tricc_operation_izscore(self, ref_expressions, original_references=None):
672
+ def tricc_operation_izscore(self, ref_expressions):
687
673
  z, ll, m, s = self.get_zscore_params(ref_expressions)
688
674
  # return (m * (z*s*l-1)^(1/l));
689
675
  return f"pow({m} * ({z} * {s} * {ll} -1), 1 div {ll})"
@@ -702,7 +688,6 @@ class XLSFormStrategy(BaseOutPutStrategy):
702
688
  # @param left part
703
689
  # @param right part
704
690
  def generate_xls_form_calculate(self, node, processed_nodes, stashed_nodes, calculates, **kwargs):
705
- self.codesystems = kwargs.get("codesystems", {})
706
691
  if is_ready_to_process(node, processed_nodes, strict=False) and process_reference(
707
692
  node,
708
693
  processed_nodes,
@@ -739,89 +724,20 @@ class XLSFormStrategy(BaseOutPutStrategy):
739
724
  # @param r reference to be translated
740
725
  if isinstance(r, TriccOperation):
741
726
  return self.get_tricc_operation_expression(r)
742
- elif isinstance(r, (TriccStatic, str, int, float)):
743
- return get_export_name(r)
744
727
  elif isinstance(r, TriccReference):
745
728
  logger.warning(f"reference `{r.value}` still used in a calculate")
746
729
  return f"${{{get_export_name(r.value)}}}"
747
-
730
+ elif isinstance(r, (TriccStatic, str, int, float)):
731
+ return get_export_name(r)
748
732
  elif isinstance(r, TriccNodeSelectOption):
749
733
  logger.debug(f"select option {r.get_name()} from {r.select.get_name()} was used as a reference")
750
734
  return get_export_name(r)
751
- elif isinstance(r, TriccNodeActivityStart):
752
- if get_export_group_required(r.activity):
753
- return f"${{{get_export_group_name(r.activity)}}}"
754
- else:
755
- return f"({self.get_tricc_operation_expression(r.relevance)})"
756
- elif isinstance(r, TriccNodeMainStart):
757
- return "1"
758
- elif issubclass(r.__class__, (TriccNodeInputModel, TriccNodeSelect)):
735
+ elif issubclass(r.__class__, TriccNodeInputModel):
759
736
  return f"coalesce(${{{get_export_name(r)}}},{coalesce_fallback})"
760
737
  elif issubclass(r.__class__, TriccNodeBaseModel):
761
738
  return f"${{{get_export_name(r)}}}"
762
739
  else:
763
740
  raise NotImplementedError(f"This type of node {r.__class__} is not supported within an operation")
764
741
 
765
- def tricc_operation_concatenate(self, ref_expressions, original_references=None):
742
+ def tricc_operation_concatenate(self, ref_expressions):
766
743
  return f"concat({','.join(map(str, ref_expressions))})"
767
-
768
- def tricc_operation_diagnosis_list(self, ref_expressions, original_references=None):
769
- from tricc_oo.converters.datadictionnary import lookup_codesystems_code
770
-
771
- parts = []
772
- for i, orig_ref in enumerate(original_references):
773
- expr = ref_expressions[i] if ref_expressions and i < len(ref_expressions) else None
774
-
775
- code = None
776
- # Use only original references for code lookup
777
- if isinstance(orig_ref, TriccReference):
778
- code = orig_ref.value
779
- elif issubclass(type(orig_ref), TriccNodeBaseModel):
780
- code = orig_ref.name
781
- else:
782
- logger.critical(f"Unexpected reference type: {type(orig_ref)}, value: {orig_ref}")
783
- exit(1)
784
-
785
- concept = lookup_codesystems_code(self.project.code_systems, code)
786
- if concept:
787
- display = getattr(concept, 'display', code)
788
- else:
789
- logger.warning(f"Diagnosis code '{code}' not found in codesystems")
790
- display = code
791
-
792
- # Always include comma after diagnosis name
793
- parts.append(f"if({expr} = 1, '{display},', '')")
794
-
795
- if parts:
796
- return f"concat({','.join(parts)})"
797
- return "''"
798
-
799
- def validate(self):
800
- """Validate the generated XLS form using pyxform."""
801
- try:
802
- # Determine the XLS file path
803
- if self.project.start_pages["main"].root.form_id is not None:
804
- form_id = str(self.project.start_pages["main"].root.form_id)
805
- xls_path = os.path.join(self.output_path, form_id + ".xlsx")
806
-
807
- if not os.path.exists(xls_path):
808
- logger.error(f"XLS file not found: {xls_path}")
809
- return False
810
-
811
- # Validate using pyxform
812
- survey = create_survey_from_xls(xls_path)
813
- xml_output = survey.to_xml()
814
-
815
- # Check if XML was generated successfully
816
- if xml_output and len(xml_output.strip()) > 0:
817
- logger.info("XLSForm validation successful")
818
- return True
819
- else:
820
- logger.error("XLSForm validation failed: Empty XML output")
821
- return False
822
- else:
823
- logger.error("Form ID not found for validation")
824
- return False
825
- except Exception as e:
826
- logger.error(f"XLSForm validation failed: {str(e)}")
827
- return False
@@ -2,13 +2,8 @@ import datetime
2
2
  import logging
3
3
  import os
4
4
  import shutil
5
- import subprocess
6
- import tempfile
7
- import zipfile
8
5
  import pandas as pd
9
6
 
10
- from pyxform.xls2xform import convert
11
-
12
7
  from tricc_oo.models.lang import SingletonLangClass
13
8
  from tricc_oo.models.calculate import TriccNodeEnd
14
9
  from tricc_oo.models.tricc import TriccNodeDisplayModel
@@ -621,9 +616,6 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
621
616
  newpath = os.path.join(self.output_path, newfilename)
622
617
  media_path = os.path.join(self.output_path, form_id + "-media")
623
618
 
624
- # Track all generated XLS files for validation
625
- generated_files = [newpath]
626
-
627
619
  settings = {
628
620
  "form_title": title,
629
621
  "form_id": form_id,
@@ -640,7 +632,6 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
640
632
  df_settings.to_excel(writer, sheet_name="settings", index=False)
641
633
  writer.close()
642
634
  # pause
643
- logger.info("generating the task and after pause questionnaires")
644
635
  ends = []
645
636
  for p in self.project.pages.values():
646
637
  p_ends = list(
@@ -669,7 +660,6 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
669
660
  new_form_id = f"{form_id}_{clean_name(e.name)}"
670
661
  newfilename = f"{new_form_id}.xlsx"
671
662
  newpath = os.path.join(self.output_path, newfilename)
672
- generated_files.append(newpath) # Track additional XLS files
673
663
  settings = {
674
664
  "form_title": title,
675
665
  "form_id": f"{new_form_id}",
@@ -718,122 +708,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
718
708
  shutil.move(os.path.join(media_path_tmp, file_name), media_path)
719
709
  shutil.rmtree(media_path_tmp)
720
710
 
721
- return generated_files
722
-
723
- def execute(self):
724
- """Override execute to handle multiple output files from CHT strategy."""
725
- version = datetime.datetime.now().strftime("%Y%m%d%H%M")
726
- logger.info(f"build version: {version}")
727
- if "main" in self.project.start_pages:
728
- self.process_base(self.project.start_pages, pages=self.project.pages, version=version)
729
- else:
730
- logger.critical("Main process required")
731
-
732
- logger.info("generate the relevance based on edges")
733
-
734
- # create relevance Expression
735
-
736
- # create calculate Expression
737
- self.process_calculate(self.project.start_pages, pages=self.project.pages)
738
- logger.info("generate the export format")
739
- # create calculate Expression
740
- self.process_export(self.project.start_pages, pages=self.project.pages)
741
-
742
- logger.info("print the export")
743
-
744
- # Export returns list of generated files for CHT strategy
745
- generated_files = self.export(self.project.start_pages, version=version)
746
-
747
- logger.info("validate the output")
748
- if not self.validate(generated_files):
749
- logger.error("CHT validation failed - aborting build")
750
- exit(1)
751
-
752
- def validate(self, generated_files=None):
753
- """Validate the generated XLS form(s) using pyxform conversion and ODK Validate JAR."""
754
- if generated_files is None:
755
- # Fallback for single file validation
756
- if self.project.start_pages["main"].root.form_id is not None:
757
- form_id = str(self.project.start_pages["main"].root.form_id)
758
- generated_files = [os.path.join(self.output_path, form_id + ".xlsx")]
759
- else:
760
- logger.error("Form ID not found for validation")
761
- return False
762
-
763
- # Ensure ODK Validate JAR is available
764
- jar_path = self._ensure_odk_validate_jar()
765
- if not jar_path:
766
- logger.error("ODK Validate JAR not available, skipping CHT validation")
767
- return False
768
-
769
- all_valid = True
770
- for xls_file in generated_files:
771
- if not os.path.exists(xls_file):
772
- logger.error(f"XLS file not found: {xls_file}")
773
- all_valid = False
774
- continue
775
-
776
- try:
777
- # Convert XLS to XForm using pyxform (without validation)
778
- xform_path = xls_file.replace('.xlsx', '.xml')
779
- convert_result = convert(
780
- xlsform=xls_file,
781
- validate=False, # Don't validate during conversion
782
- pretty_print=True
783
- )
784
- xform_content = convert_result.xform
785
-
786
- # Write XForm to temporary file for validation
787
- with tempfile.NamedTemporaryFile(mode='w', suffix='.xml', delete=False) as temp_file:
788
- temp_file.write(xform_content)
789
- temp_xform_path = temp_file.name
790
-
791
- try:
792
- # Run ODK Validate JAR on the XForm
793
- result = subprocess.run(
794
- ["java", "-Djava.awt.headless=true", "-jar", jar_path, temp_xform_path],
795
- capture_output=True,
796
- text=True,
797
- cwd=self.output_path
798
- )
799
-
800
- if result.returncode == 0 or "Cycle detected" in result.stderr:
801
- logger.info(f"CHT XLSForm validation successful: {os.path.basename(xls_file)}")
802
- else:
803
- logger.error(f"CHT XLSForm validation failed for {os.path.basename(xls_file)}: {result.stderr}")
804
- all_valid = False
805
-
806
- finally:
807
- # Clean up temporary XForm file
808
- os.unlink(temp_xform_path)
809
-
810
- except Exception as e:
811
- logger.error(f"CHT XLSForm validation error for {os.path.basename(xls_file)}: {str(e)}")
812
- all_valid = False
813
-
814
- logger.info(f"Extracted ODK Validate JAR to {jar_path}")
815
- return jar_path
816
-
817
- def _ensure_odk_validate_jar(self):
818
- """Ensure ODK Validate JAR is available by downloading from GitHub releases."""
819
- jar_path = os.path.join(os.path.dirname(__file__), "ODK_Validate.jar")
820
-
821
- # Check if JAR already exists
822
- if os.path.exists(jar_path):
823
- return jar_path
824
-
825
- # Download JAR from GitHub releases
826
- jar_url = "https://github.com/getodk/validate/releases/download/v1.20.0/ODK-Validate-v1.20.0.jar"
827
- try:
828
- import urllib.request
829
- urllib.request.urlretrieve(jar_url, jar_path)
830
- logger.info(f"Downloaded ODK Validate JAR to {jar_path}")
831
- return jar_path
832
- except Exception as e:
833
- logger.error(f"Failed to download ODK Validate JAR: {str(e)}")
834
- return None
835
-
836
- def tricc_operation_zscore(self, ref_expressions, original_references=None):
711
+ def tricc_operation_zscore(self, ref_expressions):
837
712
  y, ll, m, s = self.get_zscore_params(ref_expressions)
838
713
  # return ((Math.pow((y / m), l) - 1) / (s * l));
839
714
  return f"""cht:extension-lib('{
@@ -846,7 +721,7 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
846
721
  self.clean_coalesce(ref_expressions[3])
847
722
  })"""
848
723
 
849
- def tricc_operation_izscore(self, ref_expressions, original_references=None):
724
+ def tricc_operation_izscore(self, ref_expressions):
850
725
  z, ll, m, s = self.get_zscore_params(ref_expressions)
851
726
  # return (m * (z*s*l-1)^(1/l));
852
727
  return f"""cht:extension-lib('{
@@ -857,9 +732,9 @@ class XLSFormCHTStrategy(XLSFormCDSSStrategy):
857
732
  self.clean_coalesce(ref_expressions[2])
858
733
  } ,{
859
734
  self.clean_coalesce(ref_expressions[3])
860
- }, true"""
735
+ }, true)"""
861
736
 
862
- def tricc_operation_drug_dosage(self, ref_expressions, original_references=None):
737
+ def tricc_operation_drug_dosage(self, ref_expressions):
863
738
  # drug name
864
739
  # age
865
740
  # weight