lucasalary-jp 0.1.3 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 79df374d28e6787c5ddee481b510da82ba86ded7467f01792b46b265187cd4cb
4
- data.tar.gz: 9c7d6ce6d23d90f6e7f7926905170bf31faf33322887a9c052ca6895d523c3d3
3
+ metadata.gz: 2a28f8884c54b9a010cc55a2cf6baa7aca8ef7ce59a4ba86ce681f8ab028e80d
4
+ data.tar.gz: 37efc9c635bc18c230cad6ec2d66ec9d15a4c9cfee46b2e48ea115b0a2aff733
5
5
  SHA512:
6
- metadata.gz: 3ecd8d4e8201ed5065350af75317660d21dfdc4ae8c51aac82c4a8023c572c88cf3672a38a9b927c068a86953aca8862fe2510aeaf852cb0746dcfece47f799f
7
- data.tar.gz: 23317f9bf049e2f270cae00554c3da16b152bf83a216932c06cebb4ec22cb6643045d644766ca9d8423e7be3e022850d4492afda08bb3b62c9ef10260d0b18c0
6
+ metadata.gz: f30c300a93f1a13cb285f14354011263712e637ff1153abe543c16c435eaae4f93d6b83dc21969951da71c0805c0b1180e79de1ff8cbbcdd741279677bd3b5c0
7
+ data.tar.gz: c657f7974513bc0844d27dbb18b986401562b031e5ee5774b009679e8f16c60a39a59c1190ffd5fd8eb7709be9435dae8670cbc0409ab5e2ea2d90ae3fbdcb36
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'optparse'
5
+ require 'luca_salary/jp_payreport'
6
+
7
+ module LucaSalaryJpCmd
8
+ class Export
9
+ def self.payreport(args = nil, _params = nil)
10
+ puts LucaSalary::JpPayreport.export(args.first)
11
+ end
12
+ end
13
+ end
14
+
15
+ LucaRecord::Base.valid_project?
16
+ cmd = ARGV.shift
17
+ params = {}
18
+
19
+ case cmd
20
+ when /export/
21
+ OptionParser.new do |opt|
22
+ opt.banner = 'Usage: luca-salary-jp export year'
23
+ args = opt.parse(ARGV)
24
+ LucaSalaryJpCmd::Export.payreport(args)
25
+ end
26
+ else
27
+ puts 'Proper subcommand needed.'
28
+ puts
29
+ puts 'Usage: luca-salary-jp subcommand [options]'
30
+ puts ' export: puts CSV payment report for eLTAX'
31
+ exit 1
32
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LucaSalaryJp
4
- VERSION = '0.1.3'
4
+ VERSION = '0.1.5'
5
5
  end
@@ -21,7 +21,7 @@ class LucaSalary::Jp < LucaSalary::Base
21
21
  select_code(profile, '1').each { |k, v| h[k] = v }
22
22
  h['201'] = @insurance.health_insurance_salary(insurance_rank(profile))
23
23
  h['202'] = @insurance.pension_salary(pension_rank(profile))
24
- tax_base = sum_code(h, '1', income_tax_exception) - h['201'] - h['202']
24
+ tax_base = self.class.sum_code(h, '1', income_tax_exception) - h['201'] - h['202']
25
25
  h['203'] = JpNationalTax::IncomeTax.calc_kouran(tax_base, Date.today, true)
26
26
  h['211'] = resident_tax(profile)
27
27
  select_code(profile, '3').each { |k, v| h[k] = v }
@@ -35,16 +35,22 @@ class LucaSalary::Jp < LucaSalary::Base
35
35
  payment.tap do |p|
36
36
  p['911'] = JpNationalTax::IncomeTax.basic_deduction(p['1'], date)
37
37
  p['916'] = partner_deduction(p['1'])
38
- p['912'] = (p['201'] || 0) + (p['202'] || 0)
38
+ p['912'] = ['201', '202', '204', '205'].map{ |cd| p[cd] }.compact.sum
39
39
  p['901'] = JpNationalTax::IncomeTax.year_salary_taxable(p['1'], date)
40
40
  p['941'] = p['901'] - p['911'] - p['912'] - p['916']
41
41
  p['961'] = JpNationalTax::IncomeTax.year_tax(p['941'], date)
42
42
  diff = p['961'] - p['203']
43
43
  if diff.positive?
44
44
  p['3A1'] = diff
45
+ p['4A1'] = BigDecimal('0')
45
46
  else
46
47
  p['4A1'] = diff * -1
48
+ p['3A1'] = BigDecimal('0')
47
49
  end
50
+ p.delete '3'
51
+ p.delete '4'
52
+ p['3'] = sum_code(p, '3')
53
+ p['4'] = sum_code(p, '4')
48
54
  end
49
55
  end
50
56
 
@@ -0,0 +1,247 @@
1
+ require 'luca_salary'
2
+ require 'luca_support/config'
3
+ require 'csv'
4
+ require 'open3'
5
+
6
+ module LucaSalary
7
+ class JpPayreport < LucaSalary::Base
8
+
9
+ def self.export(year)
10
+ if !system("uconv --version > /dev/null")
11
+ exit 1 # 半角カナ必須
12
+ end
13
+
14
+ slips = LucaSalary::Total.new(year).slips
15
+ company = set_company(year.to_i)
16
+ CSV.generate do |csv|
17
+ slips.each do |s|
18
+ csv << 給与支払報告明細行(LucaSupport::Code.readable(s), company, year.to_i)
19
+ end
20
+ end
21
+ end
22
+
23
+ # TODO: extract effective field
24
+ def self.set_company(year)
25
+ {}.tap do |h|
26
+ h['name'] = CONFIG.dig('company', 'name')
27
+ h['address'] = CONFIG.dig('company', 'address')
28
+ h['address2'] = CONFIG.dig('company', 'address2')
29
+ h['tel'] = CONFIG.dig('company', 'tel')
30
+ h['tax_id'] = CONFIG.dig('company', 'tax_id')
31
+
32
+ raise "会社名、住所の設定は必須" if h['name'].nil? or h['address'].nil?
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def 給与支払報告明細行(slip, company, year)
41
+ [
42
+ 315, # 法定資料の種類
43
+ 提出義務者(company),
44
+ 0, # 提出区分(新規0, 追加1, 訂正2, 取消3)
45
+ 和暦(Date.new(year, 12, -1))[1], # 年分
46
+ 支払を受ける者(slip['profile']),
47
+ 支払(slip, year),
48
+ 支払を受ける者の詳細(slip['profile'], year),
49
+ company['tax_id'], # 法人番号
50
+ 支払を受ける者の扶養情報(slip['profile'], year),
51
+ slip['911'], # 基礎控除の額
52
+ nil, # 所得金額調整控除額 TODO: 未実装 措法41の3の3
53
+ nil, # ひとり親
54
+ 提出先判定(slip), # 必須:作成区分(国税のみ0, 地方のみ1, 両方2)
55
+ ].flatten
56
+ end
57
+
58
+ def 提出義務者(company)
59
+ [
60
+ nil, # 整理番号1
61
+ nil, # 本支店等区分番号
62
+ ['address', 'address2'].map { |attr| company[attr] }
63
+ .compact.join(' '), # 必須:住所又は所在地
64
+ company['name'], # 必須:氏名又は名称
65
+ company['tel'], # 電話番号
66
+ nil, # 整理番号2
67
+ nil, # 提出者の住所(省略する)
68
+ nil, # 提出者の氏名(省略する)
69
+ ]
70
+ end
71
+
72
+ def 支払を受ける者(profile)
73
+ [
74
+ ['address', 'address2'].map { |attr| profile[attr] }
75
+ .compact.join(' '), # 必須:住所又は居所
76
+ nil, # 国外住所表示(国内は"0"、国外は"1")
77
+ profile['name'], # 必須:氏名
78
+ nil, # 役職名
79
+ ]
80
+ end
81
+
82
+ def 支払(slip, year)
83
+ 配偶者控除等 = [slip['916'], slip['917']].compact.sum
84
+ [
85
+ '給料', # 種別
86
+ slip['1'], # 支払金額
87
+ nil, # 未払金額
88
+ slip['901'], # 給与所得控除後の給与等の金額
89
+ slip['901'] - slip['941'], # 所得控除の額の金額
90
+ slip['961'], # 源泉徴収税額
91
+ nil, # 未徴収税額
92
+ 配偶者控除等 > 0 ? 1 : 2, # 控除対象配偶者の有無 TODO: 従たる給与
93
+ 老人控除対象配偶者(slip.dig('profile', 'spouse'), year),
94
+ 配偶者控除等, # 配偶者控除の額
95
+ nil, # 控除対象扶養親族の数 特定 主
96
+ nil, # 控除対象扶養親族の数 特定 従
97
+ nil, # 控除対象扶養親族の数 老人 主
98
+ nil, # 控除対象扶養親族の数 老人 上の内訳
99
+ nil, # 控除対象扶養親族の数 老人 従
100
+ nil, # 控除対象扶養親族の数 その他 主
101
+ nil, # 控除対象扶養親族の数 その他 従
102
+ nil, # 障害者の数 特別障害者
103
+ nil, # 障害者の数 上の内訳 NOTE: 同居・同一生計
104
+ nil, # 障害者の数 その他
105
+ slip['912'], # 社会保険料等の額
106
+ nil, # 上の内訳 NOTE: 小規模企業共済等掛金
107
+ ]
108
+ end
109
+
110
+ def 支払を受ける者の詳細(profile, year)
111
+ birth = if profile['birth_date'].is_a?(String)
112
+ Date.parse(profile['birth_date'])
113
+ else
114
+ profile['birth_date']
115
+ end
116
+ 生年月日 = 和暦(birth)
117
+ 扶養対象 = 扶養親族分類(profile['family'], year)
118
+
119
+ [
120
+ nil, # 生命保険料の控除額
121
+ nil, # 地震保険料の控除額
122
+ nil, # 住宅借入金等特別控除等の額
123
+ nil, # 旧個人年金保険料の額
124
+ nil, # 配偶者の合計所得
125
+ nil, # 旧長期損害保険料の額
126
+ 生年月日[0], # 必須:受給者の生年月日 元号
127
+ 生年月日[1], # 必須:受給者の生年月日 年
128
+ 生年月日[2], # 必須:受給者の生年月日 月
129
+ 生年月日[3], # 必須:受給者の生年月日 日
130
+ nil, # 夫あり(省略する)
131
+ birth.next_year(18) < Date.new(year, 12, -1) ? 0 : 1, # 未成年者
132
+ nil, # 乙欄適用
133
+ nil, # 本人が特別障害者
134
+ nil, # 本人がその他障害者
135
+ nil, # 老年者(省略する)
136
+ nil, # 寡婦
137
+ nil, # 寡夫(省略する)
138
+ Array.new(35), # col90まで未実装
139
+ 扶養対象['16才未満'].length,
140
+ nil, # 国民年金保険料等の額
141
+ nil, # 非居住者である親族の数
142
+ ]
143
+ end
144
+
145
+ def 支払を受ける者の扶養情報(profile, year)
146
+ 扶養対象 = 扶養親族分類(profile['family'], year)
147
+
148
+ [
149
+ profile['tax_id'], # 個人番号
150
+ profile.dig('spouse', 'katakana'), # 控除対象配偶者カナ
151
+ profile.dig('spouse', 'name'), # 控除対象配偶者 氏名
152
+ profile.dig('spouse') ? 00 : nil, # 控除対象配偶者 区分 TODO: 非居住者(01)の設定
153
+ profile.dig('spouse', 'tax_id'), # 控除対象配偶者 個人番号
154
+ [0, 1, 2, 3].map { |i|
155
+ [
156
+ 扶養対象.dig('16才以上', i, 'katakana'), # カナ
157
+ 扶養対象.dig('16才以上', i, 'name'), # 氏名
158
+ 扶養対象.dig('16才以上', i) ? '00' : nil, # 区分 TODO: 非居住者(01)の設定
159
+ 扶養対象.dig('16才以上', i, 'tax_id'), # 個人番号
160
+ ]
161
+ },
162
+ [0, 1, 2, 3].map { |i|
163
+ [
164
+ 扶養対象.dig('16才未満', i, 'katakana'), # カナ
165
+ 扶養対象.dig('16才未満', i, 'name'), # 氏名
166
+ 扶養対象.dig('16才未満', i) ? '00' : nil, # 区分 TODO: 非居住者(01)の設定
167
+ 扶養対象.dig('16才未満', i, 'tax_id'), # 個人番号
168
+ ]
169
+ },
170
+ Array(扶養対象.dig('16才以上'))[4..]&.map{ |p| "(#{p['tax_id']})#{p['name']}" }&.join(' '), # 5人目以降
171
+ Array(扶養対象.dig('16才未満'))[4..]&.map{ |p| "(#{p['tax_id']})#{p['name']}" }&.join(' '), # 5人目以降
172
+ nil, # 普通徴収
173
+ nil, # 青色専従者
174
+ nil, # 条約免除
175
+ 半角変換(profile['katakana']), # 必須:支払を受ける者のフリガナ(半角)
176
+ nil, # 需給者番号
177
+ profile.dig('resident', 'area_code'), # 必須:提出先市町村コード
178
+ profile.dig('resident', 'tax_id'), # 指定番号
179
+ ]
180
+ end
181
+
182
+ # https://www.nta.go.jp/taxes/shiraberu/taxanswer/hotei/7411.htm
183
+ # TODO: 役員・弁護士の考慮
184
+ def 提出先判定(slip)
185
+ case slip['1']
186
+ when 0 .. 5_000_000
187
+ 1
188
+ else
189
+ 2
190
+ end
191
+ end
192
+
193
+ def 老人控除対象配偶者(spouse, year)
194
+ return nil if spouse.nil?
195
+ date = spouse['birth_date']
196
+ return 0 if date.nil?
197
+
198
+ date = Date.parse(date) if date.is_a?(String)
199
+ date.next_year(70) < Date.new(year, 12, -1) ? 1 : 0
200
+ end
201
+
202
+ def 扶養親族分類(family, year)
203
+ return {} if family.nil?
204
+
205
+ { '16才以上' => [], '16才未満' => [] }.tap do |result|
206
+ family.each do |p|
207
+ if !p['birth_date']
208
+ result['16才以上'] << p
209
+ else
210
+ date = p['birth_date']
211
+ date = Date.parse(date) if date.is_a?(String)
212
+ if date.next_year(16) < Date.new(year, 12, -1)
213
+ result['16才以上'] << p
214
+ else
215
+ result['16才未満'] << p
216
+ end
217
+ end
218
+ end
219
+ end
220
+ end
221
+
222
+ def 和暦(date)
223
+ return [nil, nil, nil, nil] if date.nil?
224
+
225
+ date = Date.parse(date) if date.is_a?(String)
226
+ case date
227
+ when Date.new(0, 1, 1) .. Date.new(1868, 10, 22)
228
+ raise "Not supported before 明治"
229
+ when Date.new(1868, 10, 23) .. Date.new(1912, 7, 29)
230
+ [3, format("%02d", date.year - 1867), format("%02d", date.month), format("%02d", date.day)]
231
+ when Date.new(1912, 7, 30) .. Date.new(1926, 12, 24)
232
+ [2, format("%02d", date.year - 1911), format("%02d", date.month), format("%02d", date.day)]
233
+ when Date.new(1926, 12, 25) .. Date.new(1989, 1, 7)
234
+ [1, format("%02d", date.year - 1925), format("%02d", date.month), format("%02d", date.day)]
235
+ when Date.new(1989, 1, 8) .. Date.new(2019, 4, 30)
236
+ [4, format("%02d", date.year - 1988), format("%02d", date.month), format("%02d", date.day)]
237
+ else
238
+ [5, format("%02d", date.year - 2018), format("%02d", date.month), format("%02d", date.day)]
239
+ end
240
+ end
241
+
242
+ def 半角変換(str)
243
+ return nil if str.nil? or str.empty?
244
+
245
+ result, _e, _s = Open3.capture3("uconv -x 'Fullwidth-Halfwidth'", stdin_data: str)
246
+ result
247
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lucasalary-jp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chuma Takahiro
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2021-01-13 00:00:00.000000000 Z
11
+ date: 2023-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lucasalary
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.1.14
19
+ version: 0.1.26
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.1.14
26
+ version: 0.1.26
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.17'
33
+ version: '2.3'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.17'
40
+ version: '2.3'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -68,14 +68,16 @@ dependencies:
68
68
  version: '5.0'
69
69
  description: 'LucaSalary calculation module for Japan
70
70
 
71
- '
71
+ '
72
72
  email:
73
73
  - co.chuma@gmail.com
74
- executables: []
74
+ executables:
75
+ - luca-salary-jp
75
76
  extensions: []
76
77
  extra_rdoc_files: []
77
78
  files:
78
79
  - LICENSE
80
+ - exe/luca-salary-jp
79
81
  - lib/luca_salary/dict/code.tsv
80
82
  - lib/luca_salary/jp-national-tax/.git
81
83
  - lib/luca_salary/jp-national-tax/.gitignore
@@ -85,13 +87,14 @@ files:
85
87
  - lib/luca_salary/jp.rb
86
88
  - lib/luca_salary/jp/insurance.rb
87
89
  - lib/luca_salary/jp/version.rb
88
- homepage: https://github.com/chumaltd/luca-salary-jp
90
+ - lib/luca_salary/jp_payreport.rb
91
+ homepage: https://github.com/chumaltd/luca-jp
89
92
  licenses:
90
93
  - GPL
91
94
  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
+ homepage_uri: https://github.com/chumaltd/luca-jp
96
+ source_code_uri: https://github.com/chumaltd/luca-jp
97
+ changelog_uri: https://github.com/chumaltd/luca-jp/CHANGELOG.md
95
98
  post_install_message:
96
99
  rdoc_options: []
97
100
  require_paths:
@@ -100,15 +103,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
100
103
  requirements:
101
104
  - - ">="
102
105
  - !ruby/object:Gem::Version
103
- version: 2.6.0
106
+ version: 3.0.0
104
107
  required_rubygems_version: !ruby/object:Gem::Requirement
105
108
  requirements:
106
109
  - - ">="
107
110
  - !ruby/object:Gem::Version
108
111
  version: '0'
109
112
  requirements: []
110
- rubygems_version: 3.2.3
113
+ rubygems_version: 3.4.1
111
114
  signing_key:
112
115
  specification_version: 4
113
- summary: LucaSalary calculation molule for Japan
116
+ summary: 'DEPRECATION: This gem is merged to luca-jp@0.14'
114
117
  test_files: []