brisk-bills 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6 -1
- data/TODO.txt +60 -38
- data/app/controllers/admin/employees_controller.rb +1 -1
- data/app/controllers/admin/invoices_controller.rb +38 -2
- data/app/controllers/admin/payments_controller.rb +13 -6
- data/app/helpers/admin/activity_tax_field_helper.rb +1 -1
- data/app/helpers/admin/activity_type_field_helper.rb +2 -2
- data/app/helpers/admin/payments_helper.rb +8 -2
- data/app/helpers/application_helper.rb +9 -2
- data/app/model_views/invoices_with_total.rb +5 -0
- data/app/models/activity.rb +7 -3
- data/app/models/activity/labor.rb +1 -1
- data/app/models/activity/labor/slimtimer.rb +2 -0
- data/app/models/client.rb +93 -3
- data/app/models/client_representative.rb +9 -1
- data/app/models/employee.rb +21 -1
- data/app/models/employee/slimtimer.rb +11 -0
- data/app/models/invoice.rb +93 -129
- data/app/models/invoice_payment.rb +54 -0
- data/app/models/payment.rb +25 -48
- data/config/boot.rb +1 -1
- data/db/migrate/029_invoices_with_totals_view_adjustment.rb +29 -0
- data/db/schema.rb +1 -1
- data/lib/brisk-bills.rb +1 -1
- data/lib/tasks/create_last_months_invoices.rake +8 -3
- data/public/javascripts/prototype.js +1573 -1019
- data/public/javascripts/prototype.js-1.6.0.3 +4320 -0
- data/test/test_unit_factory_helper.rb +16 -9
- data/test/unit/client_test.rb +298 -2
- data/test/unit/invoice_payment_test.rb +313 -3
- data/test/unit/invoice_test.rb +49 -36
- data/test/unit/payment_test.rb +35 -31
- data/vendor/plugins/active_scaffold_full_refresh/lib/active_scaffold_full_refresh.rb +4 -2
- metadata +69 -33
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
module Factory
|
3
2
|
def self.create_labor(attributes = {}, activity_attributes = {})
|
4
3
|
employee = Employee.find(
|
@@ -111,9 +110,9 @@ module Factory
|
|
111
110
|
end
|
112
111
|
|
113
112
|
|
114
|
-
def self.generate_invoice(total, attributes = {})
|
115
|
-
attributes[:client] ||= Factory.create_client
|
113
|
+
def self.generate_invoice(client, total, attributes = {})
|
116
114
|
attributes[:issued_on] ||= Time.now
|
115
|
+
attributes[:is_published] = true if !attributes.has_key?(:is_published) or attributes[:is_published].nil?
|
117
116
|
|
118
117
|
activity_increments = (total.floor).to_f/10
|
119
118
|
1.upto(10) do |i|
|
@@ -127,7 +126,7 @@ module Factory
|
|
127
126
|
a = Activity::Adjustment.new :label => 'test invoice'
|
128
127
|
a.activity.cost = activity_cost.to_money
|
129
128
|
a.activity.tax = activity_tax
|
130
|
-
a.activity.client =
|
129
|
+
a.activity.client = client
|
131
130
|
a.activity.occurred_on = (attributes[:issued_on] - 1.months)
|
132
131
|
a.activity.is_published = true
|
133
132
|
a.save!
|
@@ -137,16 +136,24 @@ module Factory
|
|
137
136
|
|
138
137
|
puts "\nWARNING: No activity types found in db... sure you're using the right fixtures?\n" unless activity_types.length >0
|
139
138
|
|
140
|
-
Invoice.create!(
|
139
|
+
Invoice.create!(
|
140
|
+
{
|
141
|
+
:activity_types => activity_types,
|
142
|
+
:client => client,
|
143
|
+
:payment_assignments => (attributes[:is_published]) ? client.recommend_payment_assignments_for(total) : [],
|
144
|
+
:activities => Invoice.recommended_activities_for(client, attributes[:issued_on], activity_types)
|
145
|
+
}.merge(attributes)
|
146
|
+
)
|
147
|
+
|
141
148
|
end
|
142
149
|
|
143
|
-
def self.generate_payment(amount, attributes = {})
|
144
|
-
attributes[:client] ||= Factory.create_client
|
145
|
-
|
150
|
+
def self.generate_payment(client, amount, attributes = {})
|
146
151
|
Payment.create!(
|
147
152
|
{
|
153
|
+
:client => client,
|
148
154
|
:amount => amount,
|
149
|
-
:payment_method_id => 1
|
155
|
+
:payment_method_id => 1,
|
156
|
+
:invoice_assignments => client.recommend_invoice_assignments_for(amount),
|
150
157
|
}.merge(attributes)
|
151
158
|
)
|
152
159
|
end
|
data/test/unit/client_test.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
require File.dirname(__FILE__) + '/../test_unit_factory_helper.rb'
|
2
3
|
|
3
4
|
class ClientTest < ActiveSupport::TestCase
|
4
5
|
fixtures :clients
|
5
|
-
|
6
|
+
fixtures :activity_types
|
7
|
+
|
6
8
|
def test_is_active
|
7
9
|
acme = Client.create! :company_name => 'ACME Inc.'
|
8
10
|
|
@@ -21,4 +23,298 @@ class ClientTest < ActiveSupport::TestCase
|
|
21
23
|
|
22
24
|
assert_equal base_clients, Client.find_active(:all, :conditions => ['id > 0']).collect{|e| e.company_name}
|
23
25
|
end
|
24
|
-
|
26
|
+
|
27
|
+
def test_basic_unpaid_invoices
|
28
|
+
client = Factory.create_client
|
29
|
+
|
30
|
+
payments = []
|
31
|
+
|
32
|
+
paid_invoices = []
|
33
|
+
unpaid_invoices = []
|
34
|
+
unpaid_invoices << Factory.generate_invoice( client, 100.00, :issued_on => (DateTime.now << 4), :is_published => true )
|
35
|
+
paid_invoices << Factory.generate_invoice( client, 202.00, :issued_on => (DateTime.now << 3), :is_published => true )
|
36
|
+
unpaid_invoices << Factory.generate_invoice( client, 300.00, :issued_on => (DateTime.now << 2), :is_published => true )
|
37
|
+
unpaid_invoices << Factory.generate_invoice( client, 400.00, :issued_on => (DateTime.now << 1), :is_published => true )
|
38
|
+
|
39
|
+
# This is a basic test in an obvious and typical scenario. Note that we should be matching payments up when they equal invoices..
|
40
|
+
payments << Factory.generate_payment( client, 202.00 )
|
41
|
+
|
42
|
+
client_unpaid_invoices = client.unpaid_invoices
|
43
|
+
|
44
|
+
assert_equal client_unpaid_invoices.length, unpaid_invoices.length
|
45
|
+
client_unpaid_invoices.each{ |inv| assert unpaid_invoices.collect{|un_inv| un_inv.id}.include?(inv.id) }
|
46
|
+
|
47
|
+
# Now we test a half payment, which shouldn't make a difference in what's marked as fully-paid:
|
48
|
+
payments << Factory.generate_payment( client, 99.00 )
|
49
|
+
|
50
|
+
client_unpaid_invoices = client.unpaid_invoices
|
51
|
+
|
52
|
+
assert_equal client_unpaid_invoices.length, unpaid_invoices.length
|
53
|
+
client_unpaid_invoices.each{ |inv| assert unpaid_invoices.collect{|un_inv| un_inv.id}.include?(inv.id) }
|
54
|
+
|
55
|
+
# Delete all the invoices we just created:
|
56
|
+
(paid_invoices+unpaid_invoices+payments).reject!{|o| o.delete }
|
57
|
+
paid_invoices, unpaid_invoices, payments = [], [], []
|
58
|
+
|
59
|
+
# Now try this for the case of a payment created before the invoices...
|
60
|
+
payments << Factory.generate_payment(client, 23.00)
|
61
|
+
|
62
|
+
paid_invoices << Factory.generate_invoice( client, 8.00, :issued_on => (DateTime.now << 4) )
|
63
|
+
paid_invoices << Factory.generate_invoice( client, 14.00, :issued_on => (DateTime.now << 4) )
|
64
|
+
unpaid_invoices << Factory.generate_invoice( client, 30.00, :issued_on => (DateTime.now << 1) )
|
65
|
+
unpaid_invoices << Factory.generate_invoice( client, 2.00, :issued_on => (DateTime.now << 1) )
|
66
|
+
|
67
|
+
client_unpaid_invoices = client.unpaid_invoices
|
68
|
+
|
69
|
+
assert_equal client_unpaid_invoices.uniq.length, client_unpaid_invoices.length
|
70
|
+
client_unpaid_invoices.each{ |inv| assert unpaid_invoices.collect{|un_inv| un_inv.id}.include?(inv.id) }
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_basic_unassigned_payments
|
74
|
+
client = Factory.create_client
|
75
|
+
|
76
|
+
invoices = []
|
77
|
+
|
78
|
+
unassigned_payments = []
|
79
|
+
assigned_payments = []
|
80
|
+
unassigned_payments << Factory.generate_payment( client, 230.00 )
|
81
|
+
unassigned_payments << Factory.generate_payment( client, 132.00 )
|
82
|
+
assigned_payments << Factory.generate_payment( client, 23.00 )
|
83
|
+
unassigned_payments << Factory.generate_payment( client, 993.00 )
|
84
|
+
|
85
|
+
# This is a basic test in an obvious and typical scenario. Note that we should be matching payments up when they equal invoices..
|
86
|
+
invoices << Factory.generate_invoice( client, 23.00, :issued_on => (DateTime.now << 1) )
|
87
|
+
|
88
|
+
client_unassigned_payments = client.unassigned_payments
|
89
|
+
|
90
|
+
assert_equal unassigned_payments.length, client_unassigned_payments.length
|
91
|
+
client_unassigned_payments.each{ |pymt| assert unassigned_payments.collect{|un_pymnt| un_pymnt.id}.include?(pymt.id) }
|
92
|
+
|
93
|
+
# Now we test a partial invoice, which shouldn't make a difference in what's marked as unassigned:
|
94
|
+
invoices << Factory.generate_invoice( client, 100.00 )
|
95
|
+
|
96
|
+
client_unassigned_payments = client.unassigned_payments
|
97
|
+
|
98
|
+
assert_equal unassigned_payments.length, client_unassigned_payments.length
|
99
|
+
client_unassigned_payments.each{ |pymt| assert unassigned_payments.collect{|un_pymnt| un_pymnt.id}.include?(pymt.id) }
|
100
|
+
|
101
|
+
# Delete all the payments we just created:
|
102
|
+
(unassigned_payments+assigned_payments+invoices).reject!{|o| o.delete }
|
103
|
+
assigned_payments, unassigned_payments, invoices = [], [], []
|
104
|
+
|
105
|
+
# Now try this for the case of an invoice created before the payments...
|
106
|
+
invoices << Factory.generate_invoice(client, 23.00, :issued_on => (DateTime.now << 1) )
|
107
|
+
|
108
|
+
assigned_payments << Factory.generate_payment( client, 8.00 )
|
109
|
+
assigned_payments << Factory.generate_payment( client, 14.00 )
|
110
|
+
unassigned_payments << Factory.generate_payment( client, 30.00 )
|
111
|
+
unassigned_payments << Factory.generate_payment( client, 2.00 )
|
112
|
+
|
113
|
+
client_unassigned_payments = client.unassigned_payments
|
114
|
+
|
115
|
+
assert_equal unassigned_payments.length, client_unassigned_payments.length
|
116
|
+
client_unassigned_payments.each{ |pymt| assert unassigned_payments.collect{|un_pymnt| un_pymnt.id}.include?(pymt.id) }
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_recommend_payment_assignments_for
|
120
|
+
# Make sure the assignments make sense (equal value outstanding returned before any-outstanding)
|
121
|
+
client = Factory.create_client
|
122
|
+
|
123
|
+
payments = [
|
124
|
+
Factory.generate_payment( client, 23.45, :paid_on => (DateTime.now << 5) ),
|
125
|
+
Factory.generate_payment( client, 202.02, :paid_on => (DateTime.now << 4) ),
|
126
|
+
Factory.generate_payment( client, 2.40, :paid_on => (DateTime.now << 3) ),
|
127
|
+
Factory.generate_payment( client, 94.00, :paid_on => (DateTime.now << 2) ),
|
128
|
+
Factory.generate_payment( client, 2.40, :paid_on => (DateTime.now << 1) )
|
129
|
+
]
|
130
|
+
|
131
|
+
# First test that exact-matches are properly assigned:
|
132
|
+
reccomended = client.recommend_payment_assignments_for(2.40)
|
133
|
+
assert_equal 1, reccomended.length
|
134
|
+
assert_equal payments[2].id, reccomended.first.payment_id
|
135
|
+
|
136
|
+
reccomended = client.recommend_payment_assignments_for(94)
|
137
|
+
assert_equal 1, reccomended.length
|
138
|
+
assert_equal payments[3].id, reccomended.first.payment_id
|
139
|
+
|
140
|
+
reccomended = client.recommend_payment_assignments_for(23.45)
|
141
|
+
assert_equal 1, reccomended.length
|
142
|
+
assert_equal payments[0].id, reccomended.first.payment_id
|
143
|
+
|
144
|
+
# Now test partials:
|
145
|
+
reccomended = client.recommend_payment_assignments_for(5.40)
|
146
|
+
assert_equal 1, reccomended.length
|
147
|
+
assert_equal payments[0].id, reccomended.first.payment_id
|
148
|
+
|
149
|
+
reccomended = client.recommend_payment_assignments_for(225.47)
|
150
|
+
assert_equal 2, reccomended.length
|
151
|
+
assert_equal payments[0].id, reccomended[0].payment_id
|
152
|
+
assert_equal payments[1].id, reccomended[1].payment_id
|
153
|
+
|
154
|
+
reccomended = client.recommend_payment_assignments_for(229)
|
155
|
+
assert_equal 4, reccomended.length
|
156
|
+
assert_equal payments[0].id, reccomended[0].payment_id
|
157
|
+
assert_equal payments[1].id, reccomended[1].payment_id
|
158
|
+
assert_equal payments[2].id, reccomended[2].payment_id
|
159
|
+
assert_equal payments[3].id, reccomended[3].payment_id
|
160
|
+
|
161
|
+
reccomended = client.recommend_payment_assignments_for(25)
|
162
|
+
assert_equal 2, reccomended.length
|
163
|
+
assert_equal payments[0].id, reccomended[0].payment_id
|
164
|
+
assert_equal payments[1].id, reccomended[1].payment_id
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_recommend_invoice_assignments_for
|
169
|
+
# Make sure the assignments make sense (equal value outstanding returned before any-outstanding)
|
170
|
+
client = Factory.create_client
|
171
|
+
|
172
|
+
invoices = [
|
173
|
+
Factory.generate_invoice( client, 23.45, :issued_on => (DateTime.now << 5) ),
|
174
|
+
Factory.generate_invoice( client, 202.02, :issued_on => (DateTime.now << 4) ),
|
175
|
+
Factory.generate_invoice( client, 2.40, :issued_on => (DateTime.now << 3) ),
|
176
|
+
Factory.generate_invoice( client, 94.00, :issued_on => (DateTime.now << 2) ),
|
177
|
+
Factory.generate_invoice( client, 2.40, :issued_on => (DateTime.now << 1) )
|
178
|
+
]
|
179
|
+
|
180
|
+
# First test that exact-matches are properly assigned:
|
181
|
+
reccomended = client.recommend_invoice_assignments_for(2.40)
|
182
|
+
assert_equal 1, reccomended.length
|
183
|
+
assert_equal invoices[2].id, reccomended.first.invoice_id
|
184
|
+
|
185
|
+
reccomended = client.recommend_invoice_assignments_for(94)
|
186
|
+
assert_equal 1, reccomended.length
|
187
|
+
assert_equal invoices[3].id, reccomended.first.invoice_id
|
188
|
+
|
189
|
+
reccomended = client.recommend_invoice_assignments_for(23.45)
|
190
|
+
assert_equal 1, reccomended.length
|
191
|
+
assert_equal invoices[0].id, reccomended.first.invoice_id
|
192
|
+
|
193
|
+
# Now test partials:
|
194
|
+
reccomended = client.recommend_invoice_assignments_for(5.40)
|
195
|
+
assert_equal 1, reccomended.length
|
196
|
+
assert_equal invoices[0].id, reccomended.first.invoice_id
|
197
|
+
|
198
|
+
reccomended = client.recommend_invoice_assignments_for(225.47)
|
199
|
+
assert_equal 2, reccomended.length
|
200
|
+
assert_equal invoices[0].id, reccomended[0].invoice_id
|
201
|
+
assert_equal invoices[1].id, reccomended[1].invoice_id
|
202
|
+
|
203
|
+
reccomended = client.recommend_invoice_assignments_for(229)
|
204
|
+
assert_equal 4, reccomended.length
|
205
|
+
assert_equal invoices[0].id, reccomended[0].invoice_id
|
206
|
+
assert_equal invoices[1].id, reccomended[1].invoice_id
|
207
|
+
assert_equal invoices[2].id, reccomended[2].invoice_id
|
208
|
+
assert_equal invoices[3].id, reccomended[3].invoice_id
|
209
|
+
|
210
|
+
reccomended = client.recommend_invoice_assignments_for(25)
|
211
|
+
assert_equal 2, reccomended.length
|
212
|
+
assert_equal invoices[0].id, reccomended[0].invoice_id
|
213
|
+
assert_equal invoices[1].id, reccomended[1].invoice_id
|
214
|
+
end
|
215
|
+
|
216
|
+
def test_negative_recommend_invoice_payment_assignments_for
|
217
|
+
# Make sure the assignments make sense (equal value outstanding returned before any-outstanding)
|
218
|
+
client = Factory.create_client
|
219
|
+
|
220
|
+
invoices = [
|
221
|
+
Factory.generate_invoice( client, 20.00, :issued_on => (DateTime.now << 5) ),
|
222
|
+
Factory.generate_invoice( client, -40.0, :issued_on => (DateTime.now << 4) ),
|
223
|
+
Factory.generate_invoice( client, 8.00, :is_published => true, :issued_on => (DateTime.now << 3) ),
|
224
|
+
Factory.generate_invoice( client, -2.00, :issued_on => (DateTime.now << 2) ),
|
225
|
+
Factory.generate_invoice( client, 16.00, :issued_on => (DateTime.now << 1) )
|
226
|
+
]
|
227
|
+
|
228
|
+
# First test that exact-matches are properly assigned:
|
229
|
+
reccomended = client.recommend_invoice_assignments_for(20.00)
|
230
|
+
assert_equal 1, reccomended.length
|
231
|
+
assert_equal invoices[0].id, reccomended.first.invoice_id
|
232
|
+
|
233
|
+
reccomended = client.recommend_invoice_assignments_for(8.00)
|
234
|
+
assert_equal 1, reccomended.length
|
235
|
+
assert_equal invoices[2].id, reccomended.first.invoice_id
|
236
|
+
|
237
|
+
reccomended = client.recommend_invoice_assignments_for(16.00)
|
238
|
+
assert_equal 1, reccomended.length
|
239
|
+
assert_equal invoices[4].id, reccomended.first.invoice_id
|
240
|
+
|
241
|
+
reccomended = client.recommend_invoice_assignments_for(16.00)
|
242
|
+
assert_equal 1, reccomended.length
|
243
|
+
assert_equal invoices[4].id, reccomended.first.invoice_id
|
244
|
+
|
245
|
+
# And check what happens if we have a negative amount?
|
246
|
+
reccomended = client.recommend_invoice_assignments_for(-40.00)
|
247
|
+
assert_equal 0, reccomended.length
|
248
|
+
|
249
|
+
# Now test partials:
|
250
|
+
reccomended = client.recommend_invoice_assignments_for(5.00)
|
251
|
+
assert_equal 1, reccomended.length
|
252
|
+
assert_equal invoices[0].id, reccomended.first.invoice_id
|
253
|
+
|
254
|
+
reccomended = client.recommend_invoice_assignments_for(25.00)
|
255
|
+
assert_equal 2, reccomended.length
|
256
|
+
assert_equal invoices[0].id, reccomended[0].invoice_id
|
257
|
+
assert_equal invoices[2].id, reccomended[1].invoice_id
|
258
|
+
|
259
|
+
reccomended = client.recommend_invoice_assignments_for(48)
|
260
|
+
assert_equal 3, reccomended.length
|
261
|
+
assert_equal invoices[0].id, reccomended[0].invoice_id
|
262
|
+
assert_equal invoices[2].id, reccomended[1].invoice_id
|
263
|
+
assert_equal invoices[4].id, reccomended[2].invoice_id
|
264
|
+
|
265
|
+
reccomended = client.recommend_invoice_assignments_for(28)
|
266
|
+
assert_equal 2, reccomended.length
|
267
|
+
assert_equal invoices[0].id, reccomended[0].invoice_id
|
268
|
+
assert_equal invoices[2].id, reccomended[1].invoice_id
|
269
|
+
end
|
270
|
+
|
271
|
+
# Now that we support multiple unpublished invoices - let's make sure that our payment recomendations aren't improperly
|
272
|
+
# assigning payments to unpublished invoices
|
273
|
+
def test_unpublished_invoice_payment_assignments
|
274
|
+
client = Factory.create_client
|
275
|
+
|
276
|
+
# First create three published invoices:
|
277
|
+
invoices = [
|
278
|
+
Factory.generate_invoice( client, 400.0, :issued_on => (DateTime.now << 5) ),
|
279
|
+
Factory.generate_invoice( client, 50.00, :issued_on => (DateTime.now << 4) ),
|
280
|
+
Factory.generate_invoice( client, 800.00, :issued_on => (DateTime.now << 3) )
|
281
|
+
]
|
282
|
+
payments = []
|
283
|
+
|
284
|
+
assert_equal 1250.00, client.balance
|
285
|
+
|
286
|
+
# Unpublish invoices 1 & 2
|
287
|
+
[invoices[0], invoices[1]].each do |inv|
|
288
|
+
inv.is_published = false
|
289
|
+
inv.save!
|
290
|
+
end
|
291
|
+
|
292
|
+
# Create a payment for the first
|
293
|
+
payments << Factory.generate_payment( client, 800.00 )
|
294
|
+
|
295
|
+
# Publish invoice 2:
|
296
|
+
invoices[1].is_published = true
|
297
|
+
invoices[1].save!
|
298
|
+
|
299
|
+
# Create payments for the third
|
300
|
+
payments << Factory.generate_payment( client, 26.00 )
|
301
|
+
payments << Factory.generate_payment( client, 24.00 )
|
302
|
+
|
303
|
+
# Set the 1st published
|
304
|
+
invoices[0].is_published = true
|
305
|
+
invoices[0].save!
|
306
|
+
|
307
|
+
# Create a payment for the second
|
308
|
+
payments << Factory.generate_payment( client, 500.00 )
|
309
|
+
|
310
|
+
# Now we test all the invoice_payment mappings to be sure they make sense ..
|
311
|
+
assert_equal true, invoices[0].is_paid?
|
312
|
+
assert_equal [payments[3].id], invoices[0].payment_assignments(true).collect(&:payment_id)
|
313
|
+
|
314
|
+
assert_equal true, invoices[1].is_paid?
|
315
|
+
assert_equal [payments[1].id, payments[2].id], invoices[1].payment_assignments(true).collect(&:payment_id)
|
316
|
+
|
317
|
+
assert_equal true, invoices[2].is_paid?
|
318
|
+
assert_equal [payments[0].id], invoices[2].payment_assignments(true).collect(&:payment_id)
|
319
|
+
end
|
320
|
+
end
|
@@ -1,8 +1,318 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
require File.dirname(__FILE__) + '/../test_unit_factory_helper'
|
3
|
+
|
2
4
|
|
3
5
|
class InvoicePaymentTest < ActiveSupport::TestCase
|
4
|
-
|
5
|
-
def
|
6
|
-
|
6
|
+
|
7
|
+
def test_invoice_payment_marking
|
8
|
+
client = Factory.create_client
|
9
|
+
|
10
|
+
invoices = [
|
11
|
+
Factory.generate_invoice( client, 10.00, :issued_on => (DateTime.now << 4), :payment_assignments => [] ),
|
12
|
+
Factory.generate_invoice( client, 15.00, :issued_on => (DateTime.now << 3), :payment_assignments => [] ),
|
13
|
+
Factory.generate_invoice( client, 5.00, :issued_on => (DateTime.now << 2), :payment_assignments => [] ),
|
14
|
+
]
|
15
|
+
|
16
|
+
assert_equal 30.00, client.balance
|
17
|
+
|
18
|
+
payments = [
|
19
|
+
Factory.generate_payment( client, 2.00, :invoice_assignments => [] ),
|
20
|
+
Factory.generate_payment( client, 3.00, :invoice_assignments => [] ),
|
21
|
+
Factory.generate_payment( client, 11.00, :invoice_assignments => [] ),
|
22
|
+
Factory.generate_payment( client, 4.00, :invoice_assignments => [] ),
|
23
|
+
Factory.generate_payment( client, 10.00, :invoice_assignments => [] )
|
24
|
+
]
|
25
|
+
|
26
|
+
assert_equal 0.00, client.balance
|
27
|
+
|
28
|
+
# Ensure that invoices aren't marked as 'paid' until the invoice_payments have been applied. Even though the balance is 0
|
29
|
+
assert_equal false, invoices[0].is_paid?
|
30
|
+
assert_equal false, invoices[1].is_paid?
|
31
|
+
assert_equal false, invoices[2].is_paid?
|
32
|
+
|
33
|
+
# Ensure that payments aren't marked as 'paid' until the invoice_payments have been applied. Even though the balance is 0
|
34
|
+
assert_equal false, payments[0].is_allocated?
|
35
|
+
assert_equal false, payments[1].is_allocated?
|
36
|
+
assert_equal false, payments[2].is_allocated?
|
37
|
+
assert_equal false, payments[3].is_allocated?
|
38
|
+
assert_equal false, payments[4].is_allocated?
|
39
|
+
|
40
|
+
# Now start marking payments/invocies, and testing the corresponding is_ methods :
|
41
|
+
InvoicePayment.quick_create! invoices[0], payments[2], 10.00
|
42
|
+
|
43
|
+
assert_equal true, invoices[0].is_paid?
|
44
|
+
assert_equal false, invoices[1].is_paid?
|
45
|
+
assert_equal false, invoices[2].is_paid?
|
46
|
+
assert_equal false, payments[0].is_allocated?
|
47
|
+
assert_equal false, payments[1].is_allocated?
|
48
|
+
assert_equal false, payments[2].is_allocated?
|
49
|
+
assert_equal false, payments[3].is_allocated?
|
50
|
+
assert_equal false, payments[4].is_allocated?
|
51
|
+
|
52
|
+
InvoicePayment.quick_create! invoices[1], payments[2], 1.00
|
53
|
+
InvoicePayment.quick_create! invoices[1], payments[3], 4.00
|
54
|
+
InvoicePayment.quick_create! invoices[1], payments[4], 10.00
|
55
|
+
|
56
|
+
assert_equal true, invoices[0].is_paid?
|
57
|
+
assert_equal true, invoices[1].is_paid?
|
58
|
+
assert_equal false, invoices[2].is_paid?
|
59
|
+
assert_equal false, payments[0].is_allocated?
|
60
|
+
assert_equal false, payments[1].is_allocated?
|
61
|
+
assert_equal true, payments[2].is_allocated?
|
62
|
+
assert_equal true, payments[3].is_allocated?
|
63
|
+
assert_equal true, payments[4].is_allocated?
|
64
|
+
|
65
|
+
InvoicePayment.quick_create! invoices[2], payments[0], 2.00
|
66
|
+
InvoicePayment.quick_create! invoices[2], payments[1], 3.00
|
67
|
+
|
68
|
+
# Everything should be allocated now - retest is_paid/allocated code
|
69
|
+
assert_equal true, invoices[0].is_paid?
|
70
|
+
assert_equal true, invoices[1].is_paid?
|
71
|
+
assert_equal true, invoices[2].is_paid?
|
72
|
+
|
73
|
+
assert_equal true, payments[0].is_allocated?
|
74
|
+
assert_equal true, payments[1].is_allocated?
|
75
|
+
assert_equal true, payments[2].is_allocated?
|
76
|
+
assert_equal true, payments[3].is_allocated?
|
77
|
+
assert_equal true, payments[4].is_allocated?
|
78
|
+
end
|
79
|
+
|
80
|
+
# How well does find_recomended_invoices work for a negative invoice with a credit/negative amount -payment? Write a test:
|
81
|
+
def test_negative_invoice_payment_marking
|
82
|
+
client = Factory.create_client
|
83
|
+
|
84
|
+
invoices = [
|
85
|
+
Factory.generate_invoice( client, 10.00, :issued_on => (DateTime.now << 4), :payment_assignments => [] ),
|
86
|
+
Factory.generate_invoice( client, -15.00, :issued_on => (DateTime.now << 3), :payment_assignments => [] ),
|
87
|
+
Factory.generate_invoice( client, -5.00, :issued_on => (DateTime.now << 2), :payment_assignments => [] ),
|
88
|
+
]
|
89
|
+
|
90
|
+
assert_equal -10.00, client.balance
|
91
|
+
|
92
|
+
# Negative invoices are always marked paid
|
93
|
+
assert_equal false, invoices[0].is_paid?
|
94
|
+
assert_equal true, invoices[1].is_paid?
|
95
|
+
assert_equal true, invoices[2].is_paid?
|
96
|
+
|
97
|
+
payments = [
|
98
|
+
Factory.generate_payment( client, 5.00, :invoice_assignments =>
|
99
|
+
[InvoicePayment.new(:invoice => invoices[0], :amount => 5.00 )]
|
100
|
+
),
|
101
|
+
Factory.generate_payment( client, 5.00, :invoice_assignments =>
|
102
|
+
[InvoicePayment.new(:invoice => invoices[0], :amount => 5.00 )]
|
103
|
+
)
|
104
|
+
]
|
105
|
+
|
106
|
+
assert_equal -20.00, client.balance
|
107
|
+
|
108
|
+
# Everything should be paid now:
|
109
|
+
assert_equal true, invoices[0].is_paid?
|
110
|
+
assert_equal true, invoices[1].is_paid?
|
111
|
+
assert_equal true, invoices[2].is_paid?
|
112
|
+
|
113
|
+
# Now what if the invoice they have an invoice for -$20, and an invoice for +$12. Their outstanding balance is -$8,
|
114
|
+
# but if they try to make a payment for $5, will we freak on them?
|
115
|
+
|
116
|
+
# Just for goo measure let's generate a new invoice:
|
117
|
+
invoices << Factory.generate_invoice( client, 12.00, :issued_on => (DateTime.now << 1), :payment_assignments => [] )
|
118
|
+
|
119
|
+
assert_equal -8.00, client.balance
|
120
|
+
|
121
|
+
assert_equal true, invoices[0].is_paid?
|
122
|
+
assert_equal true, invoices[1].is_paid?
|
123
|
+
assert_equal true, invoices[2].is_paid?
|
124
|
+
assert_equal false, invoices[3].is_paid?
|
125
|
+
|
126
|
+
payments << Factory.generate_payment( client, 12.00, :invoice_assignments =>
|
127
|
+
[InvoicePayment.new(:invoice => invoices[3], :amount => 12.00 )]
|
128
|
+
)
|
129
|
+
|
130
|
+
# and make sure we're cool:
|
131
|
+
assert_equal true, invoices[0].is_paid?
|
132
|
+
assert_equal true, invoices[1].is_paid?
|
133
|
+
assert_equal true, invoices[2].is_paid?
|
134
|
+
assert_equal true, invoices[3].is_paid?
|
135
|
+
|
136
|
+
assert_equal -20.00, client.balance
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_invoice_dependent_delete
|
140
|
+
client = Factory.create_client
|
141
|
+
|
142
|
+
invoice = Factory.generate_invoice client, 99.00, :issued_on => (DateTime.now << 1), :payment_assignments => []
|
143
|
+
Factory.generate_payment client, 40.00, :invoice_assignments => [InvoicePayment.new(:invoice => invoice, :amount => 40.00 )]
|
144
|
+
Factory.generate_payment client, 40.00, :invoice_assignments => [InvoicePayment.new(:invoice => invoice, :amount => 40.00 )]
|
145
|
+
Factory.generate_payment client, 20.00, :invoice_assignments => [InvoicePayment.new(:invoice => invoice, :amount => 19.00 )]
|
146
|
+
|
147
|
+
assert_equal 3, InvoicePayment.find(:all).length
|
148
|
+
|
149
|
+
invoice.is_published = false
|
150
|
+
assert_not_equal false, invoice.destroy # False would indicate that the invoice didnt delete successfully
|
151
|
+
|
152
|
+
# Now make sure all our InvoicePayments were also destroyed:
|
153
|
+
assert_equal 0, InvoicePayment.find(:all).length
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_invoice_payments_dependent_delete
|
157
|
+
client = Factory.create_client
|
158
|
+
|
159
|
+
payment = Factory.generate_payment client, 13.00, :invoice_assignments => []
|
160
|
+
|
161
|
+
Factory.generate_invoice client, 4.00, :issued_on => (DateTime.now << 1), :payment_assignments => [
|
162
|
+
InvoicePayment.new(:payment => payment, :amount => 4.00 )
|
163
|
+
]
|
164
|
+
Factory.generate_invoice client, 4.00, :issued_on => (DateTime.now << 1), :payment_assignments => [
|
165
|
+
InvoicePayment.new(:payment => payment, :amount => 4.00 )
|
166
|
+
]
|
167
|
+
Factory.generate_invoice client, 3.00, :issued_on => (DateTime.now << 1), :payment_assignments => [
|
168
|
+
InvoicePayment.new(:payment => payment, :amount => 3.00 )
|
169
|
+
]
|
170
|
+
|
171
|
+
assert_equal 3, InvoicePayment.find(:all).length
|
172
|
+
|
173
|
+
payment.destroy
|
174
|
+
|
175
|
+
# Now make sure all our InvoicePayments were also destroyed:
|
176
|
+
assert_equal 0, InvoicePayment.find(:all).length
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_bogus_invoice_payment_amounts
|
180
|
+
client = Factory.create_client
|
181
|
+
|
182
|
+
ip = nil
|
183
|
+
|
184
|
+
invoice = Factory.generate_invoice client, 100.00, :issued_on => (DateTime.now << 1), :payment_assignments => []
|
185
|
+
paymentA = Factory.generate_payment client, 20.00, :invoice_assignments => []
|
186
|
+
paymentB = Factory.generate_payment client, 110.00, :invoice_assignments => []
|
187
|
+
|
188
|
+
# Test: People can't specifify more allocations than the total payment's amount
|
189
|
+
ip = InvoicePayment.new :payment => paymentA, :invoice => invoice, :amount => 21.00
|
190
|
+
assert_equal false, ip.valid?
|
191
|
+
assert_equal "exceeds the payment's remainder amount", ip.errors.on('amount')
|
192
|
+
|
193
|
+
# Test: People can't specifify more allocations than the total invoice's amount
|
194
|
+
ip = InvoicePayment.create :payment => paymentB, :invoice => invoice, :amount => 101.00
|
195
|
+
assert_equal false, ip.valid?
|
196
|
+
assert_equal "exceeds the invoice's remainder balance", ip.errors.on('amount')
|
197
|
+
|
198
|
+
# Test: Trying the case of a second/multiple payments which exceed the invoice balance..
|
199
|
+
invoice = Factory.generate_invoice client, 20.00, :issued_on => (DateTime.now << 1), :payment_assignments => []
|
200
|
+
paymentA = Factory.generate_payment client, 12.00, :invoice_assignments => [
|
201
|
+
InvoicePayment.new( :invoice => invoice, :amount => 12.00)
|
202
|
+
]
|
203
|
+
paymentB = Factory.generate_payment client, 12.00, :invoice_assignments => []
|
204
|
+
|
205
|
+
ip = InvoicePayment.create :payment => paymentB, :invoice => invoice, :amount => 12.00
|
206
|
+
assert_equal false, ip.valid?
|
207
|
+
assert_equal "exceeds the invoice's remainder balance", ip.errors.on('amount')
|
208
|
+
|
209
|
+
# Now try the case of multiple invoices which exceed the payment balance..
|
210
|
+
invoiceA = Factory.generate_invoice client, 40.00, :issued_on => (DateTime.now << 1), :payment_assignments => []
|
211
|
+
invoiceB = Factory.generate_invoice client, 35.00, :issued_on => (DateTime.now << 1), :payment_assignments => []
|
212
|
+
|
213
|
+
payment = Factory.generate_payment client, 70.00, :invoice_assignments => [
|
214
|
+
InvoicePayment.new( :invoice => invoiceA, :amount => 40.00)
|
215
|
+
]
|
216
|
+
|
217
|
+
ip = InvoicePayment.create :payment => payment, :invoice => invoiceB, :amount => 35.00
|
218
|
+
assert_equal false, ip.valid?
|
219
|
+
assert_equal "exceeds the payment's remainder amount", ip.errors.on('amount')
|
220
|
+
end
|
221
|
+
|
222
|
+
def test_bogus_invoice_allocations
|
223
|
+
client = Factory.create_client
|
224
|
+
|
225
|
+
# This is a repeat of some of the above tests, but we're ensuring that we fail during the invoice model's creation
|
226
|
+
paymentA = Factory.generate_payment client, 4.00, :invoice_assignments => []
|
227
|
+
paymentB = Factory.generate_payment client, 8.00, :invoice_assignments => []
|
228
|
+
paymentC = Factory.generate_payment client, 8.00, :invoice_assignments => []
|
229
|
+
|
230
|
+
assert_raise ActiveRecord::RecordInvalid do
|
231
|
+
Factory.generate_invoice client, 16.00, :issued_on => (DateTime.now << 1), :payment_assignments => [
|
232
|
+
InvoicePayment.new( :payment => paymentA, :amount => 4.00 ),
|
233
|
+
InvoicePayment.new( :payment => paymentB, :amount => 8.00 ),
|
234
|
+
InvoicePayment.new( :payment => paymentC, :amount => 5.00 ) # <-- this one's invalid, b/c its greater than the invoice price
|
235
|
+
]
|
236
|
+
end
|
237
|
+
|
238
|
+
assert_raise ActiveRecord::RecordInvalid do
|
239
|
+
Factory.generate_invoice client, 16.00, :issued_on => (DateTime.now << 1), :payment_assignments => [
|
240
|
+
InvoicePayment.new( :payment => paymentA, :amount => 8.00 ), # <-- this one's invalid, b/c its greater than the payment total
|
241
|
+
InvoicePayment.new( :payment => paymentB, :amount => 4.00 ),
|
242
|
+
InvoicePayment.new( :payment => paymentC, :amount => 4.00 )
|
243
|
+
]
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def test_bogus_payment_allocations
|
248
|
+
client = Factory.create_client
|
249
|
+
|
250
|
+
# This is a repeat of some of the above tests, but we're ensuring that we fail during the payment model's creation
|
251
|
+
invoiceA = Factory.generate_invoice client, 3.00, :issued_on => (DateTime.now << 1), :payment_assignments => []
|
252
|
+
invoiceB = Factory.generate_invoice client, 6.00, :issued_on => (DateTime.now << 1), :payment_assignments => []
|
253
|
+
invoiceC = Factory.generate_invoice client, 6.00, :issued_on => (DateTime.now << 1), :payment_assignments => []
|
254
|
+
|
255
|
+
assert_raise ActiveRecord::RecordInvalid do
|
256
|
+
Factory.generate_payment client, 12.00, :invoice_assignments => [
|
257
|
+
InvoicePayment.new( :invoice => invoiceA, :amount => 3.00 ),
|
258
|
+
InvoicePayment.new( :invoice => invoiceB, :amount => 6.00 ),
|
259
|
+
InvoicePayment.new( :invoice => invoiceC, :amount => 4.00 ) # <-- this one's invalid, b/c its greater than the payment price
|
260
|
+
]
|
261
|
+
end
|
262
|
+
|
263
|
+
assert_raise ActiveRecord::RecordInvalid do
|
264
|
+
Factory.generate_payment client, 12.00, :invoice_assignments => [
|
265
|
+
InvoicePayment.new( :invoice => invoiceA, :amount => 6.00 ),# <-- this one's invalid, b/c its greater than the invoice total
|
266
|
+
InvoicePayment.new( :invoice => invoiceB, :amount => 3.00 ),
|
267
|
+
InvoicePayment.new( :invoice => invoiceC, :amount => 3.00 )
|
268
|
+
]
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def test_invoice_payment_amount_not_negative
|
273
|
+
client = Factory.create_client
|
274
|
+
|
275
|
+
# People can't specifify negative payment_allocations
|
276
|
+
invoice = Factory.generate_invoice client, 5.00, :issued_on => (DateTime.now << 1), :payment_assignments => []
|
277
|
+
payment = Factory.generate_payment client, 5.00, :invoice_assignments => []
|
278
|
+
|
279
|
+
ip = InvoicePayment.create :payment => payment, :invoice => invoice, :amount => -5.00
|
280
|
+
|
281
|
+
assert_equal false, ip.valid?
|
282
|
+
assert_equal "must be greater than or equal to 0", ip.errors.on('amount')
|
283
|
+
end
|
284
|
+
|
285
|
+
def test_payments_unapplyable_to_unpublished_invoices
|
286
|
+
client = Factory.create_client
|
287
|
+
|
288
|
+
invoice = nil
|
289
|
+
payment = nil
|
290
|
+
|
291
|
+
# Ensure Invoice :payment_assignments create fails with unpublished unvoice
|
292
|
+
payment = Factory.generate_payment( client, 40.00 , :invoice_assignments => [] )
|
293
|
+
|
294
|
+
assert_raise(ActiveRecord::RecordInvalid) do
|
295
|
+
invoice = Factory.generate_invoice( client, 40.00, :is_published => false, :payment_assignments => [
|
296
|
+
InvoicePayment.new( :payment => payment, :amount => 40.00 )
|
297
|
+
] )
|
298
|
+
end
|
299
|
+
|
300
|
+
# Ensure Payment :invoice_assignments create fails with unpublished unvoice
|
301
|
+
invoice = Factory.generate_invoice( client, 50.00, :is_published => false, :payment_assignments => [])
|
302
|
+
|
303
|
+
assert_raise(ActiveRecord::RecordInvalid) do
|
304
|
+
payment = Factory.generate_payment( client, 50.00 , :invoice_assignments => [
|
305
|
+
InvoicePayment.new( :invoice => invoice, :amount => 50.00 )
|
306
|
+
] )
|
307
|
+
end
|
308
|
+
|
309
|
+
# Test InvoicePayment create fails with unpublished unvoice
|
310
|
+
invoice = Factory.generate_invoice( client, 60.00, :is_published => false, :payment_assignments => [])
|
311
|
+
payment = Factory.generate_payment( client, 60.00, :invoice_assignments => [] )
|
312
|
+
|
313
|
+
ip = InvoicePayment.new :invoice => invoice, :payment => payment, :amount => 60.00
|
314
|
+
|
315
|
+
assert_raise(ActiveRecord::RecordInvalid) { ip.save! }
|
316
|
+
assert ip.errors.invalid?(:invoice)
|
7
317
|
end
|
8
318
|
end
|