lucaterm 0.1.2 → 0.2.0

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: a5c025e9af43938b46faab013fb8ad4bde69e7467c022deb4d08497aaa7b32eb
4
- data.tar.gz: 2cf8e35f2adfbe9ab7957aa45e94c8af5354b97a19c410dee0a996c0e144884a
3
+ metadata.gz: c072f724a2ad3fb09fc648c4912c974d8c874fd82165e525bb6cd3d06073f645
4
+ data.tar.gz: 6d6a198f22a9fab3ea8c6426f98571927577862b61f1b6b4f955e8442375b778
5
5
  SHA512:
6
- metadata.gz: ab2d8588d7e8f0903a74ed9005aee9637ac711c2653303606b7ed93b2c867da47eb6b6ec47836f6c2819534ba7099b94903124dec3a1fcde1b245b5814204425
7
- data.tar.gz: ee9956b01ffdd4022052f8a6d573005c3546106f33b5d14a013f29a30c19779fcc2adab42bfb655340a3cc327e041577ca5d8041d11dc990a3b44691cb8cef14
6
+ metadata.gz: 8d6b3ec02aaf1dac932d47dc74fa0c61604915a7ab79a3198c83075f67d94a5cffd5c5a2673cd8c852806aafcc8d875cc3040d5680c248fcfdcc25797c0030c2
7
+ data.tar.gz: 74d40973ea0f60f6e5dc9d40fd52d3548683525ffe018b5c1e054175dc06303eac3da2d4da9a10bff02c4f5e496bef4d495180dac7a5b37352c7d5816a606d11
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## LucaTerm 0.2.0
2
+
3
+ * `luca book`: Works without args. Show journals of the latest month.
4
+ * `luca book`: Show categories on Account code selection
5
+ * `luca book`: Show x-customer header on detail screen
6
+
1
7
  ## LucaTerm 0.1.2
2
8
 
3
9
  * `luca book`: '<' for prev month, '>' for next month.
data/exe/luca CHANGED
@@ -3,19 +3,22 @@
3
3
 
4
4
  require 'optparse'
5
5
  require 'curses'
6
+ require 'luca_book/journal'
6
7
  require 'luca_term'
7
8
 
8
9
  include Curses
9
10
 
10
- init_screen
11
- curs_set(0)
12
- noecho
13
11
 
14
12
  class LucaCmd
15
13
  def self.book(args, params = {})
14
+ init_screen
15
+ curs_set(0)
16
+ noecho
17
+
16
18
  begin
17
- window = Curses::Window.new(0, 0, 0, 0)
18
- LucaTerm::Book.journals(window, *ARGV)
19
+ window = Curses::Window.new(0, 0, 1, 0)
20
+ args = ARGV.empty? ? LucaBook::Journal.latest_month : ARGV
21
+ LucaTerm::Book.journals(window, *args)
19
22
  ensure
20
23
  close_screen
21
24
  end
@@ -4,13 +4,14 @@ require 'curses'
4
4
  require "unicode/display_width/string_ext"
5
5
  require 'mb_string'
6
6
  require 'luca_book'
7
-
7
+ require 'json'
8
8
  module LucaTerm
9
9
  class Book
10
10
  include Curses
11
- attr_accessor :window
11
+ attr_accessor :window, :modeline
12
12
 
13
13
  def initialize(window, year, month, data=nil)
14
+ @modeline = Window.new(1, 0, 0, 0)
14
15
  @window = window
15
16
  @year = year
16
17
  @month = month
@@ -26,16 +27,22 @@ module LucaTerm
26
27
  new(window, args[0], args[1], LucaSupport::Code.readable(LucaBook::List.term(*args).data))
27
28
  end
28
29
 
30
+ # render monthly journal list
31
+ #
29
32
  def main_loop
30
33
  loop do
34
+ modeline.setpos(0, 0)
35
+ modeline << "#{Date::ABBR_MONTHNAMES[@month.to_i]} #{@year}"
36
+ modeline.clrtoeol
37
+ modeline.refresh
38
+
31
39
  window.setpos(0,0)
32
40
  @visible.each.with_index(0) do |dat, i|
33
41
  cursor = i == @active ? :full : nil
34
42
  draw_line(dat, cursor, true)
35
- clrtoeol
36
43
  window << "\n"
37
44
  end
38
- (window.maxy - window.cury).times { window.deleteln() }
45
+ (window.maxy - window.cury).times { window << "\n" }
39
46
  window.refresh
40
47
 
41
48
  window.keypad(true)
@@ -52,7 +59,7 @@ module LucaTerm
52
59
  when 'G'
53
60
  cursor_last @data
54
61
  when 'm'
55
- ym = edit_dialog('Change month: [yyyy] m')&.split(/[\/\s]/)
62
+ ym = edit_dialog('Enter: [yyyy] m', title: 'Change Month')&.split(/[\/\s]/)
56
63
  ym = [@year, ym[0]] if ym.length == 1
57
64
  @data = LucaSupport::Code.readable(LucaBook::List.term(*ym).data)
58
65
  @year, @month = ym
@@ -75,8 +82,9 @@ module LucaTerm
75
82
  @visible = set_visible(@data)
76
83
  when KEY_ENTER, KEY_CTRL_J
77
84
  show_detail(@data[@index])
85
+ @visible = set_visible(@data)
78
86
  when 'N'
79
- newdate = edit_dialog "Enter date of new record: YYYY-m-d"
87
+ newdate = edit_dialog "Enter date of new record: YYYY-m-d", title: 'Create Journal'
80
88
  tmpl = {
81
89
  date: newdate,
82
90
  debit: [
@@ -93,16 +101,26 @@ module LucaTerm
93
101
  end
94
102
  end
95
103
 
104
+ # render each journal
105
+ #
96
106
  def show_detail(record)
97
107
  @d_v = 0
98
108
  @d_h = 0
99
109
  debit_length = Array(record[:debit]).length
100
110
  credit_length = Array(record[:credit]).length
101
111
  date, txid = LucaSupport::Code.decode_id(record[:id]) if record[:id]
112
+ fileid = record[:id].split('/').last if record[:id]
102
113
  date ||= record[:date]
114
+ modeline.setpos(0, 0)
115
+ modeline << "#{date} #{fileid} "
116
+ modeline.clrtoeol
117
+ modeline.refresh
118
+
103
119
  loop do
104
120
  window.setpos(0, 0)
105
- window << "#{date} "
121
+ if record.dig(:headers, 'x-customer')
122
+ window << format(" [%s] ", record.dig(:headers, 'x-customer'))
123
+ end
106
124
  window << record[:note]
107
125
  clrtoeol; window << "\n"
108
126
  [debit_length, credit_length].max.times do |i|
@@ -119,7 +137,7 @@ module LucaTerm
119
137
  clrtoeol
120
138
  window << "\n"
121
139
  end
122
- (window.maxy - window.cury).times { window.deleteln() }
140
+ (window.maxy - window.cury).times { window << "\n" }
123
141
  window.refresh
124
142
 
125
143
  window.keypad(true)
@@ -173,14 +191,15 @@ module LucaTerm
173
191
  debit_length = Array(record[:debit]).length
174
192
  credit_length = Array(record[:credit]).length
175
193
  when KEY_CTRL_J
176
- position = [0,1].include?(@d_h) ? :debit : :credit
194
+ position, counter = [0,1].include?(@d_h) ? [:debit, :credit] : [:credit, :debit]
177
195
  if [0, 2].include? @d_h
178
196
  new_code = select_code
179
197
  next if new_code.nil?
180
198
 
181
199
  record[position][@d_v][:code] = new_code
182
200
  else
183
- new_amount = edit_amount(record[position][@d_v][:amount])
201
+ diff = record[counter].map { |c| c[:amount] }.sum - record[position].map { |p| p[:amount] }.sum + record[position][@d_v][:amount]
202
+ new_amount = edit_amount(record[position][@d_v][:amount], diff)
184
203
  next if new_amount.nil?
185
204
 
186
205
  record[position][@d_v][:amount] = new_amount
@@ -198,9 +217,12 @@ module LucaTerm
198
217
  end
199
218
  end
200
219
 
201
- def edit_amount(current = nil)
220
+ # returns amount after edit
221
+ #
222
+ def edit_amount(current = nil, diff = nil)
223
+ diff_msg = diff.nil? ? '' : "#{diff} meets balance."
202
224
  begin
203
- scmd = edit_dialog "Current: #{current&.to_s}"
225
+ scmd = edit_dialog "Current: #{current&.to_s}", diff_msg, title: 'Edit Amount'
204
226
  return nil if scmd.length == 0
205
227
  # TODO: guard from not number
206
228
  return scmd.to_i
@@ -209,17 +231,22 @@ module LucaTerm
209
231
  end
210
232
  end
211
233
 
212
- def edit_dialog(message = '')
213
- sub = window.subwin(4, 30, (window.maxy-4)/2, (window.maxx - 30)/2)
214
- sub.box(?|, ?-)
234
+ def edit_dialog(message = '', submessage = '', title: '')
235
+ sub = window.subwin(5, 30, (window.maxy-5)/2, (window.maxx - 30)/2)
215
236
  sub.setpos(1, 1)
216
- padding = [0, 30 - message.length - 4].max
217
- sub << " #{message + ' ' * padding}"
218
- clrtoeol
237
+ sub << " #{message}"
238
+ sub.clrtoeol
219
239
  sub.setpos(2, 1)
220
- sub << " > #{' ' * (30 - 6)}"
221
- sub.setpos(2, 6)
222
- clrtoeol
240
+ sub.clrtoeol
241
+ sub.setpos(2, 3)
242
+ sub.attron(A_REVERSE) { sub << " > #{' ' * (30 - 9)}" }
243
+ sub.setpos(3, 1)
244
+ sub << " #{submessage}"
245
+ sub.clrtoeol
246
+ sub.box(?|, ?-)
247
+ sub.setpos(0, 2)
248
+ sub << "[ #{title} ]"
249
+ sub.setpos(2, 7)
223
250
  sub.refresh
224
251
  loop do
225
252
  echo
@@ -230,57 +257,75 @@ module LucaTerm
230
257
  end
231
258
  end
232
259
 
260
+ # returns Account code after selection from list dialog
261
+ #
233
262
  def select_code
234
- list = @dict.map{ |code, entry| { code: code, label: entry[:label] } }
235
- .select{ |d| d[:code].length >= 3 }
263
+ top = window.maxy >= 25 ? 5 : 2
264
+ sub = window.subwin(window.maxy - top, window.maxx - 4, top, 2)
265
+ padding = ' ' * account_index(sub.maxx)[0].length
266
+ list = @dict.reject{ |code, _e| code.length < 3 || /^[15]0XX/.match(code) || /^[89]ZZ/.match(code) }
267
+ .map{ |code, entry| { code: code, label: entry[:label], category: padding } }
268
+ tabstop = ['1', '5', '9', 'A', 'C'].map { |cap| list.index { |ac| /^#{cap}/.match(ac[:code]) } }.compact
269
+ account_index(sub.maxx).each.with_index do |cat, i|
270
+ list[tabstop[i]][:category] = cat
271
+ end
236
272
  visible_dup = @visible
237
273
  index_dup = @index
238
274
  active_dup = @active
239
275
  @index = 0
240
276
  @active = 0
241
277
  @visible = nil
242
- @visible = set_visible(list)
278
+ @visible = set_visible(list, sub.maxy - 2)
243
279
  loop do
244
- window.setpos(0,0)
245
280
  @visible.each.with_index(0) do |entry, i|
246
- line = format("%s %s", entry[:code], entry[:label])
281
+ sub.setpos(i+1, 1)
282
+ head = entry[:code].length == 3 ? '' : ' '
283
+ line = format("%s %s %s %s", head, entry[:category], entry[:code], entry[:label])
247
284
  if i == @active
248
- window.attron(A_REVERSE) { window << line }
285
+ sub.attron(A_REVERSE) { sub << line }
249
286
  else
250
- window << line
287
+ sub << line
251
288
  end
252
- clrtoeol
253
- window << "\n"
289
+ sub.clrtoeol
290
+ #sub << "\n"
254
291
  end
255
- (window.maxy - window.cury).times { window.deleteln() }
256
- window.refresh
292
+ (window.maxy - window.cury).times { window << "\n" }
293
+ sub.box(?|, ?-)
294
+ sub.setpos(0, 2)
295
+ sub << "[ Select Account ]"
296
+ sub.refresh
257
297
 
258
298
  cmd = window.getch
259
299
  case cmd
260
300
  when KEY_DOWN, 'j', KEY_CTRL_N
261
301
  next if @index >= list.length - 1
262
302
 
263
- cursor_down list
303
+ cursor_down list, sub.maxy - 2
264
304
  when KEY_NPAGE
265
- cursor_pagedown list
305
+ cursor_pagedown list, sub.maxy - 2
266
306
  when KEY_UP, 'k', KEY_CTRL_P
267
307
  next if @index <= 0
268
308
 
269
309
  cursor_up list
270
310
  when KEY_PPAGE
271
- cursor_pageup list
311
+ cursor_pageup list, sub.maxy - 2
312
+ when KEY_LEFT
313
+ cursor_jump tabstop, list, rev: true
314
+ when KEY_RIGHT
315
+ cursor_jump tabstop, list
272
316
  when 'G'
273
- cursor_last list
317
+ cursor_last list, sub.maxy - 2
274
318
  when KEY_CTRL_J
275
- code = list[@index][:code]
276
319
  @visible = visible_dup
277
320
  @index = index_dup
278
321
  @active = active_dup
279
- return code
322
+ sub.close
323
+ return list[@index][:code]
280
324
  when 'q'
281
325
  @visible = visible_dup
282
326
  @index = index_dup
283
327
  @active = active_dup
328
+ sub.close
284
329
  return nil
285
330
  end
286
331
  end
@@ -288,17 +333,36 @@ module LucaTerm
288
333
 
289
334
  private
290
335
 
336
+ def account_index(maxx = 50)
337
+ term = if maxx >= 45
338
+ ['Assets', 'Liabilities', 'Net Assets', 'Sales', 'Expenses']
339
+ elsif maxx >= 40
340
+ ['Assets', 'LIAB', 'NetAsset', 'Sales', 'EXP']
341
+ else
342
+ ['', '', '', '', '']
343
+ end
344
+ len = term.map { |str| str.length }.max
345
+ term.map { |str| str += ' ' * (len - str.length) }
346
+ end
347
+
291
348
  def draw_line(dat, cursor = nil, note = false)
292
349
  date, txid = LucaSupport::Code.decode_id(dat[:id]) if dat[:id]
350
+ date_str = date.nil? ? '' : date.split('-')[1, 2].join('/')&.mb_rjust(5, ' ')
293
351
  debit_cd = fmt_code(dat[:debit])
294
352
  debit_amount = fmt_amount(dat[:debit])
295
353
  credit_cd = fmt_code(dat[:credit])
296
354
  credit_amount = fmt_amount(dat[:credit])
297
355
  lines = [Array(dat[:debit]).length, Array(dat[:credit]).length].max
298
- window << sprintf("%s %s |%s| ",
299
- date&.mb_rjust(10, ' ') || '',
300
- txid || '',
301
- lines > 1 ? lines.to_s : ' ',
356
+ lines = if lines == 1
357
+ ' '
358
+ elsif lines > 9
359
+ '+'
360
+ else
361
+ lines
362
+ end
363
+ window << sprintf("%s |%s| ",
364
+ date_str,
365
+ lines,
302
366
  )
303
367
  case cursor
304
368
  when 0
@@ -317,8 +381,8 @@ module LucaTerm
317
381
  window.attron(A_REVERSE) { window << credit_amount }
318
382
  else
319
383
  rest = format("%s %s | %s %s", debit_cd, debit_amount, credit_cd, credit_amount)
320
- if note && window.maxx > 80
321
- rest += " | #{dat[:note].mb_truncate(window.maxx - 80)}"
384
+ if note && window.maxx > 70
385
+ rest += " | #{dat[:note]&.mb_truncate(window.maxx - 70)}"
322
386
  end
323
387
  if cursor == :full
324
388
  window.attron(A_REVERSE) { window << rest }
@@ -354,46 +418,62 @@ module LucaTerm
354
418
  @visible = set_visible(data)
355
419
  end
356
420
 
357
- def cursor_pageup(data)
358
- n_idx = @index - window.maxy
421
+ def cursor_pageup(data, maxy = nil)
422
+ maxy ||= window.maxy
423
+ n_idx = @index - maxy
359
424
  return if n_idx <= 0
360
425
 
361
426
  @index = n_idx
362
427
  @active = 0
363
- @visible = set_visible(data)
428
+ @visible = set_visible(data, maxy)
364
429
  end
365
430
 
366
- def cursor_down(data)
431
+ def cursor_down(data, maxy = nil)
432
+ maxy ||= window.maxy
367
433
  @index += 1
368
- @active = @active >= window.maxy - 1 ? window.maxy - 1 : @active + 1
369
- @visible = set_visible(data)
434
+ @active = @active >= maxy - 1 ? @active : @active + 1
435
+ @visible = set_visible(data, maxy)
370
436
  end
371
437
 
372
- def cursor_pagedown(data)
373
- n_idx = @index + window.maxy
438
+ def cursor_pagedown(data, maxy = nil)
439
+ maxy ||= window.maxy
440
+ n_idx = @index + maxy
374
441
  return if n_idx >= data.length - 1
375
442
 
376
443
  @index = n_idx
444
+ @active = 0
445
+ @visible = set_visible(data, maxy)
446
+ end
447
+
448
+ def cursor_jump(tabstop, data, rev: false)
449
+ @index = if rev
450
+ tabstop.filter{ |t| t < @index ? t : nil }.max || @index
451
+ else
452
+ tabstop.filter{ |t| t > @index ? t : nil }.min || @index
453
+ end
454
+
377
455
  @active = 0
378
456
  @visible = set_visible(data)
379
457
  end
380
458
 
381
- def cursor_last(data)
459
+ def cursor_last(data, maxy = nil)
460
+ maxy ||= window.maxy
382
461
  @index = data.length - 1
383
- @active = window.maxy - 1
384
- @visible = set_visible(data)
462
+ @active = maxy - 1
463
+ @visible = set_visible(data, maxy)
385
464
  end
386
465
 
387
- def set_visible(data)
388
- return data if data.nil? || data.length <= window.maxy
466
+ def set_visible(data, maxy = nil)
467
+ maxy ||= window.maxy
468
+ return data if data.nil? || data.length <= maxy
389
469
 
390
470
  if @visible.nil?
391
- data.slice(0, window.maxy)
471
+ data.slice(0, maxy)
392
472
  else
393
- if @active == (window.maxy - 1)
394
- data.slice(@index - window.maxy + 1, window.maxy)
473
+ if @active == (maxy - 1)
474
+ data.slice(@index - maxy + 1, maxy)
395
475
  elsif @active == 0
396
- data.slice(@index, window.maxy)
476
+ data.slice(@index, maxy)
397
477
  else
398
478
  @visible
399
479
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LucaTerm
4
- VERSION = '0.1.2'
4
+ VERSION = '0.2.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lucaterm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
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-07-30 00:00:00.000000000 Z
11
+ date: 2022-03-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: curses
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: lucarecord
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0.3'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0.3'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: bundler
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -96,7 +110,7 @@ dependencies:
96
110
  version: 12.3.3
97
111
  description: 'Terminal frontend for Luca Suite
98
112
 
99
- '
113
+ '
100
114
  email:
101
115
  - co.chuma@gmail.com
102
116
  executables:
@@ -116,7 +130,7 @@ metadata:
116
130
  homepage_uri: https://github.com/chumaltd/luca/tree/master/lucaterm
117
131
  source_code_uri: https://github.com/chumaltd/luca/tree/master/lucaterm
118
132
  changelog_uri: https://github.com/chumaltd/luca/tree/master/lucaterm/CHANGELOG.md
119
- post_install_message:
133
+ post_install_message:
120
134
  rdoc_options: []
121
135
  require_paths:
122
136
  - lib
@@ -131,8 +145,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
131
145
  - !ruby/object:Gem::Version
132
146
  version: '0'
133
147
  requirements: []
134
- rubygems_version: 3.2.3
135
- signing_key:
148
+ rubygems_version: 3.2.5
149
+ signing_key:
136
150
  specification_version: 4
137
151
  summary: Terminal frontend for Luca Suite
138
152
  test_files: []