lohnsteuer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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