lucabook 0.2.12 → 0.2.20
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 +123 -50
- data/lib/luca_book.rb +4 -0
- data/lib/luca_book/console.rb +7 -15
- data/lib/luca_book/dict.rb +10 -3
- data/lib/luca_book/import.rb +49 -41
- data/lib/luca_book/journal.rb +4 -1
- data/lib/luca_book/list.rb +138 -0
- data/lib/luca_book/setup.rb +16 -1
- data/lib/luca_book/state.rb +223 -110
- data/lib/luca_book/templates/base-jp.xbrl.erb +78 -0
- data/lib/luca_book/templates/dict-en.tsv +35 -31
- data/lib/luca_book/templates/dict-jp.tsv +163 -145
- data/lib/luca_book/util.rb +46 -0
- data/lib/luca_book/version.rb +1 -1
- metadata +5 -3
- data/lib/luca_book/report.rb +0 -3
data/lib/luca_book/journal.rb
CHANGED
@@ -30,6 +30,9 @@ module LucaBook
|
|
30
30
|
f << LucaSupport::Code.readable(debit_amount)
|
31
31
|
f << credit_code
|
32
32
|
f << LucaSupport::Code.readable(credit_amount)
|
33
|
+
['x-customer', 'x-editor'].each do |x_header|
|
34
|
+
f << [x_header, d[x_header]] if d.dig(x_header)
|
35
|
+
end
|
33
36
|
f << []
|
34
37
|
f << [d.dig('note')]
|
35
38
|
end
|
@@ -80,8 +83,8 @@ module LucaBook
|
|
80
83
|
record[:note] << line.join(' ') if body
|
81
84
|
end
|
82
85
|
end
|
83
|
-
record[:note]&.join('\n')
|
84
86
|
end
|
87
|
+
record[:note] = record[:note]&.join('\n')
|
85
88
|
end
|
86
89
|
end
|
87
90
|
end
|
@@ -0,0 +1,138 @@
|
|
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
|
+
# Journal List on specified term
|
11
|
+
#
|
12
|
+
module LucaBook
|
13
|
+
class List < LucaBook::Journal
|
14
|
+
@dirname = 'journals'
|
15
|
+
|
16
|
+
def initialize(data, start_date, code = nil)
|
17
|
+
@data = data
|
18
|
+
@code = code
|
19
|
+
@start = start_date
|
20
|
+
@dict = LucaRecord::Dict.load('base.tsv')
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.term(from_year, from_month, to_year = from_year, to_month = from_month, code: nil, basedir: @dirname)
|
24
|
+
data = LucaBook::Journal.term(from_year, from_month, to_year, to_month, code).select do |dat|
|
25
|
+
if code.nil?
|
26
|
+
true
|
27
|
+
else
|
28
|
+
[:debit, :credit].map { |key| serialize_on_key(dat[key], :code) }.flatten.include?(code)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
new data, Date.new(from_year.to_i, from_month.to_i, 1), code
|
32
|
+
end
|
33
|
+
|
34
|
+
def list_on_code
|
35
|
+
calc_code
|
36
|
+
convert_label
|
37
|
+
@data = [code_header] + @data.map do |dat|
|
38
|
+
date, txid = LucaSupport::Code.decode_id(dat[:id])
|
39
|
+
{}.tap do |res|
|
40
|
+
res['code'] = dat[:code]
|
41
|
+
res['date'] = date
|
42
|
+
res['no'] = txid
|
43
|
+
res['id'] = dat[:id]
|
44
|
+
res['diff'] = dat[:diff]
|
45
|
+
res['balance'] = dat[:balance]
|
46
|
+
res['counter_code'] = dat[:counter_code].length == 1 ? dat[:counter_code].first : dat[:counter_code]
|
47
|
+
res['note'] = dat[:note]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def list_journals
|
54
|
+
convert_label
|
55
|
+
@data = @data.map do |dat|
|
56
|
+
date, txid = LucaSupport::Code.decode_id(dat[:id])
|
57
|
+
{}.tap do |res|
|
58
|
+
res['date'] = date
|
59
|
+
res['no'] = txid
|
60
|
+
res['id'] = dat[:id]
|
61
|
+
res['debit_code'] = dat[:debit].length == 1 ? dat[:debit][0][:code] : dat[:debit].map { |d| d[:code] }
|
62
|
+
res['debit_amount'] = dat[:debit].inject(0) { |sum, d| sum + d[:amount] }
|
63
|
+
res['credit_code'] = dat[:credit].length == 1 ? dat[:credit][0][:code] : dat[:credit].map { |d| d[:code] }
|
64
|
+
res['credit_amount'] = dat[:credit].inject(0) { |sum, d| sum + d[:amount] }
|
65
|
+
res['note'] = dat[:note]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
def accumulate_code
|
72
|
+
@data.inject(BigDecimal('0')) do |sum, dat|
|
73
|
+
sum + Util.diff_by_code(dat[:debit], @code) - Util.diff_by_code(dat[:credit], @code)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_yaml
|
78
|
+
YAML.dump(LucaSupport::Code.readable(@data)).tap { |data| puts data }
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def set_balance
|
84
|
+
return BigDecimal('0') if @code.nil? || /^[A-H]/.match(@code)
|
85
|
+
|
86
|
+
balance_dict = Dict.latest_balance
|
87
|
+
start_balance = BigDecimal(balance_dict.dig(@code.to_s, :balance) || '0')
|
88
|
+
start = Dict.issue_date(balance_dict)&.next_month
|
89
|
+
last = @start.prev_month
|
90
|
+
if last.year >= start.year && last.month >= start.month
|
91
|
+
start_balance + self.class.term(start.year, start.month, last.year, last.month, code: @code).accumulate_code
|
92
|
+
else
|
93
|
+
start_balance
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def calc_code
|
98
|
+
@balance = set_balance
|
99
|
+
if @code
|
100
|
+
balance = @balance
|
101
|
+
@data.each do |dat|
|
102
|
+
dat[:diff] = Util.diff_by_code(dat[:debit], @code) - Util.diff_by_code(dat[:credit], @code)
|
103
|
+
balance += dat[:diff]
|
104
|
+
dat[:balance] = balance
|
105
|
+
dat[:code] = @code
|
106
|
+
counter = dat[:diff] * Util.pn_debit(@code) > 0 ? :credit : :debit
|
107
|
+
dat[:counter_code] = dat[counter].map { |d| d[:code] }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
self
|
111
|
+
end
|
112
|
+
|
113
|
+
def convert_label
|
114
|
+
@data.each do |dat|
|
115
|
+
if @code
|
116
|
+
dat[:code] = "#{dat[:code]} #{@dict.dig(dat[:code], :label)}"
|
117
|
+
dat[:counter_code] = dat[:counter_code].map { |counter| "#{counter} #{@dict.dig(counter, :label)}" }
|
118
|
+
else
|
119
|
+
dat[:debit].each { |debit| debit[:code] = "#{debit[:code]} #{@dict.dig(debit[:code], :label)}" }
|
120
|
+
dat[:credit].each { |credit| credit[:code] = "#{credit[:code]} #{@dict.dig(credit[:code], :label)}" }
|
121
|
+
end
|
122
|
+
end
|
123
|
+
self
|
124
|
+
end
|
125
|
+
|
126
|
+
def dict
|
127
|
+
LucaBook::Dict::Data
|
128
|
+
end
|
129
|
+
|
130
|
+
def code_header
|
131
|
+
{}.tap do |h|
|
132
|
+
%w[code date no id diff balance counter_code note].each do |k|
|
133
|
+
h[k] = k == 'balance' ? @balance : ''
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/lib/luca_book/setup.rb
CHANGED
@@ -9,7 +9,7 @@ module LucaBook
|
|
9
9
|
def self.create_project(country = nil, dir = LucaSupport::Config::Pjdir)
|
10
10
|
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
11
11
|
Dir.chdir(dir) do
|
12
|
-
%w[data/journals dict].each do |subdir|
|
12
|
+
%w[data/journals data/balance dict].each do |subdir|
|
13
13
|
FileUtils.mkdir_p(subdir) unless Dir.exist?(subdir)
|
14
14
|
end
|
15
15
|
dict = if File.exist?("#{__dir__}/templates/dict-#{country}.tsv")
|
@@ -18,6 +18,21 @@ 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
|
+
prepare_starttsv(dict) unless File.exist? 'data/balance/start.tsv'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Generate initial balance template.
|
26
|
+
# Codes are same as base dictionary.
|
27
|
+
# The previous month of start date is better for _date.
|
28
|
+
#
|
29
|
+
def self.prepare_starttsv(dict)
|
30
|
+
CSV.open('data/balance/start.tsv', 'w', col_sep: "\t", encoding: 'UTF-8') do |csv|
|
31
|
+
csv << ['code', 'label', 'balance']
|
32
|
+
csv << ['_date', '2020-1-1']
|
33
|
+
CSV.open("#{__dir__}/templates/#{dict}", 'r', col_sep: "\t", encoding: 'UTF-8').each do |row|
|
34
|
+
csv << row if /^[1-9]/.match(row[0])
|
35
|
+
end
|
21
36
|
end
|
22
37
|
end
|
23
38
|
end
|
data/lib/luca_book/state.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
require 'csv'
|
3
4
|
require 'pathname'
|
@@ -7,7 +8,6 @@ require 'luca_record'
|
|
7
8
|
require 'luca_record/dict'
|
8
9
|
require 'luca_book'
|
9
10
|
|
10
|
-
#
|
11
11
|
# Statement on specified term
|
12
12
|
#
|
13
13
|
module LucaBook
|
@@ -17,9 +17,12 @@ module LucaBook
|
|
17
17
|
|
18
18
|
attr_reader :statement
|
19
19
|
|
20
|
-
def initialize(data)
|
20
|
+
def initialize(data, count = nil, date: nil)
|
21
21
|
@data = data
|
22
|
+
@count = count
|
22
23
|
@dict = LucaRecord::Dict.load('base.tsv')
|
24
|
+
@start_date = date
|
25
|
+
@start_balance = set_balance
|
23
26
|
end
|
24
27
|
|
25
28
|
# TODO: not compatible with LucaRecord::Base.open_records
|
@@ -41,106 +44,206 @@ module LucaBook
|
|
41
44
|
last_date = Date.new(to_year.to_i, to_month.to_i, -1)
|
42
45
|
raise 'invalid term specified' if date > last_date
|
43
46
|
|
47
|
+
counts = []
|
44
48
|
reports = [].tap do |r|
|
45
49
|
while date <= last_date do
|
46
|
-
|
47
|
-
|
50
|
+
diff, count = accumulate_month(date.year, date.month)
|
51
|
+
r << diff.tap { |c| c['_d'] = date.to_s }
|
52
|
+
counts << count.tap { |c| c['_d'] = date.to_s }
|
53
|
+
date = Date.new(date.next_month.year, date.next_month.month, -1)
|
48
54
|
end
|
49
55
|
end
|
50
|
-
new
|
56
|
+
new(reports, counts, date: Date.new(from_year.to_i, from_month.to_i, -1))
|
51
57
|
end
|
52
58
|
|
53
59
|
def by_code(code, year=nil, month=nil)
|
54
|
-
raise
|
60
|
+
raise 'not supported year range yet' if ! year.nil? && month.nil?
|
55
61
|
|
56
|
-
|
57
|
-
full_term = scan_terms
|
62
|
+
balance = @book.load_start.dig(code) || 0
|
63
|
+
full_term = self.class.scan_terms
|
58
64
|
if ! month.nil?
|
59
|
-
pre_term = full_term.select{|y,m| y <= year.to_i && m < month.to_i }
|
60
|
-
|
61
|
-
[{ code: code, balance:
|
65
|
+
pre_term = full_term.select { |y, m| y <= year.to_i && m < month.to_i }
|
66
|
+
balance += pre_term.map { |y, m| self.class.net(y, m)}.inject(0){|sum, h| sum + h[code] }
|
67
|
+
[{ code: code, balance: balance, note: "#{code} #{@dict.dig(code, :label)}" }] + records_with_balance(year, month, code, balance)
|
62
68
|
else
|
63
|
-
start = { code: code, balance:
|
64
|
-
full_term.map {|y, m| y }.uniq.map {|y|
|
65
|
-
records_with_balance(y, nil, code,
|
69
|
+
start = { code: code, balance: balance, note: "#{code} #{@dict.dig(code, :label)}" }
|
70
|
+
full_term.map { |y, m| y }.uniq.map { |y|
|
71
|
+
records_with_balance(y, nil, code, balance)
|
66
72
|
}.flatten.prepend(start)
|
67
73
|
end
|
68
74
|
end
|
69
75
|
|
70
76
|
def records_with_balance(year, month, code, balance)
|
71
77
|
@book.search(year, month, nil, code).each do |h|
|
72
|
-
balance +=
|
78
|
+
balance += Util.calc_diff(Util.amount_by_code(h[:debit], code), code) - Util.calc_diff(Util.amount_by_code(h[:credit], code), code)
|
73
79
|
h[:balance] = balance
|
74
80
|
end
|
75
81
|
end
|
76
82
|
|
77
|
-
#
|
78
|
-
# TODO: useless method. consider to remove
|
79
|
-
#
|
80
|
-
def accumulate_all
|
81
|
-
current = @book.load_start
|
82
|
-
target = []
|
83
|
-
Dir.chdir(@book.pjdir) do
|
84
|
-
net_records = scan_terms(@book.pjdir).map do |year, month|
|
85
|
-
target << [year, month]
|
86
|
-
accumulate_month(year, month)
|
87
|
-
end
|
88
|
-
all_keys = net_records.map{|h| h.keys}.flatten.uniq
|
89
|
-
net_records.each.with_index(0) do |diff, i|
|
90
|
-
all_keys.each {|key| diff[key] = 0 unless diff.has_key?(key)}
|
91
|
-
diff.each do |k,v|
|
92
|
-
if current[k]
|
93
|
-
current[k] += v
|
94
|
-
else
|
95
|
-
current[k] = v
|
96
|
-
end
|
97
|
-
end
|
98
|
-
f = { target: "#{target[i][0]}-#{target[i][1]}", diff: diff.sort, current: current.sort }
|
99
|
-
yield f
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
83
|
def to_yaml
|
105
|
-
YAML.dump(code2label).tap { |data| puts data }
|
84
|
+
YAML.dump(readable(code2label)).tap { |data| puts data }
|
106
85
|
end
|
107
86
|
|
108
87
|
def code2label
|
109
88
|
@statement ||= @data
|
110
89
|
@statement.map do |report|
|
111
90
|
{}.tap do |h|
|
112
|
-
report.each { |k, v| h[@dict.dig(k, :label)] = v }
|
91
|
+
report.each { |k, v| h[@dict.dig(k, :label) || k] = v }
|
113
92
|
end
|
114
93
|
end
|
115
94
|
end
|
116
95
|
|
117
|
-
def
|
118
|
-
|
119
|
-
|
96
|
+
def stats(level = nil)
|
97
|
+
keys = @count.map(&:keys).flatten.push('_t').uniq.sort
|
98
|
+
@count.map! do |data|
|
99
|
+
sum = 0
|
100
|
+
keys.each do |k|
|
101
|
+
data[k] ||= 0
|
102
|
+
sum += data[k] if /^[^_]/.match(k)
|
103
|
+
next if level.nil? || k.length <= level
|
104
|
+
|
105
|
+
if data[k[0, level]]
|
106
|
+
data[k[0, level]] += data[k]
|
107
|
+
else
|
108
|
+
data[k[0, level]] = data[k]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
data.select! { |k, _v| k.length <= level } if level
|
112
|
+
data['_t'] = sum
|
113
|
+
data.sort.to_h
|
114
|
+
end
|
115
|
+
keys.map! { |k| k[0, level] }.uniq.select! { |k| k.length <= level } if level
|
116
|
+
@count.prepend({}.tap { |header| keys.each { |k| header[k] = @dict.dig(k, :label) }})
|
117
|
+
puts YAML.dump(@count)
|
118
|
+
@count
|
119
|
+
end
|
120
|
+
|
121
|
+
def bs(level = 3, legal: false)
|
122
|
+
@start_balance.keys.each { |k| @data.first[k] ||= 0 }
|
123
|
+
@data.map! { |data| data.select { |k, _v| k.length <= level } }
|
124
|
+
@data.map! { |data| code_sum(data).merge(data) } if legal
|
125
|
+
base = accumulate_balance(@data)
|
126
|
+
rows = [base[:debit].length, base[:credit].length].max
|
127
|
+
@statement = [].tap do |a|
|
128
|
+
rows.times do |i|
|
129
|
+
{}.tap do |res|
|
130
|
+
res['debit_label'] = base[:debit][i] ? @dict.dig(base[:debit][i].keys[0], :label) : ''
|
131
|
+
res['debit_balance'] = base[:debit][i] ? (@start_balance.dig(base[:debit][i].keys[0]) || 0) + base[:debit][i].values[0] : ''
|
132
|
+
res['debit_diff'] = base[:debit][i] ? base[:debit][i].values[0] : ''
|
133
|
+
res['credit_label'] = base[:credit][i] ? @dict.dig(base[:credit][i].keys[0], :label) : ''
|
134
|
+
res['credit_balance'] = base[:credit][i] ? (@start_balance.dig(base[:credit][i].keys[0]) || 0) + base[:credit][i].values[0] : ''
|
135
|
+
res['credit_diff'] = base[:credit][i] ? base[:credit][i].values[0] : ''
|
136
|
+
a << res
|
137
|
+
end
|
138
|
+
end
|
120
139
|
end
|
140
|
+
puts YAML.dump(readable(@statement))
|
121
141
|
self
|
122
142
|
end
|
123
143
|
|
124
|
-
def
|
144
|
+
def accumulate_balance(monthly_diffs)
|
145
|
+
data = monthly_diffs.each_with_object({}) do |month, h|
|
146
|
+
month.each do |k, v|
|
147
|
+
h[k] = h[k].nil? ? v : h[k] + v
|
148
|
+
end
|
149
|
+
end
|
150
|
+
{ debit: [], credit: [] }.tap do |res|
|
151
|
+
data.sort.to_h.each do |k, v|
|
152
|
+
case k
|
153
|
+
when /^[0-4].*/
|
154
|
+
res[:debit] << { k => v }
|
155
|
+
when /^[5-9].*/
|
156
|
+
res[:credit] << { k => v }
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def pl(level = 2)
|
163
|
+
term_keys = @data.inject([]) { |a, data| a + data.keys }
|
164
|
+
.compact.select { |k| /^[A-H_].+/.match(k) }
|
165
|
+
fy = @start_balance.select { |k, _v| /^[A-H].+/.match(k) }
|
166
|
+
keys = (term_keys + fy.keys).uniq.sort
|
167
|
+
keys.select! { |k| k.length <= level }
|
125
168
|
@statement = @data.map do |data|
|
126
|
-
|
169
|
+
{}.tap do |h|
|
170
|
+
keys.each { |k| h[k] = data[k] || BigDecimal('0') }
|
171
|
+
end
|
127
172
|
end
|
173
|
+
term = @statement.each_with_object({}) do |item, h|
|
174
|
+
item.each do |k, v|
|
175
|
+
h[k] = h[k].nil? ? v : h[k] + v if /^[^_]/.match(k)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
fy = {}.tap do |h|
|
179
|
+
keys.each do |k|
|
180
|
+
h[k] = BigDecimal(fy[k] || '0') + BigDecimal(term[k] || '0')
|
181
|
+
end
|
182
|
+
end
|
183
|
+
@statement << term.tap { |h| h['_d'] = 'Period Total' }
|
184
|
+
@statement << fy.tap { |h| h['_d'] = 'FY Total' }
|
128
185
|
self
|
129
186
|
end
|
130
187
|
|
131
|
-
def self.
|
132
|
-
|
133
|
-
|
188
|
+
def self.accumulate_term(start_year, start_month, end_year, end_month)
|
189
|
+
date = Date.new(start_year, start_month, 1)
|
190
|
+
last_date = Date.new(end_year, end_month, -1)
|
191
|
+
return nil if date > last_date
|
192
|
+
|
193
|
+
{}.tap do |res|
|
194
|
+
while date <= last_date do
|
195
|
+
diff, _count = net(date.year, date.month)
|
196
|
+
diff.each do |k, v|
|
197
|
+
next if /^[_]/.match(k)
|
198
|
+
|
199
|
+
res[k] = res[k].nil? ? v : res[k] + v
|
200
|
+
end
|
201
|
+
date = date.next_month
|
202
|
+
end
|
203
|
+
end
|
134
204
|
end
|
135
205
|
|
136
|
-
def
|
137
|
-
|
138
|
-
|
139
|
-
.inject(0){|sum, item| sum + item[:amount] }
|
206
|
+
def self.accumulate_month(year, month)
|
207
|
+
monthly_record, count = net(year, month)
|
208
|
+
[total_subaccount(monthly_record), count]
|
140
209
|
end
|
141
210
|
|
211
|
+
# Accumulate Level 2, 3 account.
|
212
|
+
#
|
142
213
|
def self.total_subaccount(report)
|
143
|
-
|
214
|
+
{}.tap do |res|
|
215
|
+
res['A0'] = sum_matched(report, /^[A][0-9A-Z]{2,}/)
|
216
|
+
res['B0'] = sum_matched(report, /^[B][0-9A-Z]{2,}/)
|
217
|
+
res['BA'] = res['A0'] - res['B0']
|
218
|
+
res['C0'] = sum_matched(report, /^[C][0-9A-Z]{2,}/)
|
219
|
+
res['CA'] = res['BA'] - res['C0']
|
220
|
+
res['D0'] = sum_matched(report, /^[D][0-9A-Z]{2,}/)
|
221
|
+
res['E0'] = sum_matched(report, /^[E][0-9A-Z]{2,}/)
|
222
|
+
res['EA'] = res['CA'] + res['D0'] - res['E0']
|
223
|
+
res['F0'] = sum_matched(report, /^[F][0-9A-Z]{2,}/)
|
224
|
+
res['G0'] = sum_matched(report, /^[G][0-9][0-9A-Z]{1,}/)
|
225
|
+
res['GA'] = res['EA'] + res['F0'] - res['G0']
|
226
|
+
res['H0'] = sum_matched(report, /^[H][0-9][0-9A-Z]{1,}/)
|
227
|
+
res['HA'] = res['GA'] - res['H0']
|
228
|
+
|
229
|
+
report['9142'] = (report['9142'] || BigDecimal('0')) + res['HA']
|
230
|
+
res['9142'] = report['9142']
|
231
|
+
res['10'] = sum_matched(report, /^[123][0-9A-Z]{2,}/)
|
232
|
+
res['40'] = sum_matched(report, /^[4][0-9A-Z]{2,}/)
|
233
|
+
res['50'] = sum_matched(report, /^[56][0-9A-Z]{2,}/)
|
234
|
+
res['70'] = sum_matched(report, /^[78][0-9A-Z]{2,}/)
|
235
|
+
res['91'] = sum_matched(report, /^91[0-9A-Z]{1,}/)
|
236
|
+
res['8ZZ'] = res['50'] + res['70']
|
237
|
+
res['9ZZ'] = sum_matched(report, /^[9][0-9A-Z]{2,}/)
|
238
|
+
|
239
|
+
res['1'] = res['10'] + res['40']
|
240
|
+
res['5'] = res['8ZZ'] + res['9ZZ']
|
241
|
+
res['_d'] = report['_d']
|
242
|
+
|
243
|
+
report.each do |k, v|
|
244
|
+
res[k] = v if k.length == 3
|
245
|
+
end
|
246
|
+
|
144
247
|
report.each do |k, v|
|
145
248
|
if k.length >= 4
|
146
249
|
if res[k[0, 3]]
|
@@ -150,54 +253,78 @@ module LucaBook
|
|
150
253
|
end
|
151
254
|
end
|
152
255
|
end
|
153
|
-
res
|
154
|
-
res['40'] = sum_matched(report, /^[4].[^0]}/)
|
155
|
-
res['50'] = sum_matched(report, /^[56].[^0]/)
|
156
|
-
res['70'] = sum_matched(report, /^[78].[^0]/)
|
157
|
-
res['90'] = sum_matched(report, /^[9].[^0]/)
|
158
|
-
res['A0'] = sum_matched(report, /^[A].[^0]/)
|
159
|
-
res['B0'] = sum_matched(report, /^[B].[^0]/)
|
160
|
-
res['BA'] = res['A0'] - res['B0']
|
161
|
-
res['C0'] = sum_matched(report, /^[C].[^0]/)
|
162
|
-
res['CA'] = res['BA'] - res['C0']
|
163
|
-
res['D0'] = sum_matched(report, /^[D].[^0]/)
|
164
|
-
res['E0'] = sum_matched(report, /^[E].[^0]/)
|
165
|
-
res['EA'] = res['CA'] + res['D0'] - res['E0']
|
166
|
-
res['F0'] = sum_matched(report, /^[F].[^0]/)
|
167
|
-
res['G0'] = sum_matched(report, /^[G].[^0]/)
|
168
|
-
res['GA'] = res['EA'] + res['F0'] - res['G0']
|
169
|
-
res['HA'] = res['GA'] - sum_matched(report, /^[H].[^0]/)
|
256
|
+
res.sort.to_h
|
170
257
|
end
|
171
258
|
end
|
172
259
|
|
260
|
+
def code_sum(report)
|
261
|
+
legal_items.each.with_object({}) do |k, h|
|
262
|
+
h[k] = self.class.sum_matched(report, /^#{k}.*/)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def set_balance
|
267
|
+
pre_last = @start_date.prev_month
|
268
|
+
pre = if @start_date.month > LucaSupport::CONFIG['fy_start'].to_i
|
269
|
+
self.class.accumulate_term(pre_last.year, LucaSupport::CONFIG['fy_start'], pre_last.year, pre_last.month)
|
270
|
+
elsif @start_date.month < LucaSupport::CONFIG['fy_start'].to_i
|
271
|
+
self.class.accumulate_term(pre_last.year - 1, LucaSupport::CONFIG['fy_start'], pre_last.year, pre_last.month)
|
272
|
+
end
|
273
|
+
|
274
|
+
base = Dict.latest_balance.each_with_object({}) do |(k, v), h|
|
275
|
+
h[k] = BigDecimal(v[:balance].to_s) if v[:balance]
|
276
|
+
end
|
277
|
+
if pre
|
278
|
+
idx = (pre.keys + base.keys).uniq
|
279
|
+
base = {}.tap do |h|
|
280
|
+
idx.each { |k| h[k] = (base[k] || BigDecimal('0')) + (pre[k] || BigDecimal('0')) }
|
281
|
+
end
|
282
|
+
end
|
283
|
+
self.class.total_subaccount(base)
|
284
|
+
end
|
285
|
+
|
173
286
|
def self.sum_matched(report, reg)
|
174
287
|
report.select { |k, v| reg.match(k)}.values.sum
|
175
288
|
end
|
176
289
|
|
177
290
|
# for assert purpose
|
291
|
+
#
|
178
292
|
def self.gross(year, month = nil, code = nil, date_range = nil, rows = 4)
|
179
293
|
if ! date_range.nil?
|
180
294
|
raise if date_range.class != Range
|
181
295
|
# TODO: date based range search
|
182
296
|
end
|
183
297
|
|
184
|
-
sum = { debit: {}, credit: {} }
|
298
|
+
sum = { debit: {}, credit: {}, debit_count: {}, credit_count: {} }
|
185
299
|
idx_memo = []
|
186
300
|
asof(year, month) do |f, _path|
|
187
301
|
CSV.new(f, headers: false, col_sep: "\t", encoding: 'UTF-8')
|
188
302
|
.each_with_index do |row, i|
|
189
303
|
break if i >= rows
|
304
|
+
|
190
305
|
case i
|
191
306
|
when 0
|
192
307
|
idx_memo = row.map(&:to_s)
|
193
|
-
idx_memo.each
|
308
|
+
idx_memo.each do |r|
|
309
|
+
sum[:debit][r] ||= BigDecimal('0')
|
310
|
+
sum[:debit_count][r] ||= 0
|
311
|
+
end
|
194
312
|
when 1
|
195
|
-
row.each_with_index
|
313
|
+
row.each_with_index do |r, j|
|
314
|
+
sum[:debit][idx_memo[j]] += BigDecimal(r.to_s)
|
315
|
+
sum[:debit_count][idx_memo[j]] += 1
|
316
|
+
end
|
196
317
|
when 2
|
197
318
|
idx_memo = row.map(&:to_s)
|
198
|
-
idx_memo.each
|
319
|
+
idx_memo.each do |r|
|
320
|
+
sum[:credit][r] ||= BigDecimal('0')
|
321
|
+
sum[:credit_count][r] ||= 0
|
322
|
+
end
|
199
323
|
when 3
|
200
|
-
row.each_with_index
|
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
|
201
328
|
else
|
202
329
|
puts row # for debug
|
203
330
|
end
|
@@ -207,52 +334,38 @@ module LucaBook
|
|
207
334
|
end
|
208
335
|
|
209
336
|
# netting vouchers in specified term
|
337
|
+
#
|
210
338
|
def self.net(year, month = nil, code = nil, date_range = nil)
|
211
339
|
g = gross(year, month, code, date_range)
|
212
340
|
idx = (g[:debit].keys + g[:credit].keys).uniq.sort
|
213
|
-
{}
|
341
|
+
count = {}
|
342
|
+
diff = {}.tap do |sum|
|
214
343
|
idx.each do |code|
|
215
|
-
sum[code] = g.dig(:debit, code).nil? ? 0 : calc_diff(g[:debit][code], code)
|
216
|
-
sum[code] -= g.dig(:credit, code).nil? ? 0 : calc_diff(g[:credit][code], code)
|
344
|
+
sum[code] = g.dig(:debit, code).nil? ? BigDecimal('0') : Util.calc_diff(g[:debit][code], code)
|
345
|
+
sum[code] -= g.dig(:credit, code).nil? ? BigDecimal('0') : Util.calc_diff(g[:credit][code], code)
|
346
|
+
count[code] = (g.dig(:debit_count, code) || 0) + (g.dig(:credit_count, code) || 0)
|
217
347
|
end
|
218
348
|
end
|
349
|
+
[diff, count]
|
219
350
|
end
|
220
351
|
|
221
|
-
# TODO:
|
352
|
+
# TODO: obsolete in favor of Dict.latest_balance()
|
222
353
|
def load_start
|
223
|
-
file = LucaSupport::Config::Pjdir
|
224
|
-
{}.tap do |
|
225
|
-
|
226
|
-
dic[row[0]] = row[2].to_i if ! row[2].nil?
|
227
|
-
end
|
354
|
+
file = Pathname(LucaSupport::Config::Pjdir) / 'data' / 'balance' / 'start.tsv'
|
355
|
+
{}.tap do |dict|
|
356
|
+
LucaRecord::Dict.load_tsv_dict(file).each { |k, v| h[k] = v[:balance] if !v[:balance].nil? }
|
228
357
|
end
|
229
358
|
end
|
230
359
|
|
231
|
-
|
232
|
-
return enum_for(:load_tsv, path) unless block_given?
|
233
|
-
|
234
|
-
data = CSV.read(path, headers: true, col_sep: "\t", encoding: 'UTF-8')
|
235
|
-
data.each { |row| yield row }
|
236
|
-
end
|
360
|
+
private
|
237
361
|
|
238
|
-
def
|
239
|
-
|
240
|
-
amount * pn_debit(code.to_s)
|
241
|
-
end
|
362
|
+
def legal_items
|
363
|
+
return [] unless LucaSupport::Config::COUNTRY
|
242
364
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
1
|
247
|
-
when /^[5-9ADF]/
|
248
|
-
-1
|
249
|
-
else
|
250
|
-
nil
|
365
|
+
case LucaSupport::Config::COUNTRY
|
366
|
+
when 'jp'
|
367
|
+
['91', '911', '912', '913', '9131', '9132', '914', '9141', '9142', '915', '916', '92', '93']
|
251
368
|
end
|
252
369
|
end
|
253
|
-
|
254
|
-
def dict
|
255
|
-
LucaBook::Dict::Data
|
256
|
-
end
|
257
370
|
end
|
258
371
|
end
|