sps_king 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +32 -0
  5. data/CONTRIBUTING.md +38 -0
  6. data/Gemfile +2 -0
  7. data/LICENSE.txt +24 -0
  8. data/README.md +246 -0
  9. data/Rakefile +6 -0
  10. data/gemfiles/Gemfile-activemodel-3.1.x +5 -0
  11. data/gemfiles/Gemfile-activemodel-3.2.x +5 -0
  12. data/gemfiles/Gemfile-activemodel-4.0.x +5 -0
  13. data/gemfiles/Gemfile-activemodel-4.1.x +5 -0
  14. data/gemfiles/Gemfile-activemodel-4.2.x +5 -0
  15. data/gemfiles/Gemfile-activemodel-5.0.x +5 -0
  16. data/gemfiles/Gemfile-activemodel-5.1.x +5 -0
  17. data/gemfiles/Gemfile-activemodel-5.2.x +5 -0
  18. data/lib/schema/pain.001.001.03.ch.02.xsd +1212 -0
  19. data/lib/schema/pain.008.001.02.ch.03.xsd +784 -0
  20. data/lib/sps_king.rb +22 -0
  21. data/lib/sps_king/account.rb +24 -0
  22. data/lib/sps_king/account/creditor_account.rb +11 -0
  23. data/lib/sps_king/account/creditor_address.rb +37 -0
  24. data/lib/sps_king/account/debtor_account.rb +5 -0
  25. data/lib/sps_king/account/debtor_address.rb +34 -0
  26. data/lib/sps_king/converter.rb +53 -0
  27. data/lib/sps_king/error.rb +4 -0
  28. data/lib/sps_king/message.rb +163 -0
  29. data/lib/sps_king/message/credit_transfer.rb +140 -0
  30. data/lib/sps_king/message/direct_debit.rb +177 -0
  31. data/lib/sps_king/structured_remittance_information.rb +20 -0
  32. data/lib/sps_king/transaction.rb +59 -0
  33. data/lib/sps_king/transaction/credit_transfer_transaction.rb +19 -0
  34. data/lib/sps_king/transaction/direct_debit_transaction.rb +58 -0
  35. data/lib/sps_king/validator.rb +55 -0
  36. data/lib/sps_king/version.rb +3 -0
  37. data/spec/examples/pain.001.001.03.ch.02.xml +172 -0
  38. data/spec/examples/pain.008.001.02.ch.03.xml +240 -0
  39. data/spec/lib/sps_king/account/creditor_account_spec.rb +52 -0
  40. data/spec/lib/sps_king/account/creditor_address_spec.rb +14 -0
  41. data/spec/lib/sps_king/account/debtor_account_spec.rb +14 -0
  42. data/spec/lib/sps_king/account/debtor_address_spec.rb +14 -0
  43. data/spec/lib/sps_king/account_spec.rb +42 -0
  44. data/spec/lib/sps_king/converter_spec.rb +88 -0
  45. data/spec/lib/sps_king/message/credit_transfer_spec.rb +350 -0
  46. data/spec/lib/sps_king/message/direct_debit_spec.rb +483 -0
  47. data/spec/lib/sps_king/message_spec.rb +128 -0
  48. data/spec/lib/sps_king/structured_remittance_information_spec.rb +32 -0
  49. data/spec/lib/sps_king/transaction/credit_transfer_transaction_spec.rb +53 -0
  50. data/spec/lib/sps_king/transaction/direct_debit_transaction_spec.rb +56 -0
  51. data/spec/lib/sps_king/transaction_spec.rb +133 -0
  52. data/spec/lib/sps_king/validation_spec.rb +23 -0
  53. data/spec/lib/sps_king/validator_spec.rb +78 -0
  54. data/spec/spec_helper.rb +33 -0
  55. data/spec/support/active_model.rb +30 -0
  56. data/spec/support/custom_matcher.rb +60 -0
  57. data/spec/support/factories.rb +33 -0
  58. data/spec/support/validations.rb +27 -0
  59. data/sps_king.gemspec +31 -0
  60. metadata +237 -0
@@ -0,0 +1,128 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ class DummyTransaction < SPS::Transaction
5
+ def valid?; true end
6
+ end
7
+
8
+ class DummyMessage < SPS::Message
9
+ self.account_class = SPS::Account
10
+ self.transaction_class = DummyTransaction
11
+ end
12
+
13
+ describe SPS::Message do
14
+ describe :amount_total do
15
+ subject do
16
+ message = DummyMessage.new
17
+ message.add_transaction amount: 1.1
18
+ message.add_transaction amount: 2.2
19
+ message
20
+ end
21
+
22
+ it 'should sum up all transactions' do
23
+ expect(subject.amount_total).to eq(3.3)
24
+ end
25
+
26
+ it 'should sum up selected transactions' do
27
+ expect(subject.amount_total([subject.transactions[0]])).to eq(1.1)
28
+ end
29
+ end
30
+
31
+ describe 'validation' do
32
+ subject { DummyMessage.new }
33
+
34
+ it 'should fail with invalid account' do
35
+ expect(subject).not_to be_valid
36
+ expect(subject.errors_on(:account).size).to eq(2)
37
+ end
38
+
39
+ it 'should fail without transactions' do
40
+ expect(subject).not_to be_valid
41
+ expect(subject.errors_on(:transactions).size).to eq(1)
42
+ end
43
+ end
44
+
45
+ describe :message_identification do
46
+ subject { DummyMessage.new }
47
+
48
+ describe 'getter' do
49
+ it 'should return prefixed random hex string' do
50
+ expect(subject.message_identification).to match(/SPS-KING\/([a-f0-9]{2}){11}/)
51
+ end
52
+ end
53
+
54
+ describe 'setter' do
55
+ it 'should accept valid ID' do
56
+ [ 'gid://myMoneyApp/Payment/15108', # for example, Rails Global ID could be a candidate
57
+ Time.now.to_f.to_s # or a time based string
58
+ ].each do |valid_msgid|
59
+ subject.message_identification = valid_msgid
60
+ expect(subject.message_identification).to eq(valid_msgid)
61
+ end
62
+ end
63
+
64
+ it 'should deny invalid string' do
65
+ [ 'my_MESSAGE_ID/123', # contains underscore
66
+ '', # blank string
67
+ 'üöäß', # non-ASCII chars
68
+ '1' * 36 # too long
69
+ ].each do |arg|
70
+ expect {
71
+ subject.message_identification = arg
72
+ }.to raise_error(ArgumentError)
73
+ end
74
+ end
75
+
76
+ it 'should deny argument other than String' do
77
+ [ 123,
78
+ nil,
79
+ :foo
80
+ ].each do |arg|
81
+ expect {
82
+ subject.message_identification = arg
83
+ }.to raise_error(ArgumentError)
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ describe :creation_date_time do
90
+ subject { DummyMessage.new }
91
+
92
+ describe 'getter' do
93
+ it 'should return Time.now.iso8601' do
94
+ expect(subject.creation_date_time).to eq(Time.now.iso8601)
95
+ end
96
+ end
97
+
98
+ describe 'setter' do
99
+ it 'should accept date time strings' do
100
+ ['2017-01-05T12:28:52', '2017-01-05T12:28:52Z', '2017-01-05 12:28:52', '2017-01-05T12:28:52+01:00'].each do |valid_dt|
101
+ subject.creation_date_time = valid_dt
102
+ expect(subject.creation_date_time).to eq(valid_dt)
103
+ end
104
+ end
105
+
106
+ it 'should deny invalid string' do
107
+ [ 'an arbitrary string',
108
+ ''
109
+ ].each do |arg|
110
+ expect {
111
+ subject.creation_date_time = arg
112
+ }.to raise_error(ArgumentError)
113
+ end
114
+ end
115
+
116
+ it 'should deny argument other than String' do
117
+ [ 123,
118
+ nil,
119
+ :foo
120
+ ].each do |arg|
121
+ expect {
122
+ subject.creation_date_time = arg
123
+ }.to raise_error(ArgumentError)
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe SPS::StructuredRemittanceInformation do
5
+ describe :new do
6
+ it 'should not accept unknown keys' do
7
+ expect {
8
+ SPS::StructuredRemittanceInformation.new foo: 'bar'
9
+ }.to raise_error(NoMethodError)
10
+ end
11
+ end
12
+
13
+ describe :proprietary do
14
+ it 'should accept valid value' do
15
+ expect(SPS::StructuredRemittanceInformation).to accept('ESR', 'IPI', for: :proprietary)
16
+ end
17
+
18
+ it 'should not accept invalid value' do
19
+ expect(SPS::StructuredRemittanceInformation).not_to accept(nil, 'something_else', for: :proprietary)
20
+ end
21
+ end
22
+
23
+ describe :reference do
24
+ it 'should accept valid value' do
25
+ expect(SPS::StructuredRemittanceInformation).to accept('a' * 35 , for: :reference)
26
+ end
27
+
28
+ it 'should not accept invalid value' do
29
+ expect(SPS::StructuredRemittanceInformation).not_to accept('', 'a' * 36, for: :reference)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe SPS::CreditTransferTransaction do
5
+ describe :initialize do
6
+ it 'should initialize a valid transaction' do
7
+ expect(
8
+ SPS::CreditTransferTransaction.new(
9
+ name: 'Contoso AG',
10
+ iban: 'CH5481230000001998736',
11
+ bic: 'RAIFCH22',
12
+ amount: 102.50,
13
+ reference: 'XYZ-1234/123',
14
+ remittance_information: 'Rechnung 123 vom 22.08.2013'
15
+ )
16
+ ).to be_valid
17
+ end
18
+ end
19
+
20
+ describe :schema_compatible? do
21
+ context 'for pain.001.001.03.ch.02' do
22
+ it 'should succeed for valid attributes' do
23
+ expect(SPS::CreditTransferTransaction.new(bic: 'RAIFCH22', currency: 'CHF'))
24
+ .to be_schema_compatible('pain.001.001.03.ch.02')
25
+ end
26
+
27
+ it 'should fail for invalid attributes' do
28
+ expect(SPS::CreditTransferTransaction.new(bic: nil))
29
+ .not_to be_schema_compatible('pain.001.001.03.ch.02')
30
+ end
31
+ end
32
+ end
33
+
34
+ context 'Requested date' do
35
+ it 'should allow valid value' do
36
+ expect(SPS::CreditTransferTransaction).to accept(nil, Date.new(1999, 1, 1), Date.today, Date.today.next, Date.today + 2, for: :requested_date)
37
+ end
38
+
39
+ it 'should not allow invalid value' do
40
+ expect(SPS::CreditTransferTransaction).not_to accept(Date.new(1995,12,21), Date.today - 1, for: :requested_date)
41
+ end
42
+ end
43
+
44
+ context 'Category Purpose' do
45
+ it 'should allow valid value' do
46
+ expect(SPS::CreditTransferTransaction).to accept(nil, 'SALA', 'X' * 4, for: :category_purpose)
47
+ end
48
+
49
+ it 'should not allow invalid value' do
50
+ expect(SPS::CreditTransferTransaction).not_to accept('', 'X' * 5, for: :category_purpose)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe SPS::DirectDebitTransaction do
5
+ let(:structured_remittance_information) do
6
+ SPS::StructuredRemittanceInformation.new(
7
+ proprietary: 'ESR',
8
+ reference: '609323234234234353453423423'
9
+ )
10
+ end
11
+
12
+ describe :initialize do
13
+ it 'should create a valid transaction' do
14
+ expect(
15
+ SPS::DirectDebitTransaction.new(
16
+ name: 'Zahlemann & Söhne Gbr',
17
+ iban: 'CH7081232000001998736',
18
+ amount: 39.99,
19
+ reference: 'XYZ-1234/123',
20
+ instruction: '123',
21
+ remittance_information: 'Vielen Dank für Ihren Einkauf!',
22
+ structured_remittance_information: structured_remittance_information
23
+ )
24
+ ).to be_valid
25
+ end
26
+ end
27
+
28
+ describe :schema_compatible? do
29
+ context 'for pain.008.001.02.ch.03' do
30
+ it 'should succeed for valid attributes' do
31
+ expect(
32
+ SPS::DirectDebitTransaction.new(
33
+ structured_remittance_information: structured_remittance_information
34
+ )
35
+ ).to be_schema_compatible('pain.008.001.02.ch.03')
36
+ end
37
+
38
+ it 'should fail for invalid attributes' do
39
+ expect(SPS::DirectDebitTransaction.new())
40
+ .not_to be_schema_compatible('pain.008.001.02.ch.03')
41
+ end
42
+ end
43
+ end
44
+
45
+ context 'Requested date' do
46
+ it 'should allow valid value' do
47
+ expect(SPS::DirectDebitTransaction)
48
+ .to accept(nil, Date.new(1999, 1, 1), Date.today.next, Date.today + 2, for: :requested_date)
49
+ end
50
+
51
+ it 'should not allow invalid value' do
52
+ expect(SPS::DirectDebitTransaction)
53
+ .not_to accept(Date.new(1995,12,21), Date.today - 1, Date.today, for: :requested_date)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,133 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe SPS::Transaction do
5
+ describe :new do
6
+ it 'should have default for reference' do
7
+ expect(SPS::Transaction.new.reference).to eq('NOTPROVIDED')
8
+ end
9
+
10
+ it 'should have default for requested_date' do
11
+ expect(SPS::Transaction.new.requested_date).to eq(Date.new(1999, 1, 1))
12
+ end
13
+
14
+ it 'should have default for batch_booking' do
15
+ expect(SPS::Transaction.new.batch_booking).to eq(true)
16
+ end
17
+ end
18
+
19
+ context 'Name' do
20
+ it 'should accept valid value' do
21
+ expect(SPS::Transaction).to accept('Manfred Mustermann III.', 'Zahlemann & Söhne GbR', 'X' * 70, for: :name)
22
+ end
23
+
24
+ it 'should not accept invalid value' do
25
+ expect(SPS::Transaction).not_to accept(nil, '', 'X' * 71, for: :name)
26
+ end
27
+ end
28
+
29
+ context 'Adress' do
30
+ context 'with address_line' do
31
+ it 'should accept valid value' do
32
+ expect(SPS::Transaction).to accept(SPS::DebtorAddress.new(
33
+ country_code: "CH",
34
+ address_line1: "Musterstrasse 123",
35
+ address_line2: "1234 Musterstadt"
36
+ ), for: :debtor_address)
37
+ end
38
+
39
+ it 'should accept valid value' do
40
+ expect(SPS::Transaction).to accept(SPS::CreditorAddress.new(
41
+ country_code: "CH",
42
+ address_line1: "Musterstrasse 123",
43
+ address_line2: "1234 Musterstadt"
44
+ ), for: :creditor_address)
45
+ end
46
+ end
47
+
48
+ context 'with individual address fields' do
49
+ it 'should accept valid value' do
50
+ expect(SPS::Transaction).to accept(SPS::DebtorAddress.new(
51
+ country_code: "CH",
52
+ street_name: 'Mustergasse',
53
+ post_code: '1234',
54
+ town_name: 'Musterstadt'
55
+ ), for: :debtor_address)
56
+ end
57
+
58
+ it 'should accept valid value' do
59
+ expect(SPS::Transaction).to accept(SPS::CreditorAddress.new(
60
+ country_code: "CH",
61
+ street_name: 'Mustergasse',
62
+ building_number: '123',
63
+ post_code: '1234',
64
+ town_name: 'Musterstadt'
65
+ ), for: :creditor_address)
66
+ end
67
+ end
68
+
69
+ it 'should not accept invalid value' do
70
+ expect(SPS::Transaction).not_to accept('', {} , for: :name)
71
+ end
72
+ end
73
+
74
+ context 'IBAN' do
75
+ it 'should accept valid value' do
76
+ expect(SPS::Transaction).to accept('DE21500500009876543210', 'PL61109010140000071219812874', for: :iban)
77
+ end
78
+
79
+ it 'should not accept invalid value' do
80
+ expect(SPS::Transaction).not_to accept(nil, '', 'invalid', for: :iban)
81
+ end
82
+ end
83
+
84
+ context 'BIC' do
85
+ it 'should accept valid value' do
86
+ expect(SPS::Transaction).to accept('DEUTDEFF', 'DEUTDEFF500', 'SPUEDE2UXXX', for: :bic)
87
+ end
88
+
89
+ it 'should not accept invalid value' do
90
+ expect(SPS::Transaction).not_to accept('', 'invalid', for: :bic)
91
+ end
92
+ end
93
+
94
+ context 'Amount' do
95
+ it 'should accept valid value' do
96
+ expect(SPS::Transaction).to accept(0.01, 1, 100, 100.00, 99.99, 1234567890.12, BigDecimal('10'), '42', '42.51', '42.512', 1.23456, for: :amount)
97
+ end
98
+
99
+ it 'should not accept invalid value' do
100
+ expect(SPS::Transaction).not_to accept(nil, 0, -3, 'xz', for: :amount)
101
+ end
102
+ end
103
+
104
+ context 'Reference' do
105
+ it 'should accept valid value' do
106
+ expect(SPS::Transaction).to accept(nil, 'ABC-1234/78.0', 'X' * 35, for: :reference)
107
+ end
108
+
109
+ it 'should not accept invalid value' do
110
+ expect(SPS::Transaction).not_to accept('', 'X' * 36, for: :reference)
111
+ end
112
+ end
113
+
114
+ context 'Remittance information' do
115
+ it 'should allow valid value' do
116
+ expect(SPS::Transaction).to accept(nil, 'Bonus', 'X' * 140, for: :remittance_information)
117
+ end
118
+
119
+ it 'should not allow invalid value' do
120
+ expect(SPS::Transaction).not_to accept('', 'X' * 141, for: :remittance_information)
121
+ end
122
+ end
123
+
124
+ context 'Currency' do
125
+ it 'should allow valid values' do
126
+ expect(SPS::Transaction).to accept('EUR', 'CHF', 'SEK', for: :currency)
127
+ end
128
+
129
+ it 'should not allow invalid values' do
130
+ expect(SPS::Transaction).not_to accept('', 'EURO', 'ABCDEF', for: :currency)
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Credit Transfer Initiation' do
4
+ it "should validate example file" do
5
+ expect(File.read('spec/examples/pain.001.001.03.ch.02.xml'))
6
+ .to validate_against('pain.001.001.03.ch.02.xsd')
7
+ end
8
+
9
+ it 'should not validate dummy string' do
10
+ expect('foo').not_to validate_against('pain.001.001.03.ch.02.xsd')
11
+ end
12
+ end
13
+
14
+ describe 'Direct Debit Initiation' do
15
+ it 'should validate example file' do
16
+ expect(File.read('spec/examples/pain.008.001.02.ch.03.xml'))
17
+ .to validate_against('pain.008.001.02.ch.03.xsd')
18
+ end
19
+
20
+ it 'should not validate dummy string' do
21
+ expect('foo').not_to validate_against('pain.008.001.02.ch.03.xsd')
22
+ end
23
+ end
@@ -0,0 +1,78 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe SPS::IBANValidator do
5
+ class Validatable
6
+ include ActiveModel::Model
7
+ attr_accessor :iban, :iban_the_terrible
8
+ validates_with SPS::IBANValidator, message: "%{value} seems wrong"
9
+ validates_with SPS::IBANValidator, field_name: :iban_the_terrible
10
+ end
11
+
12
+ it 'should accept valid IBAN' do
13
+ expect(Validatable)
14
+ .to accept('DE21500500009876543210', 'DE87200500001234567890', for: [:iban, :iban_the_terrible])
15
+ end
16
+
17
+ it 'should not accept an invalid IBAN' do
18
+ expect(Validatable).not_to accept('', 'xxx', # Oviously no IBAN
19
+ 'DE22500500009876543210', # wrong checksum
20
+ 'DE2150050000987654321', # too short
21
+ 'de87200500001234567890', # downcase characters
22
+ 'DE87 2005 0000 1234 5678 90', # spaces included
23
+ for: [:iban, :iban_the_terrible])
24
+ end
25
+
26
+ it "should customize error message" do
27
+ v = Validatable.new(:iban => 'xxx')
28
+ v.valid?
29
+ expect(v.errors[:iban]).to eq(['xxx seems wrong'])
30
+ end
31
+ end
32
+
33
+ describe SPS::BICValidator do
34
+ class Validatable
35
+ include ActiveModel::Model
36
+ attr_accessor :bic, :custom_bic
37
+ validates_with SPS::BICValidator, message: "%{value} seems wrong"
38
+ validates_with SPS::BICValidator, field_name: :custom_bic
39
+ end
40
+
41
+ it 'should accept valid BICs' do
42
+ expect(Validatable).to accept('DEUTDEDBDUE', 'DUSSDEDDXXX', for: [:bic, :custom_bic])
43
+ end
44
+
45
+ it 'should not accept an invalid BIC' do
46
+ expect(Validatable)
47
+ .not_to accept('', 'GENODE61HR', 'DEUTDEDBDUEDEUTDEDBDUE', for: [:bic, :custom_bic])
48
+ end
49
+
50
+ it "should customize error message" do
51
+ v = Validatable.new(:bic => 'xxx')
52
+ v.valid?
53
+ expect(v.errors[:bic]).to eq(['xxx seems wrong'])
54
+ end
55
+ end
56
+
57
+ describe SPS::CreditorIdentifierValidator do
58
+ class Validatable
59
+ include ActiveModel::Model
60
+ attr_accessor :creditor_identifier, :crid
61
+ validates_with SPS::CreditorIdentifierValidator, message: "%{value} seems wrong"
62
+ validates_with SPS::CreditorIdentifierValidator, field_name: :crid
63
+ end
64
+
65
+ it 'should accept valid creditor_identifier' do
66
+ expect(Validatable).to accept('DE98ZZZ09999999999', 'AT12ZZZ00000000001', 'FR12ZZZ123456', 'NL97ZZZ123456780001', 'ABC1W', for: [:creditor_identifier, :crid])
67
+ end
68
+
69
+ it 'should not accept an invalid creditor_identifier' do
70
+ expect(Validatable).not_to accept('', 'xxx', 'DE98ZZZ099999999990', for: [:creditor_identifier, :crid])
71
+ end
72
+
73
+ it "should customize error message" do
74
+ v = Validatable.new(:creditor_identifier => 'xxx')
75
+ v.valid?
76
+ expect(v.errors[:creditor_identifier]).to eq(['xxx seems wrong'])
77
+ end
78
+ end