sunnyside 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/sunnyside +6 -0
- data/lib/sunnyside/cash_receipts/cash_receipt.rb +169 -0
- data/lib/sunnyside/cash_receipts/ics.rb +69 -0
- data/lib/sunnyside/expiring_auth.rb +101 -0
- data/lib/sunnyside/ftp.rb +97 -0
- data/lib/sunnyside/ledger/auth_report.rb +110 -0
- data/lib/sunnyside/ledger/edi.rb +181 -0
- data/lib/sunnyside/ledger/ledger.rb +142 -0
- data/lib/sunnyside/ledger/private.rb +70 -0
- data/lib/sunnyside/menu.rb +41 -0
- data/lib/sunnyside/models/db_setup.rb +158 -0
- data/lib/sunnyside/models/sequel_classes.rb +12 -0
- data/lib/sunnyside/reports/mco_mltc.rb +43 -0
- data/lib/sunnyside/reports/pdf_report.rb +162 -0
- data/lib/sunnyside/reports/pdf_report_draft.rb +127 -0
- data/lib/sunnyside/reports/private.rb +55 -0
- data/lib/sunnyside/reports/report.rb +74 -0
- data/lib/sunnyside/version.rb +3 -0
- data/lib/sunnyside.rb +27 -0
- metadata +148 -0
@@ -0,0 +1,181 @@
|
|
1
|
+
module Sunnyside
|
2
|
+
def self.edi_parser
|
3
|
+
print "checking for new files...\n"
|
4
|
+
Dir["#{LOCAL_FILES}/835/*.txt"].select { |file| Filelib.where(:filename => file).count == 0 }.each do |file|
|
5
|
+
print "processing #{file}...\n"
|
6
|
+
data = File.open(file).read.split(/~CLP\*/)
|
7
|
+
edi = Edi.new(data, file)
|
8
|
+
edi.parse_claim_header
|
9
|
+
Filelib.insert(filename: file, created_at: Time.now, purpose: 'EDI Import', file_type: '835 Remittance')
|
10
|
+
edi.save_payment_to_db
|
11
|
+
end
|
12
|
+
end
|
13
|
+
class Edi
|
14
|
+
attr_reader :header, :claims, :file
|
15
|
+
def initialize(data, file)
|
16
|
+
@header, @claims = data[0], data.drop(1)
|
17
|
+
@file = file
|
18
|
+
end
|
19
|
+
|
20
|
+
def process_file
|
21
|
+
claims.map { |clm| clm.split(/~(?=SVC)/) }.each do |claim|
|
22
|
+
claim_head = claim[0]
|
23
|
+
services = claim.select { |section| section =~ /^SVC/ }
|
24
|
+
InvoiceHeader.new(claim_head, services).parse_data
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def check_number
|
29
|
+
header[/(?<=~TRN\*\d\*)\w+/, 0]
|
30
|
+
end
|
31
|
+
|
32
|
+
def check_total
|
33
|
+
header[/(?<=~BPR\*\w\*)[0-9\.\-]+/] || 0.0
|
34
|
+
end
|
35
|
+
|
36
|
+
def type
|
37
|
+
if header[/(?<=\*C\*)ACH/] == 'ACH'
|
38
|
+
'Electronic Funds Transfer'
|
39
|
+
elsif header[/(?<=\*C\*)CHK/] == 'CHK'
|
40
|
+
'Physical Check Issued'
|
41
|
+
else
|
42
|
+
'Non Payment'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# not working
|
47
|
+
|
48
|
+
# def check
|
49
|
+
# if check_number.include?('E') # E for Fidelis
|
50
|
+
# check_number[/\d+[A-Z]+(\d+)/, 1]
|
51
|
+
# else
|
52
|
+
# check_number
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
|
56
|
+
def separate_claims_from_services
|
57
|
+
claims.map {|clm| clm.split(/~(?=SVC)/)}
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_claim_header
|
61
|
+
separate_claims_from_services.each do |clm|
|
62
|
+
claim_data = clm[0]
|
63
|
+
services = clm.reject{|x| x !~ /^SVC/}
|
64
|
+
claims = InvoiceHeader.new(claim_data, check_number)
|
65
|
+
claims.format_data
|
66
|
+
claims.add_to_db(check_number, file)
|
67
|
+
parse_service(services) {|svc| claims.parse_svc(svc, check_number)}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def save_payment_to_db
|
72
|
+
provider = Claim.where(check_number: check_number).get(:provider_id) || 17
|
73
|
+
Payment.insert(provider_id: provider, filelib_id: filelib_id, check_total: check_total, check_number: check_number)
|
74
|
+
end
|
75
|
+
|
76
|
+
def filelib_id
|
77
|
+
Filelib.where(filename: file).get(:id)
|
78
|
+
end
|
79
|
+
|
80
|
+
def parse_service(services)
|
81
|
+
services.map{|x| x.split(/~/).reject{|x| x !~ /CAS|SVC|DTM/}}.each {|svc| yield svc}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class InvoiceHeader < Edi
|
86
|
+
attr_accessor :claim_number, :invoice_number, :response_code, :amt_charged, :amt_paid, :check_number
|
87
|
+
def initialize(claim, check_number)
|
88
|
+
@invoice_number, @response_code, @amt_charged, @amt_paid, @whatever, @claim_number = claim.match(/^([\w\.]+)\*(\d+)\*([0-9\.\-]+)\*([0-9\.\-]+)\*([0-9\.\-]+)?\*+\w+\*(\w+)/).captures
|
89
|
+
@check_number = check_number
|
90
|
+
end
|
91
|
+
|
92
|
+
def format_data
|
93
|
+
@invoice_number = invoice_number[/^\w+/].gsub(/[OLD]/, 'O' => '0', 'D' => '8', 'L' => '1').gsub(/^0/, '')[0..5].to_i
|
94
|
+
end
|
95
|
+
|
96
|
+
def claim_id
|
97
|
+
Claim.where(invoice_id: invoice_number, check_number: check_number).get(:id)
|
98
|
+
end
|
99
|
+
|
100
|
+
def parse_svc(service, check_number)
|
101
|
+
if service.length == 2
|
102
|
+
svc = Detail.new(service[0], service[1])
|
103
|
+
elsif service.length > 2
|
104
|
+
svc = Detail.new(service[0], service[1])
|
105
|
+
svc.set_denial(service[2])
|
106
|
+
end
|
107
|
+
svc.display(invoice_number)
|
108
|
+
svc.save_to_db(invoice_number, check_number, claim_id)
|
109
|
+
end
|
110
|
+
|
111
|
+
def prov
|
112
|
+
Invoice.where(invoice_number: invoice_number).get(:provider_id)
|
113
|
+
end
|
114
|
+
|
115
|
+
def add_to_db(check, file)
|
116
|
+
Claim.insert(provider_id: prov, invoice_id: invoice_number, billed: amt_charged, paid: amt_paid, check_number: check_number, control_number: claim_number, status: response_code)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class Detail < Edi
|
121
|
+
|
122
|
+
attr_reader :billed, :paid, :denial_reason, :date, :billed, :paid, :units, :service_code
|
123
|
+
def initialize(service, date, denial_reason=nil, denial_code=nil)
|
124
|
+
@service_code, @billed, @paid, @units = service.match(/HC:([A-Z0-9\:]+)\*([0-9\.\-]+)\*([0-9\.\-]+)?\**([0-9\-]+)?/).captures
|
125
|
+
@date = Date.parse(date[/\d+$/])
|
126
|
+
end
|
127
|
+
|
128
|
+
def display(inv)
|
129
|
+
print "#{inv} #{@service_code} #{@date} #{client(inv)} #{denial}\n"
|
130
|
+
end
|
131
|
+
|
132
|
+
def client(inv)
|
133
|
+
Invoice.where(invoice_number: inv).get(:client_name)
|
134
|
+
end
|
135
|
+
|
136
|
+
def denial
|
137
|
+
(billed.to_f - paid.to_f).round(2) if billed > paid
|
138
|
+
end
|
139
|
+
|
140
|
+
def set_denial(denial)
|
141
|
+
@denial_reason = set_code(denial[/\d+/])
|
142
|
+
end
|
143
|
+
|
144
|
+
def save_to_db(invoice, check, claim_id)
|
145
|
+
Service.insert(invoice_id: invoice, service_code: service_code, units: units.to_f, billed: billed.to_f, paid: paid.to_f, denial_reason: denial_reason, dos: date, claim_id: claim_id)
|
146
|
+
end
|
147
|
+
|
148
|
+
def set_code(code)
|
149
|
+
case code
|
150
|
+
when '125' then return 'Submission/billing error(s). At least one Remark Code must be provided'
|
151
|
+
when '140' then return 'Patient/Insured health identification number and name do not match.'
|
152
|
+
when '31' then return 'INVALID MEMBER ID'
|
153
|
+
when '62' then return 'PAID AUTHORIZED UNITS'
|
154
|
+
when '96' then return 'NO AUTHORIZATION FOR DOS'
|
155
|
+
when '146' then return 'DIAGNOSIS WAS INVALID FOR DATES LISTED'
|
156
|
+
when '197' then return 'Precertification/authorization/notification absent'
|
157
|
+
when '198' then return 'Precertification/authorization exceeded'
|
158
|
+
when '199' then return 'Revenue code and Procedure code do not match'
|
159
|
+
when '9' then return 'DIAGNOSIS ISSUE'
|
160
|
+
when '15' then return 'AUTHORIZATION MISSING/INVALID'
|
161
|
+
when '18' then return 'Exact Duplicate Claim/Service'
|
162
|
+
when '19' then return 'Expenses incurred prior to coverage'
|
163
|
+
when '27' then return 'Expenses incurred after coverage terminated'
|
164
|
+
when '29' then return 'Timely Filing'
|
165
|
+
when '39' then return 'Services denied at the time authorization/pre-certification was requested'
|
166
|
+
when '45' then return 'Charge exceeds fee schedule/maximum allowable'
|
167
|
+
when '16' then return 'Claim/service lacks information which is needed for adjudication'
|
168
|
+
when '50' then return 'These are non-covered services because this is not deemed a medical necessity by the payer'
|
169
|
+
when '192' then return 'Non standard adjustment code from paper remittance'
|
170
|
+
when '181' then return 'Procedure code was invalid on the date of service'
|
171
|
+
when '182' then return 'Procedure modifier was invalid on the date of service'
|
172
|
+
when '204' then return 'This service/equipment/drug is not covered under the patients current benefit plan'
|
173
|
+
when '151' then return '151 Payment adjusted because the payer deems the information submitted does not support this many/frequency of services'
|
174
|
+
when '177' then return 'Patient has not met the required eligibility requirements'
|
175
|
+
when '109' then return 'Claim/service not covered by this payer/contractor. You must send the claim/service to the correct payer/contractor.'
|
176
|
+
else
|
177
|
+
return "#{code} is UNIDENTIFIED"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'prawn'
|
2
|
+
module Sunnyside
|
3
|
+
# This should be redone.
|
4
|
+
def self.ledger_file
|
5
|
+
Dir["#{LOCAL_FILES}/summary/*.PDF", "#{LOCAL_FILES}/summary/*.pdf"].each {|file|
|
6
|
+
if Filelib.where(filename: file).count == 0
|
7
|
+
puts "processing #{file}..."
|
8
|
+
ledger = Ledger.new(file)
|
9
|
+
ledger.process_file
|
10
|
+
Filelib.insert(filename: file, purpose: 'summary')
|
11
|
+
end
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
class Ledger
|
16
|
+
attr_reader :post_date, :file, :pages
|
17
|
+
|
18
|
+
# when Ledger gets initialized, the page variable filters out the VNS clients
|
19
|
+
# and then proceeds to pass the page date onto the PageData class
|
20
|
+
|
21
|
+
def initialize(file)
|
22
|
+
@file = File.basename(file)
|
23
|
+
@pages = PDF::Reader.new(file).pages.select { |page| !page.raw_content.include?('VISITING NURSE SERVICE') }
|
24
|
+
end
|
25
|
+
|
26
|
+
def providers
|
27
|
+
pages.map { |page| PageData.new(page.raw_content, file) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def process_file
|
31
|
+
providers.each { |page| page.invoice_data }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# in PageData, the providers name is captured from the PDF::Reader raw_content, and the post date from the file name.
|
36
|
+
# the rest of the data (the invoices) gets split by newlines (filted by those lines that fit the criteria for invoice data)
|
37
|
+
# Then, the data gets finalized (via the InvoiceLine child class of PageData) and inserted into the database.
|
38
|
+
|
39
|
+
class PageData
|
40
|
+
include Sunnyside
|
41
|
+
attr_reader :page_data, :provider, :post_date
|
42
|
+
|
43
|
+
def initialize(page_data, file, provider = nil)
|
44
|
+
@provider = page_data[/CUSTOMER:\s+(.+)(?=\)')/, 1]
|
45
|
+
@post_date = Date.parse(file[0..7])
|
46
|
+
@page_data = page_data.split(/\n/).select { |line| line =~ /^\([0-9\/]+\s/ }
|
47
|
+
end
|
48
|
+
|
49
|
+
# Since the source data is somewhat unreliable in the format, there have been two different variations of AMERIGROUP and ELDERSERVE.
|
50
|
+
# This method accounts for the aberrations while still maintaining that any provider not recognized by the DB to be saved as a PRIVATE client.
|
51
|
+
|
52
|
+
def formatted_provider
|
53
|
+
if provider_missing?
|
54
|
+
case provider
|
55
|
+
when 'ELDERSERVEHEALTH'
|
56
|
+
Provider.where(name: 'ELDERSERVE HEALTH').first
|
57
|
+
when 'AMERIGROUP'
|
58
|
+
Provider.where(name: 'AMERIGROUP 2').first
|
59
|
+
else
|
60
|
+
Provider.where(name: 'PRIVATE').first
|
61
|
+
end
|
62
|
+
else
|
63
|
+
Provider.where(name: provider).first
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def provider_missing?
|
68
|
+
Provider.where(name: provider).count == 0
|
69
|
+
end
|
70
|
+
|
71
|
+
def invoice_lines
|
72
|
+
page_data.map { |line| InvoiceLine.new(line, formatted_provider, post_date) }
|
73
|
+
end
|
74
|
+
|
75
|
+
def invoice_data
|
76
|
+
invoice_lines.each { |inv| inv.finalize }
|
77
|
+
# Invoice.where(post_date: post_date).all.each { |inv| self.payable_csv(inv, post_date, formatted_provider) }
|
78
|
+
end
|
79
|
+
|
80
|
+
# InvoiceLine does all the nitty-gritty parsing of an invoice line into the necessary fields the DB requres.
|
81
|
+
|
82
|
+
class InvoiceLine < PageData
|
83
|
+
attr_accessor :invoice, :rate, :hours, :amount, :client_id, :client_name, :post_date, :provider
|
84
|
+
def initialize(line, provider, post_date)
|
85
|
+
@provider = provider
|
86
|
+
@post_date = post_date
|
87
|
+
@client_name = line.slice!(20..45)
|
88
|
+
@doc_date, @invoice, @client_id, @hours, @rate, @amount = line.split
|
89
|
+
end
|
90
|
+
|
91
|
+
# Some invoice totals exceed $999.99, so the strings need to be parsed into a format, sans comma, that the DB will read correctly.
|
92
|
+
# Otherwise, the DB will read 1,203.93 as 1.0.
|
93
|
+
|
94
|
+
def amt
|
95
|
+
amount.gsub(/,/, '')
|
96
|
+
end
|
97
|
+
|
98
|
+
# Ocasionally, new clients will appear on the PDF doc. If the DB does not find a client with the client_id, then it executes a method wherein
|
99
|
+
# new client gets saved into the DB with a new FUND EZ ID. It must do this before saving the invoice information.
|
100
|
+
|
101
|
+
def finalize
|
102
|
+
if !client_missing?
|
103
|
+
add_invoice
|
104
|
+
else
|
105
|
+
add_client
|
106
|
+
finalize
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def client_missing?
|
111
|
+
Client[client_id].nil?
|
112
|
+
end
|
113
|
+
|
114
|
+
def add_client
|
115
|
+
Client.insert(client_number: client_id, client_name: client_name)
|
116
|
+
end
|
117
|
+
|
118
|
+
# rarely there may be an invoice line that contains an invoice number that already exists. This method accounts for it, by merely updating the amount.
|
119
|
+
# There has only been two instances of this happening and both occurred in 2011.
|
120
|
+
|
121
|
+
def add_invoice
|
122
|
+
if invoice_exist?
|
123
|
+
update_invoice
|
124
|
+
else
|
125
|
+
Invoice.insert(invoice_number: invoice, rate: rate, hours: hours, amount: amt, client_id: client_id, post_date: post_date, provider_id: provider.id, client_name: client_name.strip)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def invoice_exist?
|
130
|
+
Invoice.where(invoice_number: invoice).count > 0
|
131
|
+
end
|
132
|
+
|
133
|
+
def update_invoice
|
134
|
+
Invoice.where(invoice_number: invoice).update(amount: amt.to_f)
|
135
|
+
end
|
136
|
+
|
137
|
+
def prev_amt
|
138
|
+
Invoice.where(invoice_number: invoice).get(:amount)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Sunnyside
|
2
|
+
def self.process_private
|
3
|
+
Dir["#{LOCAL_FILES}/private/*.PDF", "#{LOCAL_FILES}/private/*.pdf"].select { |file| Filelib.where(filename: file).count == 0 }.each do |file|
|
4
|
+
puts "processing #{file}..."
|
5
|
+
PDF::Reader.new(file).pages.each { |inv|
|
6
|
+
page = inv.text.split(/\n/)
|
7
|
+
InvoiceParse.new(page).process if page.include?('Remit')
|
8
|
+
}
|
9
|
+
Filelib.insert(filename: file, purpose: 'private client visit data')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class InvoiceParse
|
14
|
+
attr_reader :invoice_line, :client_line, :service_lines
|
15
|
+
def initialize(page)
|
16
|
+
@invoice_line = page.select { |line| line =~ /[0-9\/]{8}\s+\d{7}/ }.join
|
17
|
+
@client_line = page.select { |line| line =~ /[0-9]{7}\s+[0-9]{7}/ }.join
|
18
|
+
@service_lines = page.map { |line| ServiceLine.new(line) if line =~ /\sHHA\s|\sPCA\s/ }.compact
|
19
|
+
end
|
20
|
+
|
21
|
+
def invoice
|
22
|
+
invoice_line[/(\d{7})$/, 1].gsub(/^0/, '')
|
23
|
+
end
|
24
|
+
|
25
|
+
def client_number
|
26
|
+
client_line[/[0-9]{7}/, 0]
|
27
|
+
end
|
28
|
+
|
29
|
+
def process
|
30
|
+
service_lines.each { |line| line.to_db(invoice, client_number) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class ServiceLine
|
35
|
+
attr_reader :line
|
36
|
+
|
37
|
+
def initialize(line)
|
38
|
+
@line = line
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_db(invoice, client_number)
|
42
|
+
Visit.insert(invoice_id: invoice, client_id: client_number, dos: Date.strptime(service_date, '%m/%d/%y'), service_code: code, amount: amount)
|
43
|
+
end
|
44
|
+
|
45
|
+
def service_date
|
46
|
+
line[/[0-9\/]{8}/, 0]
|
47
|
+
end
|
48
|
+
|
49
|
+
def code
|
50
|
+
if line =~ / HHA /
|
51
|
+
'HHA'
|
52
|
+
else
|
53
|
+
'PCA'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def line_split
|
58
|
+
line.split
|
59
|
+
end
|
60
|
+
|
61
|
+
def amount
|
62
|
+
line_split[-1]
|
63
|
+
end
|
64
|
+
|
65
|
+
def rate
|
66
|
+
line_split[-2]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Sunnyside
|
2
|
+
class Menu
|
3
|
+
def start
|
4
|
+
loop do
|
5
|
+
puts "1.) LEDGER IMPORT"
|
6
|
+
puts "2.) EDI IMPORT"
|
7
|
+
puts "3.) 837 IMPORT"
|
8
|
+
puts "4.) A/R REPORT"
|
9
|
+
puts "5.) CASH RECEIPT IMPORT"
|
10
|
+
puts "6.) ACCESS FTP"
|
11
|
+
puts "7.) EXPIRING AUTHORIZATION REPORT"
|
12
|
+
puts "9.) MCO - MLTC HOURS UPDATE"
|
13
|
+
print "select option: "
|
14
|
+
case gets.chomp
|
15
|
+
when '1'
|
16
|
+
Sunnyside.ledger_file
|
17
|
+
Sunnyside.process_private
|
18
|
+
when '2'
|
19
|
+
Sunnyside.edi_parser
|
20
|
+
when '3'
|
21
|
+
Sunnyside.parse_pdf
|
22
|
+
when '4'
|
23
|
+
Sunnyside::Report.new
|
24
|
+
when '5'
|
25
|
+
Sunnyside::CashReceipt.new.process
|
26
|
+
when '6'
|
27
|
+
Sunnyside.access_ftp(:download)
|
28
|
+
Sunnyside.access_ftp(:upload)
|
29
|
+
when '7'
|
30
|
+
Sunnyside.show_opts
|
31
|
+
when '8'
|
32
|
+
Sunnyside.process_private
|
33
|
+
when '9'
|
34
|
+
Sunnyside.run_mco_mltc
|
35
|
+
else
|
36
|
+
exit
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
module Sunnyside
|
2
|
+
class << self
|
3
|
+
def create_tables
|
4
|
+
DB.create_table :charges do
|
5
|
+
primary_key :id
|
6
|
+
foreign_key :invoice_id, :invoices
|
7
|
+
foreign_key :provider_id, :providers
|
8
|
+
Date :dos
|
9
|
+
Float :amount
|
10
|
+
Float :units
|
11
|
+
String :service_code
|
12
|
+
String :filename
|
13
|
+
end
|
14
|
+
|
15
|
+
DB.create_table :invoices do
|
16
|
+
Integer :invoice_number, :primary_key=>true
|
17
|
+
index :invoice_number
|
18
|
+
Float :amount
|
19
|
+
Date :post_date, :default=>Date.today
|
20
|
+
foreign_key :client_id, :clients
|
21
|
+
foreign_key :provider_id, :providers
|
22
|
+
foreign_key :filelib_id, :filelibs
|
23
|
+
String :client_name
|
24
|
+
Float :rate
|
25
|
+
Float :hours
|
26
|
+
end
|
27
|
+
|
28
|
+
DB.create_table :payments do
|
29
|
+
primary_key :id
|
30
|
+
foreign_key :provider_id, :providers
|
31
|
+
foreign_key :filelib_id, :filelibs
|
32
|
+
Float :check_total
|
33
|
+
String :status
|
34
|
+
Integer :check_number
|
35
|
+
end
|
36
|
+
|
37
|
+
DB.create_table :claims do
|
38
|
+
primary_key :id
|
39
|
+
index :id
|
40
|
+
String :control_number
|
41
|
+
foreign_key :payment_id, :payments
|
42
|
+
foreign_key :invoice_id, :invoices
|
43
|
+
foreign_key :client_id, :clients
|
44
|
+
Float :paid
|
45
|
+
Float :billed
|
46
|
+
String :status
|
47
|
+
String :recipient_id
|
48
|
+
foreign_key :provider_id, :providers
|
49
|
+
Date :post_date
|
50
|
+
end
|
51
|
+
|
52
|
+
DB.create_table :services do
|
53
|
+
primary_key :id
|
54
|
+
foreign_key :claim_id, :claims
|
55
|
+
foreign_key :payment_id, :payments
|
56
|
+
foreign_key :invoice_id, :invoices
|
57
|
+
foreign_key :client_id, :clients
|
58
|
+
String :service_code
|
59
|
+
Float :paid
|
60
|
+
Float :billed
|
61
|
+
String :denial_reason
|
62
|
+
Float :units
|
63
|
+
Date :dos
|
64
|
+
end
|
65
|
+
|
66
|
+
DB.create_table :clients do
|
67
|
+
Integer :client_number, :primary_key=>true
|
68
|
+
String :client_name
|
69
|
+
String :fund_id
|
70
|
+
String :recipient_id
|
71
|
+
end
|
72
|
+
|
73
|
+
DB.create_table :providers do
|
74
|
+
primary_key :id
|
75
|
+
Integer :credit_account
|
76
|
+
Integer :fund
|
77
|
+
Integer :debit_account
|
78
|
+
String :name
|
79
|
+
String :abbreviation
|
80
|
+
String :type
|
81
|
+
String :edi_identifier
|
82
|
+
end
|
83
|
+
|
84
|
+
DB.create_table :filelibs do
|
85
|
+
primary_key :id
|
86
|
+
String :filename
|
87
|
+
String :purpose
|
88
|
+
String :file_type
|
89
|
+
Time :created_at
|
90
|
+
end
|
91
|
+
|
92
|
+
DB.create_table :visits do
|
93
|
+
primary_key :id
|
94
|
+
String :service_code
|
95
|
+
String :modifier
|
96
|
+
foreign_key :invoice_id, :invoices
|
97
|
+
foreign_key :client_id, :clients
|
98
|
+
Float :amount
|
99
|
+
Float :units
|
100
|
+
Date :dos
|
101
|
+
end
|
102
|
+
|
103
|
+
DB.create_table :denials do
|
104
|
+
primary_key :denial_code, :primary_key=>true
|
105
|
+
String :denial_explanation
|
106
|
+
end
|
107
|
+
|
108
|
+
DB[:providers].insert(:credit_account=>1206, :fund=>500, :debit_account=>5005, :name=>"AMERIGROUP 2", :abbreviation=>"AMG", :type=>"MCO")
|
109
|
+
DB[:providers].insert(:credit_account=>1207, :fund=>300, :debit_account=>5007, :name=>"CHILDREN'S AID SOCIETY", :abbreviation=>"CAS", :type=>"MLTC")
|
110
|
+
DB[:providers].insert(:credit_account=>1226, :fund=>300, :debit_account=>5026, :name=>"COMPREHENSIVE CARE MANAGEMENT", :abbreviation=>"CCM", :type=>"MLTC")
|
111
|
+
DB[:providers].insert(:credit_account=>1203, :fund=>300, :debit_account=>5002, :name=>"DOMINICAN SISTERS FAM HLTH", :abbreviation=>"DSF", :type=>"MLTC")
|
112
|
+
DB[:providers].insert(:credit_account=>1209, :fund=>300, :debit_account=>5009, :name=>"ELDERSERVE HEALTH", :abbreviation=>"ELD", :type=>"MLTC")
|
113
|
+
DB[:providers].insert(:credit_account=>1212, :fund=>300, :debit_account=>5012, :name=>"EMBLEM HEALTH", :abbreviation=>"EMB", :type=>"MLTC")
|
114
|
+
DB[:providers].insert(:credit_account=>1201, :fund=>300, :debit_account=>5001, :name=>"GUILDNET", :abbreviation=>"G", :type=>"MLTC")
|
115
|
+
DB[:providers].insert(:credit_account=>1227, :fund=>500, :debit_account=>5027, :name=>"HEALTH CARE PARTNERS", :abbreviation=>"HCP", :type=>"MCO")
|
116
|
+
DB[:providers].insert(:credit_account=>1218, :fund=>500, :debit_account=>5018, :name=>"HEALTH FIRST", :abbreviation=>"HFS", :type=>"MCO")
|
117
|
+
DB[:providers].insert(:credit_account=>1216, :fund=>500, :debit_account=>5016, :name=>"HEALTH INSURANCE PLAN OF NY", :abbreviation=>"HIP", :type=>"MCO")
|
118
|
+
DB[:providers].insert(:credit_account=>1223, :fund=>300, :debit_account=>5023, :name=>"HHH LONG TERM HOME HLTH CARE", :abbreviation=>"HHH", :type=>"MLTC")
|
119
|
+
DB[:providers].insert(:credit_account=>1228, :fund=>300, :debit_account=>5028, :name=>"INDEPENDENCE CARE SYSTEMS", :abbreviation=>"ICS", :type=>"MLTC")
|
120
|
+
DB[:providers].insert(:credit_account=>1217, :fund=>500, :debit_account=>5017, :name=>"METROPLUS HEALTH", :abbreviation=>"MPH", :type=>"MCO")
|
121
|
+
DB[:providers].insert(:credit_account=>1219, :fund=>500, :debit_account=>5019, :name=>"NEIGHBORHOOD HEALTH PROVIDERS", :abbreviation=>"NHP", :type=>"MCO")
|
122
|
+
DB[:providers].insert(:credit_account=>1221, :fund=>500, :debit_account=>5021, :name=>"NYS CATHOLIC/FIDELIS", :abbreviation=>"FID", :type=>"MCO")
|
123
|
+
DB[:providers].insert(:credit_account=>1200, :fund=>300, :debit_account=>5000, :name=>"PRIVATE", :abbreviation=>"P", :type=>"MLTC")
|
124
|
+
DB[:providers].insert(:credit_account=>1204, :fund=>300, :debit_account=>5004, :name=>"SENIOR HEALTH PARTNERS", :abbreviation=>"SHP", :type=>"MLTC")
|
125
|
+
DB[:providers].insert(:credit_account=>1202, :fund=>300, :debit_account=>5003, :name=>"SUNNYSIDE COMMUNITY SERVICES", :abbreviation=>"SCS", :type=>"MLTC")
|
126
|
+
DB[:providers].insert(:credit_account=>1213, :fund=>500, :debit_account=>5013, :name=>"UNITED HEALTH CARE", :abbreviation=>"UHC", :type=>"MCO")
|
127
|
+
DB[:providers].insert(:credit_account=>1229, :fund=>500, :debit_account=>5029, :name=>"VNSNY CHOICE SELECT HEALTH", :abbreviation=>"VCS", :type=>"MCO")
|
128
|
+
DB[:providers].insert(:credit_account=>1224, :fund=>500, :debit_account=>5024, :name=>"WELCARE OF NEW YORK, INC.", :abbreviation=>"WEL", :type=>"MCO")
|
129
|
+
DB[:providers].insert(:credit_account=>1310, :fund=>300, :debit_account=>5030, :name=>"VILLAGE CARE MAX", :abbreviation=>"VIL", :type=>"MLTC")
|
130
|
+
DB[:providers].insert(:credit_account=>1222, :fund=>500, :debit_account=>5022, :name=>"AFFINITY HEALTH PLUS", :abbreviation=>"AFF", :type=>"MCO")
|
131
|
+
DB[:providers].insert(:credit_account=>1218, :fund=>500, :debit_account=>5018, :name=>"HEALTH PLUS PHSP,INC", :abbreviation=>"HFS", :type=>"MCO")
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# DB[:denials].insert(denial_code: 1, denial_explanation: 'not implemented yet')
|
138
|
+
# DB[:denials].insert(denial_code: 96, denial_explanation: "NO AUTHORIZATION FOR DOS")
|
139
|
+
# DB[:denials].insert(denial_code: 197, denial_explanation: "Precertification/authorization/notification absent")
|
140
|
+
# DB[:denials].insert(denial_code: 198, denial_explanation: "Precertification/authorization exceeded")
|
141
|
+
# DB[:denials].insert(denial_code: 199, denial_explanation: "Revenue code and Procedure code do not match")
|
142
|
+
# DB[:denials].insert(denial_code: 9, denial_explanation: "DIAGNOSIS ISSUE")
|
143
|
+
# DB[:denials].insert(denial_code: 15, denial_explanation: "AUTHORIZATION MISSING/INVALID")
|
144
|
+
# DB[:denials].insert (denial_code: 18, denial_explanation: "Exact Duplicate Claim/Service")
|
145
|
+
# DB[:denials].insert(denial_code: 19, denial_explanation: "Expenses incurred prior to coverage")
|
146
|
+
# DB[:denials].insert(denial_code: 27, denial_explanation: "Expenses incurred after coverage terminated")
|
147
|
+
# DB[:denials].insert(denial_code: 29, denial_explanation: "Timely Filing")
|
148
|
+
# DB[:denials].insert(denial_code: 39, denial_explanation: "Services denied at the time authorization/pre-certification was requested")
|
149
|
+
# DB[:denials].insert(denial_code: 45, denial_explanation: "Charge exceeds fee schedule/maximum allowable")
|
150
|
+
# DB[:denials].insert(denial_code: 16, denial_explanation: "Claim/service lacks information which is needed for adjudication")
|
151
|
+
# DB[:denials].insert(denial_code: 50, denial_explanation: "These are non-covered services because this is not deemed a 'medical necessity' by the payer")
|
152
|
+
# DB[:denials].insert(denial_code: 192, denial_explanation: "Non standard adjustment code from paper remittance")
|
153
|
+
# DB[:denials].insert(denial_code: 181, denial_explanation: "Procedure code was invalid on the date of service")
|
154
|
+
# DB[:denials].insert(denial_code: 182, denial_explanation: "Procedure modifier was invalid on the date of service")
|
155
|
+
# DB[:denials].insert(denial_code: 204, denial_explanation: "This service/equipment/drug is not covered under the patients current benefit plan")
|
156
|
+
# DB[:denials].insert(denial_code: 151, denial_explanation: "151 Payment adjusted because the payer deems the information submitted does not support this many/frequency of services")
|
157
|
+
# DB[:denials].insert(denial_code: 177, denial_explanation: "Patient has not met the required eligibility requirements")
|
158
|
+
# DB[:denials].insert(denial_code: 109, denial_explanation: "Claim/service not covered by this payer/contractor. You must send the claim/service to the correct payer/contractor.")
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Sunnyside
|
2
|
+
class Auth < Sequel::Model; end
|
3
|
+
class Charge < Sequel::Model; end
|
4
|
+
class Invoice < Sequel::Model; end
|
5
|
+
class Filelib < Sequel::Model; end
|
6
|
+
class Payment < Sequel::Model; end
|
7
|
+
class Claim < Sequel::Model; end
|
8
|
+
class Client < Sequel::Model; end
|
9
|
+
class Service < Sequel::Model; end
|
10
|
+
class Provider < Sequel::Model; end
|
11
|
+
class Visit < Sequel::Model; end
|
12
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Sunnyside
|
2
|
+
def self.run_mco_mltc
|
3
|
+
print "Type in post date (YYYY-MM-DD): "
|
4
|
+
post_date = gets.chomp
|
5
|
+
Provider.map(:name).each do |provider|
|
6
|
+
ReportMCO.new(provider, post_date).run
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class ReportMCO
|
11
|
+
attr_reader :provider, :post_date, :clients
|
12
|
+
# attr_accessor :mco_total, :mltc_total
|
13
|
+
|
14
|
+
def initialize(provider, post_date)
|
15
|
+
@provider = provider
|
16
|
+
@post_date = post_date
|
17
|
+
@clients = Client.where(provider: provider)
|
18
|
+
# @mco_total = 0.0
|
19
|
+
# @mltc_total = 0.0
|
20
|
+
end
|
21
|
+
|
22
|
+
def run
|
23
|
+
mco_total = 0.0
|
24
|
+
mltc_total = 0.0
|
25
|
+
invoices.each do |inv|
|
26
|
+
if inv[:type] == 'MCO'
|
27
|
+
mco_total += inv[:hours]
|
28
|
+
# mco_total += inv.hours
|
29
|
+
elsif inv[:type] == 'MLTC'
|
30
|
+
mltc_total += inv[:hours]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
puts "#{provider}: MCO => #{mco_total} MLTC => #{mltc_total}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def invoices
|
37
|
+
Invoice.where(provider: provider, post_date: post_date).all.map { |invoice|
|
38
|
+
{ :type => Client.where(med_id: invoice.service_number).exclude(type: nil).get(:type),
|
39
|
+
:hours => invoice.hours }
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|