lucabook 0.2.10 → 0.2.18

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