lucabook 0.2.12 → 0.2.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/exe/luca-book +66 -50
- data/lib/luca_book.rb +2 -0
- data/lib/luca_book/console.rb +5 -15
- data/lib/luca_book/import.rb +39 -34
- data/lib/luca_book/journal.rb +4 -1
- data/lib/luca_book/list.rb +69 -0
- data/lib/luca_book/state.rb +10 -10
- data/lib/luca_book/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db7564331de8046e8a6507c2ccf7dc099382ff3fc1c6a603f9ecc290755398ba
|
4
|
+
data.tar.gz: 5fb64e6fbccc5a5e693211ae89d8bad6560593add1f26261879b2ae4bc67fa00
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4cee8065abe4d479dc909e2e9f12f0fdb942e7b3c51b2f5f5e993598080db28411625d990c7f7a7ec85ebc96686a4dcf6d0173e8fed58fd3a3261731ea3da831
|
7
|
+
data.tar.gz: 1cd81e73a4dfcf3eef52a8105b7e1dc921f9d79d8b9945bf2b9e74d80134d2ca157346d69d98a26037d0f087fa4475e05938ae0044a7b1fcb3120b744f3a9ba8
|
data/exe/luca-book
CHANGED
@@ -2,71 +2,87 @@
|
|
2
2
|
|
3
3
|
require 'optparse'
|
4
4
|
require 'luca_book'
|
5
|
-
require 'luca_book/console'
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
+
end
|
16
|
+
end
|
13
17
|
|
14
|
-
def list(args, params)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
def self.list(args, params)
|
19
|
+
if params['code']
|
20
|
+
LucaBook::List.term(*args, code: params['code']).flat_list.to_yaml
|
21
|
+
elsif args.length > 0
|
22
|
+
LucaBook::List.term(*args).flat_list.to_yaml
|
23
|
+
else
|
24
|
+
# TODO: define default function
|
25
|
+
end
|
26
|
+
end
|
22
27
|
end
|
23
|
-
end
|
24
28
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
class Report
|
30
|
+
def self.balancesheet(args, params)
|
31
|
+
LucaBook::State.term(*args).bs.to_yaml
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.profitloss(args, params)
|
35
|
+
LucaBook::State.term(*args).pl.to_yaml
|
36
|
+
end
|
32
37
|
end
|
33
38
|
end
|
34
39
|
|
40
|
+
|
35
41
|
LucaRecord::Base.valid_project?
|
36
42
|
cmd = ARGV.shift
|
43
|
+
params = {}
|
37
44
|
|
38
45
|
case cmd
|
39
|
-
when '
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
46
|
+
when /journals?/, 'j'
|
47
|
+
subcmd = ARGV.shift
|
48
|
+
case subcmd
|
49
|
+
when 'import'
|
50
|
+
OptionParser.new do |opt|
|
51
|
+
opt.banner = 'Usage: luca import filepath'
|
52
|
+
opt.on('-c', '--config VAL', 'import definition'){|v| params['config'] = v }
|
53
|
+
opt.on('-j', '--json', 'import via json format'){|_v| params['json'] = true }
|
54
|
+
args = opt.parse!(ARGV)
|
55
|
+
LucaCmd::Journal.import(args, params)
|
56
|
+
end
|
57
|
+
when 'list'
|
58
|
+
OptionParser.new do |opt|
|
59
|
+
opt.banner = 'Usage: luca list [year month]'
|
60
|
+
opt.on('-c', '--code VAL', 'search with code') { |v| params['code'] = v }
|
61
|
+
opt.on_tail('List records. If you specify code and/or month, search on each criteria.')
|
62
|
+
args = opt.parse!(ARGV)
|
63
|
+
LucaCmd::Journal.list(args, params)
|
64
|
+
end
|
55
65
|
end
|
56
|
-
when '
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
66
|
+
when /reports?/, 'r'
|
67
|
+
subcmd = ARGV.shift
|
68
|
+
case subcmd
|
69
|
+
when 'bs'
|
70
|
+
OptionParser.new do |opt|
|
71
|
+
opt.banner = 'Usage: luca-book reports bs'
|
72
|
+
args = opt.parse!(ARGV)
|
73
|
+
LucaCmd::Report.balancesheet(args, params)
|
74
|
+
end
|
75
|
+
when 'pl'
|
76
|
+
OptionParser.new do |opt|
|
77
|
+
opt.banner = 'Usage: luca-book reports pl'
|
78
|
+
args = opt.parse!(ARGV)
|
79
|
+
LucaCmd::Report.profitloss(args, params)
|
80
|
+
end
|
64
81
|
end
|
65
82
|
when '--help'
|
66
83
|
puts 'Usage: luca-book subcommand'
|
67
|
-
puts '
|
68
|
-
puts '
|
69
|
-
puts ' report: show reports'
|
84
|
+
puts ' journals: operate journal records'
|
85
|
+
puts ' reports: show reports'
|
70
86
|
else
|
71
87
|
puts 'Invalid subcommand'
|
72
88
|
end
|
data/lib/luca_book.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
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
|
7
8
|
autoload :Import, 'luca_book/import'
|
8
9
|
autoload :Journal, 'luca_book/journal'
|
10
|
+
autoload :List, 'luca_book/list'
|
9
11
|
autoload :Setup, 'luca_book/setup'
|
10
12
|
autoload :State, 'luca_book/state'
|
11
13
|
end
|
data/lib/luca_book/console.rb
CHANGED
@@ -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 =
|
8
|
+
@report = LucaBook::State.new(dir_path)
|
7
9
|
end
|
8
10
|
|
9
|
-
def
|
10
|
-
array = @report.
|
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
|
|
data/lib/luca_book/import.rb
CHANGED
@@ -19,36 +19,39 @@ module LucaBook
|
|
19
19
|
# TODO: yaml need to be configurable
|
20
20
|
@dict = LucaRecord::Dict.new("import-#{dict}.yaml")
|
21
21
|
@code_map = LucaRecord::Dict.reverse(LucaRecord::Dict.load('base.tsv'))
|
22
|
-
@config = @dict.csv_config
|
22
|
+
@config = @dict.csv_config if dict
|
23
23
|
end
|
24
24
|
|
25
25
|
# === JSON Format:
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
26
|
+
# [
|
27
|
+
# {
|
28
|
+
# "date": "2020-05-04",
|
29
|
+
# "debit" : [
|
30
|
+
# {
|
31
|
+
# "label": "savings accounts",
|
32
|
+
# "value": 20000
|
33
|
+
# }
|
34
|
+
# ],
|
35
|
+
# "credit" : [
|
36
|
+
# {
|
37
|
+
# "label": "trade notes receivable",
|
38
|
+
# "value": 20000
|
39
|
+
# }
|
40
|
+
# ],
|
41
|
+
# "note": "settlement for the last month trade"
|
42
|
+
# }
|
43
|
+
# ]
|
42
44
|
#
|
43
|
-
def import_json(io)
|
44
|
-
|
45
|
-
|
45
|
+
def self.import_json(io)
|
46
|
+
JSON.parse(io).each do |d|
|
47
|
+
validate(d)
|
46
48
|
|
47
|
-
|
48
|
-
|
49
|
-
|
49
|
+
code_map = LucaRecord::Dict.reverse(LucaRecord::Dict.load('base.tsv'))
|
50
|
+
d['debit'].each { |h| h['code'] = code_map.dig(h['label']) || DEBIT_DEFAULT }
|
51
|
+
d['credit'].each { |h| h['code'] = code_map.dig(h['label']) || CREDIT_DEFAULT }
|
50
52
|
|
51
|
-
|
53
|
+
LucaBook::Journal.create(d)
|
54
|
+
end
|
52
55
|
end
|
53
56
|
|
54
57
|
def import_csv
|
@@ -63,6 +66,16 @@ module LucaBook
|
|
63
66
|
end
|
64
67
|
end
|
65
68
|
|
69
|
+
def self.validate(obj)
|
70
|
+
raise 'NoDateKey' unless obj.key?('date')
|
71
|
+
raise 'NoDebitKey' unless obj.key?('debit')
|
72
|
+
raise 'NoDebitValue' if obj['debit'].empty?
|
73
|
+
raise 'NoCreditKey' unless obj.key?('credit')
|
74
|
+
raise 'NoCreditValue' if obj['credit'].empty?
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
66
79
|
#
|
67
80
|
# convert single entry data
|
68
81
|
#
|
@@ -87,7 +100,7 @@ module LucaBook
|
|
87
100
|
end
|
88
101
|
d['debit'][0]['value'] = value
|
89
102
|
d['credit'][0]['value'] = value
|
90
|
-
d['note'] =
|
103
|
+
d['note'] = Array(@config[:note]).map{ |col| row[col] }.join(' ')
|
91
104
|
end
|
92
105
|
end
|
93
106
|
|
@@ -105,7 +118,7 @@ module LucaBook
|
|
105
118
|
'code' => search_code(row[@config[:credit_label]], CREDIT_DEFAULT),
|
106
119
|
'value' => row.dig(@config[:credit_value])
|
107
120
|
}
|
108
|
-
d['note'] =
|
121
|
+
d['note'] = Array(@config[:note]).map{ |col| row[col] }.join(' ')
|
109
122
|
end
|
110
123
|
end
|
111
124
|
|
@@ -118,13 +131,5 @@ module LucaBook
|
|
118
131
|
|
119
132
|
"#{row.dig(@config[:year])}-#{row.dig(@config[:month])}-#{row.dig(@config[:day])}"
|
120
133
|
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
134
|
end
|
130
135
|
end
|
data/lib/luca_book/journal.rb
CHANGED
@@ -30,6 +30,9 @@ module LucaBook
|
|
30
30
|
f << LucaSupport::Code.readable(debit_amount)
|
31
31
|
f << credit_code
|
32
32
|
f << LucaSupport::Code.readable(credit_amount)
|
33
|
+
['x-customer', 'x-editor'].each do |x_header|
|
34
|
+
f << [x_header, d[x_header]] if d.dig(x_header)
|
35
|
+
end
|
33
36
|
f << []
|
34
37
|
f << [d.dig('note')]
|
35
38
|
end
|
@@ -80,8 +83,8 @@ module LucaBook
|
|
80
83
|
record[:note] << line.join(' ') if body
|
81
84
|
end
|
82
85
|
end
|
83
|
-
record[:note]&.join('\n')
|
84
86
|
end
|
87
|
+
record[:note] = record[:note]&.join('\n')
|
85
88
|
end
|
86
89
|
end
|
87
90
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
require 'date'
|
5
|
+
require 'luca_support'
|
6
|
+
require 'luca_record'
|
7
|
+
require 'luca_record/dict'
|
8
|
+
require 'luca_book'
|
9
|
+
|
10
|
+
# Journal List on specified term
|
11
|
+
#
|
12
|
+
module LucaBook
|
13
|
+
class List < LucaBook::Journal
|
14
|
+
@dirname = 'journals'
|
15
|
+
|
16
|
+
def initialize(data)
|
17
|
+
@data = data
|
18
|
+
@dict = LucaRecord::Dict.load('base.tsv')
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.term(from_year, from_month, to_year = from_year, to_month = from_month, code: nil, basedir: @dirname)
|
22
|
+
data = LucaBook::Journal.term(from_year, from_month, to_year, to_month, code).select do |dat|
|
23
|
+
if code.nil?
|
24
|
+
true
|
25
|
+
else
|
26
|
+
[:debit, :credit].map { |key| serialize_on_key(dat[key], :code) }.flatten.include?(code)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
new data
|
30
|
+
end
|
31
|
+
|
32
|
+
def convert_label
|
33
|
+
@data.each do |dat|
|
34
|
+
dat[:debit].each { |debit| debit[:code] = "#{debit[:code]} #{@dict.dig(debit[:code], :label)}" }
|
35
|
+
dat[:credit].each { |credit| credit[:code] = "#{credit[:code]} #{@dict.dig(credit[:code], :label)}" }
|
36
|
+
end
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def flat_list
|
41
|
+
convert_label
|
42
|
+
@data = @data.map do |dat|
|
43
|
+
idx = dat[:debit].length >= dat[:credit].length ? :debit : :credit
|
44
|
+
dat[idx].map.with_index do |_k, i|
|
45
|
+
date, txid = LucaSupport::Code.decode_id(dat[:id])
|
46
|
+
{}.tap do |res|
|
47
|
+
res['date'] = date
|
48
|
+
res['no'] = txid
|
49
|
+
res['id'] = dat[:id]
|
50
|
+
res['debit_code'] = dat[:debit][i][:code] if dat[:debit][i]
|
51
|
+
res['debit_amount'] = dat[:debit][i][:amount] if dat[:debit][i]
|
52
|
+
res['credit_code'] = dat[:credit][i][:code] if dat[:credit][i]
|
53
|
+
res['credit_amount'] = dat[:credit][i][:amount] if dat[:credit][i]
|
54
|
+
res['note'] = dat[:note]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end.flatten
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_yaml
|
62
|
+
YAML.dump(LucaSupport::Code.readable(@data)).tap { |data| puts data }
|
63
|
+
end
|
64
|
+
|
65
|
+
def dict
|
66
|
+
LucaBook::Dict::Data
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/luca_book/state.rb
CHANGED
@@ -51,18 +51,18 @@ module LucaBook
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def by_code(code, year=nil, month=nil)
|
54
|
-
raise
|
54
|
+
raise 'not supported year range yet' if ! year.nil? && month.nil?
|
55
55
|
|
56
|
-
|
57
|
-
full_term = scan_terms
|
56
|
+
balance = @book.load_start.dig(code) || 0
|
57
|
+
full_term = self.class.scan_terms
|
58
58
|
if ! month.nil?
|
59
|
-
pre_term = full_term.select{|y,m| y <= year.to_i && m < month.to_i }
|
60
|
-
|
61
|
-
[{ code: code, balance:
|
59
|
+
pre_term = full_term.select { |y, m| y <= year.to_i && m < month.to_i }
|
60
|
+
balance += pre_term.map { |y, m| self.class.net(y, m)}.inject(0){|sum, h| sum + h[code] }
|
61
|
+
[{ code: code, balance: balance, note: "#{code} #{dict.dig(code, :label)}" }] + records_with_balance(year, month, code, balance)
|
62
62
|
else
|
63
|
-
start = { code: code, balance:
|
64
|
-
full_term.map {|y, m| y }.uniq.map {|y|
|
65
|
-
records_with_balance(y, nil, code,
|
63
|
+
start = { code: code, balance: balance, note: "#{code} #{dict.dig(code, :label)}" }
|
64
|
+
full_term.map { |y, m| y }.uniq.map { |y|
|
65
|
+
records_with_balance(y, nil, code, balance)
|
66
66
|
}.flatten.prepend(start)
|
67
67
|
end
|
68
68
|
end
|
@@ -81,7 +81,7 @@ module LucaBook
|
|
81
81
|
current = @book.load_start
|
82
82
|
target = []
|
83
83
|
Dir.chdir(@book.pjdir) do
|
84
|
-
net_records = scan_terms
|
84
|
+
net_records = self.class.scan_terms.map do |year, month|
|
85
85
|
target << [year, month]
|
86
86
|
accumulate_month(year, month)
|
87
87
|
end
|
data/lib/luca_book/version.rb
CHANGED
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.
|
4
|
+
version: 0.2.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chuma Takahiro
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-11-
|
11
|
+
date: 2020-11-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: lucarecord
|
@@ -83,6 +83,7 @@ files:
|
|
83
83
|
- lib/luca_book/dict.rb
|
84
84
|
- lib/luca_book/import.rb
|
85
85
|
- lib/luca_book/journal.rb
|
86
|
+
- lib/luca_book/list.rb
|
86
87
|
- lib/luca_book/report.rb
|
87
88
|
- lib/luca_book/setup.rb
|
88
89
|
- lib/luca_book/state.rb
|