sepa_king 0.1.0 → 0.2.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/.travis.yml +1 -0
- data/README.md +31 -1
- data/lib/sepa_king/message.rb +8 -6
- data/lib/sepa_king/transaction/credit_transfer_transaction.rb +6 -0
- data/lib/sepa_king/transaction/direct_debit_transaction.rb +10 -3
- data/lib/sepa_king/transaction.rb +0 -6
- data/lib/sepa_king/validator.rb +34 -8
- data/lib/sepa_king/version.rb +1 -1
- data/spec/credit_transfer_transaction_spec.rb +10 -0
- data/spec/direct_debit_transaction_spec.rb +3 -3
- data/spec/message_spec.rb +14 -1
- data/spec/spec_helper.rb +4 -0
- data/spec/support/custom_matcher.rb +18 -14
- data/spec/transaction_spec.rb +0 -10
- data/spec/validator_spec.rb +70 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c78e42fd31151e02569f9f54ee43fc82691ba3f9
|
4
|
+
data.tar.gz: 100d813077c65787e992689fe15eede1a7424f3d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7a1c98624cd47da6dfaffe4aa498a6a35f24c22b74abfc1f0f8fdb442c2603bea00a381df53ee6a9ef0fdd2d5d7fff32c366d7d49c4e95f22993fa5640079b1f
|
7
|
+
data.tar.gz: d72486654271db57e2a778cc396ec0183d998949eb19646720fbb4131e0ce2eb62901f4f807a4acecc3e88db471b9ce6bdbac4765c8779fda10f200fcd81b9bc
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -23,7 +23,7 @@ BTW: **pain** is a shortcut for **Pa**yment **In**itiation.
|
|
23
23
|
|
24
24
|
## Requirements
|
25
25
|
|
26
|
-
* Ruby 1.9.3 or
|
26
|
+
* Ruby 1.9.3 or newer
|
27
27
|
|
28
28
|
|
29
29
|
## Installation
|
@@ -194,6 +194,36 @@ xml_string = sct.to_xml # Use latest schema pain.001.003.03
|
|
194
194
|
xml_string = sct.to_xml('pain.001.002.03') # Use former schema pain.001.002.03
|
195
195
|
```
|
196
196
|
|
197
|
+
## Validations
|
198
|
+
|
199
|
+
You can rely on our internal validations, raising errors when needed, during
|
200
|
+
message creation.
|
201
|
+
To validate your models holding SEPA related information (e.g. BIC, IBAN,
|
202
|
+
mandate_id) you can use our validator classes or rely on some constants.
|
203
|
+
|
204
|
+
Examples:
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
class BankAccount < ActiveRecord::Base
|
208
|
+
# IBAN validation, by default it validates the attribute named "iban"
|
209
|
+
validates_with SEPA::IBANValidator, field_name: :iban_the_terrible
|
210
|
+
|
211
|
+
# BIC validation, by default it validates the attribute named "bic"
|
212
|
+
validates_with SEPA::BICValidator, field_name: :bank_bic
|
213
|
+
end
|
214
|
+
|
215
|
+
class Payment < ActiveRecord::Base
|
216
|
+
validates_inclusion_of :sepa_sequence_type, in: SEPA::DirectDebitTransaction::SEQUENCE_TYPES
|
217
|
+
|
218
|
+
# Mandate ID validation, by default it validates the attribute named "mandate_id"
|
219
|
+
validates_with SEPA::MandateIdentifierValidator, field_name: :mandate_id
|
220
|
+
end
|
221
|
+
```
|
222
|
+
|
223
|
+
Also see:
|
224
|
+
* [lib/sepa_king/validator.rb](https://github.com/salesking/sepa_king/blob/master/lib/sepa_king/validator.rb)
|
225
|
+
* [lib/sepa_king/transaction/direct_debit_transaction.rb](https://github.com/salesking/sepa_king/blob/master/lib/sepa_king/transaction/direct_debit_transaction.rb)
|
226
|
+
|
197
227
|
|
198
228
|
## Changelog
|
199
229
|
|
data/lib/sepa_king/message.rb
CHANGED
@@ -13,7 +13,7 @@ module SEPA
|
|
13
13
|
|
14
14
|
validates_presence_of :transactions
|
15
15
|
validate do |record|
|
16
|
-
record.errors.add(:account,
|
16
|
+
record.errors.add(:account, record.account.errors.full_messages) unless record.account.valid?
|
17
17
|
end
|
18
18
|
|
19
19
|
class_attribute :account_class, :transaction_class, :xml_main_tag, :known_schemas
|
@@ -59,6 +59,13 @@ module SEPA
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
+
attr_writer :message_identification # Set unique identifer for the message
|
63
|
+
|
64
|
+
# Unique identifer for the whole message
|
65
|
+
def message_identification
|
66
|
+
@message_identification ||= "SEPA-KING/#{Time.now.to_i}"
|
67
|
+
end
|
68
|
+
|
62
69
|
private
|
63
70
|
# @return {Hash<Symbol=>String>} xml schema information used in output xml
|
64
71
|
def xml_schema(schema_name)
|
@@ -79,11 +86,6 @@ module SEPA
|
|
79
86
|
end
|
80
87
|
end
|
81
88
|
|
82
|
-
# Unique identifer for the whole message
|
83
|
-
def message_identification
|
84
|
-
@message_identification ||= "SEPA-KING/#{Time.now.to_i}"
|
85
|
-
end
|
86
|
-
|
87
89
|
# Unique and consecutive identifier (used for the <PmntInf> blocks)
|
88
90
|
def payment_information_identification
|
89
91
|
@payment_information_counter ||= 0
|
@@ -5,6 +5,12 @@ module SEPA
|
|
5
5
|
|
6
6
|
validates_inclusion_of :service_level, :in => %w(SEPA URGP)
|
7
7
|
|
8
|
+
validate do |t|
|
9
|
+
if t.requested_date.is_a?(Date)
|
10
|
+
errors.add(:requested_date, 'is in the past') if t.requested_date < Date.today
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
8
14
|
def initialize(attributes = {})
|
9
15
|
super
|
10
16
|
self.service_level ||= 'SEPA'
|
@@ -1,12 +1,15 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module SEPA
|
3
3
|
class DirectDebitTransaction < Transaction
|
4
|
+
SEQUENCE_TYPES = %w(FRST OOFF RCUR FNAL)
|
5
|
+
LOCAL_INSTRUMENTS = %w(CORE COR1 B2B)
|
6
|
+
|
4
7
|
attr_accessor :mandate_id, :mandate_date_of_signature, :local_instrument, :sequence_type, :creditor_account
|
5
8
|
|
6
|
-
|
9
|
+
validates_with MandateIdentifierValidator, field_name: :mandate_id
|
7
10
|
validates_presence_of :mandate_date_of_signature
|
8
|
-
validates_inclusion_of :local_instrument, :
|
9
|
-
validates_inclusion_of :sequence_type, :
|
11
|
+
validates_inclusion_of :local_instrument, in: LOCAL_INSTRUMENTS
|
12
|
+
validates_inclusion_of :sequence_type, in: SEQUENCE_TYPES
|
10
13
|
|
11
14
|
validate do |t|
|
12
15
|
if creditor_account
|
@@ -18,6 +21,10 @@ module SEPA
|
|
18
21
|
else
|
19
22
|
errors.add(:mandate_date_of_signature, 'is not a Date')
|
20
23
|
end
|
24
|
+
|
25
|
+
if t.requested_date.is_a?(Date)
|
26
|
+
errors.add(:requested_date, 'is not in the future') if t.requested_date <= Date.today
|
27
|
+
end
|
21
28
|
end
|
22
29
|
|
23
30
|
def initialize(attributes = {})
|
@@ -16,12 +16,6 @@ module SEPA
|
|
16
16
|
validates_inclusion_of :batch_booking, :in => [true, false]
|
17
17
|
validates_with BICValidator, IBANValidator
|
18
18
|
|
19
|
-
validate do |t|
|
20
|
-
if t.requested_date.is_a?(Date)
|
21
|
-
errors.add(:requested_date, 'is not in the future') if t.requested_date <= Date.today
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
19
|
def initialize(attributes = {})
|
26
20
|
attributes.each do |name, value|
|
27
21
|
send("#{name}=", value)
|
data/lib/sepa_king/validator.rb
CHANGED
@@ -2,31 +2,44 @@
|
|
2
2
|
module SEPA
|
3
3
|
class IBANValidator < ActiveModel::Validator
|
4
4
|
def validate(record)
|
5
|
-
|
6
|
-
|
5
|
+
field_name = options[:field_name] || :iban
|
6
|
+
value = record.send(field_name)
|
7
|
+
|
8
|
+
unless IBANTools::IBAN.valid?(value.to_s)
|
9
|
+
record.errors.add(field_name, :invalid)
|
7
10
|
end
|
8
11
|
end
|
9
12
|
end
|
10
13
|
|
11
14
|
class BICValidator < ActiveModel::Validator
|
15
|
+
REGEX = /\A[A-Z]{6,6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3,3}){0,1}\z/
|
16
|
+
|
12
17
|
def validate(record)
|
13
|
-
|
14
|
-
|
15
|
-
|
18
|
+
field_name = options[:field_name] || :bic
|
19
|
+
value = record.send(field_name)
|
20
|
+
|
21
|
+
if value
|
22
|
+
unless value.to_s.match(REGEX)
|
23
|
+
record.errors.add(field_name, :invalid)
|
16
24
|
end
|
17
25
|
end
|
18
26
|
end
|
19
27
|
end
|
20
28
|
|
21
29
|
class CreditorIdentifierValidator < ActiveModel::Validator
|
30
|
+
REGEX = /\A[a-zA-Z]{2,2}[0-9]{2,2}([A-Za-z0-9]|[\+|\?|\/|\-|\:|\(|\)|\.|,|']){3,3}([A-Za-z0-9]|[\+|\?|\/|\-|:|\(|\)|\.|,|']){1,28}\z/
|
31
|
+
|
22
32
|
def validate(record)
|
23
|
-
|
24
|
-
|
33
|
+
field_name = options[:field_name] || :creditor_identifier
|
34
|
+
value = record.send(field_name)
|
35
|
+
|
36
|
+
unless valid?(value)
|
37
|
+
record.errors.add(field_name, :invalid)
|
25
38
|
end
|
26
39
|
end
|
27
40
|
|
28
41
|
def valid?(creditor_identifier)
|
29
|
-
if ok = creditor_identifier.to_s.match(
|
42
|
+
if ok = creditor_identifier.to_s.match(REGEX)
|
30
43
|
# In Germany, the identifier has to be exactly 18 chars long
|
31
44
|
if creditor_identifier[0..1].match(/DE/i)
|
32
45
|
ok = creditor_identifier.length == 18
|
@@ -35,4 +48,17 @@ module SEPA
|
|
35
48
|
ok
|
36
49
|
end
|
37
50
|
end
|
51
|
+
|
52
|
+
class MandateIdentifierValidator < ActiveModel::Validator
|
53
|
+
REGEX = /\A([A-Za-z0-9]|[\+|\?|\/|\-|\:|\(|\)|\.|\,|\']){1,35}\z/
|
54
|
+
|
55
|
+
def validate(record)
|
56
|
+
field_name = options[:field_name] || :mandate_id
|
57
|
+
value = record.send(field_name)
|
58
|
+
|
59
|
+
unless value.to_s.match(REGEX)
|
60
|
+
record.errors.add(field_name, :invalid)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
38
64
|
end
|
data/lib/sepa_king/version.rb
CHANGED
@@ -33,4 +33,14 @@ describe SEPA::CreditTransferTransaction do
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
36
|
+
|
37
|
+
context 'Requested date' do
|
38
|
+
it 'should allow valid value' do
|
39
|
+
SEPA::CreditTransferTransaction.should accept(nil, Date.today, Date.today.next, Date.today + 2, for: :requested_date)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should not allow invalid value' do
|
43
|
+
SEPA::CreditTransferTransaction.should_not accept(Date.new(1995,12,21), Date.today - 1, for: :requested_date)
|
44
|
+
end
|
45
|
+
end
|
36
46
|
end
|
@@ -46,13 +46,13 @@ describe SEPA::DirectDebitTransaction do
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
context '
|
49
|
+
context 'Requested date' do
|
50
50
|
it 'should allow valid value' do
|
51
|
-
SEPA::DirectDebitTransaction.should accept(
|
51
|
+
SEPA::DirectDebitTransaction.should accept(nil, Date.today.next, Date.today + 2, for: :requested_date)
|
52
52
|
end
|
53
53
|
|
54
54
|
it 'should not allow invalid value' do
|
55
|
-
SEPA::DirectDebitTransaction.should_not accept(
|
55
|
+
SEPA::DirectDebitTransaction.should_not accept(Date.new(1995,12,21), Date.today - 1, Date.today, for: :requested_date)
|
56
56
|
end
|
57
57
|
end
|
58
58
|
end
|
data/spec/message_spec.rb
CHANGED
@@ -33,7 +33,7 @@ describe SEPA::Message do
|
|
33
33
|
|
34
34
|
it 'should fail with invalid account' do
|
35
35
|
subject.should_not be_valid
|
36
|
-
subject.should have(
|
36
|
+
subject.should have(2).error_on(:account)
|
37
37
|
end
|
38
38
|
|
39
39
|
it 'should fail without transactions' do
|
@@ -41,4 +41,17 @@ describe SEPA::Message do
|
|
41
41
|
subject.should have(1).error_on(:transactions)
|
42
42
|
end
|
43
43
|
end
|
44
|
+
|
45
|
+
describe :message_identification do
|
46
|
+
subject { DummyMessage.new }
|
47
|
+
|
48
|
+
it 'should have a reader method' do
|
49
|
+
subject.message_identification.should match(/SEPA-KING\/[0-9]+/)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should have a writer method' do
|
53
|
+
subject.message_identification = "MY_MESSAGE_ID/#{Time.now.to_i}"
|
54
|
+
subject.message_identification.should match(/MY_MESSAGE_ID/)
|
55
|
+
end
|
56
|
+
end
|
44
57
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -16,6 +16,10 @@ end
|
|
16
16
|
|
17
17
|
require 'sepa_king'
|
18
18
|
|
19
|
+
if I18n.respond_to?(:enforce_available_locales=)
|
20
|
+
I18n.enforce_available_locales = false
|
21
|
+
end
|
22
|
+
|
19
23
|
# Requires supporting ruby files with custom matchers and macros, etc,
|
20
24
|
# in spec/support/ and its subdirectories.
|
21
25
|
Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
|
@@ -36,21 +36,25 @@ RSpec::Matchers.define :have_xml do |xpath, text|
|
|
36
36
|
end
|
37
37
|
|
38
38
|
RSpec::Matchers.define :accept do |*values, options|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
39
|
+
attributes = Array(options[:for])
|
40
|
+
|
41
|
+
attributes.each do |attribute|
|
42
|
+
match_for_should do |actual|
|
43
|
+
values.all? { |value|
|
44
|
+
expect(
|
45
|
+
actual.new(attribute => value)
|
46
|
+
).to have(:no).errors_on(attribute)
|
47
|
+
}
|
48
|
+
end
|
47
49
|
end
|
48
50
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
attributes.each do |attribute|
|
52
|
+
match_for_should_not do |actual|
|
53
|
+
values.all? { |value|
|
54
|
+
expect(
|
55
|
+
actual.new(attribute => value)
|
56
|
+
).to have_at_least(1).errors_on(attribute)
|
57
|
+
}
|
58
|
+
end
|
55
59
|
end
|
56
60
|
end
|
data/spec/transaction_spec.rb
CHANGED
@@ -75,14 +75,4 @@ describe SEPA::Transaction do
|
|
75
75
|
SEPA::Transaction.should_not accept('', 'X' * 141, for: :remittance_information)
|
76
76
|
end
|
77
77
|
end
|
78
|
-
|
79
|
-
context 'Requested date' do
|
80
|
-
it 'should allow valid value' do
|
81
|
-
SEPA::Transaction.should accept(nil, Date.today.next, Date.today + 2, for: :requested_date)
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'should not allow invalid value' do
|
85
|
-
SEPA::Transaction.should_not accept(Date.new(1995,12,21), Date.today - 1, Date.today, for: :requested_date)
|
86
|
-
end
|
87
|
-
end
|
88
78
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe SEPA::IBANValidator do
|
5
|
+
class Validatable
|
6
|
+
include ActiveModel::Model
|
7
|
+
attr_accessor :iban, :iban_the_terrible
|
8
|
+
validates_with SEPA::IBANValidator
|
9
|
+
validates_with SEPA::IBANValidator, field_name: :iban_the_terrible
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should accept valid IBAN' do
|
13
|
+
Validatable.should accept('DE21500500009876543210', 'DE87200500001234567890', for: [:iban, :iban_the_terrible])
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should not accept an invalid IBAN' do
|
17
|
+
Validatable.should_not accept('', 'xxx', 'DE22500500009876543210', 'DE2150050000987654321', for: [:iban, :iban_the_terrible])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe SEPA::BICValidator do
|
22
|
+
class Validatable
|
23
|
+
include ActiveModel::Model
|
24
|
+
attr_accessor :bic, :custom_bic
|
25
|
+
validates_with SEPA::BICValidator
|
26
|
+
validates_with SEPA::BICValidator, field_name: :custom_bic
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should accept valid BICs' do
|
30
|
+
Validatable.should accept('DEUTDEDBDUE', 'DUSSDEDDXXX', for: [:bic, :custom_bic])
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should not accept an invalid BIC' do
|
34
|
+
Validatable.should_not accept('', 'GENODE61HR', 'DEUTDEDBDUEDEUTDEDBDUE', for: [:bic, :custom_bic])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe SEPA::CreditorIdentifierValidator do
|
39
|
+
class Validatable
|
40
|
+
include ActiveModel::Model
|
41
|
+
attr_accessor :creditor_identifier, :crid
|
42
|
+
validates_with SEPA::CreditorIdentifierValidator
|
43
|
+
validates_with SEPA::CreditorIdentifierValidator, field_name: :crid
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should accept valid creditor_identifier' do
|
47
|
+
Validatable.should accept('DE98ZZZ09999999999', 'AT12ZZZ00000000001', 'FR12ZZZ123456', 'NL97ZZZ123456780001', for: [:creditor_identifier, :crid])
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should not accept an invalid creditor_identifier' do
|
51
|
+
Validatable.should_not accept('', 'xxx', 'DE98ZZZ099999999990', for: [:creditor_identifier, :crid])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe SEPA::MandateIdentifierValidator do
|
56
|
+
class Validatable
|
57
|
+
include ActiveModel::Model
|
58
|
+
attr_accessor :mandate_id, :mid
|
59
|
+
validates_with SEPA::MandateIdentifierValidator
|
60
|
+
validates_with SEPA::MandateIdentifierValidator, field_name: :mid
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should accept valid mandate_identifier' do
|
64
|
+
Validatable.should accept('XYZ-123', "+?/-:().,'", 'X' * 35, for: [:mandate_id, :mid])
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should not accept an invalid mandate_identifier' do
|
68
|
+
Validatable.should_not accept(nil, '', 'X' * 36, 'ABC 123', '#/*', 'Ümläüt', for: [:mandate_id, :mid])
|
69
|
+
end
|
70
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sepa_king
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Georg Leciejewski
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-02-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activemodel
|
@@ -204,6 +204,7 @@ files:
|
|
204
204
|
- spec/support/validations.rb
|
205
205
|
- spec/transaction_spec.rb
|
206
206
|
- spec/validation_spec.rb
|
207
|
+
- spec/validator_spec.rb
|
207
208
|
homepage: http://github.com/salesking/sepa_king
|
208
209
|
licenses:
|
209
210
|
- MIT
|
@@ -224,7 +225,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
224
225
|
version: '0'
|
225
226
|
requirements: []
|
226
227
|
rubyforge_project:
|
227
|
-
rubygems_version: 2.
|
228
|
+
rubygems_version: 2.2.2
|
228
229
|
signing_key:
|
229
230
|
specification_version: 4
|
230
231
|
summary: Ruby gem for creating SEPA XML files
|
@@ -248,3 +249,4 @@ test_files:
|
|
248
249
|
- spec/support/validations.rb
|
249
250
|
- spec/transaction_spec.rb
|
250
251
|
- spec/validation_spec.rb
|
252
|
+
- spec/validator_spec.rb
|