mudrat_projector 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +3 -0
  5. data/Gemfile +4 -0
  6. data/Gemfile.lock +49 -0
  7. data/README.md +46 -0
  8. data/Rakefile +26 -0
  9. data/bin/testrb +3 -0
  10. data/finance_fu.txt +41 -0
  11. data/lib/mudrat_projector/account.rb +75 -0
  12. data/lib/mudrat_projector/amortizer.rb +103 -0
  13. data/lib/mudrat_projector/banker_rounding.rb +11 -0
  14. data/lib/mudrat_projector/chart_of_accounts.rb +119 -0
  15. data/lib/mudrat_projector/date_diff.rb +169 -0
  16. data/lib/mudrat_projector/projection.rb +45 -0
  17. data/lib/mudrat_projector/projector.rb +71 -0
  18. data/lib/mudrat_projector/schedule.rb +45 -0
  19. data/lib/mudrat_projector/scheduled_transaction.rb +45 -0
  20. data/lib/mudrat_projector/tax_calculation.rb +154 -0
  21. data/lib/mudrat_projector/tax_calculator.rb +144 -0
  22. data/lib/mudrat_projector/tax_values_by_year.yml +102 -0
  23. data/lib/mudrat_projector/transaction.rb +71 -0
  24. data/lib/mudrat_projector/transaction_entry.rb +126 -0
  25. data/lib/mudrat_projector/transaction_handler.rb +19 -0
  26. data/lib/mudrat_projector/validator.rb +49 -0
  27. data/lib/mudrat_projector/version.rb +3 -0
  28. data/lib/mudrat_projector.rb +27 -0
  29. data/mudrat_projector.gemspec +28 -0
  30. data/test/integrations/long_term_projection_test.rb +42 -0
  31. data/test/integrations/mortgage_test.rb +85 -0
  32. data/test/integrations/self_employed_tax_calculation_test.rb +44 -0
  33. data/test/models/accounts_test.rb +39 -0
  34. data/test/models/chart_of_accounts_test.rb +170 -0
  35. data/test/models/date_diff_test.rb +117 -0
  36. data/test/models/projection_test.rb +62 -0
  37. data/test/models/projector_test.rb +168 -0
  38. data/test/models/schedule_test.rb +68 -0
  39. data/test/models/scheduled_transaction_test.rb +47 -0
  40. data/test/models/tax_calculator_test.rb +145 -0
  41. data/test/models/transaction_entry_test.rb +37 -0
  42. data/test/models/transaction_handler_test.rb +67 -0
  43. data/test/models/transaction_test.rb +66 -0
  44. data/test/models/validator_test.rb +45 -0
  45. data/test/test_helper.rb +69 -0
  46. metadata +204 -0
@@ -0,0 +1,67 @@
1
+ require 'test_helper'
2
+
3
+ class TransactionHandlerTest < Minitest::Test
4
+ def setup
5
+ @chart = ChartOfAccounts.new.tap do |c|
6
+ c.add_account :checking, type: :asset
7
+ c.add_account :job, type: :revenue
8
+ end
9
+ @projection = Projection.new range: (jan_1_2000..dec_31_2000), chart: @chart
10
+ @transaction_handler = TransactionHandler.new projection: @projection
11
+ end
12
+
13
+ def test_routes_non_scheduled_transactions_in_range_to_projection
14
+ @transaction_handler << fixed_transaction
15
+ assert_equal 1, @projection.transaction_sequence.size
16
+ end
17
+
18
+ def test_does_not_route_non_scheduled_transactions_after_range_to_projection
19
+ @transaction_handler << fixed_transaction(date: jan_1_2001)
20
+ assert_equal 0, @projection.transaction_sequence.size
21
+ end
22
+
23
+ def test_routes_non_scheduled_transactions_after_range_to_next_projector
24
+ @transaction_handler.next_projector = next_projector
25
+ @transaction_handler << fixed_transaction(date: jan_1_2001)
26
+ assert_equal 1, next_projector.transactions.size
27
+ end
28
+
29
+ def test_routes_a_scheduled_transaction_into_projector
30
+ @transaction_handler << scheduled_transaction
31
+ assert_equal 12, @projection.transaction_sequence.size
32
+ end
33
+
34
+ def test_routes_any_remainder_of_a_scheduled_transaction_into_next_projector
35
+ @transaction_handler.next_projector = next_projector
36
+ @transaction_handler << scheduled_transaction(end_date: july_1_2001)
37
+ assert_equal 1, next_projector.transactions.size
38
+ end
39
+
40
+ private
41
+
42
+ def fixed_transaction date: jan_1_2000, amount: 1000
43
+ Transaction.new(
44
+ date: date,
45
+ debit: { amount: amount, account_id: :checking },
46
+ credit: { amount: amount, account_id: :job },
47
+ )
48
+ end
49
+
50
+ def scheduled_transaction start_date: jan_1_2000, end_date: dec_31_2000, amount: 1000
51
+ ScheduledTransaction.new(
52
+ date: start_date,
53
+ debit: { amount: amount, account_id: :checking },
54
+ credit: { amount: amount, account_id: :job },
55
+ schedule: every_month(until: end_date),
56
+ )
57
+ end
58
+
59
+ def next_projector
60
+ @next_projector ||=
61
+ Struct.new :transactions do
62
+ def add_transaction transaction
63
+ transactions.push transaction
64
+ end
65
+ end.new(Array.new)
66
+ end
67
+ end
@@ -0,0 +1,66 @@
1
+ require 'test_helper'
2
+
3
+ class TransactionTest < Minitest::Test
4
+ def test_balanced_on_fixed_transactions
5
+ assert Transaction.new(
6
+ date: jan_1_2000,
7
+ credits: [{ amount: 1, account_id: :checking }],
8
+ debits: [{ amount: 1, account_id: :bills }],
9
+ ).balanced?
10
+
11
+ refute Transaction.new(
12
+ date: jan_1_2000,
13
+ credits: [{ amount: 1, account_id: :checking }],
14
+ debits: [{ amount: 2, account_id: :bills }],
15
+ ).balanced?
16
+ end
17
+
18
+ def test_balanced_on_percentage_transactions
19
+ refute Transaction.new(
20
+ date: jan_1_2000,
21
+ credit: { percent: 25.0, of: :savings, account_id: :checking },
22
+ debit: { amount: 25, account_id: :bills },
23
+ ).balanced?
24
+
25
+ refute Transaction.new(
26
+ date: jan_1_2000,
27
+ credit: { percent: 25.0, of: :savings, account_id: :checking },
28
+ debit: { percent: 24.0, of: :savings, account_id: :bills },
29
+ ).balanced?
30
+
31
+ assert Transaction.new(
32
+ date: jan_1_2000,
33
+ credit: { percent: 25.0, of: :savings , account_id: :checking },
34
+ debits: [{percent: 12.5, of: :savings , account_id: :bills },
35
+ {percent: 12.5, of: :savings , account_id: :bills }],
36
+ ).balanced?
37
+ end
38
+
39
+ def test_can_supply_a_single_credit_or_debit
40
+ Transaction.new(
41
+ date: jan_1_2000,
42
+ credit: { amount: 1, account_id: :checking },
43
+ debit: { amount: 1, account_id: :bills },
44
+ )
45
+ # Can't supply both a :credit and :credits
46
+ assert_raises ArgumentError do
47
+ Transaction.new(
48
+ date: jan_1_2000,
49
+ credit: { amount: 1, account_id: :checking },
50
+ credits: [{ amount: 2, account_id: :checking }],
51
+ debits: [{ amount: 1, account_id: :bills }],
52
+ )
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def valid_transaction schedule: nil
59
+ Transaction.new(
60
+ date: jan_1_2000,
61
+ credits: [{ amount: 1, account_id: :checking }],
62
+ debits: [{ amount: 1, account_id: :bills }],
63
+ schedule: schedule,
64
+ )
65
+ end
66
+ end
@@ -0,0 +1,45 @@
1
+ require 'test_helper'
2
+
3
+ class ValidatorTest < Minitest::Test
4
+ def setup
5
+ @projector = Projector.new from: jan_1_2000
6
+ @projector.add_account :checking, type: :asset
7
+ @projector.add_account :job, type: :revenue
8
+ end
9
+
10
+ def test_cannot_add_transaction_without_entriess
11
+ assert_raises Projector::InvalidTransaction do
12
+ @projector.add_transaction(
13
+ date: jan_1_2000
14
+ )
15
+ end
16
+ assert_raises Projector::InvalidTransaction do
17
+ @projector.add_transaction(
18
+ date: jan_1_2000,
19
+ credits: [],
20
+ debits: [],
21
+ )
22
+ end
23
+ end
24
+
25
+ def test_past_transaction
26
+ assert_raises Projector::InvalidTransaction do
27
+ @projector.add_transaction(
28
+ date: dec_31_1999,
29
+ credit: { amount: 1000, account_id: :job },
30
+ debit: { amount: 1000, account_id: :checking },
31
+ )
32
+ end
33
+ end
34
+
35
+ def test_cannot_add_single_transaction_which_does_not_balance
36
+ assert_raises Projector::BalanceError do
37
+ @projector.add_transaction(
38
+ date: jan_1_2000,
39
+ credit: { amount: 1000, account_id: :job },
40
+ debit: { amount: 999, account_id: :checking },
41
+ )
42
+ end
43
+ end
44
+
45
+ end
@@ -0,0 +1,69 @@
1
+ require 'simplecov' if ENV['COVERAGE']
2
+
3
+ require 'minitest/autorun'
4
+ require 'minitest/unit'
5
+ require 'minitest/reporters'
6
+
7
+ require 'ostruct'
8
+ require 'pp'
9
+
10
+ require 'mudrat_projector'
11
+
12
+ # Require pry library on demand to avoid eating its >500ms start up penalty
13
+ class Binding
14
+ def method_missing sym, *args
15
+ if sym == :pry && args.empty? && !block_given?
16
+ require 'pry'
17
+ pry
18
+ else
19
+ super
20
+ end
21
+ end
22
+ end
23
+
24
+ # Dates need friendlier output
25
+ class Date
26
+ def inspect
27
+ strftime
28
+ end
29
+ end
30
+
31
+ # BigDecimal needs friendlier output
32
+ class BigDecimal < Numeric
33
+ def inspect
34
+ "#<BigDecmial:#{round(10).to_f.inspect}>"
35
+ end
36
+ end
37
+
38
+ Minitest::Reporters.use! MiniTest::Reporters::DefaultReporter.new
39
+
40
+ class Minitest::Test
41
+ include MudratProjector
42
+
43
+ # Enable you to just call "jan_1_2000" to new up a date.
44
+ def method_missing sym, *args, &block
45
+ return super if block_given? || args.size > 0
46
+ begin
47
+ Date.parse sym.to_s
48
+ rescue ArgumentError => ae
49
+ super
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def epoch
56
+ jan_1_1970
57
+ end
58
+
59
+ def every_month **params
60
+ end_date = params[:until]
61
+ if end_date
62
+ from = params[:from] || jan_1_2000
63
+ count = DateDiff.date_diff unit: :month, from: from, to: end_date
64
+ { unit: :month, scalar: 1, count: count }
65
+ else
66
+ { unit: :month, scalar: 1 }
67
+ end
68
+ end
69
+ end
metadata ADDED
@@ -0,0 +1,204 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mudrat_projector
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - ntl
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest-reporters
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: timecop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Mudrat Projector is a simple financial projection engine.
112
+ email:
113
+ - nathanladd+github@gmail.com
114
+ executables:
115
+ - testrb
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - .gitignore
120
+ - .ruby-version
121
+ - .travis.yml
122
+ - Gemfile
123
+ - Gemfile.lock
124
+ - README.md
125
+ - Rakefile
126
+ - bin/testrb
127
+ - finance_fu.txt
128
+ - lib/mudrat_projector.rb
129
+ - lib/mudrat_projector/account.rb
130
+ - lib/mudrat_projector/amortizer.rb
131
+ - lib/mudrat_projector/banker_rounding.rb
132
+ - lib/mudrat_projector/chart_of_accounts.rb
133
+ - lib/mudrat_projector/date_diff.rb
134
+ - lib/mudrat_projector/projection.rb
135
+ - lib/mudrat_projector/projector.rb
136
+ - lib/mudrat_projector/schedule.rb
137
+ - lib/mudrat_projector/scheduled_transaction.rb
138
+ - lib/mudrat_projector/tax_calculation.rb
139
+ - lib/mudrat_projector/tax_calculator.rb
140
+ - lib/mudrat_projector/tax_values_by_year.yml
141
+ - lib/mudrat_projector/transaction.rb
142
+ - lib/mudrat_projector/transaction_entry.rb
143
+ - lib/mudrat_projector/transaction_handler.rb
144
+ - lib/mudrat_projector/validator.rb
145
+ - lib/mudrat_projector/version.rb
146
+ - mudrat_projector.gemspec
147
+ - test/integrations/long_term_projection_test.rb
148
+ - test/integrations/mortgage_test.rb
149
+ - test/integrations/self_employed_tax_calculation_test.rb
150
+ - test/models/accounts_test.rb
151
+ - test/models/chart_of_accounts_test.rb
152
+ - test/models/date_diff_test.rb
153
+ - test/models/projection_test.rb
154
+ - test/models/projector_test.rb
155
+ - test/models/schedule_test.rb
156
+ - test/models/scheduled_transaction_test.rb
157
+ - test/models/tax_calculator_test.rb
158
+ - test/models/transaction_entry_test.rb
159
+ - test/models/transaction_handler_test.rb
160
+ - test/models/transaction_test.rb
161
+ - test/models/validator_test.rb
162
+ - test/test_helper.rb
163
+ homepage: https://github.com/ntl/mudrat-projector
164
+ licenses:
165
+ - MIT
166
+ metadata: {}
167
+ post_install_message:
168
+ rdoc_options: []
169
+ require_paths:
170
+ - lib
171
+ required_ruby_version: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - '>='
174
+ - !ruby/object:Gem::Version
175
+ version: '0'
176
+ required_rubygems_version: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - '>='
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ requirements: []
182
+ rubyforge_project:
183
+ rubygems_version: 2.0.14
184
+ signing_key:
185
+ specification_version: 4
186
+ summary: Mudrat Projector is a simple financial projection engine designed for personal
187
+ finance computations.
188
+ test_files:
189
+ - test/integrations/long_term_projection_test.rb
190
+ - test/integrations/mortgage_test.rb
191
+ - test/integrations/self_employed_tax_calculation_test.rb
192
+ - test/models/accounts_test.rb
193
+ - test/models/chart_of_accounts_test.rb
194
+ - test/models/date_diff_test.rb
195
+ - test/models/projection_test.rb
196
+ - test/models/projector_test.rb
197
+ - test/models/schedule_test.rb
198
+ - test/models/scheduled_transaction_test.rb
199
+ - test/models/tax_calculator_test.rb
200
+ - test/models/transaction_entry_test.rb
201
+ - test/models/transaction_handler_test.rb
202
+ - test/models/transaction_test.rb
203
+ - test/models/validator_test.rb
204
+ - test/test_helper.rb