lucabook 0.2.22 → 0.2.27
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 +78 -5
- data/lib/luca_book.rb +2 -0
- data/lib/luca_book/accumulator.rb +160 -0
- data/lib/luca_book/console.rb +4 -4
- data/lib/luca_book/dict.rb +95 -8
- data/lib/luca_book/import.rb +15 -13
- data/lib/luca_book/import_jp.rb +14 -14
- data/lib/luca_book/journal.rb +90 -32
- data/lib/luca_book/list.rb +47 -32
- data/lib/luca_book/list_by_header.rb +120 -0
- data/lib/luca_book/setup.rb +2 -1
- data/lib/luca_book/state.rb +157 -189
- data/lib/luca_book/templates/base-jp.xbrl.erb +23 -48
- data/lib/luca_book/templates/base-jp.xsd.erb +17 -0
- data/lib/luca_book/templates/config.yml +4 -0
- data/lib/luca_book/templates/dict-en.tsv +25 -30
- data/lib/luca_book/templates/dict-jp-edinet.tsv +167 -0
- data/lib/luca_book/templates/dict-jp.tsv +192 -162
- data/lib/luca_book/templates/monthly-report.html.erb +67 -0
- data/lib/luca_book/util.rb +1 -1
- data/lib/luca_book/version.rb +1 -1
- metadata +9 -3
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
require 'date'
|
5
|
+
require 'luca_support'
|
6
|
+
require 'luca_record'
|
7
|
+
require 'luca_record/dict'
|
8
|
+
require 'luca_book'
|
9
|
+
|
10
|
+
module LucaBook #:nodoc:
|
11
|
+
# Journal List on specified term
|
12
|
+
#
|
13
|
+
class ListByHeader < LucaBook::Journal
|
14
|
+
@dirname = 'journals'
|
15
|
+
|
16
|
+
def initialize(data, start_date, code = nil, header_name = nil)
|
17
|
+
@data = data
|
18
|
+
@code = code
|
19
|
+
@header = header_name
|
20
|
+
@start = start_date
|
21
|
+
@dict = LucaRecord::Dict.load('base.tsv')
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.term(from_year, from_month, to_year = from_year, to_month = from_month, code: nil, header: nil, basedir: @dirname)
|
25
|
+
data = Journal.term(from_year, from_month, to_year, to_month, code).select do |dat|
|
26
|
+
if code.nil?
|
27
|
+
true
|
28
|
+
else
|
29
|
+
[:debit, :credit].map { |key| serialize_on_key(dat[key], :code) }.flatten.include?(code)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
new data, Date.new(from_year.to_i, from_month.to_i, 1), code, header
|
33
|
+
end
|
34
|
+
|
35
|
+
def list_by_code
|
36
|
+
calc_code
|
37
|
+
convert_label
|
38
|
+
@data = @data.each_with_object([]) do |(k, v), a|
|
39
|
+
journals = v.map do |dat|
|
40
|
+
date, txid = decode_id(dat[:id])
|
41
|
+
{}.tap do |res|
|
42
|
+
res['header'] = k
|
43
|
+
res['date'] = date
|
44
|
+
res['no'] = txid
|
45
|
+
res['id'] = dat[:id]
|
46
|
+
res['diff'] = dat[:diff]
|
47
|
+
res['balance'] = dat[:balance]
|
48
|
+
res['counter_code'] = dat[:counter_code].length == 1 ? dat[:counter_code].first : dat[:counter_code]
|
49
|
+
res['note'] = dat[:note]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
a << { 'code' => v.last[:code], 'header' => k, 'balance' => v.last[:balance], 'count' => v.count, 'jounals' => journals }
|
53
|
+
end
|
54
|
+
readable(@data)
|
55
|
+
end
|
56
|
+
|
57
|
+
def accumulate_code
|
58
|
+
@data.each_with_object({}) do |dat, sum|
|
59
|
+
idx = dat.dig(:headers, @header) || 'others'
|
60
|
+
sum[idx] ||= BigDecimal('0')
|
61
|
+
sum[idx] += Util.diff_by_code(dat[:debit], @code) - Util.diff_by_code(dat[:credit], @code)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def set_balance
|
68
|
+
return BigDecimal('0') if @code.nil? || /^[A-H]/.match(@code)
|
69
|
+
|
70
|
+
balance_dict = Dict.latest_balance(@start)
|
71
|
+
start_balance = BigDecimal(balance_dict.dig(@code.to_s, :balance) || '0')
|
72
|
+
start = Dict.issue_date(balance_dict)&.next_month
|
73
|
+
last = @start.prev_month
|
74
|
+
if last.year >= start.year && last.month >= start.month
|
75
|
+
#TODO: start_balance to be implemented by header
|
76
|
+
self.class.term(start.year, start.month, last.year, last.month, code: @code).accumulate_code
|
77
|
+
else
|
78
|
+
#start_balance
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def calc_code
|
83
|
+
raise 'no account code specified' if @code.nil?
|
84
|
+
|
85
|
+
@balance = set_balance
|
86
|
+
balance = @balance
|
87
|
+
res = {}
|
88
|
+
@data.each do |dat|
|
89
|
+
idx = dat.dig(:headers, @header) || 'others'
|
90
|
+
balance[idx] ||= BigDecimal('0')
|
91
|
+
res[idx] ||= []
|
92
|
+
{}.tap do |h|
|
93
|
+
h[:id] = dat[:id]
|
94
|
+
h[:diff] = Util.diff_by_code(dat[:debit], @code) - Util.diff_by_code(dat[:credit], @code)
|
95
|
+
balance[idx] += h[:diff]
|
96
|
+
h[:balance] = balance[idx]
|
97
|
+
h[:code] = @code
|
98
|
+
counter = h[:diff] * Util.pn_debit(@code) > 0 ? :credit : :debit
|
99
|
+
h[:counter_code] = dat[counter].map { |d| d[:code] }
|
100
|
+
h[:note] = dat[:note]
|
101
|
+
res[idx] << h
|
102
|
+
end
|
103
|
+
end
|
104
|
+
@data = res
|
105
|
+
self
|
106
|
+
end
|
107
|
+
|
108
|
+
def convert_label
|
109
|
+
@data.each do |_k, v|
|
110
|
+
v.each do |dat|
|
111
|
+
raise 'no account code specified' if @code.nil?
|
112
|
+
|
113
|
+
dat[:code] = "#{dat[:code]} #{@dict.dig(dat[:code], :label)}"
|
114
|
+
dat[:counter_code] = dat[:counter_code].map { |counter| "#{counter} #{@dict.dig(counter, :label)}" }
|
115
|
+
end
|
116
|
+
end
|
117
|
+
self
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
data/lib/luca_book/setup.rb
CHANGED
@@ -6,7 +6,7 @@ require 'fileutils'
|
|
6
6
|
module LucaBook
|
7
7
|
class Setup
|
8
8
|
# create project skeleton under specified directory
|
9
|
-
def self.create_project(country = nil, dir = LucaSupport::
|
9
|
+
def self.create_project(country = nil, dir = LucaSupport::PJDIR)
|
10
10
|
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
11
11
|
Dir.chdir(dir) do
|
12
12
|
%w[data/journals data/balance dict].each do |subdir|
|
@@ -18,6 +18,7 @@ module LucaBook
|
|
18
18
|
'dict-en.tsv'
|
19
19
|
end
|
20
20
|
FileUtils.cp("#{__dir__}/templates/#{dict}", 'dict/base.tsv') unless File.exist?('dict/base.tsv')
|
21
|
+
FileUtils.cp("#{__dir__}/templates/config.yml", 'config.yml') unless File.exist?('config.yml')
|
21
22
|
prepare_starttsv(dict) unless File.exist? 'data/balance/start.tsv'
|
22
23
|
end
|
23
24
|
end
|
data/lib/luca_book/state.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'cgi/escape'
|
3
4
|
require 'csv'
|
5
|
+
require 'mail'
|
4
6
|
require 'pathname'
|
5
7
|
require 'date'
|
6
8
|
require 'luca_support'
|
@@ -12,17 +14,20 @@ require 'luca_book'
|
|
12
14
|
#
|
13
15
|
module LucaBook
|
14
16
|
class State < LucaRecord::Base
|
17
|
+
include Accumulator
|
18
|
+
|
15
19
|
@dirname = 'journals'
|
16
20
|
@record_type = 'raw'
|
21
|
+
@@dict = LucaRecord::Dict.new('base.tsv')
|
17
22
|
|
18
|
-
attr_reader :statement
|
23
|
+
attr_reader :statement, :pl_data, :bs_data, :start_balance
|
19
24
|
|
20
|
-
def initialize(data, count = nil,
|
21
|
-
@
|
25
|
+
def initialize(data, count = nil, start_d: nil, end_d: nil)
|
26
|
+
@monthly = data
|
22
27
|
@count = count
|
23
|
-
@
|
24
|
-
@
|
25
|
-
|
28
|
+
@start_date = start_d
|
29
|
+
@end_date = end_d
|
30
|
+
set_balance
|
26
31
|
end
|
27
32
|
|
28
33
|
def self.range(from_year, from_month, to_year = from_year, to_month = from_month)
|
@@ -39,27 +44,35 @@ module LucaBook
|
|
39
44
|
date = Date.new(date.next_month.year, date.next_month.month, -1)
|
40
45
|
end
|
41
46
|
end
|
42
|
-
new(reports, counts,
|
47
|
+
new(reports, counts,
|
48
|
+
start_d: Date.new(from_year.to_i, from_month.to_i, 1),
|
49
|
+
end_d: Date.new(to_year.to_i, to_month.to_i, -1)
|
50
|
+
)
|
43
51
|
end
|
44
52
|
|
45
|
-
def self.by_code(code, from_year, from_month, to_year = from_year, to_month = from_month)
|
53
|
+
def self.by_code(code, from_year, from_month, to_year = from_year, to_month = from_month, recursive: false)
|
54
|
+
code = search_code(code) if code
|
46
55
|
date = Date.new(from_year.to_i, from_month.to_i, -1)
|
47
56
|
last_date = Date.new(to_year.to_i, to_month.to_i, -1)
|
48
57
|
raise 'invalid term specified' if date > last_date
|
49
58
|
|
50
|
-
|
59
|
+
balance = start_balance(date.year, date.month, recursive: recursive)[code] || 0
|
60
|
+
first_line = { 'code' => nil, 'label' => nil, 'debit_amount' => nil, 'debit_count' => nil, 'credit_amount' => nil, 'credit_count' => nil, 'net' => nil, 'balance' => balance, '_d' => nil }
|
61
|
+
reports = [first_line].tap do |r|
|
51
62
|
while date <= last_date do
|
52
63
|
diff = {}.tap do |h|
|
53
|
-
g = gross(date.year, date.month, code: code)
|
64
|
+
g = gross(date.year, date.month, code: code, recursive: recursive)
|
54
65
|
sum = g.dig(:debit).nil? ? BigDecimal('0') : Util.calc_diff(g[:debit], code)
|
55
66
|
sum -= g.dig(:credit).nil? ? BigDecimal('0') : Util.calc_diff(g[:credit], code)
|
67
|
+
balance += sum
|
56
68
|
h['code'] = code
|
57
|
-
h['label'] =
|
58
|
-
h['net'] = sum
|
69
|
+
h['label'] = @@dict.dig(code, :label)
|
59
70
|
h['debit_amount'] = g[:debit]
|
60
71
|
h['debit_count'] = g[:debit_count]
|
61
72
|
h['credit_amount'] = g[:credit]
|
62
73
|
h['credit_count'] = g[:credit_count]
|
74
|
+
h['net'] = sum
|
75
|
+
h['balance'] = balance
|
63
76
|
h['_d'] = date.to_s
|
64
77
|
end
|
65
78
|
r << diff
|
@@ -70,10 +83,10 @@ module LucaBook
|
|
70
83
|
end
|
71
84
|
|
72
85
|
def code2label
|
73
|
-
@statement ||= @
|
86
|
+
@statement ||= @monthly
|
74
87
|
@statement.map do |report|
|
75
88
|
{}.tap do |h|
|
76
|
-
report.each { |k, v| h[
|
89
|
+
report.each { |k, v| h[@@dict.dig(k, :label) || k] = v }
|
77
90
|
end
|
78
91
|
end
|
79
92
|
end
|
@@ -98,25 +111,45 @@ module LucaBook
|
|
98
111
|
data.sort.to_h
|
99
112
|
end
|
100
113
|
keys.map! { |k| k[0, level] }.uniq.select! { |k| k.length <= level } if level
|
101
|
-
@count.prepend({}.tap { |header| keys.each { |k| header[k] =
|
114
|
+
@count.prepend({}.tap { |header| keys.each { |k| header[k] = @@dict.dig(k, :label) }})
|
102
115
|
@count
|
103
116
|
end
|
104
117
|
|
118
|
+
# TODO: pl/bs may not be immutable
|
119
|
+
def report_mail(level = 3)
|
120
|
+
@company = CONFIG.dig('company', 'name')
|
121
|
+
{}.tap do |res|
|
122
|
+
pl(level).reverse.each do |month|
|
123
|
+
month.each do |k, v|
|
124
|
+
res[k] ||= []
|
125
|
+
res[k] << v
|
126
|
+
end
|
127
|
+
end
|
128
|
+
@months = res['_d']
|
129
|
+
@pl = res.select{ |k,v| k != '_d' }
|
130
|
+
end
|
131
|
+
@bs = bs
|
132
|
+
|
133
|
+
mail = Mail.new
|
134
|
+
mail.to = CONFIG.dig('mail', 'preview') || CONFIG.dig('mail', 'from')
|
135
|
+
mail.subject = 'Financial Report available'
|
136
|
+
mail.html_part = Mail::Part.new(body: render_erb(search_template('monthly-report.html.erb')), content_type: 'text/html; charset=UTF-8')
|
137
|
+
LucaSupport::Mail.new(mail, PJDIR).deliver
|
138
|
+
end
|
139
|
+
|
105
140
|
def bs(level = 3, legal: false)
|
106
|
-
|
107
|
-
|
108
|
-
@data.map! { |data| code_sum(data).merge(data) } if legal
|
109
|
-
base = accumulate_balance(@data)
|
141
|
+
set_bs(level, legal: legal)
|
142
|
+
base = accumulate_balance(@bs_data)
|
110
143
|
rows = [base[:debit].length, base[:credit].length].max
|
111
144
|
@statement = [].tap do |a|
|
112
145
|
rows.times do |i|
|
113
146
|
{}.tap do |res|
|
114
|
-
res['debit_label'] = base[:debit][i] ?
|
115
|
-
res['debit_balance'] = base[:debit][i] ? (@start_balance.dig(base[:debit][i].keys[0]) || 0) + base[:debit][i].values[0] : ''
|
116
|
-
res['
|
147
|
+
res['debit_label'] = base[:debit][i] ? @@dict.dig(base[:debit][i].keys[0], :label) : ''
|
148
|
+
#res['debit_balance'] = base[:debit][i] ? (@start_balance.dig(base[:debit][i].keys[0]) || 0) + base[:debit][i].values[0] : ''
|
149
|
+
res['debit_balance'] = base[:debit][i] ? base[:debit][i].values[0] : ''
|
117
150
|
res['credit_label'] = base[:credit][i] ? @dict.dig(base[:credit][i].keys[0], :label) : ''
|
118
|
-
res['credit_balance'] = base[:credit][i] ? (@start_balance.dig(base[:credit][i].keys[0]) || 0) + base[:credit][i].values[0] : ''
|
119
|
-
res['
|
151
|
+
#res['credit_balance'] = base[:credit][i] ? (@start_balance.dig(base[:credit][i].keys[0]) || 0) + base[:credit][i].values[0] : ''
|
152
|
+
res['credit_balance'] = base[:credit][i] ? base[:credit][i].values[0] : ''
|
120
153
|
a << res
|
121
154
|
end
|
122
155
|
end
|
@@ -124,12 +157,7 @@ module LucaBook
|
|
124
157
|
readable(@statement)
|
125
158
|
end
|
126
159
|
|
127
|
-
def accumulate_balance(
|
128
|
-
data = monthly_diffs.each_with_object({}) do |month, h|
|
129
|
-
month.each do |k, v|
|
130
|
-
h[k] = h[k].nil? ? v : h[k] + v
|
131
|
-
end
|
132
|
-
end
|
160
|
+
def accumulate_balance(data)
|
133
161
|
{ debit: [], credit: [] }.tap do |res|
|
134
162
|
data.sort.to_h.each do |k, v|
|
135
163
|
case k
|
@@ -143,31 +171,22 @@ module LucaBook
|
|
143
171
|
end
|
144
172
|
|
145
173
|
def pl(level = 2)
|
146
|
-
|
147
|
-
|
148
|
-
fy = @start_balance.select { |k, _v| /^[A-H].+/.match(k) }
|
149
|
-
keys = (term_keys + fy.keys).uniq.sort
|
150
|
-
keys.select! { |k| k.length <= level }
|
151
|
-
@statement = @data.map do |data|
|
174
|
+
set_pl(level)
|
175
|
+
@statement = @monthly.map do |data|
|
152
176
|
{}.tap do |h|
|
153
|
-
keys.each { |k| h[k] = data[k] || BigDecimal('0') }
|
177
|
+
@pl_data.keys.each { |k| h[k] = data[k] || BigDecimal('0') }
|
154
178
|
end
|
155
179
|
end
|
156
|
-
|
157
|
-
item.each do |k, v|
|
158
|
-
h[k] = h[k].nil? ? v : h[k] + v if /^[^_]/.match(k)
|
159
|
-
end
|
160
|
-
end
|
161
|
-
fy = {}.tap do |h|
|
162
|
-
keys.each do |k|
|
163
|
-
h[k] = BigDecimal(fy[k] || '0') + BigDecimal(term[k] || '0')
|
164
|
-
end
|
165
|
-
end
|
166
|
-
@statement << term.tap { |h| h['_d'] = 'Period Total' }
|
167
|
-
@statement << fy.tap { |h| h['_d'] = 'FY Total' }
|
180
|
+
@statement << @pl_data
|
168
181
|
readable(code2label)
|
169
182
|
end
|
170
183
|
|
184
|
+
#
|
185
|
+
def net_income
|
186
|
+
set_pl(2)
|
187
|
+
@pl_data['HA']
|
188
|
+
end
|
189
|
+
|
171
190
|
def self.accumulate_term(start_year, start_month, end_year, end_month)
|
172
191
|
date = Date.new(start_year, start_month, 1)
|
173
192
|
last_date = Date.new(end_year, end_month, -1)
|
@@ -183,60 +202,6 @@ module LucaBook
|
|
183
202
|
end
|
184
203
|
end
|
185
204
|
|
186
|
-
def self.accumulate_month(year, month)
|
187
|
-
monthly_record, count = net(year, month)
|
188
|
-
[total_subaccount(monthly_record), count]
|
189
|
-
end
|
190
|
-
|
191
|
-
# Accumulate Level 2, 3 account.
|
192
|
-
#
|
193
|
-
def self.total_subaccount(report)
|
194
|
-
{}.tap do |res|
|
195
|
-
res['A0'] = sum_matched(report, /^[A][0-9A-Z]{2,}/)
|
196
|
-
res['B0'] = sum_matched(report, /^[B][0-9A-Z]{2,}/)
|
197
|
-
res['BA'] = res['A0'] - res['B0']
|
198
|
-
res['C0'] = sum_matched(report, /^[C][0-9A-Z]{2,}/)
|
199
|
-
res['CA'] = res['BA'] - res['C0']
|
200
|
-
res['D0'] = sum_matched(report, /^[D][0-9A-Z]{2,}/)
|
201
|
-
res['E0'] = sum_matched(report, /^[E][0-9A-Z]{2,}/)
|
202
|
-
res['EA'] = res['CA'] + res['D0'] - res['E0']
|
203
|
-
res['F0'] = sum_matched(report, /^[F][0-9A-Z]{2,}/)
|
204
|
-
res['G0'] = sum_matched(report, /^[G][0-9][0-9A-Z]{1,}/)
|
205
|
-
res['GA'] = res['EA'] + res['F0'] - res['G0']
|
206
|
-
res['H0'] = sum_matched(report, /^[H][0-9][0-9A-Z]{1,}/)
|
207
|
-
res['HA'] = res['GA'] - res['H0']
|
208
|
-
|
209
|
-
report['9142'] = (report['9142'] || BigDecimal('0')) + res['HA']
|
210
|
-
res['9142'] = report['9142']
|
211
|
-
res['10'] = sum_matched(report, /^[123][0-9A-Z]{2,}/)
|
212
|
-
res['40'] = sum_matched(report, /^[4][0-9A-Z]{2,}/)
|
213
|
-
res['50'] = sum_matched(report, /^[56][0-9A-Z]{2,}/)
|
214
|
-
res['70'] = sum_matched(report, /^[78][0-9A-Z]{2,}/)
|
215
|
-
res['91'] = sum_matched(report, /^91[0-9A-Z]{1,}/)
|
216
|
-
res['8ZZ'] = res['50'] + res['70']
|
217
|
-
res['9ZZ'] = sum_matched(report, /^[9][0-9A-Z]{2,}/)
|
218
|
-
|
219
|
-
res['1'] = res['10'] + res['40']
|
220
|
-
res['5'] = res['8ZZ'] + res['9ZZ']
|
221
|
-
res['_d'] = report['_d']
|
222
|
-
|
223
|
-
report.each do |k, v|
|
224
|
-
res[k] = v if k.length == 3
|
225
|
-
end
|
226
|
-
|
227
|
-
report.each do |k, v|
|
228
|
-
if k.length >= 4
|
229
|
-
if res[k[0, 3]]
|
230
|
-
res[k[0, 3]] += v
|
231
|
-
else
|
232
|
-
res[k[0, 3]] = v
|
233
|
-
end
|
234
|
-
end
|
235
|
-
end
|
236
|
-
res.sort.to_h
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
205
|
def code_sum(report)
|
241
206
|
legal_items.each.with_object({}) do |k, h|
|
242
207
|
h[k] = self.class.sum_matched(report, /^#{k}.*/)
|
@@ -244,114 +209,117 @@ module LucaBook
|
|
244
209
|
end
|
245
210
|
|
246
211
|
def set_balance
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
base = Dict.latest_balance.each_with_object({}) do |(k, v), h|
|
212
|
+
@start_balance = self.class.start_balance(@start_date.year, @start_date.month)
|
213
|
+
end
|
214
|
+
|
215
|
+
def self.start_balance(year, month, recursive: true)
|
216
|
+
start_date = Date.new(year, month, 1)
|
217
|
+
base = Dict.latest_balance(start_date).each_with_object({}) do |(k, v), h|
|
255
218
|
h[k] = BigDecimal(v[:balance].to_s) if v[:balance]
|
219
|
+
h[k] ||= BigDecimal('0') if k.length == 2
|
220
|
+
end
|
221
|
+
if month == CONFIG['fy_start'].to_i
|
222
|
+
return recursive ? total_subaccount(base) : base
|
256
223
|
end
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
224
|
+
|
225
|
+
pre_last = start_date.prev_month
|
226
|
+
year -= 1 if month <= CONFIG['fy_start'].to_i
|
227
|
+
pre = accumulate_term(year, CONFIG['fy_start'], pre_last.year, pre_last.month)
|
228
|
+
total = {}.tap do |h|
|
229
|
+
(pre.keys + base.keys).uniq.each do |k|
|
230
|
+
h[k] = (base[k] || BigDecimal('0')) + (pre[k] || BigDecimal('0'))
|
261
231
|
end
|
262
232
|
end
|
263
|
-
|
233
|
+
recursive ? total_subaccount(total) : total
|
264
234
|
end
|
265
235
|
|
266
|
-
def
|
267
|
-
|
236
|
+
def render_xbrl(filename = nil)
|
237
|
+
set_bs(3, legal: true)
|
238
|
+
set_pl(3)
|
239
|
+
country_suffix = CONFIG['country'] || 'en'
|
240
|
+
@company = CGI.escapeHTML(CONFIG.dig('company', 'name'))
|
241
|
+
@balance_sheet_selected = 'true'
|
242
|
+
@pl_selected = 'true'
|
243
|
+
@capital_change_selected = 'true'
|
244
|
+
@issue_date = Date.today
|
245
|
+
|
246
|
+
prior_bs = @start_balance.filter { |k, _v| /^[9]/.match(k) }
|
247
|
+
@xbrl_entries = @bs_data.map{ |k, v| xbrl_line(k, v, prior_bs[k]) }.compact.join("\n")
|
248
|
+
@xbrl_entries += @pl_data.map{ |k, v| xbrl_line(k, v) }.compact.join("\n")
|
249
|
+
@filename = filename || @issue_date.to_s
|
250
|
+
|
251
|
+
File.open("#{@filename}.xbrl", 'w') { |f| f.write render_erb(search_template("base-#{country_suffix}.xbrl.erb")) }
|
252
|
+
File.open("#{@filename}.xsd", 'w') { |f| f.write render_erb(search_template("base-#{country_suffix}.xsd.erb")) }
|
268
253
|
end
|
269
254
|
|
270
|
-
|
271
|
-
|
272
|
-
def self.gross(start_year, start_month, end_year = nil, end_month = nil, code: nil, date_range: nil, rows: 4)
|
273
|
-
if ! date_range.nil?
|
274
|
-
raise if date_range.class != Range
|
275
|
-
# TODO: date based range search
|
276
|
-
end
|
255
|
+
def xbrl_line(code, amount, prior_amount = nil)
|
256
|
+
return nil if /^_/.match(code)
|
277
257
|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
next if code && !idx_memo.include?(code)
|
298
|
-
|
299
|
-
row.each_with_index do |r, j|
|
300
|
-
sum[:debit][idx_memo[j]] += BigDecimal(r.to_s)
|
301
|
-
sum[:debit_count][idx_memo[j]] += 1
|
302
|
-
end
|
303
|
-
when 2
|
304
|
-
idx_memo = row.map(&:to_s)
|
305
|
-
break if code && !idx_memo.include?(code)
|
306
|
-
|
307
|
-
idx_memo.each do |r|
|
308
|
-
sum[:credit][r] ||= BigDecimal('0')
|
309
|
-
sum[:credit_count][r] ||= 0
|
310
|
-
end
|
311
|
-
when 3
|
312
|
-
row.each_with_index do |r, j|
|
313
|
-
sum[:credit][idx_memo[j]] += BigDecimal(r.to_s)
|
314
|
-
sum[:credit_count][idx_memo[j]] += 1
|
315
|
-
end
|
316
|
-
else
|
317
|
-
puts row # for debug
|
318
|
-
end
|
258
|
+
context = /^[0-9]/.match(code) ? 'CurrentYearNonConsolidatedInstant' : 'CurrentYearNonConsolidatedDuration'
|
259
|
+
tag = @@dict.dig(code, :xbrl_id)
|
260
|
+
#raise "xbrl_id not found: #{code}" if tag.nil?
|
261
|
+
return nil if tag.nil?
|
262
|
+
return nil if readable(amount).zero? && prior_amount.nil?
|
263
|
+
|
264
|
+
prior = prior_amount.nil? ? '' : "<#{tag} decimals=\"0\" unitRef=\"JPY\" contextRef=\"Prior1YearNonConsolidatedInstant\">#{readable(prior_amount)}</#{tag}>\n"
|
265
|
+
current = "<#{tag} decimals=\"0\" unitRef=\"JPY\" contextRef=\"#{context}\">#{readable(amount)}</#{tag}>"
|
266
|
+
|
267
|
+
prior + current
|
268
|
+
end
|
269
|
+
|
270
|
+
def self.search_code(code)
|
271
|
+
return code if @@dict.dig(code)
|
272
|
+
|
273
|
+
@@dict.search(code).tap do |new_code|
|
274
|
+
if new_code.nil?
|
275
|
+
puts "Search word is not matched with labels"
|
276
|
+
exit 1
|
319
277
|
end
|
320
278
|
end
|
321
|
-
if code
|
322
|
-
sum[:debit] = sum[:debit][code] || BigDecimal('0')
|
323
|
-
sum[:credit] = sum[:credit][code] || BigDecimal('0')
|
324
|
-
sum[:debit_count] = sum[:debit_count][code] || 0
|
325
|
-
sum[:credit_count] = sum[:credit_count][code] || 0
|
326
|
-
end
|
327
|
-
sum
|
328
279
|
end
|
329
280
|
|
330
|
-
|
331
|
-
|
332
|
-
def
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
281
|
+
private
|
282
|
+
|
283
|
+
def set_bs(level = 3, legal: false)
|
284
|
+
@start_balance.each do |k, v|
|
285
|
+
next if /^_/.match(k)
|
286
|
+
@monthly.first[k] = (v || 0) + (@monthly.first[k] || 0)
|
287
|
+
end
|
288
|
+
list = @monthly.map { |data| data.select { |k, _v| k.length <= level } }
|
289
|
+
list.map! { |data| code_sum(data).merge(data) } if legal
|
290
|
+
@bs_data = list.each_with_object({}) do |month, h|
|
291
|
+
month.each do |k, v|
|
292
|
+
next if /^_/.match(k)
|
293
|
+
|
294
|
+
h[k] = (h[k] || BigDecimal('0')) + v
|
341
295
|
end
|
342
296
|
end
|
343
|
-
[diff, count]
|
344
297
|
end
|
345
298
|
|
346
|
-
|
299
|
+
def set_pl(level = 2)
|
300
|
+
keys = @monthly.inject([]) { |a, data| a + data.keys }
|
301
|
+
.compact.select { |k| /^[A-H_].+/.match(k) }
|
302
|
+
.uniq.sort
|
303
|
+
keys.select! { |k| k.length <= level }
|
304
|
+
@pl_data = @monthly.each_with_object({}) do |item, h|
|
305
|
+
keys.each do |k|
|
306
|
+
h[k] = (h[k] || BigDecimal('0')) + (item[k] || BigDecimal('0')) if /^[^_]/.match(k)
|
307
|
+
end
|
308
|
+
h['_d'] = 'Period Total'
|
309
|
+
end
|
310
|
+
end
|
347
311
|
|
348
312
|
def legal_items
|
349
|
-
return [] unless
|
313
|
+
return [] unless CONFIG['country']
|
350
314
|
|
351
|
-
case
|
315
|
+
case CONFIG['country']
|
352
316
|
when 'jp'
|
353
|
-
['91', '911', '912', '913', '9131', '9132', '914', '9141', '9142', '915', '916', '92', '93']
|
317
|
+
['31', '32', '33', '91', '911', '912', '913', '9131', '9132', '914', '9141', '9142', '915', '916', '92', '93']
|
354
318
|
end
|
355
319
|
end
|
320
|
+
|
321
|
+
def lib_path
|
322
|
+
__dir__
|
323
|
+
end
|
356
324
|
end
|
357
325
|
end
|