# frozen_string_literal: true module CqmValidators class MeasureValidator include BaseValidator def initialize(template_oid) @template_oid = template_oid end def validate(file, data = {}) @errors = [] @doc = get_document(file) @doc.root.add_namespace_definition('cda', 'urn:hl7-org:v3') measure_ids = CQM::Measure.pluck(:hqmf_id) doc_measure_ids = @doc.xpath(measure_selector).map(&:value).map(&:upcase) # list of all of the set ids in the QRDA doc_neutral_ids = @doc.xpath(neutral_measure_selector).map(&:value).map(&:upcase).sort # list of all of the setids in the QRDA that are also in the bundle, includes duplicates if code appears twice in document bundle_neutral_ids = CQM::Measure.distinct(:hqmf_set_id) doc_bundle_neutral_ids = doc_neutral_ids - (doc_neutral_ids - bundle_neutral_ids) validate_measure_ids(doc_measure_ids, measure_ids, data) validate_set_ids(doc_neutral_ids, doc_bundle_neutral_ids, data) validate_measure_ids_set_ids_usage(doc_bundle_neutral_ids, doc_measure_ids, data) if validate_no_repeating_measure_population_ids(data) @errors end private # returns true if there are no repeating measures, check to see that the measure id usage is correct def validate_no_repeating_measure_population_ids(data = {}) no_duplicate_measures = true doc_population_ids = @doc.xpath(measure_population_selector).map(&:value).map(&:upcase).sort duplicates = doc_population_ids.group_by { |e| e }.select { |_k, v| v.size > 1 }.map(&:first) duplicates.each do |duplicate| begin measure_id = @doc.xpath(find_measure_node_for_population(duplicate)).at_xpath("cda:reference/cda:externalDocument/cda:id[./@root='2.16.840.1.113883.4.738']/@extension") @errors << build_error("Population #{duplicate} for Measure #{measure_id.value} reported more than once", '/', data[:file_name]) rescue @errors << build_error("Population #{duplicate} for reported more than once", '/', data[:file_name]) end no_duplicate_measures = false end no_duplicate_measures end def validate_measure_ids(doc_measure_ids, measure_ids, data = {}) (doc_measure_ids - measure_ids).map do |hqmf_id| @errors << build_error("Invalid HQMF ID Found: #{hqmf_id}", '/', data[:file_name]) end end def validate_set_ids(doc_neutral_ids, doc_bundle_neutral_ids, data = {}) # an error will be returned for all of the setids that are in the QRDA that aren't in the bundle (doc_neutral_ids - doc_bundle_neutral_ids).map do |hqmf_set_id| @errors << build_error("Invalid HQMF Set ID Found: #{hqmf_set_id}", '/', data[:file_name]) end end # does not work if the same measure is reported more than once, nested under the repeating measures test def validate_measure_ids_set_ids_usage(doc_bundle_neutral_ids, doc_measure_ids, data = {}) # for each of the setIds that are in the bundle, check that they are for the correct measure id entries_start_position = @doc.xpath(first_entry) previous = '' index = 1 doc_bundle_neutral_ids.each do |hqmf_set_id| # selects the measure id that is in the same entry as the set id # iterates through multiple instances of the same setId index = if previous == hqmf_set_id index + 1 else 1 end measure_id_entry = doc_measure_ids[(@doc.xpath(location_of_set_id(hqmf_set_id, index)) - entries_start_position)] previous = hqmf_set_id # queries database to see if there is a measure with the combindation of setId and measureId if CQM::Measure.where(hqmf_id: measure_id_entry, hqmf_set_id: hqmf_set_id).empty? @errors << build_error("Invalid HQMF Set ID Found: #{hqmf_set_id} for HQMF ID: #{measure_id_entry}", '/', data[:file_name]) end end end def measure_selector '/cda:ClinicalDocument/cda:component/cda:structuredBody/cda:component/cda:section/cda:entry' \ "/cda:organizer[./cda:templateId[@root='#{@template_oid}']]/cda:reference[@typeCode='REFR']" \ "/cda:externalDocument[@classCode='DOC']/cda:id[@root='2.16.840.1.113883.4.738']/@extension" end # finds all of the setIds in the QRDA document def neutral_measure_selector '/cda:ClinicalDocument/cda:component/cda:structuredBody/cda:component/cda:section/cda:entry' \ "/cda:organizer[./cda:templateId[@root='#{@template_oid}']]/cda:reference[@typeCode='REFR']" \ "/cda:externalDocument[@classCode='DOC']/cda:setId/@root" end # finds the node index of the first entry element in the measure template def first_entry "count(//cda:entry[cda:organizer[./cda:templateId[@root='#{@template_oid}']]" \ "/cda:reference[@typeCode='REFR']/cda:externalDocument[@classCode='DOC']" \ "/cda:id[@root='2.16.840.1.113883.4.738']][1]/preceding-sibling::*)+1" end # finds the node index of the extry that the specified setId is in, index is used if the same setId appears twice def location_of_set_id(set_id, index) "count(//cda:entry[cda:organizer[./cda:templateId[@root='#{@template_oid}']]" \ "/cda:reference[@typeCode='REFR']/cda:externalDocument[@classCode='DOC']" \ "/cda:setId[@root[contains(translate(.,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLOMNOPQRSTUVWXYZ')" \ ",'#{set_id}')]]][#{index}]/preceding-sibling::*)+1" end def measure_population_selector '/cda:ClinicalDocument/cda:component/cda:structuredBody/cda:component/cda:section/cda:entry' \ "/cda:organizer[./cda:templateId[@root='2.16.840.1.113883.10.20.27.3.1']]/cda:component" \ "/cda:observation[./cda:templateId[@root='2.16.840.1.113883.10.20.27.3.5']]/cda:reference" \ '/cda:externalObservation/cda:id/@root' end def find_measure_node_for_population(id) '/cda:ClinicalDocument/cda:component/cda:structuredBody/cda:component/cda:section/cda:entry' \ "/cda:organizer[ ./cda:templateId[@root='2.16.840.1.113883.10.20.27.3.1']" \ "and ./cda:component/cda:observation[./cda:templateId[@root='2.16.840.1.113883.10.20.27.3.5']]/cda:reference" \ "/cda:externalObservation/cda:id[@root[contains(translate(.,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLOMNOPQRSTUVWXYZ')" \ ",'#{id.upcase}')]]]" end end end