lucabook 0.2.27 → 0.2.31

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 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: []