lucabook 0.2.27 → 0.2.31

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ad4b1eba3419508d64bfeade5f776ed2ca0f32313deab25660864aff47767787
4
- data.tar.gz: 57aef956cbc763dbf4d089d5745c9cc4d6a6ed44dd3ff726b9c80fbc6b29629d
3
+ metadata.gz: 87936c519f40b82f1559b0cc20820e3f3a8b8d8afde4914ca1b8f749db5b69a0
4
+ data.tar.gz: 9dfc82e16185a42f2ea8e598b69a7f7448fb8aeae55d831ac72617980982e037
5
5
  SHA512:
6
- metadata.gz: 317b373f1a31c85c107dfa294ec6df0dcc89f13b8ab10277bb004b3bdceaaf0ec58cfa5c2220a088932965b5b156fd71fef1ce67be67c330857bbcea127de365
7
- data.tar.gz: e7456d393a4309bafb9a3622c28da10067e1483c80b0bbbd73a05508bb3d9a6742051e2d190870a1f6e39df5ec10b5dd7d1de698faef969a3bc54efa7b46b153
6
+ metadata.gz: f388153393b76ff871c6c8e028efeaf4476400608ec7b100c81bb1a39f0bf8efc67fa3b79d7d0e987bc8565e41c4098109164a7afe873baa816fafa2ca564ed7
7
+ data.tar.gz: 4701eb25e02571465d4ed053f1f17ee361a36f5420589dff1396f6adf1267d89e9f4de0c90fb812b45e549109da1fd0a93ce8133b007f0864120b64518037652
data/exe/luca-book CHANGED
@@ -19,13 +19,15 @@ class LucaCmd
19
19
  end
20
20
 
21
21
  def self.list(args, params)
22
- args = gen_range(params[:n] || 1) if args.empty?
22
+ args = gen_range(params[:n]) if args.empty?
23
23
  if params['code']
24
24
  if params['headers']
25
25
  render(LucaBook::ListByHeader.term(*args, code: params['code'], header: params['headers']).list_by_code, params)
26
26
  else
27
27
  render(LucaBook::List.term(*args, code: params['code'], recursive: params[:recursive]).list_by_code(params[:recursive]), params)
28
28
  end
29
+ elsif params['render']
30
+ puts LucaBook::List.term(*args).render_html(params['render'])
29
31
  else
30
32
  render(LucaBook::List.term(*args).list_journals, params)
31
33
  end
@@ -78,11 +80,19 @@ class LucaCmd
78
80
  end
79
81
  end
80
82
 
81
- def self.gen_range(count)
82
- count ||= 3
83
+ def self.gen_range(count = nil)
83
84
  today = Date.today
84
- start = today.prev_month(count - 1)
85
- [start.year, start.month, today.year, today.month]
85
+ if count
86
+ start = today.prev_month(count - 1)
87
+ [start.year, start.month, today.year, today.month]
88
+ else
89
+ start_year = if today.month >= LucaSupport::CONFIG['fy_start'].to_i
90
+ today.year
91
+ else
92
+ today.year - 1
93
+ end
94
+ [start_year, LucaSupport::CONFIG['fy_start'], start_year + 1, LucaSupport::CONFIG['fy_start'].to_i - 1]
95
+ end
86
96
  end
87
97
 
88
98
  def self.render(dat, params)
@@ -100,6 +110,11 @@ class LucaCmd
100
110
  def self.update_balance(args, params)
101
111
  LucaBook::Dict.generate_balance(*args)
102
112
  end
113
+
114
+ def self.export_balance(args, params)
115
+ date = Date.new(args[0].to_i, args[1].to_i, args[2].to_i)
116
+ LucaBook::Dict.export_balance(date)
117
+ end
103
118
  end
104
119
  end
105
120
 
@@ -133,6 +148,8 @@ when /journals?/, 'j'
133
148
  opt.on('-n VAL', 'report count') { |v| params[:n] = v.to_i }
134
149
  opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
135
150
  opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
151
+ opt.on('--html', 'output journals html') { |_v| params['render'] = :html }
152
+ opt.on('--pdf', 'output journals PDF') { |_v| params['render'] = :pdf }
136
153
  opt.on_tail('List records. If you specify code and/or month, search on each criteria.')
137
154
  args = opt.parse!(ARGV)
138
155
  LucaCmd::Journal.list(args, params)
@@ -216,9 +233,11 @@ when /reports?/, 'r'
216
233
  else
217
234
  puts 'Proper subcommand needed.'
218
235
  puts
219
- puts 'Usage: luca-book (r|report[s]) (bs|pl) [options] YYYY M'
236
+ puts 'Usage: luca-book (r|report[s]) (bs|pl|mail|xbrl) [options] YYYY M'
220
237
  puts ' bs: show balance sheet'
221
238
  puts ' pl: show statement of income'
239
+ puts ' mail: send BS/PL via email'
240
+ puts ' xbrl: render XBRL report'
222
241
  exit 1
223
242
  end
224
243
  when /balance/
@@ -230,6 +249,12 @@ when /balance/
230
249
  args = opt.parse!(ARGV)
231
250
  LucaCmd::Dict.update_balance(args, params)
232
251
  end
252
+ when 'export'
253
+ OptionParser.new do |opt|
254
+ opt.banner = 'Usage: luca-book balance export YYYY M d'
255
+ args = opt.parse!(ARGV)
256
+ LucaCmd::Dict.export_balance(args, params)
257
+ end
233
258
  end
234
259
  else
235
260
  puts 'Proper subcommand needed.'
@@ -237,5 +262,6 @@ else
237
262
  puts 'Usage: luca-book (j[ournals]|r[eports]) subcommand'
238
263
  puts ' journals: operate journal records'
239
264
  puts ' reports: show reports'
265
+ puts ' balance update: generate accumulated balance'
240
266
  exit 1
241
267
  end
@@ -74,7 +74,7 @@ module LucaBook
74
74
 
75
75
  # for assert purpose
76
76
  #
77
- def gross(start_year, start_month, end_year = nil, end_month = nil, code: nil, date_range: nil, rows: 4, recursive: false)
77
+ def gross(start_year, start_month, end_year = nil, end_month = nil, code: nil, date_range: nil, rows: 4, recursive: false)
78
78
  if ! date_range.nil?
79
79
  raise if date_range.class != Range
80
80
  # TODO: date based range search
@@ -84,7 +84,7 @@ module LucaBook
84
84
  end_month ||= start_month
85
85
  sum = { debit: {}, credit: {}, debit_count: {}, credit_count: {} }
86
86
  idx_memo = []
87
- term(start_year, start_month, end_year, end_month, code) do |f, _path|
87
+ term(start_year, start_month, end_year, end_month, code, 'journals') do |f, _path|
88
88
  CSV.new(f, headers: false, col_sep: "\t", encoding: 'UTF-8')
89
89
  .each_with_index do |row, i|
90
90
  break if i >= rows
@@ -130,20 +130,20 @@ module LucaBook
130
130
  else
131
131
  Array(code)
132
132
  end
133
- res = { debit: 0, credit: 0, debit_count: 0, credit_count: 0 }
134
- codes.each do |code|
135
- res[:debit] += sum[:debit][code] || BigDecimal('0')
136
- res[:credit] += sum[:credit][code] || BigDecimal('0')
137
- res[:debit_count] += sum[:debit_count][code] || 0
138
- res[:credit_count] += sum[:credit_count][code] || 0
133
+ res = { debit: { code => 0 }, credit: { code => 0 }, debit_count: { code => 0 }, credit_count: { code => 0 } }
134
+ codes.each do |cd|
135
+ res[:debit][code] += sum[:debit][cd] || BigDecimal('0')
136
+ res[:credit][code] += sum[:credit][cd] || BigDecimal('0')
137
+ res[:debit_count][code] += sum[:debit_count][cd] || 0
138
+ res[:credit_count][code] += sum[:credit_count][cd] || 0
139
139
  end
140
140
  res
141
141
  end
142
142
 
143
143
  # netting vouchers in specified term
144
144
  #
145
- def net(start_year, start_month, end_year = nil, end_month = nil, code: nil, date_range: nil)
146
- g = gross(start_year, start_month, end_year, end_month, code: code, date_range: date_range)
145
+ def net(start_year, start_month, end_year = nil, end_month = nil, code: nil, date_range: nil, recursive: false)
146
+ g = gross(start_year, start_month, end_year, end_month, code: code, date_range: date_range, recursive: recursive)
147
147
  idx = (g[:debit].keys + g[:credit].keys).uniq.sort
148
148
  count = {}
149
149
  diff = {}.tap do |sum|
@@ -155,6 +155,58 @@ module LucaBook
155
155
  end
156
156
  [diff, count]
157
157
  end
158
+
159
+ # Override LucaRecord::IO.load_data
160
+ #
161
+ def load_data(io, path = nil)
162
+ io
163
+ end
164
+ end
165
+
166
+ def net_amount(code, start_year = nil, start_month = nil, end_year = nil, end_month = nil, recursive: true)
167
+ start_year ||= @cursor_start&.year || @start_date.year
168
+ start_month ||= @cursor_start&.month || @start_date.month
169
+ end_year ||= @cursor_end&.year || @end_date.year
170
+ end_month ||= @cursor_end&.month || @end_date.month
171
+ self.class.net(start_year, start_month, end_year, end_month, code: code, recursive: recursive)[0][code]
172
+ end
173
+
174
+ def debit_amount(code, start_year = nil, start_month = nil, end_year = nil, end_month = nil, recursive: true)
175
+ gross_amount(code, start_year, start_month, end_year, end_month, recursive: recursive)[0]
176
+ end
177
+
178
+ def credit_amount(code, start_year = nil, start_month = nil, end_year = nil, end_month = nil, recursive: true)
179
+ gross_amount(code, start_year, start_month, end_year, end_month, recursive: recursive)[1]
180
+ end
181
+
182
+ def gross_amount(code, start_year = nil, start_month = nil, end_year = nil, end_month = nil, recursive: true)
183
+ start_year ||= @cursor_start&.year || @start_date.year
184
+ start_month ||= @cursor_start&.month || @start_date.month
185
+ end_year ||= @cursor_end&.year || @end_date.year
186
+ end_month ||= @cursor_end&.month || @end_date.month
187
+ g = self.class.gross(start_year, start_month, end_year, end_month, code: code, recursive: recursive)
188
+ [g[:debit][code], g[:credit][code]]
189
+ end
190
+
191
+ def debit_count(code, start_year = nil, start_month = nil, end_year = nil, end_month = nil, recursive: true)
192
+ gross_count(code, start_year, start_month, end_year, end_month, recursive: recursive)[0]
193
+ end
194
+
195
+ def credit_count(code, start_year = nil, start_month = nil, end_year = nil, end_month = nil, recursive: true)
196
+ gross_count(code, start_year, start_month, end_year, end_month, recursive: recursive)[1]
197
+ end
198
+
199
+ def gross_count(code, start_year = nil, start_month = nil, end_year = nil, end_month = nil, recursive: true)
200
+ start_year ||= @cursor_start&.year || @start_date.year
201
+ start_month ||= @cursor_start&.month || @start_date.month
202
+ end_year ||= @cursor_end&.year || @end_date.year
203
+ end_month ||= @cursor_end&.month || @end_date.month
204
+ g = self.class.gross(start_year, start_month, end_year, end_month, code: code, recursive: recursive)
205
+ [g[:debit_count][code], g[:credit_count][code]]
206
+ end
207
+
208
+ def each_month
209
+ yield
158
210
  end
159
211
  end
160
212
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'luca_support/code'
4
4
  require 'luca_support/config'
5
+ require 'luca_support/range'
5
6
  require 'luca_record/dict'
6
7
  require 'luca_record/io'
7
8
  require 'luca_book'
@@ -10,11 +11,12 @@ require 'pathname'
10
11
 
11
12
  module LucaBook
12
13
  class Dict < LucaRecord::Dict
13
- include Accumulator
14
+ include LucaSupport::Range
15
+ include LucaBook::Util
14
16
  include LucaRecord::IO
17
+ include Accumulator
15
18
 
16
19
  @dirname = 'journals'
17
- @record_type = 'raw'
18
20
  # Column number settings for CSV/TSV convert
19
21
  #
20
22
  # :label
@@ -137,6 +139,31 @@ module LucaBook
137
139
  File.open(filepath, 'w') { |f| f.write csv }
138
140
  end
139
141
 
142
+ # TODO: support date in the middle of month.
143
+ def self.export_balance(date)
144
+ start_date, end_date = Util.current_fy(date, to: date)
145
+ labels = load('base.tsv')
146
+ bs = load_balance(start_date, end_date)
147
+ dat = [].tap do |res|
148
+ item = {}
149
+ item['date'] = date.to_s
150
+ item['debit'] = []
151
+ item['credit'] = []
152
+ bs.each do |code, balance|
153
+ next if balance.zero?
154
+
155
+ if /^[1-4]/.match(code)
156
+ item['debit'] << { 'label' => labels.dig(code, :label), 'amount' => LucaSupport::Code.readable(balance) }
157
+ elsif /^[5-9]/.match(code)
158
+ item['credit'] << { 'label' => labels.dig(code, :label), 'amount' => LucaSupport::Code.readable(balance) }
159
+ end
160
+ end
161
+ item['x-editor'] = 'LucaBook'
162
+ res << item
163
+ end
164
+ puts JSON.dump(dat)
165
+ end
166
+
140
167
  def self.load_balance(start_date, end_date)
141
168
  base = latest_balance(start_date).each_with_object({}) do |(k, v), h|
142
169
  h[k] = BigDecimal(v[:balance].to_s) if v[:balance]
@@ -170,15 +197,5 @@ module LucaBook
170
197
  digest = `git rev-parse HEAD`
171
198
  $?.exitstatus == 0 ? digest.strip : nil
172
199
  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
183
200
  end
184
201
  end
@@ -81,7 +81,7 @@ module LucaBook
81
81
  else
82
82
  amount = BigDecimal(row[@config[:credit_amount]])
83
83
  end
84
- default_label = debit ? @config.dig(:default_debit) : @config.dig(:default_credit)
84
+ default_label = debit ? @config[:default_debit] : @config[:default_credit]
85
85
  code, options = search_code(row[@config[:label]], default_label, amount)
86
86
  counter_code = @code_map.dig(@config[:counter_label])
87
87
  if options
@@ -94,10 +94,12 @@ module LucaBook
94
94
  d['date'] = parse_date(row)
95
95
  if debit
96
96
  d['debit'] = data
97
+ d['debit'][0]['code'] ||= DEBIT_DEFAULT
97
98
  d['credit'] = data_c
98
99
  else
99
100
  d['debit'] = data_c
100
101
  d['credit'] = data
102
+ d['credit'][0]['code'] ||= CREDIT_DEFAULT
101
103
  end
102
104
  d['note'] = Array(@config[:note]).map{ |col| row[col] }.join(' ')
103
105
  d['headers'] = { 'x-editor' => "LucaBook::Import/#{@dict_name}" }
@@ -101,16 +101,127 @@ module LucaBook #:nodoc:
101
101
  end
102
102
  end
103
103
 
104
+ def render_html(file_type = :html)
105
+ start_balance = set_balance(true)
106
+ @journals = group_by_code.map do |account|
107
+ balance = start_balance[account[:code]] || BigDecimal('0')
108
+ table = []
109
+ table << %Q(<h2 class="title">#{@@dict.dig(account[:code], :label)}</h2>)
110
+
111
+ account[:vouchers].map { |voucher| filter_by_code(voucher, account[:code]) }.flatten
112
+ .unshift({ balance: readable(balance) })
113
+ .map { |row|
114
+ balance += Util.pn_debit(account[:code]) * ((row.dig(:amount, :debit) || 0) - (row.dig(:amount, :credit) || 0))
115
+ row[:balance] = readable(balance)
116
+ row
117
+ }
118
+ .map { |row| render_line(row) }
119
+ .each_slice(28) do |rows|
120
+ table << table_header
121
+ table << rows.join("\n")
122
+ table << table_footer
123
+ table << %Q(<hr class='pgbr' />)
124
+ end
125
+ table[0..-2].join("\n")
126
+ end
127
+
128
+ case file_type
129
+ when :html
130
+ render_erb(search_template('journals.html.erb'))
131
+ when :pdf
132
+ erb2pdf(search_template('journals.html.erb'))
133
+ else
134
+ raise 'This filetype is not supported.'
135
+ end
136
+ end
137
+
138
+ def table_header
139
+ %Q(<table>
140
+ <thead>
141
+ <th>Date<br />No</th>
142
+ <th>Counter account</th>
143
+ <th>Sub account<br />Note</th>
144
+ <th>Debit</th>
145
+ <th>Credit</th>
146
+ <th>Balance</th>
147
+ </thead>
148
+ <tbody>)
149
+ end
150
+
151
+ def table_footer
152
+ %Q(</tbody>
153
+ </table>)
154
+ end
155
+
156
+ def filter_by_code(voucher, code)
157
+ [:debit, :credit].each_with_object([]) do |balance, lines|
158
+ voucher[balance].each do |record|
159
+ next unless /^#{code}/.match(record[:code])
160
+
161
+ counter_balance = (balance == :debit) ? :credit : :debit
162
+ view = { code: record[:code], amount: {} }
163
+ view[:date], view[:txid] = decode_id(voucher[:id])
164
+ view[:label] = @@dict.dig(record[:code], :label) if record[:code].length >= 4
165
+ view[:label] = voucher.dig(:headers, 'x-customer') if view[:label].nil?
166
+ view[:amount][balance] = readable(record[:amount])
167
+ view[:counter_code] = voucher.dig(counter_balance, 0, :code)
168
+ view[:counter_label] = @@dict.dig(view[:counter_code], :label) || ''
169
+ view[:counter_label] += ' sundry a/c' if voucher[counter_balance].length > 1
170
+ view[:note] = voucher[:note]
171
+ lines << view
172
+ end
173
+ end
174
+ end
175
+
176
+ def render_line(view)
177
+ %Q(<tr>
178
+ <td class="date">#{view[:date]}<br /><div>#{view[:txid]}</div></td>
179
+ <td class="counter">#{view[:counter_label]}</td>
180
+ <td class="note">#{view[:label]}<br /><div class="note">#{view[:note]}</div></td>
181
+ <td class="debit amount">#{view.dig(:amount, :debit)}</td>
182
+ <td class="credit amount">#{view.dig(:amount, :credit)}</td>
183
+ <td class="balance">#{view[:balance]}</td>
184
+ </tr>)
185
+ end
186
+
187
+ def group_by_code(level = 3)
188
+ list_accounts.map do |code|
189
+ vouchers = @data.filter do |voucher|
190
+ codes = [:debit, :credit].map do |balance|
191
+ voucher[balance].map { |record| record[:code][0, level] }
192
+ end
193
+ codes.flatten.include?(code)
194
+ end
195
+ { code: code, vouchers: vouchers }
196
+ end
197
+ end
198
+
199
+ def list_accounts(level = 3)
200
+ return nil if level < 3
201
+
202
+ list = @data.each_with_object([]) do |voucher, codes|
203
+ [:debit, :credit].each do |balance|
204
+ voucher[balance].each do |record|
205
+ next if record[:code].length < level
206
+
207
+ codes << record[:code][0, level]
208
+ end
209
+ end
210
+ end
211
+ list.uniq.sort
212
+ end
213
+
104
214
  private
105
215
 
106
216
  def set_balance(recursive = false)
107
- return BigDecimal('0') if @code.nil? || /^[A-H]/.match(@code)
217
+ return LucaBook::State.start_balance(@start.year, @start.month, recursive: recursive) if @code.nil?
218
+ return BigDecimal('0') if /^[A-H]/.match(@code)
108
219
 
109
- LucaBook::State.start_balance(@start.year, @start.month, recursive: recursive)
220
+ LucaBook::State.start_balance(@start.year, @start.month, recursive: recursive)[@code] || BigDecimal('0')
110
221
  end
111
222
 
112
223
  def calc_code(recursive: false)
113
- @balance = set_balance(recursive)[@code] || BigDecimal('0')
224
+ @balance = set_balance(recursive)
114
225
  if @code
115
226
  balance = @balance
116
227
  @data.each do |dat|
@@ -145,5 +256,9 @@ module LucaBook #:nodoc:
145
256
  end
146
257
  end
147
258
  end
259
+
260
+ def lib_path
261
+ __dir__
262
+ end
148
263
  end
149
264
  end
@@ -49,7 +49,7 @@ module LucaBook #:nodoc:
49
49
  res['note'] = dat[:note]
50
50
  end
51
51
  end
52
- a << { 'code' => v.last[:code], 'header' => k, 'balance' => v.last[:balance], 'count' => v.count, 'jounals' => journals }
52
+ a << { 'code' => v.last[:code], 'header' => k, 'balance' => v.last[:balance], 'count' => v.count, 'journals' => journals }
53
53
  end
54
54
  readable(@data)
55
55
  end
@@ -67,16 +67,8 @@ 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(@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
70
+ #TODO: start_balance to be implemented by header
71
+ LucaBook::State.start_balance(@start.year, @start.month)
80
72
  end
81
73
 
82
74
  def calc_code
@@ -17,7 +17,6 @@ module LucaBook
17
17
  include Accumulator
18
18
 
19
19
  @dirname = 'journals'
20
- @record_type = 'raw'
21
20
  @@dict = LucaRecord::Dict.new('base.tsv')
22
21
 
23
22
  attr_reader :statement, :pl_data, :bs_data, :start_balance
@@ -62,15 +61,15 @@ module LucaBook
62
61
  while date <= last_date do
63
62
  diff = {}.tap do |h|
64
63
  g = gross(date.year, date.month, code: code, recursive: recursive)
65
- sum = g.dig(:debit).nil? ? BigDecimal('0') : Util.calc_diff(g[:debit], code)
66
- sum -= g.dig(:credit).nil? ? BigDecimal('0') : Util.calc_diff(g[:credit], code)
64
+ sum = g.dig(:debit, code).nil? ? BigDecimal('0') : Util.calc_diff(g[:debit][code], code)
65
+ sum -= g.dig(:credit, code).nil? ? BigDecimal('0') : Util.calc_diff(g[:credit][code], code)
67
66
  balance += sum
68
67
  h['code'] = code
69
68
  h['label'] = @@dict.dig(code, :label)
70
- h['debit_amount'] = g[:debit]
71
- h['debit_count'] = g[:debit_count]
72
- h['credit_amount'] = g[:credit]
73
- h['credit_count'] = g[:credit_count]
69
+ h['debit_amount'] = g.dig(:debit, code)
70
+ h['debit_count'] = g.dig(:debit_count, code)
71
+ h['credit_amount'] = g.dig(:credit, code)
72
+ h['credit_count'] = g.dig(:credit_count, code)
74
73
  h['net'] = sum
75
74
  h['balance'] = balance
76
75
  h['_d'] = date.to_s
@@ -147,7 +146,7 @@ module LucaBook
147
146
  res['debit_label'] = base[:debit][i] ? @@dict.dig(base[:debit][i].keys[0], :label) : ''
148
147
  #res['debit_balance'] = base[:debit][i] ? (@start_balance.dig(base[:debit][i].keys[0]) || 0) + base[:debit][i].values[0] : ''
149
148
  res['debit_balance'] = base[:debit][i] ? base[:debit][i].values[0] : ''
150
- res['credit_label'] = base[:credit][i] ? @dict.dig(base[:credit][i].keys[0], :label) : ''
149
+ res['credit_label'] = base[:credit][i] ? @@dict.dig(base[:credit][i].keys[0], :label) : ''
151
150
  #res['credit_balance'] = base[:credit][i] ? (@start_balance.dig(base[:credit][i].keys[0]) || 0) + base[:credit][i].values[0] : ''
152
151
  res['credit_balance'] = base[:credit][i] ? base[:credit][i].values[0] : ''
153
152
  a << res
@@ -233,6 +232,7 @@ module LucaBook
233
232
  recursive ? total_subaccount(total) : total
234
233
  end
235
234
 
235
+ # TODO: currency setting other than JPY
236
236
  def render_xbrl(filename = nil)
237
237
  set_bs(3, legal: true)
238
238
  set_pl(3)
@@ -261,7 +261,11 @@ module LucaBook
261
261
  return nil if tag.nil?
262
262
  return nil if readable(amount).zero? && prior_amount.nil?
263
263
 
264
- prior = prior_amount.nil? ? '' : "<#{tag} decimals=\"0\" unitRef=\"JPY\" contextRef=\"Prior1YearNonConsolidatedInstant\">#{readable(prior_amount)}</#{tag}>\n"
264
+ prior = if prior_amount.nil?
265
+ /^[9]/.match(code) ? "<#{tag} decimals=\"0\" unitRef=\"JPY\" contextRef=\"Prior1YearNonConsolidatedInstant\">0</#{tag}>\n" : ''
266
+ else
267
+ "<#{tag} decimals=\"0\" unitRef=\"JPY\" contextRef=\"Prior1YearNonConsolidatedInstant\">#{readable(prior_amount)}</#{tag}>\n"
268
+ end
265
269
  current = "<#{tag} decimals=\"0\" unitRef=\"JPY\" contextRef=\"#{context}\">#{readable(amount)}</#{tag}>"
266
270
 
267
271
  prior + current
@@ -82,7 +82,7 @@ code label xbrl_id consumption_tax income_tax
82
82
  91 株主資本 jppfs_cor:ShareholdersAbstract
83
83
  911 資本金 jppfs_cor:CapitalStock
84
84
  912 新株式申込証拠金 jppfs_cor:DepositForSubscriptionsToShares
85
- 913 資本剰余金 jppfs_cor:LegalCapitalSurplus
85
+ 913 資本剰余金 jppfs_cor:CapitalSurplus
86
86
  9131 資本準備金 jppfs_cor:LegalCapitalSurplus
87
87
  9132 その他資本剰余金 jppfs_cor:OtherCapitalSurplus
88
88
  914 利益剰余金 jppfs_cor:RetainedEarnings
@@ -105,7 +105,7 @@ code label xbrl_id consumption_tax income_tax
105
105
  91 株主資本 jpfr-t-cte:ShareholdersEquity
106
106
  911 資本金 jpfr-t-cte:CapitalStock
107
107
  912 新株式申込証拠金 jpfr-t-cte:DepositForSubscriptionsToShares
108
- 913 資本剰余金 jpfr-t-cte:LegalCapitalSurplus
108
+ 913 資本剰余金 jpfr-t-cte:CapitalSurplus
109
109
  9131 資本準備金 jpfr-t-cte:LegalCapitalSurplus
110
110
  9132 その他資本剰余金 jpfr-t-cte:OtherCapitalSurplus
111
111
  914 繰越利益剰余金 jpfr-t-cte:RetainedEarningsBroughtForward
@@ -0,0 +1,23 @@
1
+ <html>
2
+ <head>
3
+ <meta charset="utf-8">
4
+ <style>
5
+ body { size: A4; padding-top: 2em; padding-bottom: 2em }
6
+ .pgbr { page-break-after: always; visibility: hidden }
7
+ .title { margin-bottom: 1.5rem; text-align: center }
8
+ div.note { font-size: .8em }
9
+ table { border-collapse: collapse; max-width: 92%; margin: 1em auto }
10
+ th, td { border-bottom: solid 1px #555; }
11
+ td div { break-before: avoid-page; break-after: avoid-page; break-inside: avoid-page }
12
+ td { padding-top: .3em; padding-bottom: .3em; break-inside: avoid-page }
13
+ td.date { min-width: 7em; text-align: right; padding-right: 1em }
14
+ td.counter { min-width: 8.5em; padding-right: .5em }
15
+ td.note { min-width: 12em }
16
+ td.amount { text-align: right; min-width: 7em }
17
+ td.balance { text-align: right; min-width: 10em; padding-right: 1em }
18
+ </style>
19
+ </head>
20
+ <body>
21
+ <%= @journals.join("<hr class='pgbr' />\n") %>
22
+ </body>
23
+ </html>
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/autorun'
4
+ require 'luca_book'
5
+ require 'luca_record/io'
6
+ require 'luca_support/range'
7
+
8
+ module LucaBook # :nodoc:
9
+ # Provide data testing framework utilizing minitest.
10
+ #
11
+ class Test < MiniTest::Test
12
+ include LucaSupport::Range
13
+ include LucaRecord::IO
14
+ include LucaBook::Accumulator
15
+ include LucaBook::Util
16
+ end
17
+ end
@@ -42,5 +42,15 @@ module LucaBook
42
42
  nil
43
43
  end
44
44
  end
45
+
46
+ def current_fy(date = nil, to: nil)
47
+ date ||= Date.today
48
+ start_month = LucaSupport::CONFIG['fy_start']
49
+ start_year = date.month >= start_month ? date.year : date.year - 1
50
+ @start_date = Date.new(start_year, start_month, 1)
51
+ @end_date = Date.new(start_year + 1, start_month - 1, -1)
52
+ @end_date = [to, @end_date].min if to
53
+ [@start_date, @end_date]
54
+ end
45
55
  end
46
56
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LucaBook
4
- VERSION = '0.2.27'
4
+ VERSION = '0.2.31'
5
5
  end
data/lib/luca_book.rb CHANGED
@@ -13,5 +13,6 @@ module LucaBook
13
13
  autoload :ListByHeader, 'luca_book/list_by_header'
14
14
  autoload :Setup, 'luca_book/setup'
15
15
  autoload :State, 'luca_book/state'
16
+ autoload :Test, 'luca_book/test'
16
17
  autoload :Util, 'luca_book/util'
17
18
  end
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.27
4
+ version: 0.2.31
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chuma Takahiro
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-15 00:00:00.000000000 Z
11
+ date: 2022-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lucarecord
@@ -68,7 +68,7 @@ dependencies:
68
68
  version: 12.3.3
69
69
  description: 'Book keep
70
70
 
71
- '
71
+ '
72
72
  email:
73
73
  - co.chuma@gmail.com
74
74
  executables:
@@ -95,7 +95,9 @@ files:
95
95
  - lib/luca_book/templates/dict-en.tsv
96
96
  - lib/luca_book/templates/dict-jp-edinet.tsv
97
97
  - lib/luca_book/templates/dict-jp.tsv
98
+ - lib/luca_book/templates/journals.html.erb
98
99
  - lib/luca_book/templates/monthly-report.html.erb
100
+ - lib/luca_book/test.rb
99
101
  - lib/luca_book/util.rb
100
102
  - lib/luca_book/version.rb
101
103
  homepage: https://github.com/chumaltd/luca/tree/master/lucabook
@@ -104,7 +106,7 @@ licenses:
104
106
  metadata:
105
107
  homepage_uri: https://github.com/chumaltd/luca/tree/master/lucabook
106
108
  source_code_uri: https://github.com/chumaltd/luca/tree/master/lucabook
107
- post_install_message:
109
+ post_install_message:
108
110
  rdoc_options: []
109
111
  require_paths:
110
112
  - lib
@@ -119,8 +121,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
121
  - !ruby/object:Gem::Version
120
122
  version: '0'
121
123
  requirements: []
122
- rubygems_version: 3.2.3
123
- signing_key:
124
+ rubygems_version: 3.2.5
125
+ signing_key:
124
126
  specification_version: 4
125
127
  summary: Book keep
126
128
  test_files: []