ledger-rest 2.0.3 → 3.0.0
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 +15 -0
- data/.gitignore +2 -0
- data/Gemfile +1 -1
- data/Guardfile +4 -22
- data/{LICENSE.txt → LICENSE} +1 -1
- data/README.md +62 -11
- data/config.ru +1 -1
- data/ledger-rest.gemspec +17 -17
- data/ledger-rest.yml.example +3 -0
- data/lib/ledger-rest/app.rb +21 -34
- data/lib/ledger-rest/core_ext.rb +4 -3
- data/lib/ledger-rest/git.rb +8 -7
- data/lib/ledger-rest/ledger.rb +29 -24
- data/lib/ledger-rest/ledger/balance.rb +48 -15
- data/lib/ledger-rest/ledger/budget.rb +35 -16
- data/lib/ledger-rest/ledger/entry.rb +1 -4
- data/lib/ledger-rest/ledger/parser.rb +41 -37
- data/lib/ledger-rest/ledger/register.rb +31 -24
- data/lib/ledger-rest/ledger/transaction.rb +33 -28
- data/lib/ledger-rest/transactions.py +47 -0
- data/lib/ledger-rest/version.rb +2 -1
- data/spec/files/append.ledger +13 -0
- data/spec/files/budget.ledger +4 -0
- data/spec/files/main.ledger +4 -0
- data/spec/files/opening_balance.ledger +4 -0
- data/spec/files/transactions.ledger +11 -0
- data/spec/ledger-rest.yml +3 -0
- data/spec/ledger-rest/api/accounts_spec.rb +19 -0
- data/spec/ledger-rest/api/balance_spec.rb +117 -0
- data/spec/ledger-rest/api/budget_spec.rb +110 -0
- data/spec/ledger-rest/api/payees_spec.rb +19 -0
- data/spec/ledger-rest/api/register_spec.rb +233 -0
- data/spec/ledger-rest/api/transactions_spec.rb +201 -0
- data/spec/ledger-rest/api/version_spec.rb +13 -0
- data/spec/ledger-rest/ledger/balance_spec.rb +124 -0
- data/spec/ledger-rest/ledger/parser_spec.rb +184 -117
- data/spec/ledger-rest/ledger/transaction_spec.rb +38 -31
- data/spec/spec_helper.rb +22 -0
- data/spec/support/deep_eq_matcher.rb +149 -0
- metadata +52 -31
- data/ledger-rest.org +0 -22
@@ -1,23 +1,29 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
module LedgerRest
|
2
3
|
class Ledger
|
3
4
|
class Balance
|
4
|
-
|
5
5
|
FORMAT = [
|
6
6
|
'{',
|
7
|
-
'
|
8
|
-
'
|
9
|
-
'
|
7
|
+
'"total":%(quoted(display_total)),',
|
8
|
+
'"name":%(quoted(partial_account)),',
|
9
|
+
'"depth":%(depth), "fullname": %(quoted(account))',
|
10
10
|
'},%/',
|
11
|
-
'{
|
12
|
-
].join
|
11
|
+
'{"total":%(quoted(display_total))}'
|
12
|
+
].join
|
13
13
|
|
14
14
|
class << self
|
15
|
+
def get(query = nil, params = {})
|
16
|
+
data = JSON.parse(json(query, params), symbolize_names: true)
|
17
|
+
|
18
|
+
data[:accounts] = expand_accounts(data[:accounts])
|
19
|
+
unless query =~ /--flat/
|
20
|
+
data[:accounts] = wrap_accounts(data[:accounts])
|
21
|
+
end
|
15
22
|
|
16
|
-
|
17
|
-
JSON.parse(json(query, params), :symbolize_names => true)
|
23
|
+
data
|
18
24
|
end
|
19
25
|
|
20
|
-
def json
|
26
|
+
def json(query = nil, params = {})
|
21
27
|
params = { '--format' => FORMAT }.merge(params)
|
22
28
|
result = Ledger.exec("bal #{query}", params)
|
23
29
|
|
@@ -25,19 +31,46 @@ module LedgerRest
|
|
25
31
|
if result.end_with?(',')
|
26
32
|
result = result[0..-2]
|
27
33
|
else
|
28
|
-
match_total = result.match(
|
34
|
+
match_total = result.match(/,{"total":("[0-9\.A-Za-z ]+")}\z/)
|
29
35
|
if match_total
|
30
36
|
total = match_total[1]
|
31
|
-
result = result[0,match_total.offset(0)[0]]
|
37
|
+
result = result[0, match_total.offset(0)[0]]
|
32
38
|
end
|
33
39
|
end
|
34
40
|
|
35
|
-
json_str =
|
36
|
-
json_str << "
|
37
|
-
json_str << "
|
38
|
-
json_str <<
|
41
|
+
json_str = '{'
|
42
|
+
json_str << "\"accounts\":[#{result}]"
|
43
|
+
json_str << ",\"total\":#{total}" if total
|
44
|
+
json_str << '}'
|
45
|
+
end
|
46
|
+
|
47
|
+
def expand_accounts(accounts)
|
48
|
+
accounts.inject([]) do |acc, elem|
|
49
|
+
fullname = elem[:fullname].gsub(/:?#{elem[:name]}/, '')
|
50
|
+
acc + elem[:name].split(':').map do |name|
|
51
|
+
fullname << "#{':' unless fullname.empty?}#{name}"
|
52
|
+
parent = elem.dup
|
53
|
+
parent[:fullname], parent[:name], parent[:depth] =
|
54
|
+
fullname.dup, name.dup, fullname.count(':')+1
|
55
|
+
parent
|
56
|
+
end
|
57
|
+
end
|
39
58
|
end
|
40
59
|
|
60
|
+
def wrap_accounts(accounts)
|
61
|
+
stack = []
|
62
|
+
accounts.inject([]) do |acc, elem|
|
63
|
+
stack.pop while stack.last && stack.last[:depth] >= elem[:depth]
|
64
|
+
if stack.empty?
|
65
|
+
stack << elem
|
66
|
+
acc << elem
|
67
|
+
else
|
68
|
+
(stack.last[:accounts] ||= []) << elem
|
69
|
+
stack << elem
|
70
|
+
end
|
71
|
+
acc
|
72
|
+
end
|
73
|
+
end
|
41
74
|
end
|
42
75
|
end
|
43
76
|
end
|
@@ -1,33 +1,52 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
module LedgerRest
|
2
3
|
class Ledger
|
3
4
|
class Budget
|
4
5
|
FORMAT = [
|
5
|
-
'
|
6
|
-
'
|
7
|
-
'
|
8
|
-
'
|
9
|
-
'
|
10
|
-
'
|
11
|
-
'
|
12
|
-
'
|
13
|
-
|
6
|
+
'%(scrub(get_at(display_total, 0)))\n',
|
7
|
+
'%(-scrub(get_at(display_total, 1)))\n',
|
8
|
+
'%(scrub(get_at(display_total, 1) + get_at(display_total, 0)))\n',
|
9
|
+
'%(get_at(display_total, 1) ? (100% * scrub(get_at(display_total, 0))) / -scrub(get_at(display_total, 1)) : 0)\n',
|
10
|
+
'%(account)\n',
|
11
|
+
'---\n',
|
12
|
+
'%/---\n',
|
13
|
+
'%$1\n',
|
14
|
+
'%$2\n',
|
15
|
+
'%$3\n',
|
16
|
+
'%$4\n',
|
17
|
+
'%/'
|
18
|
+
].join
|
14
19
|
|
15
20
|
class << self
|
16
|
-
|
17
21
|
def get(query = nil, params = {})
|
18
|
-
JSON.parse(json(query, params), :
|
22
|
+
JSON.parse(json(query, params), symbolize_names: true)
|
19
23
|
end
|
20
24
|
|
21
25
|
def json(query = nil, params = {})
|
22
26
|
params = { '--format' => FORMAT }.merge(params)
|
23
27
|
result = Ledger.exec("budget #{query}", params)
|
24
|
-
|
25
|
-
|
26
|
-
|
28
|
+
budget = {}
|
29
|
+
accounts, total = result.split("---\n---\n")
|
30
|
+
budget['accounts'] = accounts.split("---\n").map do |str|
|
31
|
+
val = str.split("\n")
|
32
|
+
{
|
33
|
+
'total' => val[0].empty? ? '0' : val[0],
|
34
|
+
'budget' => val[1].empty? ? '0' : val[1],
|
35
|
+
'difference' => val[2].empty? ? '0' : val[2],
|
36
|
+
'percentage' => val[3].empty? ? '0' : val[3],
|
37
|
+
'account' => val[4].empty? ? '0' : val[4]
|
38
|
+
}
|
39
|
+
end
|
40
|
+
if total
|
41
|
+
val = total.split("\n")
|
42
|
+
budget['total'] = val[0].empty? ? '0' : val[0]
|
43
|
+
budget['budget'] = val[1].empty? ? '0' : val[1]
|
44
|
+
budget['difference'] = val[2].empty? ? '0' : val[2]
|
45
|
+
budget['percentage'] = val[3].empty? ? '0' : val[3]
|
46
|
+
end
|
47
|
+
budget.to_json
|
27
48
|
end
|
28
|
-
|
29
49
|
end
|
30
|
-
|
31
50
|
end
|
32
51
|
end
|
33
52
|
end
|
@@ -1,13 +1,11 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
module LedgerRest
|
2
3
|
class Ledger
|
3
|
-
|
4
4
|
# Ledger offers a simple command to create a new entry based on
|
5
5
|
# previous entries in your ledger files. This class abstracts
|
6
6
|
# mentioned functionality for easy integration into ledger-rest.
|
7
7
|
class Entry
|
8
|
-
|
9
8
|
class << self
|
10
|
-
|
11
9
|
# Return a new transaction object based on previous transactions.
|
12
10
|
def get(desc, options = {})
|
13
11
|
result = Ledger.exec("entry #{desc}", options)
|
@@ -20,7 +18,6 @@ module LedgerRest
|
|
20
18
|
transaction.append_to(Ledger.append_file)
|
21
19
|
transaction
|
22
20
|
end
|
23
|
-
|
24
21
|
end
|
25
22
|
end
|
26
23
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
module LedgerRest
|
3
3
|
class Ledger
|
4
|
-
|
5
4
|
# A very simple parser for single legder format transactions.
|
6
5
|
# There has to be a better way ... This does not implement the
|
7
6
|
# whole ledger format. Tragically ... someone told me it´s the
|
@@ -11,14 +10,11 @@ module LedgerRest
|
|
11
10
|
#
|
12
11
|
# This works for `ledger entry` with my transactions ...
|
13
12
|
class Parser
|
14
|
-
|
15
13
|
class << self
|
16
|
-
|
17
14
|
def parse(str)
|
18
15
|
parser = Parser.new
|
19
16
|
parser.parse(str)
|
20
17
|
end
|
21
|
-
|
22
18
|
end
|
23
19
|
|
24
20
|
def initialize
|
@@ -30,20 +26,20 @@ module LedgerRest
|
|
30
26
|
@str = str
|
31
27
|
@transaction[:postings] = []
|
32
28
|
|
33
|
-
@transaction[:date],str = parse_date(str)
|
29
|
+
@transaction[:date], str = parse_date(str)
|
34
30
|
|
35
31
|
effective_date, str = parse_effective_date(str)
|
36
32
|
@transaction[:effective_date] = effective_date if effective_date
|
37
33
|
|
38
|
-
@transaction[:cleared],str = parse_cleared(str)
|
39
|
-
@transaction[:pending],str = parse_pending(str)
|
34
|
+
@transaction[:cleared], str = parse_cleared(str)
|
35
|
+
@transaction[:pending], str = parse_pending(str)
|
40
36
|
|
41
37
|
code, str = parse_code(str)
|
42
38
|
@transaction[:code] = code if code
|
43
39
|
|
44
|
-
@transaction[:payee],str = parse_payee(str)
|
40
|
+
@transaction[:payee], str = parse_payee(str)
|
45
41
|
|
46
|
-
comments,str = parse_comments(str)
|
42
|
+
comments, str = parse_comments(str)
|
47
43
|
@transaction[:comments] = comments if comments
|
48
44
|
|
49
45
|
str.split("\n").each do |line|
|
@@ -58,60 +54,60 @@ module LedgerRest
|
|
58
54
|
end
|
59
55
|
|
60
56
|
def parse_date(str)
|
61
|
-
if match = str.match(
|
62
|
-
[
|
57
|
+
if match = str.match(%r{\A(\d{4}/\d{1,2}/\d{1,2})(.*)}m)
|
58
|
+
[match[1], match[2]]
|
63
59
|
else
|
64
|
-
|
60
|
+
fail 'Date was expected.'
|
65
61
|
end
|
66
62
|
end
|
67
63
|
|
68
64
|
def parse_effective_date(str)
|
69
|
-
if match = str.match(
|
70
|
-
[
|
65
|
+
if match = str.match(%r{\A=(\d{4}/\d{1,2}/\d{1,2})(.*)}m)
|
66
|
+
[match[1], match[2]]
|
71
67
|
else
|
72
|
-
[
|
68
|
+
[nil, str]
|
73
69
|
end
|
74
70
|
end
|
75
71
|
|
76
72
|
def parse_pending(str)
|
77
73
|
if match = str.match(/\A ! (.*)/m)
|
78
|
-
[
|
74
|
+
[true, match[1]]
|
79
75
|
else
|
80
|
-
[
|
76
|
+
[false, str]
|
81
77
|
end
|
82
78
|
end
|
83
79
|
|
84
80
|
def parse_cleared(str)
|
85
81
|
if match = str.match(/\A \* (.*)/m)
|
86
|
-
[
|
82
|
+
[true, match[1]]
|
87
83
|
else
|
88
|
-
[
|
84
|
+
[false, str]
|
89
85
|
end
|
90
86
|
end
|
91
87
|
|
92
88
|
def parse_code(str)
|
93
89
|
if match = str.match(/\A *?\(([^\(\)]+)\) (.*)/m)
|
94
|
-
[
|
90
|
+
[match[1], match[2]]
|
95
91
|
else
|
96
|
-
[
|
92
|
+
[nil, str]
|
97
93
|
end
|
98
94
|
end
|
99
95
|
|
100
96
|
def parse_payee(str)
|
101
97
|
if match = str.match(/\A *?([^ ][^\n]+)\n(.*)/m)
|
102
|
-
[
|
98
|
+
[match[1], match[2]]
|
103
99
|
else
|
104
|
-
|
100
|
+
fail 'No payee given.'
|
105
101
|
end
|
106
102
|
end
|
107
103
|
|
108
104
|
def parse_comments(str)
|
109
|
-
comments =
|
105
|
+
comments = ''
|
110
106
|
while str && match = str.match(/\A +;(.*?)(\n|$)(.*)/m)
|
111
107
|
comments << match[1].strip << "\n"
|
112
108
|
str = match[3]
|
113
109
|
end
|
114
|
-
[
|
110
|
+
[comments.empty? ? nil : comments, str]
|
115
111
|
end
|
116
112
|
|
117
113
|
# parses a ledger posting line
|
@@ -124,9 +120,9 @@ module LedgerRest
|
|
124
120
|
posting[:balanced] = balanced if balanced
|
125
121
|
|
126
122
|
amount, posting_cost, per_unit_cost, str = parse_amount(str)
|
127
|
-
posting[:amount] = amount if amount
|
128
|
-
posting[:posting_cost] = posting_cost if posting_cost
|
129
|
-
posting[:per_unit_cost] = per_unit_cost if per_unit_cost
|
123
|
+
posting[:amount], posting[:commodity] = parse_amount_parts(amount) if amount
|
124
|
+
posting[:posting_cost], posting[:posting_cost_commodity] = parse_amount_parts(posting_cost) if posting_cost
|
125
|
+
posting[:per_unit_cost], posting[:per_unit_commodity] = parse_amount_parts(per_unit_cost) if per_unit_cost
|
130
126
|
|
131
127
|
comment, actual_date, effective_date = parse_posting_comment(str)
|
132
128
|
posting[:comment] = comment if comment
|
@@ -137,28 +133,36 @@ module LedgerRest
|
|
137
133
|
end
|
138
134
|
|
139
135
|
def parse_account(str)
|
140
|
-
return [] if str.nil?
|
136
|
+
return [] if str.nil? || str.empty?
|
141
137
|
if match = str.match(/\A +([\w:]+)(\n|$| )(.*)/m)
|
142
|
-
[
|
138
|
+
[match[1], false, false , match[3]]
|
143
139
|
elsif match = str.match(/\A +\(([\w:]+)\)(\n|$| )(.*)/m)
|
144
|
-
[
|
140
|
+
[match[1], true, false , match[3]]
|
145
141
|
elsif match = str.match(/\A +\[([\w:]+)\](\n|$| )(.*)/m)
|
146
|
-
[
|
142
|
+
[match[1], true, true , match[3]]
|
147
143
|
else
|
148
|
-
[
|
144
|
+
[nil, false, false, str]
|
149
145
|
end
|
150
146
|
end
|
151
147
|
|
152
148
|
def parse_amount(str)
|
153
149
|
if match = str.match(/\A(.*?)@@([^;]*?)(;(.*)|\n(.*)|$(.*))/m)
|
154
150
|
amount = match[1].strip
|
155
|
-
[
|
151
|
+
[amount.empty? ? nil : amount, nil, match[2].strip, match[3]]
|
156
152
|
elsif match = str.match(/\A(.*?)@([^;]*)(;(.*)|\n(.*)|$(.*))/m)
|
157
153
|
amount = match[1].strip
|
158
|
-
[
|
154
|
+
[amount.empty? ? nil : amount, match[2].strip, nil, match[3]]
|
159
155
|
elsif match = str.match(/\A([^;]*?)(;(.*)|\n(.*)|$(.*))/m)
|
160
156
|
amount = match[1].strip
|
161
|
-
[
|
157
|
+
[amount.empty? ? nil : amount, nil, nil, match[2]]
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def parse_amount_parts(str)
|
162
|
+
if match = str.match(/^(.*?)(\d+(\.\d+)?)(.*?)$/)
|
163
|
+
[match[2].to_f, match[1].strip + match[4].strip]
|
164
|
+
else
|
165
|
+
[str, nil]
|
162
166
|
end
|
163
167
|
end
|
164
168
|
|
@@ -171,7 +175,7 @@ module LedgerRest
|
|
171
175
|
comment = match[1]
|
172
176
|
end
|
173
177
|
|
174
|
-
[
|
178
|
+
[comment, actual_date, effective_date]
|
175
179
|
end
|
176
180
|
end
|
177
181
|
end
|
@@ -1,38 +1,45 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
module LedgerRest
|
2
3
|
class Ledger
|
3
4
|
class Register
|
4
|
-
|
5
|
-
FORMAT = [
|
6
|
-
"{",
|
7
|
-
' "date": %(quoted(date)),',
|
8
|
-
' "effective_date": %(effective_date ? quoted(effective_date) : "null"),',
|
9
|
-
' "code": %(code ? quoted(code) : "null"),',
|
10
|
-
' "cleared": %(cleared ? "true" : "false"),',
|
11
|
-
' "pending": %(pending ? "true" : "false"),',
|
12
|
-
' "payee": %(quoted(payee)),',
|
13
|
-
' "postings":',
|
14
|
-
' [',
|
15
|
-
' { "account": %(quoted(display_account)), "amount": %(quoted(amount)) },%/',
|
16
|
-
' { "account": %(quoted(display_account)), "amount": %(quoted(amount)) },%/',
|
17
|
-
' ]',
|
18
|
-
'},'
|
19
|
-
].join('\\n')
|
20
|
-
|
21
5
|
class << self
|
6
|
+
def format(query)
|
7
|
+
format = '{'
|
8
|
+
if query =~ /-D|--daily|-W|--weekly|-M|--monthly|--quarterly|-Y|--yearly/
|
9
|
+
format << '"beginning": %(quoted(format_date(date))),'
|
10
|
+
format << '"end": %(quoted(payee)),'
|
11
|
+
elsif query =~ /--by-payee/
|
12
|
+
format << '"payee": %(quoted(payee)),'
|
13
|
+
else
|
14
|
+
format << '"date": %(quoted(format_date(date))),'
|
15
|
+
format << '"effective_date": %(effective_date ? quoted(format_date(effective_date)) : "null"),'
|
16
|
+
format << '"code": %(code ? quoted(code) : "null"),'
|
17
|
+
format << '"cleared": %(cleared ? "true" : "false"),'
|
18
|
+
format << '"pending": %(pending ? "true" : "false"),'
|
19
|
+
format << '"payee": %(quoted(payee)),'
|
20
|
+
end
|
21
|
+
format << '"postings": ['
|
22
|
+
format << '{ "account": %(quoted(display_account)), "amount": %(quoted(quantity(scrub(display_amount)))), "total": %(quoted(quantity(scrub(display_amount)))), "commodity": %(quoted(commodity)) },%/'
|
23
|
+
format << '{ "account": %(quoted(display_account)), "amount": %(quoted(quantity(scrub(display_amount)))), "total": %(quoted(quantity(scrub(display_amount)))), "commodity": %(quoted(commodity)) },%/'
|
24
|
+
format << ']},'
|
25
|
+
format
|
26
|
+
end
|
22
27
|
|
23
28
|
def get(query = nil, params = {})
|
24
|
-
JSON.parse(json(query, params), :
|
29
|
+
JSON.parse(json(query, params), symbolize_names: true)
|
25
30
|
end
|
26
31
|
|
27
32
|
def json(query = nil, params = {})
|
28
|
-
params = {
|
33
|
+
params = {
|
34
|
+
'--format' => format(query),
|
35
|
+
'--date-format' => '%Y/%m/%d'
|
36
|
+
}.merge(params)
|
29
37
|
result = Ledger.exec("reg #{query}", params)
|
30
|
-
result << "
|
31
|
-
result.gsub!
|
32
|
-
|
33
|
-
"
|
38
|
+
result << "]}"
|
39
|
+
result.gsub! '"end": "- ', '"end": "'
|
40
|
+
result.gsub! /\},\n? *?\]/m, "}]"
|
41
|
+
"[#{result}]"
|
34
42
|
end
|
35
|
-
|
36
43
|
end
|
37
44
|
end
|
38
45
|
end
|
@@ -2,14 +2,11 @@
|
|
2
2
|
module LedgerRest
|
3
3
|
class Ledger
|
4
4
|
class Transaction < Hash
|
5
|
-
|
6
5
|
class << self
|
7
|
-
|
8
6
|
# Parse a ledger transaction string into a `Transaction` object.
|
9
7
|
def parse(str)
|
10
8
|
LedgerRest::Ledger::Parser.parse(str)
|
11
9
|
end
|
12
|
-
|
13
10
|
end
|
14
11
|
|
15
12
|
def initialize(params = {})
|
@@ -18,31 +15,39 @@ module LedgerRest
|
|
18
15
|
|
19
16
|
# Return true if the `Transaction#to_ledger` is a valid ledger string.
|
20
17
|
def valid?
|
21
|
-
result = IO.popen("#{
|
22
|
-
f.write
|
18
|
+
result = IO.popen("#{Ledger.bin} -f - stats 2>&1", 'r+') do |f|
|
19
|
+
f.write to_ledger
|
23
20
|
f.close_write
|
24
21
|
f.readlines
|
25
22
|
end
|
26
23
|
|
27
|
-
$?.success?
|
24
|
+
$?.success? && !result.empty?
|
25
|
+
end
|
26
|
+
|
27
|
+
def check
|
28
|
+
IO.popen("#{Ledger.bin} -f - stats 2>&1", 'r+') do |f|
|
29
|
+
f.write to_ledger
|
30
|
+
f.close_write
|
31
|
+
f.readlines
|
32
|
+
end
|
28
33
|
end
|
29
34
|
|
30
35
|
def to_ledger
|
31
|
-
if self[:date].nil?
|
32
|
-
self[:payee].nil? or
|
33
|
-
self[:postings].nil?
|
36
|
+
if self[:date].nil? || self[:payee].nil? || self[:postings].nil?
|
34
37
|
return nil
|
35
38
|
end
|
36
39
|
|
37
|
-
result =
|
40
|
+
result = ''
|
38
41
|
|
39
42
|
result << self[:date]
|
40
|
-
|
43
|
+
if self[:effective_date]
|
44
|
+
result << "=#{self[:effective_date]}"
|
45
|
+
end
|
41
46
|
|
42
47
|
if self[:cleared]
|
43
|
-
result <<
|
48
|
+
result << ' *'
|
44
49
|
elsif self[:pending]
|
45
|
-
result <<
|
50
|
+
result << ' !'
|
46
51
|
end
|
47
52
|
|
48
53
|
result << " (#{self[:code]})" if self[:code]
|
@@ -51,7 +56,7 @@ module LedgerRest
|
|
51
56
|
|
52
57
|
self[:postings].each do |posting|
|
53
58
|
if posting[:comment]
|
54
|
-
result << "
|
59
|
+
result << " ; #{posting[:comment]}\n"
|
55
60
|
next
|
56
61
|
end
|
57
62
|
|
@@ -59,12 +64,12 @@ module LedgerRest
|
|
59
64
|
|
60
65
|
if posting[:virtual]
|
61
66
|
if posting[:balance]
|
62
|
-
result << "
|
67
|
+
result << " [#{posting[:account]}]"
|
63
68
|
else
|
64
|
-
result << "
|
69
|
+
result << " (#{posting[:account]})"
|
65
70
|
end
|
66
71
|
else
|
67
|
-
result << "
|
72
|
+
result << " #{posting[:account]}"
|
68
73
|
end
|
69
74
|
|
70
75
|
if posting[:amount].nil?
|
@@ -72,26 +77,26 @@ module LedgerRest
|
|
72
77
|
next
|
73
78
|
end
|
74
79
|
|
75
|
-
result << " #{posting[:amount]}"
|
80
|
+
result << " #{'%.2f' % posting[:amount]}#{posting[:commodity]}"
|
76
81
|
|
77
|
-
if
|
78
|
-
result << " @@ #{posting[:per_unit_cost]}"
|
79
|
-
elsif
|
80
|
-
result << " @ #{posting[:posting_cost]}"
|
82
|
+
if posting[:per_unit_cost]
|
83
|
+
result << " @@ #{'%.2f' % posting[:per_unit_cost]}#{posting[:per_unit_commodity]}"
|
84
|
+
elsif posting[:posting_cost]
|
85
|
+
result << " @ #{'%.2f' % posting[:posting_cost]}#{posting[:posting_cost_commodity]}"
|
81
86
|
end
|
82
87
|
|
83
|
-
if posting[:actual_date]
|
84
|
-
result <<
|
88
|
+
if posting[:actual_date] || posting[:effective_date]
|
89
|
+
result << ' ; ['
|
85
90
|
result << posting[:actual_date] if posting[:actual_date]
|
86
|
-
|
87
|
-
|
91
|
+
if posting[:effective_date]
|
92
|
+
result << "=#{posting[:effective_date]}"
|
93
|
+
end
|
94
|
+
result << ']'
|
88
95
|
end
|
89
96
|
|
90
97
|
result << "\n"
|
91
98
|
end
|
92
99
|
|
93
|
-
result << "\n"
|
94
|
-
|
95
100
|
result
|
96
101
|
end
|
97
102
|
end
|