ng-bank-parser 0.1.6 → 0.1.7
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 -1
- data/Gemfile.lock +42 -40
- data/README.md +10 -2
- data/lib/ng-bank-parser.rb +11 -10
- data/lib/ng-bank-parser/banks.rb +10 -1
- data/lib/ng-bank-parser/fixtures/ecobank-pdf-invalid.pdf +160 -0
- data/lib/ng-bank-parser/fixtures/ecobank-pdf-valid.pdf +0 -0
- data/lib/ng-bank-parser/parsers/accessbank-pdf-parser/helpers.rb +1 -3
- data/lib/ng-bank-parser/parsers/ecobank-pdf-parser.rb +35 -0
- data/lib/ng-bank-parser/parsers/ecobank-pdf-parser/helpers.rb +164 -0
- data/lib/ng-bank-parser/version.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 051a42caac128747e23f1153ab29969b73cbaa38
|
|
4
|
+
data.tar.gz: 613248ebd4a944520d81c31366c3eebca7c6297e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b97fc6045653913ba4b119c814f53936265d895c72066c303266437411362cde7878d985e6049930ca20996717fa508db3f3b8ee6c6d6f43390210c832a71e63
|
|
7
|
+
data.tar.gz: 145c45868fb797ec049bbf9e26ba0621256a95ea3926f5c40018826d790237be0a99feb9bac79ed986eee6cea204f4f7452c5161d9c31d8ccaac4319f64fdfbe
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -11,64 +11,66 @@ PATH
|
|
|
11
11
|
GEM
|
|
12
12
|
remote: https://rubygems.org/
|
|
13
13
|
specs:
|
|
14
|
-
Ascii85 (1.0.
|
|
15
|
-
activesupport (
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
Ascii85 (1.0.3)
|
|
15
|
+
activesupport (5.2.1)
|
|
16
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
17
|
+
i18n (>= 0.7, < 2)
|
|
18
18
|
minitest (~> 5.1)
|
|
19
|
-
thread_safe (~> 0.3, >= 0.3.4)
|
|
20
19
|
tzinfo (~> 1.1)
|
|
21
20
|
afm (0.2.2)
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
concurrent-ruby (1.0.5)
|
|
22
|
+
diff-lcs (1.3)
|
|
23
|
+
domain_name (0.5.20180417)
|
|
24
24
|
unf (>= 0.0.5, < 1.0.0)
|
|
25
|
-
hashery (2.1.
|
|
26
|
-
http-cookie (1.0.
|
|
25
|
+
hashery (2.1.2)
|
|
26
|
+
http-cookie (1.0.3)
|
|
27
27
|
domain_name (~> 0.5)
|
|
28
|
-
i18n (
|
|
29
|
-
|
|
30
|
-
mime-types (2.
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
i18n (1.1.0)
|
|
29
|
+
concurrent-ruby (~> 1.0)
|
|
30
|
+
mime-types (3.2.2)
|
|
31
|
+
mime-types-data (~> 3.2015)
|
|
32
|
+
mime-types-data (3.2018.0812)
|
|
33
|
+
mini_portile2 (2.3.0)
|
|
34
|
+
minitest (5.11.3)
|
|
33
35
|
netrc (0.11.0)
|
|
34
|
-
nokogiri (1.
|
|
35
|
-
mini_portile2 (~> 2.
|
|
36
|
-
pdf-reader (1.
|
|
36
|
+
nokogiri (1.8.4)
|
|
37
|
+
mini_portile2 (~> 2.3.0)
|
|
38
|
+
pdf-reader (2.1.0)
|
|
37
39
|
Ascii85 (~> 1.0.0)
|
|
38
|
-
afm (~> 0.2.
|
|
40
|
+
afm (~> 0.2.1)
|
|
39
41
|
hashery (~> 2.0)
|
|
40
42
|
ruby-rc4
|
|
41
43
|
ttfunk
|
|
42
|
-
rake (10.
|
|
43
|
-
rest-client (
|
|
44
|
+
rake (10.5.0)
|
|
45
|
+
rest-client (2.0.2)
|
|
44
46
|
http-cookie (>= 1.0.2, < 2.0)
|
|
45
|
-
mime-types (>= 1.16, <
|
|
46
|
-
netrc (~> 0.
|
|
47
|
-
roo (2.
|
|
47
|
+
mime-types (>= 1.16, < 4.0)
|
|
48
|
+
netrc (~> 0.8)
|
|
49
|
+
roo (2.7.1)
|
|
48
50
|
nokogiri (~> 1)
|
|
49
51
|
rubyzip (~> 1.1, < 2.0.0)
|
|
50
|
-
rspec (3.
|
|
51
|
-
rspec-core (~> 3.
|
|
52
|
-
rspec-expectations (~> 3.
|
|
53
|
-
rspec-mocks (~> 3.
|
|
54
|
-
rspec-core (3.
|
|
55
|
-
rspec-support (~> 3.
|
|
56
|
-
rspec-expectations (3.
|
|
52
|
+
rspec (3.8.0)
|
|
53
|
+
rspec-core (~> 3.8.0)
|
|
54
|
+
rspec-expectations (~> 3.8.0)
|
|
55
|
+
rspec-mocks (~> 3.8.0)
|
|
56
|
+
rspec-core (3.8.0)
|
|
57
|
+
rspec-support (~> 3.8.0)
|
|
58
|
+
rspec-expectations (3.8.1)
|
|
57
59
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
58
|
-
rspec-support (~> 3.
|
|
59
|
-
rspec-mocks (3.
|
|
60
|
+
rspec-support (~> 3.8.0)
|
|
61
|
+
rspec-mocks (3.8.0)
|
|
60
62
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
61
|
-
rspec-support (~> 3.
|
|
62
|
-
rspec-support (3.
|
|
63
|
+
rspec-support (~> 3.8.0)
|
|
64
|
+
rspec-support (3.8.0)
|
|
63
65
|
ruby-rc4 (0.1.5)
|
|
64
|
-
rubyzip (1.
|
|
65
|
-
thread_safe (0.3.
|
|
66
|
-
ttfunk (1.
|
|
67
|
-
tzinfo (1.2.
|
|
66
|
+
rubyzip (1.2.2)
|
|
67
|
+
thread_safe (0.3.6)
|
|
68
|
+
ttfunk (1.5.1)
|
|
69
|
+
tzinfo (1.2.5)
|
|
68
70
|
thread_safe (~> 0.1)
|
|
69
71
|
unf (0.1.4)
|
|
70
72
|
unf_ext
|
|
71
|
-
unf_ext (0.0.7.
|
|
73
|
+
unf_ext (0.0.7.5)
|
|
72
74
|
|
|
73
75
|
PLATFORMS
|
|
74
76
|
ruby
|
|
@@ -80,4 +82,4 @@ DEPENDENCIES
|
|
|
80
82
|
rspec
|
|
81
83
|
|
|
82
84
|
BUNDLED WITH
|
|
83
|
-
1.
|
|
85
|
+
1.16.4
|
data/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
This is a simple gem to parse Nigerian bank statements of all formats. If your bank and/or file format is not supported, consider reading the contribute wiki and submitting a pull request.
|
|
3
3
|
|
|
4
4
|
## API
|
|
5
|
-
Because not everyone develops in rails, we created a public API to use the gem at http://bank-parser.
|
|
5
|
+
Because not everyone develops in rails, we created a public API to use the gem at http://bank-parser.square-api.com/parse. The parameters are (bank_key, file_path, password). Read the *Usage* section for more information
|
|
6
6
|
|
|
7
|
-
http://bank-parser.
|
|
7
|
+
http://bank-parser.square-api.com/parse(bank_key, file_path, password)
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
@@ -92,6 +92,14 @@ Heritage Bank:
|
|
|
92
92
|
- key: hb
|
|
93
93
|
- supported formats: pdf
|
|
94
94
|
|
|
95
|
+
Access Bank:
|
|
96
|
+
- key: accessbank
|
|
97
|
+
- supported formats: pdf
|
|
98
|
+
|
|
99
|
+
Ecobank:
|
|
100
|
+
- key: ecobank
|
|
101
|
+
- supported formats: pdf
|
|
102
|
+
|
|
95
103
|
## Contributing
|
|
96
104
|
|
|
97
105
|
Documentation on contribution can be found in the contribution wiki
|
data/lib/ng-bank-parser.rb
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
require_relative "ng-bank-parser/version"
|
|
2
|
+
require_relative "ng-bank-parser/banks"
|
|
3
|
+
require_relative "ng-bank-parser/router"
|
|
4
|
+
require_relative "ng-bank-parser/pdf-unlocker"
|
|
5
|
+
require_relative "ng-bank-parser/parsers/gtb-excel-parser"
|
|
6
|
+
require_relative "ng-bank-parser/parsers/uba-pdf-parser"
|
|
7
|
+
require_relative "ng-bank-parser/parsers/hb-pdf-parser"
|
|
8
|
+
require_relative "ng-bank-parser/parsers/firstbank-pdf-parser"
|
|
9
|
+
require_relative "ng-bank-parser/parsers/accessbank-pdf-parser"
|
|
10
|
+
require_relative "ng-bank-parser/parsers/ecobank-pdf-parser"
|
|
10
11
|
|
|
11
12
|
module NgBankParser
|
|
12
|
-
# Your code goes here...
|
|
13
|
+
# Your code goes here...
|
|
13
14
|
end
|
data/lib/ng-bank-parser/banks.rb
CHANGED
|
@@ -46,6 +46,15 @@ module NgBankParser
|
|
|
46
46
|
invalid: "lib/ng-bank-parser/fixtures/accessbank-pdf-invalid.pdf",
|
|
47
47
|
extensions: ["pdf"]
|
|
48
48
|
}]
|
|
49
|
-
}
|
|
49
|
+
},{
|
|
50
|
+
key: "ecobank",
|
|
51
|
+
name: "Ecobank Nigeria",
|
|
52
|
+
parsers: [{
|
|
53
|
+
format: "pdf",
|
|
54
|
+
valid: "lib/ng-bank-parser/fixtures/ecobank-pdf-valid.pdf",
|
|
55
|
+
invalid: "lib/ng-bank-parser/fixtures/ecobank-pdf-invalid.pdf",
|
|
56
|
+
extensions: ["pdf"]
|
|
57
|
+
}]
|
|
58
|
+
}]
|
|
50
59
|
end
|
|
51
60
|
end
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
%PDF-1.3
|
|
2
|
+
3 0 obj
|
|
3
|
+
<</Type /Page
|
|
4
|
+
/Parent 1 0 R
|
|
5
|
+
/Resources 2 0 R
|
|
6
|
+
/Contents 4 0 R>>
|
|
7
|
+
endobj
|
|
8
|
+
4 0 obj
|
|
9
|
+
<</Length 165>>
|
|
10
|
+
stream
|
|
11
|
+
0.57 w
|
|
12
|
+
0 G
|
|
13
|
+
BT
|
|
14
|
+
/F1 16 Tf
|
|
15
|
+
16 TL
|
|
16
|
+
0 g
|
|
17
|
+
56.69 785.20 Td
|
|
18
|
+
(Hello world!) Tj
|
|
19
|
+
ET
|
|
20
|
+
BT
|
|
21
|
+
/F1 16 Tf
|
|
22
|
+
16 TL
|
|
23
|
+
0 g
|
|
24
|
+
56.69 756.85 Td
|
|
25
|
+
(This a random PDF file for testing our parsers.) Tj
|
|
26
|
+
ET
|
|
27
|
+
endstream
|
|
28
|
+
endobj
|
|
29
|
+
1 0 obj
|
|
30
|
+
<</Type /Pages
|
|
31
|
+
/Kids [3 0 R ]
|
|
32
|
+
/Count 1
|
|
33
|
+
/MediaBox [0 0 595.28 841.89]
|
|
34
|
+
>>
|
|
35
|
+
endobj
|
|
36
|
+
5 0 obj
|
|
37
|
+
<</BaseFont/Helvetica/Type/Font
|
|
38
|
+
/Encoding/WinAnsiEncoding
|
|
39
|
+
/Subtype/Type1>>
|
|
40
|
+
endobj
|
|
41
|
+
6 0 obj
|
|
42
|
+
<</BaseFont/Helvetica-Bold/Type/Font
|
|
43
|
+
/Encoding/WinAnsiEncoding
|
|
44
|
+
/Subtype/Type1>>
|
|
45
|
+
endobj
|
|
46
|
+
7 0 obj
|
|
47
|
+
<</BaseFont/Helvetica-Oblique/Type/Font
|
|
48
|
+
/Encoding/WinAnsiEncoding
|
|
49
|
+
/Subtype/Type1>>
|
|
50
|
+
endobj
|
|
51
|
+
8 0 obj
|
|
52
|
+
<</BaseFont/Helvetica-BoldOblique/Type/Font
|
|
53
|
+
/Encoding/WinAnsiEncoding
|
|
54
|
+
/Subtype/Type1>>
|
|
55
|
+
endobj
|
|
56
|
+
9 0 obj
|
|
57
|
+
<</BaseFont/Courier/Type/Font
|
|
58
|
+
/Encoding/WinAnsiEncoding
|
|
59
|
+
/Subtype/Type1>>
|
|
60
|
+
endobj
|
|
61
|
+
10 0 obj
|
|
62
|
+
<</BaseFont/Courier-Bold/Type/Font
|
|
63
|
+
/Encoding/WinAnsiEncoding
|
|
64
|
+
/Subtype/Type1>>
|
|
65
|
+
endobj
|
|
66
|
+
11 0 obj
|
|
67
|
+
<</BaseFont/Courier-Oblique/Type/Font
|
|
68
|
+
/Encoding/WinAnsiEncoding
|
|
69
|
+
/Subtype/Type1>>
|
|
70
|
+
endobj
|
|
71
|
+
12 0 obj
|
|
72
|
+
<</BaseFont/Courier-BoldOblique/Type/Font
|
|
73
|
+
/Encoding/WinAnsiEncoding
|
|
74
|
+
/Subtype/Type1>>
|
|
75
|
+
endobj
|
|
76
|
+
13 0 obj
|
|
77
|
+
<</BaseFont/Times-Roman/Type/Font
|
|
78
|
+
/Encoding/WinAnsiEncoding
|
|
79
|
+
/Subtype/Type1>>
|
|
80
|
+
endobj
|
|
81
|
+
14 0 obj
|
|
82
|
+
<</BaseFont/Times-Bold/Type/Font
|
|
83
|
+
/Encoding/WinAnsiEncoding
|
|
84
|
+
/Subtype/Type1>>
|
|
85
|
+
endobj
|
|
86
|
+
15 0 obj
|
|
87
|
+
<</BaseFont/Times-Italic/Type/Font
|
|
88
|
+
/Encoding/WinAnsiEncoding
|
|
89
|
+
/Subtype/Type1>>
|
|
90
|
+
endobj
|
|
91
|
+
16 0 obj
|
|
92
|
+
<</BaseFont/Times-BoldItalic/Type/Font
|
|
93
|
+
/Encoding/WinAnsiEncoding
|
|
94
|
+
/Subtype/Type1>>
|
|
95
|
+
endobj
|
|
96
|
+
2 0 obj
|
|
97
|
+
<<
|
|
98
|
+
/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
|
|
99
|
+
/Font <<
|
|
100
|
+
/F1 5 0 R
|
|
101
|
+
/F2 6 0 R
|
|
102
|
+
/F3 7 0 R
|
|
103
|
+
/F4 8 0 R
|
|
104
|
+
/F5 9 0 R
|
|
105
|
+
/F6 10 0 R
|
|
106
|
+
/F7 11 0 R
|
|
107
|
+
/F8 12 0 R
|
|
108
|
+
/F9 13 0 R
|
|
109
|
+
/F10 14 0 R
|
|
110
|
+
/F11 15 0 R
|
|
111
|
+
/F12 16 0 R
|
|
112
|
+
>>
|
|
113
|
+
/XObject <<
|
|
114
|
+
>>
|
|
115
|
+
>>
|
|
116
|
+
endobj
|
|
117
|
+
17 0 obj
|
|
118
|
+
<<
|
|
119
|
+
/Producer (jsPDF 20120619)
|
|
120
|
+
/CreationDate (D:20150829130726)
|
|
121
|
+
>>
|
|
122
|
+
endobj
|
|
123
|
+
18 0 obj
|
|
124
|
+
<<
|
|
125
|
+
/Type /Catalog
|
|
126
|
+
/Pages 1 0 R
|
|
127
|
+
/OpenAction [3 0 R /FitH null]
|
|
128
|
+
/PageLayout /OneColumn
|
|
129
|
+
>>
|
|
130
|
+
endobj
|
|
131
|
+
xref
|
|
132
|
+
0 19
|
|
133
|
+
0000000000 65535 f
|
|
134
|
+
0000000301 00000 n
|
|
135
|
+
0000001530 00000 n
|
|
136
|
+
0000000009 00000 n
|
|
137
|
+
0000000087 00000 n
|
|
138
|
+
0000000388 00000 n
|
|
139
|
+
0000000478 00000 n
|
|
140
|
+
0000000573 00000 n
|
|
141
|
+
0000000671 00000 n
|
|
142
|
+
0000000773 00000 n
|
|
143
|
+
0000000861 00000 n
|
|
144
|
+
0000000955 00000 n
|
|
145
|
+
0000001052 00000 n
|
|
146
|
+
0000001153 00000 n
|
|
147
|
+
0000001246 00000 n
|
|
148
|
+
0000001338 00000 n
|
|
149
|
+
0000001432 00000 n
|
|
150
|
+
0000001754 00000 n
|
|
151
|
+
0000001836 00000 n
|
|
152
|
+
trailer
|
|
153
|
+
<<
|
|
154
|
+
/Size 19
|
|
155
|
+
/Root 18 0 R
|
|
156
|
+
/Info 17 0 R
|
|
157
|
+
>>
|
|
158
|
+
startxref
|
|
159
|
+
1940
|
|
160
|
+
%%EOF
|
|
Binary file
|
|
@@ -111,8 +111,6 @@ module AccessbankPdfHelpers
|
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
116
114
|
def error(msg)
|
|
117
115
|
{ status: 400, message: msg }
|
|
118
116
|
end
|
|
@@ -122,7 +120,6 @@ module AccessbankPdfHelpers
|
|
|
122
120
|
end
|
|
123
121
|
|
|
124
122
|
|
|
125
|
-
|
|
126
123
|
private
|
|
127
124
|
def remove_line_spacing(str)
|
|
128
125
|
str.gsub(/^$\n/, '').lines
|
|
@@ -161,6 +158,7 @@ module AccessbankPdfHelpers
|
|
|
161
158
|
Date.strptime(date_str, '%d-%b-%y')
|
|
162
159
|
end
|
|
163
160
|
|
|
161
|
+
|
|
164
162
|
def string_with_slash_to_date(date_str)
|
|
165
163
|
Date.strptime(date_str, '%d/%m/%Y')
|
|
166
164
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'pdf-reader'
|
|
2
|
+
require 'open-uri'
|
|
3
|
+
require_relative 'ecobank-pdf-parser/helpers'
|
|
4
|
+
|
|
5
|
+
module NgBankParser
|
|
6
|
+
class EcobankPdf
|
|
7
|
+
extend EcobankPdfHelpers
|
|
8
|
+
|
|
9
|
+
FILE_FORMATS = [".pdf"]
|
|
10
|
+
|
|
11
|
+
def self.parse(path, password=nil)
|
|
12
|
+
unless FILE_FORMATS.include? File.extname(path)
|
|
13
|
+
return error("Invalid file format. Please use one of the following: #{ FILE_FORMATS.each{ |format| format }}")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
file = open(path)
|
|
17
|
+
begin
|
|
18
|
+
@pdf = PDF::Reader.new(file)
|
|
19
|
+
rescue PDF::Reader::EncryptedPDFError
|
|
20
|
+
return error("Invalid file. Please use an unencrypted pdf")
|
|
21
|
+
rescue
|
|
22
|
+
return error("Couldn't parse this file")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
pdf_array = pdf_to_a(@pdf)
|
|
26
|
+
|
|
27
|
+
unless has_valid_details?(pdf_array)
|
|
28
|
+
return error("Couldn't fetch account details from pdf")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
response = get_details(pdf_array)
|
|
32
|
+
return success(response)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
module NgBankParser
|
|
2
|
+
module EcobankPdfHelpers
|
|
3
|
+
|
|
4
|
+
def pdf_to_a(pdf)
|
|
5
|
+
lines = []
|
|
6
|
+
|
|
7
|
+
pdf.pages.each do |page|
|
|
8
|
+
remove_line_spacing(page.text).each do |line|
|
|
9
|
+
lines << line.strip.split(/\s\s+/)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
return lines
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_details(pdf_array)
|
|
18
|
+
details = Hash.new
|
|
19
|
+
details[:bank_name] = 'Ecobank'
|
|
20
|
+
details[:account_number] = get_account_number(pdf_array)
|
|
21
|
+
details[:account_name] = get_account_name(pdf_array)
|
|
22
|
+
|
|
23
|
+
transactions = get_transactions(pdf_array)
|
|
24
|
+
details[:from_date] = transactions[0][:date]
|
|
25
|
+
details[:to_date] = transactions[-1][:date]
|
|
26
|
+
details[:transactions] = transactions
|
|
27
|
+
|
|
28
|
+
return details
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def has_valid_details?(pdf_array)
|
|
33
|
+
return (get_account_number(pdf_array) and get_account_name(pdf_array))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_account_name(pdf_array)
|
|
38
|
+
pdf_array.each do |row|
|
|
39
|
+
row.each_with_index do |cell, index|
|
|
40
|
+
if cell == 'Name'
|
|
41
|
+
return row[index + 1]
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
return nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_account_number(pdf_array)
|
|
50
|
+
pdf_array.each do |row|
|
|
51
|
+
row.each do |cell|
|
|
52
|
+
if cell =~ /[0-9]{10}/
|
|
53
|
+
return cell
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
return nil
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def get_transactions(pdf_array)
|
|
62
|
+
start_index = get_first_line_of_transactions(pdf_array)
|
|
63
|
+
transactions = []
|
|
64
|
+
|
|
65
|
+
opening_balance = pdf_array[start_index][-1]
|
|
66
|
+
|
|
67
|
+
pdf_array[start_index..-1].each do |transaction|
|
|
68
|
+
if valid_transaction?(transaction)
|
|
69
|
+
|
|
70
|
+
transaction_hash = Hash.new
|
|
71
|
+
transaction_hash[:date] = string_with_dash_to_date(transaction[0])
|
|
72
|
+
|
|
73
|
+
if transaction.count == 6
|
|
74
|
+
transaction_hash[:remarks] = transaction[2]
|
|
75
|
+
transaction_hash[:ref] = transaction[3]
|
|
76
|
+
transaction_hash[:amount] = amount_to_f(transaction[4])
|
|
77
|
+
transaction_hash[:balance] = amount_to_f(transaction[5])
|
|
78
|
+
elsif transaction.count == 5
|
|
79
|
+
if transaction[2].chars.first === "'"
|
|
80
|
+
transaction_hash[:remarks] = ""
|
|
81
|
+
transaction_hash[:ref] = transaction[2]
|
|
82
|
+
transaction_hash[:amount] = amount_to_f(transaction[3])
|
|
83
|
+
transaction_hash[:balance] = amount_to_f(transaction[4])
|
|
84
|
+
elsif transaction[2].split("'")[1]
|
|
85
|
+
transaction_hash[:remarks] = transaction[2].split("'")[0]
|
|
86
|
+
transaction_hash[:ref] = transaction[2].split("'")[1]
|
|
87
|
+
transaction_hash[:amount] = amount_to_f(transaction[3])
|
|
88
|
+
transaction_hash[:balance] = amount_to_f(transaction[4])
|
|
89
|
+
else
|
|
90
|
+
transaction_hash[:remarks] = transaction[2]
|
|
91
|
+
transaction_hash[:ref] = transaction[3]
|
|
92
|
+
amount_and_balance = transaction[4].split(" ")
|
|
93
|
+
transaction_hash[:amount] = amount_to_f(amount_and_balance[0])
|
|
94
|
+
transaction_hash[:balance] = amount_to_f(amount_and_balance[1])
|
|
95
|
+
end
|
|
96
|
+
else
|
|
97
|
+
remarks_and_ref = transaction[2].split("'")
|
|
98
|
+
transaction_hash[:remarks] = remarks_and_ref[0]
|
|
99
|
+
transaction_hash[:ref] = "'" << remarks_and_ref[1]
|
|
100
|
+
amount_and_balance = transaction[3].split(" ")
|
|
101
|
+
transaction_hash[:amount] = amount_to_f(amount_and_balance[0])
|
|
102
|
+
transaction_hash[:balance] = amount_to_f(amount_and_balance[1])
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
transaction_hash[:type] = transaction_type(transaction_hash[:balance], opening_balance)
|
|
106
|
+
|
|
107
|
+
opening_balance = transaction_hash[:balance]
|
|
108
|
+
transactions << transaction_hash
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
return transactions
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def error(message)
|
|
117
|
+
{ status: 400, message: message }
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def success(data)
|
|
121
|
+
{ status: 200, data: data }
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
def remove_line_spacing(str)
|
|
127
|
+
str.gsub(/^$\n/, '').lines
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def transaction_type(current_balance, former_balance)
|
|
132
|
+
former_balance = amount_to_f(former_balance) if former_balance.is_a?(String)
|
|
133
|
+
|
|
134
|
+
current_balance - former_balance > 1 ? 'credit' : 'debit'
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def amount_to_f(amount)
|
|
139
|
+
amount.gsub(/[^\d\.]/, '').to_f
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def get_first_line_of_transactions(pdf_array)
|
|
144
|
+
start = -1
|
|
145
|
+
|
|
146
|
+
pdf_array.each_with_index do |row, index|
|
|
147
|
+
start = index + 1 if row[0] == 'Transaction Date'
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
return start
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def valid_transaction?(line)
|
|
155
|
+
# first column matches ecobank transaction date pattern and it has between 4 and 6 columns
|
|
156
|
+
line[0] =~ /([0-3][0-9])[\-]([a-zA-Z]+)[\-]([0-9]{4})/ and line.count >= 4 and line.count <= 6
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def string_with_dash_to_date(date_str)
|
|
161
|
+
Date.strptime(date_str, '%d-%b-%y')
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ng-bank-parser
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Opemipo Aikomo
|
|
@@ -11,7 +11,7 @@ authors:
|
|
|
11
11
|
autorequire:
|
|
12
12
|
bindir: exe
|
|
13
13
|
cert_chain: []
|
|
14
|
-
date:
|
|
14
|
+
date: 2018-09-14 00:00:00.000000000 Z
|
|
15
15
|
dependencies:
|
|
16
16
|
- !ruby/object:Gem::Dependency
|
|
17
17
|
name: bundler
|
|
@@ -150,6 +150,8 @@ files:
|
|
|
150
150
|
- lib/ng-bank-parser/banks.rb
|
|
151
151
|
- lib/ng-bank-parser/fixtures/accessbank-pdf-invalid.pdf
|
|
152
152
|
- lib/ng-bank-parser/fixtures/accessbank-pdf-valid.pdf
|
|
153
|
+
- lib/ng-bank-parser/fixtures/ecobank-pdf-invalid.pdf
|
|
154
|
+
- lib/ng-bank-parser/fixtures/ecobank-pdf-valid.pdf
|
|
153
155
|
- lib/ng-bank-parser/fixtures/firstbank-pdf-invalid.pdf
|
|
154
156
|
- lib/ng-bank-parser/fixtures/firstbank-pdf-valid.pdf
|
|
155
157
|
- lib/ng-bank-parser/fixtures/gtb-excel-invalid.pdf
|
|
@@ -161,6 +163,8 @@ files:
|
|
|
161
163
|
- lib/ng-bank-parser/fixtures/uba-pdf-valid.pdf
|
|
162
164
|
- lib/ng-bank-parser/parsers/accessbank-pdf-parser.rb
|
|
163
165
|
- lib/ng-bank-parser/parsers/accessbank-pdf-parser/helpers.rb
|
|
166
|
+
- lib/ng-bank-parser/parsers/ecobank-pdf-parser.rb
|
|
167
|
+
- lib/ng-bank-parser/parsers/ecobank-pdf-parser/helpers.rb
|
|
164
168
|
- lib/ng-bank-parser/parsers/firstbank-pdf-parser.rb
|
|
165
169
|
- lib/ng-bank-parser/parsers/firstbank-pdf-parser/helpers.rb
|
|
166
170
|
- lib/ng-bank-parser/parsers/firstbank-pdf-parser/statement_utils.rb
|
|
@@ -199,7 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
199
203
|
version: '0'
|
|
200
204
|
requirements: []
|
|
201
205
|
rubyforge_project:
|
|
202
|
-
rubygems_version: 2.
|
|
206
|
+
rubygems_version: 2.5.2
|
|
203
207
|
signing_key:
|
|
204
208
|
specification_version: 4
|
|
205
209
|
summary: This is a simple gem to parse Nigerian bank statements of all formats created
|