reckon 0.6.0 → 0.6.1
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 +4 -4
- data/.github/workflows/ruby.yml +50 -0
- data/.gitignore +2 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +23 -3
- data/Gemfile.lock +1 -1
- data/README.md +72 -16
- data/Rakefile +17 -1
- data/lib/reckon/app.rb +10 -5
- data/lib/reckon/csv_parser.rb +2 -7
- data/lib/reckon/date_column.rb +10 -0
- data/lib/reckon/money.rb +48 -48
- data/lib/reckon/version.rb +1 -1
- 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/money_column_spec.rb +24 -24
- data/spec/reckon/money_spec.rb +13 -32
- metadata +93 -7
- data/.travis.yml +0 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aebd4114b69fd94cc45e9cf425da57269ae80508b90f781fbbc5c96c6912b100
|
|
4
|
+
data.tar.gz: 0de1e3fb308bc2dad8cfa679056189092a4f07ece989b8e3b57c8acca100c77c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c59e8ae6ecbf11534086bd9fc179ff5e8aa52066b8fb0cd5ddbce28b6a4a01b32659fdf51cdaa00403a86be2b3023e390184b76924fb13a6ed5288b8d637c8c0
|
|
7
|
+
data.tar.gz: 75a5921df0c427351768c803bbe019b3bdf7a12ec8f8d714779086a73ab850ea50b49708c9430ac823b97c0ef35493b5888b5980cdbfab4691cecc05b759224e
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
|
2
|
+
# They are provided by a third-party and are governed by
|
|
3
|
+
# separate terms of service, privacy policy, and support
|
|
4
|
+
# documentation.
|
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
|
7
|
+
|
|
8
|
+
name: Build Status
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
branches: [ master ]
|
|
13
|
+
pull_request:
|
|
14
|
+
branches: [ master ]
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
test:
|
|
18
|
+
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
strategy:
|
|
21
|
+
matrix:
|
|
22
|
+
ruby-version:
|
|
23
|
+
# Current ruby stable version
|
|
24
|
+
- 3.0
|
|
25
|
+
# Ubuntu 20.10
|
|
26
|
+
- 2.7
|
|
27
|
+
# Ubuntu 19.10
|
|
28
|
+
- 2.5
|
|
29
|
+
# Mac v11 Big Sur
|
|
30
|
+
# - 2.6?
|
|
31
|
+
# Mac v10.15 Catalina
|
|
32
|
+
- 2.6
|
|
33
|
+
# Mac v10.14 Mojave
|
|
34
|
+
- 2.3.7
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/checkout@v2
|
|
37
|
+
- name: Install packages
|
|
38
|
+
run: sudo apt-get -y install ledger hledger
|
|
39
|
+
- name: Install bundler
|
|
40
|
+
run: sudo gem install -v 1.17.3 bundler
|
|
41
|
+
- name: Set up Ruby
|
|
42
|
+
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
|
43
|
+
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
|
44
|
+
uses: ruby/setup-ruby@v1
|
|
45
|
+
# uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
|
|
46
|
+
with:
|
|
47
|
+
ruby-version: ${{ matrix.ruby-version }}
|
|
48
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
|
49
|
+
- name: Run tests
|
|
50
|
+
run: bundle exec rake test_all
|
data/.gitignore
CHANGED
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
3.0.0
|
data/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [0.6.
|
|
3
|
+
## [0.6.1](https://github.com/cantino/reckon/tree/0.6.1) (2021-01-23)
|
|
4
4
|
|
|
5
|
-
[Full Changelog](https://github.com/cantino/reckon/compare/v0.
|
|
5
|
+
[Full Changelog](https://github.com/cantino/reckon/compare/v0.6.0...0.6.1)
|
|
6
|
+
|
|
7
|
+
**Implemented enhancements:**
|
|
8
|
+
|
|
9
|
+
- \[Feature Request\] Note flag --add-notes in CLI to allow additional notes for each ledger entry [\#86](https://github.com/cantino/reckon/issues/86)
|
|
10
|
+
|
|
11
|
+
**Closed issues:**
|
|
12
|
+
|
|
13
|
+
- spaces in tokens [\#97](https://github.com/cantino/reckon/issues/97)
|
|
14
|
+
- Migrate CI system from travis-ci.org [\#93](https://github.com/cantino/reckon/issues/93)
|
|
15
|
+
- \[Feature Request\] Pipe ledger file input to the bayesian predictor \(instead of csv\) [\#91](https://github.com/cantino/reckon/issues/91)
|
|
16
|
+
|
|
17
|
+
**Merged pull requests:**
|
|
18
|
+
|
|
19
|
+
- Add github actions [\#100](https://github.com/cantino/reckon/pull/100) ([benprew](https://github.com/benprew))
|
|
20
|
+
- Add documentation for doing a substring match. Fixes \#97 [\#99](https://github.com/cantino/reckon/pull/99) ([benprew](https://github.com/benprew))
|
|
21
|
+
- Test fixes [\#94](https://github.com/cantino/reckon/pull/94) ([benprew](https://github.com/benprew))
|
|
22
|
+
|
|
23
|
+
## [v0.6.0](https://github.com/cantino/reckon/tree/v0.6.0) (2020-09-04)
|
|
24
|
+
|
|
25
|
+
[Full Changelog](https://github.com/cantino/reckon/compare/v0.5.4...v0.6.0)
|
|
6
26
|
|
|
7
27
|
**Fixed bugs:**
|
|
8
28
|
|
|
@@ -198,6 +218,7 @@
|
|
|
198
218
|
|
|
199
219
|
**Merged pull requests:**
|
|
200
220
|
|
|
221
|
+
- Updated the sources to allow for custom curreny [\#11](https://github.com/cantino/reckon/pull/11) ([ghost](https://github.com/ghost))
|
|
201
222
|
- Add --account option on the commandline [\#10](https://github.com/cantino/reckon/pull/10) ([copiousfreetime](https://github.com/copiousfreetime))
|
|
202
223
|
|
|
203
224
|
## [v0.3.6](https://github.com/cantino/reckon/tree/v0.3.6) (2013-04-30)
|
|
@@ -231,7 +252,6 @@
|
|
|
231
252
|
|
|
232
253
|
**Merged pull requests:**
|
|
233
254
|
|
|
234
|
-
- Updated the sources to allow for custom curreny [\#11](https://github.com/cantino/reckon/pull/11) ([ghost](https://github.com/ghost))
|
|
235
255
|
- adds support for Nordea csv files [\#1](https://github.com/cantino/reckon/pull/1) ([x2q](https://github.com/x2q))
|
|
236
256
|
|
|
237
257
|
## [v0.3.3](https://github.com/cantino/reckon/tree/v0.3.3) (2013-01-13)
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Reckon
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+

|
|
4
4
|
|
|
5
5
|
Reckon automagically converts CSV files for use with the command-line accounting tool [Ledger](http://www.ledger-cli.org/). It also helps you to select the correct accounts associated with the CSV data using Bayesian machine learning.
|
|
6
6
|
|
|
@@ -34,9 +34,8 @@ Learn more:
|
|
|
34
34
|
|
|
35
35
|
Usage: Reckon.rb [options]
|
|
36
36
|
|
|
37
|
-
|
|
38
37
|
-f, --file FILE The CSV file to parse
|
|
39
|
-
-a, --account
|
|
38
|
+
-a, --account NAME The Ledger Account this file is for
|
|
40
39
|
-v, --[no-]verbose Run verbosely
|
|
41
40
|
-i, --inverse Use the negative of each amount
|
|
42
41
|
-p, --print-table Print out the parsed CSV in table form
|
|
@@ -44,6 +43,12 @@ Learn more:
|
|
|
44
43
|
-l, --learn-from FILE An existing ledger file to learn accounts from
|
|
45
44
|
--ignore-columns 1,2,5
|
|
46
45
|
Columns to ignore in the CSV file - the first column is column 1
|
|
46
|
+
--money-column 2
|
|
47
|
+
Specify the money column instead of letting Reckon guess - the first column is column 1
|
|
48
|
+
--raw-money
|
|
49
|
+
Don't format money column (for stocks)
|
|
50
|
+
--date-column 3
|
|
51
|
+
Specify the date column instead of letting Reckon guess - the first column is column 1
|
|
47
52
|
--contains-header [N]
|
|
48
53
|
The first row of the CSV is a header and should be skipped. Optionally add the number of rows to skip.
|
|
49
54
|
--csv-separator ','
|
|
@@ -57,9 +62,9 @@ Learn more:
|
|
|
57
62
|
Force the date format (see Ruby DateTime strftime)
|
|
58
63
|
-u, --unattended Don't ask questions and guess all the accounts automatically. Used with --learn-from or --account-tokens options.
|
|
59
64
|
-t, --account-tokens FILE YAML file with manually-assigned tokens for each account (see README)
|
|
60
|
-
--default-into-account
|
|
65
|
+
--default-into-account NAME
|
|
61
66
|
Default into account
|
|
62
|
-
--default-outof-account
|
|
67
|
+
--default-outof-account NAME
|
|
63
68
|
Default 'out of' account
|
|
64
69
|
--suffixed
|
|
65
70
|
If --currency should be used as a suffix. Defaults to false.
|
|
@@ -77,6 +82,16 @@ To guess the accounts reckon can use an existing ledger file or a token file wit
|
|
|
77
82
|
|
|
78
83
|
`reckon --unattended --account-tokens tokens.yaml -f bank.csv -o ledger.dat`
|
|
79
84
|
|
|
85
|
+
### Account Tokens
|
|
86
|
+
|
|
87
|
+
The account tokens file provides a way to teach reckon about what tokens are associated with an account. As an example, this `tokens.yaml` file:
|
|
88
|
+
|
|
89
|
+
Expenses:
|
|
90
|
+
Bank:
|
|
91
|
+
- 'ING Direct Deposit'
|
|
92
|
+
|
|
93
|
+
Would tokenize to 'ING', 'Direct' and 'Deposit'. The matcher would then suggest matches to transactions that included those tokens. (ex 'Chase Direct Deposit')
|
|
94
|
+
|
|
80
95
|
Here's an example of `tokens.yaml`:
|
|
81
96
|
|
|
82
97
|
```
|
|
@@ -96,21 +111,62 @@ Expenses:
|
|
|
96
111
|
- '4433221100' # Your own account number
|
|
97
112
|
```
|
|
98
113
|
|
|
99
|
-
|
|
100
|
-
|
|
114
|
+
Reckon will use `Income:Unknown` or `Expenses:Unknown` if it can't match a transaction to an account.
|
|
115
|
+
|
|
116
|
+
You can override these names with the `--default_outof_account` and `--default_into_account` options.
|
|
117
|
+
|
|
118
|
+
### Substring Match
|
|
119
|
+
|
|
120
|
+
If, in the above example, you'd prefer to match any transaction that contains the string 'ING Direct Deposit' you have to use a regex:
|
|
121
|
+
|
|
122
|
+
Expenses:
|
|
123
|
+
Bank:
|
|
124
|
+
- /ING Direct Deposit/
|
|
125
|
+
|
|
126
|
+
## Contributing
|
|
127
|
+
|
|
128
|
+
We encourage you to contribute to Reckon! Here is some information to help you.
|
|
129
|
+
|
|
130
|
+
### Patches/Pull Requests Process
|
|
131
|
+
|
|
132
|
+
1. Fork the project.
|
|
133
|
+
2. Make your feature addition or bug fix.
|
|
134
|
+
3. Add tests for it. This is important so I don't break it in a
|
|
135
|
+
4. future version unintentionally.
|
|
136
|
+
5. Commit, do not mess with rakefile, version, or history.
|
|
137
|
+
- (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
|
138
|
+
6. Send me a pull request. Bonus points for topic branches.
|
|
101
139
|
|
|
102
|
-
|
|
140
|
+
### Integration Tests
|
|
141
|
+
|
|
142
|
+
Reckon has integration test located in `spec/integration`. These are integration and regression tests for reckon.
|
|
143
|
+
|
|
144
|
+
Run all the tests:
|
|
145
|
+
|
|
146
|
+
./spec/integration/test.sh
|
|
147
|
+
|
|
148
|
+
Run a single test
|
|
149
|
+
|
|
150
|
+
./spec/integration/test.sh chase/account_tokens_and_regex
|
|
151
|
+
|
|
152
|
+
#### Add a new integration test
|
|
153
|
+
|
|
154
|
+
Each test has it's own directory, which you can add any files you want, but the following files are required:
|
|
155
|
+
|
|
156
|
+
- `test_args` - arguments to add to the reckon command to test against, can specify `--unattended`, `-f input.csv`, etc
|
|
157
|
+
- `output.ledger` - the expected ledger file output
|
|
158
|
+
|
|
159
|
+
If the result of running reckon with `test_args` does not match `output.ledger`, then the test fails.
|
|
160
|
+
|
|
161
|
+
Most tests will specify `--unattended`, otherwise reckon prompts for keyboard input.
|
|
162
|
+
|
|
163
|
+
The convention is to use `input.csv` as the input file, and `tokens.yml` as the tokens file, but it is not required.
|
|
103
164
|
|
|
104
|
-
* Fork the project.
|
|
105
|
-
* Make your feature addition or bug fix.
|
|
106
|
-
* Add tests for it. This is important so I don't break it in a
|
|
107
|
-
future version unintentionally.
|
|
108
|
-
* Commit, do not mess with rakefile, version, or history.
|
|
109
|
-
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
|
110
|
-
* Send me a pull request. Bonus points for topic branches.
|
|
111
165
|
|
|
112
166
|
## Copyright
|
|
113
167
|
|
|
114
|
-
Copyright (c) 2013 Andrew Cantino. See LICENSE for details.
|
|
168
|
+
Copyright (c) 2013 Andrew Cantino (@cantino). See LICENSE for details.
|
|
115
169
|
|
|
116
170
|
Thanks to @BlackEdder for many contributions!
|
|
171
|
+
|
|
172
|
+
Currently maintained by @benprew. Thank you!
|
data/Rakefile
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "bundler/gem_tasks"
|
|
2
4
|
require 'rspec/core/rake_task'
|
|
5
|
+
require 'English'
|
|
3
6
|
|
|
4
7
|
RSpec::Core::RakeTask.new(:spec)
|
|
5
8
|
|
|
6
|
-
task :
|
|
9
|
+
task default: :spec
|
|
10
|
+
|
|
11
|
+
task :test_all do
|
|
12
|
+
puts "#{`ledger --version |head -n1`}"
|
|
13
|
+
puts "Running unit tests"
|
|
14
|
+
Rake::Task["spec"].invoke
|
|
15
|
+
puts "Running integration tests"
|
|
16
|
+
Rake::Task["integration_tests"].invoke
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
task :integration_tests do
|
|
20
|
+
puts `./spec/integration/test.sh`
|
|
21
|
+
raise 'Integration tests failed' if $CHILD_STATUS.exitstatus != 0
|
|
22
|
+
end
|
data/lib/reckon/app.rb
CHANGED
|
@@ -8,9 +8,10 @@ module Reckon
|
|
|
8
8
|
attr_accessor :options, :seen, :csv_parser, :regexps, :matcher
|
|
9
9
|
@@cli = HighLine.new
|
|
10
10
|
|
|
11
|
-
def initialize(
|
|
11
|
+
def initialize(opts = {})
|
|
12
|
+
self.options = opts
|
|
12
13
|
LOGGER.level = Logger::INFO if options[:verbose]
|
|
13
|
-
|
|
14
|
+
|
|
14
15
|
self.regexps = {}
|
|
15
16
|
self.seen = Set.new
|
|
16
17
|
self.options[:currency] ||= '$'
|
|
@@ -157,7 +158,7 @@ module Reckon
|
|
|
157
158
|
:money => @csv_parser.money_for(index),
|
|
158
159
|
:description => @csv_parser.description_for(index) }
|
|
159
160
|
end
|
|
160
|
-
rows.sort_by { |n| n[:date] }.each { |row| yield row }
|
|
161
|
+
rows.sort_by { |n| [n[:date], -n[:money], n[:description]] }.each { |row| yield row }
|
|
161
162
|
end
|
|
162
163
|
|
|
163
164
|
def print_transaction(rows)
|
|
@@ -252,7 +253,7 @@ module Reckon
|
|
|
252
253
|
end
|
|
253
254
|
|
|
254
255
|
def ledger_format(row, line1, line2)
|
|
255
|
-
out = "#{row[:pretty_date]}\t#{row[:description]}\t;
|
|
256
|
+
out = "#{row[:pretty_date]}\t#{row[:description]}#{row[:note] ? "\t; " + row[:note]: ""}\n"
|
|
256
257
|
out += "\t#{line1.first}\t\t\t#{line1.last}\n"
|
|
257
258
|
out += "\t#{line2.first}\t\t\t#{line2.last}\n\n"
|
|
258
259
|
out
|
|
@@ -327,6 +328,10 @@ module Reckon
|
|
|
327
328
|
options[:money_column] = column_number
|
|
328
329
|
end
|
|
329
330
|
|
|
331
|
+
opts.on("", "--raw-money", "Don't format money column (for stocks)") do |n|
|
|
332
|
+
options[:raw] = n
|
|
333
|
+
end
|
|
334
|
+
|
|
330
335
|
opts.on("", "--date-column 3", Integer, "Specify the date column instead of letting Reckon guess - the first column is column 1") do |column_number|
|
|
331
336
|
options[:date_column] = column_number
|
|
332
337
|
end
|
|
@@ -399,7 +404,7 @@ module Reckon
|
|
|
399
404
|
end
|
|
400
405
|
|
|
401
406
|
unless options[:bank_account]
|
|
402
|
-
fail "Please specify --account
|
|
407
|
+
fail "Please specify --account in unattended mode" if options[:unattended]
|
|
403
408
|
|
|
404
409
|
options[:bank_account] = @@cli.ask("What is the account name of this bank account in Ledger? ") do |q|
|
|
405
410
|
q.readline = true
|
data/lib/reckon/csv_parser.rb
CHANGED
|
@@ -89,12 +89,7 @@ module Reckon
|
|
|
89
89
|
money_score += Money::likelihood( entry )
|
|
90
90
|
possible_neg_money_count += 1 if entry =~ /^\$?[\-\(]\$?\d+/
|
|
91
91
|
possible_pos_money_count += 1 if entry =~ /^\+?\$?\+?\d+/
|
|
92
|
-
date_score +=
|
|
93
|
-
date_score += 5 if entry =~ /^[\-\/\.\d:\[\]]+$/
|
|
94
|
-
date_score += entry.gsub(/[^\-\/\.\d:\[\]]/, '').length if entry.gsub(/[^\-\/\.\d:\[\]]/, '').length > 3
|
|
95
|
-
date_score -= entry.gsub(/[\-\/\.\d:\[\]]/, '').length
|
|
96
|
-
date_score += 30 if entry =~ /^\d+[:\/\.-]\d+[:\/\.-]\d+([ :]\d+[:\/\.]\d+)?$/
|
|
97
|
-
date_score += 10 if entry =~ /^\d+\[\d+:GMT\]$/i
|
|
92
|
+
date_score += DateColumn.likelihood(entry)
|
|
98
93
|
|
|
99
94
|
# Try to determine if this is a balance column
|
|
100
95
|
entry_as_num = entry.gsub(/[^\-\d\.]/, '').to_f
|
|
@@ -168,7 +163,7 @@ module Reckon
|
|
|
168
163
|
results = evaluate_columns(columns)
|
|
169
164
|
|
|
170
165
|
if options[:money_column]
|
|
171
|
-
self.money_column_indices = [
|
|
166
|
+
self.money_column_indices = [options[:money_column] - 1]
|
|
172
167
|
else
|
|
173
168
|
self.money_column_indices = results.select { |n| n[:is_money_column] }.map { |n| n[:index] }
|
|
174
169
|
if self.money_column_indices.length == 1
|
data/lib/reckon/date_column.rb
CHANGED
|
@@ -56,5 +56,15 @@ module Reckon
|
|
|
56
56
|
date.iso8601
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
+
def self.likelihood(entry)
|
|
60
|
+
date_score = 0
|
|
61
|
+
date_score += 10 if entry =~ /\b(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)/i
|
|
62
|
+
date_score += 5 if entry =~ /^[\-\/\.\d:\[\]]+$/
|
|
63
|
+
date_score += entry.gsub(/[^\-\/\.\d:\[\]]/, '').length if entry.gsub(/[^\-\/\.\d:\[\]]/, '').length > 3
|
|
64
|
+
date_score -= entry.gsub(/[\-\/\.\d:\[\]]/, '').length
|
|
65
|
+
date_score += 30 if entry =~ /^\d+[:\/\.-]\d+[:\/\.-]\d+([ :]\d+[:\/\.]\d+)?$/
|
|
66
|
+
date_score += 10 if entry =~ /^\d+\[\d+:GMT\]$/i
|
|
67
|
+
return date_score
|
|
68
|
+
end
|
|
59
69
|
end
|
|
60
70
|
end
|
data/lib/reckon/money.rb
CHANGED
|
@@ -5,12 +5,13 @@ module Reckon
|
|
|
5
5
|
class Money
|
|
6
6
|
include Comparable
|
|
7
7
|
attr_accessor :amount, :currency, :suffixed
|
|
8
|
-
def initialize(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
def initialize(amount, options = {})
|
|
9
|
+
@options = options
|
|
10
|
+
@amount_raw = amount
|
|
11
|
+
@raw = options[:raw]
|
|
12
|
+
|
|
13
|
+
@amount = parse(amount, options)
|
|
14
|
+
@amount = -@amount if options[:inverse]
|
|
14
15
|
@currency = options[:currency] || "$"
|
|
15
16
|
@suffixed = options[:suffixed]
|
|
16
17
|
end
|
|
@@ -19,11 +20,19 @@ module Reckon
|
|
|
19
20
|
return @amount
|
|
20
21
|
end
|
|
21
22
|
|
|
23
|
+
def to_s
|
|
24
|
+
return @options[:raw] ? "#{@amount_raw} | #{@amount}" : @amount
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# unary minus
|
|
28
|
+
# ex
|
|
29
|
+
# m = Money.new
|
|
30
|
+
# -m
|
|
22
31
|
def -@
|
|
23
|
-
Money.new(
|
|
32
|
+
Money.new(-@amount, :currency => @currency, :suffixed => @suffixed)
|
|
24
33
|
end
|
|
25
34
|
|
|
26
|
-
def <=>(
|
|
35
|
+
def <=>(mon)
|
|
27
36
|
other_amount = mon.to_f
|
|
28
37
|
if @amount < other_amount
|
|
29
38
|
-1
|
|
@@ -34,7 +43,13 @@ module Reckon
|
|
|
34
43
|
end
|
|
35
44
|
end
|
|
36
45
|
|
|
37
|
-
def pretty(
|
|
46
|
+
def pretty(negate = false)
|
|
47
|
+
if @raw
|
|
48
|
+
return @amount_raw unless negate
|
|
49
|
+
|
|
50
|
+
return @amount_raw[0] == '-' ? @amount_raw[1..-1] : "-#{@amount_raw}"
|
|
51
|
+
end
|
|
52
|
+
|
|
38
53
|
if @suffixed
|
|
39
54
|
(@amount >= 0 ? " " : "") + sprintf("%0.2f #{@currency}", @amount * (negate ? -1 : 1))
|
|
40
55
|
else
|
|
@@ -42,34 +57,20 @@ module Reckon
|
|
|
42
57
|
end
|
|
43
58
|
end
|
|
44
59
|
|
|
45
|
-
def
|
|
60
|
+
def parse(value, options = {})
|
|
61
|
+
value = value.to_s
|
|
46
62
|
# Empty string is treated as money with value 0
|
|
47
|
-
return
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
value = value.
|
|
52
|
-
value = value.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
any_number_regex = /^(.*?)([\d\.]+)/
|
|
56
|
-
|
|
57
|
-
# Prefer matching the money_format, match any number otherwise
|
|
58
|
-
m = value.match( money_format_regex ) ||
|
|
59
|
-
value.match( any_number_regex )
|
|
60
|
-
if m
|
|
61
|
-
amount = m[2].to_f
|
|
62
|
-
# Check whether the money had a - or (, which indicates negative amounts
|
|
63
|
-
if (m[1].match( /^[\(-]/ ) || m[1].match( /-$/ ))
|
|
64
|
-
amount *= -1
|
|
65
|
-
end
|
|
66
|
-
return Money.new( amount, options )
|
|
67
|
-
else
|
|
68
|
-
return nil
|
|
69
|
-
end
|
|
63
|
+
return value.to_f if value.to_s.empty?
|
|
64
|
+
|
|
65
|
+
invert = value.match(/^\(.*\)$/)
|
|
66
|
+
value = value.gsub(/[^0-9,.-]/, '')
|
|
67
|
+
value = value.tr('.', '').tr(',', '.') if options[:comma_separates_cents]
|
|
68
|
+
value = value.tr(',', '')
|
|
69
|
+
value = value.to_f
|
|
70
|
+
return invert ? -value : value
|
|
70
71
|
end
|
|
71
72
|
|
|
72
|
-
def Money::likelihood(
|
|
73
|
+
def Money::likelihood(entry)
|
|
73
74
|
money_score = 0
|
|
74
75
|
# digits separated by , or . with no more than 2 trailing digits
|
|
75
76
|
money_score += 40 if entry.match(/\d+[,.]\d{2}[^\d]*$/)
|
|
@@ -83,31 +84,30 @@ module Reckon
|
|
|
83
84
|
end
|
|
84
85
|
|
|
85
86
|
class MoneyColumn < Array
|
|
86
|
-
def initialize(
|
|
87
|
-
arr.each { |str|
|
|
87
|
+
def initialize(arr = [], options = {})
|
|
88
|
+
arr.each { |str| push(Money.new(str, options)) }
|
|
88
89
|
end
|
|
89
90
|
|
|
90
91
|
def positive?
|
|
91
|
-
|
|
92
|
-
return false if money < 0
|
|
92
|
+
each do |money|
|
|
93
|
+
return false if money && money < 0
|
|
93
94
|
end
|
|
94
95
|
true
|
|
95
96
|
end
|
|
96
97
|
|
|
97
|
-
def merge!(
|
|
98
|
+
def merge!(other_column)
|
|
98
99
|
invert = false
|
|
99
|
-
invert = true if
|
|
100
|
-
|
|
100
|
+
invert = true if positive? && other_column.positive?
|
|
101
|
+
each_with_index do |mon, i|
|
|
101
102
|
other = other_column[i]
|
|
102
|
-
return nil if
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
elsif mon == 0.00 && other != 0.00
|
|
103
|
+
return nil if !mon || !other
|
|
104
|
+
|
|
105
|
+
if mon != 0.0 && other == 0.0
|
|
106
|
+
self[i] = -mon if invert
|
|
107
|
+
elsif mon == 0.0 && other != 0.0
|
|
108
108
|
self[i] = other
|
|
109
109
|
else
|
|
110
|
-
|
|
110
|
+
self[i] = Money.new(0)
|
|
111
111
|
end
|
|
112
112
|
end
|
|
113
113
|
self
|