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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/README.markdown +32 -0
- data/Rakefile +6 -0
- data/lib/lohnsteuer.rb +62 -0
- data/lib/lohnsteuer/lst1215.rb +710 -0
- data/lib/lohnsteuer/lst2016.rb +589 -0
- data/lib/lohnsteuer/version.rb +3 -0
- data/lohnsteuer.gemspec +23 -0
- data/test/lohnsteuer_test.rb +71 -0
- data/test/lst1215_test.rb +96 -0
- data/test/lst2016_test.rb +97 -0
- metadata +88 -0
data/lohnsteuer.gemspec
ADDED
@@ -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
|