lucabook 0.2.25 → 0.2.26
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 +4 -4
- data/exe/luca-book +18 -2
- data/lib/luca_book.rb +1 -0
- data/lib/luca_book/accumulator.rb +152 -0
- data/lib/luca_book/dict.rb +90 -3
- data/lib/luca_book/list.rb +18 -10
- data/lib/luca_book/list_by_header.rb +1 -1
- data/lib/luca_book/state.rb +26 -144
- data/lib/luca_book/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 933e3d04315c04b7f6e998b16499b458ceeeafe8bfae9ce4ef4422018eb17040
|
4
|
+
data.tar.gz: 2e243b4e85cdc50bd45e39ed311cf78a8aa12e1956be0d0273c2a634147be16c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b2292a4972ce1fcf883a828d17479f1580e3145e0db2d26ff6044a73495d2e151d60f0bd98fd5b2f945c3b74cdff879f9f7779073487c05c70a078306b069bbe
|
7
|
+
data.tar.gz: 27bf6b4bcea1b2eb9d5dac761d5465ce478af02a4074f0a20038b7f8a21c528b66faf399d4364702ebf22f06cc0a0112d13a4ee2e10acb22eb16b52859aaf4b6
|
data/exe/luca-book
CHANGED
@@ -95,6 +95,12 @@ class LucaCmd
|
|
95
95
|
puts YAML.dump(dat)
|
96
96
|
end
|
97
97
|
end
|
98
|
+
|
99
|
+
class Dict < LucaCmd
|
100
|
+
def self.update_balance(args, params)
|
101
|
+
LucaBook::Dict.generate_balance(*args)
|
102
|
+
end
|
103
|
+
end
|
98
104
|
end
|
99
105
|
|
100
106
|
def new_pj(args = nil, params = {})
|
@@ -120,7 +126,7 @@ when /journals?/, 'j'
|
|
120
126
|
when 'list'
|
121
127
|
OptionParser.new do |opt|
|
122
128
|
opt.banner = 'Usage: luca-book journals list [options] [YYYY M]'
|
123
|
-
opt.on('-c', '--code VAL', '
|
129
|
+
opt.on('-c', '--code VAL', 'filter with code or label') { |v| params['code'] = v }
|
124
130
|
opt.on('--customer', 'categorize by x-customer header') { |_v| params['headers'] = 'x-customer' }
|
125
131
|
opt.on('-n VAL', 'report count') { |v| params[:n] = v.to_i }
|
126
132
|
opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
|
@@ -142,7 +148,7 @@ when /journals?/, 'j'
|
|
142
148
|
when 'stats'
|
143
149
|
OptionParser.new do |opt|
|
144
150
|
opt.banner = 'Usage: luca-book journals stats [options] [YYYY M]'
|
145
|
-
opt.on('-c', '--code VAL', '
|
151
|
+
opt.on('-c', '--code VAL', 'filter with code or label') { |v| params['code'] = v }
|
146
152
|
opt.on('-n VAL', 'report count') { |v| params[:n] = v.to_i }
|
147
153
|
opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
|
148
154
|
opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
|
@@ -211,6 +217,16 @@ when /reports?/, 'r'
|
|
211
217
|
puts ' pl: show statement of income'
|
212
218
|
exit 1
|
213
219
|
end
|
220
|
+
when /balance/
|
221
|
+
subcmd = ARGV.shift
|
222
|
+
case subcmd
|
223
|
+
when 'update'
|
224
|
+
OptionParser.new do |opt|
|
225
|
+
opt.banner = 'Usage: luca-book balance update YYYY [M]'
|
226
|
+
args = opt.parse!(ARGV)
|
227
|
+
LucaCmd::Dict.update_balance(args, params)
|
228
|
+
end
|
229
|
+
end
|
214
230
|
else
|
215
231
|
puts 'Proper subcommand needed.'
|
216
232
|
puts
|
data/lib/luca_book.rb
CHANGED
@@ -0,0 +1,152 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'luca_book/util'
|
4
|
+
require 'luca_support/config'
|
5
|
+
|
6
|
+
module LucaBook
|
7
|
+
module Accumulator
|
8
|
+
def self.included(klass) # :nodoc:
|
9
|
+
klass.extend ClassMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def accumulate_month(year, month)
|
14
|
+
monthly_record, count = net(year, month)
|
15
|
+
[total_subaccount(monthly_record), count]
|
16
|
+
end
|
17
|
+
|
18
|
+
# Accumulate Level 2, 3 account.
|
19
|
+
#
|
20
|
+
def total_subaccount(report)
|
21
|
+
{}.tap do |res|
|
22
|
+
res['A0'] = sum_matched(report, /^[A][0-9A-Z]{2,}/)
|
23
|
+
res['B0'] = sum_matched(report, /^[B][0-9A-Z]{2,}/)
|
24
|
+
res['BA'] = res['A0'] - res['B0']
|
25
|
+
res['C0'] = sum_matched(report, /^[C][0-9A-Z]{2,}/)
|
26
|
+
res['CA'] = res['BA'] - res['C0']
|
27
|
+
res['D0'] = sum_matched(report, /^[D][0-9A-Z]{2,}/)
|
28
|
+
res['E0'] = sum_matched(report, /^[E][0-9A-Z]{2,}/)
|
29
|
+
res['EA'] = res['CA'] + res['D0'] - res['E0']
|
30
|
+
res['F0'] = sum_matched(report, /^[F][0-9A-Z]{2,}/)
|
31
|
+
res['G0'] = sum_matched(report, /^[G][0-9][0-9A-Z]{1,}/)
|
32
|
+
res['GA'] = res['EA'] + res['F0'] - res['G0']
|
33
|
+
res['H0'] = sum_matched(report, /^[H][0-9][0-9A-Z]{1,}/)
|
34
|
+
res['HA'] = res['GA'] - res['H0']
|
35
|
+
|
36
|
+
report['9142'] = (report['9142'] || BigDecimal('0')) + res['HA']
|
37
|
+
res['9142'] = report['9142']
|
38
|
+
res['10'] = sum_matched(report, /^[12][0-9A-Z]{2,}/)
|
39
|
+
jp_4v = sum_matched(report, /^[4][V]{2,}/) # deferred assets for JP GAAP
|
40
|
+
res['30'] = sum_matched(report, /^[34][0-9A-Z]{2,}/) - jp_4v
|
41
|
+
res['4V'] = jp_4v if LucaSupport::CONFIG['country'] == 'jp'
|
42
|
+
res['50'] = sum_matched(report, /^[56][0-9A-Z]{2,}/)
|
43
|
+
res['70'] = sum_matched(report, /^[78][0-9A-Z]{2,}/)
|
44
|
+
res['91'] = sum_matched(report, /^91[0-9A-Z]{1,}/)
|
45
|
+
res['8ZZ'] = res['50'] + res['70']
|
46
|
+
res['9ZZ'] = sum_matched(report, /^[9][0-9A-Z]{2,}/)
|
47
|
+
|
48
|
+
res['1'] = res['10'] + res['30']
|
49
|
+
res['5'] = res['8ZZ'] + res['9ZZ']
|
50
|
+
res['_d'] = report['_d']
|
51
|
+
|
52
|
+
report.each do |k, v|
|
53
|
+
res[k] ||= sum_matched(report, /^#{k}[0-9A-Z]{1,}/) if k.length == 2
|
54
|
+
res[k] = v if k.length == 3
|
55
|
+
end
|
56
|
+
|
57
|
+
report.each do |k, v|
|
58
|
+
if k.length >= 4
|
59
|
+
if res[k[0, 3]]
|
60
|
+
res[k[0, 3]] += v
|
61
|
+
else
|
62
|
+
res[k[0, 3]] = v
|
63
|
+
end
|
64
|
+
res[k] = v
|
65
|
+
end
|
66
|
+
end
|
67
|
+
res.sort.to_h
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def sum_matched(report, reg)
|
72
|
+
report.select { |k, v| reg.match(k)}.values.sum
|
73
|
+
end
|
74
|
+
|
75
|
+
# for assert purpose
|
76
|
+
#
|
77
|
+
def gross(start_year, start_month, end_year = nil, end_month = nil, code: nil, date_range: nil, rows: 4)
|
78
|
+
if ! date_range.nil?
|
79
|
+
raise if date_range.class != Range
|
80
|
+
# TODO: date based range search
|
81
|
+
end
|
82
|
+
|
83
|
+
end_year ||= start_year
|
84
|
+
end_month ||= start_month
|
85
|
+
sum = { debit: {}, credit: {}, debit_count: {}, credit_count: {} }
|
86
|
+
idx_memo = []
|
87
|
+
term(start_year, start_month, end_year, end_month, code) do |f, _path|
|
88
|
+
CSV.new(f, headers: false, col_sep: "\t", encoding: 'UTF-8')
|
89
|
+
.each_with_index do |row, i|
|
90
|
+
break if i >= rows
|
91
|
+
|
92
|
+
case i
|
93
|
+
when 0
|
94
|
+
idx_memo = row.map(&:to_s)
|
95
|
+
next if code && !idx_memo.include?(code)
|
96
|
+
|
97
|
+
idx_memo.each do |r|
|
98
|
+
sum[:debit][r] ||= BigDecimal('0')
|
99
|
+
sum[:debit_count][r] ||= 0
|
100
|
+
end
|
101
|
+
when 1
|
102
|
+
next if code && !idx_memo.include?(code)
|
103
|
+
|
104
|
+
row.each_with_index do |r, j|
|
105
|
+
sum[:debit][idx_memo[j]] += BigDecimal(r.to_s)
|
106
|
+
sum[:debit_count][idx_memo[j]] += 1
|
107
|
+
end
|
108
|
+
when 2
|
109
|
+
idx_memo = row.map(&:to_s)
|
110
|
+
break if code && !idx_memo.include?(code)
|
111
|
+
|
112
|
+
idx_memo.each do |r|
|
113
|
+
sum[:credit][r] ||= BigDecimal('0')
|
114
|
+
sum[:credit_count][r] ||= 0
|
115
|
+
end
|
116
|
+
when 3
|
117
|
+
row.each_with_index do |r, j|
|
118
|
+
sum[:credit][idx_memo[j]] += BigDecimal(r.to_s)
|
119
|
+
sum[:credit_count][idx_memo[j]] += 1
|
120
|
+
end
|
121
|
+
else
|
122
|
+
puts row # for debug
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
if code
|
127
|
+
sum[:debit] = sum[:debit][code] || BigDecimal('0')
|
128
|
+
sum[:credit] = sum[:credit][code] || BigDecimal('0')
|
129
|
+
sum[:debit_count] = sum[:debit_count][code] || 0
|
130
|
+
sum[:credit_count] = sum[:credit_count][code] || 0
|
131
|
+
end
|
132
|
+
sum
|
133
|
+
end
|
134
|
+
|
135
|
+
# netting vouchers in specified term
|
136
|
+
#
|
137
|
+
def net(start_year, start_month, end_year = nil, end_month = nil, code: nil, date_range: nil)
|
138
|
+
g = gross(start_year, start_month, end_year, end_month, code: code, date_range: date_range)
|
139
|
+
idx = (g[:debit].keys + g[:credit].keys).uniq.sort
|
140
|
+
count = {}
|
141
|
+
diff = {}.tap do |sum|
|
142
|
+
idx.each do |code|
|
143
|
+
sum[code] = g.dig(:debit, code).nil? ? BigDecimal('0') : LucaBook::Util.calc_diff(g[:debit][code], code)
|
144
|
+
sum[code] -= g.dig(:credit, code).nil? ? BigDecimal('0') : LucaBook::Util.calc_diff(g[:credit][code], code)
|
145
|
+
count[code] = (g.dig(:debit_count, code) || 0) + (g.dig(:credit_count, code) || 0)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
[diff, count]
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
data/lib/luca_book/dict.rb
CHANGED
@@ -1,12 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'luca_support/code'
|
3
4
|
require 'luca_support/config'
|
4
5
|
require 'luca_record/dict'
|
6
|
+
require 'luca_record/io'
|
7
|
+
require 'luca_book'
|
5
8
|
require 'date'
|
6
9
|
require 'pathname'
|
7
10
|
|
8
11
|
module LucaBook
|
9
12
|
class Dict < LucaRecord::Dict
|
13
|
+
include Accumulator
|
14
|
+
include LucaRecord::IO
|
15
|
+
|
16
|
+
@dirname = 'journals'
|
17
|
+
@record_type = 'raw'
|
10
18
|
# Column number settings for CSV/TSV convert
|
11
19
|
#
|
12
20
|
# :label
|
@@ -84,14 +92,93 @@ module LucaBook
|
|
84
92
|
nil
|
85
93
|
end
|
86
94
|
|
87
|
-
|
95
|
+
# Find balance at financial year start by given date.
|
96
|
+
# If not found 'start-yyyy-mm-*.tsv', use 'start.tsv' as default.
|
97
|
+
#
|
98
|
+
def self.latest_balance(date)
|
99
|
+
load_tsv_dict(latest_balance_path(date))
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.latest_balance_path(date)
|
103
|
+
start_year = date.month >= LucaSupport::CONFIG['fy_start'] ? date.year : date.year - 1
|
104
|
+
latest = Date.new(start_year, LucaSupport::CONFIG['fy_start'], 1).prev_month
|
88
105
|
dict_dir = Pathname(LucaSupport::PJDIR) / 'data' / 'balance'
|
89
|
-
|
90
|
-
|
106
|
+
fileglob = %Q(start-#{latest.year}-#{format("%02d", latest.month)}-*)
|
107
|
+
path = Dir.glob(fileglob, base: dict_dir)[0] || 'start.tsv'
|
108
|
+
dict_dir / path
|
91
109
|
end
|
92
110
|
|
93
111
|
def self.issue_date(obj)
|
94
112
|
Date.parse(obj.dig('_date', :label))
|
95
113
|
end
|
114
|
+
|
115
|
+
def self.generate_balance(year, month = nil)
|
116
|
+
start_date = Date.new((year.to_i - 1), LucaSupport::CONFIG['fy_start'], 1)
|
117
|
+
month ||= LucaSupport::CONFIG['fy_start'] - 1
|
118
|
+
end_date = Date.new(year.to_i, month, -1)
|
119
|
+
labels = load('base.tsv')
|
120
|
+
bs = load_balance(start_date, end_date)
|
121
|
+
fy_digest = checksum(start_date, end_date)
|
122
|
+
current_ref = gitref
|
123
|
+
csv = CSV.generate(String.new, col_sep: "\t", headers: false) do |f|
|
124
|
+
f << ['code', 'label', 'balance']
|
125
|
+
f << ['_date', end_date]
|
126
|
+
f << ['_digest', fy_digest]
|
127
|
+
f << ['_gitref', current_ref] if current_ref
|
128
|
+
bs.each do |code, balance|
|
129
|
+
next if LucaSupport::Code.readable(balance) == 0
|
130
|
+
|
131
|
+
f << [code, labels.dig(code, :label), LucaSupport::Code.readable(balance)]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
dict_dir = Pathname(LucaSupport::PJDIR) / 'data' / 'balance'
|
135
|
+
filepath = dict_dir / "start-#{end_date.to_s}.tsv"
|
136
|
+
|
137
|
+
File.open(filepath, 'w') { |f| f.write csv }
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.load_balance(start_date, end_date)
|
141
|
+
base = latest_balance(start_date).each_with_object({}) do |(k, v), h|
|
142
|
+
h[k] = BigDecimal(v[:balance].to_s) if v[:balance]
|
143
|
+
end
|
144
|
+
|
145
|
+
search_range = term_by_month(start_date, end_date)
|
146
|
+
bs = search_range.each_with_object(base) do |date, h|
|
147
|
+
net(date.year, date.month)[0].each do |code, amount|
|
148
|
+
next if /^[^1-9]/.match(code)
|
149
|
+
|
150
|
+
h[code] ||= BigDecimal('0')
|
151
|
+
h[code] += amount
|
152
|
+
end
|
153
|
+
end
|
154
|
+
bs['9142'] ||= BigDecimal('0')
|
155
|
+
bs['9142'] += LucaBook::State
|
156
|
+
.range(start_date.year, start_date.month, end_date.year, end_date.month)
|
157
|
+
.net_income
|
158
|
+
bs.sort
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.checksum(start_date, end_date)
|
162
|
+
digest = update_digest(String.new, File.read(latest_balance_path(start_date)))
|
163
|
+
term_by_month(start_date, end_date)
|
164
|
+
.map { |date| dir_digest(date.year, date.month) }
|
165
|
+
.each { |month_digest| digest = update_digest(digest, month_digest) }
|
166
|
+
digest
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.gitref
|
170
|
+
digest = `git rev-parse HEAD`
|
171
|
+
$?.exitstatus == 0 ? digest.strip : nil
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.term_by_month(start_date, end_date)
|
175
|
+
Enumerator.new do |yielder|
|
176
|
+
each_month = start_date
|
177
|
+
while each_month <= end_date
|
178
|
+
yielder << each_month
|
179
|
+
each_month = each_month.next_month
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
96
183
|
end
|
97
184
|
end
|
data/lib/luca_book/list.rb
CHANGED
@@ -12,16 +12,17 @@ module LucaBook #:nodoc:
|
|
12
12
|
#
|
13
13
|
class List < LucaBook::Journal
|
14
14
|
@dirname = 'journals'
|
15
|
+
@@dict = LucaRecord::Dict.new('base.tsv')
|
15
16
|
attr_reader :data
|
16
17
|
|
17
18
|
def initialize(data, start_date, code = nil)
|
18
19
|
@data = data
|
19
20
|
@code = code
|
20
21
|
@start = start_date
|
21
|
-
@dict = LucaRecord::Dict.load('base.tsv')
|
22
22
|
end
|
23
23
|
|
24
24
|
def self.term(from_year, from_month, to_year = from_year, to_month = from_month, code: nil, basedir: @dirname)
|
25
|
+
code = search_code(code) if code
|
25
26
|
data = LucaBook::Journal.term(from_year, from_month, to_year, to_month, code).select do |dat|
|
26
27
|
if code.nil?
|
27
28
|
true
|
@@ -85,12 +86,23 @@ module LucaBook #:nodoc:
|
|
85
86
|
end
|
86
87
|
end
|
87
88
|
|
89
|
+
def self.search_code(code)
|
90
|
+
return code if @@dict.dig(code)
|
91
|
+
|
92
|
+
@@dict.search(code).tap do |new_code|
|
93
|
+
if new_code.nil?
|
94
|
+
puts "Search word is not matched with labels"
|
95
|
+
exit 1
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
88
100
|
private
|
89
101
|
|
90
102
|
def set_balance
|
91
103
|
return BigDecimal('0') if @code.nil? || /^[A-H]/.match(@code)
|
92
104
|
|
93
|
-
balance_dict = Dict.latest_balance
|
105
|
+
balance_dict = Dict.latest_balance(@start)
|
94
106
|
start_balance = BigDecimal(balance_dict.dig(@code.to_s, :balance) || '0')
|
95
107
|
start = Dict.issue_date(balance_dict)&.next_month
|
96
108
|
last = @start.prev_month
|
@@ -120,20 +132,16 @@ module LucaBook #:nodoc:
|
|
120
132
|
def convert_label
|
121
133
|
@data.each do |dat|
|
122
134
|
if @code
|
123
|
-
dat[:code] = "#{dat[:code]} #{
|
124
|
-
dat[:counter_code] = dat[:counter_code].map { |counter| "#{counter} #{
|
135
|
+
dat[:code] = "#{dat[:code]} #{@@dict.dig(dat[:code], :label)}"
|
136
|
+
dat[:counter_code] = dat[:counter_code].map { |counter| "#{counter} #{@@dict.dig(counter, :label)}" }
|
125
137
|
else
|
126
|
-
dat[:debit].each { |debit| debit[:code] = "#{debit[:code]} #{
|
127
|
-
dat[:credit].each { |credit| credit[:code] = "#{credit[:code]} #{
|
138
|
+
dat[:debit].each { |debit| debit[:code] = "#{debit[:code]} #{@@dict.dig(debit[:code], :label)}" }
|
139
|
+
dat[:credit].each { |credit| credit[:code] = "#{credit[:code]} #{@@dict.dig(credit[:code], :label)}" }
|
128
140
|
end
|
129
141
|
end
|
130
142
|
self
|
131
143
|
end
|
132
144
|
|
133
|
-
def dict
|
134
|
-
LucaBook::Dict::Data
|
135
|
-
end
|
136
|
-
|
137
145
|
def code_header
|
138
146
|
{}.tap do |h|
|
139
147
|
%w[code date no id diff balance counter_code note].each do |k|
|
@@ -67,7 +67,7 @@ module LucaBook #:nodoc:
|
|
67
67
|
def set_balance
|
68
68
|
return BigDecimal('0') if @code.nil? || /^[A-H]/.match(@code)
|
69
69
|
|
70
|
-
balance_dict = Dict.latest_balance
|
70
|
+
balance_dict = Dict.latest_balance(@start)
|
71
71
|
start_balance = BigDecimal(balance_dict.dig(@code.to_s, :balance) || '0')
|
72
72
|
start = Dict.issue_date(balance_dict)&.next_month
|
73
73
|
last = @start.prev_month
|
data/lib/luca_book/state.rb
CHANGED
@@ -14,15 +14,17 @@ require 'luca_book'
|
|
14
14
|
#
|
15
15
|
module LucaBook
|
16
16
|
class State < LucaRecord::Base
|
17
|
+
include Accumulator
|
18
|
+
|
17
19
|
@dirname = 'journals'
|
18
20
|
@record_type = 'raw'
|
21
|
+
@@dict = LucaRecord::Dict.new('base.tsv')
|
19
22
|
|
20
23
|
attr_reader :statement, :pl_data, :bs_data, :start_balance
|
21
24
|
|
22
25
|
def initialize(data, count = nil, start_d: nil, end_d: nil)
|
23
26
|
@monthly = data
|
24
27
|
@count = count
|
25
|
-
@dict = LucaRecord::Dict.load('base.tsv')
|
26
28
|
@start_date = start_d
|
27
29
|
@end_date = end_d
|
28
30
|
@start_balance = set_balance
|
@@ -49,6 +51,7 @@ module LucaBook
|
|
49
51
|
end
|
50
52
|
|
51
53
|
def self.by_code(code, from_year, from_month, to_year = from_year, to_month = from_month)
|
54
|
+
code = search_code(code) if code
|
52
55
|
date = Date.new(from_year.to_i, from_month.to_i, -1)
|
53
56
|
last_date = Date.new(to_year.to_i, to_month.to_i, -1)
|
54
57
|
raise 'invalid term specified' if date > last_date
|
@@ -79,7 +82,7 @@ module LucaBook
|
|
79
82
|
@statement ||= @monthly
|
80
83
|
@statement.map do |report|
|
81
84
|
{}.tap do |h|
|
82
|
-
report.each { |k, v| h[
|
85
|
+
report.each { |k, v| h[@@dict.dig(k, :label) || k] = v }
|
83
86
|
end
|
84
87
|
end
|
85
88
|
end
|
@@ -104,7 +107,7 @@ module LucaBook
|
|
104
107
|
data.sort.to_h
|
105
108
|
end
|
106
109
|
keys.map! { |k| k[0, level] }.uniq.select! { |k| k.length <= level } if level
|
107
|
-
@count.prepend({}.tap { |header| keys.each { |k| header[k] =
|
110
|
+
@count.prepend({}.tap { |header| keys.each { |k| header[k] = @@dict.dig(k, :label) }})
|
108
111
|
@count
|
109
112
|
end
|
110
113
|
|
@@ -137,7 +140,7 @@ module LucaBook
|
|
137
140
|
@statement = [].tap do |a|
|
138
141
|
rows.times do |i|
|
139
142
|
{}.tap do |res|
|
140
|
-
res['debit_label'] = base[:debit][i] ?
|
143
|
+
res['debit_label'] = base[:debit][i] ? @@dict.dig(base[:debit][i].keys[0], :label) : ''
|
141
144
|
#res['debit_balance'] = base[:debit][i] ? (@start_balance.dig(base[:debit][i].keys[0]) || 0) + base[:debit][i].values[0] : ''
|
142
145
|
res['debit_balance'] = base[:debit][i] ? base[:debit][i].values[0] : ''
|
143
146
|
res['credit_label'] = base[:credit][i] ? @dict.dig(base[:credit][i].keys[0], :label) : ''
|
@@ -174,6 +177,12 @@ module LucaBook
|
|
174
177
|
readable(code2label)
|
175
178
|
end
|
176
179
|
|
180
|
+
#
|
181
|
+
def net_income
|
182
|
+
set_pl(2)
|
183
|
+
@pl_data['HA']
|
184
|
+
end
|
185
|
+
|
177
186
|
def self.accumulate_term(start_year, start_month, end_year, end_month)
|
178
187
|
date = Date.new(start_year, start_month, 1)
|
179
188
|
last_date = Date.new(end_year, end_month, -1)
|
@@ -189,64 +198,6 @@ module LucaBook
|
|
189
198
|
end
|
190
199
|
end
|
191
200
|
|
192
|
-
def self.accumulate_month(year, month)
|
193
|
-
monthly_record, count = net(year, month)
|
194
|
-
[total_subaccount(monthly_record), count]
|
195
|
-
end
|
196
|
-
|
197
|
-
# Accumulate Level 2, 3 account.
|
198
|
-
#
|
199
|
-
def self.total_subaccount(report)
|
200
|
-
{}.tap do |res|
|
201
|
-
res['A0'] = sum_matched(report, /^[A][0-9A-Z]{2,}/)
|
202
|
-
res['B0'] = sum_matched(report, /^[B][0-9A-Z]{2,}/)
|
203
|
-
res['BA'] = res['A0'] - res['B0']
|
204
|
-
res['C0'] = sum_matched(report, /^[C][0-9A-Z]{2,}/)
|
205
|
-
res['CA'] = res['BA'] - res['C0']
|
206
|
-
res['D0'] = sum_matched(report, /^[D][0-9A-Z]{2,}/)
|
207
|
-
res['E0'] = sum_matched(report, /^[E][0-9A-Z]{2,}/)
|
208
|
-
res['EA'] = res['CA'] + res['D0'] - res['E0']
|
209
|
-
res['F0'] = sum_matched(report, /^[F][0-9A-Z]{2,}/)
|
210
|
-
res['G0'] = sum_matched(report, /^[G][0-9][0-9A-Z]{1,}/)
|
211
|
-
res['GA'] = res['EA'] + res['F0'] - res['G0']
|
212
|
-
res['H0'] = sum_matched(report, /^[H][0-9][0-9A-Z]{1,}/)
|
213
|
-
res['HA'] = res['GA'] - res['H0']
|
214
|
-
|
215
|
-
report['9142'] = (report['9142'] || BigDecimal('0')) + res['HA']
|
216
|
-
res['9142'] = report['9142']
|
217
|
-
res['10'] = sum_matched(report, /^[12][0-9A-Z]{2,}/)
|
218
|
-
jp_4v = sum_matched(report, /^[4][V]{2,}/) # deferred assets for JP GAAP
|
219
|
-
res['30'] = sum_matched(report, /^[34][0-9A-Z]{2,}/) - jp_4v
|
220
|
-
res['4V'] = jp_4v if CONFIG['country'] == 'jp'
|
221
|
-
res['50'] = sum_matched(report, /^[56][0-9A-Z]{2,}/)
|
222
|
-
res['70'] = sum_matched(report, /^[78][0-9A-Z]{2,}/)
|
223
|
-
res['91'] = sum_matched(report, /^91[0-9A-Z]{1,}/)
|
224
|
-
res['8ZZ'] = res['50'] + res['70']
|
225
|
-
res['9ZZ'] = sum_matched(report, /^[9][0-9A-Z]{2,}/)
|
226
|
-
|
227
|
-
res['1'] = res['10'] + res['30']
|
228
|
-
res['5'] = res['8ZZ'] + res['9ZZ']
|
229
|
-
res['_d'] = report['_d']
|
230
|
-
|
231
|
-
report.each do |k, v|
|
232
|
-
res[k] ||= sum_matched(report, /^#{k}[0-9A-Z]{1,}/) if k.length == 2
|
233
|
-
res[k] = v if k.length == 3
|
234
|
-
end
|
235
|
-
|
236
|
-
report.each do |k, v|
|
237
|
-
if k.length >= 4
|
238
|
-
if res[k[0, 3]]
|
239
|
-
res[k[0, 3]] += v
|
240
|
-
else
|
241
|
-
res[k[0, 3]] = v
|
242
|
-
end
|
243
|
-
res[k] = v
|
244
|
-
end
|
245
|
-
end
|
246
|
-
res.sort.to_h
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
201
|
def code_sum(report)
|
251
202
|
legal_items.each.with_object({}) do |k, h|
|
252
203
|
h[k] = self.class.sum_matched(report, /^#{k}.*/)
|
@@ -262,7 +213,7 @@ module LucaBook
|
|
262
213
|
end
|
263
214
|
pre = self.class.accumulate_term(start_year, CONFIG['fy_start'], pre_last.year, pre_last.month)
|
264
215
|
|
265
|
-
base = Dict.latest_balance.each_with_object({}) do |(k, v), h|
|
216
|
+
base = Dict.latest_balance(@start_date).each_with_object({}) do |(k, v), h|
|
266
217
|
h[k] = BigDecimal(v[:balance].to_s) if v[:balance]
|
267
218
|
h[k] ||= BigDecimal('0') if k.length == 2
|
268
219
|
end
|
@@ -275,86 +226,6 @@ module LucaBook
|
|
275
226
|
self.class.total_subaccount(base)
|
276
227
|
end
|
277
228
|
|
278
|
-
def self.sum_matched(report, reg)
|
279
|
-
report.select { |k, v| reg.match(k)}.values.sum
|
280
|
-
end
|
281
|
-
|
282
|
-
# for assert purpose
|
283
|
-
#
|
284
|
-
def self.gross(start_year, start_month, end_year = nil, end_month = nil, code: nil, date_range: nil, rows: 4)
|
285
|
-
if ! date_range.nil?
|
286
|
-
raise if date_range.class != Range
|
287
|
-
# TODO: date based range search
|
288
|
-
end
|
289
|
-
|
290
|
-
end_year ||= start_year
|
291
|
-
end_month ||= start_month
|
292
|
-
sum = { debit: {}, credit: {}, debit_count: {}, credit_count: {} }
|
293
|
-
idx_memo = []
|
294
|
-
term(start_year, start_month, end_year, end_month, code) do |f, _path|
|
295
|
-
CSV.new(f, headers: false, col_sep: "\t", encoding: 'UTF-8')
|
296
|
-
.each_with_index do |row, i|
|
297
|
-
break if i >= rows
|
298
|
-
|
299
|
-
case i
|
300
|
-
when 0
|
301
|
-
idx_memo = row.map(&:to_s)
|
302
|
-
next if code && !idx_memo.include?(code)
|
303
|
-
|
304
|
-
idx_memo.each do |r|
|
305
|
-
sum[:debit][r] ||= BigDecimal('0')
|
306
|
-
sum[:debit_count][r] ||= 0
|
307
|
-
end
|
308
|
-
when 1
|
309
|
-
next if code && !idx_memo.include?(code)
|
310
|
-
|
311
|
-
row.each_with_index do |r, j|
|
312
|
-
sum[:debit][idx_memo[j]] += BigDecimal(r.to_s)
|
313
|
-
sum[:debit_count][idx_memo[j]] += 1
|
314
|
-
end
|
315
|
-
when 2
|
316
|
-
idx_memo = row.map(&:to_s)
|
317
|
-
break if code && !idx_memo.include?(code)
|
318
|
-
|
319
|
-
idx_memo.each do |r|
|
320
|
-
sum[:credit][r] ||= BigDecimal('0')
|
321
|
-
sum[:credit_count][r] ||= 0
|
322
|
-
end
|
323
|
-
when 3
|
324
|
-
row.each_with_index do |r, j|
|
325
|
-
sum[:credit][idx_memo[j]] += BigDecimal(r.to_s)
|
326
|
-
sum[:credit_count][idx_memo[j]] += 1
|
327
|
-
end
|
328
|
-
else
|
329
|
-
puts row # for debug
|
330
|
-
end
|
331
|
-
end
|
332
|
-
end
|
333
|
-
if code
|
334
|
-
sum[:debit] = sum[:debit][code] || BigDecimal('0')
|
335
|
-
sum[:credit] = sum[:credit][code] || BigDecimal('0')
|
336
|
-
sum[:debit_count] = sum[:debit_count][code] || 0
|
337
|
-
sum[:credit_count] = sum[:credit_count][code] || 0
|
338
|
-
end
|
339
|
-
sum
|
340
|
-
end
|
341
|
-
|
342
|
-
# netting vouchers in specified term
|
343
|
-
#
|
344
|
-
def self.net(start_year, start_month, end_year = nil, end_month = nil, code: nil, date_range: nil)
|
345
|
-
g = gross(start_year, start_month, end_year, end_month, code: code, date_range: date_range)
|
346
|
-
idx = (g[:debit].keys + g[:credit].keys).uniq.sort
|
347
|
-
count = {}
|
348
|
-
diff = {}.tap do |sum|
|
349
|
-
idx.each do |code|
|
350
|
-
sum[code] = g.dig(:debit, code).nil? ? BigDecimal('0') : Util.calc_diff(g[:debit][code], code)
|
351
|
-
sum[code] -= g.dig(:credit, code).nil? ? BigDecimal('0') : Util.calc_diff(g[:credit][code], code)
|
352
|
-
count[code] = (g.dig(:debit_count, code) || 0) + (g.dig(:credit_count, code) || 0)
|
353
|
-
end
|
354
|
-
end
|
355
|
-
[diff, count]
|
356
|
-
end
|
357
|
-
|
358
229
|
def render_xbrl(filename = nil)
|
359
230
|
set_bs(3, legal: true)
|
360
231
|
set_pl(3)
|
@@ -378,7 +249,7 @@ module LucaBook
|
|
378
249
|
return nil if /^_/.match(code)
|
379
250
|
|
380
251
|
context = /^[0-9]/.match(code) ? 'CurrentYearNonConsolidatedInstant' : 'CurrentYearNonConsolidatedDuration'
|
381
|
-
tag =
|
252
|
+
tag = @@dict.dig(code, :xbrl_id)
|
382
253
|
#raise "xbrl_id not found: #{code}" if tag.nil?
|
383
254
|
return nil if tag.nil?
|
384
255
|
return nil if readable(amount).zero? && prior_amount.nil?
|
@@ -389,6 +260,17 @@ module LucaBook
|
|
389
260
|
prior + current
|
390
261
|
end
|
391
262
|
|
263
|
+
def self.search_code(code)
|
264
|
+
return code if @@dict.dig(code)
|
265
|
+
|
266
|
+
@@dict.search(code).tap do |new_code|
|
267
|
+
if new_code.nil?
|
268
|
+
puts "Search word is not matched with labels"
|
269
|
+
exit 1
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
392
274
|
private
|
393
275
|
|
394
276
|
def set_bs(level = 3, legal: false)
|
data/lib/luca_book/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lucabook
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.26
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chuma Takahiro
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-03-
|
11
|
+
date: 2021-03-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: lucarecord
|
@@ -79,6 +79,7 @@ files:
|
|
79
79
|
- LICENSE
|
80
80
|
- exe/luca-book
|
81
81
|
- lib/luca_book.rb
|
82
|
+
- lib/luca_book/accumulator.rb
|
82
83
|
- lib/luca_book/console.rb
|
83
84
|
- lib/luca_book/dict.rb
|
84
85
|
- lib/luca_book/import.rb
|