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
@@ -0,0 +1,47 @@
|
|
1
|
+
import ledger
|
2
|
+
import json
|
3
|
+
import sys
|
4
|
+
|
5
|
+
filename = sys.argv[1]
|
6
|
+
query = sys.argv[2]
|
7
|
+
|
8
|
+
transactions = []
|
9
|
+
last_xact = None
|
10
|
+
for match in ledger.read_journal(filename).query(query):
|
11
|
+
if match.xact != last_xact:
|
12
|
+
transaction = {}
|
13
|
+
transaction['payee'] = match.xact.payee
|
14
|
+
transaction['date'] = match.xact.date.strftime('%Y/%m/%d')
|
15
|
+
|
16
|
+
if match.xact.code != None:
|
17
|
+
transaction['code'] = match.xact.code
|
18
|
+
|
19
|
+
if match.xact.note != None:
|
20
|
+
transaction['note'] = match.xact.note.strip()
|
21
|
+
|
22
|
+
if match.xact.aux_date != None:
|
23
|
+
transaction['effective_date'] = match.xact.aux_date.strftime('%Y/%m/%d')
|
24
|
+
|
25
|
+
if str(match.xact.state) == 'Cleared':
|
26
|
+
transaction['cleared'] = True
|
27
|
+
transaction['pending'] = False
|
28
|
+
elif str(match.xact.state) == 'Pending':
|
29
|
+
transaction['cleared'] = False
|
30
|
+
transaction['pending'] = True
|
31
|
+
else:
|
32
|
+
transaction['cleared'] = False
|
33
|
+
transaction['pending'] = False
|
34
|
+
|
35
|
+
transaction['posts'] = []
|
36
|
+
for post in match.xact.posts():
|
37
|
+
new_post = {}
|
38
|
+
new_post['account'] = str(post.account)
|
39
|
+
new_post['amount'] = float(post.amount)
|
40
|
+
new_post['commodity'] = str(post.amount.commodity)
|
41
|
+
transaction['posts'].append(new_post)
|
42
|
+
|
43
|
+
transactions.append(transaction)
|
44
|
+
|
45
|
+
last_xact = match.xact
|
46
|
+
|
47
|
+
print json.dumps(transactions)
|
data/lib/ledger-rest/version.rb
CHANGED
@@ -0,0 +1,13 @@
|
|
1
|
+
2013/12/03 NaveenaPath
|
2
|
+
Expenses:Restaurants 9.00EUR
|
3
|
+
Assets:Cash
|
4
|
+
|
5
|
+
2013/12/05 Shikgoo
|
6
|
+
Expenses:Restaurants 12.00EUR
|
7
|
+
Liabilities:Max Mustermann
|
8
|
+
; meta_info: Some interesting meta information
|
9
|
+
|
10
|
+
2013/12/10 Bioladen Tegeler Straße
|
11
|
+
; Sonnenblumenkernbrot
|
12
|
+
Assets:Reimbursements:Hans Maulwurf 3.10EUR
|
13
|
+
Assets:Cash
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe '/accounts' do
|
5
|
+
it 'returns accounts' do
|
6
|
+
get '/accounts'
|
7
|
+
|
8
|
+
JSON.parse(last_response.body).should =~
|
9
|
+
[
|
10
|
+
'Assets:Cash',
|
11
|
+
'Assets:Giro',
|
12
|
+
'Assets:Reimbursements:Hans Maulwurf',
|
13
|
+
'Equity:Opening Balances',
|
14
|
+
'Expenses:Restaurants',
|
15
|
+
'Income:Invoice',
|
16
|
+
'Liabilities:Max Mustermann'
|
17
|
+
]
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe '/balance' do
|
5
|
+
context 'normally' do
|
6
|
+
let(:valid_json) do
|
7
|
+
{
|
8
|
+
'accounts' =>
|
9
|
+
[
|
10
|
+
{
|
11
|
+
'total' => '3177.80EUR',
|
12
|
+
'name' => 'Assets',
|
13
|
+
'depth' => 1,
|
14
|
+
'fullname' => 'Assets',
|
15
|
+
'accounts' =>
|
16
|
+
[
|
17
|
+
{
|
18
|
+
'total' => '5.70EUR',
|
19
|
+
'name' => 'Cash',
|
20
|
+
'depth' => 2,
|
21
|
+
'fullname' => 'Assets:Cash'
|
22
|
+
},
|
23
|
+
{
|
24
|
+
'total' => '3150.00EUR',
|
25
|
+
'name' => 'Giro',
|
26
|
+
'depth' => 2,
|
27
|
+
'fullname' => 'Assets:Giro'
|
28
|
+
},
|
29
|
+
{
|
30
|
+
'total' => '22.10EUR',
|
31
|
+
'name' => 'Reimbursements',
|
32
|
+
'depth' => 2,
|
33
|
+
'fullname' => 'Assets:Reimbursements',
|
34
|
+
'accounts' =>
|
35
|
+
[
|
36
|
+
{
|
37
|
+
'total' => '22.10EUR',
|
38
|
+
'name' => 'Hans Maulwurf',
|
39
|
+
'depth' => 3,
|
40
|
+
'fullname' => 'Assets:Reimbursements:Hans Maulwurf'
|
41
|
+
}
|
42
|
+
]
|
43
|
+
}
|
44
|
+
]
|
45
|
+
},
|
46
|
+
{
|
47
|
+
'total' => '-12.00EUR',
|
48
|
+
'name' => 'Liabilities',
|
49
|
+
'depth' => 1,
|
50
|
+
'fullname' => 'Liabilities',
|
51
|
+
'accounts' =>
|
52
|
+
[
|
53
|
+
{
|
54
|
+
'total' => '-12.00EUR',
|
55
|
+
'name' => 'Max Mustermann',
|
56
|
+
'depth' => 2,
|
57
|
+
'fullname' => 'Liabilities:Max Mustermann'
|
58
|
+
}
|
59
|
+
]
|
60
|
+
}
|
61
|
+
],
|
62
|
+
'total' => '3165.80EUR'
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'expands and wraps accounts' do
|
67
|
+
get '/balance', query: 'Assets Liabilities'
|
68
|
+
JSON.parse(last_response.body).should deep_eq valid_json
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'with --flat query' do
|
73
|
+
let(:valid_json) do
|
74
|
+
{
|
75
|
+
'accounts' =>
|
76
|
+
[
|
77
|
+
{
|
78
|
+
'total' => '5.70EUR',
|
79
|
+
'name' => 'Cash',
|
80
|
+
'depth' => 2,
|
81
|
+
'fullname' => 'Assets:Cash'
|
82
|
+
}, {
|
83
|
+
'total' => '3150.00EUR',
|
84
|
+
'name' => 'Giro',
|
85
|
+
'depth' => 2,
|
86
|
+
'fullname' => 'Assets:Giro'
|
87
|
+
}, {
|
88
|
+
'total' => '22.10EUR',
|
89
|
+
'name' => 'Reimbursements',
|
90
|
+
'depth' => 2,
|
91
|
+
'fullname' => 'Assets:Reimbursements'
|
92
|
+
}, {
|
93
|
+
'total' => '22.10EUR',
|
94
|
+
'name' => 'Hans Maulwurf',
|
95
|
+
'depth' => 3,
|
96
|
+
'fullname' => 'Assets:Reimbursements:Hans Maulwurf'
|
97
|
+
}, {
|
98
|
+
'total' => '-12.00EUR',
|
99
|
+
'name' => 'Liabilities',
|
100
|
+
'depth' => 1,
|
101
|
+
'fullname' => 'Liabilities'
|
102
|
+
}, {
|
103
|
+
'total' => '-12.00EUR',
|
104
|
+
'name' => 'Max Mustermann',
|
105
|
+
'depth' => 2,
|
106
|
+
'fullname' => 'Liabilities:Max Mustermann' }
|
107
|
+
],
|
108
|
+
'total' => '3165.80EUR'
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'does not wrap accounts' do
|
113
|
+
get '/balance', query: '--flat Assets Liabilities'
|
114
|
+
JSON.parse(last_response.body).should deep_eq valid_json
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe '/budget' do
|
4
|
+
context 'with query' do
|
5
|
+
let(:valid_json) do
|
6
|
+
{
|
7
|
+
'accounts' =>
|
8
|
+
[
|
9
|
+
{
|
10
|
+
'total' => '3177.80EUR',
|
11
|
+
'budget' => '-6600.00EUR',
|
12
|
+
'difference' => '9777.80EUR',
|
13
|
+
'percentage' => '-48%',
|
14
|
+
'account' => 'Assets'
|
15
|
+
}, {
|
16
|
+
'total' => '53.20EUR',
|
17
|
+
'budget' => '6600.00EUR',
|
18
|
+
'difference' => '-6546.80EUR',
|
19
|
+
'percentage' => '1%',
|
20
|
+
'account' => 'Expenses'
|
21
|
+
}, {
|
22
|
+
'total' => '0',
|
23
|
+
'budget' => '5400.00EUR',
|
24
|
+
'difference' => '-5400.00EUR',
|
25
|
+
'percentage' => '0%',
|
26
|
+
'account' => 'Expenses:Flat'
|
27
|
+
}, {
|
28
|
+
'total' => '53.20EUR',
|
29
|
+
'budget' => '1200.00EUR',
|
30
|
+
'difference' => '-1146.80EUR',
|
31
|
+
'percentage' => '4%',
|
32
|
+
'account' => 'Expenses:Restaurants'
|
33
|
+
}
|
34
|
+
],
|
35
|
+
'total' => '3231.00EUR',
|
36
|
+
'budget' => '0',
|
37
|
+
'difference' => '3231.00EUR',
|
38
|
+
'percentage' => '0'
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'responds with the right budget' do
|
43
|
+
get '/budget'
|
44
|
+
|
45
|
+
JSON.parse(last_response.body).should deep_eq valid_json
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'querying single account' do
|
50
|
+
let(:valid_json) do
|
51
|
+
{
|
52
|
+
'accounts' =>
|
53
|
+
[
|
54
|
+
{
|
55
|
+
'total' => '53.20EUR',
|
56
|
+
'budget' => '100.00EUR',
|
57
|
+
'difference' => '-46.80EUR',
|
58
|
+
'percentage' => '53%',
|
59
|
+
'account' => 'Expenses:Restaurants'
|
60
|
+
}
|
61
|
+
]
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'responds with the right budget' do
|
66
|
+
get '/budget', query: 'Restaurants'
|
67
|
+
|
68
|
+
JSON.parse(last_response.body).should deep_eq valid_json
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'querying single account' do
|
73
|
+
let(:valid_json) do
|
74
|
+
{
|
75
|
+
'accounts' =>
|
76
|
+
[
|
77
|
+
{
|
78
|
+
'total' => '53.20EUR',
|
79
|
+
'budget' => '550.00EUR',
|
80
|
+
'difference' => '-496.80EUR',
|
81
|
+
'percentage' => '10%',
|
82
|
+
'account' => 'Expenses'
|
83
|
+
}, {
|
84
|
+
'total' => '0',
|
85
|
+
'budget' => '450.00EUR',
|
86
|
+
'difference' => '-450.00EUR',
|
87
|
+
'percentage' => '0%',
|
88
|
+
'account' => 'Expenses:Flat'
|
89
|
+
}, {
|
90
|
+
'total' => '53.20EUR',
|
91
|
+
'budget' => '100.00EUR',
|
92
|
+
'difference' => '-46.80EUR',
|
93
|
+
'percentage' => '53%',
|
94
|
+
'account' => 'Expenses:Restaurants'
|
95
|
+
}
|
96
|
+
],
|
97
|
+
'total' => '53.20EUR',
|
98
|
+
'budget' => '550.00EUR',
|
99
|
+
'difference' => '-496.80EUR',
|
100
|
+
'percentage' => '10%',
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'responds with the right budget' do
|
105
|
+
get '/budget', query: 'Expenses'
|
106
|
+
|
107
|
+
JSON.parse(last_response.body).should deep_eq valid_json
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe '/payees' do
|
5
|
+
it 'returns payees' do
|
6
|
+
get '/payees'
|
7
|
+
|
8
|
+
JSON.parse(last_response.body).should =~
|
9
|
+
[
|
10
|
+
'Bioladen Tegeler Straße',
|
11
|
+
'Customer X',
|
12
|
+
'NaveenaPath',
|
13
|
+
'Opening Balance',
|
14
|
+
'Shikgoo',
|
15
|
+
'Sparkasse',
|
16
|
+
'Trattoria La Vialla'
|
17
|
+
]
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe '/register' do
|
5
|
+
context 'normal' do
|
6
|
+
let(:valid_response) do
|
7
|
+
[
|
8
|
+
{
|
9
|
+
'date' => '2013/12/01',
|
10
|
+
'effective_date' => '2013/12/02',
|
11
|
+
'code' => nil,
|
12
|
+
'cleared' => true,
|
13
|
+
'pending' => false,
|
14
|
+
'payee' => 'Sparkasse',
|
15
|
+
'postings' =>
|
16
|
+
[
|
17
|
+
{ 'account' => 'Assets:Cash',
|
18
|
+
'amount' => '50',
|
19
|
+
'total' => '50',
|
20
|
+
'commodity' => 'EUR'
|
21
|
+
},
|
22
|
+
{
|
23
|
+
'account' => 'Assets:Giro',
|
24
|
+
'amount' => '-50',
|
25
|
+
'total' => '-50',
|
26
|
+
'commodity' => 'EUR'
|
27
|
+
}
|
28
|
+
]
|
29
|
+
}
|
30
|
+
]
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'shows all fields' do
|
34
|
+
get '/register', query: '-p "2013-12-01"'
|
35
|
+
JSON.parse(last_response.body).should deep_eq valid_response
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'daily report' do
|
40
|
+
let(:valid_response) do
|
41
|
+
[
|
42
|
+
{
|
43
|
+
'beginning' => '2013/12/03',
|
44
|
+
'end' => '2013/12/03',
|
45
|
+
'postings' =>
|
46
|
+
[
|
47
|
+
{
|
48
|
+
'account' => 'Expenses:Restaurants',
|
49
|
+
'amount' => '9',
|
50
|
+
'total' => '9',
|
51
|
+
'commodity' => 'EUR'
|
52
|
+
}
|
53
|
+
]
|
54
|
+
}, {
|
55
|
+
'beginning' => '2013/12/04',
|
56
|
+
'end' => '2013/12/04',
|
57
|
+
'postings' =>
|
58
|
+
[
|
59
|
+
{
|
60
|
+
'account' => 'Expenses:Restaurants',
|
61
|
+
'amount' => '32.2',
|
62
|
+
'total' => '32.2',
|
63
|
+
'commodity' => 'EUR'
|
64
|
+
}
|
65
|
+
]
|
66
|
+
}, {
|
67
|
+
'beginning' => '2013/12/05',
|
68
|
+
'end' => '2013/12/05',
|
69
|
+
'postings' =>
|
70
|
+
[
|
71
|
+
{
|
72
|
+
'account' => 'Expenses:Restaurants',
|
73
|
+
'amount' => '12',
|
74
|
+
'total' => '12',
|
75
|
+
'commodity' => 'EUR'
|
76
|
+
}
|
77
|
+
]
|
78
|
+
}
|
79
|
+
]
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'shows beginning, end and postings with account, amount and total' do
|
83
|
+
get '/register', query: '--daily ^Expenses'
|
84
|
+
JSON.parse(last_response.body).should deep_eq valid_response
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'weekly report' do
|
89
|
+
let(:valid_response) do
|
90
|
+
[
|
91
|
+
{
|
92
|
+
'beginning' => '2013/12/01',
|
93
|
+
'end' => '2013/12/07',
|
94
|
+
'postings' =>
|
95
|
+
[
|
96
|
+
{
|
97
|
+
'account' => 'Expenses:Restaurants',
|
98
|
+
'amount' => '53.2',
|
99
|
+
'total' => '53.2',
|
100
|
+
'commodity' => 'EUR'
|
101
|
+
}
|
102
|
+
]
|
103
|
+
}
|
104
|
+
]
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'shows beginning, end and postings with account, amount and total' do
|
108
|
+
get '/register', query: '-W ^Expenses'
|
109
|
+
JSON.parse(last_response.body).should deep_eq valid_response
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'monthly report' do
|
114
|
+
let(:valid_response) do
|
115
|
+
[
|
116
|
+
{
|
117
|
+
'beginning' => '2013/12/01',
|
118
|
+
'end' => '2013/12/31',
|
119
|
+
'postings' =>
|
120
|
+
[
|
121
|
+
{
|
122
|
+
'account' => 'Expenses:Restaurants',
|
123
|
+
'amount' => '53.2',
|
124
|
+
'total' => '53.2',
|
125
|
+
'commodity' => 'EUR'
|
126
|
+
}
|
127
|
+
]
|
128
|
+
}
|
129
|
+
]
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'shows beginning, end and postings with account, amount and total' do
|
133
|
+
get '/register', query: '-M ^Expenses'
|
134
|
+
JSON.parse(last_response.body).should deep_eq valid_response
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'quarterly report' do
|
139
|
+
let(:valid_response) do
|
140
|
+
[
|
141
|
+
{
|
142
|
+
'beginning' => '2013/10/01',
|
143
|
+
'end' => '2013/12/31',
|
144
|
+
'postings' =>
|
145
|
+
[
|
146
|
+
{
|
147
|
+
'account' => 'Expenses:Restaurants',
|
148
|
+
'amount' => '53.2',
|
149
|
+
'total' => '53.2',
|
150
|
+
'commodity' => 'EUR'
|
151
|
+
}
|
152
|
+
]
|
153
|
+
}
|
154
|
+
]
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'shows beginning, end and postings with account, amount and total' do
|
158
|
+
get '/register', query: '--quarterly ^Expenses'
|
159
|
+
JSON.parse(last_response.body).should deep_eq valid_response
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'yearly report' do
|
164
|
+
let(:valid_response) do
|
165
|
+
[
|
166
|
+
{
|
167
|
+
'beginning' => '2013/01/01',
|
168
|
+
'end' => '2013/12/31',
|
169
|
+
'postings' =>
|
170
|
+
[
|
171
|
+
{
|
172
|
+
'account' => 'Expenses:Restaurants',
|
173
|
+
'amount' => '53.2',
|
174
|
+
'total' => '53.2',
|
175
|
+
'commodity' => 'EUR'
|
176
|
+
}
|
177
|
+
]
|
178
|
+
}
|
179
|
+
]
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'shows beginning, end and postings with account, amount and total' do
|
183
|
+
get '/register', query: '-Y ^Expenses'
|
184
|
+
JSON.parse(last_response.body).should deep_eq valid_response
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
context 'report by payee' do
|
189
|
+
let(:valid_response) do
|
190
|
+
[
|
191
|
+
{
|
192
|
+
'payee' => 'NaveenaPath',
|
193
|
+
'postings' =>
|
194
|
+
[
|
195
|
+
{
|
196
|
+
'account' => 'Expenses:Restaurants',
|
197
|
+
'amount' => '9',
|
198
|
+
'total' => '9',
|
199
|
+
'commodity' => 'EUR'
|
200
|
+
}
|
201
|
+
]
|
202
|
+
}, {
|
203
|
+
'payee' => 'Shikgoo',
|
204
|
+
'postings' =>
|
205
|
+
[
|
206
|
+
{
|
207
|
+
'account' => 'Expenses:Restaurants',
|
208
|
+
'amount' => '12',
|
209
|
+
'total' => '12',
|
210
|
+
'commodity' => 'EUR'
|
211
|
+
}
|
212
|
+
]
|
213
|
+
}, {
|
214
|
+
'payee' => 'Trattoria La Vialla',
|
215
|
+
'postings' =>
|
216
|
+
[
|
217
|
+
{
|
218
|
+
'account' => 'Expenses:Restaurants',
|
219
|
+
'amount' => '32.2',
|
220
|
+
'total' => '32.2',
|
221
|
+
'commodity' => 'EUR'
|
222
|
+
}
|
223
|
+
]
|
224
|
+
}
|
225
|
+
]
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'shows beginning, end and postings with account, amount and total' do
|
229
|
+
get '/register', query: '--by-payee ^Expenses'
|
230
|
+
JSON.parse(last_response.body).should deep_eq valid_response
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|