lucasalary 0.1.25 → 0.1.28

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: 3de293feb769006a2764979fdc52357699cc79c116fcde6b6c871b473e650035
4
- data.tar.gz: 63f14cd43cc3a7aec7c31c6a59bafa67c03b998c8a23b882becb5d76e308fbbe
3
+ metadata.gz: 13c3b82fd0dbc0628ded542e7e41034b61c72b70d2b95c6db395e802a5d1a868
4
+ data.tar.gz: 2c9867511fc9db6f1f1855bac932eed3ea52b89f5a64646200348b05139f01a8
5
5
  SHA512:
6
- metadata.gz: 99ed7707f597948379ec7059926c67bd101f5fb182c33c3cf347574ed9dc44daa9af1519768c89f88723c579b5339d7fb57d78bb05976f8e46ba4eb2d6db0e1f
7
- data.tar.gz: 88ac6c04ab1956d26f976e31e5fbb9474d49163fbabbe3bd9259defd472190898280d8f3b76a6ddd32ca8420ba41d289d2c379abd2f7ddc1c5f1072326f9a982
6
+ metadata.gz: 0ff1f112099e366cb6b6950a37eaed47d632d338cd3c497fd293b4a8ca2bba50c734032208ef4e7f43c963a990b63d890dc9cc34fc458ae5efc414db6146088b
7
+ data.tar.gz: 73b50ab1845ed285aaf131056de8c05a0d3e6f4c0ca293b542675418fda8ec3a904216ff116ad920cbca6b77e9b7503d891692a31d7cf368973dfac924cf2b1a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## LucaSalary 0.1.28
2
+
3
+ * BREAKING: `luca-salary payments total` directory structure changed. Upsert 1 record per 1 profile.
4
+ * move yearly totale methods to LucaSalary::Total
5
+ * add `luca-salary pay[ments]` short hand.
6
+ * add `luca-salary payments list --nu`.
7
+
8
+ ## LucaSalary 0.1.27
9
+
10
+ * Implement LucaSalary::Total for Year totaling.
11
+
12
+ ## LucaSalary 0.1.26
13
+
14
+ * Add `luca-salary payments report`: monthly statement by code.
15
+
1
16
  ## LucaSalary 0.1.25
2
17
 
3
18
  * Add `luca-salary payments total --adjust`: applying yearly tax refund.
data/exe/luca-salary CHANGED
@@ -1,9 +1,11 @@
1
1
  #!/usr/bin/ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'json'
4
5
  require 'optparse'
5
6
  require 'luca_salary'
6
7
  require 'luca_salary/monthly'
8
+ require 'luca_support' #TODO: test use only
7
9
 
8
10
  module LucaCmd
9
11
  class Profile
@@ -34,17 +36,32 @@ module LucaCmd
34
36
  def self.list(args = nil, params = nil)
35
37
  if args
36
38
  args << 28 if args.length == 2 # specify safe last day
37
- LucaSalary::Monthly.new(args.join('-')).report(params.dig('mode'))
39
+ render(LucaSalary::Monthly.new(args.join('-')).report(params.dig('mode')), params)
38
40
  else
39
- LucaSalary::Monthly.new.report(params.dig('mode'))
41
+ render(LucaSalary::Monthly.new.report(params.dig('mode')), params)
40
42
  end
41
43
  end
42
44
 
45
+ def self.report(args = nil, params = nil)
46
+ render(LucaSalary::State.range(*args).report(), params)
47
+ end
48
+
43
49
  def self.total(args = nil, params = nil)
44
50
  if params['mode'] == 'adjust'
45
- LucaSalary::Payment.year_adjust(args[0].to_i, args[1].to_i)
51
+ LucaSalary::Total.year_adjust(args[0].to_i, args[1].to_i)
52
+ else
53
+ LucaSalary::Total.accumulator(args.first.to_i)
54
+ end
55
+ end
56
+
57
+ def self.render(dat, params)
58
+ case params[:output]
59
+ when 'json'
60
+ puts JSON.dump(dat)
61
+ when 'nu'
62
+ LucaSupport::View.nushell(dat)
46
63
  else
47
- LucaSalary::Payment.year_total(args.first.to_i)
64
+ puts YAML.dump(dat)
48
65
  end
49
66
  end
50
67
  end
@@ -70,9 +87,23 @@ when /profiles?/
70
87
  puts 'Usage: luca-salary profile[s] create Name'
71
88
  exit 1
72
89
  end
90
+ when 'enc', 'encrypt'
91
+ # TODO: proxy encrypt/decrypt
92
+ OptionParser.new do |opt|
93
+ opt.banner = 'Usage: luca-salary enc|encrypt'
94
+ opt.on('--clean', 'remove plain directory') { |_v| params[:clean] = true }
95
+ args = opt.parse(ARGV)
96
+ LucaSupport::Enc.encrypt("s_profiles", cleanup: params[:clean])
97
+ end
98
+ when 'dec', 'decrypt'
99
+ OptionParser.new do |opt|
100
+ opt.banner = 'Usage: luca-salary dec|decrypt'
101
+ args = opt.parse(ARGV)
102
+ LucaSupport::Enc.decrypt("s_profiles")
103
+ end
73
104
  when 'export'
74
105
  LucaCmd::Payment.export(ARGV)
75
- when /payments?/
106
+ when 'pay', /payments?/
76
107
  subcmd = ARGV.shift
77
108
  case subcmd
78
109
  when 'create'
@@ -83,11 +114,19 @@ when /payments?/
83
114
  end
84
115
  when 'list'
85
116
  OptionParser.new do |opt|
86
- opt.banner = 'Usage: luca-salary payments list [--mail] year month [date]'
117
+ opt.banner = 'Usage: luca-salary payments list [--mail|--nu] year month [date]'
87
118
  opt.on('--mail', 'send to managers') { |_v| params['mode'] = 'mail' }
119
+ opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
88
120
  args = opt.parse(ARGV)
89
121
  LucaCmd::Payment.list(args, params)
90
122
  end
123
+ when 'report'
124
+ OptionParser.new do |opt|
125
+ opt.banner = 'Usage: luca-salary payments report [--nu] year month [year month]'
126
+ opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
127
+ args = opt.parse(ARGV)
128
+ LucaCmd::Payment.report(args, params)
129
+ end
91
130
  when 'total'
92
131
  OptionParser.new do |opt|
93
132
  opt.banner = 'Usage: luca-salary payments total [--adjust] year [month]'
@@ -108,5 +147,7 @@ else
108
147
  puts ' profiles'
109
148
  puts ' payments'
110
149
  puts ' export: puts payment data for LucaBook import'
150
+ puts ' encrypt: encrypt secure profiles'
151
+ puts ' decrypt: decrypt secure profiles'
111
152
  exit 1
112
153
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LucaSalary
4
+ module Accumulator
5
+ def self.included(klass) #:nodoc:
6
+ klass.extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def accumulate(records)
11
+ count = 0
12
+ result = records.each_with_object({}) do |record, result|
13
+ count += 1
14
+ record
15
+ .select { |k, _v| /^[1-4][0-9A-Fa-f]{,3}$/.match(k) }
16
+ .each do |k, v|
17
+ next if v.nil?
18
+
19
+ result[k] = result[k] ? result[k] + v : v
20
+ end
21
+ end
22
+ [result, count]
23
+ end
24
+ end
25
+ end
26
+ end
@@ -48,7 +48,7 @@ module LucaSalary
48
48
  mail.text_part = YAML.dump(LucaSupport::Code.readable(data))
49
49
  LucaSupport::Mail.new(mail, @pjdir).deliver
50
50
  else
51
- puts YAML.dump(LucaSupport::Code.readable(data))
51
+ LucaSupport::Code.readable(data)
52
52
  end
53
53
  end
54
54
 
@@ -9,6 +9,8 @@ require 'luca_record'
9
9
 
10
10
  module LucaSalary
11
11
  class Payment < LucaRecord::Base
12
+ include Accumulator
13
+
12
14
  @dirname = 'payments'
13
15
 
14
16
  def initialize(date = nil)
@@ -44,64 +46,6 @@ module LucaSalary
44
46
  end
45
47
  end
46
48
 
47
- def self.year_total(year)
48
- Profile.all do |profile|
49
- id = profile.dig('id')
50
- payment = { 'profile_id' => id }
51
- # payment = {}
52
- (1..12).each do |month|
53
- search(year, month, nil, id).each do |origin|
54
- # TODO: to be updated null check
55
- if origin == {}
56
- month
57
- else
58
- origin.select { |k, _v| /^[1-4][0-9A-Fa-f]{,3}$/.match(k) }.each do |k, v|
59
- payment[k] = payment[k] ? payment[k] + v : v
60
- end
61
- nil
62
- end
63
- end
64
- end
65
- date = Date.new(year, 12, 31)
66
- payment = local_convert(payment, date)
67
- create(payment, date: date, codes: [id], basedir: 'payments/total')
68
- end
69
- end
70
-
71
- def self.local_convert(payment, date)
72
- return payment if CONFIG['country'].nil?
73
-
74
- require "luca_salary/#{CONFIG['country'].downcase}"
75
- klass = Kernel.const_get("LucaSalary::#{CONFIG['country'].capitalize}")
76
- klass.year_total(payment, date)
77
- rescue NameError
78
- return payment
79
- end
80
-
81
- # Apply adjustment for yearly refund.
82
- # Search Year Total records 6 months before specified payslip month.
83
- #
84
- def self.year_adjust(year, month)
85
- target_month = Date.new(year, month, 1)
86
- total_st = target_month.prev_month(6)
87
- search(year, month).each do |slip, path|
88
- term(total_st.year, total_st.month, year, month, slip['profile_id'], "#{@dirname}/total/") do |total|
89
- slip['3A1'] = total['3A1']
90
- slip['4A1'] = total['4A1']
91
- end
92
- # Recalculate sum
93
- ['3', '4'].each do |key|
94
- slip[key] = 0
95
- slip[key] = LucaSalary::Base.sum_code(slip, key)
96
- slip['5'] = slip['1'] - slip['2'] - slip['3'] + slip['4']
97
- end
98
- IO.write(
99
- abs_path(@dirname) / path[0] / "#{path[1]}-#{path[2]}",
100
- YAML.dump(LucaSupport::Code.readable(slip.sort.to_h))
101
- )
102
- end
103
- end
104
-
105
49
  # Export json for LucaBook.
106
50
  # Accrual_date can be change with `payment_term` on config.yml. Default value is 0.
107
51
  # `payment_term: 1` means payment on the next month of calculation target.
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'luca_support'
4
+ require 'luca_record'
5
+
6
+ module LucaSalary
7
+ class State < LucaRecord::Base
8
+ include Accumulator
9
+
10
+ @dirname = 'payments'
11
+
12
+ def initialize(data, count = nil, start_d: nil, end_d: nil)
13
+ @monthly = data
14
+ @count = count
15
+ @start_date = start_d
16
+ @end_date = end_d
17
+ @dict = LucaRecord::Dict.load_tsv_dict(Pathname(LucaSupport::PJDIR) / 'dict' / 'code.tsv')
18
+ end
19
+
20
+ def self.range(from_year, from_month, to_year = from_year, to_month = from_month)
21
+ date = Date.new(from_year.to_i, from_month.to_i, -1)
22
+ last_date = Date.new(to_year.to_i, to_month.to_i, -1)
23
+ raise 'invalid term specified' if date > last_date
24
+
25
+ counts = []
26
+ reports = [].tap do |r|
27
+ while date <= last_date do
28
+ slips = term(date.year, date.month, date.year, date.month)
29
+ record, count = accumulate(slips)
30
+ r << record.tap { |c| c['_d'] = date.to_s }
31
+ counts << count
32
+ date = Date.new(date.next_month.year, date.next_month.month, -1)
33
+ end
34
+ end
35
+ new(reports, counts,
36
+ start_d: Date.new(from_year.to_i, from_month.to_i, 1),
37
+ end_d: Date.new(to_year.to_i, to_month.to_i, -1)
38
+ )
39
+ end
40
+
41
+ def report()
42
+ total, _count = LucaSalary::State.accumulate(@monthly)
43
+ total['_d'] = 'total'
44
+ [@monthly, total].flatten.map do |m|
45
+ {}.tap do |r|
46
+ m.sort.to_h.each do |k, v|
47
+ r["#{@dict.dig(k, :label) || k}"] = readable(v)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'luca_support'
4
+ require 'luca_record'
5
+
6
+ module LucaSalary
7
+ # == Total
8
+ # Yearly summary records are stored in 'payments/total' by each profile.
9
+ #
10
+ class Total < LucaRecord::Base
11
+ include Accumulator
12
+ @dirname = 'payments/total'
13
+
14
+ attr_reader :slips
15
+
16
+ def initialize(year)
17
+ @date = Date.new(year.to_i, 12, -1)
18
+ @slips = Total.search(year, 12).map do |slip|
19
+ slip['profile'] = parse_current(Profile.find_secure(slip['id']))
20
+ slip
21
+ end
22
+ @dict = LucaRecord::Dict.load_tsv_dict(Pathname(LucaSupport::PJDIR) / 'dict' / 'code.tsv')
23
+ end
24
+
25
+ def self.accumulator(year)
26
+ Profile.all do |profile|
27
+ id = profile.dig('id')
28
+ slips = term(year, 1, year, 12, id, 'payments')
29
+ payment, _count = accumulate(slips)
30
+ payment['id'] = id
31
+ date = Date.new(year, 12, 31)
32
+ payment = local_convert(payment, date)
33
+ upsert(payment, basedir: "payments/total/#{year}#{LucaSupport::Code.encode_month(12)}")
34
+ end
35
+ end
36
+
37
+ def self.local_convert(payment, date)
38
+ return payment if CONFIG['country'].nil?
39
+
40
+ require "luca_salary/#{CONFIG['country'].downcase}"
41
+ klass = Kernel.const_get("LucaSalary::#{CONFIG['country'].capitalize}")
42
+ klass.year_total(payment, date)
43
+ rescue NameError
44
+ return payment
45
+ end
46
+
47
+ # Apply adjustment for yearly refund.
48
+ # Search Year Total records 6 months before specified payslip month.
49
+ #
50
+ def self.year_adjust(year, month)
51
+ total_dirs = Array(0..6)
52
+ .map{ |i| LucaSupport::Code.encode_dirname(Date.new(year, month, 1).prev_month(i)) }
53
+ .map do |subdir|
54
+ search_path = "#{@dirname}/#{subdir}"
55
+ Dir.exist?(abs_path(search_path)) ? search_path : nil
56
+ end
57
+ total_path = total_dirs.compact.first
58
+ if total_path.nil?
59
+ puts "No Year total directory exists. exit"
60
+ exit 1
61
+ end
62
+
63
+ search(year, month, nil, nil, 'payments').each do |slip, path|
64
+ begin
65
+ find(slip['profile_id'], total_path) do |total|
66
+ ['3A1', '4A1'].each { |cd| slip[cd] = total[cd] }
67
+ end
68
+ rescue
69
+ # skip no adjust profile
70
+ end
71
+ # Recalculate sum
72
+ ['3', '4'].each do |key|
73
+ slip[key] = 0
74
+ slip[key] = LucaSalary::Base.sum_code(slip, key)
75
+ end
76
+ slip['5'] = slip['1'] - slip['2'] - slip['3'] + slip['4']
77
+ update_record(
78
+ 'payments',
79
+ path,
80
+ YAML.dump(LucaSupport::Code.readable(slip.sort.to_h))
81
+ )
82
+ end
83
+ end
84
+ end
85
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LucaSalary
4
- VERSION = '0.1.25'
4
+ VERSION = '0.1.28'
5
5
  end
data/lib/luca_salary.rb CHANGED
@@ -4,7 +4,10 @@ require 'luca_record'
4
4
  require 'luca_salary/version'
5
5
 
6
6
  module LucaSalary
7
+ autoload :Accumulator, 'luca_salary/accumulator'
7
8
  autoload :Base, 'luca_salary/base'
8
9
  autoload :Payment, 'luca_salary/payment'
9
10
  autoload :Profile, 'luca_salary/profile'
11
+ autoload :State, 'luca_salary/state'
12
+ autoload :Total, 'luca_salary/total'
10
13
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lucasalary
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.25
4
+ version: 0.1.28
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chuma Takahiro
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-01-16 00:00:00.000000000 Z
11
+ date: 2023-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lucarecord
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: 0.5.4
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'
26
+ version: 0.5.4
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -81,10 +81,13 @@ files:
81
81
  - README.md
82
82
  - exe/luca-salary
83
83
  - lib/luca_salary.rb
84
+ - lib/luca_salary/accumulator.rb
84
85
  - lib/luca_salary/base.rb
85
86
  - lib/luca_salary/monthly.rb
86
87
  - lib/luca_salary/payment.rb
87
88
  - lib/luca_salary/profile.rb
89
+ - lib/luca_salary/state.rb
90
+ - lib/luca_salary/total.rb
88
91
  - lib/luca_salary/version.rb
89
92
  homepage: https://github.com/chumaltd/luca/tree/master/lucasalary
90
93
  licenses:
@@ -93,7 +96,7 @@ metadata:
93
96
  homepage_uri: https://github.com/chumaltd/luca/tree/master/lucasalary
94
97
  source_code_uri: https://github.com/chumaltd/luca/tree/master/lucasalary
95
98
  changelog_uri: https://github.com/chumaltd/luca/tree/master/lucasalary/CHANGELOG.md
96
- post_install_message:
99
+ post_install_message:
97
100
  rdoc_options: []
98
101
  require_paths:
99
102
  - lib
@@ -109,7 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
112
  version: '0'
110
113
  requirements: []
111
114
  rubygems_version: 3.3.5
112
- signing_key:
115
+ signing_key:
113
116
  specification_version: 4
114
117
  summary: Salary calculation framework
115
118
  test_files: []