lucabook 0.2.10 → 0.2.18

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: 52bbc28428badf8b379f7a2f3e8ebf9a9a6f5bf0a496b433964af96fd644945f
4
- data.tar.gz: 8a321eceda532d2484c622fc6ace820ba44a5ec6715727fe406b8e68fe9284a7
3
+ metadata.gz: d25b3a6c62980682db52a5553ce26cafdcb36e80e9657a302a8413e1e92b565b
4
+ data.tar.gz: e82a86c04d13aa6addef398afd85755a7a54ce437d1e9415ce3f98bf1b28f914
5
5
  SHA512:
6
- metadata.gz: 30fbac4fe640155e20314cdb55058e5ef0bcfad21d4d1f94f082f8123a8ff0b9211a02c6285a6d4fb1c630a615d83df6062afde4560aa419bf49e41c93967021
7
- data.tar.gz: 9d117b4365d2c0efaade185af52e647a521fcd1fce540abd22480c7935476646a9a9e6bf17ff81633b0bec2d36ffdae3b6193c9c66de9ab851d8cde4195339b1
6
+ metadata.gz: 652c00f982977bbb619bfc834c312dbbb06f2ada524e1824869c04ef4ed09e3fadd5aee2b082fc3944cda4eaf7bfd18fd041a80582fe57f67cc88d13197b60a6
7
+ data.tar.gz: 422dedf33b9a9bd53ac8502613ae4a27c3c10730e2ac65841fddd9e424d9435a2cb92118700f9571dceea09b54b1f9a1538b9c76facfed87542832e2ce4ba939
@@ -2,71 +2,142 @@
2
2
 
3
3
  require 'optparse'
4
4
  require 'luca_book'
5
- require 'luca_book/console'
6
5
 
7
- def import(args, params)
8
- if params['config']
9
- LucaBook::Import.new(args[0], params['config']).import_csv
10
- else
11
- puts 'Usage: luca-book import -c import_config'
6
+ module LucaCmd
7
+ class Journal
8
+ def self.import(args, params)
9
+ if params['config']
10
+ LucaBook::Import.new(args[0], params['config']).import_csv
11
+ elsif params['json']
12
+ LucaBook::Import.import_json(STDIN.read)
13
+ else
14
+ puts 'Usage: luca-book import -c import_config'
15
+ exit 1
16
+ end
17
+ end
18
+
19
+ def self.list(args, params)
20
+ args = LucaCmd.gen_range(params[:n] || 1) if args.empty?
21
+ if params['code']
22
+ LucaBook::List.term(*args, code: params['code']).list_on_code.to_yaml
23
+ else
24
+ LucaBook::List.term(*args).list_journals.to_yaml
25
+ end
26
+ end
27
+
28
+ def self.stats(args, params)
29
+ args = LucaCmd.gen_range(params[:n]) if args.empty?
30
+ LucaBook::State.term(*args).stats(params[:level])
31
+ end
12
32
  end
13
33
 
14
- def list(args, params)
15
- if params['c'] or params['code']
16
- code = params['c'] || params['code']
17
- LucaBookConsole.new.by_code(code, args.dig(0), args.dig(1))
18
- elsif args.length > 0
19
- LucaBookConsole.new.by_month(args[0], args.dig(1))
20
- else
21
- LucaBookConsole.new.all
34
+ class Report
35
+ def self.balancesheet(args, params)
36
+ level = params[:level] || 2
37
+ legal = params[:legal] || false
38
+ args = LucaCmd.gen_range(params[:n] || 1) if args.empty?
39
+ LucaBook::State.term(*args).bs(level, legal: legal)
40
+ end
41
+
42
+ def self.profitloss(args, params)
43
+ args = LucaCmd.gen_range(params[:n]) if args.empty?
44
+ LucaBook::State.term(*args).pl.to_yaml
45
+ end
22
46
  end
23
- end
24
47
 
25
- def report(args, params)
26
- if params['bs']
27
- LucaBook::State.term(*args).bs.to_yaml
28
- elsif params['pl']
29
- LucaBook::State.term(*args).pl.to_yaml
30
- else
31
- LucaBook::State.term(*args).to_yaml
48
+ module_function
49
+
50
+ def gen_range(count)
51
+ count ||= 3
52
+ today = Date.today
53
+ start = today.prev_month(count - 1)
54
+ [start.year, start.month, today.year, today.month]
32
55
  end
33
56
  end
34
57
 
58
+ def new_pj(args = nil, params = {})
59
+ LucaBook::Setup.create_project params['country'], args[0]
60
+ end
61
+
35
62
  LucaRecord::Base.valid_project?
36
63
  cmd = ARGV.shift
64
+ params = {}
37
65
 
38
66
  case cmd
39
- when 'import'
40
- params = {}
41
- OptionParser.new do |opt|
42
- opt.banner = 'Usage: luca import filepath'
43
- opt.on('-c', '--config VAL', 'import definition'){|v| params["config"] = v }
44
- args = opt.parse!(ARGV)
45
- import(args, params)
67
+ when /journals?/, 'j'
68
+ subcmd = ARGV.shift
69
+ case subcmd
70
+ when 'import'
71
+ OptionParser.new do |opt|
72
+ opt.banner = 'Usage: luca-book journals import [options] filepath'
73
+ opt.on('-c', '--config VAL', 'import definition'){ |v| params['config'] = v }
74
+ opt.on('-j', '--json', 'import via json format'){ |_v| params['json'] = true }
75
+ args = opt.parse!(ARGV)
76
+ LucaCmd::Journal.import(args, params)
77
+ end
78
+ when 'list'
79
+ OptionParser.new do |opt|
80
+ opt.banner = 'Usage: luca-book journals list [options] [YYYY M]'
81
+ opt.on('-c', '--code VAL', 'search with code') { |v| params['code'] = v }
82
+ opt.on('-n VAL', 'report count') { |v| params[:n] = v.to_i }
83
+ opt.on_tail('List records. If you specify code and/or month, search on each criteria.')
84
+ args = opt.parse!(ARGV)
85
+ LucaCmd::Journal.list(args, params)
86
+ end
87
+ when 'stats'
88
+ OptionParser.new do |opt|
89
+ opt.banner = 'Usage: luca-book journals stats [options] [YYYY M]'
90
+ opt.on('-n VAL', 'report count') { |v| params[:n] = v.to_i }
91
+ args = opt.parse!(ARGV)
92
+ LucaCmd::Journal.stats(args, params)
93
+ end
94
+ else
95
+ puts 'Proper subcommand needed.'
96
+ puts
97
+ puts 'Usage: luca-book (j|journal[s]) subcommand [options] [YYYY M YYYY M]'
98
+ puts ' import: import journals from JSON/TSV'
99
+ puts ' list: list journals'
100
+ puts ' stats: list account statistics'
101
+ exit 1
46
102
  end
47
- when 'list'
48
- params = {}
103
+ when 'new'
49
104
  OptionParser.new do |opt|
50
- opt.banner = 'Usage: luca list [year month]'
51
- opt.on('-c', '--code VAL', 'search with code'){|v| params["code"] = v }
52
- opt.on_tail('List records. If you specify code and/or month, search on each criteria.')
53
- args = opt.parse!(ARGV)
54
- list(args, params)
105
+ opt.banner = 'Usage: luca-book new [options] Dir'
106
+ opt.on('-c', '--country VAL', 'specify country code') { |v| params['coountry'] = v }
107
+ args = opt.parse(ARGV)
108
+ new_pj(args, params)
55
109
  end
56
- when 'report'
57
- params = {}
58
- OptionParser.new do |opt|
59
- opt.banner = 'Usage: luca-book report'
60
- opt.on('--bs', 'show Balance sheet'){|v| params["bs"] = v }
61
- opt.on('--pl', 'show Income statement'){|v| params["pl"] = v }
62
- args = opt.parse!(ARGV)
63
- report(args, params)
110
+ when /reports?/, 'r'
111
+ subcmd = ARGV.shift
112
+ case subcmd
113
+ when 'bs'
114
+ OptionParser.new do |opt|
115
+ opt.banner = 'Usage: luca-book reports bs [options] [YYYY M]'
116
+ opt.on('-l', '--level VAL', 'account level') { |v| params[:level] = v.to_i }
117
+ opt.on('--legal', 'show legal mandatory account') { |_v| params[:legal] = true }
118
+ args = opt.parse!(ARGV)
119
+ LucaCmd::Report.balancesheet(args, params)
120
+ end
121
+ when 'pl'
122
+ OptionParser.new do |opt|
123
+ opt.banner = 'Usage: luca-book reports pl [options] [YYYY M YYYY M]'
124
+ opt.on('-n VAL', 'report count') { |v| params[:n] = v.to_i }
125
+ args = opt.parse!(ARGV)
126
+ LucaCmd::Report.profitloss(args, params)
127
+ end
128
+ else
129
+ puts 'Proper subcommand needed.'
130
+ puts
131
+ puts 'Usage: luca-book (r|report[s]) (bs|pl) [options] YYYY M'
132
+ puts ' bs: show balance sheet'
133
+ puts ' pl: show statement of income'
134
+ exit 1
64
135
  end
65
- when '--help'
66
- puts 'Usage: luca-book subcommand'
67
- puts ' import: import records'
68
- puts ' list: list records'
69
- puts ' report: show reports'
70
136
  else
71
- puts 'Invalid subcommand'
137
+ puts 'Proper subcommand needed.'
138
+ puts
139
+ puts 'Usage: luca-book (j[ournals]|r[eports]) subcommand'
140
+ puts ' journals: operate journal records'
141
+ puts ' reports: show reports'
142
+ exit 1
72
143
  end
@@ -1,11 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'csv'
3
4
  require 'luca_record'
4
5
  require 'luca_book/version'
5
6
 
6
7
  module LucaBook
8
+ autoload :Dict, 'luca_book/dict'
7
9
  autoload :Import, 'luca_book/import'
8
10
  autoload :Journal, 'luca_book/journal'
11
+ autoload :List, 'luca_book/list'
9
12
  autoload :Setup, 'luca_book/setup'
10
13
  autoload :State, 'luca_book/state'
14
+ autoload :Util, 'luca_book/util'
11
15
  end
@@ -1,25 +1,15 @@
1
1
  require 'luca_book'
2
2
 
3
+ # This class will be deleted
4
+ #
3
5
  class LucaBookConsole
4
6
 
5
7
  def initialize(dir_path=nil)
6
- @report = LucaBookReport.new(dir_path)
8
+ @report = LucaBook::State.new(dir_path)
7
9
  end
8
10
 
9
- def all
10
- array = @report.scan_terms(@report.book.pjdir).map{|y,m| y}.uniq.map{|year|
11
- @report.book.search(year)
12
- }.flatten
13
- show_records(array)
14
- end
15
-
16
- def by_code(code, year=nil, month=nil)
17
- array = @report.by_code(code, year, month)
18
- show_records(array)
19
- end
20
-
21
- def by_month(year, month)
22
- array = @report.book.search(year, month)
11
+ def by_term(year, month, end_year = year, end_month = month)
12
+ array = @report.book.class.term(year, month, end_year, end_month)
23
13
  show_records(array)
24
14
  end
25
15
 
@@ -39,6 +29,7 @@ class LucaBookConsole
39
29
  end
40
30
  end
41
31
 
32
+ # TODO: deprecated. accumulate_all() already removed.
42
33
  def bs
43
34
  target = []
44
35
  report = []
@@ -66,6 +57,7 @@ class LucaBookConsole
66
57
  puts "---- ----"
67
58
  end
68
59
 
60
+ # TODO: deprecated. accumulate_all() already removed.
69
61
  def pl
70
62
  target = []
71
63
  report = []
@@ -2,12 +2,19 @@
2
2
 
3
3
  require 'luca_support/config'
4
4
  require 'luca_record/dict'
5
+ require 'date'
6
+ require 'pathname'
5
7
 
6
8
  module LucaBook
7
9
  class Dict < LucaRecord::Dict
10
+ def self.latest_balance
11
+ dict_dir = Pathname(LucaSupport::Config::Pjdir) / 'data' / 'balance'
12
+ # TODO: search latest balance dictionary
13
+ load_tsv_dict(dict_dir / 'start.tsv')
14
+ end
8
15
 
9
- @filename = 'dict.tsv'
10
-
11
- Data = load
16
+ def self.issue_date(obj)
17
+ Date.parse(obj.dig('_date', :label))
18
+ end
12
19
  end
13
20
  end
@@ -9,70 +9,84 @@ require 'luca_record'
9
9
 
10
10
  module LucaBook
11
11
  class Import
12
- DEBIT_DEFAULT = '仮払金'
13
- CREDIT_DEFAULT = '仮受金'
12
+ DEBIT_DEFAULT = '10XX'
13
+ CREDIT_DEFAULT = '50XX'
14
14
 
15
15
  def initialize(path, dict)
16
16
  raise 'no such file' unless FileTest.file?(path)
17
17
 
18
18
  @target_file = path
19
19
  # TODO: yaml need to be configurable
20
+ @dict_name = dict
20
21
  @dict = LucaRecord::Dict.new("import-#{dict}.yaml")
21
22
  @code_map = LucaRecord::Dict.reverse(LucaRecord::Dict.load('base.tsv'))
22
- @config = @dict.csv_config
23
+ @config = @dict.csv_config if dict
23
24
  end
24
25
 
25
26
  # === JSON Format:
26
- # {
27
- # "date": "2020-05-04",
28
- # "debit" : [
29
- # {
30
- # "label": "savings accounts",
31
- # "value": 20000
32
- # }
33
- # ],
34
- # "credit" : [
35
- # {
36
- # "label": "trade notes receivable",
37
- # "value": 20000
38
- # }
39
- # ],
40
- # "note": "settlement for the last month trade"
41
- # }
27
+ # [
28
+ # {
29
+ # "date": "2020-05-04",
30
+ # "debit" : [
31
+ # {
32
+ # "label": "savings accounts",
33
+ # "value": 20000
34
+ # }
35
+ # ],
36
+ # "credit" : [
37
+ # {
38
+ # "label": "trade notes receivable",
39
+ # "value": 20000
40
+ # }
41
+ # ],
42
+ # "note": "settlement for the last month trade"
43
+ # }
44
+ # ]
42
45
  #
43
- def import_json(io)
44
- d = JSON.parse(io)
45
- validate(d)
46
+ def self.import_json(io)
47
+ JSON.parse(io).each do |d|
48
+ validate(d)
46
49
 
47
- # dict = LucaBook::Dict.reverse_dict(LucaBook::Dict::Data)
48
- d['debit'].each { |h| h['code'] = @dict.search(h['label'], DEBIT_DEFAULT) }
49
- d['credit'].each { |h| h['code'] = @dict.search(h['label'], CREDIT_DEFAULT) }
50
+ code_map = LucaRecord::Dict.reverse(LucaRecord::Dict.load('base.tsv'))
51
+ d['debit'].each { |h| h['code'] = code_map.dig(h['label']) || DEBIT_DEFAULT }
52
+ d['credit'].each { |h| h['code'] = code_map.dig(h['label']) || CREDIT_DEFAULT }
50
53
 
51
- LucaBook.new.create!(d)
54
+ LucaBook::Journal.create(d)
55
+ end
52
56
  end
53
57
 
54
58
  def import_csv
55
59
  @dict.load_csv(@target_file) do |row|
56
60
  if @config[:type] == 'single'
57
- LucaBook::Journal.create!(parse_single(row))
61
+ LucaBook::Journal.create(parse_single(row))
58
62
  elsif @config[:type] == 'double'
59
- p parse_double(row)
63
+ p parse_double(row) # TODO: Not implemented yet
60
64
  else
61
65
  p row
62
66
  end
63
67
  end
64
68
  end
65
69
 
70
+ def self.validate(obj)
71
+ raise 'NoDateKey' unless obj.key?('date')
72
+ raise 'NoDebitKey' unless obj.key?('debit')
73
+ raise 'NoDebitValue' if obj['debit'].empty?
74
+ raise 'NoCreditKey' unless obj.key?('credit')
75
+ raise 'NoCreditValue' if obj['credit'].empty?
76
+ end
77
+
78
+ private
79
+
66
80
  #
67
81
  # convert single entry data
68
82
  #
69
83
  def parse_single(row)
70
84
  value = row.dig(@config[:credit_value])&.empty? ? row[@config[:debit_value]] : row[@config[:credit_value]]
71
- {}.tap do |d|
85
+ {}.tap do |d|
72
86
  d['date'] = parse_date(row)
73
87
  if row.dig(@config[:credit_value])&.empty?
74
88
  d['debit'] = [
75
- { 'code' => search_code(row[@config[:label]], DEBIT_DEFAULT) }
89
+ { 'code' => search_code(row[@config[:label]], @config.dig(:default_debit)) || DEBIT_DEFAULT }
76
90
  ]
77
91
  d['credit'] = [
78
92
  { 'code' => @code_map.dig(@config[:counter_label]) }
@@ -82,12 +96,13 @@ module LucaBook
82
96
  { 'code' => @code_map.dig(@config[:counter_label]) }
83
97
  ]
84
98
  d['credit'] = [
85
- { 'code' => search_code(row[@config[:label]], CREDIT_DEFAULT) }
99
+ { 'code' => search_code(row[@config[:label]], @config.dig(:default_credit)) || CREDIT_DEFAULT }
86
100
  ]
87
101
  end
88
102
  d['debit'][0]['value'] = value
89
103
  d['credit'][0]['value'] = value
90
- d['note'] = row[@config[:note]]
104
+ d['note'] = Array(@config[:note]).map{ |col| row[col] }.join(' ')
105
+ d['x-editor'] = "LucaBook::Import/#{@dict_name}"
91
106
  end
92
107
  end
93
108
 
@@ -98,14 +113,15 @@ module LucaBook
98
113
  {}.tap do |d|
99
114
  d['date'] = parse_date(row)
100
115
  d['debit'] = {
101
- 'code' => search_code(row[@config[:debit_label]], DEBIT_DEFAULT),
116
+ 'code' => search_code(row[@config[:label]], @config.dig(:default_debit)) || DEBIT_DEFAULT,
102
117
  'value' => row.dig(@config[:debit_value])
103
118
  }
104
119
  d['credit'] = {
105
- 'code' => search_code(row[@config[:credit_label]], CREDIT_DEFAULT),
120
+ 'code' => search_code(row[@config[:label]], @config.dig(:default_credit)) || CREDIT_DEFAULT,
106
121
  'value' => row.dig(@config[:credit_value])
107
122
  }
108
- d['note'] = row[@config[:note]]
123
+ d['note'] = Array(@config[:note]).map{ |col| row[col] }.join(' ')
124
+ d['x-editor'] = "LucaBook::Import/#{@dict_name}"
109
125
  end
110
126
  end
111
127
 
@@ -118,13 +134,5 @@ module LucaBook
118
134
 
119
135
  "#{row.dig(@config[:year])}-#{row.dig(@config[:month])}-#{row.dig(@config[:day])}"
120
136
  end
121
-
122
- def validate(obj)
123
- raise 'NoDateKey' if ! obj.has_key?('date')
124
- raise 'NoDebitKey' if ! obj.has_key?('debit')
125
- raise 'NoDebitValue' if obj['debit'].length < 1
126
- raise 'NoCreditKey' if ! obj.has_key?('credit')
127
- raise 'NoCreditValue' if obj['credit'].length < 1
128
- end
129
137
  end
130
138
  end