class Era835Parser::Parser

Constants

ADJUSTMENT_CODES
ADJUSTMENT_GROUP_CODES
CLAIM_STATUS_CODES
PROVIDER_LEVEL_ADJUSTMENTS
REMARK_CODES

Attributes

file[R]
file_path[R]

Public Class Methods

new(**options) click to toggle source
# File lib/era_835_parser/parser.rb, line 15
def initialize(**options)
  @file_path = options[:file_path]
  @file = options[:file]
end

Public Instance Methods

parse() click to toggle source
# File lib/era_835_parser/parser.rb, line 20
def parse
  # hash initialization
  era = Hash.new
  checks = Hash.new
  check = Hash.new
  line_items = Hash.new
  adjustment_groups = Hash.new
  adjustments = Hash.new
  individual_era = Hash.new
  individual_line_item = Hash.new
  check_number = ''
  era_text = "--------------------------------------------------------------------------------------------------------------------------------------------------------\n"

  # counters
  adjustment_counter = 0
  adjustment_counter_a = -1
  svc_counter = 0

  # trigger variables
  adjustments_start = false
  checks_start = false
  eras_start = false
  next_line_check_number = false
  next_line_address = false
  next_line_city = false
  next_line_tax_id = false
  next_line_payer_claim_control = false
  next_line_claim_statement_period = false
  next_line_line_item = false
  next_line_adjustment_group = false

  # file type
  file_type = ''

  # loops
  payer_identification_loop = false
  payee_identification_loop = false
  header_number_loop = false
  claim_payment_information_loop = false
  patient_loop = false
  rendering_provider_loop = false
  service_payment_information_loop = false
  bpr_amount = ''
  bpr_date = ''
  receive_date = false
  claim_date_start = false
  claim_date_end = false
  service_date = false
  floating_adjustment_group_code = nil
  returned_reference_number = false

  file_or_file_path = !file.nil? ? file : file_path
  opened_file = file_or_file_path.respond_to?(:write) ? file_or_file_path : open(file_or_file_path)
  opened_file.readlines.each do |line|
    if line.include?("ISA")
      file_type = "machine_readable"
    elsif line.include?("Dear:")
      file_type = "human_readable"
    end

    if file_type == "human_readable"
      era_text += line if eras_start && line !~ /-{10,}/i

      if line.include?("Dear:")
        era[:addressed_to] = line.gsub("Dear:", "").strip
      end

      if line !~ /={10,}/i && adjustments_start == true
        adjustment = Hash.new
        adjustment[:adjustment_date] = /\d+\/\d+\/\d+/.match(line)[0].strip if !/\d+\/\d+\/\d+/.match(line).nil?
        adjustment[:provider_id] = /\d+\/\d+\/\d+\s+\d+\s+[^\s]+/.match(line)[0].split(" ")[1].strip if !/\d+\/\d+\/\d+\s+\d+\s+[^\s]+/.match(line).nil?
        adjustment[:reference_id] = /\d+\/\d+\/\d+\s+[^\.]+/.match(line)[0].split(" ").each_with_index.map { |x,i| (/\d+\/\d+\/\d+\s+[^\.]+/.match(line)[0].split(" ").count - 1) > i && i > 1 ? x.strip : '' }.join(" ").strip if !/\d+\/\d+\/\d+\s+[^\.]+/.match(line).nil?
        adjustment[:adjustment_amount] = (/\d+\/\d+\/\d+\s+[^\.]+\.\d+/.match(line)[0].split(" ")[-1].strip.to_f * 100).round().to_i if !/\d+\/\d+\/\d+\s+[^\.]+\.\d+/.match(line).nil?
        adjustment[:reason] = line.gsub(/\d+\/\d+\/\d+\s+[^\.]+\.\d+/, "").strip
        adjustments[adjustment_counter] = adjustment
        adjustment_counter += 1
      end

      if line !~ /={10,}/i && checks_start == true && line !~ /^\s+$/ && line !~ /-{10,}/i
        check = Hash.new
        check[:check_number] = /^[^\s]+(?=\s)/.match(line)[0] if !/^[^\s]+(?=\s)/.match(line).nil?
        check[:amount] = (/^[^\s]+\s+\d+\.\d+(?=\s)/.match(line)[0].split(" ")[1].strip.to_f * 100).round().to_i if !/^[^\s]+\s+\d+\.\d+(?=\s)/.match(line).nil?
        check[:number_of_claims] = /^[^\s]+\s+\d+\.\d+\s+\d+(?=\s)/.match(line)[0].split(" ")[2].strip.to_i if !/^[^\s]+\s+\d+\.\d+\s+\d+(?=\s)/.match(line).nil?
        check[:npi_tax_id] = /^[^\s]+\s+\d+\.\d+\s+\d+\s+[^\s]+/.match(line)[0].split(" ")[3].strip if !/^[^\s]+\s+\d+\.\d+\s+\d+\s+[^\s]+/.match(line).nil?
        check[:date] = /\d+\/\d+\/\d+/.match(line)[0] if !/\d+\/\d+\/\d+/.match(line).nil?
        check[:payee] = line.gsub(check[:check_number].to_s, "").gsub(check[:npi_tax_id].to_s, "").gsub(check[:amount].to_s, "").gsub(/\d/, "").gsub(/\./, "").gsub(/\//, "").strip
        checks[check[:check_number]] = check
      end

      if next_line_line_item
        individual_line_item = Hash.new
        adjustment_groups = Hash.new
      end

      if line.include?("Line Item:") || line =~ /-{10,}/i || line =~ /^\s+$/
        next_line_adjustment_group = false
      end

      if next_line_adjustment_group &&
        individual_adjustment_group_item = Hash.new
        individual_adjustment_group_item[:adjustment_group] = /.+\s+\-?\d+\.\d+/.match(line)[0].strip.split(/\s+\-?\d+/)[0].strip if !/.+\s+\-?\d+\.\d+/.match(line).nil?
        individual_adjustment_group_item[:adjustment_amount] = (/\-?\d+\.\d+/.match(line)[0].strip.to_f * 100).round().to_i if !/\-?\d+\.\d+/.match(line).nil?
        individual_adjustment_group_item[:translated_reason_code] = /\-?\d+\.\d+\s+.+/.match(line)[0].strip.split(/(?:\d)\s/)[1].strip if !/\-?\d+\.\d+\s+.+/.match(line).nil?
        if adjustment_groups.nil?
          adjustment_groups[0] = individual_adjustment_group_item
        else
          adjustment_groups[adjustment_groups.count] = individual_adjustment_group_item
        end
        individual_line_item[:adjustment_groups] = adjustment_groups
      end

      if line.include?("Adjustment Group")
        next_line_adjustment_group = true
      end

      if next_line_line_item
        individual_line_item[:service_date] = /\d+\/\d+\/\d+/.match(line)[0].strip if !/\d+\/\d+\/\d+/.match(line).nil?
        individual_line_item[:cpt_code] = /\d+\/\d+\/\d+\s\d+/.match(line)[0].strip.split(" ")[1] if !/\d+\/\d+\/\d+\s\d+/.match(line).nil?
        individual_line_item[:charge_amount] = (/\d+\/\d+\/\d+\s\d+\s+\-?\d+\.\d+/.match(line)[0].strip.split(" ")[2].to_f * 100).round().to_i if !/\d+\/\d+\/\d+\s\d+\s+\-?\d+\.\d+/.match(line).nil?
        individual_line_item[:payment_amount] = (/\d+\/\d+\/\d+\s\d+\s+\-?\d+\.\d+\s+\-?\d+\.\d+/.match(line)[0].strip.split(" ")[3].to_f * 100).round().to_i if !/\d+\/\d+\/\d+\s\d+\s+\-?\d+\.\d+\s+\-?\d+\.\d+/.match(line).nil?
        individual_line_item[:total_adjustment_amount] = (/\d+\/\d+\/\d+\s\d+\s+\-?\d+\.\d+\s+\-?\d+\.\d+\s+\-?\d+\.\d+/.match(line)[0].strip.split(" ")[4].to_f * 100).round().to_i if !/\d+\/\d+\/\d+\s\d+\s+\-?\d+\.\d+\s+\-?\d+\.\d+\s+\-?\d+\.\d+/.match(line).nil?
        individual_line_item[:remarks] = line.gsub(/\d+\/\d+\/\d+\s\d+\s+\-?\d+\.\d+\s+\-?\d+\.\d+\s+\-?\d+\.\d+/, "").strip if !/\d+\/\d+\/\d+\s\d+\s+\-?\d+\.\d+\s+\-?\d+\.\d+\s+\-?\d+\.\d+/.match(line).nil?
        if line_items.nil?
          if individual_line_item[:service_date].nil?
            individual_line_item[:service_date] = individual_era[:claim_statement_period_start]
          end
          line_items[0] = individual_line_item
        else
          if individual_line_item[:service_date].nil?
            individual_line_item[:service_date] = individual_era[:claim_statement_period_start]
          end
          line_items[line_items.count] = individual_line_item
        end
        next_line_line_item = false
      end

      if line.include?("Line Item:")
        next_line_line_item = true
      end

      if next_line_claim_statement_period && line.include?("Claim Statement Period")
        individual_era[:claim_statement_period_start] = line.gsub("Claim Statement Period:", "").strip.split("-")[0].strip
        individual_era[:claim_statement_period_end] = line.gsub("Claim Statement Period:", "").strip.split("-")[1].strip
        next_line_claim_statement_period = false
      elsif next_line_claim_statement_period
        next_line_claim_statement_period = false
      end

      if next_line_payer_claim_control && line.include?("Payer Claim Control Number")
        individual_era[:payer_claim_control_number] = line.gsub("Payer Claim Control Number:", "").strip
        next_line_payer_claim_control = false
        next_line_claim_statement_period = true
      elsif next_line_payer_claim_control
        next_line_payer_claim_control = false
        next_line_claim_statement_period = true
      end

      if next_line_tax_id && line.include?("Tax ID")
        era[:checks][check_number][:payer_tax_id] = line.gsub("Tax ID:", "").strip
        next_line_tax_id = false
        next_line_payer_claim_control = true
      elsif next_line_tax_id
        next_line_tax_id = false
        next_line_payer_claim_control = true
      end

      if next_line_city
        if line.include?(",")
          era[:checks][check_number][:payer_city] = line.strip.split(",")[0].strip
          era[:checks][check_number][:payer_state] = line.strip.split(",")[1].split(" ")[0].strip
          era[:checks][check_number][:payer_zip_code] = line.strip.split(",")[1].split(" ")[1].strip
          next_line_city = false
          next_line_tax_id = true
        else
          era[:checks][check_number][:payer_address] = era[:checks][check_number][:payer_address] + " " + line.strip
        end
      end

      if next_line_address
        era[:checks][check_number][:payer_address] = line.strip
        next_line_address = false
        next_line_city = true
      end

      if next_line_check_number
        check_number = /^[^\s]+(?=\s)/.match(line)[0].strip if !/^[^\s]+(?=\s)/.match(line).nil?
        next_line_check_number = false
        individual_era[:patient_id] = /^[^\s]+(?=\s)\s+[^\s]+/.match(line)[0].strip.split(" ")[1] if !/^[^\s]+(?=\s)\s+[^\s]+/.match(line).nil?
        individual_era[:patient_name] = /\s\D*,\D*\s/.match(line)[0].strip if !/\s\D*,\D*\s/.match(line).nil?
        individual_era[:patient_last_name] = individual_era[:patient_name].split(",")[0].downcase.split(" ").map { |word| word.capitalize }.join(" ") if !individual_era[:patient_name].split(",")[0].nil?
        individual_era[:patient_first_name] = individual_era[:patient_name].split(",")[1].downcase.split(" ").map { |word| word.capitalize }.join(" ") if !individual_era[:patient_name].split(",")[1].nil?
        individual_era[:charge_amount] = (/,\D+\d+\.\d+\s/.match(line)[0].gsub(/[a-zA-Z,]/, "").strip.to_f * 100).round().to_i if !/,\D+\d+\.\d+\s/.match(line).nil?
        individual_era[:payment_amount] = (/\.\d+\s+\-?\d+\.\d+\s/.match(line)[0].strip.split(" ")[1].strip.to_f * 100).round().to_i if !/\.\d+\s+\-?\d+\.\d+\s/.match(line).nil?
        individual_era[:account_number] = /\.\d+\s+\-?\d+\.\d+\s+[A-Z\d]+\s/.match(line)[0].strip.split(" ")[2] if !/\.\d+\s+\-?\d+\.\d+\s+[A-Z\d]+\s/.match(line).nil?
        if !/PROCESSED AS PRIMARY\s+.+$/.match(line).nil? && !/^[^\s]+(?=\s)/.match(line).nil?
          individual_era[:status] = "PROCESSED AS PRIMARY"
          era[:checks][check_number][:payer_name] = /PROCESSED AS PRIMARY\s+.+$/.match(line)[0].gsub("PROCESSED AS PRIMARY", "").strip
        elsif !/PROCESSED AS SECONDARY\s+.+$/.match(line).nil? && !/^[^\s]+(?=\s)/.match(line).nil?
          individual_era[:status] = "PROCESSED AS SECONDARY"
          era[:checks][check_number][:payer_name] = /PROCESSED AS SECONDARY\s+.+$/.match(line)[0].gsub("PROCESSED AS SECONDARY", "").strip
        elsif !/PROCESSED AS TERTIARY\s+.+$/.match(line).nil? && !/^[^\s]+(?=\s)/.match(line).nil?
          individual_era[:status] = "PROCESSED AS TERTIARY"
          era[:checks][check_number][:payer_name] = /PROCESSED AS TERTIARY\s+.+$/.match(line)[0].gsub("PROCESSED AS TERTIARY", "").strip
        elsif !/PROCESSED AS PRIMARY,\sFWDED\s+.+$/.match(line).nil? && !/^[^\s]+(?=\s)/.match(line).nil?
          individual_era[:status] = "PROCESSED AS PRIMARY, FWDED"
          era[:checks][check_number][:payer_name] = /PROCESSED AS PRIMARY,\sFWDED\s+.+$/.match(line)[0].gsub("PROCESSED AS PRIMARY, FWDED", "").strip
        elsif !/PROCESSED AS SECONDARY,\sFWDED\s+.+$/.match(line).nil? && !/^[^\s]+(?=\s)/.match(line).nil?
          individual_era[:status] = "PROCESSED AS SECONDARY, FWDED"
          era[:checks][check_number][:payer_name] = /PROCESSED AS SECONDARY,\sFWDED\s+.+$/.match(line)[0].gsub("PROCESSED AS SECONDARY, FWDED", "").strip
        elsif !/PROCESSED AS TERTIARY,\sFWDED\s+.+$/.match(line).nil? && !/^[^\s]+(?=\s)/.match(line).nil?
          individual_era[:status] = "PROCESSED AS TERTIARY, FWDED"
          era[:checks][check_number][:payer_name] = /PROCESSED AS TERTIARY,\sFWDED\s+.+$/.match(line)[0].gsub("PROCESSED AS TERTIARY, FWDED", "").strip
        elsif !/DENIED\s+.+$/.match(line).nil? && !/^[^\s]+(?=\s)/.match(line).nil?
          individual_era[:status] = "DENIED"
          era[:checks][check_number][:payer_name] = /DENIED\s+.+$/.match(line)[0].gsub("DENIED", "").strip
        elsif !/OTHER\s+.+$/.match(line).nil? && !/^[^\s]+(?=\s)/.match(line).nil?
          individual_era[:status] = "OTHER"
          era[:checks][check_number][:payer_name] = /OTHER\s+.+$/.match(line)[0].gsub("OTHER", "").strip
        end
        next_line_address = true
      end

      if line.include?("Check#") && line.include?("Patient ID")
        next_line_check_number = true
        individual_era = Hash.new
        line_items = Hash.new
      end

      if eras_start == true && !line.include?("Check#")
        if line =~ /-{10,}/i
          if era[:checks][check_number][:eras].nil?
            era_counter = 0
            eras = Hash.new
            individual_era[:line_items] = line_items
            individual_era[:era_text] = era_text.strip.gsub(/\r/, "")
            eras[era_counter] = individual_era
            era[:checks][check_number][:eras] = eras
          else
            era_counter = era[:checks][check_number][:eras].count
            eras = Hash.new
            individual_era[:line_items] = line_items
            individual_era[:era_text] = era_text.strip.gsub(/\r/, "")
            eras[era_counter] = individual_era
            era[:checks][check_number][:eras] = era[:checks][check_number][:eras].merge(eras)
          end
          era_text = "--------------------------------------------------------------------------------------------------------------------------------------------------------\n"
        end
      end

      if line.include?("Adjustment Date")
        adjustments_start = true
      end

      if line.include?("Check#") && line.include?("# Claims")
        checks_start = true
      end

      if line =~ /={10,}/i && adjustments_start == true && adjustments != {}
        adjustments_start = false
      end

      if line =~ /-{10,}/i && checks_start == true && checks != {}
        checks_start = false
        era[:adjustments] = adjustments
        era[:checks] = checks
        eras_start = true
      end
    else
      element_types = []
      line.split("~").each do |subline|
        next if subline.strip == ""

        element_type = /[^\*]+/.match(subline)[0]
        element_types << element_type
        # puts "-------------"
        # puts element_type
        # puts subline
        # https://www.healthpartnersplans.com/media/100017241/254_Electronic-Remittance-Advice.pdf
        subline.split("*").each_with_index do |element, index|
          case element_type
          when "ST"
            # Start of new check
            payer_identification_loop = false
            payee_identification_loop = false
            claim_payment_information_loop = false
          when "ISA"
            case index
            when 1
              # Authorization Information Qualifier
              # puts "Authorization Information Qualifier: #{element}"
            when 2
              # Authorization Information
              # puts "Authorization Information: #{element}"
            when 3
              # Security Information Qualifier
              # puts "Security Information Qualifier: #{element}"
            when 4
              # Security Information
              # puts "Security Information: #{element}"
            when 5
              # Interchange Sender ID Qualifier
              # puts "Interchange Sender ID Qualifier: #{element}"
            when 6
              # Interchange Sender ID
              # puts "Interchange Sender ID: #{element}"
            when 7
              # Interchange Receiver ID Qualifier
              # puts "Interchange Receiver ID Qualifier: #{element}"
            when 8
              # Interchange Receiver ID
              # puts "Interchange Receiver ID: #{element}"
              era[:addressed_to] = element.strip.downcase
            when 9
              # Interchange Date
              # puts "Interchange Date: #{element}"
            when 10
              # Interchange Time
              # puts "Interchange Time: #{element}"
            when 11
              # Interchange Control Standards Identifier
              # puts "Interchange Control Standards Identifier: #{element}"
            when 12
              # Interchange Control Version Number
              # puts "Interchange Control Version Number: #{element}"
            when 13
              # Interchange Control Number
              # puts "Interchange Control Number: #{element}"
            when 14
              # Acknowledgement Requested
              # puts "Acknowledgement Requested: #{element}"
            when 15
              # Usage Indicator
              # puts "Usage Indicator: #{element}"
            when 16
              # Component element Separator
              # puts "Component element Separator: #{element}"
            end
          when "BPR"
            case index
            when 1
              # Transaction Handling Code
              # puts "Transaction Handling Code: #{element}"
            when 2
              # Monetary Amount
              # puts "Monetary Amount: #{element}"
              bpr_amount = element.strip
            when 3
              # Credit/Debit Flag
              # puts "Credit/Debit Flag: #{element}"
            when 4
              # PAYMENT METHOD CODE
              # puts "PAYMENT METHOD CODE: #{element}"
            when 5
              # PAYMENT FORMAT CODE
              # puts "PAYMENT FORMAT CODE: #{element}"
            when 6
              # (DFI) ID NUMBER QUALIFIER
              # puts "(DFI) ID NUMBER QUALIFIER: #{element}"
            when 7
              # (DFI) IDENTIFICATION NUMBER
              # puts "(DFI) IDENTIFICATION NUMBER: #{element}"
            when 8
              # Account Number Qualifier
              # puts "Account Number Qualifier: #{element}"
            when 9
              # Sender Bank Account Number
              # puts "Sender Bank Account Number: #{element}"
            when 10
              # ORIGINATING COMPANY IDENTIFIER
              # puts "ORIGINATING COMPANY IDENTIFIER: #{element}"
            when 11
              # Originating Company Supplemental Code
              # puts "Originating Company Supplemental Code: #{element}"
            when 12
              # DFI Identification Number Qualifier
              # puts "DFI Identification Number Qualifier: #{element}"
            when 13
              # Receiver or Provider Bank ID Number
              # puts "Receiver or Provider Bank ID Number: #{element}"
            when 14
              # ACCOUNT NUMBER QUALIFIER
              # puts "ACCOUNT NUMBER QUALIFIER: #{element}"
            when 15
              # Receiver or Provider ACCOUNT NUMBER
              # puts "Receiver or Provider ACCOUNT NUMBER: #{element}"
            when 16
              # Check Issue or EFT Effective Date
              # puts "Check Issue or EFT Effective Date: #{element}"
              bpr_date = element.strip[4..5] + "/" + element.strip[6..7] + "/" + element.strip[0..3]
            end
          when "GS"
            case index
            when 1
              # Functional Identifier Code
              # puts "Functional Identifier Code : #{element}"
            when 2
              # Application Sender Code
              # puts "Application Sender Code: #{element}"
            when 3
              # Application Receiver ID
              # puts "Application Receiver ID: #{element}"
            when 4
              # Date
              # puts "Date: #{element}"
            when 5
              # Time
              # puts "Time: #{element}"
            when 6
              # Group Control Number
              # puts "Group Control Number: #{element}"
            when 7
              # Responsible Agency Code
              # puts "Responsible Agency Code: #{element}"
            when 8
              # Version/Release/Industry Identifier
              # puts "Version/Release/Industry Identifier: #{element}"
            end
          when "TRN"
            case index
            when 1
              # Trace Type Code
              # puts "Trace Type Code: #{element}"
            when 2
              # REFERENCE IDENTIFICATION
              # puts "REFERENCE IDENTIFICATION: #{element}"
              check = Hash.new
              check[:check_number] = element.strip
              check[:amount] = (bpr_amount.to_f * 100).round().to_i
              bpr_amount = ''
              check[:date] = bpr_date
              bpr_date = ''
              checks[check[:check_number]] = check
            when 3
              # ORIGINATING COMPANY IDENTIFIER
              # puts "ORIGINATING COMPANY IDENTIFIER: #{element}"
              era[:checks][check[:check_number]][:payer_tax_id] = element.strip[1..2] + "-" + element.strip[3..-1]
            when 4
              # Originating Company Supplemental Code
              # puts "Originating Company Supplemental Code: #{element}"
            end
          when "N1"
            if !payer_identification_loop && !payee_identification_loop
              payer_identification_loop = true
            end

            case index
            when 1
              # Payer Identifier Code
              # puts "Payer Identifier Code: #{element}"
            when 2
              # Payer NAME
              # puts "Payer NAME: #{element}"
              if payer_identification_loop
                era[:checks][check[:check_number]][:payer_name] = element.strip
              elsif payee_identification_loop
                era[:checks][check[:check_number]][:payee] = element.strip
              end
            when 3
              # Identification Code Qualifier
              # puts "Identification Code Qualifier: #{element}"
            when 4
              # Payer Identification Code
              # puts "Payer Identification Code: #{element}"
              if payee_identification_loop
                era[:checks][check[:check_number]][:npi_tax_id] = element.strip
                payee_identification_loop = false
              end
            end
          when "N3"
            case index
            when 1
              # Payer Address Line
              # puts "Payer Address Line: #{element}"
              if payer_identification_loop
                era[:checks][check[:check_number]][:payer_address] = element.strip
              end
            when 2
              # Payer Address Line
              # puts "Payer Address Line: #{element}"
              if payer_identification_loop
                era[:checks][check[:check_number]][:payer_address] = era[:checks][check[:check_number]][:payer_address] + " " + element.strip
              end
            end
          when "DTM"
            case index
            when 1
              # Date Time Qualifier
              # puts "Date Time Qualifier: #{element}"
              if element == "050"
                receive_date = true
              elsif element == "150"
                service_date = true
              elsif element == "232"
                claim_date_start = true
              elsif element == "233"
                claim_date_end = true
              elsif element == "472"
                service_date = true
              end
            when 2
              # Service Date
              # puts "Service Date: #{element}"
              if service_date
                individual_line_item[:service_date] = element.strip[4..5] + "/" + element.strip[6..7] + "/" + element.strip[0..3]
                service_date = false
              elsif claim_date_start
                individual_era[:claim_statement_period_start] = element.strip[4..5] + "/" + element.strip[6..7] + "/" + element.strip[0..3]
                claim_date_start = false
              elsif claim_date_end
                individual_era[:claim_statement_period_end] = element.strip[4..5] + "/" + element.strip[6..7] + "/" + element.strip[0..3]
                claim_date_end = false
              end
            end
          when "N4"
            case index
            when 1
              # Payer City Name
              # puts "Payer City Name: #{element}"
              if payer_identification_loop
                era[:checks][check[:check_number]][:payer_city] = element.strip
              end
            when 2
              # Payer State Code
              # puts "Payer State Code: #{element}"
              if payer_identification_loop
                era[:checks][check[:check_number]][:payer_state] = element.strip
              end
            when 3
              # Payer Postal Zone or Zip Code
              # puts "Payer Postal Zone or Zip Code: #{element}"
              if payer_identification_loop
                era[:checks][check[:check_number]][:payer_zip_code] = element.strip
                payer_identification_loop = false
                payee_identification_loop = true
              end
            end
          when "PER"
            case index
            when 1
              # Contact Function Code
              # puts "Contact Function Code: #{element}"
            when 2
              # Payer Technical Contact Name
              # puts "Payer Technical Contact Name: #{element}"
            when 3
              # Communication Number Qualifier
              # puts "Communication Number Qualifier: #{element}"
            when 4
              # Payer Contact Communication Number
              # puts "Payer Contact Communication Number: #{element}"
            when 5
              # Payer Contact Communication Number
              # puts "Payer Contact Communication Number: #{element}"
            when 6
              # Payer Technical Contact Communication
              # puts "Payer Technical Contact Communication: #{element}"
            end
          when "LX"
            case index
            when 1
              # Claim Sequence Number
              # puts "Claim Sequence Number: #{element}"
            end
          when "CLP"
            svc_counter = 0
            claim_payment_information_loop = true
            service_payment_information_loop = true if individual_line_item[:service_date].nil?
            case index
            when 1
              if individual_line_item != {}
                if line_items.nil?
                  if individual_line_item[:service_date].nil?
                    individual_line_item[:service_date] = individual_era[:claim_statement_period_start]
                  end
                  line_items[0] = individual_line_item
                else
                  if individual_line_item[:service_date].nil?
                    individual_line_item[:service_date] = individual_era[:claim_statement_period_start]
                  end
                  line_items[line_items.count] = individual_line_item
                end
                individual_era[:line_items] = line_items
                individual_line_item = Hash.new
              end
              individual_era = Hash.new
              line_items = Hash.new
              adjustment_groups = Hash.new
              # Patient Control Number
              # puts "Patient Control Number: #{element}"
              individual_era[:account_number] = element.strip
            when 2
              # Claim Status Code
              # puts "Claim Status Code: #{element}"
              individual_era[:claim_status_code] = element.strip
              individual_era[:status] = CLAIM_STATUS_CODES[element.strip][1]
            when 3
              # Total Claim Charge Amount
              # puts "Total Claim Charge Amount: #{element}"
              individual_era[:charge_amount] = (element.to_f * 100).round().to_i
            when 4
              # Total Claim Payment Amount
              # puts "Total Claim Payment Amount: #{element}"
              individual_era[:payment_amount] = (element.to_f * 100).round().to_i
            when 5
              # Patient Responsibility Amount
              # puts "Patient Responsibility Amount: #{element}"
            when 6
              # Claim Filing Indicator Code
              # puts "Claim Filing Indicator Code: #{element}"
            when 7
              # Payer Claim Control Number
              # puts "Payer Claim Control Number: #{element}"
              individual_era[:payer_claim_control_number] = element.strip
              if era[:checks][check[:check_number]][:eras].nil?
                individual_eras = Hash.new
                individual_eras[0] = individual_era
                era[:checks][check[:check_number]][:eras] = individual_eras
              else
                individual_eras = era[:checks][check[:check_number]][:eras]
                individual_eras[era[:checks][check[:check_number]][:eras].size] = individual_era
                era[:checks][check[:check_number]][:eras] = individual_eras
              end
            when 8
              # Facility Type Code
              # puts "Facility Type Code: #{element}"
            when 9
              # Claim Frequency Code
              # puts "Claim Frequency Code: #{element}"
            when 10
              # Patient Status Code
              # puts "Patient Status Code: #{element}"
            when 11
              # Diagnosis Related Group (DRG) Code
              # puts "Diagnosis Related Group (DRG) Code: #{element}"
            when 12
              # DRG Weight
              # puts "DRG Weight: #{element}"
            when 13
              # PERCENT - Discharge Fraction
              # puts "PERCENT - Discharge Fraction: #{element}"
            end
          when "PLB"
            case index
            when 1
              # Provider Identifier
              adjustment_counter_a += 1
              adjustment = Hash.new
              adjustment[:provider_id] = element.strip
            when 2
              # Fiscal Period Date
              adjustment[:adjustment_date] = element.strip[4..5] + "/" + element.strip[6..7] + "/" + element.strip[0..3]
            when 3
              element.split(":").each_with_index do |subelement, i|
                case i
                when 0
                  # PROVIDER ADJUSTMENT REASON CODE
                  # puts "PROVIDER ADJUSTMENT REASON CODE: #{subelement}"
                  adjustment[:reason_code] = subelement.strip
                  adjustment[:reason] = PROVIDER_LEVEL_ADJUSTMENTS[subelement.strip]
                when 1
                  # Provider Adjustment Identifier
                  # puts "Provider Adjustment Identifier: #{subelement}"
                  adjustment[:reference_id] = subelement.strip
                end
              end
            when 4
              # Provider Adjustment Amount
              adjustment[:adjustment_amount] = (element.to_f * 100).round().to_i
            when 5
              adjustment_counter_a += 1
              element.split(":").each_with_index do |subelement, i|
                case i
                when 0
                  # PROVIDER ADJUSTMENT REASON CODE
                  # puts "PROVIDER ADJUSTMENT REASON CODE: #{subelement}"
                  adjustment[:reason_code] = subelement.strip
                  adjustment[:reason] = PROVIDER_LEVEL_ADJUSTMENTS[subelement.strip]
                when 1
                  # Provider Adjustment Identifier
                  # puts "Provider Adjustment Identifier: #{subelement}"
                  adjustment[:reference_id] = subelement.strip
                end
              end
            when 6
              # Provider Adjustment Amount
              adjustment[:adjustment_amount] = (element.to_f * 100).round().to_i
            when 7
              adjustment_counter_a += 1
              element.split(":").each_with_index do |subelement, i|
                case i
                when 0
                  # PROVIDER ADJUSTMENT REASON CODE
                  # puts "PROVIDER ADJUSTMENT REASON CODE: #{subelement}"
                  adjustment[:reason_code] = subelement.strip
                  adjustment[:reason] = PROVIDER_LEVEL_ADJUSTMENTS[subelement.strip]
                when 1
                  # Provider Adjustment Identifier
                  # puts "Provider Adjustment Identifier: #{subelement}"
                  adjustment[:reference_id] = subelement.strip
                end
              end
            when 8
              # Provider Adjustment Amount
              adjustment[:adjustment_amount] = (element.to_f * 100).round().to_i
            when 9
              adjustment_counter_a += 1
              element.split(":").each_with_index do |subelement, i|
                case i
                when 0
                  # PROVIDER ADJUSTMENT REASON CODE
                  # puts "PROVIDER ADJUSTMENT REASON CODE: #{subelement}"
                  adjustment[:reason_code] = subelement.strip
                  adjustment[:reason] = PROVIDER_LEVEL_ADJUSTMENTS[subelement.strip]
                when 1
                  # Provider Adjustment Identifier
                  # puts "Provider Adjustment Identifier: #{subelement}"
                  adjustment[:reference_id] = subelement.strip
                end
              end
            when 10
              # Provider Adjustment Amount
              adjustment[:adjustment_amount] = (element.to_f * 100).round().to_i
            when 11
              adjustment_counter_a += 1
              element.split(":").each_with_index do |subelement, i|
                case i
                when 0
                  # PROVIDER ADJUSTMENT REASON CODE
                  # puts "PROVIDER ADJUSTMENT REASON CODE: #{subelement}"
                  adjustment[:reason_code] = subelement.strip
                  adjustment[:reason] = PROVIDER_LEVEL_ADJUSTMENTS[subelement.strip]
                when 1
                  # Provider Adjustment Identifier
                  # puts "Provider Adjustment Identifier: #{subelement}"
                  adjustment[:reference_id] = subelement.strip
                end
              end
            when 12
              # Provider Adjustment Amount
              adjustment[:adjustment_amount] = (element.to_f * 100).round().to_i
            when 13
              adjustment_counter_a += 1
              element.split(":").each_with_index do |subelement, i|
                case i
                when 0
                  # PROVIDER ADJUSTMENT REASON CODE
                  # puts "PROVIDER ADJUSTMENT REASON CODE: #{subelement}"
                  adjustment[:reason_code] = subelement.strip
                  adjustment[:reason] = PROVIDER_LEVEL_ADJUSTMENTS[subelement.strip]
                when 1
                  # Provider Adjustment Identifier
                  # puts "Provider Adjustment Identifier: #{subelement}"
                  adjustment[:reference_id] = subelement.strip
                end
              end
            when 14
              # Provider Adjustment Amount
              adjustment[:adjustment_amount] = (element.to_f * 100).round().to_i
            end
            adjustments[adjustment_counter_a] = adjustment if adjustment_counter_a > -1 && (adjustment != {} && !adjustment.nil?)
          when "CAS"
            case index
            when 1
              # Claim Adjustment Group Code
              # puts "Claim Adjustment Group Code: #{element}"
              individual_adjustment_group_item = Hash.new
              individual_adjustment_group_item[:adjustment_group_code] = element.strip
              individual_adjustment_group_item[:adjustment_group] = ADJUSTMENT_GROUP_CODES[element.strip]
              floating_adjustment_group_code = element.strip
            when 2,5,8,11,14,17
              # Adjustment Reason Code
              if index > 2
                individual_adjustment_group_item = Hash.new
                individual_adjustment_group_item[:adjustment_group_code] = floating_adjustment_group_code
                individual_adjustment_group_item[:adjustment_group] = ADJUSTMENT_GROUP_CODES[floating_adjustment_group_code]
              end
              # puts "Adjustment Reason Code: #{element}"
              individual_adjustment_group_item[:reason_code] = element.strip
              individual_adjustment_group_item[:translated_reason_code] = ADJUSTMENT_CODES[element.strip]
            when 3,6,9,12,15,18
              # Adjustment Amount
              # puts "Adjustment Amount: #{element}"
              #
              individual_adjustment_group_item[:adjustment_amount] = (element.to_f * 100).round().to_i
              # puts individual_adjustment_group_item
              if adjustment_groups.nil?
                adjustment_groups[0] = individual_adjustment_group_item
              else
                adjustment_groups[adjustment_groups.count] = individual_adjustment_group_item
              end
              individual_line_item[:adjustment_groups] = adjustment_groups
              adjustment_amount_tally = 0
              individual_line_item[:adjustment_groups].each do |k,v|
                adjustment_amount_tally += v[:adjustment_amount]
              end
              individual_line_item[:total_adjustment_amount] = adjustment_amount_tally
            when 4,7,10,13,16,19
              # QUANTITY
              # puts "QUANTITY: #{element}"
            end

          when "LQ"
            case index
            when 1
              # Service Line Remittance Remark Code 1
              # puts "Service Line Remittance Remark Code 1: #{element}"
            when 2
              # Service Line Remittance Remark Code 2
              # puts "Service Line Remittance Remark Code 2: #{element}"
              individual_line_item[:remark_code] = element.strip
              individual_line_item[:remarks] = REMARK_CODES[element.strip]
            end
          when "AMT"
            case index
            when 1
              # Amount Qualifier Code
              # puts "Amount Qualifier Code: #{element}"
            when 2
              # Service Line Allowed Amount
              # puts "Service Line Allowed Amount: #{element}"
            end
          when "NM1"
            case index
            when 1
              # Patient Identifier Code
              # puts "Patient Identifier Code: #{element}"
              if element == "QC"
                patient_loop = true
              else
                patient_loop = false
              end
              if element == "82"
                rendering_provider_loop = true
              else
                rendering_provider_loop = false
              end
            when 2
              # Entity Type Qualifier
              # puts "Entity Type Qualifier: #{element}"
            when 3
              # Patient Last Name
              # puts "Patient Last Name: #{element}"
              if claim_payment_information_loop && patient_loop
                individual_era[:patient_last_name] = element.strip.downcase.split(" ").map { |word| word.capitalize }.join(" ")
              end
              if claim_payment_information_loop && rendering_provider_loop
                individual_era[:rendering_provider_last_name] = element.strip.downcase.split(" ").map { |word| word.capitalize }.join(" ")
              end
            when 4
              # Patient First Name
              # puts "Patient First Name: #{element}"
              if claim_payment_information_loop && patient_loop
                individual_era[:patient_first_name] = element.strip.downcase.split(" ").map { |word| word.capitalize }.join(" ")
                individual_era[:patient_name] = individual_era[:patient_last_name].upcase + "," + individual_era[:patient_first_name].upcase
              end
              if claim_payment_information_loop && rendering_provider_loop
                individual_era[:rendering_provider_first_name] = element.strip.downcase.split(" ").map { |word| word.capitalize }.join(" ")
                individual_era[:rendering_provider_name] = individual_era[:rendering_provider_last_name].upcase + "," + individual_era[:rendering_provider_first_name].upcase
              end
            when 5
              # Patient Middle Initial
              # puts "Patient Middle Initial: #{element}"
            when 6
              # Name Prefix
              # puts "Name Prefix: #{element}"
            when 7
              # Patient Name Suffix
              # puts "Patient Name Suffix: #{element}"
            when 8
              # Identification Code Qualifier
              # puts "Identification Code Qualifier: #{element}"
            when 9
              # Patient Member Number
              # puts "Patient Member Number: #{element}"
              if claim_payment_information_loop && patient_loop
                individual_era[:patient_id] = element.strip
              end
            end
          when "SVC"
            case index
            when 1
              svc_counter += 1
              if individual_line_item != {} && svc_counter > 1
                if line_items.nil?
                  if individual_line_item[:service_date].nil?
                    individual_line_item[:service_date] = individual_era[:claim_statement_period_start]
                  end
                  line_items[0] = individual_line_item
                else
                  if individual_line_item[:service_date].nil?
                    individual_line_item[:service_date] = individual_era[:claim_statement_period_start]
                  end
                  line_items[line_items.count] = individual_line_item
                end
                individual_era[:line_items] = line_items
                individual_line_item = Hash.new
              end
              adjustment_groups = Hash.new
              service_payment_information_loop = true if individual_line_item[:service_date].nil?
              element.split(":").each_with_index do |subelement, i|
                case i
                when 0
                  # Service Type Code
                  # puts "Service Type Code: #{subelement}"
                when 1
                  # Service Code
                  # puts "Service Code: #{subelement}"
                  individual_line_item[:cpt_code] = subelement.strip
                end
              end
            when 2
              # Monetary Amount (Charge amount)
              # puts "Monetary Amount (Charge amount): #{element}"
              individual_line_item[:charge_amount] = (element.to_f * 100).round().to_i
            when 3
              # Monetary Amount (Payment amount)
              # puts "Monetary Amount (Payment amount): #{element}"
              individual_line_item[:payment_amount] = (element.to_f * 100).round().to_i
            when 4
              # NUBC Revenue Code
              # puts "NUBC Revenue Code: #{element}"
            when 5
              # Units of Service Paid Count
              # puts "Units of Service Paid Count: #{element}"
            when 6
              element.split(":").each_with_index do |subelement, i|
                case index
                when 1
                  # PRODUCT/SERVICE ID QUALIFIER
                  # puts "PRODUCT/SERVICE ID QUALIFIER: #{element}"
                when 2
                  # Procedure Code
                  # puts "Procedure Code: #{element}"
                end
              end
            when 7
              # Original Units of Service Count
              # puts "Original Units of Service Count: #{element}"
            end
          when "REF"
            case index
            when 1
              # Additional Payee Identification Qualifier
              # puts "Additional Payee Identification Qualifier: #{element}"
              returned_reference_number = true if element == '6R'
            when 2
              # Reference Identification Code
              # puts "Reference Identification Code: #{element}"
              if individual_line_item != {} && svc_counter >= 1 && returned_reference_number && !element.nil?
                individual_line_item[:reference_number] = element
                returned_reference_number = false
              end
            when 3
              # Additional Payee Identification Qualifier
              # puts "Additional Payee Identification Qualifier: #{element}"
            when 4
              # Reference Identification Code
              # puts "Reference Identification Code: #{element}"
            end
          end
          era[:checks] = checks
        end
      end
    end
  end
  if file_type == "human_readable"
    if era[:checks][check_number][:eras].nil?
      era_counter = 0
      eras = Hash.new
      individual_era[:line_items] = line_items
      individual_era[:era_text] = era_text.strip.gsub(/\r/, "")
      eras[era_counter] = individual_era
      era[:checks][check_number][:eras] = eras
    else
      era_counter = era[:checks][check_number][:eras].count
      eras = Hash.new
      individual_era[:line_items] = line_items
      individual_era[:era_text] = era_text.strip.gsub(/\r/, "")
      eras[era_counter] = individual_era
      era[:checks][check_number][:eras] = era[:checks][check_number][:eras].merge(eras)
    end
    return era
  else
    if individual_line_item != {}
      if line_items.nil?
        if individual_line_item[:service_date].nil?
          individual_line_item[:service_date] = individual_era[:claim_statement_period_start]
        end
        line_items[0] = individual_line_item
      else
        if individual_line_item[:service_date].nil?
          individual_line_item[:service_date] = individual_era[:claim_statement_period_start]
        end
        line_items[line_items.count] = individual_line_item
      end
      individual_era[:line_items] = line_items
    end
    era[:adjustments] = adjustments if adjustments != {}
    era[:checks].each do |i, check|
      if check[:eras].nil?
        era[:checks][check[:check_number]][:number_of_claims] = 0
      else
        era[:checks][check[:check_number]][:number_of_claims] = check[:eras].size
      end
      if !check[:eras].nil?
        check[:eras].each do |era_counter, individual_era|
          line_items = ''
          if !individual_era[:line_items].nil?
            individual_era[:line_items].each do |line_item_counter, line_item|
              if line_item[:remarks].nil?
                remark = "NO REMARKS"
              else
                remark = truncate(line_item[:remarks], 82)
              end
              line_items += "#{" " * (22)}#{line_item[:service_date]} #{line_item[:cpt_code]}#{" " * (7 - get_length(line_item[:cpt_code]))}#{'%.2f' % (line_item[:charge_amount].to_f / 100)}#{" " * (13 - get_length('%.2f' % (line_item[:charge_amount].to_f / 100)))}#{'%.2f' % (line_item[:payment_amount].to_f / 100)}#{" " * (13 - get_length('%.2f' % (line_item[:payment_amount].to_f / 100)))}#{'%.2f' % (line_item[:total_adjustment_amount].to_f / 100)}#{" " * (15 - get_length('%.2f' % (line_item[:total_adjustment_amount].to_f / 100)))}#{remark}\n\n"

              if !line_item[:adjustment_groups].nil?
                line_item[:adjustment_groups].each do |adjustment_group_counter, adjustment_group|
                  line_items += "                                Adjustment Group            Adj Amt Translated Reason Code\n" if adjustment_group_counter == 0
                  reason_code = adjustment_group[:translated_reason_code].nil? ? '' : adjustment_group[:translated_reason_code].upcase
                  line_items += "                                #{adjustment_group[:adjustment_group].upcase}#{" " * (28 - get_length(adjustment_group[:adjustment_group]))}#{'%.2f' % (adjustment_group[:adjustment_amount].to_f / 100)}#{" " * (8 - get_length('%.2f' % (adjustment_group[:adjustment_amount].to_f / 100)))}#{truncate(reason_code, 84)}\n"
                  line_items += "\n" if line_item[:adjustment_groups].length == (adjustment_group_counter + 1)
                end
              end
            end
          end
          era_text = "--------------------------------------------------------------------------------------------------------------------------------------------------------\n"
          era_text += "Check#                         Patient ID         Last,First          Charge Amt  Payment Amt  Accnt##{" " * [8, get_length(individual_era[:account_number]) - 5].max}Status                         Payer\n"
          era_text += "#{check[:check_number]}#{" " * (31 - get_length(check[:check_number]))}#{individual_era[:patient_id]}#{" " * (19 - get_length(individual_era[:patient_id]))}#{truncate(individual_era[:patient_name], 18)}#{" " * (20 - get_length(truncate(individual_era[:patient_name], 18)))}#{'%.2f' % (individual_era[:charge_amount].to_f / 100)}#{" " * (12 - get_length('%.2f' % (individual_era[:charge_amount].to_f / 100)))}#{'%.2f' % (individual_era[:payment_amount].to_f / 100)}#{" " * (13 - get_length('%.2f' % (individual_era[:payment_amount].to_f / 100)))}#{individual_era[:account_number]}#{" " * ([14, get_length(individual_era[:account_number]) + 1].max - get_length(individual_era[:account_number]))}#{individual_era[:status]}#{" " * (31 - get_length(individual_era[:status]))}#{check[:payer_name]}\n"
          era_text += "#{" " * (126 + [14, get_length(individual_era[:account_number]) + 1].max)}#{check[:payer_address]}\n"
          era_text += "#{" " * (126 + [14, get_length(individual_era[:account_number]) + 1].max)}#{check[:payer_city]},#{check[:payer_state]} #{check[:payer_zip_code]}\n"
          era_text += "#{" " * (126 + [14, get_length(individual_era[:account_number]) + 1].max)}Tax ID: #{check[:payer_tax_id]}\n"

          if !individual_era[:claim_statement_period_end].nil? && !individual_era[:claim_statement_period_start].nil?
            era_text += "#{" " * (96)}Payer Claim Control Number: #{individual_era[:payer_claim_control_number]}\n"
            era_text += "#{" " * (96)}Claim Statement Period: #{individual_era[:claim_statement_period_start]} - #{individual_era[:claim_statement_period_end]}\n\n"
          else
            era_text += "#{" " * (96)}Payer Claim Control Number: #{individual_era[:payer_claim_control_number]}\n\n"
          end
          if line_items.length > 0
            era_text += "#{" " * (10)}Line Item:  Svc Date   CPT    Charge Amt   Payment Amt  Total Adj Amt  Remarks\n"
            era_text += line_items
          end
          era[:checks][check[:check_number]][:eras][era_counter][:era_text] = era_text
        end
      end
    end
    return era
  end
end

Private Instance Methods

get_length(string) click to toggle source
# File lib/era_835_parser/parser.rb, line 1073
def get_length(string)
  if string.nil?
    return 0
  else
    return string.length
  end
end
truncate(string, truncate_at) click to toggle source
# File lib/era_835_parser/parser.rb, line 1081
def truncate(string, truncate_at)
  if !string.nil?
    return string.to_s[0...truncate_at]
  end
end