lohnsteuer 0.1.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.
@@ -0,0 +1,3 @@
1
+ module Lohnsteuer
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'lohnsteuer/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "lohnsteuer"
8
+ spec.version = Lohnsteuer::VERSION
9
+ spec.authors = ["Jan Ahrens"]
10
+ spec.email = ["jan.ahrens+rubygems@googlemail.com"]
11
+ spec.summary = %q{German tax calculation algorithm}
12
+ spec.description = ""
13
+ spec.homepage = "https://github.com/JanAhrens/lohnsteuer-ruby"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ end
@@ -0,0 +1,71 @@
1
+ require 'minitest/autorun'
2
+ require 'lohnsteuer'
3
+
4
+ class LohnsteuerTest < MiniTest::Unit::TestCase
5
+ def test_calculate_month_throws_an_error_when_no_tax_algorithm_applies
6
+ assert_raises(RuntimeError) do
7
+ Lohnsteuer.calculate_month(1991, 12, 2000)
8
+ end
9
+ end
10
+
11
+ def test_calculate_month_delegates_to_the_correct_tax_algorithm
12
+ mock = MiniTest::Mock.new
13
+ mock.expect(:applies?, true, [Date.new(2016, 2, 1)])
14
+ mock.expect(:calculate, {}, [default_calculate_params.merge(RE4: 2000 * 100.0)])
15
+
16
+ Lohnsteuer.stub(:tax_algorithms, [mock]) do
17
+ Lohnsteuer.calculate_month(2016, 2, 2000)
18
+ end
19
+
20
+ assert mock.verify
21
+ end
22
+
23
+ def test_calculate_delegates_to_calculate_month
24
+ options_stub = Object.new
25
+ mock = MiniTest::Mock.new
26
+ (1..12).each { |month| mock.expect(:call, valid_calculate_month_result, [2016, month, 2000.0, options_stub]) }
27
+
28
+ Lohnsteuer.stub(:calculate_month, mock) do
29
+ Lohnsteuer.calculate(2016, 24_000, options_stub)
30
+ end
31
+
32
+ assert mock.verify
33
+ end
34
+
35
+ def test_calculate_month_maps_the_results
36
+ result_to_map = { LSTLZZ: 19500, STS: 1000, STV: 200, SOLZLZZ: 1900, SOLZS: 100 }
37
+ mock = MiniTest::Mock.new
38
+ mock.expect(:applies?, true, [Date.new(2016, 2, 1)])
39
+ mock.expect(:calculate, result_to_map, [default_calculate_params.merge(RE4: 2000 * 100.0)])
40
+
41
+ Lohnsteuer.stub(:tax_algorithms, [mock]) do
42
+ res = Lohnsteuer.calculate_month(2016, 2, 2000)
43
+ assert_equal 207.0, res[:income_tax]
44
+ assert_equal 20.0, res[:solidarity_tax]
45
+ end
46
+ end
47
+
48
+ def test_calculate_combines_the_results_of_all_months
49
+ options_stub = Object.new
50
+ mock = MiniTest::Mock.new
51
+ (1..12).each do |month|
52
+ mock.expect(:call, valid_calculate_month_result, [2016, month, 2000.0, options_stub])
53
+ end
54
+
55
+ Lohnsteuer.stub(:calculate_month, mock) do
56
+ res = Lohnsteuer.calculate(2016, 24_000, options_stub)
57
+ assert_equal 2_400, res[:income_tax]
58
+ assert_equal 240, res[:solidarity_tax]
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def default_calculate_params
65
+ { STKL: 1, LZZ: 2, PKV: 0, KVZ: 1.10, PVZ: 1, ZKF: 0 }
66
+ end
67
+
68
+ def valid_calculate_month_result
69
+ { income_tax: 200, solidarity_tax: 20 }
70
+ end
71
+ end
@@ -0,0 +1,96 @@
1
+ require 'minitest/autorun'
2
+ require 'lohnsteuer/lst1215'
3
+
4
+ # Note: The test data was taken from page 40 and 41:
5
+ # https://www.bmf-steuerrechner.de/pruefdaten/pap2015Dezember.pdf
6
+ class Lst1215Test < MiniTest::Unit::TestCase
7
+ def test_applies_to_december_2015
8
+ assert_equal true, Lst1215.applies?(Date.new(2015, 12, 7))
9
+ end
10
+
11
+ def test_doesnt_apply_to_november_2015
12
+ assert_equal false, Lst1215.applies?(Date.new(2015, 11, 30))
13
+ end
14
+
15
+ def test_general_tax_class_1
16
+ params = general_params.merge(RE4: 40_000 * 100, STKL: 1)
17
+ res = Lst1215.calculate(params)
18
+ assert_equal 6_499, res[:LSTLZZ] / 100
19
+ end
20
+
21
+ def test_general_tax_class_2
22
+ params = general_params.merge(RE4: 40_000 * 100, STKL: 2, PVZ: 0)
23
+ res = Lst1215.calculate(params)
24
+ assert_equal 5_912, res[:LSTLZZ] / 100
25
+ end
26
+
27
+ def test_general_tax_class_3
28
+ params = general_params.merge(RE4: 40_000 * 100, STKL: 3)
29
+ res = Lst1215.calculate(params)
30
+ assert_equal 3_388, res[:LSTLZZ] / 100
31
+ end
32
+
33
+ def test_general_tax_class_4
34
+ params = general_params.merge(RE4: 40_000 * 100, STKL: 4)
35
+ res = Lst1215.calculate(params)
36
+ assert_equal 6_499, res[:LSTLZZ] / 100
37
+ end
38
+
39
+ def test_general_tax_class_5
40
+ params = general_params.merge(RE4: 40_000 * 100, STKL: 5)
41
+ res = Lst1215.calculate(params)
42
+ assert_equal 10_656, res[:LSTLZZ] / 100
43
+ end
44
+
45
+ def test_general_tax_class_6
46
+ params = general_params.merge(RE4: 40_000 * 100, STKL: 6)
47
+ res = Lst1215.calculate(params)
48
+ assert_equal 11_091, res[:LSTLZZ] / 100
49
+ end
50
+
51
+ def test_special_tax_class_1
52
+ params = special_params.merge(RE4: 40_000 * 100, STKL: 1)
53
+ res = Lst1215.calculate(params)
54
+ assert_equal 7_877, res[:LSTLZZ] / 100
55
+ end
56
+
57
+ def test_special_tax_class_2
58
+ params = special_params.merge(RE4: 40_000 * 100, STKL: 2)
59
+ res = Lst1215.calculate(params)
60
+ assert_equal 7_222, res[:LSTLZZ] / 100
61
+ end
62
+
63
+ def test_special_tax_class_3
64
+ params = special_params.merge(RE4: 40_000 * 100, STKL: 3)
65
+ res = Lst1215.calculate(params)
66
+ assert_equal 4_154, res[:LSTLZZ] / 100
67
+ end
68
+
69
+ def test_special_tax_class_4
70
+ params = special_params.merge(RE4: 40_000 * 100, STKL: 4)
71
+ res = Lst1215.calculate(params)
72
+ assert_equal 7_877, res[:LSTLZZ] / 100
73
+ end
74
+
75
+ def test_special_tax_class_5
76
+ params = special_params.merge(RE4: 40_000 * 100, STKL: 5)
77
+ res = Lst1215.calculate(params)
78
+ assert_equal 12_367, res[:LSTLZZ] / 100
79
+ end
80
+
81
+ def test_special_tax_class_6
82
+ params = special_params.merge(RE4: 40_000 * 100, STKL: 6)
83
+ res = Lst1215.calculate(params)
84
+ assert_equal 12_802, res[:LSTLZZ] / 100
85
+ end
86
+
87
+ private
88
+
89
+ def general_params
90
+ { LZZ: 1, KVZ: 0.9, PKV: 0, PVZ: 1 }
91
+ end
92
+
93
+ def special_params
94
+ { LZZ: 1, KRV: 2, PKV: 1, PKPV: 0 }
95
+ end
96
+ end
@@ -0,0 +1,97 @@
1
+ require 'minitest/autorun'
2
+ require 'date'
3
+ require 'lohnsteuer/lst2016'
4
+
5
+ # Note: The test data was taken from page 37 and 38:
6
+ # https://www.bmf-steuerrechner.de/pruefdaten/pap2016.pdf
7
+ class Lst2016Test < MiniTest::Unit::TestCase
8
+ def test_applies_to_2016
9
+ assert_equal true, Lst2016.applies?(Date.new(2016, 2, 1))
10
+ end
11
+
12
+ def test_doesnt_apply_to_2015
13
+ assert_equal false, Lst2016.applies?(Date.new(2015, 12, 31))
14
+ end
15
+
16
+ def test_general_tax_class_1
17
+ params = general_params.merge(RE4: 40_000 * 100, STKL: 1)
18
+ res = Lst2016.calculate(params)
19
+ assert_equal 6_350, res[:LSTLZZ] / 100
20
+ end
21
+
22
+ def test_general_tax_class_2
23
+ params = general_params.merge(RE4: 40_000 * 100, STKL: 2, PVZ: 0)
24
+ res = Lst2016.calculate(params)
25
+ assert_equal 5_768, res[:LSTLZZ] / 100
26
+ end
27
+
28
+ def test_general_tax_class_3
29
+ params = general_params.merge(RE4: 40_000 * 100, STKL: 3)
30
+ res = Lst2016.calculate(params)
31
+ assert_equal 3_236, res[:LSTLZZ] / 100
32
+ end
33
+
34
+ def test_general_tax_class_4
35
+ params = general_params.merge(RE4: 40_000 * 100, STKL: 4)
36
+ res = Lst2016.calculate(params)
37
+ assert_equal 6_350, res[:LSTLZZ] / 100
38
+ end
39
+
40
+ def test_general_tax_class_5
41
+ params = general_params.merge(RE4: 40_000 * 100, STKL: 5)
42
+ res = Lst2016.calculate(params)
43
+ assert_equal 10_513, res[:LSTLZZ] / 100
44
+ end
45
+
46
+ def test_general_tax_class_6
47
+ params = general_params.merge(RE4: 40_000 * 100, STKL: 6)
48
+ res = Lst2016.calculate(params)
49
+ assert_equal 10_948, res[:LSTLZZ] / 100
50
+ end
51
+
52
+ def test_special_tax_class_1
53
+ params = special_params.merge(RE4: 40_000 * 100, STKL: 1)
54
+ res = Lst2016.calculate(params)
55
+ assert_equal 7_793, res[:LSTLZZ] / 100
56
+ end
57
+
58
+ def test_special_tax_class_2
59
+ params = special_params.merge(RE4: 40_000 * 100, STKL: 2)
60
+ res = Lst2016.calculate(params)
61
+ assert_equal 7_143, res[:LSTLZZ] / 100
62
+ end
63
+
64
+ def test_special_tax_class_3
65
+ params = special_params.merge(RE4: 40_000 * 100, STKL: 3)
66
+ res = Lst2016.calculate(params)
67
+ assert_equal 4_056, res[:LSTLZZ] / 100
68
+ end
69
+
70
+ def test_special_tax_class_4
71
+ params = special_params.merge(RE4: 40_000 * 100, STKL: 4)
72
+ res = Lst2016.calculate(params)
73
+ assert_equal 7_793, res[:LSTLZZ] / 100
74
+ end
75
+
76
+ def test_special_tax_class_5
77
+ params = special_params.merge(RE4: 40_000 * 100, STKL: 5)
78
+ res = Lst2016.calculate(params)
79
+ assert_equal 12_321, res[:LSTLZZ] / 100
80
+ end
81
+
82
+ def test_special_tax_class_6
83
+ params = special_params.merge(RE4: 40_000 * 100, STKL: 6)
84
+ res = Lst2016.calculate(params)
85
+ assert_equal 12_756, res[:LSTLZZ] / 100
86
+ end
87
+
88
+ private
89
+
90
+ def general_params
91
+ { LZZ: 1, KVZ: 1.10, PKV: 0, PVZ: 1 }
92
+ end
93
+
94
+ def special_params
95
+ { LZZ: 1, KRV: 2, PKV: 1, PKPV: 0 }
96
+ end
97
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lohnsteuer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jan Ahrens
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-12-11 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.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: ''
42
+ email:
43
+ - jan.ahrens+rubygems@googlemail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - ".ruby-version"
50
+ - Gemfile
51
+ - README.markdown
52
+ - Rakefile
53
+ - lib/lohnsteuer.rb
54
+ - lib/lohnsteuer/lst1215.rb
55
+ - lib/lohnsteuer/lst2016.rb
56
+ - lib/lohnsteuer/version.rb
57
+ - lohnsteuer.gemspec
58
+ - test/lohnsteuer_test.rb
59
+ - test/lst1215_test.rb
60
+ - test/lst2016_test.rb
61
+ homepage: https://github.com/JanAhrens/lohnsteuer-ruby
62
+ licenses:
63
+ - MIT
64
+ metadata: {}
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ requirements: []
80
+ rubyforge_project:
81
+ rubygems_version: 2.2.2
82
+ signing_key:
83
+ specification_version: 4
84
+ summary: German tax calculation algorithm
85
+ test_files:
86
+ - test/lohnsteuer_test.rb
87
+ - test/lst1215_test.rb
88
+ - test/lst2016_test.rb