bankline_csv_import_file 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +3 -3
- data/README.md +78 -12
- data/bankline_csv_import_file.gemspec +2 -2
- data/lib/bankline_csv_import_file.rb +77 -4
- data/lib/bankline_csv_import_file/version.rb +1 -1
- metadata +9 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 54025cfff6c29e03b95f121166c159066a5c4ffb
|
4
|
+
data.tar.gz: bec14e977478642df29e3c967096cb69b34766ef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8eba6219bfb10225a9d9ac28e6d1e6d75d1897781e78abc82f123ef955a5bd85e6d9bbd8c839405dbab369320631088acb63e9d17c8ee979fb66503c944aac57
|
7
|
+
data.tar.gz: 4b7d8620a44aceb424979484501c301898502d3aa59c494851e2090d988e283875b38eb621dca7f4ec84e3fa8b1725f406e05b3a844e6d4294bf416bfc7667b0
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
bankline_csv_import_file (0.
|
4
|
+
bankline_csv_import_file (0.2.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -27,8 +27,8 @@ PLATFORMS
|
|
27
27
|
|
28
28
|
DEPENDENCIES
|
29
29
|
bankline_csv_import_file!
|
30
|
-
bundler
|
31
|
-
rake
|
30
|
+
bundler
|
31
|
+
rake
|
32
32
|
rspec
|
33
33
|
|
34
34
|
BUNDLED WITH
|
data/README.md
CHANGED
@@ -9,28 +9,90 @@ USER BEWARE: At the time of writing, we have not yet verified that the produced
|
|
9
9
|
|
10
10
|
## Usage
|
11
11
|
|
12
|
-
|
12
|
+
Add any number of payments as described below, then generate the CSV content:
|
13
13
|
|
14
|
-
|
14
|
+
file = BanklineCsvImportFile.new
|
15
|
+
|
16
|
+
file.add_domestic_payment(…)
|
17
|
+
file.add_domestic_payment(…)
|
18
|
+
file.add_international_payment(…)
|
19
|
+
|
20
|
+
file.generate # => "foo,bar,…"
|
15
21
|
|
16
|
-
|
22
|
+
|
23
|
+
### Domestic payment
|
24
|
+
|
25
|
+
All these fields are required unless stated otherwise.
|
17
26
|
|
18
27
|
file = BanklineCsvImportFile.new
|
28
|
+
|
19
29
|
file.add_domestic_payment(
|
20
|
-
payer_sort_code: "151000",
|
21
|
-
payer_account_number: "31806542",
|
22
|
-
amount: "123.45", # Strings and BigDecimal are allowed. (Floats are not advisable for money.)
|
23
|
-
beneficiary_sort_code: "151000",
|
24
|
-
beneficiary_account_number: "44298801",
|
30
|
+
payer_sort_code: "151000",
|
31
|
+
payer_account_number: "31806542",
|
32
|
+
amount: "123.45", # Strings and BigDecimal are allowed. (Floats are not advisable for money.) Rounded to 2 decimals.
|
33
|
+
beneficiary_sort_code: "151000",
|
34
|
+
beneficiary_account_number: "44298801",
|
35
|
+
beneficiary_name: "John Doe", # Truncated to a max length of 35.
|
36
|
+
beneficiary_reference: "Invoice 123", # Truncated to a max length of 18.
|
37
|
+
payment_date: Date.new(2018, 1, 1), # Optional. Defaults to Date.current if available, otherwise Date.today. See note below.
|
38
|
+
)
|
39
|
+
|
40
|
+
file.generate # => "foo,bar,…"
|
41
|
+
|
42
|
+
Currency is assumed to be GBP.
|
43
|
+
|
44
|
+
Texts are converted to UPPERCASE and characters other than A-Z, 0-9, space and .-/& are automatically removed from free-text fields.
|
45
|
+
|
46
|
+
Sort codes and account numbers are automatically normalised to the expected format.
|
47
|
+
|
48
|
+
Bankline says this about the payment date:
|
49
|
+
|
50
|
+
> Date payment to arrive (credit date)
|
51
|
+
>
|
52
|
+
> Identifies the date on which the funds are to be received by the beneficiary bank. Although not guaranteed this will normally be the same date on which the funds will be made available to the beneficiary.
|
53
|
+
|
54
|
+
|
55
|
+
### International payment
|
56
|
+
|
57
|
+
All these fields are required unless stated otherwise.
|
58
|
+
|
59
|
+
file = BanklineCsvImportFile.new
|
60
|
+
file.add_international_payment(
|
61
|
+
payer_sort_code: "151000", # Any non-digits will be stripped automatically.
|
62
|
+
payer_account_number: "31806542", # Any non-digits will be stripped automatically.
|
63
|
+
amount: "123.45", # Strings and BigDecimal are allowed. (Floats are not advisable for money.)
|
64
|
+
payment_date: Date.new(2018, 1, 1), # Optional. Defaults to Date.current if available, otherwise Date.today. See note below.
|
65
|
+
beneficiary_bic: "SPKHDE2H",
|
66
|
+
beneficiary_iban: "DE53250501800039370089",
|
25
67
|
beneficiary_name: "John Doe",
|
26
|
-
|
27
|
-
|
68
|
+
|
69
|
+
# Optional but recommended, see below. Truncated to 35 chars per line and max 3 lines.
|
70
|
+
beneficiary_address: "10 Foo Street\nBartown, Baz County\nABC 123"
|
71
|
+
|
72
|
+
beneficiary_reference: "Invoice 123", # Optional. Truncated to 35 chars per line and max 4 lines.
|
28
73
|
)
|
29
74
|
file.generate # => "foo,bar,…"
|
30
75
|
|
31
|
-
|
76
|
+
Currency is assumed to be GBP.
|
77
|
+
|
78
|
+
Characters other than a-z, A-Z, 0-9, space and .-/?:(),+' are automatically removed from free-text fields.
|
79
|
+
|
80
|
+
Sort codes, account numbers, IBAN and BIC are automatically normalised to the expected format.
|
32
81
|
|
33
|
-
|
82
|
+
Bankline says this about the payment date:
|
83
|
+
|
84
|
+
> Execution date
|
85
|
+
>
|
86
|
+
> Identifies the date on which the payment is to be initiated.
|
87
|
+
|
88
|
+
Bankline says this about the beneficiary address:
|
89
|
+
|
90
|
+
> We strongly recommend providing a beneficiary address as this is mandatory for certain destination countries and failure to populate this may cause the payment to be delayed or even rejected by the receiving bank.
|
91
|
+
|
92
|
+
|
93
|
+
### Payment templates, CHAPS
|
94
|
+
|
95
|
+
Not currently supported. Pull requests welcome! [The documentation](https://www.business.rbs.co.uk/content/dam/rbs_co_uk/Business_and_Content/PDFs/Bankline/Bankline-import-file-guide-CSV-RBS.pdf) is great and this codebase is tiny – you can do it! 💪
|
34
96
|
|
35
97
|
|
36
98
|
## Installation
|
@@ -56,6 +118,10 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
56
118
|
|
57
119
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
58
120
|
|
121
|
+
## Also see
|
122
|
+
|
123
|
+
* [Banktools::GB](https://github.com/barsoom/banktools-gb)
|
124
|
+
|
59
125
|
|
60
126
|
## License
|
61
127
|
|
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
|
-
spec.add_development_dependency "bundler"
|
25
|
-
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "bundler"
|
25
|
+
spec.add_development_dependency "rake"
|
26
26
|
spec.add_development_dependency "rspec"
|
27
27
|
end
|
@@ -26,8 +26,55 @@ class BanklineCsvImportFile
|
|
26
26
|
record["T016"] = formatted_payment_date
|
27
27
|
record["T022"] = normalize_account(beneficiary_sort_code)
|
28
28
|
record["T028"] = normalize_account(beneficiary_account_number)
|
29
|
-
record["T030"] =
|
30
|
-
record["T034"] =
|
29
|
+
record["T030"] = domestic_normalize_string(beneficiary_name, max_length: 35)
|
30
|
+
record["T034"] = domestic_normalize_string(beneficiary_reference, max_length: 18)
|
31
|
+
|
32
|
+
@records << record
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_international_payment(payer_sort_code:, payer_account_number:, amount:, beneficiary_bic:, beneficiary_iban:, beneficiary_name:, beneficiary_address: nil, beneficiary_reference:, payment_date: nil)
|
36
|
+
# Use Ruby on Rails' `Date.current` when available, since it will be in the app time zone rather than the server time zone.
|
37
|
+
payment_date ||= Date.respond_to?(:current) ? Date.current : Date.today
|
38
|
+
formatted_payment_date = payment_date.strftime("%d%m%Y")
|
39
|
+
|
40
|
+
payer_account_with_sort_code = normalize_account("#{payer_sort_code}#{payer_account_number}")
|
41
|
+
|
42
|
+
normalized_iban = normalize_iban(beneficiary_iban)
|
43
|
+
normalized_bic = normalize_bic(beneficiary_bic)
|
44
|
+
|
45
|
+
beneficiary_country = normalized_iban[0, 2]
|
46
|
+
|
47
|
+
beneficiary_address_line_1, beneficiary_address_line_2, beneficiary_address_line_3 =
|
48
|
+
international_normalize_multiline_string(beneficiary_address, max_lines: 3, max_length_per_line: 35)
|
49
|
+
|
50
|
+
beneficiary_reference_line_1, beneficiary_reference_line_2, beneficiary_reference_line_3, beneficiary_reference_line_4 =
|
51
|
+
international_normalize_multiline_string(beneficiary_reference, max_lines: 4, max_length_per_line: 35)
|
52
|
+
|
53
|
+
record = Record.new
|
54
|
+
|
55
|
+
# https://www.business.rbs.co.uk/content/dam/rbs_co_uk/Business_and_Content/PDFs/Bankline/Bankline-import-file-guide-CSV-RBS.pdf
|
56
|
+
# Section 4.6, page 54.
|
57
|
+
record["T001"] = "04" # 04 = International payment.
|
58
|
+
record["T007"] = beneficiary_country
|
59
|
+
record["T008"] = "N" # Normal priority.
|
60
|
+
record["T010"] = payer_account_with_sort_code
|
61
|
+
record["T013"] = "GBP" # Payment currency. (Presumably the target currency.)
|
62
|
+
record["T014"] = sprintf("%.2f", BigDecimal(amount))
|
63
|
+
record["T015"] = formatted_payment_date
|
64
|
+
record["T022"] = normalized_bic
|
65
|
+
record["T028"] = normalized_iban
|
66
|
+
record["T030"] = international_normalize_string(beneficiary_name, max_length: 35)
|
67
|
+
|
68
|
+
record["T031"] = beneficiary_address_line_1 if beneficiary_address_line_1
|
69
|
+
record["T032"] = beneficiary_address_line_2 if beneficiary_address_line_2
|
70
|
+
record["T033"] = beneficiary_address_line_3 if beneficiary_address_line_3
|
71
|
+
|
72
|
+
record["T037"] = beneficiary_reference_line_1 if beneficiary_reference_line_1
|
73
|
+
record["T038"] = beneficiary_reference_line_2 if beneficiary_reference_line_2
|
74
|
+
record["T039"] = beneficiary_reference_line_3 if beneficiary_reference_line_3
|
75
|
+
record["T040"] = beneficiary_reference_line_4 if beneficiary_reference_line_4
|
76
|
+
|
77
|
+
record["T042"] = "GBP" # Credit currency. (Presumably the source currency.)
|
31
78
|
|
32
79
|
@records << record
|
33
80
|
end
|
@@ -42,13 +89,39 @@ class BanklineCsvImportFile
|
|
42
89
|
|
43
90
|
private
|
44
91
|
|
92
|
+
def normalize_bic(bic)
|
93
|
+
normalized_bic = bic.to_s.upcase.gsub(/[^A-Z\d]/, "")
|
94
|
+
|
95
|
+
# https://www.business.rbs.co.uk/content/dam/rbs_co_uk/Business_and_Content/PDFs/Bankline/Bankline-import-file-guide-CSV-RBS.pdf section 2.5, page 6:
|
96
|
+
# "For any 8 character BIC, please append this with XXX i.e., for ULSBIE2D populate as ULSBIE2DXXX."
|
97
|
+
normalized_bic << "XXX" if normalized_bic.length == 8
|
98
|
+
|
99
|
+
normalized_bic
|
100
|
+
end
|
101
|
+
|
102
|
+
def normalize_iban(iban)
|
103
|
+
iban.to_s.upcase.gsub(/[^A-Z\d]/, "")
|
104
|
+
end
|
105
|
+
|
45
106
|
def normalize_account(string)
|
46
|
-
string.gsub(/\D/, "")
|
107
|
+
string.upcase.gsub(/\D/, "")
|
47
108
|
end
|
48
109
|
|
49
|
-
def
|
110
|
+
def domestic_normalize_string(string, max_length:)
|
50
111
|
output = string.to_s.upcase
|
51
112
|
output = output.gsub(%r{[^A-Z0-9./& -]}, "")
|
52
113
|
output[0, max_length]
|
53
114
|
end
|
115
|
+
|
116
|
+
def international_normalize_multiline_string(string, max_lines:, max_length_per_line:)
|
117
|
+
string.to_s.split("\n").reject(&:empty?)[0, max_lines].map { |line|
|
118
|
+
international_normalize_string(line, max_length: max_length_per_line)
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
def international_normalize_string(string, max_length:)
|
123
|
+
output = string.to_s
|
124
|
+
output = output.gsub(%r{[^a-zA-Z0-9./?:(),+' -]}, "")
|
125
|
+
output[0, max_length]
|
126
|
+
end
|
54
127
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bankline_csv_import_file
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Henrik Nyh
|
@@ -14,30 +14,30 @@ dependencies:
|
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|