brisk-bills 0.6.0 → 0.7.0
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/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
|