reckon 0.5.1 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +50 -0
- data/.gitignore +2 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +74 -0
- data/Gemfile.lock +1 -5
- data/README.md +72 -16
- data/Rakefile +17 -1
- data/lib/reckon.rb +2 -5
- data/lib/reckon/app.rb +145 -71
- data/lib/reckon/cosine_similarity.rb +92 -89
- data/lib/reckon/csv_parser.rb +67 -122
- data/lib/reckon/date_column.rb +10 -0
- data/lib/reckon/ledger_parser.rb +11 -1
- data/lib/reckon/logger.rb +4 -0
- data/lib/reckon/money.rb +52 -51
- data/lib/reckon/version.rb +1 -1
- data/reckon.gemspec +1 -2
- data/spec/data_fixtures/51-sample.csv +8 -0
- data/spec/data_fixtures/51-tokens.yml +9 -0
- data/spec/data_fixtures/85-date-example.csv +2 -0
- data/spec/integration/another_bank_example/input.csv +9 -0
- data/spec/integration/another_bank_example/output.ledger +36 -0
- data/spec/integration/another_bank_example/test_args +1 -0
- data/spec/integration/austrian_example/input.csv +13 -0
- data/spec/integration/austrian_example/output.ledger +52 -0
- data/spec/integration/austrian_example/test_args +2 -0
- data/spec/integration/bom_utf8_file/input.csv +3 -0
- data/spec/integration/bom_utf8_file/output.ledger +4 -0
- data/spec/integration/bom_utf8_file/test_args +3 -0
- data/spec/integration/broker_canada_example/input.csv +12 -0
- data/spec/integration/broker_canada_example/output.ledger +48 -0
- data/spec/integration/broker_canada_example/test_args +1 -0
- data/spec/integration/chase/account_tokens_and_regex/output.ledger +36 -0
- data/spec/integration/chase/account_tokens_and_regex/test_args +2 -0
- data/spec/integration/chase/account_tokens_and_regex/tokens.yml +16 -0
- data/spec/integration/chase/default_account_names/output.ledger +36 -0
- data/spec/integration/chase/default_account_names/test_args +3 -0
- data/spec/integration/chase/input.csv +9 -0
- data/spec/integration/chase/learn_from_existing/learn.ledger +7 -0
- data/spec/integration/chase/learn_from_existing/output.ledger +36 -0
- data/spec/integration/chase/learn_from_existing/test_args +1 -0
- data/spec/integration/chase/simple/output.ledger +36 -0
- data/spec/integration/chase/simple/test_args +1 -0
- data/spec/integration/danish_kroner_nordea_example/input.csv +6 -0
- data/spec/integration/danish_kroner_nordea_example/output.ledger +24 -0
- data/spec/integration/danish_kroner_nordea_example/test_args +1 -0
- data/spec/integration/english_date_example/input.csv +3 -0
- data/spec/integration/english_date_example/output.ledger +12 -0
- data/spec/integration/english_date_example/test_args +1 -0
- data/spec/integration/extratofake/input.csv +24 -0
- data/spec/integration/extratofake/output.ledger +92 -0
- data/spec/integration/extratofake/test_args +1 -0
- data/spec/integration/french_example/input.csv +9 -0
- data/spec/integration/french_example/output.ledger +36 -0
- data/spec/integration/french_example/test_args +2 -0
- data/spec/integration/german_date_example/input.csv +3 -0
- data/spec/integration/german_date_example/output.ledger +12 -0
- data/spec/integration/german_date_example/test_args +1 -0
- data/spec/integration/harder_date_example/input.csv +5 -0
- data/spec/integration/harder_date_example/output.ledger +20 -0
- data/spec/integration/harder_date_example/test_args +1 -0
- data/spec/integration/ing/input.csv +3 -0
- data/spec/integration/ing/output.ledger +12 -0
- data/spec/integration/ing/test_args +1 -0
- data/spec/integration/intuit_mint_example/input.csv +7 -0
- data/spec/integration/intuit_mint_example/output.ledger +28 -0
- data/spec/integration/intuit_mint_example/test_args +1 -0
- data/spec/integration/invalid_header_example/input.csv +6 -0
- data/spec/integration/invalid_header_example/output.ledger +8 -0
- data/spec/integration/invalid_header_example/test_args +1 -0
- data/spec/integration/inversed_credit_card/input.csv +16 -0
- data/spec/integration/inversed_credit_card/output.ledger +64 -0
- data/spec/integration/inversed_credit_card/test_args +1 -0
- data/spec/integration/nationwide/input.csv +4 -0
- data/spec/integration/nationwide/output.ledger +16 -0
- data/spec/integration/nationwide/test_args +1 -0
- data/spec/integration/regression/issue_51_account_tokens/input.csv +8 -0
- data/spec/integration/regression/issue_51_account_tokens/output.ledger +32 -0
- data/spec/integration/regression/issue_51_account_tokens/test_args +4 -0
- data/spec/integration/regression/issue_51_account_tokens/tokens.yml +9 -0
- data/spec/integration/regression/issue_64_date_column/input.csv +3 -0
- data/spec/integration/regression/issue_64_date_column/output.ledger +8 -0
- data/spec/integration/regression/issue_64_date_column/test_args +1 -0
- data/spec/integration/regression/issue_73_account_token_matching/input.csv +2 -0
- data/spec/integration/regression/issue_73_account_token_matching/output.ledger +4 -0
- data/spec/integration/regression/issue_73_account_token_matching/test_args +6 -0
- data/spec/integration/regression/issue_73_account_token_matching/tokens.yml +8 -0
- data/spec/integration/regression/issue_85_date_example/input.csv +2 -0
- data/spec/integration/regression/issue_85_date_example/output.ledger +8 -0
- data/spec/integration/regression/issue_85_date_example/test_args +1 -0
- data/spec/integration/spanish_date_example/input.csv +3 -0
- data/spec/integration/spanish_date_example/output.ledger +12 -0
- data/spec/integration/spanish_date_example/test_args +1 -0
- data/spec/integration/suntrust/input.csv +7 -0
- data/spec/integration/suntrust/output.ledger +28 -0
- data/spec/integration/suntrust/test_args +1 -0
- data/spec/integration/test.sh +82 -0
- data/spec/integration/test_money_column/input.csv +3 -0
- data/spec/integration/test_money_column/output.ledger +8 -0
- data/spec/integration/test_money_column/test_args +1 -0
- data/spec/integration/two_money_columns/input.csv +5 -0
- data/spec/integration/two_money_columns/output.ledger +20 -0
- data/spec/integration/two_money_columns/test_args +1 -0
- data/spec/integration/yyyymmdd_date_example/input.csv +1 -0
- data/spec/integration/yyyymmdd_date_example/output.ledger +4 -0
- data/spec/integration/yyyymmdd_date_example/test_args +1 -0
- data/spec/reckon/app_spec.rb +18 -2
- data/spec/reckon/csv_parser_spec.rb +129 -129
- data/spec/reckon/ledger_parser_spec.rb +42 -5
- data/spec/reckon/money_column_spec.rb +24 -24
- data/spec/reckon/money_spec.rb +36 -42
- data/spec/spec_helper.rb +19 -0
- metadata +97 -22
- data/.travis.yml +0 -13
@@ -0,0 +1 @@
|
|
1
|
+
-f input.csv --unattended --account Assets:Bank:Checking
|
@@ -0,0 +1,5 @@
|
|
1
|
+
4/1/2008,Check - 0000000122,122,-$76.00,"","$1,750.06"
|
2
|
+
3/28/2008,BLARG R SH 456930,"","",+$327.49,"$1,826.06"
|
3
|
+
3/27/2008,Check - 0000000112,112,-$800.00,"","$1,498.57"
|
4
|
+
3/26/2008,Check - 0000000251,251,-$88.55,"","$1,298.57"
|
5
|
+
3/26/2008,Check - 0000000251,251,"","+$88.55","$1,298.57"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
2008-03-26 Check - 0000000251; 251; $1,298.57
|
2
|
+
Assets:Bank:Checking $88.55
|
3
|
+
Income:Unknown
|
4
|
+
|
5
|
+
2008-03-26 Check - 0000000251; 251; $1,298.57
|
6
|
+
Income:Unknown
|
7
|
+
Assets:Bank:Checking -$88.55
|
8
|
+
|
9
|
+
2008-03-27 Check - 0000000112; 112; $1,498.57
|
10
|
+
Income:Unknown
|
11
|
+
Assets:Bank:Checking -$800.00
|
12
|
+
|
13
|
+
2008-03-28 BLARG R SH 456930; $1,826.06
|
14
|
+
Assets:Bank:Checking $327.49
|
15
|
+
Income:Unknown
|
16
|
+
|
17
|
+
2008-04-01 Check - 0000000122; 122; $1,750.06
|
18
|
+
Income:Unknown
|
19
|
+
Assets:Bank:Checking -$76.00
|
20
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
-f input.csv --unattended --account Assets:Bank:Checking
|
@@ -0,0 +1 @@
|
|
1
|
+
DEBIT,20121231,"ODESK***BAL-27DEC12 650-12345 CA 12/28",-123.45
|
@@ -0,0 +1 @@
|
|
1
|
+
-f input.csv --unattended --account Assets:Bank:Checking
|
data/spec/reckon/app_spec.rb
CHANGED
@@ -8,7 +8,7 @@ describe Reckon::App do
|
|
8
8
|
context 'with chase csv input' do
|
9
9
|
before do
|
10
10
|
@chase = Reckon::App.new(string: BANK_CSV)
|
11
|
-
@chase.
|
11
|
+
@chase.learn_from_ledger(BANK_LEDGER)
|
12
12
|
@rows = []
|
13
13
|
@chase.each_row_backwards { |row| @rows.push(row) }
|
14
14
|
end
|
@@ -68,7 +68,7 @@ describe Reckon::App do
|
|
68
68
|
end
|
69
69
|
|
70
70
|
it 'should learn from a ledger file' do
|
71
|
-
chase.
|
71
|
+
chase.learn_from_ledger(BANK_LEDGER)
|
72
72
|
chase.walk_backwards
|
73
73
|
output_file.string.scan('Expenses:Books').count.should == 1
|
74
74
|
end
|
@@ -121,6 +121,22 @@ describe Reckon::App do
|
|
121
121
|
end
|
122
122
|
end
|
123
123
|
|
124
|
+
context 'Issue #51 - regression test' do
|
125
|
+
it 'should assign correct accounts with tokens' do
|
126
|
+
output = StringIO.new
|
127
|
+
Reckon::App.new(
|
128
|
+
file: fixture_path('51-sample.csv'),
|
129
|
+
unattended: true,
|
130
|
+
account_tokens_file: fixture_path('51-tokens.yml'),
|
131
|
+
ignore_columns: [5],
|
132
|
+
bank_account: 'Assets:Chequing',
|
133
|
+
output_file: output
|
134
|
+
).walk_backwards
|
135
|
+
expect(output.string).not_to include('Income:Unknown')
|
136
|
+
expect(output.string.scan('Expenses:Dining:Resturant').size).to eq(8)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
124
140
|
#DATA
|
125
141
|
BANK_CSV = (<<-CSV).strip
|
126
142
|
DEBIT,20091224120000[0:GMT],"HOST 037196321563 MO 12/22SLICEHOST",-85.00
|
@@ -5,38 +5,29 @@ require_relative "../spec_helper"
|
|
5
5
|
require 'rubygems'
|
6
6
|
require_relative '../../lib/reckon'
|
7
7
|
|
8
|
-
Reckon::CSVParser.settings[:testing] = true
|
9
|
-
|
10
8
|
describe Reckon::CSVParser do
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
@intuit_mint = Reckon::CSVParser.new(file: fixture_path('intuit_mint_example.csv'))
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should be in testing mode" do
|
31
|
-
@chase.settings[:testing].should be true
|
32
|
-
Reckon::CSVParser.settings[:testing].should be true
|
33
|
-
end
|
9
|
+
let(:chase) { Reckon::CSVParser.new(file: fixture_path('chase.csv')) }
|
10
|
+
let(:some_other_bank) { Reckon::CSVParser.new(file: fixture_path('some_other.csv')) }
|
11
|
+
let(:two_money_columns) { Reckon::CSVParser.new(file: fixture_path('two_money_columns.csv')) }
|
12
|
+
let(:suntrust_csv) { Reckon::CSVParser.new(file: fixture_path('suntrust.csv')) }
|
13
|
+
let(:simple_csv) { Reckon::CSVParser.new(file: fixture_path('simple.csv')) }
|
14
|
+
let(:nationwide) { Reckon::CSVParser.new(file: fixture_path('nationwide.csv'), csv_separator: ',', suffixed: true, currency: "POUND") }
|
15
|
+
let(:german_date) { Reckon::CSVParser.new(file: fixture_path('german_date_example.csv')) }
|
16
|
+
let(:danish_kroner_nordea) { Reckon::CSVParser.new(file: fixture_path('danish_kroner_nordea_example.csv'), csv_separator: ';', comma_separates_cents: true) }
|
17
|
+
let(:yyyymmdd_date) { Reckon::CSVParser.new(file: fixture_path('yyyymmdd_date_example.csv')) }
|
18
|
+
let(:spanish_date) { Reckon::CSVParser.new(file: fixture_path('spanish_date_example.csv'), date_format: '%d/%m/%Y') }
|
19
|
+
let(:english_date) { Reckon::CSVParser.new(file: fixture_path('english_date_example.csv')) }
|
20
|
+
let(:ing_csv) { Reckon::CSVParser.new(file: fixture_path('ing.csv'), comma_separates_cents: true ) }
|
21
|
+
let(:austrian_csv) { Reckon::CSVParser.new(file: fixture_path('austrian_example.csv'), comma_separates_cents: true, csv_separator: ';' ) }
|
22
|
+
let(:french_csv) { Reckon::CSVParser.new(file: fixture_path('french_example.csv'), csv_separator: ';', comma_separates_cents: true) }
|
23
|
+
let(:broker_canada) { Reckon::CSVParser.new(file: fixture_path('broker_canada_example.csv')) }
|
24
|
+
let(:intuit_mint) { Reckon::CSVParser.new(file: fixture_path('intuit_mint_example.csv')) }
|
34
25
|
|
35
26
|
describe "parse" do
|
36
27
|
it "should use binary encoding if none specified and chardet fails" do
|
37
28
|
allow(CharDet).to receive(:detect).and_return({'encoding' => nil})
|
38
29
|
app = Reckon::CSVParser.new(file: fixture_path("extratofake.csv"))
|
39
|
-
expect(app.try_encoding
|
30
|
+
expect(app.send(:try_encoding, "foobarbaz")).to eq("BINARY")
|
40
31
|
end
|
41
32
|
|
42
33
|
it "should work with foreign character encodings" do
|
@@ -76,8 +67,8 @@ describe Reckon::CSVParser do
|
|
76
67
|
|
77
68
|
describe "columns" do
|
78
69
|
it "should return the csv transposed" do
|
79
|
-
|
80
|
-
|
70
|
+
simple_csv.columns.should == [["entry1", "entry4"], ["entry2", "entry5"], ["entry3", "entry6"]]
|
71
|
+
chase.columns.length.should == 4
|
81
72
|
end
|
82
73
|
|
83
74
|
it "should be ok with empty lines" do
|
@@ -88,46 +79,44 @@ describe Reckon::CSVParser do
|
|
88
79
|
end
|
89
80
|
|
90
81
|
describe "detect_columns" do
|
91
|
-
|
92
|
-
@harder_date_example_csv = Reckon::CSVParser.new(file: fixture_path('harder_date_example.csv'))
|
93
|
-
end
|
82
|
+
let(:harder_date_example_csv) { Reckon::CSVParser.new(file: fixture_path('harder_date_example.csv')) }
|
94
83
|
|
95
84
|
it "should detect the money column" do
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
85
|
+
chase.money_column_indices.should == [3]
|
86
|
+
some_other_bank.money_column_indices.should == [3]
|
87
|
+
two_money_columns.money_column_indices.should == [3, 4]
|
88
|
+
suntrust_csv.money_column_indices.should == [3, 4]
|
89
|
+
nationwide.money_column_indices.should == [3, 4]
|
90
|
+
harder_date_example_csv.money_column_indices.should == [1]
|
91
|
+
danish_kroner_nordea.money_column_indices.should == [3]
|
92
|
+
yyyymmdd_date.money_column_indices.should == [3]
|
93
|
+
ing_csv.money_column_indices.should == [6]
|
94
|
+
austrian_csv.money_column_indices.should == [4]
|
95
|
+
french_csv.money_column_indices.should == [4]
|
96
|
+
broker_canada.money_column_indices.should == [8]
|
97
|
+
intuit_mint.money_column_indices.should == [3]
|
109
98
|
end
|
110
99
|
|
111
100
|
it "should detect the date column" do
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
101
|
+
chase.date_column_index.should == 1
|
102
|
+
some_other_bank.date_column_index.should == 1
|
103
|
+
two_money_columns.date_column_index.should == 0
|
104
|
+
harder_date_example_csv.date_column_index.should == 0
|
105
|
+
danish_kroner_nordea.date_column_index.should == 0
|
106
|
+
yyyymmdd_date.date_column_index.should == 1
|
107
|
+
french_csv.date_column_index.should == 1
|
108
|
+
broker_canada.date_column_index.should == 0
|
109
|
+
intuit_mint.date_column_index.should == 0
|
121
110
|
Reckon::CSVParser.new(:string => '2014-01-13,"22211100000",-10').date_column_index.should == 0
|
122
111
|
end
|
123
112
|
|
124
113
|
it "should consider all other columns to be description columns" do
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
114
|
+
chase.description_column_indices.should == [0, 2]
|
115
|
+
some_other_bank.description_column_indices.should == [0, 2]
|
116
|
+
two_money_columns.description_column_indices.should == [1, 2, 5]
|
117
|
+
harder_date_example_csv.description_column_indices.should == [2, 3, 4, 5, 6, 7]
|
118
|
+
danish_kroner_nordea.description_column_indices.should == [1, 2, 4]
|
119
|
+
yyyymmdd_date.description_column_indices.should == [0, 2]
|
131
120
|
end
|
132
121
|
end
|
133
122
|
|
@@ -143,36 +132,36 @@ describe Reckon::CSVParser do
|
|
143
132
|
|
144
133
|
describe "money_for" do
|
145
134
|
it "should return the appropriate fields" do
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
135
|
+
chase.money_for(1).should == -20
|
136
|
+
chase.money_for(4).should == 1558.52
|
137
|
+
chase.money_for(7).should == -116.22
|
138
|
+
some_other_bank.money_for(1).should == -20
|
139
|
+
some_other_bank.money_for(4).should == 1558.52
|
140
|
+
some_other_bank.money_for(7).should == -116.22
|
141
|
+
two_money_columns.money_for(0).should == -76
|
142
|
+
two_money_columns.money_for(1).should == 327.49
|
143
|
+
two_money_columns.money_for(2).should == -800
|
144
|
+
two_money_columns.money_for(3).should == -88.55
|
145
|
+
two_money_columns.money_for(4).should == 88.55
|
146
|
+
nationwide.money_for(0).should == 500.00
|
147
|
+
nationwide.money_for(1).should == -20.00
|
148
|
+
danish_kroner_nordea.money_for(0).should == -48.00
|
149
|
+
danish_kroner_nordea.money_for(1).should == -79.00
|
150
|
+
danish_kroner_nordea.money_for(2).should == 497.90
|
151
|
+
danish_kroner_nordea.money_for(3).should == -995.00
|
152
|
+
danish_kroner_nordea.money_for(4).should == -3452.90
|
153
|
+
danish_kroner_nordea.money_for(5).should == -655.00
|
154
|
+
yyyymmdd_date.money_for(0).should == -123.45
|
155
|
+
ing_csv.money_for(0).should == -136.13
|
156
|
+
ing_csv.money_for(1).should == 375.00
|
157
|
+
austrian_csv.money_for(0).should == -18.00
|
158
|
+
austrian_csv.money_for(2).should == 120.00
|
159
|
+
french_csv.money_for(0).should == -10.00
|
160
|
+
french_csv.money_for(1).should == -5.76
|
161
|
+
broker_canada.money_for(0).should == 12.55
|
162
|
+
broker_canada.money_for(1).should == -81.57
|
163
|
+
intuit_mint.money_for(0).should == 0.01
|
164
|
+
intuit_mint.money_for(1).should == -331.63
|
176
165
|
end
|
177
166
|
|
178
167
|
it "should handle the comma_separates_cents option correctly" do
|
@@ -200,59 +189,63 @@ describe Reckon::CSVParser do
|
|
200
189
|
|
201
190
|
describe "date_for" do
|
202
191
|
it "should return a parsed date object" do
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
192
|
+
chase.date_for(1).year.should == Time.parse("2009/12/24").year
|
193
|
+
chase.date_for(1).month.should == Time.parse("2009/12/24").month
|
194
|
+
chase.date_for(1).day.should == Time.parse("2009/12/24").day
|
195
|
+
some_other_bank.date_for(1).year.should == Time.parse("2010/12/24").year
|
196
|
+
some_other_bank.date_for(1).month.should == Time.parse("2010/12/24").month
|
197
|
+
some_other_bank.date_for(1).day.should == Time.parse("2010/12/24").day
|
198
|
+
german_date.date_for(1).year.should == Time.parse("2009/12/24").year
|
199
|
+
german_date.date_for(1).month.should == Time.parse("2009/12/24").month
|
200
|
+
german_date.date_for(1).day.should == Time.parse("2009/12/24").day
|
201
|
+
danish_kroner_nordea.date_for(0).year.should == Time.parse("2012/11/16").year
|
202
|
+
danish_kroner_nordea.date_for(0).month.should == Time.parse("2012/11/16").month
|
203
|
+
danish_kroner_nordea.date_for(0).day.should == Time.parse("2012/11/16").day
|
204
|
+
yyyymmdd_date.date_for(0).year.should == Time.parse("2012/12/31").year
|
205
|
+
yyyymmdd_date.date_for(0).month.should == Time.parse("2012/12/31").month
|
206
|
+
yyyymmdd_date.date_for(0).day.should == Time.parse("2012/12/31").day
|
207
|
+
spanish_date.date_for(1).year.should == Time.parse("2009/12/02").year
|
208
|
+
spanish_date.date_for(1).month.should == Time.parse("2009/12/02").month
|
209
|
+
spanish_date.date_for(1).day.should == Time.parse("2009/12/02").day
|
210
|
+
english_date.date_for(1).year.should == Time.parse("2009/12/24").year
|
211
|
+
english_date.date_for(1).month.should == Time.parse("2009/12/24").month
|
212
|
+
english_date.date_for(1).day.should == Time.parse("2009/12/24").day
|
213
|
+
nationwide.date_for(1).month.should == 10
|
214
|
+
ing_csv.date_for(1).month.should == Time.parse("2012/11/12").month
|
215
|
+
ing_csv.date_for(1).day.should == Time.parse("2012/11/12").day
|
216
|
+
broker_canada.date_for(5).year.should == 2014
|
217
|
+
broker_canada.date_for(5).month.should == 1
|
218
|
+
broker_canada.date_for(5).day.should == 7
|
219
|
+
intuit_mint.date_for(1).year.should == 2014
|
220
|
+
intuit_mint.date_for(1).month.should == 2
|
221
|
+
intuit_mint.date_for(1).day.should == 3
|
233
222
|
end
|
234
223
|
end
|
235
224
|
|
236
225
|
describe "description_for" do
|
237
226
|
it "should return the combined fields that are not money for date fields" do
|
238
|
-
|
239
|
-
|
227
|
+
chase.description_for(1).should == "CHECK; CHECK 2656"
|
228
|
+
chase.description_for(7).should == "CREDIT; PAYPAL TRANSFER PPD ID: PAYPALSDSL"
|
240
229
|
end
|
241
230
|
|
242
231
|
it "should not append empty description column" do
|
243
232
|
parser = Reckon::CSVParser.new(:string => '01/09/2015,05354 SUBWAY,8.19,,',:date_format => '%d/%m/%Y')
|
244
|
-
parser.description_column_indices.should == [1, 4]
|
245
233
|
parser.description_for(0).should == '05354 SUBWAY'
|
246
234
|
end
|
235
|
+
|
236
|
+
it "should handle nil description" do
|
237
|
+
parser = Reckon::CSVParser.new(string: '2015-09-01,test,3.99')
|
238
|
+
expect(parser.description_for(1)).to eq("")
|
239
|
+
end
|
247
240
|
end
|
248
241
|
|
249
242
|
describe "pretty_money_for" do
|
250
243
|
it "work with negative and positive numbers" do
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
244
|
+
some_other_bank.pretty_money_for(1).should == "-$20.00"
|
245
|
+
some_other_bank.pretty_money_for(4).should == " $1558.52"
|
246
|
+
some_other_bank.pretty_money_for(7).should == "-$116.22"
|
247
|
+
some_other_bank.pretty_money_for(5).should == " $0.23"
|
248
|
+
some_other_bank.pretty_money_for(6).should == "-$0.96"
|
256
249
|
end
|
257
250
|
|
258
251
|
it "work with other currencies such as €" do
|
@@ -274,8 +267,15 @@ describe Reckon::CSVParser do
|
|
274
267
|
end
|
275
268
|
|
276
269
|
it "should work with merge columns" do
|
277
|
-
|
278
|
-
|
270
|
+
nationwide.pretty_money_for(0).should == " 500.00 POUND"
|
271
|
+
nationwide.pretty_money_for(1).should == "-20.00 POUND"
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
describe '85 regression test' do
|
276
|
+
it 'should detect correct date column' do
|
277
|
+
p = Reckon::CSVParser.new(file:fixture_path('85-date-example.csv'))
|
278
|
+
expect(p.date_column_index).to eq(2)
|
279
279
|
end
|
280
280
|
end
|
281
281
|
end
|
@@ -20,14 +20,16 @@ describe Reckon::LedgerParser do
|
|
20
20
|
formats = ["%Y/%m/%d", "%Y-%m-%d"]
|
21
21
|
types = [' ! ', ' * ', ' ']
|
22
22
|
delimiters = [" ", "\t", "\t\t"]
|
23
|
+
comment_chars = ';#%*|'
|
23
24
|
currency_delimiters = delimiters + ['']
|
24
25
|
currencies = ['', '$', '£']
|
25
26
|
property_of do
|
26
27
|
Rantly do
|
27
28
|
description = Proc.new do
|
28
|
-
sized(15){string}.tr(%q{'`:*\\},'').gsub(/\s+/, ' ').gsub(/^[!;<\[( ]+/, '')
|
29
|
+
sized(15){string}.tr(%q{'`:*\\},'').gsub(/\s+/, ' ').gsub(/^[!;<\[( #{comment_chars}]+/, '')
|
29
30
|
end
|
30
31
|
currency = choose(*currencies) # to be consistent within the transaction
|
32
|
+
single_line_comments = ";#|%*".split('').map { |n| "#{n} #{call(description)}" }
|
31
33
|
comments = ['', '; ', "\t;#{call(description)}", " ; #{call(description)}"]
|
32
34
|
date = Time.at(range(0, 1_581_389_644)).strftime(choose(*formats))
|
33
35
|
codes = [' ', " (#{string(:alnum).tr('()', '')}) "]
|
@@ -48,23 +50,58 @@ describe Reckon::LedgerParser do
|
|
48
50
|
ledger += "#{call(account_line)}\n"
|
49
51
|
end
|
50
52
|
ledger += "#{call(account)}\n"
|
53
|
+
ledger += choose(*single_line_comments) + "\n"
|
51
54
|
ledger
|
52
55
|
end
|
53
56
|
end.check(1000) do |s|
|
54
57
|
filter_format = lambda { |n| [n['date'], n['desc'], n['name'], sprintf("%.02f", n['amount'])] }
|
55
58
|
headers = %w[date code desc name currency amount type commend]
|
56
59
|
safe_s = Shellwords.escape(s)
|
57
|
-
ledger_csv = `echo #{safe_s} | ledger csv --date-format '%Y-%m-%d' -f - `
|
58
|
-
ledger_parser_csv = Reckon::LedgerParser.new(s, date_format: '%Y/%m/%d').to_csv.join("\n")
|
59
60
|
|
60
|
-
|
61
|
-
actual = CSV.parse(
|
61
|
+
lp_csv = Reckon::LedgerParser.new(s, date_format: '%Y/%m/%d').to_csv.join("\n")
|
62
|
+
actual = CSV.parse(lp_csv, headers: headers).map(&filter_format)
|
63
|
+
|
64
|
+
ledger_csv = `echo #{safe_s} | ledger csv --date-format '%Y/%m/%d' -f - `
|
65
|
+
expected = CSV.parse(ledger_csv.gsub('\"', '""'), headers: headers).map(&filter_format)
|
62
66
|
expected.length.times do |i|
|
63
67
|
expect(actual[i]).to eq(expected[i])
|
64
68
|
end
|
65
69
|
end
|
66
70
|
end
|
67
71
|
|
72
|
+
it 'should filter block comments' do
|
73
|
+
ledger = <<HERE
|
74
|
+
1970/11/01 Dinner should show up
|
75
|
+
Assets:Checking -123.00
|
76
|
+
Expenses:Restaurants
|
77
|
+
|
78
|
+
comment
|
79
|
+
|
80
|
+
1970/11/01 Lunch should NOT show up
|
81
|
+
Assets:Checking -12.00
|
82
|
+
Expenses:Restaurants
|
83
|
+
|
84
|
+
end comment
|
85
|
+
HERE
|
86
|
+
l = Reckon::LedgerParser.new(ledger)
|
87
|
+
expect(l.entries.length).to eq(1)
|
88
|
+
expect(l.entries.first[:desc]).to eq('Dinner should show up')
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should transaction comments' do
|
93
|
+
ledger = <<HERE
|
94
|
+
2020-03-27 AMZN Mktp USX999H3203; Shopping; Sale
|
95
|
+
Expenses:Household $82.77
|
96
|
+
Liabilities:ChaseSapphire -$81.77
|
97
|
+
# END FINANCE SCRIPT OUTPUT Thu 02 Apr 2020 12:05:54 PM EDT
|
98
|
+
HERE
|
99
|
+
l = Reckon::LedgerParser.new(ledger)
|
100
|
+
expect(l.entries.first[:accounts].map { |n| n[:name] }).to eq(['Expenses:Household', 'Liabilities:ChaseSapphire'])
|
101
|
+
expect(l.entries.first[:accounts].size).to eq(2)
|
102
|
+
expect(l.entries.length).to eq(1)
|
103
|
+
end
|
104
|
+
|
68
105
|
it "should ignore non-standard entries" do
|
69
106
|
@ledger.entries.length.should == 7
|
70
107
|
end
|