mudrat_projector 0.9.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 (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