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.
@@ -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
@@ -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::Config::Pjdir)
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
@@ -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, date: nil)
21
- @data = data
25
+ def initialize(data, count = nil, start_d: nil, end_d: nil)
26
+ @monthly = data
22
27
  @count = count
23
- @dict = LucaRecord::Dict.load('base.tsv')
24
- @start_date = date
25
- @start_balance = set_balance
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, date: Date.new(from_year.to_i, from_month.to_i, -1))
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
- reports = [].tap do |r|
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'] = LucaRecord::Dict.load('base.tsv').dig(code, :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 ||= @data
86
+ @statement ||= @monthly
74
87
  @statement.map do |report|
75
88
  {}.tap do |h|
76
- report.each { |k, v| h[@dict.dig(k, :label) || k] = v }
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] = @dict.dig(k, :label) }})
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
- @start_balance.keys.each { |k| @data.first[k] ||= 0 }
107
- @data.map! { |data| data.select { |k, _v| k.length <= level } }
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] ? @dict.dig(base[:debit][i].keys[0], :label) : ''
115
- res['debit_balance'] = base[:debit][i] ? (@start_balance.dig(base[:debit][i].keys[0]) || 0) + base[:debit][i].values[0] : ''
116
- res['debit_diff'] = base[:debit][i] ? base[:debit][i].values[0] : ''
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['credit_diff'] = base[:credit][i] ? base[:credit][i].values[0] : ''
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(monthly_diffs)
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
- term_keys = @data.inject([]) { |a, data| a + data.keys }
147
- .compact.select { |k| /^[A-H_].+/.match(k) }
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
- term = @statement.each_with_object({}) do |item, h|
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
- pre_last = @start_date.prev_month
248
- pre = if @start_date.month > LucaSupport::CONFIG['fy_start'].to_i
249
- self.class.accumulate_term(pre_last.year, LucaSupport::CONFIG['fy_start'], pre_last.year, pre_last.month)
250
- elsif @start_date.month < LucaSupport::CONFIG['fy_start'].to_i
251
- self.class.accumulate_term(pre_last.year - 1, LucaSupport::CONFIG['fy_start'], pre_last.year, pre_last.month)
252
- end
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
- if pre
258
- idx = (pre.keys + base.keys).uniq
259
- base = {}.tap do |h|
260
- idx.each { |k| h[k] = (base[k] || BigDecimal('0')) + (pre[k] || BigDecimal('0')) }
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
- self.class.total_subaccount(base)
233
+ recursive ? total_subaccount(total) : total
264
234
  end
265
235
 
266
- def self.sum_matched(report, reg)
267
- report.select { |k, v| reg.match(k)}.values.sum
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
- # for assert purpose
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
- end_year ||= start_year
279
- end_month ||= start_month
280
- sum = { debit: {}, credit: {}, debit_count: {}, credit_count: {} }
281
- idx_memo = []
282
- term(start_year, start_month, end_year, end_month, code) do |f, _path|
283
- CSV.new(f, headers: false, col_sep: "\t", encoding: 'UTF-8')
284
- .each_with_index do |row, i|
285
- break if i >= rows
286
-
287
- case i
288
- when 0
289
- idx_memo = row.map(&:to_s)
290
- next if code && !idx_memo.include?(code)
291
-
292
- idx_memo.each do |r|
293
- sum[:debit][r] ||= BigDecimal('0')
294
- sum[:debit_count][r] ||= 0
295
- end
296
- when 1
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
- # netting vouchers in specified term
331
- #
332
- def self.net(start_year, start_month, end_year = nil, end_month = nil, code: nil, date_range: nil)
333
- g = gross(start_year, start_month, end_year, end_month, code: code, date_range: date_range)
334
- idx = (g[:debit].keys + g[:credit].keys).uniq.sort
335
- count = {}
336
- diff = {}.tap do |sum|
337
- idx.each do |code|
338
- sum[code] = g.dig(:debit, code).nil? ? BigDecimal('0') : Util.calc_diff(g[:debit][code], code)
339
- sum[code] -= g.dig(:credit, code).nil? ? BigDecimal('0') : Util.calc_diff(g[:credit][code], code)
340
- count[code] = (g.dig(:debit_count, code) || 0) + (g.dig(:credit_count, code) || 0)
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
- private
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 LucaSupport::Config::COUNTRY
313
+ return [] unless CONFIG['country']
350
314
 
351
- case LucaSupport::Config::COUNTRY
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