health-data-standards 3.6.1 → 3.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (434) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +7 -2
  3. data/Rakefile +2 -1
  4. data/lib/health-data-standards.rb +22 -1
  5. data/lib/health-data-standards/export/cat_1.rb +25 -6
  6. data/lib/health-data-standards/export/cat_1_r2.rb +8 -2
  7. data/lib/health-data-standards/export/cat_3.rb +8 -7
  8. data/lib/health-data-standards/export/exceptions.rb +13 -0
  9. data/lib/health-data-standards/export/helper/cat1_view_helper.rb +17 -11
  10. data/lib/health-data-standards/export/helper/html_view_helper.rb +13 -7
  11. data/lib/health-data-standards/export/helper/scooped_view_helper.rb +68 -25
  12. data/lib/health-data-standards/export/html.rb +9 -4
  13. data/lib/health-data-standards/export/qrda/entry_template_resolver.rb +29 -11
  14. data/lib/health-data-standards/export/qrda/hqmf-qrda-oids.json +89 -5
  15. data/lib/health-data-standards/export/rendering_context.rb +2 -2
  16. data/lib/health-data-standards/export/template_helper.rb +7 -2
  17. data/lib/health-data-standards/export/view_helper.rb +107 -39
  18. data/lib/health-data-standards/import/bulk_record_importer.rb +8 -5
  19. data/lib/health-data-standards/import/bundle/importer.rb +21 -14
  20. data/lib/health-data-standards/import/c32/care_goal_importer.rb +1 -1
  21. data/lib/health-data-standards/import/c32/immunization_importer.rb +1 -1
  22. data/lib/health-data-standards/import/cat1/clinical_trial_participant_importer.rb +20 -0
  23. data/lib/health-data-standards/import/cat1/device_order_importer.rb +20 -0
  24. data/lib/health-data-standards/import/cat1/diagnosis_active_importer.rb +4 -9
  25. data/lib/health-data-standards/import/cat1/diagnosis_importer.rb +15 -0
  26. data/lib/health-data-standards/import/cat1/diagnosis_inactive_importer.rb +1 -1
  27. data/lib/health-data-standards/import/cat1/diagnostic_study_order_importer.rb +6 -0
  28. data/lib/health-data-standards/import/cat1/encounter_order_act_importer.rb +19 -0
  29. data/lib/health-data-standards/import/cat1/encounter_performed_act_importer.rb +19 -0
  30. data/lib/health-data-standards/import/cat1/encounter_performed_importer.rb +16 -0
  31. data/lib/health-data-standards/import/cat1/immunization_administered_importer.rb +14 -0
  32. data/lib/health-data-standards/import/cat1/medication_dispensed_act_importer.rb +18 -0
  33. data/lib/health-data-standards/import/cat1/patient_importer.rb +44 -17
  34. data/lib/health-data-standards/import/cat1/procedure_order_importer.rb +4 -4
  35. data/lib/health-data-standards/import/cat1/procedure_performed_importer.rb +1 -0
  36. data/lib/health-data-standards/import/cat1/transfer_from_act_importer.rb +18 -0
  37. data/lib/health-data-standards/import/cat1/transfer_from_importer.rb +24 -0
  38. data/lib/health-data-standards/import/cat1/transfer_to_act_importer.rb +18 -0
  39. data/lib/health-data-standards/import/cat1/transfer_to_importer.rb +23 -0
  40. data/lib/health-data-standards/import/cda/allergy_importer.rb +1 -1
  41. data/lib/health-data-standards/import/cda/communication_importer.rb +55 -0
  42. data/lib/health-data-standards/import/cda/condition_importer.rb +17 -1
  43. data/lib/health-data-standards/import/cda/encounter_importer.rb +23 -21
  44. data/lib/health-data-standards/import/cda/medical_equipment_importer.rb +1 -0
  45. data/lib/health-data-standards/import/cda/medication_importer.rb +14 -4
  46. data/lib/health-data-standards/import/cda/procedure_importer.rb +4 -4
  47. data/lib/health-data-standards/import/cda/result_importer.rb +1 -1
  48. data/lib/health-data-standards/import/cda/section_importer.rb +59 -18
  49. data/lib/health-data-standards/models/assessment.rb +3 -0
  50. data/lib/health-data-standards/models/care_experience.rb +2 -0
  51. data/lib/health-data-standards/models/care_goal.rb +4 -0
  52. data/lib/health-data-standards/models/communication.rb +3 -0
  53. data/lib/health-data-standards/models/condition.rb +12 -9
  54. data/lib/health-data-standards/models/cqm/bundle.rb +2 -1
  55. data/lib/health-data-standards/models/cqm/measure.rb +2 -1
  56. data/lib/health-data-standards/models/cqm/patient_cache.rb +7 -3
  57. data/lib/health-data-standards/models/cqm/query_cache.rb +2 -0
  58. data/lib/health-data-standards/models/encounter.rb +14 -1
  59. data/lib/health-data-standards/models/encounter_principal_diagnosis.rb +36 -0
  60. data/lib/health-data-standards/models/entry.rb +5 -1
  61. data/lib/health-data-standards/models/family_history.rb +4 -0
  62. data/lib/health-data-standards/models/immunization.rb +1 -0
  63. data/lib/health-data-standards/models/lab_result.rb +10 -1
  64. data/lib/health-data-standards/models/medical_equipment.rb +2 -1
  65. data/lib/health-data-standards/models/medication.rb +19 -2
  66. data/lib/health-data-standards/models/patient_preference.rb +5 -0
  67. data/lib/health-data-standards/models/procedure.rb +16 -3
  68. data/lib/health-data-standards/models/provider.rb +17 -1
  69. data/lib/health-data-standards/models/provider_preference.rb +5 -0
  70. data/lib/health-data-standards/models/record.rb +8 -9
  71. data/lib/health-data-standards/models/reference.rb +1 -1
  72. data/lib/health-data-standards/models/svs/value_set.rb +28 -10
  73. data/lib/health-data-standards/models/transfer.rb +6 -1
  74. data/lib/health-data-standards/tasks/bundle.rake +5 -3
  75. data/lib/health-data-standards/util/hqmf_template_helper.rb +20 -14
  76. data/lib/health-data-standards/util/hqmfr2_template_oid_map.json +382 -0
  77. data/lib/health-data-standards/util/nlm_helper.rb +14 -0
  78. data/lib/health-data-standards/util/vs_api.rb +72 -54
  79. data/lib/health-data-standards/validate/measure_validator.rb +8 -3
  80. data/lib/health-data-standards/validate/performance_rate_validator.rb +1 -1
  81. data/lib/health-data-standards/validate/qrda_qdm_template_validator.rb +253 -0
  82. data/lib/health-data-standards/validate/reported_result_extractor.rb +5 -1
  83. data/lib/health-data-standards/validate/schematron_validator.rb +6 -0
  84. data/lib/health-data-standards/validate/validators.rb +49 -1
  85. data/lib/hqmf-generator/document.xml.erb +6 -5
  86. data/lib/hqmf-generator/field.xml.erb +1 -0
  87. data/lib/hqmf-generator/hqmf-generator.rb +85 -41
  88. data/lib/hqmf-generator/subset.xml.erb +15 -0
  89. data/lib/hqmf-generator/temporal_relationship.xml.erb +8 -3
  90. data/lib/hqmf-generator/temporal_relationship_attribute.xml.erb +10 -0
  91. data/lib/hqmf-generator/value.xml.erb +2 -2
  92. data/lib/hqmf-model/data_criteria.json +88 -17
  93. data/lib/hqmf-model/data_criteria.rb +144 -72
  94. data/lib/hqmf-model/population_criteria.rb +20 -18
  95. data/lib/hqmf-model/precondition.rb +6 -3
  96. data/lib/hqmf-model/types.rb +1 -1
  97. data/lib/hqmf-parser.rb +9 -0
  98. data/lib/hqmf-parser/1.0/utilities.rb +1 -1
  99. data/lib/hqmf-parser/2.0/data_criteria.rb +293 -319
  100. data/lib/hqmf-parser/2.0/data_criteria_helpers/dc_base_extract.rb +80 -0
  101. data/lib/hqmf-parser/2.0/data_criteria_helpers/dc_definition_from_template_or_type_extract.rb +201 -0
  102. data/lib/hqmf-parser/2.0/data_criteria_helpers/dc_post_processing.rb +85 -0
  103. data/lib/hqmf-parser/2.0/data_criteria_helpers/dc_specific_occurrences_and_source_data_criteria_extract.rb +117 -0
  104. data/lib/hqmf-parser/2.0/document.rb +246 -222
  105. data/lib/hqmf-parser/2.0/document_helpers/doc_population_helper.rb +175 -0
  106. data/lib/hqmf-parser/2.0/document_helpers/doc_utilities.rb +131 -0
  107. data/lib/hqmf-parser/2.0/field_value_helper.rb +251 -0
  108. data/lib/hqmf-parser/2.0/population_criteria.rb +101 -32
  109. data/lib/hqmf-parser/2.0/precondition.rb +61 -35
  110. data/lib/hqmf-parser/2.0/source_data_criteria_helper.rb +112 -0
  111. data/lib/hqmf-parser/2.0/types.rb +253 -73
  112. data/lib/hqmf-parser/2.0/utilities.rb +27 -12
  113. data/lib/hqmf-parser/2.0/value_set_helper.rb +101 -0
  114. data/lib/hqmf-parser/converter/pass1/data_criteria_converter.rb +6 -1
  115. data/lib/hqmf-parser/converter/pass1/population_criteria_converter.rb +34 -30
  116. data/lib/hqmf-parser/parser.rb +5 -5
  117. data/resources/schematron/qrda/cat_1/{CDAR2_QRDA_I_R1_D3_2015MAY_Schematron.sch → HL7_CDAR2_QRDA_Category_I_2_12_16.sch} +4692 -4675
  118. data/resources/schematron/qrda/cat_1_r3_1/HL7 QRDA Category I STU 3.1.sch +3573 -0
  119. data/resources/schematron/qrda/cat_1_r3_1/HL7 QRDA Category III STU 1.1.sch +464 -0
  120. data/resources/schematron/qrda/cat_1_r3_1/QRDA Category I STU Release 3.1.sch +5394 -0
  121. data/resources/schematron/qrda/cat_1_r3_1/voc.xml +1229 -0
  122. data/resources/schematron/qrda/cat_1_r4/HL7 QRDA Category I STU 4.sch +3526 -0
  123. data/resources/schematron/qrda/cat_1_r4/voc.xml +1186 -0
  124. data/resources/schematron/qrda/cat_3_r1_1/HL7 QRDA Category III STU 1.1.sch +528 -0
  125. data/resources/schematron/qrda/cat_3_r1_1/voc.xml +8 -0
  126. data/resources/schematron/qrda/cat_3_r2/HL7 QRDA Category III STU 2.sch +677 -0
  127. data/resources/schematron/qrda/cat_3_r2/voc.xml +1186 -0
  128. data/resources/schematron/qrda/cat_3_r2_1/HL7 QRDA Category III STU 2.1.sch +678 -0
  129. data/resources/schematron/qrda/cat_3_r2_1/voc.xml +1186 -0
  130. data/templates/c32/_medical_equipment.c32.erb +1 -1
  131. data/templates/c32/_vital_signs.c32.erb +1 -1
  132. data/templates/cat1/{_2.16.840.1.113883.10.20.22.4.85.cat1.erb → r2/_2.16.840.1.113883.10.20.22.4.85.cat1.erb} +1 -1
  133. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.1.cat1.erb → r2/_2.16.840.1.113883.10.20.24.3.1.cat1.erb} +3 -3
  134. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.101.cat1.erb → r2/_2.16.840.1.113883.10.20.24.3.101.cat1.erb} +1 -1
  135. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.103.cat1.erb → r2/_2.16.840.1.113883.10.20.24.3.103.cat1.erb} +9 -5
  136. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.105.cat1.erb → r2/_2.16.840.1.113883.10.20.24.3.105.cat1.erb} +18 -10
  137. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.11.cat1.erb +88 -0
  138. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.12.cat1.erb +50 -0
  139. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.13.cat1.erb +54 -0
  140. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.135.cat1.erb +70 -0
  141. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.136.cat1.erb +52 -0
  142. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.14.cat1.erb → r2/_2.16.840.1.113883.10.20.24.3.14.cat1.erb} +24 -6
  143. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.140.cat1.erb +39 -0
  144. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.17.cat1.erb +23 -0
  145. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.18.cat1.erb +25 -0
  146. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.2.cat1.erb +29 -0
  147. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.20.cat1.erb → r2/_2.16.840.1.113883.10.20.24.3.20.cat1.erb} +4 -4
  148. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.22.cat1.erb +22 -0
  149. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.23.cat1.erb +114 -0
  150. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.26.cat1.erb +20 -0
  151. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.28.cat1.erb → r2/_2.16.840.1.113883.10.20.24.3.28.cat1.erb} +2 -2
  152. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.3.cat1.erb +25 -0
  153. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.31.cat1.erb +23 -0
  154. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.32.cat1.erb +20 -0
  155. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.34.cat1.erb → r2/_2.16.840.1.113883.10.20.24.3.34.cat1.erb} +6 -6
  156. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.37.cat1.erb +22 -0
  157. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.38.cat1.erb +20 -0
  158. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.4.cat1.erb +29 -0
  159. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.40.cat1.erb → r2/_2.16.840.1.113883.10.20.24.3.40.cat1.erb} +3 -3
  160. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.41.cat1.erb +46 -0
  161. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.42.cat1.erb +38 -0
  162. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.43.cat1.erb +24 -0
  163. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.44.cat1.erb +25 -0
  164. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.45.cat1.erb +26 -0
  165. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.46.cat1.erb +30 -0
  166. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.47.cat1.erb +47 -0
  167. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.51.cat1.erb +14 -0
  168. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.54.cat1.erb +32 -0
  169. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.55.cat1.erb → r2/_2.16.840.1.113883.10.20.24.3.55.cat1.erb} +0 -0
  170. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.57.cat1.erb +23 -0
  171. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.59.cat1.erb +22 -0
  172. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.62.cat1.erb +36 -0
  173. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.63.cat1.erb +21 -0
  174. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.64.cat1.erb +52 -0
  175. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.66.cat1.erb → r2/_2.16.840.1.113883.10.20.24.3.66.cat1.erb} +6 -6
  176. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.69.cat1.erb +23 -0
  177. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.7.cat1.erb +33 -0
  178. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.76.cat1.erb → r2/_2.16.840.1.113883.10.20.24.3.76.cat1.erb} +5 -3
  179. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.81.cat1.erb +23 -0
  180. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.82.cat1.erb +23 -0
  181. data/templates/cat1/r2/_2.16.840.1.113883.10.20.24.3.9.cat1.erb +64 -0
  182. data/templates/cat1/r2/_2.16.840.1.113883.10.20.28.3.6.cat1.erb +17 -0
  183. data/templates/cat1/{_address.cat1.erb → r2/_address.cat1.erb} +0 -0
  184. data/templates/cat1/{_author.cat1.erb → r2/_author.cat1.erb} +0 -0
  185. data/templates/cat1/r2/_fulfills.cat1.erb +14 -0
  186. data/templates/cat1/{_id.cat1.erb → r2/_id.cat1.erb} +0 -0
  187. data/templates/cat1/{_measures.cat1.erb → r2/_measures.cat1.erb} +1 -1
  188. data/templates/cat1/{_medication_details.cat1.erb → r2/_medication_details.cat1.erb} +3 -2
  189. data/templates/cat1/r2/_medication_dispense.cat1.erb +22 -0
  190. data/templates/cat1/{_ordinality.cat1.erb → r2/_ordinality.cat1.erb} +0 -0
  191. data/templates/cat1/{_organization.cat1.erb → r2/_organization.cat1.erb} +0 -0
  192. data/templates/cat1/{_patient_data.cat1.erb → r2/_patient_data.cat1.erb} +4 -1
  193. data/templates/cat1/r2/_patient_data_r3_1.cat1.erb +17 -0
  194. data/templates/cat1/r2/_providers.cat1.erb +76 -0
  195. data/templates/cat1/r2/_reason.cat1.erb +45 -0
  196. data/templates/cat1/{_record_target.cat1.erb → r2/_record_target.cat1.erb} +3 -0
  197. data/templates/cat1/r2/_reporting_parameters.cat1.erb +31 -0
  198. data/templates/cat1/{_result_value.cat1.erb → r2/_result_value.cat1.erb} +1 -1
  199. data/templates/cat1/{_telecom.cat1.erb → r2/_telecom.cat1.erb} +0 -0
  200. data/templates/cat1/{show.cat1.erb → r2/show.cat1.erb} +52 -5
  201. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.1.cat1.erb +14 -0
  202. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.103.cat1.erb +17 -0
  203. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.105.cat1.erb +68 -0
  204. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.11.cat1.erb +58 -0
  205. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.12.cat1.erb → r3/_2.16.840.1.113883.10.20.24.3.12.cat1.erb} +4 -5
  206. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.13.cat1.erb +39 -0
  207. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.14.cat1.erb +39 -0
  208. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.17.cat1.erb +23 -0
  209. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.18.cat1.erb +25 -0
  210. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.2.cat1.erb +29 -0
  211. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.22.cat1.erb → r3/_2.16.840.1.113883.10.20.24.3.22.cat1.erb} +6 -5
  212. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.23.cat1.erb → r3/_2.16.840.1.113883.10.20.24.3.23.cat1.erb} +26 -30
  213. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.26.cat1.erb +20 -0
  214. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.3.cat1.erb +25 -0
  215. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.31.cat1.erb +23 -0
  216. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.32.cat1.erb → r3/_2.16.840.1.113883.10.20.24.3.32.cat1.erb} +4 -4
  217. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.37.cat1.erb +22 -0
  218. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.38.cat1.erb → r3/_2.16.840.1.113883.10.20.24.3.38.cat1.erb} +3 -3
  219. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.4.cat1.erb +29 -0
  220. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.41.cat1.erb → r3/_2.16.840.1.113883.10.20.24.3.41.cat1.erb} +8 -10
  221. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.42.cat1.erb +38 -0
  222. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.43.cat1.erb +24 -0
  223. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.44.cat1.erb +25 -0
  224. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.45.cat1.erb → r3/_2.16.840.1.113883.10.20.24.3.45.cat1.erb} +5 -5
  225. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.46.cat1.erb +30 -0
  226. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.47.cat1.erb +47 -0
  227. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.51.cat1.erb +14 -0
  228. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.54.cat1.erb → r3/_2.16.840.1.113883.10.20.24.3.54.cat1.erb} +4 -4
  229. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.55.cat1.erb +18 -0
  230. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.57.cat1.erb +23 -0
  231. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.59.cat1.erb +22 -0
  232. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.62.cat1.erb +36 -0
  233. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.63.cat1.erb → r3/_2.16.840.1.113883.10.20.24.3.63.cat1.erb} +6 -8
  234. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.64.cat1.erb +51 -0
  235. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.69.cat1.erb +23 -0
  236. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.7.cat1.erb +33 -0
  237. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.76.cat1.erb +19 -0
  238. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.81.cat1.erb +24 -0
  239. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.82.cat1.erb +24 -0
  240. data/templates/cat1/r3/_2.16.840.1.113883.10.20.24.3.9.cat1.erb +57 -0
  241. data/templates/cat1/r3/_address.cat1.erb +9 -0
  242. data/templates/{cat3/_author.cat3.erb → cat1/r3/_author.cat1.erb} +0 -0
  243. data/templates/cat1/{_fulfills.cat1.erb → r3/_fulfills.cat1.erb} +0 -0
  244. data/templates/{cat3/_id.cat3.erb → cat1/r3/_id.cat1.erb} +0 -0
  245. data/templates/cat1/r3/_measures.cat1.erb +93 -0
  246. data/templates/cat1/r3/_medication_details.cat1.erb +16 -0
  247. data/templates/cat1/{_medication_dispense.cat1.erb → r3/_medication_dispense.cat1.erb} +3 -3
  248. data/templates/cat1/r3/_ordinality.cat1.erb +10 -0
  249. data/templates/cat1/r3/_organization.cat1.erb +9 -0
  250. data/templates/cat1/r3/_patient_data.cat1.erb +17 -0
  251. data/templates/cat1/r3/_providers.cat1.erb +76 -0
  252. data/templates/cat1/r3/_reason.cat1.erb +34 -0
  253. data/templates/cat1/r3/_record_target.cat1.erb +56 -0
  254. data/templates/cat1/r3/_reporting_parameters.cat1.erb +31 -0
  255. data/templates/cat1/r3/_result_value.cat1.erb +28 -0
  256. data/templates/{cat3/_telecom.cat3.erb → cat1/r3/_telecom.cat1.erb} +0 -0
  257. data/templates/cat1/r3/show.cat1.erb +183 -0
  258. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.1.cat1.erb +14 -0
  259. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.103.cat1.erb +17 -0
  260. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.105.cat1.erb +68 -0
  261. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.12.cat1.erb +53 -0
  262. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.135.cat1.erb +71 -0
  263. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.136.cat1.erb +52 -0
  264. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.140.cat1.erb +39 -0
  265. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.17.cat1.erb +23 -0
  266. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.18.cat1.erb → r3_1/_2.16.840.1.113883.10.20.24.3.18.cat1.erb} +3 -3
  267. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.2.cat1.erb → r3_1/_2.16.840.1.113883.10.20.24.3.2.cat1.erb} +2 -2
  268. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.22.cat1.erb +30 -0
  269. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.23.cat1.erb +116 -0
  270. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.26.cat1.erb → r3_1/_2.16.840.1.113883.10.20.24.3.26.cat1.erb} +4 -2
  271. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.3.cat1.erb → r3_1/_2.16.840.1.113883.10.20.24.3.3.cat1.erb} +2 -2
  272. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.31.cat1.erb +24 -0
  273. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.32.cat1.erb +21 -0
  274. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.37.cat1.erb +22 -0
  275. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.38.cat1.erb +21 -0
  276. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.4.cat1.erb → r3_1/_2.16.840.1.113883.10.20.24.3.4.cat1.erb} +2 -2
  277. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.41.cat1.erb +45 -0
  278. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.42.cat1.erb → r3_1/_2.16.840.1.113883.10.20.24.3.42.cat1.erb} +4 -4
  279. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.43.cat1.erb → r3_1/_2.16.840.1.113883.10.20.24.3.43.cat1.erb} +3 -3
  280. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.44.cat1.erb → r3_1/_2.16.840.1.113883.10.20.24.3.44.cat1.erb} +3 -3
  281. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.45.cat1.erb +35 -0
  282. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.46.cat1.erb → r3_1/_2.16.840.1.113883.10.20.24.3.46.cat1.erb} +4 -4
  283. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.47.cat1.erb +47 -0
  284. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.51.cat1.erb +14 -0
  285. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.54.cat1.erb +32 -0
  286. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.55.cat1.erb +18 -0
  287. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.57.cat1.erb → r3_1/_2.16.840.1.113883.10.20.24.3.57.cat1.erb} +3 -3
  288. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.59.cat1.erb +22 -0
  289. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.62.cat1.erb → r3_1/_2.16.840.1.113883.10.20.24.3.62.cat1.erb} +5 -5
  290. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.63.cat1.erb +21 -0
  291. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.64.cat1.erb → r3_1/_2.16.840.1.113883.10.20.24.3.64.cat1.erb} +7 -7
  292. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.69.cat1.erb → r3_1/_2.16.840.1.113883.10.20.24.3.69.cat1.erb} +2 -2
  293. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.7.cat1.erb → r3_1/_2.16.840.1.113883.10.20.24.3.7.cat1.erb} +12 -9
  294. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.81.cat1.erb +33 -0
  295. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.82.cat1.erb +33 -0
  296. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.24.3.9.cat1.erb +41 -0
  297. data/templates/cat1/r3_1/_2.16.840.1.113883.10.20.28.3.6.cat1.erb +17 -0
  298. data/templates/cat1/r3_1/_address.cat1.erb +9 -0
  299. data/templates/cat1/r3_1/_author.cat1.erb +28 -0
  300. data/templates/cat1/r3_1/_fulfills.cat1.erb +14 -0
  301. data/templates/cat1/r3_1/_id.cat1.erb +1 -0
  302. data/templates/cat1/r3_1/_measures.cat1.erb +93 -0
  303. data/templates/cat1/r3_1/_medication_details.cat1.erb +16 -0
  304. data/templates/cat1/r3_1/_medication_dispense.cat1.erb +22 -0
  305. data/templates/cat1/r3_1/_ordinality.cat1.erb +10 -0
  306. data/templates/cat1/r3_1/_organization.cat1.erb +9 -0
  307. data/templates/cat1/r3_1/_patient_data.cat1.erb +17 -0
  308. data/templates/cat1/r3_1/_providers.cat1.erb +76 -0
  309. data/templates/cat1/r3_1/_reason.cat1.erb +34 -0
  310. data/templates/cat1/r3_1/_record_target.cat1.erb +56 -0
  311. data/templates/cat1/r3_1/_reporting_parameters.cat1.erb +31 -0
  312. data/templates/cat1/r3_1/_result_value.cat1.erb +28 -0
  313. data/templates/cat1/r3_1/_telecom.cat1.erb +1 -0
  314. data/templates/cat1/r3_1/show.cat1.erb +183 -0
  315. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.1.cat1.erb +14 -0
  316. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.103.cat1.erb +17 -0
  317. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.105.cat1.erb +68 -0
  318. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.12.cat1.erb +53 -0
  319. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.135.cat1.erb +75 -0
  320. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.136.cat1.erb +52 -0
  321. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.140.cat1.erb +39 -0
  322. data/templates/cat1/{_2.16.840.1.113883.10.20.24.3.59.cat1.erb → r4/_2.16.840.1.113883.10.20.24.3.144.cat1.erb} +6 -6
  323. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.145.cat1.erb +24 -0
  324. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.17.cat1.erb +23 -0
  325. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.18.cat1.erb +25 -0
  326. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.2.cat1.erb +29 -0
  327. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.22.cat1.erb +30 -0
  328. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.23.cat1.erb +116 -0
  329. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.3.cat1.erb +25 -0
  330. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.31.cat1.erb +24 -0
  331. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.32.cat1.erb +21 -0
  332. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.37.cat1.erb +22 -0
  333. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.38.cat1.erb +21 -0
  334. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.4.cat1.erb +29 -0
  335. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.41.cat1.erb +45 -0
  336. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.42.cat1.erb +38 -0
  337. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.43.cat1.erb +24 -0
  338. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.44.cat1.erb +25 -0
  339. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.45.cat1.erb +35 -0
  340. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.46.cat1.erb +30 -0
  341. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.47.cat1.erb +47 -0
  342. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.51.cat1.erb +14 -0
  343. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.54.cat1.erb +32 -0
  344. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.55.cat1.erb +18 -0
  345. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.57.cat1.erb +23 -0
  346. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.59.cat1.erb +22 -0
  347. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.62.cat1.erb +36 -0
  348. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.63.cat1.erb +21 -0
  349. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.64.cat1.erb +52 -0
  350. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.7.cat1.erb +33 -0
  351. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.81.cat1.erb +33 -0
  352. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.82.cat1.erb +33 -0
  353. data/templates/cat1/r4/_2.16.840.1.113883.10.20.24.3.9.cat1.erb +41 -0
  354. data/templates/cat1/r4/_2.16.840.1.113883.10.20.28.3.6.cat1.erb +17 -0
  355. data/templates/cat1/r4/_address.cat1.erb +7 -0
  356. data/templates/cat1/r4/_author.cat1.erb +28 -0
  357. data/templates/cat1/r4/_fulfills.cat1.erb +14 -0
  358. data/templates/cat1/r4/_id.cat1.erb +1 -0
  359. data/templates/cat1/r4/_measures.cat1.erb +93 -0
  360. data/templates/cat1/r4/_medication_details.cat1.erb +16 -0
  361. data/templates/cat1/r4/_medication_dispense.cat1.erb +22 -0
  362. data/templates/cat1/r4/_ordinality.cat1.erb +10 -0
  363. data/templates/cat1/r4/_organization.cat1.erb +9 -0
  364. data/templates/cat1/r4/_patient_data.cat1.erb +17 -0
  365. data/templates/cat1/r4/_providers.cat1.erb +76 -0
  366. data/templates/cat1/r4/_reason.cat1.erb +34 -0
  367. data/templates/cat1/r4/_record_target.cat1.erb +54 -0
  368. data/templates/cat1/r4/_reporting_parameters.cat1.erb +31 -0
  369. data/templates/cat1/r4/_result_value.cat1.erb +28 -0
  370. data/templates/cat1/r4/_telecom.cat1.erb +1 -0
  371. data/templates/cat1/r4/show.cat1.erb +192 -0
  372. data/templates/cat3/{_address.cat3.erb → r1/_address.cat3.erb} +0 -0
  373. data/templates/cat3/r1/_author.cat3.erb +28 -0
  374. data/templates/cat3/{_continuous_variable_value.cat3.erb → r1/_continuous_variable_value.cat3.erb} +0 -0
  375. data/templates/cat3/r1/_id.cat3.erb +1 -0
  376. data/templates/cat3/{_measure_data.cat3.erb → r1/_measure_data.cat3.erb} +7 -6
  377. data/templates/cat3/{_organization.cat3.erb → r1/_organization.cat3.erb} +0 -0
  378. data/templates/cat3/{_performance_rate.cat3.erb → r1/_performance_rate.cat3.erb} +1 -3
  379. data/templates/cat3/{_providers.cat3.erb → r1/_providers.cat3.erb} +0 -0
  380. data/templates/cat3/{_reporting_parameters.cat3.erb → r1/_reporting_parameters.cat3.erb} +0 -0
  381. data/templates/cat3/{_supplemental_data.cat3.erb → r1/_supplemental_data.cat3.erb} +2 -0
  382. data/templates/cat3/r1/_telecom.cat3.erb +1 -0
  383. data/templates/cat3/{show.cat3.erb → r1/show.cat3.erb} +5 -5
  384. data/templates/cat3/r1_1/_address.cat3.erb +9 -0
  385. data/templates/cat3/r1_1/_author.cat3.erb +28 -0
  386. data/templates/cat3/r1_1/_continuous_variable_value.cat3.erb +20 -0
  387. data/templates/cat3/r1_1/_id.cat3.erb +1 -0
  388. data/templates/cat3/r1_1/_measure_data.cat3.erb +136 -0
  389. data/templates/cat3/r1_1/_organization.cat3.erb +6 -0
  390. data/templates/cat3/r1_1/_performance_rate.cat3.erb +18 -0
  391. data/templates/{cat1/_providers.cat1.erb → cat3/r1_1/_providers.cat3.erb} +18 -18
  392. data/templates/{cat1/_reporting_parameters.cat1.erb → cat3/r1_1/_reporting_parameters.cat3.erb} +5 -1
  393. data/templates/cat3/r1_1/_supplemental_data.cat3.erb +38 -0
  394. data/templates/cat3/r1_1/_telecom.cat3.erb +1 -0
  395. data/templates/cat3/r1_1/show.cat3.erb +150 -0
  396. data/templates/cat3/r2/_address.cat3.erb +9 -0
  397. data/templates/cat3/r2/_author.cat3.erb +28 -0
  398. data/templates/cat3/r2/_continuous_variable_value.cat3.erb +20 -0
  399. data/templates/cat3/r2/_id.cat3.erb +1 -0
  400. data/templates/cat3/r2/_measure_data.cat3.erb +136 -0
  401. data/templates/cat3/r2/_organization.cat3.erb +6 -0
  402. data/templates/cat3/r2/_performance_rate.cat3.erb +19 -0
  403. data/templates/cat3/r2/_providers.cat3.erb +57 -0
  404. data/templates/cat3/r2/_reporting_parameters.cat3.erb +29 -0
  405. data/templates/cat3/r2/_supplemental_data.cat3.erb +38 -0
  406. data/templates/cat3/r2/_telecom.cat3.erb +1 -0
  407. data/templates/cat3/r2/show.cat3.erb +150 -0
  408. data/templates/cat3/r2_1/_address.cat3.erb +9 -0
  409. data/templates/cat3/r2_1/_author.cat3.erb +28 -0
  410. data/templates/cat3/r2_1/_continuous_variable_value.cat3.erb +20 -0
  411. data/templates/cat3/r2_1/_id.cat3.erb +1 -0
  412. data/templates/cat3/r2_1/_measure_data.cat3.erb +136 -0
  413. data/templates/cat3/r2_1/_organization.cat3.erb +6 -0
  414. data/templates/cat3/r2_1/_performance_rate.cat3.erb +19 -0
  415. data/templates/cat3/r2_1/_providers.cat3.erb +57 -0
  416. data/templates/cat3/r2_1/_reporting_parameters.cat3.erb +20 -0
  417. data/templates/cat3/r2_1/_reporting_parameters_act.cat3.erb +10 -0
  418. data/templates/cat3/r2_1/_supplemental_data.cat3.erb +38 -0
  419. data/templates/cat3/r2_1/_telecom.cat3.erb +1 -0
  420. data/templates/cat3/r2_1/show.cat3.erb +153 -0
  421. data/templates/ccda/_medical_equipment.ccda.erb +1 -1
  422. data/templates/ccda/_social_history.ccda.erb +2 -2
  423. data/templates/ccda/_vital_signs.ccda.erb +1 -1
  424. data/templates/html/_entries_by_section.html.erb +1 -1
  425. metadata +425 -153
  426. data/lib/health-data-standards/import/cat1/procedure_importer.rb +0 -42
  427. data/templates/cat1/_2.16.840.1.113883.10.20.24.3.11.cat1.erb +0 -55
  428. data/templates/cat1/_2.16.840.1.113883.10.20.24.3.13.cat1.erb +0 -38
  429. data/templates/cat1/_2.16.840.1.113883.10.20.24.3.17.cat1.erb +0 -22
  430. data/templates/cat1/_2.16.840.1.113883.10.20.24.3.31.cat1.erb +0 -22
  431. data/templates/cat1/_2.16.840.1.113883.10.20.24.3.37.cat1.erb +0 -20
  432. data/templates/cat1/_2.16.840.1.113883.10.20.24.3.47.cat1.erb +0 -27
  433. data/templates/cat1/_2.16.840.1.113883.10.20.24.3.51.cat1.erb +0 -13
  434. data/templates/cat1/_reason.cat1.erb +0 -23
@@ -2,64 +2,133 @@ module HQMF2
2
2
  # Represents an HQMF population criteria, also supports all the same methods as
3
3
  # HQMF2::Precondition
4
4
  class PopulationCriteria
5
-
6
5
  include HQMF2::Utilities
7
-
6
+
8
7
  attr_reader :preconditions, :id, :hqmf_id, :title, :aggregator, :comments
9
- #need to do this to allow for setting the type to OBSERV for
8
+ # need to do this to allow for setting the type to OBSERV for
10
9
  attr_accessor :type
11
10
  # Create a new population criteria from the supplied HQMF entry
12
11
  # @param [Nokogiri::XML::Element] the HQMF entry
13
- def initialize(entry, doc)
12
+ def initialize(entry, doc, id_generator)
13
+ @id_generator = id_generator
14
14
  @doc = doc
15
15
  @entry = entry
16
- @hqmf_id = attr_val('./*/cda:id/@extension') || attr_val('./*/cda:typeId/@extension')
17
- @title = attr_val('./*/cda:code/cda:displayName/@value')
16
+ setup_derived_entry_elements(id_generator)
17
+ # modify type to meet current expected population names
18
+ @type = 'IPP' if @type == 'IPOP' || @type == 'IPPOP'
19
+ @comments = nil if comments.empty?
20
+ # MEAN is handled in current code. Changed since it should have the same effect
21
+ @aggregator = 'MEAN' if @aggregator == 'AVERAGE'
22
+ @hqmf_id = @type unless @hqmf_id # The id extension is not required, if it's not provided use the code
23
+ handle_type(id_generator)
24
+ end
25
+
26
+ # Handles how the code should deal with the type definition (aggregate vs non-aggregate)
27
+ def handle_type(id_generator)
28
+ if @type != 'AGGREGATE'
29
+ # Generate the precondition for this population
30
+ if @preconditions.length > 1 ||
31
+ (@preconditions.length == 1 && @preconditions[0].conjunction != conjunction_code)
32
+ @preconditions = [Precondition.new(id_generator.next_id, conjunction_code, @preconditions)]
33
+ end
34
+ else
35
+ # Extract the data criteria this population references
36
+ dc = handle_observation_criteria
37
+ @preconditions = [Precondition.new(id_generator.next_id, nil, nil, false, HQMF2::Reference.new(dc.id))]
38
+ end
39
+ end
40
+
41
+ # Handles extracting elements from the entry
42
+ def setup_derived_entry_elements(id_generator)
43
+ @hqmf_id = attr_val('./*/cda:id/@root') || attr_val('./*/cda:typeId/@extension')
44
+ @title = attr_val('./*/cda:code/cda:displayName/@value').try(:titleize)
18
45
  @type = attr_val('./*/cda:code/@code')
19
- @aggregator = nil
20
- @comments = @entry.xpath("./*/cda:text/cda:xml/cda:qdmUserComments/cda:item/text()", HQMF2::Document::NAMESPACES)
21
- .map{ |v| v.content }
46
+ @comments = @entry.xpath('./*/cda:text/cda:xml/cda:qdmUserComments/cda:item/text()', HQMF2::Document::NAMESPACES)
47
+ .map(&:content)
48
+ handle_preconditions(id_generator)
22
49
  obs_test = attr_val('./cda:measureObservationDefinition/@classCode')
23
- if !@title && obs_test.to_s == "OBS"
24
- @title = attr_val('../cda:code/cda:displayName/@value')
25
- @aggregator = attr_val('./cda:measureObservationDefinition/cda:methodCode/cda:item/@code')
26
- end
27
- if(!@hqmf_id) # The id extension is not required, if it's not provided use the code
28
- @hqmf_id = @type
50
+ # If there are no measure observations, or there is a title, then there are no aggregations to extract
51
+ return unless !@title && obs_test.to_s == 'OBS'
52
+ @title = attr_val('../cda:code/cda:displayName/@value')
53
+ @aggregator = attr_val('./cda:measureObservationDefinition/cda:methodCode/cda:item/@code')
54
+ end
55
+
56
+ # specifically handles extracting the preconditions for the population criteria
57
+ def handle_preconditions(id_generator)
58
+ # Nest multiple preconditions under a single root precondition
59
+ @preconditions = @entry.xpath('./*/cda:precondition[not(@nullFlavor)]', HQMF2::Document::NAMESPACES)
60
+ .collect do |pre|
61
+ precondition = Precondition.parse(pre, @doc, id_generator)
62
+ precondition.reference.nil? && precondition.preconditions.empty? ? nil : precondition
29
63
  end
30
- @preconditions = @entry.xpath('./*/cda:precondition[not(@nullFlavor)]', HQMF2::Document::NAMESPACES).collect do |precondition|
31
- Precondition.new(precondition, @doc)
64
+ # Remove uneeded nils from the array
65
+ @preconditions.compact!
66
+ end
67
+
68
+ # extracts out any measure observation definitons, creating from them the proper criteria to generate a precondition
69
+ def handle_observation_criteria
70
+ exp = @entry.at_xpath('./cda:measureObservationDefinition/cda:value/cda:expression/@value',
71
+ HQMF2::Document::NAMESPACES)
72
+ # Measure Observations criteria rely on computed expressions. If it doesn't have one,
73
+ # then it is likely formatted improperly.
74
+ fail 'Measure Observations criteria is missing computed expression(s) ' if exp.nil?
75
+ parts = exp.to_s.split('-')
76
+ dc = parse_parts_to_dc(parts)
77
+ @doc.add_data_criteria(dc)
78
+ # Update reference_ids with any newly referenced data criteria
79
+ dc.children_criteria.each { |cc| @doc.add_reference_id(cc) } unless dc.children_criteria.nil?
80
+ dc
81
+ end
82
+
83
+ # generates the value given in an expression based on the number of criteria it references.
84
+ def parse_parts_to_dc(parts)
85
+ case parts.length
86
+ when 1
87
+ # If there is only one part, it is a reference to an existing data criteria's value
88
+ @doc.find_criteria_by_lvn(parts.first.strip.split('.')[0])
89
+ when 2
90
+ # If there are two parts, there is a computation performed, specifically time difference, on the two criteria
91
+ children = parts.collect { |p| @doc.find_criteria_by_lvn(p.strip.split('.')[0]).id }
92
+ id = "GROUP_TIMEDIFF_#{@id_generator.next_id}"
93
+ HQMF2::DataCriteriaWrapper.new(id: id,
94
+ title: id,
95
+ subset_operators: [HQMF::SubsetOperator.new('DATETIMEDIFF', nil)],
96
+ children_criteria: children,
97
+ derivation_operator: HQMF::DataCriteria::XPRODUCT,
98
+ type: 'derived',
99
+ definition: 'derived',
100
+ negation: false,
101
+ source_data_criteria: id
102
+ )
103
+ else
104
+ # If there are neither one or 2 parts, the code should fail
105
+ fail "No defined extraction method to handle #{parts.length} parts"
32
106
  end
33
107
  end
34
-
108
+
35
109
  def create_human_readable_id(id)
36
110
  @id = id
37
111
  end
38
-
39
- # Return true of this precondition represents a conjunction with nested preconditions
40
- # or false of this precondition is a reference to a data criteria
41
- def conjunction?
42
- true
43
- end
44
112
 
45
- # Get the conjunction code, e.g. allTrue, allFalse
113
+ # Get the conjunction code, ALL_TRUE or AT_LEAST_ONE_TRUE
46
114
  # @return [String] conjunction code
47
115
  def conjunction_code
48
116
  case @type
49
- when HQMF::PopulationCriteria::IPP, HQMF::PopulationCriteria::DENOM, HQMF::PopulationCriteria::NUMER,HQMF::PopulationCriteria::MSRPOPL
117
+ when HQMF::PopulationCriteria::IPP, HQMF::PopulationCriteria::DENOM, HQMF::PopulationCriteria::NUMER,
118
+ HQMF::PopulationCriteria::MSRPOPL, HQMF::PopulationCriteria::STRAT
50
119
  HQMF::Precondition::ALL_TRUE
51
- when HQMF::PopulationCriteria::DENEXCEP, HQMF::PopulationCriteria::DENEX
120
+ when HQMF::PopulationCriteria::DENEXCEP, HQMF::PopulationCriteria::DENEX, HQMF::PopulationCriteria::MSRPOPLEX,
121
+ HQMF::PopulationCriteria::NUMEX
52
122
  HQMF::Precondition::AT_LEAST_ONE_TRUE
53
123
  else
54
- raise "Unknown population type [#{@type}]"
124
+ fail "Unknown population type [#{@type}]"
55
125
  end
56
126
  end
57
-
127
+
128
+ # Generates this classes hqmf-model equivalent
58
129
  def to_model
59
- mps = preconditions.collect {|p| p.to_model}
130
+ mps = preconditions.collect(&:to_model)
60
131
  HQMF::PopulationCriteria.new(id, hqmf_id, type, mps, title, aggregator, comments)
61
132
  end
62
-
63
133
  end
64
-
65
134
  end
@@ -1,47 +1,73 @@
1
1
  module HQMF2
2
-
2
+ # Represents the logic that defines grouping of criteria and actions done on it.
3
3
  class Precondition
4
-
5
4
  include HQMF2::Utilities
6
-
7
- attr_reader :preconditions, :reference
8
-
9
- def initialize(entry, doc)
10
- @doc = doc
11
- @entry = entry
12
- @preconditions = @entry.xpath('./*/cda:precondition', HQMF2::Document::NAMESPACES).collect do |precondition|
13
- Precondition.new(precondition, @doc)
5
+
6
+ attr_reader :preconditions, :reference, :conjunction, :id
7
+
8
+ def self.parse(entry, doc, id_generator)
9
+ doc = doc
10
+ entry = entry
11
+ aggregation = entry.at_xpath('./cda:allTrue | ./cda:atLeastOneTrue | ./cda:allFalse | ./cda:atLeastOneFalse',
12
+ HQMF2::Document::NAMESPACES)
13
+
14
+ # Sets the reference criteria for the precondition (if it exists)
15
+ reference_def = entry.at_xpath('./*/cda:id', HQMF2::Document::NAMESPACES)
16
+ reference_def ||= entry.at_xpath('./cda:join/cda:templateId/cda:item', HQMF2::Document::NAMESPACES)
17
+ reference = Reference.new(reference_def) if reference_def
18
+
19
+ # Unless there is an aggregator, no further actions are necessary.
20
+ return new(id_generator.next_id, nil, [], false, reference) unless aggregation
21
+
22
+ precondition_entries = entry.xpath('./*/cda:precondition', HQMF2::Document::NAMESPACES)
23
+ preconditions = precondition_entries.collect do |precondition|
24
+ precondition = Precondition.parse(precondition, doc, id_generator)
25
+ # There are cases where a precondition may contain no references or preconditions, and should be ignored.
26
+ precondition.reference.nil? && precondition.preconditions.empty? ? nil : precondition
14
27
  end
15
- reference_def = @entry.at_xpath('./*/cda:id', HQMF2::Document::NAMESPACES)
16
- if !reference_def
17
- reference_def = @entry.at_xpath('./cda:join/cda:templateId/cda:item', HQMF2::Document::NAMESPACES)
18
- end
19
- if reference_def
20
- @reference = Reference.new(reference_def)
21
- end
22
- end
23
-
24
- # Return true of this precondition represents a conjunction with nested preconditions
25
- # or false of this precondition is a reference to a data criteria
26
- def conjunction?
27
- @preconditions.length>0
28
+ preconditions.compact!
29
+ handle_aggregation(id_generator, reference, preconditions, aggregation)
28
30
  end
29
-
30
- # Get the conjunction code, e.g. allTrue, allFalse
31
- # @return [String] conjunction code
32
- def conjunction_code
33
- if conjunction?
34
- @entry.at_xpath('./*[1]', HQMF2::Document::NAMESPACES).name
31
+
32
+ # "False" aggregators exist, and require special handling, so this manages that and returns the
33
+ # proper precondition.
34
+ def self.handle_aggregation(id_generator, reference, preconditions, aggregation, conjunction = nil)
35
+ negation = false
36
+ conjunction = aggregation.name
37
+ case conjunction
38
+ # DeMorgan's law is used to handle negated caes: e.g. to find if all are false, negate the "at least one true"
39
+ # check.
40
+ when 'allFalse'
41
+ negation = true
42
+ conjunction = 'atLeastOneTrue'
43
+ when 'atLeastOneFalse'
44
+ negation = true
45
+ conjunction = 'allTrue'
46
+ end
47
+ # Return the proper precondition given if a negation exists
48
+ if negation
49
+ # Wrap the negation in a seperate precondition which this will reference
50
+ precondition_wrapper = new(id_generator.next_id, conjunction, preconditions, true, reference)
51
+ new(id_generator.next_id, conjunction, [precondition_wrapper])
35
52
  else
36
- nil
53
+ new(id_generator.next_id, conjunction, preconditions, false, reference)
37
54
  end
38
55
  end
39
-
56
+
57
+ def initialize(id, conjunction, preconditions = [], negation = false, reference = nil)
58
+ @preconditions = preconditions || []
59
+ @conjunction = conjunction
60
+ @reference = reference
61
+ @negation = negation
62
+ @id = id
63
+ end
64
+
65
+ # Generates this classes hqmf-model equivalent
40
66
  def to_model
41
- pcs = preconditions.collect {|p| p.to_model}
42
- mr = reference ? reference.to_model : nil
43
- HQMF::Precondition.new(nil, pcs, mr, conjunction_code, false)
67
+ pcs = @preconditions.collect(&:to_model)
68
+ mr = @reference ? @reference.to_model : nil
69
+ cc = @conjunction
70
+ HQMF::Precondition.new(@id, pcs, mr, cc, @negation)
44
71
  end
45
72
  end
46
-
47
73
  end
@@ -0,0 +1,112 @@
1
+ module HQMF2
2
+ # Generates the Source Data Criteria from the entries in the HQMF
3
+ class SourceDataCriteriaHelper
4
+ # Generates an identifier based on the leftover elements included in the source data criteria.
5
+ def self.identifier(criteria)
6
+ sha256 = ''
7
+ sha256 << "#{criteria.code_list_id}:"
8
+ sha256 << "#{criteria.definition}:"
9
+ sha256 << "#{criteria.status}:"
10
+ sha256 << "#{criteria.specific_occurrence}:"
11
+ sha256 << "#{criteria.specific_occurrence_const}:"
12
+ sha256 << "#{criteria.variable}:"
13
+ sha256 << (criteria.children_criteria.nil? ? '<nil>:' : "#{criteria.children_criteria.sort.join(',')}:")
14
+
15
+ Digest::SHA256.hexdigest sha256
16
+ end
17
+
18
+ # Rejects any derived elements as they should never be used as source.
19
+ def self.should_reject?(dc)
20
+ dc.definition == 'derived'
21
+ end
22
+
23
+ # Removes unnecessary elements from a data criteria to create a source data criteria
24
+ def self.strip_non_sc_elements(dc)
25
+ if [HQMF::DataCriteria::SATISFIES_ANY, HQMF::DataCriteria::SATISFIES_ALL].include? dc.definition
26
+ dc.instance_variable_set(:@definition, 'derived')
27
+ end
28
+ dc.instance_variable_set(:@source_data_criteria, dc.id)
29
+ dc.instance_variable_set(:@field_values, {})
30
+ dc.instance_variable_set(:@temporal_references, [])
31
+ dc.instance_variable_set(:@subset_operators, [])
32
+ dc.instance_variable_set(:@value, nil)
33
+ dc.instance_variable_set(:@negation, false)
34
+ dc.instance_variable_set(:@negation_code_list_id, nil)
35
+ dc
36
+ end
37
+
38
+ # determins if a data criteria has any non-SDC fields set (i.e., those fields need to be stripped)
39
+ def self.already_stripped?(dc)
40
+ dc.field_values.blank? && dc.temporal_references.blank? && dc.subset_operators.blank? && dc.value.blank? && dc.negation.blank? && dc.negation_code_list_id.blank?
41
+ end
42
+
43
+ # Creates a data criteria based on an entry xml, removes any unnecessary elements (for the source),
44
+ # and adds a data criteria reference if none exist
45
+ def self.as_source_data_criteria(entry, data_criteria_references = {}, occurrences_map = {})
46
+ dc = DataCriteria.new(entry, data_criteria_references, occurrences_map)
47
+ dc.original_id = dc.id
48
+ unless dc.definition == 'derived' # && dc.temporal_references.blank? && dc.subset_operators.blank? && dc.value.blank? && dc.field_values.blank?
49
+ # add "_source" to the id to differentiate from the non-source
50
+ dc.id = "#{dc.id}_source"
51
+ end
52
+ dc = SourceDataCriteriaHelper.strip_non_sc_elements(dc)
53
+ # add it as a reference
54
+ if dc && (data_criteria_references[dc.id].nil? || data_criteria_references[dc.id].code_list_id.nil?)
55
+ data_criteria_references[dc.original_id] = dc
56
+ end
57
+
58
+ dc
59
+ end
60
+
61
+ # Check if there is an existing entry in the source data criteria list that matches the candidate passed in
62
+ # this is used to prevent adding duplicate source data criteria entries when one already exists
63
+ def self.find_existing_source_data_criteria(list, candidate)
64
+ list.each do |sdc|
65
+ # check if we have an exact match on an existing SDC
66
+ return sdc if SourceDataCriteriaHelper.identifier(sdc) == SourceDataCriteriaHelper.identifier(candidate)
67
+ # we have another existing copy of the specific occurrence (identified via the constant and occurrence lettering), use that rather than duplicating... there will not be an
68
+ # exact match for variables since a new child will have been generated
69
+ return sdc if !sdc.specific_occurrence_const.nil? && sdc.specific_occurrence_const == candidate.specific_occurrence_const && sdc.specific_occurrence == candidate.specific_occurrence
70
+ end
71
+ nil
72
+ end
73
+
74
+ # Given a list of criteria obtained from the XML, generate most of the source data criteria (since no explicit
75
+ # sources are given). After generating the source data criteria, filter the list to not include repeated,
76
+ # unnecessary sources, but maintain and return map of those that have been removed to those that they were replaced
77
+ # with.
78
+ def self.get_source_data_criteria_list(full_criteria_list, data_criteria_references = {}, occurrences_map = {})
79
+ # currently, this will erase the sources if the ids are the same, but will not correct references later on
80
+ source_data_criteria = full_criteria_list.map do |entry|
81
+ SourceDataCriteriaHelper.as_source_data_criteria(entry, data_criteria_references, occurrences_map)
82
+ end
83
+
84
+ collapsed_source_data_criteria_map = {}
85
+ uniq_source_data_criteria = {}
86
+ source_data_criteria.each do |sdc|
87
+ identifier = SourceDataCriteriaHelper.identifier(sdc)
88
+ if uniq_source_data_criteria.key? identifier
89
+ collapsed_source_data_criteria_map[sdc.original_id] = uniq_source_data_criteria[identifier].id
90
+ else
91
+ uniq_source_data_criteria[identifier] = sdc
92
+ end
93
+ end
94
+ unique = uniq_source_data_criteria.values.reject { |dc| SourceDataCriteriaHelper.should_reject?(dc) }
95
+
96
+ # we need an empty data criteria in source that acts as the target for the specific occurrence
97
+ # the data criteria that we are duplicating will eventually get turned into a specific occurrence
98
+ occurrences = unique.select {|dc| occurrences_map[dc.id] && dc.definition != 'derived' }
99
+ occurrences.each do |occurrence|
100
+ # do not create a nonspecific SDC for variables
101
+ unless occurrence.variable
102
+ dc = SourceDataCriteriaHelper.as_source_data_criteria(occurrence.entry)
103
+ dc.id = "#{dc.id}_nonSpecific"
104
+ dc.instance_variable_set(:@source_data_criteria, dc.id)
105
+ unique << dc unless SourceDataCriteriaHelper.find_existing_source_data_criteria(unique, dc)
106
+ end
107
+ end
108
+
109
+ [unique, collapsed_source_data_criteria_map]
110
+ end
111
+ end
112
+ end
@@ -3,35 +3,88 @@ module HQMF2
3
3
  # don't specify any restrictions on that value
4
4
  class AnyValue
5
5
  attr_reader :type
6
-
7
- def initialize(type='ANYNonNull')
8
- @type = type
6
+
7
+ def initialize(type = 'ANYNonNull')
8
+ @type = type
9
9
  end
10
-
10
+
11
+ # Generates this classes hqmf-model equivalent
11
12
  def to_model
12
13
  HQMF::AnyValue.new(@type)
13
- end
14
+ end
14
15
  end
15
-
16
+
16
17
  # Represents a bound within a HQMF pauseQuantity, has a value, a unit and an
17
18
  # inclusive/exclusive indicator
18
19
  class Value
19
20
  include HQMF2::Utilities
20
-
21
+
21
22
  attr_reader :type, :unit, :value
22
-
23
- def initialize(entry, default_type='PQ', force_inclusive=false)
23
+
24
+ def initialize(entry, default_type = 'PQ', force_inclusive = false, _parent = nil)
24
25
  @entry = entry
25
26
  @type = attr_val('./@xsi:type') || default_type
26
27
  @unit = attr_val('./@unit')
27
28
  @value = attr_val('./@value')
28
29
  @force_inclusive = force_inclusive
30
+
31
+ # FIXME: Remove below when lengthOfStayQuantity unit is fixed
32
+ @unit = 'd' if @unit == 'days'
29
33
  end
30
-
34
+
31
35
  def inclusive?
32
- attr_val("../@#{@entry.name}Closed") == 'true' || @force_inclusive
36
+ # If the high and low value are at any time the same, then it must be an inclusive value.
37
+ equivalent = attr_val('../cda:low/@value') == attr_val('../cda:high/@value')
38
+
39
+ # If and inclusivity value is set for any specific value, then mark the value as inclusive.
40
+ # IDEA: This could be limited in future iterations by including the parent type (temporal reference, subset code,
41
+ # etc.)
42
+ inclusive_temporal_ref? || inclusive_length_of_stay? || inclusive_basic_values? || inclusive_subsets? ||
43
+ equivalent || @force_inclusive
33
44
  end
34
-
45
+
46
+ # Check whether the temporal reference should be marked as inclusive
47
+ def inclusive_temporal_ref?
48
+ # FIXME: NINF is used instead of 0 sometimes...? (not in the IG)
49
+ # FIXME: Given nullFlavor, but IG uses it and nullValue everywhere...
50
+ less_than_equal_tr = attr_val('../@highClosed') == 'true' &&
51
+ (attr_val('../cda:low/@value') == '0' || attr_val('../cda:low/@nullFlavor') == 'NINF')
52
+ greater_than_equal_tr = attr_val('../cda:high/@nullFlavor') == 'PINF' &&
53
+ attr_val('../cda:low/@value')
54
+ # Both less and greater require lowClosed to be set to true
55
+ (less_than_equal_tr || greater_than_equal_tr) && attr_val('../@lowClosed') == 'true'
56
+ end
57
+
58
+ # Check whether the length of stay should be inclusive.
59
+ def inclusive_length_of_stay?
60
+ # lengthOfStay - EH111, EH108
61
+ less_than_equal_los = attr_val('../cda:low/@nullFlavor') == 'NINF' &&
62
+ attr_val('../@highClosed') != 'false'
63
+
64
+ greater_than_equal_los = attr_val('../cda:high/@nullFlavor') == 'PINF' &&
65
+ attr_val('../@lowClosed') != 'false'
66
+ # Both less and greater require that the type is PQ
67
+ (less_than_equal_los || greater_than_equal_los) && attr_val('@xsi:type') == 'PQ'
68
+ end
69
+
70
+ # Check is the basic values should be marked as inclusive, currently only checks for greater than case
71
+ def inclusive_basic_values?
72
+ # Basic values - EP65, EP9, and more
73
+ attr_val('../cda:high/@nullFlavor') == 'PINF' &&
74
+ attr_val('../cda:low/@value') &&
75
+ attr_val('../@lowClosed') != 'false' &&
76
+ attr_val('../@xsi:type') == 'IVL_PQ'
77
+ end
78
+
79
+ # Check if subset values should be marked as inclusive. Currently only handles greater than
80
+ def inclusive_subsets?
81
+ # subset - EP128, EH108
82
+ attr_val('../cda:low/@value') != '0' &&
83
+ !attr_val('../cda:high/@value') &&
84
+ attr_val('../@lowClosed') != 'false' &&
85
+ !attr_val('../../../../../qdm:subsetCode/@code').nil?
86
+ end
87
+
35
88
  def derived?
36
89
  case attr_val('./@nullFlavor')
37
90
  when 'DER'
@@ -40,7 +93,7 @@ module HQMF2
40
93
  false
41
94
  end
42
95
  end
43
-
96
+
44
97
  def expression
45
98
  if !derived?
46
99
  nil
@@ -48,53 +101,81 @@ module HQMF2
48
101
  attr_val('./cda:expression/@value')
49
102
  end
50
103
  end
51
-
104
+
105
+ # Generates this classes hqmf-model equivalent
52
106
  def to_model
53
- HQMF::Value.new(type,unit,value,inclusive?,derived?,expression)
107
+ HQMF::Value.new(type, unit, value, inclusive?, derived?, expression)
54
108
  end
55
109
  end
56
-
110
+
57
111
  # Represents a HQMF physical quantity which can have low and high bounds
58
112
  class Range
59
113
  include HQMF2::Utilities
60
114
  attr_accessor :low, :high, :width
61
-
62
- def initialize(entry, type=nil)
115
+
116
+ def initialize(entry, type = nil)
63
117
  @type = type
64
118
  @entry = entry
65
- if @entry
66
- @low = optional_value("#{default_element_name}/cda:low", default_bounds_type)
67
- @high = optional_value("#{default_element_name}/cda:high", default_bounds_type)
68
- @width = optional_value("#{default_element_name}/cda:width", 'PQ')
69
- end
119
+ return unless @entry
120
+ @low = optional_value("#{default_element_name}/cda:low", default_bounds_type)
121
+ @high = optional_value("#{default_element_name}/cda:high", default_bounds_type)
122
+ # Unset low bound to resolve verbose value bounds descriptions
123
+ @low = nil if (@high.try(:value) && @high.value.to_i > 0) && (@low.try(:value) && @low.value.try(:to_i) == 0)
124
+ @width = optional_value("#{default_element_name}/cda:width", 'PQ')
70
125
  end
71
-
126
+
72
127
  def type
73
128
  @type || attr_val('./@xsi:type')
74
129
  end
75
-
130
+
131
+ # Generates this classes hqmf-model equivalent
76
132
  def to_model
77
- lm = low ? low.to_model : nil
78
- hm = high ? high.to_model : nil
79
- wm = width ? width.to_model : nil
133
+ lm = low.try(:to_model)
134
+ hm = high.try(:to_model)
135
+ wm = width.try(:to_model)
80
136
  model_type = type
81
137
  if @entry.at_xpath('./cda:uncertainRange', HQMF2::Document::NAMESPACES)
82
138
  model_type = 'IVL_PQ'
83
139
  end
84
- HQMF::Range.new(model_type, lm, hm, wm)
140
+
141
+ if generate_any_value?(lm, hm)
142
+ # Generate AnyValue if the only elements in the range are AnyValues.
143
+ HQMF::AnyValue.new
144
+ elsif generate_value?(lm, hm)
145
+ # Generate a singel value if both low and high are the same
146
+ HQMF::Value.new(lm.type, nil, lm.value, lm.inclusive?, lm.derived?, lm.expression)
147
+ else
148
+ HQMF::Range.new(model_type, lm, hm, wm)
149
+ end
85
150
  end
86
-
151
+
152
+ # Check if are only AnyValue elements for low and high
153
+ def generate_any_value?(lm, hm)
154
+ (lm.nil? || lm.is_a?(HQMF::AnyValue)) && (hm.nil? || hm.is_a?(HQMF::AnyValue))
155
+ end
156
+
157
+ # Check if the value for the range should actually produce a single value instead of a range (if low and high are
158
+ # the same)
159
+ def generate_value?(lm, hm)
160
+ !lm.nil? && lm.try(:value) == hm.try(:value) && lm.try(:unit).nil? && hm.try(:unit).nil?
161
+ end
162
+
87
163
  private
88
-
164
+
165
+ # Either derives a value from a specific path or generates a new value (or returns nil if none found)
89
166
  def optional_value(xpath, type)
90
167
  value_def = @entry.at_xpath(xpath, HQMF2::Document::NAMESPACES)
91
- if value_def
92
- Value.new(value_def, type)
168
+ return unless value_def
169
+ if value_def['flavorId'] == 'ANY.NONNULL'
170
+ AnyValue.new
93
171
  else
94
- nil
172
+ created_value = Value.new(value_def, type)
173
+ # Return nil if no value was parsed
174
+ created_value if created_value.try(:value)
95
175
  end
96
176
  end
97
177
 
178
+ # Defines how the time based element should be described
98
179
  def default_element_name
99
180
  case type
100
181
  when 'IVL_PQ'
@@ -105,7 +186,8 @@ module HQMF2
105
186
  'cda:uncertainRange'
106
187
  end
107
188
  end
108
-
189
+
190
+ # Sets up the default bound type as either time based or a physical quantity
109
191
  def default_bounds_type
110
192
  case type
111
193
  when 'IVL_TS'
@@ -115,38 +197,38 @@ module HQMF2
115
197
  end
116
198
  end
117
199
  end
118
-
119
- # Represents a HQMF effective time which is a specialization of a interval
200
+
201
+ # Represents an HQMF effective time which is a specialization of an interval
120
202
  class EffectiveTime < Range
121
203
  def initialize(entry)
122
204
  super
123
205
  end
124
-
206
+
125
207
  def type
126
208
  'IVL_TS'
127
209
  end
128
210
  end
129
-
211
+
130
212
  # Represents a HQMF CD value which has a code and codeSystem
131
213
  class Coded
132
214
  include HQMF2::Utilities
133
-
215
+
134
216
  def initialize(entry)
135
217
  @entry = entry
136
218
  end
137
-
219
+
138
220
  def type
139
221
  attr_val('./@xsi:type') || 'CD'
140
222
  end
141
-
223
+
142
224
  def system
143
225
  attr_val('./@codeSystem')
144
226
  end
145
-
227
+
146
228
  def code
147
229
  attr_val('./@code')
148
230
  end
149
-
231
+
150
232
  def code_list_id
151
233
  attr_val('./@valueSet')
152
234
  end
@@ -166,103 +248,201 @@ module HQMF2
166
248
  def unit
167
249
  nil
168
250
  end
169
-
251
+
252
+ # Generates this classes hqmf-model equivalent
170
253
  def to_model
171
254
  HQMF::Coded.new(type, system, code, code_list_id, title)
172
255
  end
173
-
174
256
  end
175
-
257
+ # Represents a subset of a specific group (the first in the group, the sum of the group, etc.)
176
258
  class SubsetOperator
177
259
  include HQMF2::Utilities
178
260
 
179
261
  attr_reader :type, :value
262
+ ORDER_SUBSETS = %w(FIRST SECOND THIRD FOURTH FIFTH)
263
+ LAST_SUBSETS = %w(LAST RECENT)
264
+ TIME_SUBSETS = %w(DATEDIFF TIMEDIFF)
265
+ QDM_TYPE_MAP = { 'QDM_LAST:' => 'RECENT', 'QDM_SUM:SUM' => 'COUNT' }
180
266
 
181
267
  def initialize(entry)
182
268
  @entry = entry
183
- @type = attr_val('./cda:subsetCode/@code')
269
+
270
+ sequence_number = attr_val('./cda:sequenceNumber/@value')
271
+ qdm_subset_code = attr_val('./qdm:subsetCode/@code')
272
+ subset_code = attr_val('./cda:subsetCode/@code')
273
+ if sequence_number
274
+ @type = ORDER_SUBSETS[sequence_number.to_i - 1]
275
+ else
276
+ @type = translate_type(subset_code, qdm_subset_code)
277
+ end
278
+
279
+ value_def = handle_value_definition
280
+ @value = HQMF2::Range.new(value_def, 'IVL_PQ') if value_def && !@value
281
+ end
282
+
283
+ # Return the value definition (what to calculate it on) associated with this subset.
284
+ # Other values, such as type and value, may be modified depending on this value.
285
+ def handle_value_definition
184
286
  value_def = @entry.at_xpath('./*/cda:repeatNumber', HQMF2::Document::NAMESPACES)
185
- if !value_def
287
+ unless value_def
288
+ # TODO: HQMF needs better differentiation between SUM & COUNT...
289
+ # currently using presence of repeatNumber...
290
+ @type = 'SUM' if @type == 'COUNT'
186
291
  value_def = @entry.at_xpath('./*/cda:value', HQMF2::Document::NAMESPACES)
187
292
  end
293
+
294
+ # TODO: Resolve extracting values embedded in criteria within outboundRel's
295
+ if @type == 'SUM'
296
+ value_def = @entry.at_xpath('./*/*/*/cda:value', HQMF2::Document::NAMESPACES)
297
+ end
298
+
188
299
  if value_def
189
300
  value_type = value_def.at_xpath('./@xsi:type', HQMF2::Document::NAMESPACES)
190
- if String.try_convert(value_type) == "ANY"
191
- @value = HQMF2::AnyValue.new()
192
- end
301
+ @value = HQMF2::AnyValue.new if String.try_convert(value_type) == 'ANY'
193
302
  end
194
303
 
195
- if value_def && !@value
196
- @value = HQMF2::Range.new(value_def, 'IVL_PQ')
304
+ value_def
305
+ end
306
+
307
+ # Take a qdm type code to map it to a subset operator, or failing at finding that, return the given subset code.
308
+ def translate_type(subset_code, qdm_subset_code)
309
+ combined = "#{qdm_subset_code}:#{subset_code}"
310
+ if QDM_TYPE_MAP[combined]
311
+ QDM_TYPE_MAP[combined]
312
+ else
313
+ subset_code
197
314
  end
198
315
  end
199
316
 
317
+ # Generates this classes hqmf-model equivalent
200
318
  def to_model
201
319
  vm = value ? value.to_model : nil
202
320
  HQMF::SubsetOperator.new(type, vm)
203
321
  end
204
322
  end
205
-
323
+
324
+ # Represents a time bounded reference. Wraps the "Range" class
206
325
  class TemporalReference
207
326
  include HQMF2::Utilities
208
-
327
+
209
328
  attr_reader :type, :reference, :range
210
329
 
330
+ # Use updated mappings to HDS temporal reference types (as used in SimpleXML Parser)
331
+ # https://github.com/projecttacoma/simplexml_parser/blob/fa0f589d98059b88d77dc3cb465b62184df31671/lib/model/types.rb#L167
332
+ UPDATED_TYPES = {
333
+ 'EAOCW' => 'EACW',
334
+ 'EAEORECW' => 'EACW',
335
+ 'EAOCWSO' => 'EACWS',
336
+ 'EASORECWS' => 'EACWS',
337
+ 'EBOCW' => 'EBCW',
338
+ 'EBEORECW' => 'EBCW',
339
+ 'EBOCWSO' => 'EBCWS',
340
+ 'EBSORECWS' => 'EBCWS',
341
+ 'ECWSO' => 'ECWS',
342
+ 'SAOCWEO' => 'SACWE',
343
+ 'SAEORSCWE' => 'SACWE',
344
+ 'SAOCW' => 'SACW',
345
+ 'SASORSCW' => 'SACW',
346
+ 'SBOCWEO' => 'SBCWE',
347
+ 'SBEORSCWE' => 'SBCWE',
348
+ 'SBOCW' => 'SBCW',
349
+ 'SBSORSCW' => 'SBCW',
350
+ 'SCWEO' => 'SCWE',
351
+ 'OVERLAPS' => 'OVERLAP'
352
+ }
353
+
211
354
  def initialize(entry)
212
355
  @entry = entry
213
- @type = attr_val('./@typeCode')
356
+ @type = UPDATED_TYPES[attr_val('./@typeCode')] || attr_val('./@typeCode')
214
357
  @reference = Reference.new(@entry.at_xpath('./*/cda:id', HQMF2::Document::NAMESPACES))
215
- range_def = @entry.at_xpath('./cda:pauseQuantity', HQMF2::Document::NAMESPACES)
216
- if range_def
217
- @range = HQMF2::Range.new(range_def, 'PQ')
218
- end
358
+ range_def = @entry.at_xpath('./qdm:temporalInformation/qdm:delta', HQMF2::Document::NAMESPACES)
359
+ @range = HQMF2::Range.new(range_def, 'IVL_PQ') if range_def
219
360
  end
220
-
361
+
362
+ # Generates this classes hqmf-model equivalent
221
363
  def to_model
222
364
  rm = range ? range.to_model : nil
223
365
  HQMF::TemporalReference.new(type, reference.to_model, rm)
224
- end
366
+ end
225
367
  end
226
368
 
227
- # Represents a HQMF reference to a data criteria that has a given type
369
+ # Represents a HQMF reference to a data criteria that has a given type
228
370
  class TypedReference
229
371
  include HQMF2::Utilities
230
372
  attr_accessor :id, :type, :mood
231
373
 
232
374
  # Create a new HQMF::Reference
233
375
  # @param [String] id
234
- def initialize(entry)
376
+ def initialize(entry, type = nil, verbose = false)
235
377
  @entry = entry
236
378
  @type = type || attr_val('./@classCode')
237
379
  @mood = attr_val('./@moodCode')
238
380
  @entry = entry.elements.first unless entry.at_xpath('./@extension')
381
+ @verbose = verbose
239
382
  end
240
383
 
384
+ # Generate the reference for the typed reference to use
241
385
  def reference
242
- attr_val('./@extension')
386
+ value = "#{attr_val('./@extension')}_#{attr_val('./@root')}"
387
+ strip_tokens(value)
243
388
  end
244
389
 
390
+ # Generates this classes hqmf-model equivalent
245
391
  def to_model
246
- HQMF::TypedReference.new(reference,@type,@mood)
392
+ HQMF::TypedReference.new(reference, @type, @mood)
247
393
  end
248
-
249
394
  end
250
395
 
251
396
  # Represents a HQMF reference from a precondition to a data criteria
252
397
  class Reference
253
398
  include HQMF2::Utilities
254
-
399
+
255
400
  def initialize(entry)
256
401
  @entry = entry
257
402
  end
258
-
403
+
404
+ # Generates the id to use for a reference
259
405
  def id
260
- attr_val('./@extension')
406
+ if @entry.is_a? String
407
+ @entry
408
+ else
409
+ id = strip_tokens("#{attr_val('./@extension')}_#{attr_val('./@root')}")
410
+ # Handle MeasurePeriod references for calculation code
411
+ id = 'MeasurePeriod' if id.try(:start_with?, 'measureperiod')
412
+ id
413
+ end
261
414
  end
262
-
415
+
416
+ # Generates this classes hqmf-model equivalent
263
417
  def to_model
264
418
  HQMF::Reference.new(id)
265
419
  end
266
420
  end
267
-
421
+
422
+ # Creates a Data Criteria given a map of options, and is used when full
423
+ # criteria parsing is not necessary.
424
+ class DataCriteriaWrapper
425
+ attr_accessor :status, :value, :effective_time
426
+ attr_accessor :temporal_references, :subset_operators, :children_criteria
427
+ attr_accessor :derivation_operator, :negation, :negation_code_list_id, :description
428
+ attr_accessor :field_values, :source_data_criteria, :specific_occurrence_const
429
+ attr_accessor :specific_occurrence, :comments
430
+ attr_accessor :id, :title, :definition, :variable, :code_list_id, :value, :inline_code_list
431
+
432
+ def initialize(opts = {})
433
+ opts.each { |k, v| instance_variable_set("@#{k}", v) }
434
+ end
435
+
436
+ # Generates this classes hqmf-model equivalent
437
+ def to_model
438
+ mv = @value ? @value.to_model : nil
439
+ met = @effective_time ? @effective_time.to_model : nil
440
+ mtr = @temporal_references
441
+ mso = @subset_operators
442
+ HQMF::DataCriteria.new(@id, @title, nil, @description, @code_list_id, @children_criteria,
443
+ @derivation_operator, @definition, @status, mv, field_values, met, @inline_code_list,
444
+ @negation, @negation_code_list_id, mtr, mso, @specific_occurrence,
445
+ @specific_occurrence_const, @source_data_criteria, @comments, @variable)
446
+ end
447
+ end
268
448
  end