girocode 0.1.0 → 1.0.0
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/CHANGELOG.md +5 -0
- data/README.md +28 -2
- data/lib/girocode/bic.rb +67 -0
- data/lib/girocode/code.rb +23 -23
- data/lib/girocode/version.rb +1 -1
- data/lib/girocode.rb +2 -1
- metadata +9 -53
- data/Rakefile +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ae1af8187bb62eb64c3b96a6d9001899e7f156bba781844f1d3f462bf954a248
|
4
|
+
data.tar.gz: bd8ca3c9fd7156c50d801368f91986c8ea63bbb7e6934d6b356bb0a91a8df7db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2271e8db17f381aa6debff46557c81b08c3bf23bc74043a27fd61957f91f22d13fd6e6ba8791534d5a6f1df8e4eac85557befd4ec1ca4bc41ba9c3f799d1b6af
|
7
|
+
data.tar.gz: 8ac181062def7582a6fd8bc5604983a8ec8f95144cc276398f9f4df3d4ca2334b0c1a0101ff28d75d0de1655d661181cc0e908c44e8064bca27dc410a3524515
|
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
[](http://badge.fury.io/rb/girocode) [](http://badge.fury.io/rb/girocode) [](https://github.com/mtgrosser/girocode/actions/workflows/build.yml)
|
2
2
|
# Girocode - create EPC QR codes for SEPA bank transfers
|
3
3
|
|
4
|
-
Pure Ruby library to generate QR codes in SVG, PNG, HTML or ASCII format
|
4
|
+
Pure Ruby library to generate EPC QR codes in SVG, PNG, HTML or ASCII format
|
5
5
|
|
6
6
|

|
7
7
|
|
@@ -28,3 +28,29 @@ code.to_ascii
|
|
28
28
|
# in your console
|
29
29
|
puts code.to_ansi
|
30
30
|
```
|
31
|
+
|
32
|
+
## Supported attributes
|
33
|
+
|
34
|
+
Codes can be generated with the following attributes:
|
35
|
+
|
36
|
+
| Attribute | Description | required | exclusive | max size |
|
37
|
+
|----------------------|--------------------------------|--------------------|-----------|----------|
|
38
|
+
| `bic` | Bank Identifier Code | | | 11 |
|
39
|
+
| `name` | Name of beneficiary | ✓ | | 70 |
|
40
|
+
| `iban` | IBAN | ✓ | | 34 |
|
41
|
+
| `currency` | ISO-4217 currency code | if `amount` given | | 3 |
|
42
|
+
| `amount` | Money amount | | | 12 |
|
43
|
+
| `purpose` | SEPA purpose code | | | 4 |
|
44
|
+
| `creditor_reference` | ISO-11649 creditor reference | | ✓ | 35 |
|
45
|
+
| `reference` | Unstructured reference | | ✓ | 140 |
|
46
|
+
| `bto_info` | Beneficiary to originator info | | | 70 |
|
47
|
+
|
48
|
+
## Limitations
|
49
|
+
|
50
|
+
Codes are generated as EPC-QR Version 2 in UTF-8 format only.
|
51
|
+
|
52
|
+
## Specification
|
53
|
+
|
54
|
+
European Payments Council: Quick Response Code
|
55
|
+
|
56
|
+
[Guidelines to enable data capture for the initiation of a SEPA credit transfer](https://www.europeanpaymentscouncil.eu/sites/default/files/kb/file/2018-05/EPC069-12%20v2.1%20Quick%20Response%20Code%20-%20Guidelines%20to%20Enable%20the%20Data%20Capture%20for%20the%20Initiation%20of%20a%20SCT.pdf)
|
data/lib/girocode/bic.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# derived from bank-contact/bic by Kevin
|
2
|
+
|
3
|
+
module Girocode
|
4
|
+
class BIC
|
5
|
+
REGEX = /\A([A-Z]{4})([A-Z]{2})([A-Z0-9]{2})([A-Z0-9]{3})?\z/.freeze
|
6
|
+
|
7
|
+
def self.valid?(code)
|
8
|
+
new(code).valid?
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(code)
|
12
|
+
@code = code.to_s.gsub(/\s+/, '').upcase
|
13
|
+
end
|
14
|
+
|
15
|
+
def bank_code
|
16
|
+
@code[0..3]
|
17
|
+
end
|
18
|
+
|
19
|
+
def country_code
|
20
|
+
@code[4..5]
|
21
|
+
end
|
22
|
+
|
23
|
+
def location_code
|
24
|
+
@code[6..7]
|
25
|
+
end
|
26
|
+
|
27
|
+
def branch_code
|
28
|
+
@code[8..10]
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s(formatted = false)
|
32
|
+
formatted ? to_formatted_str : @code
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_formatted_str
|
36
|
+
"#{bank_code} #{country_code} #{location_code} #{branch_code}".strip
|
37
|
+
end
|
38
|
+
|
39
|
+
def test?
|
40
|
+
location_code[1] == '0'
|
41
|
+
end
|
42
|
+
|
43
|
+
def passive?
|
44
|
+
location_code[1] == '1'
|
45
|
+
end
|
46
|
+
|
47
|
+
def reverse_billing?
|
48
|
+
location_code[1] == '2'
|
49
|
+
end
|
50
|
+
|
51
|
+
def valid?
|
52
|
+
valid_format? && valid_location_code? && valid_branch_code?
|
53
|
+
end
|
54
|
+
|
55
|
+
def valid_format?
|
56
|
+
REGEX.match?(@code)
|
57
|
+
end
|
58
|
+
|
59
|
+
def valid_location_code?
|
60
|
+
!location_code.start_with?('0', '1') && !location_code.end_with?('O')
|
61
|
+
end
|
62
|
+
|
63
|
+
def valid_branch_code?
|
64
|
+
branch_code.empty? || branch_code == 'XXX' || !branch_code.start_with?('X')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/girocode/code.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
module Girocode
|
2
2
|
class Error < StandardError; end
|
3
|
-
|
3
|
+
|
4
4
|
class Code
|
5
5
|
ATTRIBUTES = %i[bic name iban currency amount purpose creditor_reference reference bto_info]
|
6
6
|
attr_reader *ATTRIBUTES
|
7
|
-
|
7
|
+
|
8
8
|
MAX_PAYLOAD_BYTES = 331
|
9
9
|
AMOUNT_RANGE = BigDecimal('0.01')..BigDecimal('999999999.99')
|
10
|
-
|
10
|
+
|
11
11
|
def initialize(**attrs)
|
12
12
|
if keys = attrs.keys - ATTRIBUTES and not keys.empty?
|
13
13
|
raise ArgumentError, "Illegal attributes #{keys.inspect}"
|
@@ -19,17 +19,17 @@ module Girocode
|
|
19
19
|
raise ArgumentError, "either creditor reference or reference may be set" if creditor_reference? && reference?
|
20
20
|
raise ArgumentError, "payload too long" if payload.bytesize > MAX_PAYLOAD_BYTES
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def bic=(value)
|
24
24
|
if value.nil?
|
25
25
|
@bic = nil
|
26
26
|
else
|
27
|
-
bic =
|
27
|
+
bic = BIC.new(value)
|
28
28
|
raise ArgumentError, "Invalid BIC #{value.inspect}" unless bic.valid?
|
29
29
|
@bic = bic.to_s
|
30
30
|
end
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
def name=(value)
|
34
34
|
value = value.strip
|
35
35
|
raise ArgumentError, 'name is required' unless value
|
@@ -37,81 +37,81 @@ module Girocode
|
|
37
37
|
raise ArgumentError, 'Illegal name' if value.include?("\n") || value.include?("\r")
|
38
38
|
@name = value
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
def iban=(value)
|
42
|
-
|
43
|
-
|
44
|
-
@iban =
|
42
|
+
raise ArgumentError, "Invalid IBAN #{value.inspect}" unless IBANTools::IBAN.valid?(value)
|
43
|
+
|
44
|
+
@iban = value
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
def currency=(value)
|
48
48
|
value = value.to_s.upcase
|
49
49
|
raise ArgumentError, "Invalid currency" unless value.match?(/\A[A-Z]{3}\z/)
|
50
50
|
@currency = value
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
def amount=(value)
|
54
54
|
raise ArgumentError, 'amount is required' unless value
|
55
55
|
value = BigDecimal(value, Float::DIG + 1)
|
56
56
|
raise ArgumentError, "invalid amount #{value.inspect}" unless AMOUNT_RANGE.cover?(value)
|
57
57
|
@amount = value
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
def purpose=(value)
|
61
61
|
unless value.nil?
|
62
62
|
raise ArgumentError, "invalid purpose #{value.inspect}" unless value.match?(/\A[A-z0-9]{0,4}\z/)
|
63
63
|
end
|
64
64
|
@purpose = value
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
def creditor_reference=(value)
|
68
68
|
unless value.nil?
|
69
69
|
raise ArgumentError, "invalid creditor reference #{value.inspect}" if value.include?("\n") || value.include?("\r") || value.size > 35
|
70
70
|
end
|
71
71
|
@creditor_reference = value
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
def reference=(value)
|
75
75
|
unless value.nil?
|
76
76
|
raise ArgumentError, "invalid reference #{value.inspect}" if value.include?("\n") || value.include?("\r") || value.size > 140
|
77
77
|
end
|
78
78
|
@reference = value
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
def bto_info=(value)
|
82
82
|
unless value.nil?
|
83
83
|
raise ArgumentError, "invalid bto_info #{value.inspect}" if value.include?("\n") || value.include?("\r") || value.size > 70
|
84
84
|
end
|
85
85
|
@bto_info = value
|
86
86
|
end
|
87
|
-
|
87
|
+
|
88
88
|
ATTRIBUTES.each do |attr|
|
89
89
|
define_method("#{attr}?") do
|
90
90
|
value = instance_variable_get("@#{attr}")
|
91
91
|
value.respond_to?(:empty?) ? !value.empty? : !!value
|
92
92
|
end
|
93
93
|
end
|
94
|
-
|
94
|
+
|
95
95
|
def payload
|
96
96
|
['BCD', '002', '1', 'SCT',
|
97
97
|
bic, name, iban,formatted_amount, purpose,
|
98
98
|
creditor_reference || reference, bto_info].map(&:to_s).join("\n")
|
99
99
|
end
|
100
|
-
|
100
|
+
|
101
101
|
def to_qrcode
|
102
102
|
RQRCode::QRCode.new(payload, level: :m, mode: :byte_8bit)
|
103
103
|
end
|
104
|
-
|
104
|
+
|
105
105
|
def to_ascii
|
106
106
|
to_qrcode.to_s
|
107
107
|
end
|
108
|
-
|
108
|
+
|
109
109
|
%i[png svg html ansi].each do |format|
|
110
110
|
define_method("to_#{format}") { |*args| to_qrcode.public_send("as_#{format}", *args) }
|
111
111
|
end
|
112
|
-
|
112
|
+
|
113
113
|
private
|
114
|
-
|
114
|
+
|
115
115
|
def formatted_amount
|
116
116
|
"#{currency}#{amount.round(2).to_s('F')}" if currency? && amount
|
117
117
|
end
|
data/lib/girocode/version.rb
CHANGED
data/lib/girocode.rb
CHANGED
metadata
CHANGED
@@ -1,17 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: girocode
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthias Grosser
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
13
|
+
name: bigdecimal
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
16
15
|
requirements:
|
17
16
|
- - ">="
|
@@ -25,7 +24,7 @@ dependencies:
|
|
25
24
|
- !ruby/object:Gem::Version
|
26
25
|
version: '0'
|
27
26
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
27
|
+
name: rqrcode
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
30
29
|
requirements:
|
31
30
|
- - ">="
|
@@ -39,55 +38,13 @@ dependencies:
|
|
39
38
|
- !ruby/object:Gem::Version
|
40
39
|
version: '0'
|
41
40
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '1.17'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '1.17'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: rake
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '10.0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '10.0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: minitest
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '5.0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '5.0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: simplecov
|
41
|
+
name: iban-tools
|
85
42
|
requirement: !ruby/object:Gem::Requirement
|
86
43
|
requirements:
|
87
44
|
- - ">="
|
88
45
|
- !ruby/object:Gem::Version
|
89
46
|
version: '0'
|
90
|
-
type: :
|
47
|
+
type: :runtime
|
91
48
|
prerelease: false
|
92
49
|
version_requirements: !ruby/object:Gem::Requirement
|
93
50
|
requirements:
|
@@ -101,17 +58,17 @@ executables: []
|
|
101
58
|
extensions: []
|
102
59
|
extra_rdoc_files: []
|
103
60
|
files:
|
61
|
+
- CHANGELOG.md
|
104
62
|
- LICENSE
|
105
63
|
- README.md
|
106
|
-
- Rakefile
|
107
64
|
- lib/girocode.rb
|
65
|
+
- lib/girocode/bic.rb
|
108
66
|
- lib/girocode/code.rb
|
109
67
|
- lib/girocode/version.rb
|
110
68
|
homepage: https://github.com/mtgrosser/girocode
|
111
69
|
licenses:
|
112
70
|
- MIT
|
113
71
|
metadata: {}
|
114
|
-
post_install_message:
|
115
72
|
rdoc_options: []
|
116
73
|
require_paths:
|
117
74
|
- lib
|
@@ -126,8 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
126
83
|
- !ruby/object:Gem::Version
|
127
84
|
version: '0'
|
128
85
|
requirements: []
|
129
|
-
rubygems_version: 3.
|
130
|
-
signing_key:
|
86
|
+
rubygems_version: 3.6.7
|
131
87
|
specification_version: 4
|
132
88
|
summary: Generate QR codes for SEPA credit transfers
|
133
89
|
test_files: []
|