amex_csv_to_ledger 0.1.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 +7 -0
- data/.rubocop.yml +6 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +60 -0
- data/README.md +54 -0
- data/Rakefile +16 -0
- data/doc/config.yml.example +6 -0
- data/lib/amex_csv_to_ledger/config.rb +44 -0
- data/lib/amex_csv_to_ledger/ledger_date_line.rb +35 -0
- data/lib/amex_csv_to_ledger/ledger_expense_line.rb +75 -0
- data/lib/amex_csv_to_ledger/ledger_outgoing_line.rb +34 -0
- data/lib/amex_csv_to_ledger/ledger_report.rb +39 -0
- data/lib/amex_csv_to_ledger/statement.rb +24 -0
- data/lib/amex_csv_to_ledger/statement_line.rb +14 -0
- data/lib/amex_csv_to_ledger/version.rb +5 -0
- data/lib/amex_csv_to_ledger.rb +23 -0
- data/tmp/.gitkeep +0 -0
- metadata +61 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 293cf23b091e043c0dfbb7a2e1ac82fcc5a42030d41a97124f4e3c469f205d38
|
4
|
+
data.tar.gz: 68f8bcbc78d056cb1209065b432b97e9697b60e9f112e463334f944a2f985df2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f3a3991de3df88999aff7116d0d96a162fbb31bd9662c04abfba393208ed079e90e08f55247dd74dff6404f0bba25d8e3d531eb95b232cf40e34799716df276c
|
7
|
+
data.tar.gz: 5da02d8e0152f2a08fd0fe79b86dc97353ce35a375a789e0b777866ef31d076e9b163a6bb014098c6be949b2a2fa8f990806997bc10211da52a852e389b962bc
|
data/.rubocop.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
amex_csv_to_ledger (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
ast (2.4.2)
|
10
|
+
byebug (11.1.3)
|
11
|
+
coderay (1.1.3)
|
12
|
+
json (2.6.2)
|
13
|
+
method_source (1.0.0)
|
14
|
+
minitest (5.16.3)
|
15
|
+
parallel (1.22.1)
|
16
|
+
parser (3.1.2.1)
|
17
|
+
ast (~> 2.4.1)
|
18
|
+
pry (0.14.1)
|
19
|
+
coderay (~> 1.1)
|
20
|
+
method_source (~> 1.0)
|
21
|
+
pry-byebug (3.10.1)
|
22
|
+
byebug (~> 11.0)
|
23
|
+
pry (>= 0.13, < 0.15)
|
24
|
+
rainbow (3.1.1)
|
25
|
+
rake (13.0.6)
|
26
|
+
regexp_parser (2.5.0)
|
27
|
+
rexml (3.2.5)
|
28
|
+
rubocop (1.35.0)
|
29
|
+
json (~> 2.3)
|
30
|
+
parallel (~> 1.10)
|
31
|
+
parser (>= 3.1.2.1)
|
32
|
+
rainbow (>= 2.2.2, < 4.0)
|
33
|
+
regexp_parser (>= 1.8, < 3.0)
|
34
|
+
rexml (>= 3.2.5, < 4.0)
|
35
|
+
rubocop-ast (>= 1.20.1, < 2.0)
|
36
|
+
ruby-progressbar (~> 1.7)
|
37
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
38
|
+
rubocop-ast (1.21.0)
|
39
|
+
parser (>= 3.1.1.0)
|
40
|
+
rubocop-minitest (0.21.0)
|
41
|
+
rubocop (>= 0.90, < 2.0)
|
42
|
+
rubocop-rake (0.6.0)
|
43
|
+
rubocop (~> 1.0)
|
44
|
+
ruby-progressbar (1.11.0)
|
45
|
+
unicode-display_width (2.2.0)
|
46
|
+
|
47
|
+
PLATFORMS
|
48
|
+
x86_64-linux
|
49
|
+
|
50
|
+
DEPENDENCIES
|
51
|
+
amex_csv_to_ledger!
|
52
|
+
minitest (~> 5.0)
|
53
|
+
pry-byebug (~> 3.10)
|
54
|
+
rake (~> 13.0)
|
55
|
+
rubocop (~> 1.21)
|
56
|
+
rubocop-minitest (~> 0.21)
|
57
|
+
rubocop-rake (~> 0.6)
|
58
|
+
|
59
|
+
BUNDLED WITH
|
60
|
+
2.3.7
|
data/README.md
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# AMEX CSV to Ledger
|
2
|
+
|
3
|
+
Configurable Ruby gem to convert American Express CSV statements to Ledger 3
|
4
|
+
format.
|
5
|
+
|
6
|
+
## Dependencies
|
7
|
+
|
8
|
+
Requires Ruby 2.6 or above.
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
It's easiest to install it as a Ruby gem:
|
13
|
+
|
14
|
+
$ gem install amex_csv_to_ledger
|
15
|
+
|
16
|
+
## Usage
|
17
|
+
|
18
|
+
Run the executable that ships with the gem and pass in the path to an AMEX CSV.
|
19
|
+
|
20
|
+
$ amex_csv_to_ledger statement.csv
|
21
|
+
|
22
|
+
The output will be the converted statement.
|
23
|
+
|
24
|
+
## Configuration
|
25
|
+
|
26
|
+
It's possible to configure various things in the output of this script, such as
|
27
|
+
the currency, what category names to use, tabs vs. spaces, etc.
|
28
|
+
|
29
|
+
There's a template that is populated with the default values in the doc folder.
|
30
|
+
Copy it to your home config directory to use it.
|
31
|
+
|
32
|
+
mkdir ~/.config/amex_csv_to_ledger
|
33
|
+
cp doc/config.yml.example ~/.config/amex_csv_to_ledger/config.yml
|
34
|
+
|
35
|
+
Then edit it to your liking, it's a normal YAML file.
|
36
|
+
|
37
|
+
## Development
|
38
|
+
|
39
|
+
After checking out the repo, run `bundle` to install dependencies. Then, run
|
40
|
+
`rake test` to run the tests.
|
41
|
+
|
42
|
+
Bear in mind when running tests that the tests will pick up the config in your
|
43
|
+
home directory. Remove it if you are getting failures.
|
44
|
+
|
45
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To
|
46
|
+
release a new version, update the version number in `version.rb`, and then run
|
47
|
+
`bundle exec rake release`, which will create a git tag for the version, push
|
48
|
+
git commits and the created tag, and push the `.gem` file to
|
49
|
+
[rubygems.org](https://rubygems.org).
|
50
|
+
|
51
|
+
## Contributing
|
52
|
+
|
53
|
+
Bug reports and pull requests are welcome. Send via email to the author, the
|
54
|
+
address is in git.
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/testtask'
|
5
|
+
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs << 'test'
|
8
|
+
t.libs << 'lib'
|
9
|
+
t.test_files = FileList['test/**/test_*.rb']
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'rubocop/rake_task'
|
13
|
+
|
14
|
+
RuboCop::RakeTask.new
|
15
|
+
|
16
|
+
task default: %i[test rubocop]
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module AmexCsvToLedger
|
6
|
+
# Class to load and parse the config file.
|
7
|
+
class Config
|
8
|
+
DEFAULT_PATH = '~/.config/amex_csv_to_ledger/config.yml'
|
9
|
+
|
10
|
+
def initialize(path = DEFAULT_PATH)
|
11
|
+
@config = YAML.load_file(File.expand_path(path))
|
12
|
+
rescue StandardError
|
13
|
+
@config = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def date_format
|
17
|
+
@config.fetch('date_format', '%Y-%m-%d')
|
18
|
+
end
|
19
|
+
|
20
|
+
def use_tabs?
|
21
|
+
@config.fetch('use_tabs', false)
|
22
|
+
end
|
23
|
+
|
24
|
+
def indent_size
|
25
|
+
@config.fetch('indent_size', 4)
|
26
|
+
end
|
27
|
+
|
28
|
+
def expense_placeholder
|
29
|
+
@config.fetch('expense_placeholder', 'expenses:placeholder')
|
30
|
+
end
|
31
|
+
|
32
|
+
def currency_prefixed?
|
33
|
+
@config.fetch('currency_prefixed', false)
|
34
|
+
end
|
35
|
+
|
36
|
+
def currency
|
37
|
+
@config.fetch('currency', 'GBP')
|
38
|
+
end
|
39
|
+
|
40
|
+
def amex_category
|
41
|
+
@config.fetch('amex_category', 'liabilities:creditcard:amex')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
module AmexCsvToLedger
|
6
|
+
# Class to format ledger date lines with a description.
|
7
|
+
class LedgerDateLine
|
8
|
+
AMEX_DATE_FORMAT = '%Y/%m/%d'
|
9
|
+
|
10
|
+
attr_reader :description
|
11
|
+
|
12
|
+
def initialize(date:, description:)
|
13
|
+
@date = date
|
14
|
+
@description = description
|
15
|
+
end
|
16
|
+
|
17
|
+
def output
|
18
|
+
"#{date} #{description}"
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def date
|
24
|
+
parsed_date.strftime(date_format)
|
25
|
+
end
|
26
|
+
|
27
|
+
def parsed_date
|
28
|
+
Date.parse(@date, AMEX_DATE_FORMAT)
|
29
|
+
end
|
30
|
+
|
31
|
+
def date_format
|
32
|
+
AmexCsvToLedger.config.date_format
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AmexCsvToLedger
|
4
|
+
# Class to format ledger expense lines with a currency amount.
|
5
|
+
class LedgerExpenseLine
|
6
|
+
DEFAULT_SPACING = 62 # spacing used by LedgerAlignBuffer
|
7
|
+
TAB_LENGTH = 8
|
8
|
+
|
9
|
+
attr_reader :amount
|
10
|
+
|
11
|
+
def initialize(amount:)
|
12
|
+
@amount = amount
|
13
|
+
end
|
14
|
+
|
15
|
+
def output
|
16
|
+
"#{indent}#{placeholder}#{spaces}#{formatted_amount}"
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def indent
|
22
|
+
if use_tabs?
|
23
|
+
"\t"
|
24
|
+
else
|
25
|
+
' ' * indent_size
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def placeholder
|
30
|
+
AmexCsvToLedger.config.expense_placeholder
|
31
|
+
end
|
32
|
+
|
33
|
+
def spaces
|
34
|
+
' ' * spacing
|
35
|
+
end
|
36
|
+
|
37
|
+
def spacing
|
38
|
+
len = DEFAULT_SPACING - indent_size - placeholder.length - amount.length
|
39
|
+
|
40
|
+
if currency_prefixed?
|
41
|
+
len - currency.length
|
42
|
+
else
|
43
|
+
len
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def currency
|
48
|
+
AmexCsvToLedger.config.currency
|
49
|
+
end
|
50
|
+
|
51
|
+
def use_tabs?
|
52
|
+
AmexCsvToLedger.config.use_tabs?
|
53
|
+
end
|
54
|
+
|
55
|
+
def indent_size
|
56
|
+
if use_tabs?
|
57
|
+
TAB_LENGTH
|
58
|
+
else
|
59
|
+
AmexCsvToLedger.config.indent_size
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def currency_prefixed?
|
64
|
+
AmexCsvToLedger.config.currency_prefixed?
|
65
|
+
end
|
66
|
+
|
67
|
+
def formatted_amount
|
68
|
+
if currency_prefixed?
|
69
|
+
"#{currency}#{amount}"
|
70
|
+
else
|
71
|
+
"#{amount} #{currency}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AmexCsvToLedger
|
4
|
+
# Class to format ledger outgoing lines.
|
5
|
+
class LedgerOutgoingLine
|
6
|
+
TAB_LENGTH = 8
|
7
|
+
|
8
|
+
def output
|
9
|
+
"#{indent}#{outgoing_account}"
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def indent
|
15
|
+
if use_tabs?
|
16
|
+
"\t"
|
17
|
+
else
|
18
|
+
' ' * indent_size
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def outgoing_account
|
23
|
+
AmexCsvToLedger.config.amex_category
|
24
|
+
end
|
25
|
+
|
26
|
+
def use_tabs?
|
27
|
+
AmexCsvToLedger.config.use_tabs?
|
28
|
+
end
|
29
|
+
|
30
|
+
def indent_size
|
31
|
+
AmexCsvToLedger.config.indent_size
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AmexCsvToLedger
|
4
|
+
# A class to glue together all the ledger lines to create a full report.
|
5
|
+
class LedgerReport
|
6
|
+
attr_reader :statement
|
7
|
+
|
8
|
+
def initialize(statement)
|
9
|
+
@statement = statement
|
10
|
+
end
|
11
|
+
|
12
|
+
def lines
|
13
|
+
statement.lines.map do |line|
|
14
|
+
[
|
15
|
+
date_line(line),
|
16
|
+
expense_line(line),
|
17
|
+
outgoing_line
|
18
|
+
].join("\n")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def date_line(line)
|
25
|
+
LedgerDateLine.new(
|
26
|
+
date: line.date,
|
27
|
+
description: line.description
|
28
|
+
).output
|
29
|
+
end
|
30
|
+
|
31
|
+
def expense_line(line)
|
32
|
+
LedgerExpenseLine.new(amount: line.amount).output
|
33
|
+
end
|
34
|
+
|
35
|
+
def outgoing_line
|
36
|
+
LedgerOutgoingLine.new.output
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'csv'
|
4
|
+
|
5
|
+
module AmexCsvToLedger
|
6
|
+
# Class to hold the data found in an AMEX statement.
|
7
|
+
class Statement
|
8
|
+
attr_reader :csv
|
9
|
+
|
10
|
+
def initialize(csv)
|
11
|
+
@csv = csv
|
12
|
+
end
|
13
|
+
|
14
|
+
def lines
|
15
|
+
@lines ||= CSV.parse(csv, headers: true).map do |row|
|
16
|
+
StatementLine.new(
|
17
|
+
amount: row['Amount'],
|
18
|
+
date: row['Date'],
|
19
|
+
description: row['Description']
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AmexCsvToLedger
|
4
|
+
# Class to hold the data found in a line of an AMEX statement.
|
5
|
+
class StatementLine
|
6
|
+
attr_reader :amount, :date, :description
|
7
|
+
|
8
|
+
def initialize(amount:, date:, description:)
|
9
|
+
@amount = amount
|
10
|
+
@date = date
|
11
|
+
@description = description
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'amex_csv_to_ledger/version'
|
4
|
+
require_relative 'amex_csv_to_ledger/config'
|
5
|
+
require_relative 'amex_csv_to_ledger/ledger_date_line'
|
6
|
+
require_relative 'amex_csv_to_ledger/ledger_expense_line'
|
7
|
+
require_relative 'amex_csv_to_ledger/ledger_outgoing_line'
|
8
|
+
require_relative 'amex_csv_to_ledger/ledger_report'
|
9
|
+
require_relative 'amex_csv_to_ledger/statement'
|
10
|
+
require_relative 'amex_csv_to_ledger/statement_line'
|
11
|
+
|
12
|
+
# Top level class for the converter which glues together all of the code.
|
13
|
+
module AmexCsvToLedger
|
14
|
+
def self.convert(csv_path)
|
15
|
+
csv = File.open(csv_path)
|
16
|
+
statement = Statement.new(csv)
|
17
|
+
puts LedgerReport.new(statement).lines.join("\n\n")
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.config
|
21
|
+
Config.new
|
22
|
+
end
|
23
|
+
end
|
data/tmp/.gitkeep
ADDED
File without changes
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: amex_csv_to_ledger
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- baak6
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-08-22 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Command line utility to convert AMEX CSV to Ledger.
|
14
|
+
email:
|
15
|
+
- baak6@baak6.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ".rubocop.yml"
|
21
|
+
- Gemfile
|
22
|
+
- Gemfile.lock
|
23
|
+
- README.md
|
24
|
+
- Rakefile
|
25
|
+
- doc/config.yml.example
|
26
|
+
- lib/amex_csv_to_ledger.rb
|
27
|
+
- lib/amex_csv_to_ledger/config.rb
|
28
|
+
- lib/amex_csv_to_ledger/ledger_date_line.rb
|
29
|
+
- lib/amex_csv_to_ledger/ledger_expense_line.rb
|
30
|
+
- lib/amex_csv_to_ledger/ledger_outgoing_line.rb
|
31
|
+
- lib/amex_csv_to_ledger/ledger_report.rb
|
32
|
+
- lib/amex_csv_to_ledger/statement.rb
|
33
|
+
- lib/amex_csv_to_ledger/statement_line.rb
|
34
|
+
- lib/amex_csv_to_ledger/version.rb
|
35
|
+
- tmp/.gitkeep
|
36
|
+
homepage: https://git.baak6.com/amex_csv_to_ledger.git/
|
37
|
+
licenses:
|
38
|
+
- GPL-3.0
|
39
|
+
metadata:
|
40
|
+
source_code_uri: https://git.baak6.com/amex_csv_to_ledger.git/
|
41
|
+
rubygems_mfa_required: 'true'
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: 2.6.0
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
requirements: []
|
57
|
+
rubygems_version: 3.3.7
|
58
|
+
signing_key:
|
59
|
+
specification_version: 4
|
60
|
+
summary: AMEX CSV to Ledger.
|
61
|
+
test_files: []
|