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.
Files changed (34) hide show
  1. data/CHANGELOG +6 -1
  2. data/TODO.txt +60 -38
  3. data/app/controllers/admin/employees_controller.rb +1 -1
  4. data/app/controllers/admin/invoices_controller.rb +38 -2
  5. data/app/controllers/admin/payments_controller.rb +13 -6
  6. data/app/helpers/admin/activity_tax_field_helper.rb +1 -1
  7. data/app/helpers/admin/activity_type_field_helper.rb +2 -2
  8. data/app/helpers/admin/payments_helper.rb +8 -2
  9. data/app/helpers/application_helper.rb +9 -2
  10. data/app/model_views/invoices_with_total.rb +5 -0
  11. data/app/models/activity.rb +7 -3
  12. data/app/models/activity/labor.rb +1 -1
  13. data/app/models/activity/labor/slimtimer.rb +2 -0
  14. data/app/models/client.rb +93 -3
  15. data/app/models/client_representative.rb +9 -1
  16. data/app/models/employee.rb +21 -1
  17. data/app/models/employee/slimtimer.rb +11 -0
  18. data/app/models/invoice.rb +93 -129
  19. data/app/models/invoice_payment.rb +54 -0
  20. data/app/models/payment.rb +25 -48
  21. data/config/boot.rb +1 -1
  22. data/db/migrate/029_invoices_with_totals_view_adjustment.rb +29 -0
  23. data/db/schema.rb +1 -1
  24. data/lib/brisk-bills.rb +1 -1
  25. data/lib/tasks/create_last_months_invoices.rake +8 -3
  26. data/public/javascripts/prototype.js +1573 -1019
  27. data/public/javascripts/prototype.js-1.6.0.3 +4320 -0
  28. data/test/test_unit_factory_helper.rb +16 -9
  29. data/test/unit/client_test.rb +298 -2
  30. data/test/unit/invoice_payment_test.rb +313 -3
  31. data/test/unit/invoice_test.rb +49 -36
  32. data/test/unit/payment_test.rb +35 -31
  33. data/vendor/plugins/active_scaffold_full_refresh/lib/active_scaffold_full_refresh.rb +4 -2
  34. 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 = attributes[: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!( { :activity_types => activity_types }.merge(attributes) )
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
@@ -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
- end
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
- # Replace this with your real tests.
5
- def test_truth
6
- assert true
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