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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 66e997668b73970bc4435e68a9151d949bec1547
4
- data.tar.gz: 285e3b7f92f5d1406434a8d8ce937e9862ee7920
3
+ metadata.gz: 54025cfff6c29e03b95f121166c159066a5c4ffb
4
+ data.tar.gz: bec14e977478642df29e3c967096cb69b34766ef
5
5
  SHA512:
6
- metadata.gz: c4fe98dc2e53dbd8fd4932073ee28ba4e81d8fa19c66dcfd87bbc5094a6a837ac89154ddf4162d906a7abb32134e2bf4c0ed1d7ae8f2e620cfb012d41f104593
7
- data.tar.gz: ab835ab9aa6e9c6fe4e2c5b3ad4d03bc178ccaf130837e6ec268bd2b70fdaf05b92e062911926b5e7f5ab0089b879a8cdbf40a90f43578cb4c3c3e45aa0fa5a3
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.1.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 (~> 1.16)
31
- rake (~> 10.0)
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
- ### Standard domestic payment
12
+ Add any number of payments as described below, then generate the CSV content:
13
13
 
14
- All these fields are required unless stated.
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
- Currency will be assumed to be GBP.
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", # Any non-digits will be stripped automatically.
21
- payer_account_number: "31806542", # Any non-digits will be stripped automatically.
22
- amount: "123.45", # Strings and BigDecimal are allowed. (Floats are not advisable for money.)
23
- beneficiary_sort_code: "151000", # Any non-digits will be stripped automatically.
24
- beneficiary_account_number: "44298801", # Any non-digits will be stripped automatically.
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
- beneficiary_reference: "Invoice 123",
27
- payment_date: Date.new(2018, 1, 1), # Optional. Defaults to Date.current if available, otherwise Date.today.
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
- ### Payment templates, CHAPS, international payments
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
- Not currently supported. Pull requests welcome!
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", "~> 1.16"
25
- spec.add_development_dependency "rake", "~> 10.0"
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"] = normalize_string(beneficiary_name, max_length: 35)
30
- record["T034"] = normalize_string(beneficiary_reference, max_length: 18)
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 normalize_string(string, max_length:)
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
@@ -1,3 +1,3 @@
1
1
  class BanklineCsvImportFile
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  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.1.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: '1.16'
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: '1.16'
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: '10.0'
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: '10.0'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement