sunnyside 0.0.5 → 0.0.7
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.
- data/lib/sunnyside/cash_receipts/cash_receipt.rb +129 -101
- data/lib/sunnyside/ftp.rb +40 -30
- data/lib/sunnyside/ledger/auth_report.rb +24 -30
- data/lib/sunnyside/ledger/edi.rb +120 -165
- data/lib/sunnyside/ledger/ledger.rb +32 -22
- data/lib/sunnyside/ledger/private.rb +10 -7
- data/lib/sunnyside/menu.rb +14 -12
- data/lib/sunnyside/models/db_setup.rb +41 -35
- data/lib/sunnyside/models/sequel_classes.rb +1 -0
- data/lib/sunnyside/query/query.rb +29 -0
- data/lib/sunnyside/reports/pdf_report.rb +81 -136
- data/lib/sunnyside/reports/private.rb +1 -1
- data/lib/sunnyside/reports/report.rb +77 -35
- data/lib/sunnyside/version.rb +1 -1
- data/lib/sunnyside.rb +9 -10
- metadata +3 -3
- data/lib/sunnyside/cash_receipts/ics.rb +0 -69
@@ -1,123 +1,149 @@
|
|
1
1
|
module Sunnyside
|
2
2
|
|
3
|
-
def
|
3
|
+
def self.cash_receipt
|
4
4
|
puts "1.) EDI PAYMENT"
|
5
5
|
puts "2.) MANUAL PAYMENT"
|
6
|
-
|
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
|
7
14
|
end
|
8
15
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
+
class CashReceipt
|
17
|
+
attr_reader :post_date, :type_of_entry
|
18
|
+
|
19
|
+
def initialize(type_of_entry)
|
20
|
+
print "Enter in post date (YYYY-MM-DD): "
|
21
|
+
@post_date = Date.parse(gets.chomp)
|
22
|
+
@type_of_entry = type_of_entry
|
16
23
|
end
|
17
|
-
end
|
18
24
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
25
|
+
def collate
|
26
|
+
case type_of_entry
|
27
|
+
when :electronic
|
28
|
+
Sunnyside.check_prompt { |payment_id| EdiPayment.new(payment_id, post_date).collate }
|
29
|
+
when :manual
|
30
|
+
manual_invoices
|
31
|
+
else
|
32
|
+
exit
|
33
|
+
end
|
34
|
+
end
|
23
35
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
36
|
+
def invoice_selection
|
37
|
+
puts "Enter in the invoices, each separated by a space. If any invoice has a denial, 'flag' it by typing '-d' after the invoice number.\n"
|
38
|
+
invoices = gets.chomp.split
|
39
|
+
print "You have typed out #{invoices.length} number of invoices. Do you wish to add more to the same check? (Y or N): "
|
40
|
+
if gets.chomp.upcase == 'Y'
|
41
|
+
more_invoices = gets.chomp.split
|
42
|
+
return (more_invoices + invoices)
|
43
|
+
else
|
44
|
+
return invoices
|
45
|
+
end
|
29
46
|
end
|
30
47
|
|
31
|
-
def
|
32
|
-
|
48
|
+
def manual_invoices
|
49
|
+
print "# of checks to enter for the post date of #{post_date}? "
|
50
|
+
num = gets.chomp.to_i
|
51
|
+
num.times do
|
52
|
+
prov = provider
|
53
|
+
print "Enter in the check number: "
|
54
|
+
check = gets.chomp
|
55
|
+
invoices = invoice_selection
|
56
|
+
manual = ManualPayment.new(invoices, post_date, prov, check)
|
57
|
+
manual.seed_claims_and_services
|
58
|
+
manual.create_csv
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def provider
|
63
|
+
Provider.all.each { |prov| puts "#{prov.id}: #{prov.name}"}
|
64
|
+
print "Type in the Provider ID: "
|
65
|
+
return Provider[gets.chomp] || ''
|
33
66
|
end
|
34
67
|
end
|
35
68
|
|
69
|
+
|
70
|
+
|
36
71
|
class EdiPayment
|
37
72
|
include Sunnyside
|
38
|
-
attr_reader :
|
39
|
-
|
40
|
-
def initialize
|
41
|
-
@check_number, @post_date, @prov = self.check_date_abbre
|
42
|
-
end
|
73
|
+
attr_reader :payment, :post_date
|
43
74
|
|
44
|
-
def
|
45
|
-
|
75
|
+
def initialize(payment, post_date)
|
76
|
+
@payment, @post_date = payment, post_date
|
46
77
|
end
|
47
78
|
|
48
79
|
def populated_data
|
49
|
-
|
80
|
+
Claim.where(payment_id: payment.id).all.select { |clm| clm.paid > 0.0 }
|
50
81
|
end
|
51
82
|
|
52
83
|
def total
|
53
|
-
populated_data.map { |
|
54
|
-
end
|
55
|
-
|
56
|
-
def payment_id
|
57
|
-
Payment.where(check_number: check_number).get(:id)
|
84
|
+
populated_data.map { |clm| clm.paid }.inject { |x, y| x + y }.round(2)
|
58
85
|
end
|
59
86
|
|
60
87
|
def collate
|
61
88
|
puts "Total Amount Paid for this check is: #{total}\nProcessing..."
|
62
|
-
populated_data.each
|
63
|
-
|
64
|
-
|
89
|
+
populated_data.each do |clm|
|
90
|
+
if not_paid_fully?(clm)
|
91
|
+
self.receivable_csv(clm, payment, post_date)
|
92
|
+
else
|
93
|
+
print "#{clm.invoice_id} was not added to the spreadsheet because the invoice was already fully paid for.\n"
|
94
|
+
print "Please consider this $#{clm.paid} as an interest payment.\n"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
puts "----------------------------------------------------------------------------------------------------------"
|
98
|
+
puts "------------------------------Check added to #{DRIVE}/EDI-citywide-import.csv-----------------------------"
|
99
|
+
puts "-------------Please note that there are #{denied_services} service days with possible denials-------------"
|
100
|
+
puts "----------------------------------------------------------------------------------------------------------"
|
101
|
+
end
|
102
|
+
|
103
|
+
def not_fully_paid?(clm)
|
104
|
+
Claim.where(invoice_id: clm.invoice_id).sum(:paid).round(2) < clm.paid
|
65
105
|
end
|
66
106
|
|
67
107
|
def denied_services
|
68
|
-
Service.where(
|
108
|
+
Service.where(payment_id: payment.id).exclude(denial_reason: nil).count
|
69
109
|
end
|
70
110
|
end
|
71
111
|
|
72
|
-
class ManualPayment
|
73
|
-
|
74
|
-
|
75
|
-
def initialize
|
76
|
-
@check, @post_date, @prov = self.check_date_abbre
|
77
|
-
@manual_invs = self.invoice_numbers
|
78
|
-
end
|
112
|
+
class ManualPayment
|
113
|
+
include Sunnyside
|
114
|
+
attr_reader :denied_invoices, :paid_invoices, :post_date, :provider, :check, :payment_id
|
79
115
|
|
80
|
-
def
|
81
|
-
|
116
|
+
def initialize(invoices, post_date, prov, check)
|
117
|
+
@denied_invoices = invoices.select { |inv| inv.include?('-d') }.map { |inv| Invoice[inv.gsub(/-d/, '')] }
|
118
|
+
@paid_invoices = invoices.reject { |inv| inv.include?('-d') }.map { |inv| Invoice[inv] }
|
119
|
+
@post_date = post_date
|
120
|
+
@provider = prov
|
121
|
+
@check = check
|
122
|
+
@payment_id = Payment.insert(check_number: check, post_date: post_date, provider_id: prov.id)
|
82
123
|
end
|
83
124
|
|
84
|
-
def
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
Payment.insert(check_number: check, post_date: post_date, provider_id: provider.id)
|
125
|
+
def seed_claims_and_services
|
126
|
+
(denied_invoices + paid_invoices).each do |invoice|
|
127
|
+
claim_id = create_claim(invoice)
|
128
|
+
create_services(invoice, claim_id)
|
89
129
|
end
|
130
|
+
edit_services if denied_invoices.length > 0
|
90
131
|
end
|
91
132
|
|
92
|
-
def
|
93
|
-
|
133
|
+
def create_csv
|
134
|
+
claims.each { |clm| self.receivable_csv(clm, Payment[payment_id], post_date) if clm.paid > 0.0 }
|
94
135
|
end
|
95
136
|
|
96
|
-
def
|
97
|
-
|
98
|
-
end
|
99
|
-
|
100
|
-
def collate
|
101
|
-
manual_invs.each { |inv|
|
102
|
-
invoice = Invoice[inv.gsub(/-d/, '')]
|
103
|
-
claim_id = create_claim(invoice)
|
104
|
-
create_services(invoice, claim_id)
|
105
|
-
edit_services(claim_id) if denial_present?(inv)
|
106
|
-
self.receivable_csv(invoice, payment_id, check, post_date)
|
107
|
-
}
|
108
|
-
end
|
109
|
-
|
110
|
-
def invoice_data(inv)
|
111
|
-
invoice = inv.gsub(/-d/, '').to_i
|
112
|
-
yield Invoice[invoice]
|
137
|
+
def claims
|
138
|
+
(denied_invoices + paid_invoices).map { |inv| Claim.where(invoice_id: inv.invoice_number, payment_id: payment_id).first }
|
113
139
|
end
|
114
140
|
|
115
141
|
def create_claim(invoice)
|
116
142
|
Claim.insert(
|
117
|
-
:invoice_id => invoice.
|
143
|
+
:invoice_id => invoice.invoice_number,
|
118
144
|
:client_id => invoice.client_id,
|
119
145
|
:billed => invoice.amount,
|
120
|
-
:paid =>
|
146
|
+
:paid => invoice.amount,
|
121
147
|
:payment_id => payment_id,
|
122
148
|
:provider_id => invoice.provider_id
|
123
149
|
)
|
@@ -143,51 +169,53 @@ module Sunnyside
|
|
143
169
|
Visit.where(invoice_id: invoice.invoice_number).all
|
144
170
|
end
|
145
171
|
|
146
|
-
def
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
service = EditServices.new(inv, payment_id)
|
152
|
-
loop do
|
153
|
-
service.show_all
|
154
|
-
service.adjust
|
155
|
-
end
|
156
|
-
end
|
172
|
+
def edit_services
|
173
|
+
denied_invoices.each { |inv|
|
174
|
+
services = Service.where(invoice_id: inv.invoice_number, payment_id: payment_id)
|
175
|
+
edit_service = EditService.new(services)
|
176
|
+
edit_service.show_all
|
157
177
|
|
158
|
-
|
159
|
-
|
178
|
+
edit_service.adjust
|
179
|
+
|
180
|
+
adjust_claim(inv)
|
181
|
+
}
|
160
182
|
end
|
161
183
|
|
162
184
|
def visits(invoice)
|
163
185
|
Visit.where(invoice_id: invoice.invoice_number).all
|
164
186
|
end
|
165
187
|
|
166
|
-
|
167
|
-
|
188
|
+
def adjust_claim(inv)
|
189
|
+
service_sum = Service.where(payment_id: payment_id, invoice_id: inv.invoice_number).sum(:paid).round(2)
|
190
|
+
Claim.where(invoice_id: inv.invoice_number, payment_id: payment_id).update(:paid => service_sum)
|
191
|
+
end
|
192
|
+
end
|
168
193
|
|
169
|
-
|
170
|
-
|
171
|
-
@services = Service.where(claim_id: claim_id).all
|
172
|
-
end
|
194
|
+
class EditService
|
195
|
+
attr_reader :services
|
173
196
|
|
174
|
-
|
175
|
-
|
176
|
-
|
197
|
+
def initialize(services)
|
198
|
+
@services = services.all
|
199
|
+
end
|
200
|
+
|
201
|
+
def show_all
|
202
|
+
services.each { |svc| puts "ID: #{svc.id} #{svc.dos} #{svc.service_code} #{svc.paid}" }
|
203
|
+
end
|
177
204
|
|
178
|
-
|
179
|
-
|
180
|
-
|
205
|
+
def adjust
|
206
|
+
print "Type in the Service(s) ID # to change the amount: "
|
207
|
+
ids = gets.chomp.split
|
208
|
+
ids.each do |id|
|
181
209
|
print "You selected #{id} - Type in the adjusted amount: "
|
182
210
|
amt = gets.chomp
|
183
211
|
print "And now type in the denial reason: "
|
184
212
|
reason = gets.chomp
|
185
213
|
adjust_service(id, amt, reason)
|
186
214
|
end
|
215
|
+
end
|
187
216
|
|
188
|
-
|
189
|
-
|
190
|
-
end
|
217
|
+
def adjust_service(id, amt, reason)
|
218
|
+
Service[id].update(paid: amt, denial_reason: reason)
|
191
219
|
end
|
192
220
|
end
|
193
221
|
end
|
data/lib/sunnyside/ftp.rb
CHANGED
@@ -2,32 +2,47 @@ require "net/ftp"
|
|
2
2
|
require 'rubygems'
|
3
3
|
|
4
4
|
module Sunnyside
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
5
|
+
def self.access_ftp
|
6
|
+
puts "1.) GUILDNET"
|
7
|
+
puts "2.) ELDERSERVE"
|
8
|
+
puts "3.) CPHL"
|
9
|
+
print "Select option: "
|
10
|
+
case gets.chomp
|
11
|
+
when '1'
|
12
|
+
print 'Username for Guildnet? '
|
13
|
+
username = gets.chomp
|
14
|
+
print 'Password for Guildnet? '
|
15
|
+
pass = gets.chomp
|
16
|
+
access = SunnyFTP.new(username, pass, 'GUILDNET')
|
17
|
+
when '2'
|
18
|
+
print 'Username for ELDERSERVE? '
|
19
|
+
username = gets.chomp
|
20
|
+
print 'Password for ELDERSERVE? '
|
21
|
+
pass = gets.chomp
|
22
|
+
access = SunnyFTP.new(username, pass, 'ELDERSERVE')
|
23
|
+
when '3'
|
24
|
+
print 'Username for CPHL? '
|
25
|
+
username = gets.chomp
|
26
|
+
print 'Password for CPHL? '
|
27
|
+
pass = gets.chomp
|
28
|
+
access = SunnyFTP.new(username, pass, 'CPHL')
|
29
|
+
else
|
30
|
+
exit
|
31
|
+
end
|
32
|
+
access.log_on
|
33
|
+
puts "Logged into #{access.name}..."
|
34
|
+
access.download_files
|
35
|
+
access.upload_files
|
21
36
|
end
|
22
37
|
|
23
38
|
class SunnyFTP
|
24
39
|
attr_reader :ftp, :username, :password, :name, :directory
|
25
40
|
|
26
|
-
def initialize(
|
41
|
+
def initialize(username, password, name)
|
27
42
|
@ftp = Net::FTP.new('depot.per-se.com')
|
28
|
-
@username =
|
29
|
-
@password =
|
30
|
-
@name =
|
43
|
+
@username = username
|
44
|
+
@password = password
|
45
|
+
@name = name
|
31
46
|
end
|
32
47
|
|
33
48
|
def log_on
|
@@ -44,7 +59,7 @@ module Sunnyside
|
|
44
59
|
|
45
60
|
def download_folder
|
46
61
|
ftp.chdir('../outgoing')
|
47
|
-
if
|
62
|
+
if ftp.nlst.size == 0
|
48
63
|
puts "No files found. Exiting..."
|
49
64
|
ftp.close
|
50
65
|
return []
|
@@ -54,7 +69,7 @@ module Sunnyside
|
|
54
69
|
end
|
55
70
|
|
56
71
|
def up_files
|
57
|
-
Dir["
|
72
|
+
Dir["#{DRIVE}/sunnyside-files/ftp/837/#{name}/*.txt"]
|
58
73
|
end
|
59
74
|
|
60
75
|
def upload_files
|
@@ -64,14 +79,14 @@ module Sunnyside
|
|
64
79
|
ftp.putbinaryfile(file)
|
65
80
|
puts "Upload complete."
|
66
81
|
puts "deleting #{file} in local folder."
|
67
|
-
FileUtils.mv(file, "
|
82
|
+
FileUtils.mv(file, "#{DRIVE}/sunnyside-files/ftp/837/#{name}/#{File.basename(file)}")
|
68
83
|
end
|
69
84
|
}
|
70
85
|
ftp.close
|
71
86
|
end
|
72
87
|
|
73
88
|
def provider_folder
|
74
|
-
Dir["
|
89
|
+
Dir["#{DRIVE}/sunnyside-files/ftp/835/#{name}"].map { |file| File.basename(file) }
|
75
90
|
end
|
76
91
|
|
77
92
|
def new_file?(file)
|
@@ -82,12 +97,7 @@ module Sunnyside
|
|
82
97
|
download_folder.each do |file|
|
83
98
|
if !provider_folder.include?(file)
|
84
99
|
puts "Downloading #{file}..."
|
85
|
-
|
86
|
-
when file.include?('TA1') then ftp.getbinaryfile(file, "edi/incoming/#{name}/TA1/#{file}")
|
87
|
-
when file.include?('997') then ftp.getbinaryfile(file, "edi/incoming/#{name}/997/#{file}")
|
88
|
-
else
|
89
|
-
ftp.getbinaryfile(file, "edi/incoming/#{name}/#{file}")
|
90
|
-
end
|
100
|
+
ftp.getbinaryfile(file, "#{DRIVE}/sunnyside-files/ftp/835/#{name}/#{file}") if File.basename(file).include?('835')
|
91
101
|
puts "#{file} placed."
|
92
102
|
end
|
93
103
|
end
|
@@ -4,11 +4,13 @@ module Sunnyside
|
|
4
4
|
# report page by page, it would be best to compress the text from every page into a single string and then parse from there.
|
5
5
|
|
6
6
|
def self.parse_pdf
|
7
|
-
Dir["#{
|
7
|
+
files = Dir["#{DRIVE}/sunnyside-files/837/*.PDF"].select { |file| Filelib.where(filename: file).count == 0 }
|
8
|
+
files.each do |file|
|
8
9
|
puts "processing #{file}..."
|
9
10
|
data = PDF::Reader.new(file).pages.map { |page| page.raw_content.gsub(/^\(\s|\)'$/, '') }.join
|
10
|
-
data.split(
|
11
|
+
data.split(/(?=REG\s+LOC)/).each { |entry| ParseInvoice.new(entry).process }
|
11
12
|
Filelib.insert(filename: file, purpose: '837')
|
13
|
+
FileUtils.mv(file, "#{DRIVE}/sunnyside-files/837/archive/#{File.basename(file)}")
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
@@ -16,8 +18,12 @@ module Sunnyside
|
|
16
18
|
attr_reader :client_line, :visits
|
17
19
|
|
18
20
|
def initialize(entry)
|
19
|
-
@client_line = entry.split(/\n/).select { |line| line =~ /\s+001\s+/ }
|
20
|
-
@visits = entry.split(/\n/).select { |line| line =~ /^\d{6}/
|
21
|
+
@client_line = entry.split(/\n/).select { |line| line =~ /\s+001\s+/ }.join
|
22
|
+
@visits = entry.split(/\n/).select { |line| line =~ /^\d{6}/ }
|
23
|
+
end
|
24
|
+
|
25
|
+
def client_data
|
26
|
+
client_line.slice(9..28) + client_line.slice(54..120)
|
21
27
|
end
|
22
28
|
|
23
29
|
def invoice_lines
|
@@ -34,10 +40,7 @@ module Sunnyside
|
|
34
40
|
}
|
35
41
|
end
|
36
42
|
|
37
|
-
|
38
|
-
def client_data
|
39
|
-
client_line.map { |line| ( line.slice(9..28) + line.slice(66..120) ).split }[0]
|
40
|
-
end
|
43
|
+
# removes the client name from the line
|
41
44
|
|
42
45
|
def process
|
43
46
|
invoice_lines.each { |inv| inv.to_db }
|
@@ -57,12 +60,12 @@ module Sunnyside
|
|
57
60
|
@modifier = invoice_line[:modifier]
|
58
61
|
@dos = invoice_line[:dos]
|
59
62
|
@units = invoice_line[:units]
|
60
|
-
@amount = invoice_line[:amount]
|
63
|
+
@amount = invoice_line[:amount].gsub(/,/, '')
|
61
64
|
end
|
62
65
|
|
63
66
|
def to_db
|
64
67
|
Visit.insert(
|
65
|
-
:client_id =>
|
68
|
+
:client_id => client_id,
|
66
69
|
:modifier => modifier,
|
67
70
|
:invoice_id => invoice,
|
68
71
|
:amount => amount,
|
@@ -70,39 +73,30 @@ module Sunnyside
|
|
70
73
|
:dos => Date.strptime(dos, '%m/%d/%y'),
|
71
74
|
:units => units
|
72
75
|
)
|
73
|
-
|
76
|
+
update_client_demographics
|
74
77
|
end
|
75
78
|
|
76
|
-
def
|
77
|
-
Invoice[invoice].
|
79
|
+
def client_id
|
80
|
+
Invoice[invoice].client_id
|
78
81
|
end
|
79
82
|
|
80
|
-
def
|
81
|
-
client.authorization
|
83
|
+
def update_client_demographics
|
84
|
+
Invoice[invoice].update(:auth => client.authorization, :recipient_id => client.recipient_id, service_number: client.service_id)
|
85
|
+
Client[client_id].update(:recipient_id => client.recipient_id)
|
82
86
|
end
|
83
87
|
end
|
84
88
|
|
85
89
|
class ClientData < ParseInvoice
|
86
|
-
attr_reader :client_id, :service_id, :recipient_id, :authorization
|
90
|
+
attr_reader :client_id, :service_id, :recipient_id, :authorization, :dob
|
87
91
|
|
88
92
|
def initialize(client)
|
89
|
-
@client_id, @service_id, @recipient_id, @authorization = client.map { |line| line.strip }
|
90
|
-
end
|
91
|
-
|
92
|
-
def client_number
|
93
|
-
if client_missing?
|
94
|
-
puts 'how the hell is it happening? ' + client_id
|
95
|
-
else
|
96
|
-
client_id
|
97
|
-
end
|
93
|
+
@client_id, @service_id, @dob, @recipient_id, @authorization = client.split.map { |line| line.strip }
|
98
94
|
end
|
99
95
|
|
100
|
-
|
101
|
-
authorization
|
102
|
-
end
|
96
|
+
# Not parsing correctly.
|
103
97
|
|
104
|
-
def
|
105
|
-
|
98
|
+
def date_of_birth
|
99
|
+
Date.strptime(dob, '%m/%d/%Y')
|
106
100
|
end
|
107
101
|
end
|
108
102
|
end
|