sunnyside 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8e0f90574f4539e1f9daa2488cbca27d81414ad3
4
+ data.tar.gz: 12ce71ebb22046f4d41c371ef3b5e984b04a25a4
5
+ SHA512:
6
+ metadata.gz: 4cace35d98ac36f145edd1f29c32564fc56195d8711ee6ab4a941e721d4d2ecfcee4070aa7dd2d88ee5b0f119979cbc56d6309508dcfd7d44e1b10aac396bc48
7
+ data.tar.gz: 0ac9c8a12d46770f952cfc36e3072bad461572c843b0c24ff69d17888ebdd51c9aced11f7e59c5cd78587b2be5f24beca8227816d4e48c4824161a6809d1e88b
data/bin/sunnyside CHANGED
@@ -1,6 +1,6 @@
1
- #!/usr/bin/env ruby
2
- require 'rubygems'
3
- require 'sequel'
4
- require 'sunnyside'
5
-
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'sequel'
4
+ require 'sunnyside'
5
+
6
6
  Sunnyside::Menu.new.start
data/lib/sunnyside.rb CHANGED
@@ -1,35 +1,35 @@
1
- require 'prawn'
2
- require 'sequel'
3
- require 'csv'
4
- require 'fileutils'
5
- require "sunnyside/version"
6
- require 'sunnyside/cash_receipts/cash_receipt'
7
- require 'sunnyside/ledger/ledger'
8
- require 'sunnyside/ledger/edi'
9
- require 'sunnyside/ledger/auth_report'
10
- require 'sunnyside/ledger/private'
11
- require 'sunnyside/reports/pdf_report'
12
- require 'sunnyside/reports/private'
13
- require 'sunnyside/reports/report'
14
- require 'sunnyside/query/query'
15
- require 'sunnyside/ftp'
16
- require 'sunnyside/menu'
17
- require 'sunnyside/expiring_auth'
18
- require 'sunnyside/models/db_setup'
19
- require 'sunnyside/advanced'
20
-
21
- module Sunnyside
22
- DRIVE = ENV["HOMEDRIVE"]
23
-
24
- Sunnyside.create_folders if !Dir.exist?("#{DRIVE}/sunnyside-files")
25
- Dir.chdir("R:/Departments/AR Department")
26
- DB = Sequel.connect("sqlite://sunnyside.db")
27
-
28
- if DB.tables.empty?
29
- Sunnyside.create_tables
30
- Sunnyside.add_providers
31
- Sunnyside.add_denial_data
32
- end
33
-
34
- require 'sunnyside/models/sequel_classes'
35
- end
1
+ require 'prawn'
2
+ require 'sequel'
3
+ require 'csv'
4
+ require 'fileutils'
5
+ require "sunnyside/version"
6
+ require 'sunnyside/cash_receipts/cash_receipt'
7
+ require 'sunnyside/ledger/ledger'
8
+ require 'sunnyside/ledger/edi'
9
+ require 'sunnyside/ledger/auth_report'
10
+ require 'sunnyside/ledger/private'
11
+ require 'sunnyside/reports/pdf_report'
12
+ require 'sunnyside/reports/private'
13
+ require 'sunnyside/reports/report'
14
+ require 'sunnyside/query/query'
15
+ require 'sunnyside/ftp'
16
+ require 'sunnyside/menu'
17
+ require 'sunnyside/expiring_auth'
18
+ require 'sunnyside/models/db_setup'
19
+ require 'sunnyside/advanced'
20
+
21
+ module Sunnyside
22
+ DRIVE = ENV["HOMEDRIVE"]
23
+
24
+ Sunnyside.create_folders if !Dir.exist?("#{DRIVE}/sunnyside-files")
25
+ Dir.chdir("R:/Departments/AR Department")
26
+ DB = Sequel.connect("sqlite://sunnyside.db")
27
+
28
+ if DB.tables.empty?
29
+ Sunnyside.create_tables
30
+ Sunnyside.add_providers
31
+ Sunnyside.add_denial_data
32
+ end
33
+
34
+ require 'sunnyside/models/sequel_classes'
35
+ end
@@ -1,85 +1,85 @@
1
- module Sunnyside
2
- def self.advanced_opts
3
- puts "1.) Add new provider"
4
- puts "2.) Export A/R denials"
5
-
6
- case gets.chomp
7
- when '1'
8
- print "Type in the provider name _EXACTLY_ how it appears on the SanData archive report files (e.g. Guildnet is always GUILDNET): "
9
- provider = gets.chomp
10
- print "Now type in the abbreviation (batch initials - e.g. MetroPlus Health is MPH): "
11
- abbrev = gets.chomp
12
- print "Now type in the CREDIT account that is used in FUND EZ: "
13
- credit = gets.chomp
14
- print "Now type in the DEBIT account that is used in FUND EZ: "
15
- debit = gets.chomp
16
- print "And finally, type in the FUND number that is used in FUND EZ: "
17
- fund = gets.chomp
18
- review = "--------Name: #{provider}, Credit Account: #{credit}, Debit Account: #{debit}, Fund: #{fund}, Abbreviation: #{abbrev}--------"
19
- puts "Please review the below information."
20
- puts '-' * review.length
21
- puts review
22
- puts '-' * review.length
23
- print "Is this correct? (Y for yes, N for No): "
24
- raise 'You have an empty field! Start over!' if [provider, credit, debit, fund, abbrev].any? { |elem| elem.empty? }
25
- if gets.chomp.upcase == 'Y'
26
- provider = Provider.insert(name: provider, credit_account: credit, debit_account: debit, fund: fund, abbreviation: abbrev)
27
- puts "#{Provider[provider].name} added."
28
- else
29
- Sunnyside.advanced_opts
30
- end
31
- else
32
- exit
33
- end
34
- end
35
-
36
- def self.rails_server
37
- puts "Please wait..."
38
-
39
- Dir.chdir("R:/Departments/AR Department/sunnyside-app")
40
-
41
- %x(rails s)
42
- end
43
-
44
- def self.determine_browser
45
- if Dir.exist?("#{DRIVE}/Program Files (x86)")
46
- Dir.chdir("#{DRIVE}/Program Files (x86)/Mozilla Firefox")
47
- else
48
- Dir.chdir("#{DRIVE}/Program Files/Mozilla Firefox")
49
- end
50
- end
51
-
52
- def self.add_provider_to_ftp
53
- Provider.all.each { |prov| puts "#{prov.id}: #{prov.name}"}
54
- print "Type in the corresponding ID Number for the provider you would like to add to FTP: "
55
-
56
- provider = Provider[gets.chomp].abbreviation
57
-
58
- puts "You've selected #{provider}"
59
-
60
- print "Type in the ftp address now: "
61
- site = gets.chomp
62
-
63
- print "Type in the username now: "
64
- username = gets.chomp
65
-
66
- print "Type in the password now: "
67
- password = gets.chomp
68
-
69
- review = "-------Provider: #{provider}, Site: #{site}, Username: #{username}, Password: #{password}--------------"
70
- puts "Please review the following information: "
71
- puts '-' * review.length
72
- puts review
73
- puts '-' * review.length
74
-
75
- puts "Is this correct? Type Y or N."
76
- if gets.chomp.downcase == 'y'
77
- Login.insert(site: site, username: username, password: password, provider: provider)
78
- Dir.mkdir("#{DRIVE}/sunnyside-files/ftp/835/#{provider}")
79
- Dir.mkdir("#{DRIVE}/sunnyside-files/ftp/837/#{provider}")
80
- else
81
- puts 'Please try again.'
82
- Sunnyside.add_provider_to_ftp
83
- end
84
- end
1
+ module Sunnyside
2
+ def self.advanced_opts
3
+ puts "1.) Add new provider"
4
+ puts "2.) Export A/R denials"
5
+
6
+ case gets.chomp
7
+ when '1'
8
+ print "Type in the provider name _EXACTLY_ how it appears on the SanData archive report files (e.g. Guildnet is always GUILDNET): "
9
+ provider = gets.chomp
10
+ print "Now type in the abbreviation (batch initials - e.g. MetroPlus Health is MPH): "
11
+ abbrev = gets.chomp
12
+ print "Now type in the CREDIT account that is used in FUND EZ: "
13
+ credit = gets.chomp
14
+ print "Now type in the DEBIT account that is used in FUND EZ: "
15
+ debit = gets.chomp
16
+ print "And finally, type in the FUND number that is used in FUND EZ: "
17
+ fund = gets.chomp
18
+ review = "--------Name: #{provider}, Credit Account: #{credit}, Debit Account: #{debit}, Fund: #{fund}, Abbreviation: #{abbrev}--------"
19
+ puts "Please review the below information."
20
+ puts '-' * review.length
21
+ puts review
22
+ puts '-' * review.length
23
+ print "Is this correct? (Y for yes, N for No): "
24
+ raise 'You have an empty field! Start over!' if [provider, credit, debit, fund, abbrev].any? { |elem| elem.empty? }
25
+ if gets.chomp.upcase == 'Y'
26
+ provider = Provider.insert(name: provider, credit_account: credit, debit_account: debit, fund: fund, abbreviation: abbrev)
27
+ puts "#{Provider[provider].name} added."
28
+ else
29
+ Sunnyside.advanced_opts
30
+ end
31
+ else
32
+ exit
33
+ end
34
+ end
35
+
36
+ def self.rails_server
37
+ puts "Please wait..."
38
+
39
+ Dir.chdir("R:/Departments/AR Department/sunnyside-app")
40
+
41
+ %x(rails s)
42
+ end
43
+
44
+ def self.determine_browser
45
+ if Dir.exist?("#{DRIVE}/Program Files (x86)")
46
+ Dir.chdir("#{DRIVE}/Program Files (x86)/Mozilla Firefox")
47
+ else
48
+ Dir.chdir("#{DRIVE}/Program Files/Mozilla Firefox")
49
+ end
50
+ end
51
+
52
+ def self.add_provider_to_ftp
53
+ Provider.all.each { |prov| puts "#{prov.id}: #{prov.name}"}
54
+ print "Type in the corresponding ID Number for the provider you would like to add to FTP: "
55
+
56
+ provider = Provider[gets.chomp].abbreviation
57
+
58
+ puts "You've selected #{provider}"
59
+
60
+ print "Type in the ftp address now: "
61
+ site = gets.chomp
62
+
63
+ print "Type in the username now: "
64
+ username = gets.chomp
65
+
66
+ print "Type in the password now: "
67
+ password = gets.chomp
68
+
69
+ review = "-------Provider: #{provider}, Site: #{site}, Username: #{username}, Password: #{password}--------------"
70
+ puts "Please review the following information: "
71
+ puts '-' * review.length
72
+ puts review
73
+ puts '-' * review.length
74
+
75
+ puts "Is this correct? Type Y or N."
76
+ if gets.chomp.downcase == 'y'
77
+ Login.insert(site: site, username: username, password: password, provider: provider)
78
+ Dir.mkdir("#{DRIVE}/sunnyside-files/ftp/835/#{provider}")
79
+ Dir.mkdir("#{DRIVE}/sunnyside-files/ftp/837/#{provider}")
80
+ else
81
+ puts 'Please try again.'
82
+ Sunnyside.add_provider_to_ftp
83
+ end
84
+ end
85
85
  end
@@ -3,14 +3,18 @@ module Sunnyside
3
3
  def self.cash_receipt
4
4
  puts "1.) EDI PAYMENT"
5
5
  puts "2.) MANUAL PAYMENT"
6
- cash_receipt =
7
- case gets.chomp
8
- when '1'
9
- CashReceipt.new(:electronic)
10
- when '2'
11
- CashReceipt.new(:manual)
12
- end
13
- cash_receipt.collate
6
+ puts "3.) RESET A/R SPREADSHEET"
7
+ case gets.chomp
8
+ when '1'
9
+ cash_receipt = CashReceipt.new(:electronic)
10
+ when '2'
11
+ cash_receipt = CashReceipt.new(:manual)
12
+ when '3'
13
+ CSV.open("#{DRIVE}/sunnyside-files/cash_receipts/EDI-citywide-import.csv", "w") { |row|
14
+ row << ['Seq','Receipt','post_date','other id','invoice','header memo','batch','doc date','detail memo','fund','account','cc1','cc2','cc3','debit','credit']
15
+ }
16
+ end
17
+ cash_receipt.collate if cash_receipt
14
18
  end
15
19
 
16
20
  class CashReceipt
@@ -39,9 +43,9 @@ module Sunnyside
39
43
  print "You have typed out #{invoices.length} number of invoices. Do you wish to add more to the same check? (Y or N): "
40
44
  if gets.chomp.upcase == 'Y'
41
45
  more_invoices = gets.chomp.split
42
- return (more_invoices + invoices)
46
+ return (more_invoices + invoices).uniq
43
47
  else
44
- return invoices
48
+ return invoices.uniq
45
49
  end
46
50
  end
47
51
 
@@ -61,7 +65,6 @@ module Sunnyside
61
65
  manual_invoices
62
66
  end
63
67
  end
64
-
65
68
  end
66
69
 
67
70
  def invoices_exist?(invoices)
File without changes
data/lib/sunnyside/ftp.rb CHANGED
File without changes
File without changes
@@ -1,175 +1,175 @@
1
- module Sunnyside
2
- def self.edi_parser
3
- print "checking for new files...\n"
4
- Dir["#{DRIVE}/sunnyside-files/835/*.txt"].each do |file|
5
-
6
- if Filelib.where(filename: file).count > 0
7
- puts "This file has been processed already. File removed."
8
- File.delete(file)
9
- else
10
- print "processing #{file}...\n"
11
- file_data = File.open(file)
12
- data = file_data.read
13
- # Detect to see if the EDI file already has new lines inserted. If so, the newlines are removed before the file gets processed.
14
-
15
- data.gsub!(/\n/, '')
16
-
17
- data = data.split(/~CLP\*/)
18
-
19
- edi_file = EdiReader.new(data)
20
- edi_file.parse_claims
21
- Filelib.insert(filename: file, purpose: '835')
22
- file_data.close
23
- FileUtils.mv(file, "#{DRIVE}/sunnyside-files/835/archive/#{File.basename(file)}")
24
- end
25
- end
26
- end
27
-
28
- class EdiReader
29
- attr_reader :data
30
-
31
- def initialize(data)
32
- @data = data
33
- end
34
-
35
- def claims
36
- data.select { |clm| clm =~ /^\d+/ }.map { |clm| clm.split(/~(?=SVC)/) }
37
- end
38
-
39
- def check_number
40
- check = data[0][/(?<=~TRN\*\d\*)\w+/]
41
- return check.include?('E') ? check[/\d+$/] : check
42
- end
43
-
44
- def check_total
45
- data[0][/(?<=~BPR\*\w\*)[0-9\.\-]+/, 0]
46
- end
47
-
48
- def parse_claims
49
- payment_id = Payment.insert(check_number: check_number, check_total: check_total)
50
- claims.each { |claim| ClaimParser.new(claim, payment_id).parse }
51
- end
52
- end
53
-
54
- class ClaimParser < EdiReader
55
- attr_reader :claim_header, :service_data, :payment_id
56
-
57
- def initialize(claim, payment_id)
58
- @claim_header = claim[0].split(/\*/)
59
- @service_data = claim.select { |clm| clm =~ /^SVC/ }
60
- @payment_id = Payment[payment_id]
61
- end
62
-
63
- def header
64
- {
65
- :invoice => claim_header[0],
66
- :response_code => claim_header[1],
67
- :billed => claim_header[2],
68
- :paid => claim_header[3],
69
- :units => claim_header[5], # 4 is not used - that is the patient responsibility amount
70
- :claim_number => claim_header[6][/^\d+/]
71
- }
72
- end
73
-
74
- def parse
75
- claim = ClaimEntry.new(header)
76
- claim_id = claim.to_db(payment_id)
77
- service_data.each { |service| ServiceParser.new(service, claim_id).parse }
78
- end
79
- end
80
-
81
- class ClaimEntry < EdiReader
82
- attr_reader :invoice, :response_code, :billed, :paid, :units, :claim_number
83
-
84
- def initialize(header = {})
85
- @invoice = header[:invoice].gsub(/[OLD]/, 'O' => '0', 'D' => '8', 'L' => '1').gsub(/^0/, '')[0..5].to_i # for the corrupt SHP EDI files
86
- @response_code = header[:response_code]
87
- @billed = header[:billed]
88
- @paid = header[:paid]
89
- @units = header[:units]
90
- @claim_number = header[:claim_number]
91
- end
92
-
93
- def to_db(payment)
94
- payment.update(provider_id: inv.provider_id) if payment.provider_id.nil?
95
- Claim.insert(
96
- :invoice_id => invoice,
97
- :payment_id => payment.id,
98
- :client_id => inv.client_id,
99
- :control_number => claim_number,
100
- :paid => paid,
101
- :billed => billed,
102
- :status => response_code,
103
- :provider_id => inv.provider_id,
104
- :recipient_id => inv.recipient_id
105
- )
106
- end
107
-
108
- def inv
109
- Invoice[invoice]
110
- end
111
- end
112
-
113
- class ServiceParser < EdiReader
114
- attr_reader :service_line, :claim
115
-
116
- def initialize(service_line, claim_id)
117
- @service_line = service_line.split(/~/)
118
- @claim = Claim[claim_id]
119
- end
120
-
121
- def dos
122
- service_line.detect { |svc| svc =~ /^DTM/ }[/\w+$/]
123
- end
124
-
125
- def service_header
126
- line = service_line[0].split(/\*/).drop(1)
127
- if line.length == 7 || line[1] != line[2]
128
- return line.uniq
129
- else
130
- return line
131
- end
132
- end
133
-
134
- def error_codes
135
- service_line.find_all { |section| section =~ /^CAS|^SE/ }.map { |code| code[/\w+\*\w+\*(\d+)/, 1] }
136
- end
137
-
138
- def parse
139
- service = ServiceEntry.new(service_header, dos, error_codes)
140
- service.to_db(claim)
141
- end
142
- end
143
-
144
- class ServiceEntry < EdiReader
145
- attr_reader :paid, :billed, :service_code, :units, :res_code, :error_codes, :dos
146
-
147
- def initialize(service_header, dos, error_codes)
148
- @service_code, @billed, @paid, @res_code, @units = service_header
149
- @dos = Date.parse(dos)
150
- @error_codes = error_codes.map { |id| Denial[id].denial_explanation }
151
- end
152
-
153
- def to_db(claim)
154
- Service.insert(
155
- :claim_id => claim.id,
156
- :invoice_id => claim.invoice_id,
157
- :payment_id => claim.payment_id,
158
- :denial_reason => denial_reason,
159
- :service_code => service_code.gsub(/HC:/, ''),
160
- :paid => paid,
161
- :billed => billed,
162
- :units => units,
163
- :dos => dos
164
- )
165
- end
166
-
167
- def denial_reason
168
- error_codes.join("\n") if denied?
169
- end
170
-
171
- def denied?
172
- paid != billed
173
- end
174
- end
1
+ module Sunnyside
2
+ def self.edi_parser
3
+ print "checking for new files...\n"
4
+ Dir["#{DRIVE}/sunnyside-files/835/*.txt"].each do |file|
5
+
6
+ if Filelib.where(filename: file).count > 0
7
+ puts "This file has been processed already. File removed."
8
+ File.delete(file)
9
+ else
10
+ print "processing #{file}...\n"
11
+ file_data = File.open(file)
12
+ data = file_data.read
13
+ # Detect to see if the EDI file already has new lines inserted. If so, the newlines are removed before the file gets processed.
14
+
15
+ data.gsub!(/\n/, '')
16
+
17
+ data = data.split(/~CLP\*/)
18
+
19
+ edi_file = EdiReader.new(data)
20
+ edi_file.parse_claims
21
+ Filelib.insert(filename: File.basename(file), purpose: '835')
22
+ file_data.close
23
+ FileUtils.mv(file, "#{DRIVE}/sunnyside-files/835/archive/#{File.basename(file)}")
24
+ end
25
+ end
26
+ end
27
+
28
+ class EdiReader
29
+ attr_reader :data
30
+
31
+ def initialize(data)
32
+ @data = data
33
+ end
34
+
35
+ def claims
36
+ data.select { |clm| clm =~ /^\d+/ }.map { |clm| clm.split(/~(?=SVC)/) }
37
+ end
38
+
39
+ def check_number
40
+ check = data[0][/(?<=~TRN\*\d\*)\w+/]
41
+ return check.include?('E') ? check[/\d+$/] : check
42
+ end
43
+
44
+ def check_total
45
+ data[0][/(?<=~BPR\*\w\*)[0-9\.\-]+/, 0]
46
+ end
47
+
48
+ def parse_claims
49
+ payment_id = Payment.insert(check_number: check_number, check_total: check_total)
50
+ claims.each { |claim| ClaimParser.new(claim, payment_id).parse }
51
+ end
52
+ end
53
+
54
+ class ClaimParser < EdiReader
55
+ attr_reader :claim_header, :service_data, :payment_id
56
+
57
+ def initialize(claim, payment_id)
58
+ @claim_header = claim[0].split(/\*/)
59
+ @service_data = claim.select { |clm| clm =~ /^SVC/ }
60
+ @payment_id = Payment[payment_id]
61
+ end
62
+
63
+ def header
64
+ {
65
+ :invoice => claim_header[0],
66
+ :response_code => claim_header[1],
67
+ :billed => claim_header[2],
68
+ :paid => claim_header[3],
69
+ :units => claim_header[5], # 4 is not used - that is the patient responsibility amount
70
+ :claim_number => claim_header[6][/^\d+/]
71
+ }
72
+ end
73
+
74
+ def parse
75
+ claim = ClaimEntry.new(header)
76
+ claim_id = claim.to_db(payment_id)
77
+ service_data.each { |service| ServiceParser.new(service, claim_id).parse }
78
+ end
79
+ end
80
+
81
+ class ClaimEntry < EdiReader
82
+ attr_reader :invoice, :response_code, :billed, :paid, :units, :claim_number
83
+
84
+ def initialize(header = {})
85
+ @invoice = header[:invoice].gsub(/[OLD]/, 'O' => '0', 'D' => '8', 'L' => '1').gsub(/^0/, '')[0..5].to_i # for the corrupt SHP EDI files
86
+ @response_code = header[:response_code]
87
+ @billed = header[:billed]
88
+ @paid = header[:paid]
89
+ @units = header[:units]
90
+ @claim_number = header[:claim_number]
91
+ end
92
+
93
+ def to_db(payment)
94
+ payment.update(provider_id: inv.provider_id) if payment.provider_id.nil?
95
+ Claim.insert(
96
+ :invoice_id => invoice,
97
+ :payment_id => payment.id,
98
+ :client_id => inv.client_id,
99
+ :control_number => claim_number,
100
+ :paid => paid,
101
+ :billed => billed,
102
+ :status => response_code,
103
+ :provider_id => inv.provider_id,
104
+ :recipient_id => inv.recipient_id
105
+ )
106
+ end
107
+
108
+ def inv
109
+ Invoice[invoice]
110
+ end
111
+ end
112
+
113
+ class ServiceParser < EdiReader
114
+ attr_reader :service_line, :claim
115
+
116
+ def initialize(service_line, claim_id)
117
+ @service_line = service_line.split(/~/)
118
+ @claim = Claim[claim_id]
119
+ end
120
+
121
+ def dos
122
+ service_line.detect { |svc| svc =~ /^DTM/ }[/\w+$/]
123
+ end
124
+
125
+ def service_header
126
+ line = service_line[0].split(/\*/).drop(1)
127
+ if line.length == 7 || line[1] != line[2]
128
+ return line.uniq
129
+ else
130
+ return line
131
+ end
132
+ end
133
+
134
+ def error_codes
135
+ service_line.find_all { |section| section =~ /^CAS|^SE/ }.map { |code| code[/\w+\*\w+\*(\d+)/, 1] }
136
+ end
137
+
138
+ def parse
139
+ service = ServiceEntry.new(service_header, dos, error_codes)
140
+ service.to_db(claim)
141
+ end
142
+ end
143
+
144
+ class ServiceEntry < EdiReader
145
+ attr_reader :paid, :billed, :service_code, :units, :res_code, :error_codes, :dos
146
+
147
+ def initialize(service_header, dos, error_codes)
148
+ @service_code, @billed, @paid, @res_code, @units = service_header
149
+ @dos = Date.parse(dos)
150
+ @error_codes = error_codes.map { |id| Denial[id].denial_explanation }
151
+ end
152
+
153
+ def to_db(claim)
154
+ Service.insert(
155
+ :claim_id => claim.id,
156
+ :invoice_id => claim.invoice_id,
157
+ :payment_id => claim.payment_id,
158
+ :denial_reason => denial_reason,
159
+ :service_code => service_code.gsub(/HC:/, ''),
160
+ :paid => paid,
161
+ :billed => billed,
162
+ :units => units,
163
+ :dos => dos
164
+ )
165
+ end
166
+
167
+ def denial_reason
168
+ error_codes.join("\n") if denied?
169
+ end
170
+
171
+ def denied?
172
+ paid != billed
173
+ end
174
+ end
175
175
  end