amex_csv_to_ledger 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|