financial 0.0.1

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 (59) hide show
  1. data/.gitignore +4 -0
  2. data/.infinity_test +16 -0
  3. data/.rspec +3 -0
  4. data/.rvmrc +1 -0
  5. data/Gemfile +15 -0
  6. data/Gemfile.lock +74 -0
  7. data/README.markdown +157 -0
  8. data/Rakefile +1 -0
  9. data/duck_tales.gif +0 -0
  10. data/example.png +0 -0
  11. data/examples/two_accounts.rb +32 -0
  12. data/features/portuguese_dsl.feature +93 -0
  13. data/features/print_financial_table.feature +318 -0
  14. data/features/support/env.rb +1 -0
  15. data/financial.gemspec +22 -0
  16. data/lib/financial.rb +39 -0
  17. data/lib/financial/account.rb +129 -0
  18. data/lib/financial/account_manager.rb +26 -0
  19. data/lib/financial/balance.rb +11 -0
  20. data/lib/financial/balance_calculation.rb +35 -0
  21. data/lib/financial/cost.rb +34 -0
  22. data/lib/financial/costs.rb +30 -0
  23. data/lib/financial/deposit.rb +30 -0
  24. data/lib/financial/deposits.rb +15 -0
  25. data/lib/financial/dsl.rb +16 -0
  26. data/lib/financial/financial_date.rb +18 -0
  27. data/lib/financial/financial_table.rb +109 -0
  28. data/lib/financial/locale.rb +153 -0
  29. data/lib/financial/locales/en.yml +34 -0
  30. data/lib/financial/locales/pt.yml +67 -0
  31. data/lib/financial/parcels.rb +87 -0
  32. data/lib/financial/per_cent.rb +12 -0
  33. data/lib/financial/print_table.rb +34 -0
  34. data/lib/financial/revenue.rb +40 -0
  35. data/lib/financial/revenues.rb +16 -0
  36. data/lib/financial/rspec_matchers.rb +32 -0
  37. data/lib/financial/tax.rb +4 -0
  38. data/lib/financial/version.rb +3 -0
  39. data/spec/financial/account_manager_spec.rb +38 -0
  40. data/spec/financial/account_spec.rb +399 -0
  41. data/spec/financial/balance_spec.rb +44 -0
  42. data/spec/financial/cost_spec.rb +78 -0
  43. data/spec/financial/costs_spec.rb +18 -0
  44. data/spec/financial/deposit_spec.rb +78 -0
  45. data/spec/financial/deposits_spec.rb +23 -0
  46. data/spec/financial/english_spec.rb +76 -0
  47. data/spec/financial/financial_date_spec.rb +50 -0
  48. data/spec/financial/financial_spec.rb +14 -0
  49. data/spec/financial/financial_table_spec.rb +31 -0
  50. data/spec/financial/locale_spec.rb +37 -0
  51. data/spec/financial/parcels_spec.rb +179 -0
  52. data/spec/financial/per_cent_spec.rb +24 -0
  53. data/spec/financial/portuguese_spec.rb +117 -0
  54. data/spec/financial/print_table_spec.rb +76 -0
  55. data/spec/financial/revenue_spec.rb +89 -0
  56. data/spec/financial/revenues_spec.rb +18 -0
  57. data/spec/financial/tax_spec.rb +42 -0
  58. data/spec/spec_helper.rb +25 -0
  59. metadata +139 -0
@@ -0,0 +1,32 @@
1
+ module Financial
2
+ module RSpecMatchers
3
+ def self.included(base)
4
+ create_include_balance_matcher
5
+ end
6
+
7
+ def create_include_balance_matcher
8
+ RSpec::Matchers.define :include_balance do |expected|
9
+ chain :in_date do |date|
10
+ @date = Financial::FinancialDate.new(date).date
11
+ end
12
+
13
+ failure_message_for_should do |actual|
14
+ if @date
15
+ "expected #{actual} to have balance #{expected} in date #{@date}"
16
+ else
17
+ "expected #{actual} to have balance #{expected}"
18
+ end
19
+ end
20
+
21
+ match do |actual|
22
+ actual.should_not be_empty
23
+ if @date
24
+ actual.any? { |balance| balance.date == @date and balance.value == expected }
25
+ else
26
+ actual.any? { |balance| balance.value == expected }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,4 @@
1
+ module Financial
2
+ class Tax < Cost
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ module Financial
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ module Financial
4
+ describe AccountManager do
5
+ let(:account_manager) { AccountManager.instance }
6
+
7
+ describe '.instance' do
8
+ it 'should have the singleton pattern' do
9
+ account_manager.should be_equal AccountManager.instance
10
+ end
11
+ end
12
+
13
+ describe '#accounts' do
14
+ it 'should initialize with an Array' do
15
+ account_manager.accounts.should be_instance_of(Array)
16
+ end
17
+ end
18
+
19
+ describe '#find_account' do
20
+ before do
21
+ @lucy_bank = account_manager.new_account(:lucy_bank)
22
+ @leo_bank = account_manager.new_account(:leo_bank)
23
+ end
24
+
25
+ it 'should find the account specified' do
26
+ account_manager.find_account(:lucy_bank).should == [@lucy_bank]
27
+ end
28
+
29
+ it 'should find all the accounts when pass :all option' do
30
+ account_manager.find_account(:all).should equal account_manager.accounts
31
+ end
32
+
33
+ it 'should find all the accounts when pass :all option' do
34
+ account_manager.find_account(:todas).should equal account_manager.accounts
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,399 @@
1
+ require 'spec_helper'
2
+
3
+ module Financial
4
+ describe Account do
5
+ let(:reserved_bank) { Financial.account_manager.new_account(:reserved_bank) }
6
+ let(:bank_account) { Account.new([:bank_account, {:as=>"Bank Account"}]) }
7
+ let(:super_bank_account) { Account.new(:super_bank_account) }
8
+
9
+ describe '#name' do
10
+ it 'should return the name of the account' do
11
+ reserved_bank.name.should equal :reserved_bank
12
+ end
13
+
14
+ it 'should assign the name when pass many args' do
15
+ bank_account.name.should equal :bank_account
16
+ end
17
+ end
18
+
19
+ describe '#banner' do
20
+ it 'should assign the name with spaces and capitalize if dont pass a name' do
21
+ reserved_bank.banner.should == "Reserved bank"
22
+ end
23
+
24
+ it 'should assign the banner as a option' do
25
+ bank_account.banner.should == 'Bank Account'
26
+ end
27
+ end
28
+
29
+ describe '#total' do
30
+ it 'should return zero if dont pass any value' do
31
+ bank_account.total.should be 0
32
+ end
33
+
34
+ it 'should return the value passed in argument' do
35
+ bank_account.total(400)
36
+ bank_account.total.should be 400
37
+ end
38
+ end
39
+
40
+ describe '#total_costs' do
41
+ it 'should calculate total costs' do
42
+ bank_account.costs do
43
+ credit_card 100
44
+ other_costs 1040
45
+ end
46
+ bank_account.total_costs.should be 1140
47
+ end
48
+
49
+ it 'should calculate total costs counting parcels' do
50
+ bank_account.costs do
51
+ credit_card 1000
52
+ parcels(10).of(300)
53
+ end
54
+ bank_account.total_costs.should be 4000
55
+ end
56
+
57
+ it 'should calculate floats too' do
58
+ bank_account.costs do
59
+ credit 500.55
60
+ other 100.10
61
+ end
62
+ bank_account.total_costs.should == 600.65
63
+ end
64
+
65
+ it 'should assign to instance variable' do
66
+ bank_account.costs { some_costs 300 }
67
+ bank_account.total_costs
68
+ bank_account.instance_variable_get(:@total_costs).should be 300
69
+ end
70
+
71
+ it 'should return zero when dont have costs' do
72
+ bank_account.total_costs.should be 0
73
+ end
74
+
75
+ it 'should assign a instance variable zero if dont have revenues' do
76
+ bank_account.total_costs
77
+ bank_account.instance_variable_get(:@total_costs).should be 0
78
+ end
79
+
80
+ it 'should count the deposits with costs' do
81
+ bank_account.costs { credit 1000 }
82
+ bank_account.deposits { deposit(2000) }
83
+ bank_account.total_costs.should be 3000
84
+ end
85
+
86
+ it 'should count the deposits' do
87
+ bank_account.deposits { deposit(100) }
88
+ bank_account.total_costs.should be 100
89
+ end
90
+ end
91
+
92
+ describe '#deposits' do
93
+ it 'should have some deposits' do
94
+ bank_account.deposits do
95
+ deposit(100)
96
+ end
97
+ bank_account.deposits.should have(1).item
98
+ end
99
+ end
100
+
101
+ describe '#taxes' do
102
+ it 'should have some taxes' do
103
+ bank_account.revenues do
104
+ billing(100).tax(1)
105
+ end
106
+ bank_account.taxes.should == [Tax.new(:billing, 100)]
107
+ end
108
+
109
+ it 'should ignore the revenues without taxes' do
110
+ bank_account.revenues { billing 100 }
111
+ bank_account.taxes.should == []
112
+ end
113
+ end
114
+
115
+ describe '#total_revenues' do
116
+ it 'should return the revenue value if have one revenue only' do
117
+ bank_account.revenues { billing_value 500 }
118
+ bank_account.total_revenues.should be 500
119
+ end
120
+
121
+ it 'should return calculate the revenue value' do
122
+ bank_account.revenues do
123
+ billing_value 499
124
+ other_value 1000
125
+ end
126
+ bank_account.total_revenues.should be 1499
127
+ end
128
+
129
+ it 'should return zero when dont have revenues' do
130
+ bank_account.total_revenues.should be 0
131
+ end
132
+
133
+ it 'should assign a instance variable' do
134
+ bank_account.revenues { a_revenue 100 }
135
+ bank_account.total_revenues
136
+ bank_account.instance_variable_get(:@total_revenues).should be 100
137
+ end
138
+
139
+ it 'should assign a instance variable zero if dont have revenues' do
140
+ bank_account.total_revenues
141
+ bank_account.instance_variable_get(:@total_revenues).should be 0
142
+ end
143
+ end
144
+
145
+ describe '#costs' do
146
+ it 'should return an empty costs when does not have any costs' do
147
+ reserved_bank.costs.should be_empty
148
+ end
149
+
150
+ it 'should return an Costs' do
151
+ reserved_bank.costs.should be_instance_of(Costs)
152
+ end
153
+
154
+ context 'with parcels' do
155
+ before { reserved_bank.costs { parcels(2).of(400) } }
156
+
157
+ it 'should split all the parcels in cost' do
158
+ reserved_bank.costs.all? { |cost| cost.class == Cost }.should be_true
159
+ end
160
+
161
+ it 'should keep the value of the parcel and setting in the cost' do
162
+ reserved_bank.costs.all? { |cost| cost.value.equal?(400) }.should be_true
163
+ end
164
+
165
+ it 'should keep the dates of the parcel and setting in the cost' do
166
+ reserved_bank.costs.all? { |cost| cost.date.is_a?(Date) }.should be_true
167
+ end
168
+ end
169
+
170
+ context 'with a block' do
171
+ let(:cost) { reserved_bank.costs.first }
172
+ before do
173
+ Financial.locale = :en
174
+ reserved_bank.costs do
175
+ a_cost(400).in_date('09/20/2011')
176
+ end
177
+ cost.should_not be_nil
178
+ end
179
+
180
+ it 'cost should be instance of Cost' do
181
+ cost.should be_instance_of(Financial::Cost)
182
+ end
183
+
184
+ it 'cost should set the cost_name' do
185
+ cost.name.should == 'A cost'
186
+ end
187
+
188
+ it 'cost should set the value' do
189
+ cost.value.should equal 400
190
+ end
191
+
192
+ it 'cost should set the date' do
193
+ cost.date.should == Date.new(2011, 9, 20)
194
+ end
195
+ end
196
+ end
197
+
198
+ describe '#revenues' do
199
+ it 'should return an empty revenues when does not have revenues' do
200
+ reserved_bank.revenues.should be_empty
201
+ end
202
+
203
+ it 'should return an Array' do
204
+ reserved_bank.revenues.should be_instance_of(Financial::Revenues)
205
+ end
206
+
207
+ context 'with a block should push a revenue that:' do
208
+ let(:revenue) { reserved_bank.revenues.first }
209
+ before do
210
+ reserved_bank.revenues do
211
+ a_revenue(100).in_date('7/17/2011')
212
+ end
213
+ revenue.should_not be_nil
214
+ end
215
+
216
+ it 'contain a instance of Financial::Revenue' do
217
+ revenue.should be_instance_of(Financial::Revenue)
218
+ end
219
+
220
+ it 'contain the name of the revenue' do
221
+ revenue.name.should == 'A revenue'
222
+ end
223
+
224
+ it 'contain the value of the revenue' do
225
+ revenue.value.should equal 100
226
+ end
227
+
228
+ it 'contain the date of the revenue' do
229
+ revenue.date.should == Date.civil(2011, 7, 17)
230
+ end
231
+ end
232
+ end
233
+
234
+ describe '#balances' do
235
+ before do
236
+ reserved_bank.total 300
237
+ end
238
+
239
+ it 'should include a balance that subtract costs' do
240
+ reserved_bank.costs { credit(100).in_date('1/1/2011')}
241
+ reserved_bank.calculate_balances.should include_balance(200).in_date('1/1/2011')
242
+ end
243
+
244
+ it 'should include a balance that subtract deposits' do
245
+ reserved_bank.deposits { deposit(900).in_date('1/2/2011')}
246
+ reserved_bank.calculate_balances.should include_balance(-600).in_date('1/2/2011')
247
+ end
248
+
249
+ it 'should include a balance that subtract the tax' do
250
+ reserved_bank.revenues { bill(100).in_date('1/2/2011').tax(0.1).in_date('1/3/2011') }
251
+ reserved_bank.calculate_balances.should include_balance(390).in_date('1/3/2011')
252
+ end
253
+
254
+ it 'should include a balance that add a revenue' do
255
+ reserved_bank.revenues { bill(1000).in_date('4/4/2011') }
256
+ reserved_bank.calculate_balances.should include_balance(1300).in_date('4/4/2011')
257
+ end
258
+
259
+ it 'should include a balance that add a revenue and subtract a cost in the same date' do
260
+ reserved_bank.revenues { bill(900).in_date('3/3/2011')}
261
+ reserved_bank.costs { credit(600).in_date('3/3/2011')}
262
+ reserved_bank.calculate_balances.should include_balance(600).in_date('3/3/2011')
263
+ reserved_bank.balances.should include_balance(600).in_date('3/3/2011')
264
+ end
265
+
266
+ it 'should include a balance that subtract costs, deposits and taxes in the same date' do
267
+ reserved_bank.revenues { bill(1000).in_date('5/5/2011').tax(0.1).in_date('5/5/2011')}
268
+ reserved_bank.costs { credit(400).in_date('5/5/2011') }
269
+ reserved_bank.deposits { deposit(600).in_date('5/5/2011') }
270
+ reserved_bank.calculate_balances.should have(1).item
271
+ reserved_bank.calculate_balances.should include_balance(200.0).in_date('5/5/2011')
272
+ end
273
+
274
+ it 'should include a balance for the reserved_bank that receives a deposit' do
275
+ bank_account.total 110.0
276
+ reserved_bank.deposits { deposit(150).in_account(:bank_account).in_date('9/20/2011') }
277
+ bank_account.balances.should include_balance(260.0).in_date('9/20/2011')
278
+ end
279
+
280
+ it 'should include a balance of all receiveds deposits in the same date' do
281
+ super_bank_account.total 4000
282
+ account :other_super_account do
283
+ deposits do
284
+ deposit(100).in_account(:super_bank_account).in_date('9/20/2011')
285
+ end
286
+ end
287
+ account :hiper do
288
+ deposits do
289
+ deposit(1000).in_account(:super_bank_account).in_date('9/20/2011')
290
+ end
291
+ end
292
+ super_bank_account.balances.should include_balance(5100).in_date('9/20/2011')
293
+ end
294
+ end
295
+
296
+ describe '#costs_in_date' do
297
+ let(:date) { Date.civil(2011, 7, 1) }
298
+
299
+ it 'should return all costs in date' do
300
+ bank_account.costs do
301
+ credit_card(400).in_date '7/1/2011'
302
+ other(300).in_date '3/4/2011'
303
+ end
304
+ bank_account.costs_in_date(date).should == [bank_account.costs.first]
305
+ end
306
+
307
+ it 'should return an empty array when dont have costs' do
308
+ bank_account.costs_in_date(date).should == []
309
+ end
310
+ end
311
+
312
+ describe '#revenues_in_date' do
313
+ let(:date) { Date.civil(2011, 7, 1) }
314
+
315
+ it 'should return all costs in date' do
316
+ bank_account.revenues do
317
+ bill(400).in_date '7/1/2011'
318
+ salary(300).in_date '3/4/2011'
319
+ end
320
+ bank_account.revenues_in_date(date).should == [bank_account.revenues.first]
321
+ end
322
+
323
+ it 'should return the receiveds deposits for bank_account' do
324
+ bank_account.deposits { deposit(100).in_account(:super_bank_account).in_date('7/1/2011') }
325
+ super_account = Financial.account_manager.new_account(:super_bank_account)
326
+ Financial.account_manager.should_receive(:accounts).and_return([super_account, bank_account])
327
+ super_account.revenues_in_date(date).should == [bank_account.deposits.first]
328
+ end
329
+
330
+ it 'should return an empty array when dont have costs' do
331
+ bank_account.revenues_in_date(date).should == []
332
+ end
333
+ end
334
+
335
+ describe '#events_in_date' do
336
+ let(:date) { Date.civil(2011, 7, 1) }
337
+
338
+ it 'should return all costs in date' do
339
+ bank_account.costs do
340
+ credit_card(400).in_date '7/1/2011'
341
+ end
342
+ bank_account.events_in_date(date).should == [bank_account.costs.first]
343
+ end
344
+
345
+ it 'should return all revenues in date' do
346
+ bank_account.revenues do
347
+ service(500).in_date '7/1/2011'
348
+ end
349
+ bank_account.events_in_date(date).should == [bank_account.revenues.first]
350
+ end
351
+
352
+ it 'should return all deposits in date' do
353
+ bank_account.deposits do
354
+ deposit(500).in_date('7/1/2011')
355
+ deposit(1000).in_date('7/1/2011')
356
+ end
357
+ bank_account.events_in_date(date).should == bank_account.deposits
358
+ end
359
+ end
360
+
361
+ describe '#last_balance_in_date' do
362
+ let(:date) { Date.civil(2011, 6, 14)}
363
+
364
+ it 'should return the toal when not have balances' do
365
+ bank_account.last_balance_in_date(date).should be(0)
366
+ end
367
+
368
+ it 'should return the last balance for the exactly date' do
369
+ bank_account.costs { a_cost(400).in_date '6/14/2011' }
370
+ bank_account.last_balance_in_date(date).should be -400
371
+ end
372
+
373
+ it 'should return the last balance that is less than date' do
374
+ bank_account.costs { other_cost(980).in_date '6/01/2011'}
375
+ bank_account.last_balance_in_date(date).should be -980
376
+ end
377
+
378
+ it 'should not return a old balance that is not the last balance for date' do
379
+ bank_account.costs do
380
+ a_cost(700).in_date '6/01/2011'
381
+ credit(300).in_date '6/12/2011'
382
+ end
383
+ bank_account.last_balance_in_date(date).should be -1000
384
+ end
385
+ end
386
+
387
+ describe '.find' do
388
+ it 'should find the reserved_bank account' do
389
+ bank_account
390
+ Account.find(:name => :reserved_bank).should == reserved_bank
391
+ end
392
+
393
+ it 'should find the reserved_bank account pass a stirng value' do
394
+ bank_account
395
+ Account.find(:name => 'reserved_bank').should == reserved_bank
396
+ end
397
+ end
398
+ end
399
+ end