sps_king 0.1.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.
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