Skip to content
This repository has been archived by the owner on Sep 3, 2021. It is now read-only.

Patient Importer - Comm from Provider to Provider - Wrong ID #333

Open
grexican opened this issue Nov 26, 2015 · 2 comments
Open

Patient Importer - Comm from Provider to Provider - Wrong ID #333

grexican opened this issue Nov 26, 2015 · 2 comments

Comments

@grexican
Copy link

In patient_importer.rb:
generate_importer(Cat1::ProcedureImporter, nil, '2.16.840.1.113883.3.560.1.129'), #comm from provider to provider

If I look at the spec, the code should be ...1.29 not ...1.129. There's an extra 1 in there.1.129is thenegation: trueversion ofcommunication_from_provider_to_provideraccording to thehqmf_template_oid_map`.

I think anyway :) If I'm wrong, please let me know why. FWIW, I had to edit my records documents in my DB to be 1.29 instead of 1.129 to pass Measure 0089 QRDA Cat I Test in Cypress.

@grexican
Copy link
Author

The following monkeypatch, under the assumption it should be 1.29 and not 1.129, makes measure 0089 passable in cypress.

module HealthDataStandards
  module Import
    module Cat1

      # This class is the central location for taking a QRDA Cat 1 XML document and converting it
      # into the processed form we store in MongoDB. The class does this by running each measure
      # independently on the XML document
      #
      # This class is a Singleton. It should be accessed by calling PatientImporter.instance
      class PatientImporter
        alias_method :original_initialize, :initialize

        def initialize
          original_initialize

          # MONKEY PATCH: USING 1.129 (negative) instead of 1.29 (positive) for P2P Communication
          begin
            index = @section_importers[:procedures].find_index { |p| p.hqmf_oid == '2.16.840.1.113883.3.560.1.129'}

            if index.present?
              ptpcomm = @section_importers[:procedures][index]
              ptpcomm.hqmf_oid = '2.16.840.1.113883.3.560.1.29'
              @section_importers[:procedures][index] = ptpcomm

              puts "monkey patched initialize: #{@section_importers[:procedures][index].to_yaml}"
            else
              puts "MONKEY PATCH FAILED!"
            end

          rescue
            puts "Error #{$!}"
          end
        end

      end
    end
  end
end

@grexican
Copy link
Author

grexican commented Dec 3, 2015

Actually the issue, I think, is much bigger than this. As I said above, it's not just the OID, but it's the NEGATIVE OID. Well that negative (NOT DONE) version needs to be accounted for to. And from what I see, it's not accounted for anywhere in the importer.

When generating QRDA III documents and doing performance calculations, everything still seems to come out fine. But when re-generating QRDA I documents, things don't go so well. So in order to combat this, I did 2 things:

  1. I implemented a negative version of each code. Usually that's adding 100 to the last numeric sequence in the OID. So if ti's 1.2.3.4 then the negative version of that OID is 1.2.3.104. If it's 1.2.3.95 then the negative version is 1.2.3.195. In the few cases that doesn't follow suit, the naming convention seems to be NOT DONE. So if the OID name is "Medication, Given" then the negative version is "Medication, Given not done." So given that, I implemented an automatic find-and-use negative version of codes passed in that hinges off of the negationInd flag.
  2. There were a bunch of codes in the patient importer that were incorrectly pointed to the negative version of the code. So I removed those and re-add them from the positive.

Here's the full monkey patch. I'm more than happy to turn this into a pull request and update the core code. I just need to know that it will actually be merged. I don't want to waste my time. This project seems very inactive. So I'm at least putting this here for the sake of others.

NOTE: with this monkey patch, I get 100% success flags on all ambulatory and inpatient Cypress tests on the latest package.

module HealthDataStandards
  module Import
    module Cat1

      class PatientImporter
        alias_method :original_initialize, :initialize

        def initialize
          original_initialize

          # MONKEY PATCH: USING 1.129 (negative) instead of 1.29 (positive) for Provider To Provider Communication
          # MONKEY PATCH: USING 1.103 (negative) instead of 1.3 (positive) for Diagnostic Study, Performed
          # MONKEY PATCH: USING 1.131 (negative) instead of 1.31 (positive) for Communication: From Provider to Patient
          # MONKEY PATCH: USING 1.110 (negative) instead of 1.10 (positive) for Device, Applied
          # MONKEY PATCH: Missing Substance, Administered
          begin
            index = @section_importers[:procedures].find_index { |p| p.hqmf_oid == '2.16.840.1.113883.3.560.1.129'}

            if index.present?
              importer = generate_importer(Cat1::ProcedureImporter, nil, '2.16.840.1.113883.3.560.1.29') #comm from provider to provider
              @section_importers[:procedures][index] = importer

              # puts "monkey patched initialize: #{@section_importers[:procedures][index].to_yaml}"
            else
              puts "MONKEY PATCH FAILED! - 129"
            end

            index = @section_importers[:procedures].find_index { |p| p.hqmf_oid == '2.16.840.1.113883.3.560.1.103'}

            if index.present?
              importer = generate_importer(CDA::ProcedureImporter, "./cda:entry/cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.18']", '2.16.840.1.113883.3.560.1.3', 'performed') #diagnostic study performed
              @section_importers[:procedures][index] = importer

              # puts "monkey patched initialize: #{@section_importers[:procedures][index].to_yaml}"
            else
              puts "MONKEY PATCH FAILED! - 103"
            end

            index = @section_importers[:procedures].find_index { |p| p.hqmf_oid == '2.16.840.1.113883.3.560.1.131'}

            if index.present?
              importer = generate_importer(CDA::ProcedureImporter, "./cda:entry/cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.3']", '2.16.840.1.113883.3.560.1.31') #comm from provider to patient
              @section_importers[:procedures][index] = importer

              # puts "monkey patched initialize: #{@section_importers[:procedures][index].to_yaml}"
            else
              puts "MONKEY PATCH FAILED! - 131"
            end

            index = @section_importers[:medical_equipment].find_index { |p| p.hqmf_oid == '2.16.840.1.113883.3.560.1.110'}

            if index.present?
              importer = generate_importer(CDA::MedicalEquipmentImporter, "./cda:entry/cda:procedure[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.7']", '2.16.840.1.113883.3.560.1.10', 'applied')
              @section_importers[:medical_equipment][index] = importer

              # puts "monkey patched initialize: #{@section_importers[:procedures][index].to_yaml}"
            else
              puts "MONKEY PATCH FAILED! - 110"
            end


            index = @section_importers[:medications].find_index { |p| p.hqmf_oid == '2.16.840.1.113883.3.560.1.14'}

            if index.present?
              importer = generate_importer(CDA::MedicationImporter, "./cda:entry/cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.42']/cda:entryRelationship/cda:substanceAdministration[cda:templateId/@root='2.16.840.1.113883.10.20.22.4.16' and cda:text[not(contains(text(), 'Substance'))] ]", '2.16.840.1.113883.3.560.1.14', 'administered') #medication administered
              @section_importers[:medications][index] = importer

              importer = generate_importer(CDA::MedicationImporter, "./cda:entry/cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.42']/cda:entryRelationship/cda:substanceAdministration[cda:templateId/@root='2.16.840.1.113883.10.20.22.4.16' and cda:text[contains(text(), 'Substance')] ]", '2.16.840.1.113883.3.560.1.64', 'administered') # substance administered
              @section_importers[:medications] << importer

              # puts "monkey patched initialize: #{@section_importers[:procedures][index].to_yaml}"
            else
              puts "MONKEY PATCH FAILED! - 14"
            end

          rescue  => e
            puts "OOPS! #{e.inspect}"
            puts e.backtrace
          end
        end

        # def import_sections(record, doc)
        #
        #   context = doc.xpath("/cda:ClinicalDocument/cda:component/cda:structuredBody/cda:component/cda:section[cda:templateId/@root = '2.16.840.1.113883.10.20.24.2.1']")
        #   nrh = CDA::NarrativeReferenceHandler.new
        #   nrh.build_id_map(doc)
        #   @section_importers.each do |section, entry_packages|
        #     entry_packages.each do |entry_package|
        #       puts "#{section.to_json} - #{entry_package.to_json} - #{entry_package.package_entries(context, nrh).to_json}" if section.to_s == 'procedures' && entry_package.package_entries(context, nrh).length > 0
        #       record.send(section) << entry_package.package_entries(context, nrh)
        #     end
        #   end
        #end

      end
    end
  end
end

module HealthDataStandards
  module Import
    module CDA
      class SectionImporter

        private

        alias_method :original_extract_code, :extract_code

        # MONKEY PATCH: Only return code_hash if a code was found (fix for codeClass="UNK")
        # MONKEY PATCH: template generators expect code_system not codeSystem
        def extract_code(parent_element, code_xpath, code_system=nil)
          code_hash = original_extract_code parent_element, code_xpath, code_system

          code_hash = nil unless code_hash.present? && code_hash['code'].present?

          if code_hash.present?
            code_hash['code_system'] = code_hash['codeSystem'] if code_hash['codeSystem']
            code_hash['code_system_oid'] = code_hash['codeSystemOid'] if code_hash['codeSystemOid']
          end

          code_hash
        end

      end
    end
  end
end

module HealthDataStandards
  module Import
    module Cat1
      class EntryPackage

        attr_accessor :oid_hash, :status_hash

        alias_method :original_initialize, :initialize

        def initialize (type, oid, stat = nil)
          begin
            if oid.is_a?(Hash)
              self.oid_hash = oid
              oid = oid[:positive]
            else
              self.oid_hash = { positive: oid, negative: find_negative(oid) }
            end

            if stat.is_a?(Hash)
              self.status_hash = stat
              stat = stat[:positive]
            else
              self.status_hash = { positive: stat }
              self.status_hash[:negative] = "not " + stat if stat.present?
            end

            return original_initialize(type, oid, stat)
          rescue => e
            puts "OOPS! #{e.inspect}"
            puts e.backtrace
          end
        end

        def find_negative(oid)
          neg_oid = oid.dup # copy
          ri = neg_oid.rindex('.')
          rn = neg_oid[ri + 1, 10].to_i

          if rn < 1000
            rn = rn + 100
          else
            rn = '1' + rn.to_s
          end

          neg_oid = neg_oid[0, ri + 1] + rn.to_s

          ret = oid # default ret if can't find

          by_id = HealthDataStandards::Export::QRDA::EntryTemplateResolver.hqmf_qrda_oid_map.select { |e|
            e['hqmf_oid'] == oid
          }

          if by_id.length == 1
            # found just one positive... let's do it

            negs = HealthDataStandards::Export::QRDA::EntryTemplateResolver.hqmf_qrda_oid_map.select { |e|
              e['qrda_oid'] == by_id[0]['qrda_oid'] && (e['hqmf_oid'] == neg_oid || e['hqmf_name'] == by_id[0]['hqmf_name'] + " not done")
            }

            if negs.length == 1
              ret = negs[0]['hqmf_oid']
              puts "  FOUND NEG FOR #{oid}: #{negs[0].to_json}"
              puts " NEG SET, BUT ID MISMATCH FOR #{oid}: #{ret} != #{neg_oid}" if neg_oid != ret
            else
              puts "  NO NEG FOR #{oid}: neg_by_name.length: #{negs.length}"
            end
          else
            puts "  NO NEG SET FOR #{oid}: by_id.length: #{by_id.length}"
          end

          #puts " NEG SET: #{ret} for #{oid}" if oid != ret

          return ret
        end

        def select_oid(entry)
          return self.oid_hash[:positive] unless entry.negation_ind
          return self.oid_hash[:negative] if entry.negation_ind
        end

        def select_status(entry)
          return self.status_hash[:positive] unless entry.negation_ind
          return self.status_hash[:negative] if entry.negation_ind
        end

        def package_entries (doc, nrh)
          entries = self.importer_type.create_entries(doc, nrh)
          entries.each do |entry|

            begin
              entry.oid = self.select_oid(entry)
              entry.status = self.select_status(entry)
            rescue
              "DOH! #{$!}"
            end

          end
          entries
        end
      end
    end
  end
end

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant