lucasalary-jp 0.1.1

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,106 @@
1
+ require "date"
2
+ require "bigdecimal"
3
+
4
+ module JP
5
+ module IncomeTax
6
+ module Kouran2020
7
+
8
+ module_function
9
+
10
+ def effective_date
11
+ Date.parse("2020-01-01")
12
+ end
13
+
14
+ #
15
+ # 月額表の甲欄を適用する給与等につき、電子計算機等を使用して源泉徴収税額を計算する方法
16
+ #
17
+ def monthly_kouran (その月の社会保険料等控除後の給与等の金額, 配偶者 = false, 控除対象扶養親族の数 = 0)
18
+
19
+ b = その月の社会保険料等控除後の給与等の金額
20
+
21
+ 配偶者控除の額及び扶養控除の額 = 扶養控除の額 (控除対象扶養親族の数)
22
+ 配偶者控除の額及び扶養控除の額 += 配偶者控除の額 if 配偶者
23
+
24
+ 課税給与所得金額 = b - 配偶者控除の額及び扶養控除の額 - 給与所得控除の額(b) - 基礎控除の額(b)
25
+
26
+ 源泉徴収額 = 税額(課税給与所得金額).to_i
27
+
28
+ if 源泉徴収額 > 0
29
+ 源泉徴収額
30
+ else
31
+ 0
32
+ end
33
+
34
+ end
35
+
36
+
37
+ def 給与所得控除の額 (その月の社会保険料控除後の給与等の金額)
38
+
39
+ case その月の社会保険料控除後の給与等の金額
40
+ when 0 .. 135_416
41
+ 45_834
42
+ when 135_417 .. 149_999
43
+ (その月の社会保険料控除後の給与等の金額 * BigDecimal("0.4")).ceil - 8_333
44
+ when 150_000 .. 299_999
45
+ (その月の社会保険料控除後の給与等の金額 * BigDecimal("0.3")).ceil + 6_667
46
+ when 300_000 .. 549_999
47
+ (その月の社会保険料控除後の給与等の金額 * BigDecimal("0.2")).ceil + 36_667
48
+ when 550_000 .. 708_330
49
+ (その月の社会保険料控除後の給与等の金額 * BigDecimal("0.1")).ceil + 91_667
50
+ else
51
+ 162_500
52
+ end
53
+
54
+ end
55
+
56
+
57
+ def 配偶者控除の額
58
+ 31_667
59
+ end
60
+
61
+
62
+ def 扶養控除の額 (控除対象扶養親族の数)
63
+ 31_667 * 控除対象扶養親族の数
64
+ end
65
+
66
+
67
+ def 基礎控除の額 (その月の社会保険料等控除後の給与等の金額)
68
+
69
+ case その月の社会保険料等控除後の給与等の金額
70
+ when 0 .. 2_162_499
71
+ 40_000
72
+ when 2_162_500 .. 2_204_166
73
+ 26_667
74
+ when 2_204_167 .. 2_245_833
75
+ 13_334
76
+ else
77
+ 0
78
+ end
79
+
80
+ end
81
+
82
+
83
+ def 税額 (その月の課税給与所得金額)
84
+
85
+ case その月の課税給与所得金額
86
+ when 0 .. 162_500
87
+ (その月の課税給与所得金額 * BigDecimal("0.05105")).round(0, BigDecimal::ROUND_HALF_UP)
88
+ when 162_501 .. 275_000
89
+ (その月の課税給与所得金額 * BigDecimal("0.10210")).round(0, BigDecimal::ROUND_HALF_UP) - 8_296
90
+ when 275_001 .. 579_166
91
+ (その月の課税給与所得金額 * BigDecimal("0.20420")).round(0, BigDecimal::ROUND_HALF_UP) - 36_374
92
+ when 579_001 .. 750_000
93
+ (その月の課税給与所得金額 * BigDecimal("0.23483")).round(0, BigDecimal::ROUND_HALF_UP) - 54_113
94
+ when 750_001 .. 1_500_000
95
+ (その月の課税給与所得金額 * BigDecimal("0.33693")).round(0, BigDecimal::ROUND_HALF_UP) - 130_688
96
+ when 1_500_001 .. 3_333_333
97
+ (その月の課税給与所得金額 * BigDecimal("0.40840")).round(0, BigDecimal::ROUND_HALF_UP) - 237_893
98
+ else
99
+ (その月の課税給与所得金額 * BigDecimal("0.45945")).round(0, BigDecimal::ROUND_HALF_UP) - 408_061
100
+ end
101
+
102
+ end
103
+
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,33 @@
1
+ require "date"
2
+ Dir[File.expand_path("income-tax/income*.rb", __dir__)].each{|f| require_relative(f)}
3
+
4
+ module JP
5
+ module IncomeTax
6
+ MOD = [Kouran2020]
7
+
8
+ module_function
9
+
10
+ def calc_kouran(pay_amount, pay_date, partner = false, dependent = 0)
11
+ responsible_module(pay_date)
12
+ .send(:monthly_kouran, pay_amount, partner, dependent)
13
+ .to_i
14
+ end
15
+
16
+ def responsible_module(date = nil)
17
+ if date.nil?
18
+ raise UndefinedDateError
19
+ elsif date.class.name == "String"
20
+ date = Date.parse(date)
21
+ end
22
+
23
+ rules = MOD.map{|mod| [mod.send(:effective_date), mod] }.filter{|a| date >= a[0]}
24
+
25
+ if rules.length > 0
26
+ rules.sort_by{|a| a[0]}.reverse!.first[1]
27
+ else
28
+ raise NoValidModuleError
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,50 @@
1
+ require 'luca_salary/jp/version'
2
+ require 'date'
3
+ require 'luca_salary'
4
+ require 'luca_salary/jp/insurance'
5
+ require 'jp_national_tax'
6
+
7
+ class LucaSalary::JP < LucaSalary::Base
8
+ def initialize(dir_path, config = nil, date = nil)
9
+ @pjdir = dir_path
10
+ @date = date
11
+ @insurance = InsuranceJP.new(@pjdir, config.dig('jp', 'area'), date)
12
+ end
13
+
14
+ # need for local dictionary loading
15
+ def self.country_path
16
+ __dir__
17
+ end
18
+
19
+ def calc_payment(profile)
20
+ {}.tap do |h|
21
+ select_code(profile, '1').each { |k, v| h[k] = v }
22
+ h['201'] = @insurance.health_insurance_salary(insurance_rank(profile))
23
+ h['202'] = @insurance.pension_salary(pension_rank(profile))
24
+ tax_base = sum_code(h, '1', income_tax_exception) - h['201'] - h['202']
25
+ h['203'] = JpNationalTax::IncomeTax.calc_kouran(tax_base, Date.today, true)
26
+ h['211'] = resident_tax(profile)
27
+ select_code(profile, '3').each { |k, v| h[k] = v }
28
+ select_code(profile, '4').each { |k, v| h[k] = v }
29
+ h.merge!(amount_by_code(h))
30
+ h['id'] = profile.dig('id')
31
+ end
32
+ end
33
+
34
+ def income_tax_exception
35
+ %w[116 118 119 11A 11B]
36
+ end
37
+
38
+ def insurance_rank(dat)
39
+ dat.dig('insurance', 'rank')
40
+ end
41
+
42
+ def pension_rank(dat)
43
+ dat.dig('pension', 'rank')
44
+ end
45
+
46
+ def resident_tax(dat)
47
+ attr = @date.month == 6 ? 'extra' : 'ordinal'
48
+ dat.dig('resident', attr)
49
+ end
50
+ end
@@ -0,0 +1,66 @@
1
+ require 'bigdecimal'
2
+ require 'date'
3
+ require 'json'
4
+ require 'pathname'
5
+
6
+ class InsuranceJP
7
+ attr_reader :table
8
+
9
+ # load config
10
+ def initialize(dir_path, area=nil, date=nil)
11
+ @pjdir = Pathname(dir_path) + 'dict'
12
+ @area = area
13
+ @date = date
14
+ @table = load_table
15
+ end
16
+
17
+ def load_table
18
+ file_name = @pjdir + select_active_filename
19
+ JSON.parse(File.read(file_name.to_s))
20
+ end
21
+
22
+ def health_insurance_salary(rank)
23
+ round6(select_health_insurance(rank).dig('insurance_elder_salary'))
24
+ end
25
+
26
+ def pension_salary(rank)
27
+ round6(select_pension(rank).dig('pension_salary'))
28
+ end
29
+
30
+ def select_health_insurance(rank)
31
+ @table['fee'].filter{|h| h['rank'] == rank}.first
32
+ end
33
+
34
+ def select_pension(rank)
35
+ @table['fee'].filter{|h| h['pension_rank'] == rank}.first
36
+ end
37
+
38
+ private
39
+
40
+ def round6(num)
41
+ BigDecimal(num).round(0, BigDecimal::ROUND_HALF_DOWN).to_i
42
+ end
43
+
44
+ # TODO: need selection logic
45
+ def select_active_filename
46
+ list = load_json
47
+ list.first[1]
48
+ end
49
+
50
+ def load_json
51
+ table_list = [].tap do |a|
52
+ open_tables do |f, name|
53
+ data = JSON.parse(f.read)
54
+ a << [Date.parse(data['effective_date']), name]
55
+ end
56
+ end
57
+ end
58
+
59
+ def open_tables
60
+ Dir.chdir(@pjdir.to_s) do
61
+ Dir.glob("*.json").each do |file_name|
62
+ File.open(file_name, 'r') {|f| yield(f, file_name)}
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,3 @@
1
+ module LucaSalaryJp
2
+ VERSION = '0.1.1'
3
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lucasalary-jp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Chuma Takahiro
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-10-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: lucasalary
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.17'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.17'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 12.3.3
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 12.3.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
69
+ description: 'LucaSalary calculation module for Japan
70
+
71
+ '
72
+ email:
73
+ - co.chuma@gmail.com
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - LICENSE
79
+ - lib/luca_salary/dict/code.tsv
80
+ - lib/luca_salary/jp-national-tax/.git
81
+ - lib/luca_salary/jp-national-tax/.gitignore
82
+ - lib/luca_salary/jp-national-tax/LICENSE
83
+ - lib/luca_salary/jp-national-tax/income-tax/income_kouran_2020.rb
84
+ - lib/luca_salary/jp-national-tax/income_tax.rb
85
+ - lib/luca_salary/jp.rb
86
+ - lib/luca_salary/jp/insurance.rb
87
+ - lib/luca_salary/jp/version.rb
88
+ homepage: https://github.com/chumaltd/luca-salary-jp
89
+ licenses:
90
+ - GPL
91
+ metadata:
92
+ homepage_uri: https://github.com/chumaltd/luca-salary-jp
93
+ source_code_uri: https://github.com/chumaltd/luca-salary-jp
94
+ changelog_uri: https://github.com/chumaltd/luca-salary-jp/CHANGELOG.md
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 2.6.0
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubygems_version: 3.1.2
111
+ signing_key:
112
+ specification_version: 4
113
+ summary: LucaSalary calculation molule for Japan
114
+ test_files: []