td_statement_extractor 0.1.1 → 0.1.4
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/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/Gemfile.lock +70 -47
- data/README.md +43 -1
- data/exe/td_statement_extractor +112 -0
- data/lib/td_statement_extractor/statement.rb +18 -5
- data/lib/td_statement_extractor/version.rb +3 -1
- data/lib/td_statement_extractor.rb +6 -0
- data/td_statement_extractor.gemspec +13 -7
- metadata +56 -27
- data/bin/td_statement_extractor +0 -23
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7701d9cdc02962a99d9167b766c29ea6decd99c0a9746fb0b4523f4d3a46697d
|
|
4
|
+
data.tar.gz: ff8436a9506435b0f29a0302843092a09d00faa862c5b78a27f656534dfd71c1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3a682e37d868b6dd45251f1b897d8cedf3b87fc1138021cf5ecfec981c71607866681f2bf8c7f4f02f807fb8c653717b082e3af42ea3a283caf6e029ea0880c8
|
|
7
|
+
data.tar.gz: eb1fd4bd60d84c6979d4c2026e528653468163d62d7f851f6507d07c6fd2666e03e20e8e03043f7999672b4baaa09bfb6d2c81d80e54a54e424ca163fb493674
|
data/.gitignore
CHANGED
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.1
|
|
1
|
+
3.4.1
|
data/Gemfile.lock
CHANGED
|
@@ -1,84 +1,107 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
td_statement_extractor (0.1.
|
|
5
|
-
|
|
4
|
+
td_statement_extractor (0.1.4)
|
|
5
|
+
csv (~> 3.3.5)
|
|
6
|
+
pdf-reader (~> 2.14.1)
|
|
6
7
|
|
|
7
8
|
GEM
|
|
8
9
|
remote: https://rubygems.org/
|
|
9
10
|
specs:
|
|
10
|
-
Ascii85 (
|
|
11
|
+
Ascii85 (2.0.1)
|
|
11
12
|
afm (0.2.2)
|
|
12
|
-
ast (2.4.
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
ast (2.4.3)
|
|
14
|
+
base64 (0.3.0)
|
|
15
|
+
bigdecimal (3.2.2)
|
|
16
|
+
csv (3.3.5)
|
|
17
|
+
diff-lcs (1.6.2)
|
|
18
|
+
docile (1.4.1)
|
|
15
19
|
hashery (2.1.2)
|
|
16
|
-
json (2.
|
|
17
|
-
language_server-protocol (3.17.0.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
json (2.12.2)
|
|
21
|
+
language_server-protocol (3.17.0.5)
|
|
22
|
+
lint_roller (1.1.0)
|
|
23
|
+
parallel (1.27.0)
|
|
24
|
+
parser (3.3.8.0)
|
|
20
25
|
ast (~> 2.4.1)
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
racc
|
|
27
|
+
pdf-reader (2.14.1)
|
|
28
|
+
Ascii85 (>= 1.0, < 3.0, != 2.0.0)
|
|
23
29
|
afm (~> 0.2.1)
|
|
24
30
|
hashery (~> 2.0)
|
|
25
31
|
ruby-rc4
|
|
26
32
|
ttfunk
|
|
33
|
+
prism (1.4.0)
|
|
34
|
+
racc (1.8.1)
|
|
27
35
|
rainbow (3.1.1)
|
|
28
|
-
rake (13.0
|
|
29
|
-
regexp_parser (2.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
rspec-
|
|
33
|
-
rspec-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
rspec-expectations (3.12.2)
|
|
36
|
+
rake (13.3.0)
|
|
37
|
+
regexp_parser (2.10.0)
|
|
38
|
+
rspec (3.13.1)
|
|
39
|
+
rspec-core (~> 3.13.0)
|
|
40
|
+
rspec-expectations (~> 3.13.0)
|
|
41
|
+
rspec-mocks (~> 3.13.0)
|
|
42
|
+
rspec-core (3.13.4)
|
|
43
|
+
rspec-support (~> 3.13.0)
|
|
44
|
+
rspec-expectations (3.13.5)
|
|
38
45
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
39
|
-
rspec-support (~> 3.
|
|
40
|
-
rspec-mocks (3.
|
|
46
|
+
rspec-support (~> 3.13.0)
|
|
47
|
+
rspec-mocks (3.13.5)
|
|
41
48
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
42
|
-
rspec-support (~> 3.
|
|
43
|
-
rspec-support (3.
|
|
44
|
-
rubocop (1.
|
|
49
|
+
rspec-support (~> 3.13.0)
|
|
50
|
+
rspec-support (3.13.4)
|
|
51
|
+
rubocop (1.75.8)
|
|
45
52
|
json (~> 2.3)
|
|
53
|
+
language_server-protocol (~> 3.17.0.2)
|
|
54
|
+
lint_roller (~> 1.1.0)
|
|
46
55
|
parallel (~> 1.10)
|
|
47
|
-
parser (>= 3.
|
|
56
|
+
parser (>= 3.3.0.2)
|
|
48
57
|
rainbow (>= 2.2.2, < 4.0)
|
|
49
|
-
regexp_parser (>=
|
|
50
|
-
|
|
51
|
-
rubocop-ast (>= 1.24.1, < 2.0)
|
|
58
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
59
|
+
rubocop-ast (>= 1.44.0, < 2.0)
|
|
52
60
|
ruby-progressbar (~> 1.7)
|
|
53
|
-
unicode-display_width (>=
|
|
54
|
-
rubocop-ast (1.
|
|
55
|
-
parser (>= 3.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
62
|
+
rubocop-ast (1.45.1)
|
|
63
|
+
parser (>= 3.3.7.2)
|
|
64
|
+
prism (~> 1.4)
|
|
65
|
+
rubocop-performance (1.25.0)
|
|
66
|
+
lint_roller (~> 1.1)
|
|
67
|
+
rubocop (>= 1.75.0, < 2.0)
|
|
68
|
+
rubocop-ast (>= 1.38.0, < 2.0)
|
|
69
|
+
ruby-progressbar (1.13.0)
|
|
60
70
|
ruby-rc4 (0.1.5)
|
|
61
71
|
simplecov (0.17.1)
|
|
62
72
|
docile (~> 1.1)
|
|
63
73
|
json (>= 1.8, < 3)
|
|
64
74
|
simplecov-html (~> 0.10.0)
|
|
65
75
|
simplecov-html (0.10.2)
|
|
66
|
-
standard (1.
|
|
76
|
+
standard (1.50.0)
|
|
67
77
|
language_server-protocol (~> 3.17.0.2)
|
|
68
|
-
|
|
69
|
-
rubocop
|
|
70
|
-
|
|
71
|
-
|
|
78
|
+
lint_roller (~> 1.0)
|
|
79
|
+
rubocop (~> 1.75.5)
|
|
80
|
+
standard-custom (~> 1.0.0)
|
|
81
|
+
standard-performance (~> 1.8)
|
|
82
|
+
standard-custom (1.0.2)
|
|
83
|
+
lint_roller (~> 1.0)
|
|
84
|
+
rubocop (~> 1.50)
|
|
85
|
+
standard-performance (1.8.0)
|
|
86
|
+
lint_roller (~> 1.1)
|
|
87
|
+
rubocop-performance (~> 1.25.0)
|
|
88
|
+
ttfunk (1.8.0)
|
|
89
|
+
bigdecimal (~> 3.1)
|
|
90
|
+
unicode-display_width (3.1.4)
|
|
91
|
+
unicode-emoji (~> 4.0, >= 4.0.4)
|
|
92
|
+
unicode-emoji (4.0.4)
|
|
72
93
|
|
|
73
94
|
PLATFORMS
|
|
74
95
|
arm64-darwin-21
|
|
96
|
+
arm64-darwin-24
|
|
75
97
|
|
|
76
98
|
DEPENDENCIES
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
99
|
+
base64 (~> 0.3.0)
|
|
100
|
+
bundler (~> 2.4.5)
|
|
101
|
+
rake (~> 13.3.0)
|
|
102
|
+
rspec (~> 3.13.1)
|
|
80
103
|
simplecov (~> 0.17.1)
|
|
81
|
-
standard
|
|
104
|
+
standard (~> 1.50.0)
|
|
82
105
|
td_statement_extractor!
|
|
83
106
|
|
|
84
107
|
BUNDLED WITH
|
data/README.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
[](https://github.com/aarongough/td_statement_extractor/actions/workflows/ruby.yml)
|
|
3
3
|
[](https://codeclimate.com/github/aarongough/td_statement_extractor/maintainability)
|
|
4
4
|
[](https://codeclimate.com/github/aarongough/td_statement_extractor/test_coverage)
|
|
5
|
+
[](https://badge.fury.io/rb/td_statement_extractor)
|
|
5
6
|
|
|
6
7
|
# TD Statement Extractor
|
|
7
8
|
|
|
@@ -14,8 +15,49 @@ Install from the command line:
|
|
|
14
15
|
$ gem install td_statement_extractor
|
|
15
16
|
|
|
16
17
|
## Usage
|
|
18
|
+
You can process a single file from the command line like so:
|
|
17
19
|
|
|
18
|
-
td_statement_extractor INPUT_FILE OUTPUT_FILE
|
|
20
|
+
td_statement_extractor ~/path_to/INPUT_FILE ~/path_to/OUTPUT_FILE.csv
|
|
21
|
+
|
|
22
|
+
Or you can process a number of files and produce a single CSV output. This is great for processing an entire year's worth of statements and outputting a CSV ready for import into your accounting software come tax time. It is recommended that you only process statements for a single account at a time:
|
|
23
|
+
|
|
24
|
+
# Process multiple files using a wildcard operator in the input path
|
|
25
|
+
td_statement_extractor ~/path_to_statements/* ~/path_to/OUTPUT_FILE.csv
|
|
26
|
+
|
|
27
|
+
# Process multiple files by listing each file manually
|
|
28
|
+
td_statement_extractor INPUT_FILE_1 INPUT_FILE_2 [etc...] ~/path_to/OUTPUT_FILE.csv
|
|
29
|
+
|
|
30
|
+
After processing each file the system will generate a summary of the output, including a `Total activity` amount that should match up with the `Total activity` from the PDF statement. This is a great way to sanity check the output of the script and make sure it's accurate:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
Decrypting and pre-processing file... This may take a minute.
|
|
34
|
+
Decryption and pre-processing completed.
|
|
35
|
+
|
|
36
|
+
Processed file: /Users/SomeGuy/Downloads/TD_EMERALD_FLEX_RATE_VISA__CARD_XXXX.pdf
|
|
37
|
+
Details:
|
|
38
|
+
Transactions: 15
|
|
39
|
+
Total activity: $908.41
|
|
40
|
+
|
|
41
|
+
Transactions:
|
|
42
|
+
Date | Description | Amount
|
|
43
|
+
-----------|---------------------------------------|----------
|
|
44
|
+
2024-07-15 | PAYMENT - THANK YOU | $286.66
|
|
45
|
+
2024-07-18 | GITHUB, INC. HTTPSGITHUB. | -$5.62
|
|
46
|
+
2024-07-27 | SPOTIFY STOCKHOLM | -$12.42
|
|
47
|
+
2024-08-01 | UBER* TRIP HTTPSWWW.UBE | -$14.34
|
|
48
|
+
2024-08-01 | UBER CANADA/UBERTRIP | -$18.56
|
|
49
|
+
2024-08-01 | UBER* TRIP HTTPSWWW.UBE | -$7.83
|
|
50
|
+
2024-08-01 | PAYMENT - THANK YOU | $831.0
|
|
51
|
+
2024-08-02 | Amazon.ca Prime Member amazon.ca/pr | -$11.29
|
|
52
|
+
2024-08-01 | WAL-MART ONLINE PHOTO | -$75.05
|
|
53
|
+
2024-08-02 | UBER CANADA/UBERTRIP | -$3.0
|
|
54
|
+
2024-08-02 | UBER CANADA/UBERTRIP | -$10.67
|
|
55
|
+
2024-08-02 | UBER CANADA/UBERTRIP | -$18.67
|
|
56
|
+
2024-08-06 | PREAUTHORIZED PAYMENT | $10.0
|
|
57
|
+
2024-08-09 | INTUIT *QBooks Online | -$27.12
|
|
58
|
+
2024-08-13 | GOOGLE *YouTubePremium g.co/helppay | -$14.68
|
|
59
|
+
-----------|---------------------------------------|----------
|
|
60
|
+
```
|
|
19
61
|
|
|
20
62
|
## Development
|
|
21
63
|
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
4
|
+
require "td_statement_extractor"
|
|
5
|
+
|
|
6
|
+
LOGO = <<~LOGO
|
|
7
|
+
|
|
8
|
+
_________ __ __ __
|
|
9
|
+
/ _____// |______ _/ |_ ____ _____ ____ _____/ |_
|
|
10
|
+
\\_____ \\\\ __\\__ \\\\ __\\/ __ \\ / \\_/ __ \\ / \\ __\\
|
|
11
|
+
/ \\| | / __ \\| | \\ ___/| Y Y \\ ___/| | \\ |
|
|
12
|
+
/_______ /|__| (____ /__| \\___ >__|_| /\\___ >___| /__|
|
|
13
|
+
\\/ \\/ \\/ \\/ \\/ \\/
|
|
14
|
+
___________ __ __
|
|
15
|
+
\\_ _____/__ ____/ |_____________ _____/ |_ ___________
|
|
16
|
+
| __)_\\ \\/ /\\ __\\_ __ \\__ \\ _/ ___\\ __\\/ _ \\_ __ \\
|
|
17
|
+
| \\> < | | | | \\// __ \\\\ \\___| | ( <_> ) | \\/
|
|
18
|
+
/_______ /__/\\_ \\ |__| |__| (____ /\\___ >__| \\____/|__|
|
|
19
|
+
\\/ \\/ \\/ \\/
|
|
20
|
+
|
|
21
|
+
Copyright (c) 2025 - by Aaron Gough
|
|
22
|
+
|
|
23
|
+
LOGO
|
|
24
|
+
|
|
25
|
+
HELP_TEXT = <<~HELP_TEXT
|
|
26
|
+
|
|
27
|
+
Usage: td_statement_extractor [input_file_path] [output_file_path]
|
|
28
|
+
|
|
29
|
+
Extracts transactions from a TD Bank statement PDF and outputs them to a CSV file.
|
|
30
|
+
|
|
31
|
+
Arguments:
|
|
32
|
+
input_file_path The path to the TD Bank statement PDF file.
|
|
33
|
+
output_file_path The path to the output CSV file.
|
|
34
|
+
|
|
35
|
+
Example:
|
|
36
|
+
td_statement_extractor ~/Downloads/td_statement.pdf ~/Desktop/transactions.csv
|
|
37
|
+
|
|
38
|
+
HELP_TEXT
|
|
39
|
+
|
|
40
|
+
def process_file(input_file_path)
|
|
41
|
+
raise "Input file does not exist" unless File.exist?(input_file_path)
|
|
42
|
+
|
|
43
|
+
if File.extname(input_file_path) != ".pdf"
|
|
44
|
+
puts "Input file must be a PDF file, skipping: #{input_file_path}"
|
|
45
|
+
return
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
puts "Processing file: #{input_file_path}"
|
|
49
|
+
|
|
50
|
+
statement = TdStatementExtractor::Statement.new(input_file_path)
|
|
51
|
+
|
|
52
|
+
puts
|
|
53
|
+
puts "Processed file: #{input_file_path}"
|
|
54
|
+
puts "Details:"
|
|
55
|
+
puts " Transactions: #{statement.transactions.count}"
|
|
56
|
+
puts " Total activity: #{("$" + statement.total_activity.to_s).gsub("$-", "-$")}"
|
|
57
|
+
puts " Sub total (purchases only): #{("$" + statement.sub_total.to_s).gsub("$-", "-$")}"
|
|
58
|
+
puts " Payments and credits: #{("$" + statement.payments_and_credits.to_s).gsub("$-", "-$")}"
|
|
59
|
+
puts
|
|
60
|
+
|
|
61
|
+
puts "Transactions:"
|
|
62
|
+
puts " Date | Description | Amount "
|
|
63
|
+
puts " -----------|---------------------------------------|----------"
|
|
64
|
+
statement.transactions.each do |transaction|
|
|
65
|
+
puts " #{transaction[:date].to_s[0, 10].ljust(10)} | #{transaction[:description].to_s[0, 37].ljust(37)} | #{("$" + transaction[:amount].to_s).gsub("$-", "-$")}"
|
|
66
|
+
end
|
|
67
|
+
puts " -----------|---------------------------------------|----------"
|
|
68
|
+
puts
|
|
69
|
+
|
|
70
|
+
statement
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def display_logo
|
|
74
|
+
puts LOGO
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def display_help_text(error_message = "")
|
|
78
|
+
puts "ERROR: #{error_message}" unless error_message.empty?
|
|
79
|
+
puts HELP_TEXT
|
|
80
|
+
exit
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def main
|
|
84
|
+
display_help_text if ARGV.include?("-h") || ARGV.include?("--help")
|
|
85
|
+
display_help_text("Wrong number of arguments") if ARGV.length < 2
|
|
86
|
+
|
|
87
|
+
display_logo
|
|
88
|
+
|
|
89
|
+
input_file_paths = ARGV[0..-2] # every argument except the last one
|
|
90
|
+
output_file_path = ARGV[-1] # only the last element
|
|
91
|
+
|
|
92
|
+
puts "Processing #{input_file_paths.count} files..."
|
|
93
|
+
statements = []
|
|
94
|
+
input_file_paths.each do |input_file_path|
|
|
95
|
+
statements << process_file(input_file_path)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
statements.compact!
|
|
99
|
+
|
|
100
|
+
puts "Writing data to output file: #{output_file_path}"
|
|
101
|
+
transactions = statements.map(&:transactions).flatten.compact
|
|
102
|
+
transactions.sort_by! { |transaction| transaction[:date] }
|
|
103
|
+
transactions.reverse!
|
|
104
|
+
transactions.uniq!
|
|
105
|
+
|
|
106
|
+
statement = statements.first
|
|
107
|
+
statement.transactions = transactions
|
|
108
|
+
|
|
109
|
+
statement.output_csv(output_file_path)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
main
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
require "date"
|
|
3
|
-
require "csv"
|
|
1
|
+
# frozen_string_literal: true
|
|
4
2
|
|
|
5
3
|
module TdStatementExtractor
|
|
6
4
|
class Statement
|
|
@@ -41,7 +39,9 @@ module TdStatementExtractor
|
|
|
41
39
|
# Use Ghostscript to decrypt and decompress the PDF. Also remove
|
|
42
40
|
# all images and crop the margins to remove watermarking that interferes
|
|
43
41
|
# with the scraping process
|
|
44
|
-
|
|
42
|
+
puts "Decrypting and pre-processing file... This may take a minute." unless defined?(RSpec)
|
|
43
|
+
`gs -o "#{@temp_file_path}" -sDEVICE=pdfwrite -dFILTERVECTOR -dFILTERIMAGE -g5400x7200 -c "<</PageOffset [-36 -36]>> setpagedevice" -f "#{@input_file_path}" 2>&1`
|
|
44
|
+
puts "Decryption and pre-processing completed." unless defined?(RSpec)
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
def import_pdf
|
|
@@ -60,7 +60,7 @@ module TdStatementExtractor
|
|
|
60
60
|
|
|
61
61
|
def transaction_from_line(line)
|
|
62
62
|
date = line.match(DATE)&.[](:date)
|
|
63
|
-
amount = -(line.match(AMOUNT)&.[](:amount)&.
|
|
63
|
+
amount = -(line.match(AMOUNT)&.[](:amount)&.delete("$")&.delete(",")&.to_f || 0)
|
|
64
64
|
description = line.match(DESCRIPTION)&.[](:description)&.strip
|
|
65
65
|
|
|
66
66
|
raise MissingDateError, "Error extracting DATE from line: #{line}" if date.nil? || date.empty?
|
|
@@ -94,6 +94,19 @@ module TdStatementExtractor
|
|
|
94
94
|
-transactions.reduce(0) { |total, x| total + x[:amount] }.round(2)
|
|
95
95
|
end
|
|
96
96
|
|
|
97
|
+
# Newer TD statements no longer show `total activity` as a line item,
|
|
98
|
+
# so we want a `sub total` value as well. This value does not include
|
|
99
|
+
# payments, credits, or refunds, and is the sum of all debits (i.e. purchases)
|
|
100
|
+
def sub_total
|
|
101
|
+
-transactions.select { |t| t[:amount] < 0 }.reduce(0) { |total, x| total + x[:amount] }.round(2)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Signed contribution of payments and credits, such that
|
|
105
|
+
# sub_total + payments_and_credits == total_activity.
|
|
106
|
+
def payments_and_credits
|
|
107
|
+
-transactions.select { |t| t[:amount] > 0 }.reduce(0) { |total, x| total + x[:amount] }.round(2)
|
|
108
|
+
end
|
|
109
|
+
|
|
97
110
|
def output_csv(output_path)
|
|
98
111
|
CSV.open(output_path, "a") do |csv|
|
|
99
112
|
transactions.each do |transaction|
|
|
@@ -9,7 +9,11 @@ Gem::Specification.new do |spec|
|
|
|
9
9
|
spec.email = ["aaron.gough@gmail.com"]
|
|
10
10
|
|
|
11
11
|
spec.summary = "Extract machine readable transaction data from TD credit card statements."
|
|
12
|
-
spec.description =
|
|
12
|
+
spec.description = <<~EOM
|
|
13
|
+
Extract machine readable transaction data from TD credit card statements.
|
|
14
|
+
This gem parses PDF statements from TD Canada Trust and extracts transaction data into a structured format.
|
|
15
|
+
It is designed to work with the PDF format used by TD Canada Trust for their credit card statements.
|
|
16
|
+
EOM
|
|
13
17
|
spec.homepage = "https://github.com/aarongough/td_statement_extractor"
|
|
14
18
|
spec.license = "MIT"
|
|
15
19
|
|
|
@@ -21,15 +25,17 @@ Gem::Specification.new do |spec|
|
|
|
21
25
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
22
26
|
end
|
|
23
27
|
|
|
24
|
-
spec.bindir = "
|
|
28
|
+
spec.bindir = "exe"
|
|
25
29
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
26
30
|
spec.require_paths = ["lib"]
|
|
27
31
|
|
|
28
|
-
spec.add_dependency "pdf-reader", "~> 2.
|
|
32
|
+
spec.add_dependency "pdf-reader", "~> 2.14.1"
|
|
33
|
+
spec.add_dependency "csv", "~> 3.3.5"
|
|
29
34
|
|
|
30
|
-
spec.add_development_dependency "standard"
|
|
31
|
-
spec.add_development_dependency "
|
|
32
|
-
spec.add_development_dependency "
|
|
33
|
-
spec.add_development_dependency "
|
|
35
|
+
spec.add_development_dependency "standard", "~> 1.50.0"
|
|
36
|
+
spec.add_development_dependency "base64", "~> 0.3.0"
|
|
37
|
+
spec.add_development_dependency "bundler", "~> 2.4.5"
|
|
38
|
+
spec.add_development_dependency "rake", "~> 13.3.0"
|
|
39
|
+
spec.add_development_dependency "rspec", "~> 3.13.1"
|
|
34
40
|
spec.add_development_dependency "simplecov", "~> 0.17.1"
|
|
35
41
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: td_statement_extractor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Aaron Gough
|
|
8
|
-
|
|
9
|
-
bindir: bin
|
|
8
|
+
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 2026-05-24 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: pdf-reader
|
|
@@ -16,70 +15,98 @@ dependencies:
|
|
|
16
15
|
requirements:
|
|
17
16
|
- - "~>"
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: 2.
|
|
18
|
+
version: 2.14.1
|
|
20
19
|
type: :runtime
|
|
21
20
|
prerelease: false
|
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
22
|
requirements:
|
|
24
23
|
- - "~>"
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: 2.
|
|
25
|
+
version: 2.14.1
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: csv
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 3.3.5
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: 3.3.5
|
|
27
40
|
- !ruby/object:Gem::Dependency
|
|
28
41
|
name: standard
|
|
29
42
|
requirement: !ruby/object:Gem::Requirement
|
|
30
43
|
requirements:
|
|
31
|
-
- - "
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: 1.50.0
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: 1.50.0
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: base64
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
32
59
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
60
|
+
version: 0.3.0
|
|
34
61
|
type: :development
|
|
35
62
|
prerelease: false
|
|
36
63
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
64
|
requirements:
|
|
38
|
-
- - "
|
|
65
|
+
- - "~>"
|
|
39
66
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
67
|
+
version: 0.3.0
|
|
41
68
|
- !ruby/object:Gem::Dependency
|
|
42
69
|
name: bundler
|
|
43
70
|
requirement: !ruby/object:Gem::Requirement
|
|
44
71
|
requirements:
|
|
45
|
-
- - "
|
|
72
|
+
- - "~>"
|
|
46
73
|
- !ruby/object:Gem::Version
|
|
47
|
-
version:
|
|
74
|
+
version: 2.4.5
|
|
48
75
|
type: :development
|
|
49
76
|
prerelease: false
|
|
50
77
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
78
|
requirements:
|
|
52
|
-
- - "
|
|
79
|
+
- - "~>"
|
|
53
80
|
- !ruby/object:Gem::Version
|
|
54
|
-
version:
|
|
81
|
+
version: 2.4.5
|
|
55
82
|
- !ruby/object:Gem::Dependency
|
|
56
83
|
name: rake
|
|
57
84
|
requirement: !ruby/object:Gem::Requirement
|
|
58
85
|
requirements:
|
|
59
|
-
- - "
|
|
86
|
+
- - "~>"
|
|
60
87
|
- !ruby/object:Gem::Version
|
|
61
|
-
version:
|
|
88
|
+
version: 13.3.0
|
|
62
89
|
type: :development
|
|
63
90
|
prerelease: false
|
|
64
91
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
92
|
requirements:
|
|
66
|
-
- - "
|
|
93
|
+
- - "~>"
|
|
67
94
|
- !ruby/object:Gem::Version
|
|
68
|
-
version:
|
|
95
|
+
version: 13.3.0
|
|
69
96
|
- !ruby/object:Gem::Dependency
|
|
70
97
|
name: rspec
|
|
71
98
|
requirement: !ruby/object:Gem::Requirement
|
|
72
99
|
requirements:
|
|
73
100
|
- - "~>"
|
|
74
101
|
- !ruby/object:Gem::Version
|
|
75
|
-
version:
|
|
102
|
+
version: 3.13.1
|
|
76
103
|
type: :development
|
|
77
104
|
prerelease: false
|
|
78
105
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
106
|
requirements:
|
|
80
107
|
- - "~>"
|
|
81
108
|
- !ruby/object:Gem::Version
|
|
82
|
-
version:
|
|
109
|
+
version: 3.13.1
|
|
83
110
|
- !ruby/object:Gem::Dependency
|
|
84
111
|
name: simplecov
|
|
85
112
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -94,10 +121,14 @@ dependencies:
|
|
|
94
121
|
- - "~>"
|
|
95
122
|
- !ruby/object:Gem::Version
|
|
96
123
|
version: 0.17.1
|
|
97
|
-
description:
|
|
124
|
+
description: |
|
|
125
|
+
Extract machine readable transaction data from TD credit card statements.
|
|
126
|
+
This gem parses PDF statements from TD Canada Trust and extracts transaction data into a structured format.
|
|
127
|
+
It is designed to work with the PDF format used by TD Canada Trust for their credit card statements.
|
|
98
128
|
email:
|
|
99
129
|
- aaron.gough@gmail.com
|
|
100
|
-
executables:
|
|
130
|
+
executables:
|
|
131
|
+
- td_statement_extractor
|
|
101
132
|
extensions: []
|
|
102
133
|
extra_rdoc_files: []
|
|
103
134
|
files:
|
|
@@ -112,7 +143,7 @@ files:
|
|
|
112
143
|
- Rakefile
|
|
113
144
|
- bin/console
|
|
114
145
|
- bin/setup
|
|
115
|
-
-
|
|
146
|
+
- exe/td_statement_extractor
|
|
116
147
|
- lib/td_statement_extractor.rb
|
|
117
148
|
- lib/td_statement_extractor/statement.rb
|
|
118
149
|
- lib/td_statement_extractor/version.rb
|
|
@@ -121,7 +152,6 @@ homepage: https://github.com/aarongough/td_statement_extractor
|
|
|
121
152
|
licenses:
|
|
122
153
|
- MIT
|
|
123
154
|
metadata: {}
|
|
124
|
-
post_install_message:
|
|
125
155
|
rdoc_options: []
|
|
126
156
|
require_paths:
|
|
127
157
|
- lib
|
|
@@ -129,15 +159,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
129
159
|
requirements:
|
|
130
160
|
- - ">="
|
|
131
161
|
- !ruby/object:Gem::Version
|
|
132
|
-
version:
|
|
162
|
+
version: 3.4.1
|
|
133
163
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
134
164
|
requirements:
|
|
135
165
|
- - ">="
|
|
136
166
|
- !ruby/object:Gem::Version
|
|
137
167
|
version: '0'
|
|
138
168
|
requirements: []
|
|
139
|
-
rubygems_version: 3.
|
|
140
|
-
signing_key:
|
|
169
|
+
rubygems_version: 3.6.2
|
|
141
170
|
specification_version: 4
|
|
142
171
|
summary: Extract machine readable transaction data from TD credit card statements.
|
|
143
172
|
test_files: []
|
data/bin/td_statement_extractor
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
require "rubygems"
|
|
3
|
-
require "bundler/setup"
|
|
4
|
-
require "td_statement_extractor"
|
|
5
|
-
|
|
6
|
-
raise "Input file path cannot be blank" if ARGV[0].nil?
|
|
7
|
-
raise "Output file path cannot be blank" if ARGV[1].nil?
|
|
8
|
-
|
|
9
|
-
input_file_path = File.expand_path(ARGV[0])
|
|
10
|
-
output_file_path = File.expand_path(ARGV[1])
|
|
11
|
-
|
|
12
|
-
raise "Input file does not exist" unless File.exist?(input_file_path)
|
|
13
|
-
|
|
14
|
-
statement = TdStatementExtractor::Statement.new(input_file_path)
|
|
15
|
-
statement.output_csv(output_file_path)
|
|
16
|
-
|
|
17
|
-
puts
|
|
18
|
-
puts "Processed file: #{input_file_path}"
|
|
19
|
-
puts "CSV written to: #{output_file_path}"
|
|
20
|
-
puts "Details:"
|
|
21
|
-
puts " Transactions: #{statement.transactions.count}"
|
|
22
|
-
puts " Total activity: #{("$" + statement.total_activity.to_s).gsub("$-", "-$")}"
|
|
23
|
-
puts
|