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.
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