sepa_king_codeur 0.12.1

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 (67) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +37 -0
  5. data/CONTRIBUTING.md +38 -0
  6. data/Gemfile +2 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +297 -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/gemfiles/Gemfile-activemodel-6.0.x +5 -0
  19. data/lib/schema/pain.001.001.03.ch.02.xsd +1212 -0
  20. data/lib/schema/pain.001.001.03.xsd +921 -0
  21. data/lib/schema/pain.001.002.03.xsd +450 -0
  22. data/lib/schema/pain.001.003.03.xsd +474 -0
  23. data/lib/schema/pain.008.001.02.xsd +879 -0
  24. data/lib/schema/pain.008.002.02.xsd +597 -0
  25. data/lib/schema/pain.008.003.02.xsd +614 -0
  26. data/lib/sepa_king.rb +19 -0
  27. data/lib/sepa_king/account.rb +19 -0
  28. data/lib/sepa_king/account/creditor_account.rb +8 -0
  29. data/lib/sepa_king/account/creditor_address.rb +37 -0
  30. data/lib/sepa_king/account/debtor_account.rb +5 -0
  31. data/lib/sepa_king/account/debtor_address.rb +37 -0
  32. data/lib/sepa_king/converter.rb +51 -0
  33. data/lib/sepa_king/error.rb +4 -0
  34. data/lib/sepa_king/message.rb +169 -0
  35. data/lib/sepa_king/message/credit_transfer.rb +137 -0
  36. data/lib/sepa_king/message/direct_debit.rb +207 -0
  37. data/lib/sepa_king/transaction.rb +56 -0
  38. data/lib/sepa_king/transaction/credit_transfer_transaction.rb +31 -0
  39. data/lib/sepa_king/transaction/direct_debit_transaction.rb +56 -0
  40. data/lib/sepa_king/validator.rb +57 -0
  41. data/lib/sepa_king/version.rb +3 -0
  42. data/sepa_king.gemspec +33 -0
  43. data/spec/account_spec.rb +42 -0
  44. data/spec/converter_spec.rb +74 -0
  45. data/spec/credit_transfer_spec.rb +520 -0
  46. data/spec/credit_transfer_transaction_spec.rb +74 -0
  47. data/spec/creditor_account_spec.rb +23 -0
  48. data/spec/debtor_account_spec.rb +12 -0
  49. data/spec/debtor_address_spec.rb +12 -0
  50. data/spec/direct_debit_spec.rb +657 -0
  51. data/spec/direct_debit_transaction_spec.rb +69 -0
  52. data/spec/examples/pain.001.001.03.ch.02.xml +172 -0
  53. data/spec/examples/pain.001.001.03.xml +89 -0
  54. data/spec/examples/pain.001.002.03.xml +89 -0
  55. data/spec/examples/pain.001.003.03.xml +89 -0
  56. data/spec/examples/pain.008.002.02.xml +134 -0
  57. data/spec/examples/pain.008.003.02.xml +134 -0
  58. data/spec/message_spec.rb +128 -0
  59. data/spec/spec_helper.rb +33 -0
  60. data/spec/support/active_model.rb +30 -0
  61. data/spec/support/custom_matcher.rb +60 -0
  62. data/spec/support/factories.rb +24 -0
  63. data/spec/support/validations.rb +27 -0
  64. data/spec/transaction_spec.rb +134 -0
  65. data/spec/validation_spec.rb +25 -0
  66. data/spec/validator_spec.rb +99 -0
  67. metadata +250 -0
@@ -0,0 +1,74 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe SEPA::CreditTransferTransaction do
5
+ describe :initialize do
6
+ it 'should initialize a valid transaction' do
7
+ expect(
8
+ SEPA::CreditTransferTransaction.new name: 'Telekomiker AG',
9
+ iban: 'DE37112589611964645802',
10
+ bic: 'PBNKDEFF370',
11
+ amount: 102.50,
12
+ reference: 'XYZ-1234/123',
13
+ remittance_information: 'Rechnung 123 vom 22.08.2013'
14
+ ).to be_valid
15
+ end
16
+ end
17
+
18
+ describe :schema_compatible? do
19
+ context 'for pain.001.003.03' do
20
+ it 'should succeed' do
21
+ expect(SEPA::CreditTransferTransaction.new({})).to be_schema_compatible('pain.001.003.03')
22
+ end
23
+
24
+ it 'should fail for invalid attributes' do
25
+ expect(SEPA::CreditTransferTransaction.new(:currency => 'CHF')).not_to be_schema_compatible('pain.001.003.03')
26
+ end
27
+ end
28
+
29
+ context 'pain.001.002.03' do
30
+ it 'should succeed for valid attributes' do
31
+ expect(SEPA::CreditTransferTransaction.new(:bic => 'SPUEDE2UXXX', :service_level => 'SEPA')).to be_schema_compatible('pain.001.002.03')
32
+ end
33
+
34
+ it 'should fail for invalid attributes' do
35
+ expect(SEPA::CreditTransferTransaction.new(:bic => nil)).not_to be_schema_compatible('pain.001.002.03')
36
+ expect(SEPA::CreditTransferTransaction.new(:bic => 'SPUEDE2UXXX', :service_level => 'URGP')).not_to be_schema_compatible('pain.001.002.03')
37
+ expect(SEPA::CreditTransferTransaction.new(:bic => 'SPUEDE2UXXX', :currency => 'CHF')).not_to be_schema_compatible('pain.001.002.03')
38
+ end
39
+ end
40
+
41
+ context 'for pain.001.001.03' do
42
+ it 'should succeed for valid attributes' do
43
+ expect(SEPA::CreditTransferTransaction.new(:bic => 'SPUEDE2UXXX', :currency => 'CHF')).to be_schema_compatible('pain.001.001.03')
44
+ expect(SEPA::CreditTransferTransaction.new(:bic => nil)).to be_schema_compatible('pain.001.003.03')
45
+ end
46
+ end
47
+
48
+ context 'for pain.001.001.03.ch.02' do
49
+ it 'should succeed for valid attributes' do
50
+ expect(SEPA::CreditTransferTransaction.new(:bic => 'SPUEDE2UXXX', :currency => 'CHF')).to be_schema_compatible('pain.001.001.03.ch.02')
51
+ end
52
+ end
53
+ end
54
+
55
+ context 'Requested date' do
56
+ it 'should allow valid value' do
57
+ expect(SEPA::CreditTransferTransaction).to accept(nil, Date.new(1999, 1, 1), Date.today, Date.today.next, Date.today + 2, for: :requested_date)
58
+ end
59
+
60
+ it 'should not allow invalid value' do
61
+ expect(SEPA::CreditTransferTransaction).not_to accept(Date.new(1995,12,21), Date.today - 1, for: :requested_date)
62
+ end
63
+ end
64
+
65
+ context 'Category Purpose' do
66
+ it 'should allow valid value' do
67
+ expect(SEPA::CreditTransferTransaction).to accept(nil, 'SALA', 'X' * 4, for: :category_purpose)
68
+ end
69
+
70
+ it 'should not allow invalid value' do
71
+ expect(SEPA::CreditTransferTransaction).not_to accept('', 'X' * 5, for: :category_purpose)
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe SEPA::CreditorAccount do
5
+ it 'should initialize a new account' do
6
+ expect(
7
+ SEPA::CreditorAccount.new name: 'Gläubiger GmbH',
8
+ bic: 'BANKDEFFXXX',
9
+ iban: 'DE87200500001234567890',
10
+ creditor_identifier: 'DE98ZZZ09999999999'
11
+ ).to be_valid
12
+ end
13
+
14
+ describe :creditor_identifier do
15
+ it 'should accept valid value' do
16
+ expect(SEPA::CreditorAccount).to accept('DE98ZZZ09999999999', 'AT12ZZZ00000000001', 'IT97ZZZA1B2C3D4E5F6G7H8', 'NL97ZZZ123456780001', 'FR12ZZZ123456', for: :creditor_identifier)
17
+ end
18
+
19
+ it 'should not accept invalid value' do
20
+ expect(SEPA::CreditorAccount).not_to accept('', 'invalid', 'DE98ZZZ099999999990', 'DEAAAAAAAAAAAAAAAA', for: :creditor_identifier)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe SEPA::DebtorAccount do
5
+ it 'should initialize a new account' do
6
+ expect(
7
+ SEPA::DebtorAccount.new name: 'Gläubiger GmbH',
8
+ bic: 'BANKDEFFXXX',
9
+ iban: 'DE87200500001234567890'
10
+ ).to be_valid
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe SEPA::DebtorAddress do
5
+ it 'should initialize a new address' do
6
+ expect(
7
+ SEPA::DebtorAddress.new country_code: 'CH',
8
+ address_line1: 'Mustergasse 123',
9
+ address_line2: '12345 Musterstadt'
10
+ ).to be_valid
11
+ end
12
+ end
@@ -0,0 +1,657 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe SEPA::DirectDebit do
5
+ let(:message_id_regex) { /SEPA-KING\/[0-9a-z_]{22}/ }
6
+
7
+ let(:direct_debit) {
8
+ SEPA::DirectDebit.new name: 'Gläubiger GmbH',
9
+ bic: 'BANKDEFFXXX',
10
+ iban: 'DE87200500001234567890',
11
+ creditor_identifier: 'DE98ZZZ09999999999'
12
+ }
13
+
14
+ describe :new do
15
+ it 'should accept missing options' do
16
+ expect {
17
+ SEPA::DirectDebit.new
18
+ }.to_not raise_error
19
+ end
20
+ end
21
+
22
+ describe :add_transaction do
23
+ it 'should add valid transactions' do
24
+ 3.times do
25
+ direct_debit.add_transaction(direct_debt_transaction)
26
+ end
27
+
28
+ expect(direct_debit.transactions.size).to eq(3)
29
+ end
30
+
31
+ it 'should fail for invalid transaction' do
32
+ expect {
33
+ direct_debit.add_transaction name: ''
34
+ }.to raise_error(ArgumentError)
35
+ end
36
+ end
37
+
38
+ describe :batch_id do
39
+ it 'returns the id of the batch where the given transactions belongs to (1 batch)' do
40
+ direct_debit.add_transaction(direct_debt_transaction(reference: "EXAMPLE REFERENCE"))
41
+
42
+ expect(direct_debit.batch_id("EXAMPLE REFERENCE")).to match(/#{message_id_regex}\/1/)
43
+ end
44
+
45
+ it 'returns the id of the batch where the given transactions belongs to (2 batches)' do
46
+ direct_debit.add_transaction(direct_debt_transaction(reference: "EXAMPLE REFERENCE 1"))
47
+ direct_debit.add_transaction(direct_debt_transaction(reference: "EXAMPLE REFERENCE 2", requested_date: Date.today.next.next))
48
+ direct_debit.add_transaction(direct_debt_transaction(reference: "EXAMPLE REFERENCE 3"))
49
+
50
+ expect(direct_debit.batch_id("EXAMPLE REFERENCE 1")).to match(/#{message_id_regex}\/1/)
51
+ expect(direct_debit.batch_id("EXAMPLE REFERENCE 2")).to match(/#{message_id_regex}\/2/)
52
+ expect(direct_debit.batch_id("EXAMPLE REFERENCE 3")).to match(/#{message_id_regex}\/1/)
53
+ end
54
+ end
55
+
56
+ describe :batches do
57
+ it 'returns an array of batch ids in the sepa message' do
58
+ direct_debit.add_transaction(direct_debt_transaction(reference: "EXAMPLE REFERENCE 1"))
59
+ direct_debit.add_transaction(direct_debt_transaction(reference: "EXAMPLE REFERENCE 2", requested_date: Date.today.next.next))
60
+ direct_debit.add_transaction(direct_debt_transaction(reference: "EXAMPLE REFERENCE 3"))
61
+
62
+ expect(direct_debit.batches.size).to eq(2)
63
+ expect(direct_debit.batches[0]).to match(/#{message_id_regex}\/[0-9]+/)
64
+ expect(direct_debit.batches[1]).to match(/#{message_id_regex}\/[0-9]+/)
65
+ end
66
+ end
67
+
68
+ describe :to_xml do
69
+ context 'for invalid creditor' do
70
+ it 'should fail' do
71
+ expect {
72
+ SEPA::DirectDebit.new.to_xml
73
+ }.to raise_error(SEPA::Error)
74
+ end
75
+ end
76
+
77
+ context 'setting debtor address with adrline' do
78
+ subject do
79
+ sdd = SEPA::DirectDebit.new name: 'Gläubiger GmbH',
80
+ iban: 'DE87200500001234567890',
81
+ creditor_identifier: 'DE98ZZZ09999999999'
82
+
83
+ sda = SEPA::DebtorAddress.new country_code: 'CH',
84
+ address_line1: 'Mustergasse 123',
85
+ address_line2: '1234 Musterstadt'
86
+
87
+ sdd.add_transaction name: 'Zahlemann & Söhne GbR',
88
+ bic: 'SPUEDE2UXXX',
89
+ iban: 'DE21500500009876543210',
90
+ amount: 39.99,
91
+ reference: 'XYZ/2013-08-ABO/12345',
92
+ remittance_information: 'Unsere Rechnung vom 10.08.2013',
93
+ mandate_id: 'K-02-2011-12345',
94
+ debtor_address: sda,
95
+ mandate_date_of_signature: Date.new(2011,1,25)
96
+
97
+ sdd
98
+ end
99
+
100
+ it 'should validate against pain.008.003.02' do
101
+ expect(subject.to_xml(SEPA::PAIN_008_003_02)).to validate_against('pain.008.003.02.xsd')
102
+ end
103
+ end
104
+
105
+ context 'setting debtor address with structured fields' do
106
+ subject do
107
+ sdd = SEPA::DirectDebit.new name: 'Gläubiger GmbH',
108
+ iban: 'DE87200500001234567890',
109
+ creditor_identifier: 'DE98ZZZ09999999999'
110
+
111
+ sda = SEPA::DebtorAddress.new country_code: 'CH',
112
+ street_name: 'Mustergasse',
113
+ building_number: '123',
114
+ post_code: '1234',
115
+ town_name: 'Musterstadt'
116
+
117
+ sdd.add_transaction name: 'Zahlemann & Söhne GbR',
118
+ bic: 'SPUEDE2UXXX',
119
+ iban: 'DE21500500009876543210',
120
+ amount: 39.99,
121
+ reference: 'XYZ/2013-08-ABO/12345',
122
+ remittance_information: 'Unsere Rechnung vom 10.08.2013',
123
+ mandate_id: 'K-02-2011-12345',
124
+ debtor_address: sda,
125
+ mandate_date_of_signature: Date.new(2011,1,25)
126
+
127
+ sdd
128
+ end
129
+
130
+ it 'should validate against pain.008.001.02' do
131
+ expect(subject.to_xml(SEPA::PAIN_008_001_02)).to validate_against('pain.008.001.02.xsd')
132
+ end
133
+ end
134
+
135
+ context 'for valid creditor' do
136
+ context 'without BIC (IBAN-only)' do
137
+ subject do
138
+ sdd = SEPA::DirectDebit.new name: 'Gläubiger GmbH',
139
+ iban: 'DE87200500001234567890',
140
+ creditor_identifier: 'DE98ZZZ09999999999'
141
+
142
+ sdd.add_transaction name: 'Zahlemann & Söhne GbR',
143
+ bic: 'SPUEDE2UXXX',
144
+ iban: 'DE21500500009876543210',
145
+ amount: 39.99,
146
+ reference: 'XYZ/2013-08-ABO/12345',
147
+ remittance_information: 'Unsere Rechnung vom 10.08.2013',
148
+ mandate_id: 'K-02-2011-12345',
149
+ mandate_date_of_signature: Date.new(2011,1,25)
150
+
151
+ sdd
152
+ end
153
+
154
+ it 'should validate against pain.008.003.02' do
155
+ expect(subject.to_xml(SEPA::PAIN_008_003_02)).to validate_against('pain.008.003.02.xsd')
156
+ end
157
+
158
+ it 'should fail for pain.008.002.02' do
159
+ expect {
160
+ subject.to_xml(SEPA::PAIN_008_002_02)
161
+ }.to raise_error(SEPA::Error)
162
+ end
163
+
164
+ it 'should validate against pain.008.001.02' do
165
+ expect(subject.to_xml(SEPA::PAIN_008_001_02)).to validate_against('pain.008.001.02.xsd')
166
+ end
167
+ end
168
+
169
+ context 'with BIC' do
170
+ subject do
171
+ sdd = direct_debit
172
+
173
+ sdd.add_transaction name: 'Zahlemann & Söhne GbR',
174
+ bic: 'SPUEDE2UXXX',
175
+ iban: 'DE21500500009876543210',
176
+ amount: 39.99,
177
+ reference: 'XYZ/2013-08-ABO/12345',
178
+ remittance_information: 'Unsere Rechnung vom 10.08.2013',
179
+ mandate_id: 'K-02-2011-12345',
180
+ mandate_date_of_signature: Date.new(2011,1,25)
181
+
182
+ sdd
183
+ end
184
+
185
+ it 'should validate against pain.008.001.02' do
186
+ expect(subject.to_xml(SEPA::PAIN_008_001_02)).to validate_against('pain.008.001.02.xsd')
187
+ end
188
+
189
+ it 'should validate against pain.008.002.02' do
190
+ expect(subject.to_xml(SEPA::PAIN_008_002_02)).to validate_against('pain.008.002.02.xsd')
191
+ end
192
+
193
+ it 'should validate against pain.008.003.02' do
194
+ expect(subject.to_xml(SEPA::PAIN_008_003_02)).to validate_against('pain.008.003.02.xsd')
195
+ end
196
+ end
197
+
198
+ context 'with BIC and debtor address ' do
199
+ subject do
200
+ sdd = direct_debit
201
+
202
+ sda = SEPA::DebtorAddress.new(
203
+ country_code: 'CH',
204
+ address_line1: 'Mustergasse 123',
205
+ address_line2: '1234 Musterstadt'
206
+ )
207
+
208
+ sdd.add_transaction name: 'Zahlemann & Söhne GbR',
209
+ bic: 'SPUEDE2UXXX',
210
+ iban: 'DE21500500009876543210',
211
+ amount: 39.99,
212
+ reference: 'XYZ/2013-08-ABO/12345',
213
+ remittance_information: 'Unsere Rechnung vom 10.08.2013',
214
+ mandate_id: 'K-02-2011-12345',
215
+ debtor_address: sda,
216
+ mandate_date_of_signature: Date.new(2011,1,25)
217
+
218
+ sdd
219
+ end
220
+
221
+ it 'should validate against pain.008.001.02' do
222
+ expect(subject.to_xml(SEPA::PAIN_008_001_02)).to validate_against('pain.008.001.02.xsd')
223
+ end
224
+
225
+ it 'should validate against pain.008.002.02' do
226
+ expect(subject.to_xml(SEPA::PAIN_008_002_02)).to validate_against('pain.008.002.02.xsd')
227
+ end
228
+
229
+ it 'should validate against pain.008.003.02' do
230
+ expect(subject.to_xml(SEPA::PAIN_008_003_02)).to validate_against('pain.008.003.02.xsd')
231
+ end
232
+ end
233
+
234
+ context 'without requested_date given' do
235
+ subject do
236
+ sdd = direct_debit
237
+
238
+ sdd.add_transaction name: 'Zahlemann & Söhne GbR',
239
+ bic: 'SPUEDE2UXXX',
240
+ iban: 'DE21500500009876543210',
241
+ amount: 39.99,
242
+ reference: 'XYZ/2013-08-ABO/12345',
243
+ remittance_information: 'Unsere Rechnung vom 10.08.2013',
244
+ mandate_id: 'K-02-2011-12345',
245
+ mandate_date_of_signature: Date.new(2011,1,25)
246
+
247
+ sdd.add_transaction name: 'Meier & Schulze oHG',
248
+ iban: 'DE68210501700012345678',
249
+ amount: 750.00,
250
+ reference: 'XYZ/2013-08-ABO/6789',
251
+ remittance_information: 'Vielen Dank für Ihren Einkauf!',
252
+ mandate_id: 'K-08-2010-42123',
253
+ mandate_date_of_signature: Date.new(2010,7,25)
254
+
255
+ sdd.to_xml
256
+ end
257
+
258
+ it 'should create valid XML file' do
259
+ expect(subject).to validate_against('pain.008.003.02.xsd')
260
+ end
261
+
262
+ it 'should have creditor identifier' do
263
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/GrpHdr/InitgPty/Id/OrgId/Othr/Id', direct_debit.account.creditor_identifier)
264
+ end
265
+
266
+ it 'should contain <PmtInfId>' do
267
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/PmtInfId', /#{message_id_regex}\/1/)
268
+ end
269
+
270
+ it 'should contain <ReqdColltnDt>' do
271
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/ReqdColltnDt', Date.new(1999, 1, 1).iso8601)
272
+ end
273
+
274
+ it 'should contain <PmtMtd>' do
275
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/PmtMtd', 'DD')
276
+ end
277
+
278
+ it 'should contain <BtchBookg>' do
279
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/BtchBookg', 'true')
280
+ end
281
+
282
+ it 'should contain <NbOfTxs>' do
283
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/NbOfTxs', '2')
284
+ end
285
+
286
+ it 'should contain <CtrlSum>' do
287
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/CtrlSum', '789.99')
288
+ end
289
+
290
+ it 'should contain <Cdtr>' do
291
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/Cdtr/Nm', 'Gläubiger GmbH')
292
+ end
293
+
294
+ it 'should contain <CdtrAcct>' do
295
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/CdtrAcct/Id/IBAN', 'DE87200500001234567890')
296
+ end
297
+
298
+ it 'should contain <CdtrAgt>' do
299
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/CdtrAgt/FinInstnId/BIC', 'BANKDEFFXXX')
300
+ end
301
+
302
+ it 'should contain <CdtrAgt>' do
303
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/CdtrSchmeId/Id/PrvtId/Othr/Id', 'DE98ZZZ09999999999')
304
+ end
305
+
306
+ it 'should contain <EndToEndId>' do
307
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/PmtId/EndToEndId', 'XYZ/2013-08-ABO/12345')
308
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[2]/PmtId/EndToEndId', 'XYZ/2013-08-ABO/6789')
309
+ end
310
+
311
+ it 'should contain <InstdAmt>' do
312
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/InstdAmt', '39.99')
313
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[2]/InstdAmt', '750.00')
314
+ end
315
+
316
+ it 'should contain <MndtId>' do
317
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/DrctDbtTx/MndtRltdInf/MndtId', 'K-02-2011-12345')
318
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[2]/DrctDbtTx/MndtRltdInf/MndtId', 'K-08-2010-42123')
319
+ end
320
+
321
+ it 'should contain <DtOfSgntr>' do
322
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/DrctDbtTx/MndtRltdInf/DtOfSgntr', '2011-01-25')
323
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[2]/DrctDbtTx/MndtRltdInf/DtOfSgntr', '2010-07-25')
324
+ end
325
+
326
+ it 'should contain <DbtrAgt>' do
327
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/DbtrAgt/FinInstnId/BIC', 'SPUEDE2UXXX')
328
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[2]/DbtrAgt/FinInstnId/Othr/Id', 'NOTPROVIDED')
329
+ end
330
+
331
+ it 'should contain <Dbtr>' do
332
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/Dbtr/Nm', 'Zahlemann & Söhne GbR')
333
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[2]/Dbtr/Nm', 'Meier & Schulze oHG')
334
+ end
335
+
336
+ it 'should contain <DbtrAcct>' do
337
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/DbtrAcct/Id/IBAN', 'DE21500500009876543210')
338
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[2]/DbtrAcct/Id/IBAN', 'DE68210501700012345678')
339
+ end
340
+
341
+ it 'should contain <RmtInf>' do
342
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/RmtInf/Ustrd', 'Unsere Rechnung vom 10.08.2013')
343
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[2]/RmtInf/Ustrd', 'Vielen Dank für Ihren Einkauf')
344
+ end
345
+ end
346
+
347
+ context 'with different requested_date given' do
348
+ subject do
349
+ sdd = direct_debit
350
+
351
+ sdd.add_transaction(direct_debt_transaction.merge requested_date: Date.today + 1)
352
+ sdd.add_transaction(direct_debt_transaction.merge requested_date: Date.today + 2)
353
+ sdd.add_transaction(direct_debt_transaction.merge requested_date: Date.today + 2)
354
+
355
+ sdd.to_xml
356
+ end
357
+
358
+ it 'should contain two payment_informations with <ReqdColltnDt>' do
359
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[1]/ReqdColltnDt', (Date.today + 1).iso8601)
360
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[2]/ReqdColltnDt', (Date.today + 2).iso8601)
361
+
362
+ expect(subject).not_to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[3]')
363
+ end
364
+
365
+ it 'should contain two payment_informations with different <PmtInfId>' do
366
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[1]/PmtInfId', /#{message_id_regex}\/1/)
367
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[2]/PmtInfId', /#{message_id_regex}\/2/)
368
+ end
369
+ end
370
+
371
+ context 'with different local_instrument given' do
372
+ subject do
373
+ sdd = direct_debit
374
+
375
+ sdd.add_transaction(direct_debt_transaction.merge local_instrument: 'CORE')
376
+ sdd.add_transaction(direct_debt_transaction.merge local_instrument: 'B2B')
377
+
378
+ sdd
379
+ end
380
+
381
+ it 'should have errors' do
382
+ expect(subject.errors_on(:base).size).to eq(1)
383
+ end
384
+
385
+ it 'should raise error on XML generation' do
386
+ expect {
387
+ subject.to_xml
388
+ }.to raise_error(SEPA::Error)
389
+ end
390
+ end
391
+
392
+ context 'with different sequence_type given' do
393
+ subject do
394
+ sdd = direct_debit
395
+
396
+ sdd.add_transaction(direct_debt_transaction.merge sequence_type: 'OOFF')
397
+ sdd.add_transaction(direct_debt_transaction.merge sequence_type: 'FRST')
398
+ sdd.add_transaction(direct_debt_transaction.merge sequence_type: 'FRST')
399
+
400
+ sdd.to_xml
401
+ end
402
+
403
+ it 'should contain two payment_informations with <LclInstrm>' do
404
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[1]/PmtTpInf/SeqTp', 'OOFF')
405
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[2]/PmtTpInf/SeqTp', 'FRST')
406
+
407
+ expect(subject).not_to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[3]')
408
+ end
409
+ end
410
+
411
+ context 'with different batch_booking given' do
412
+ subject do
413
+ sdd = direct_debit
414
+
415
+ sdd.add_transaction(direct_debt_transaction.merge batch_booking: false)
416
+ sdd.add_transaction(direct_debt_transaction.merge batch_booking: true)
417
+ sdd.add_transaction(direct_debt_transaction.merge batch_booking: true)
418
+
419
+ sdd.to_xml
420
+ end
421
+
422
+ it 'should contain two payment_informations with <BtchBookg>' do
423
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[1]/BtchBookg', 'false')
424
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[2]/BtchBookg', 'true')
425
+
426
+ expect(subject).not_to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[3]')
427
+ end
428
+ end
429
+
430
+ context 'with transactions containing different group criteria' do
431
+ subject do
432
+ sdd = direct_debit
433
+
434
+ sdd.add_transaction(direct_debt_transaction.merge requested_date: Date.today + 1, sequence_type: 'OOFF', amount: 1)
435
+ sdd.add_transaction(direct_debt_transaction.merge requested_date: Date.today + 1, sequence_type: 'FNAL', amount: 2)
436
+ sdd.add_transaction(direct_debt_transaction.merge requested_date: Date.today + 2, sequence_type: 'OOFF', amount: 4)
437
+ sdd.add_transaction(direct_debt_transaction.merge requested_date: Date.today + 2, sequence_type: 'FNAL', amount: 8)
438
+
439
+ sdd.to_xml
440
+ end
441
+
442
+ it 'should contain multiple payment_informations' do
443
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[1]/ReqdColltnDt', (Date.today + 1).iso8601)
444
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[1]/PmtTpInf/SeqTp', 'OOFF')
445
+
446
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[2]/ReqdColltnDt', (Date.today + 1).iso8601)
447
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[2]/PmtTpInf/SeqTp', 'FNAL')
448
+
449
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[3]/ReqdColltnDt', (Date.today + 2).iso8601)
450
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[3]/PmtTpInf/SeqTp', 'OOFF')
451
+
452
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[4]/ReqdColltnDt', (Date.today + 2).iso8601)
453
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[4]/PmtTpInf/SeqTp', 'FNAL')
454
+ end
455
+
456
+ it 'should have multiple control sums' do
457
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[1]/CtrlSum', '1.00')
458
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[2]/CtrlSum', '2.00')
459
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[3]/CtrlSum', '4.00')
460
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[4]/CtrlSum', '8.00')
461
+ end
462
+ end
463
+
464
+ context 'with transactions containing different creditor_account' do
465
+ subject do
466
+ sdd = direct_debit
467
+
468
+ sdd.add_transaction(direct_debt_transaction)
469
+ sdd.add_transaction(direct_debt_transaction.merge(creditor_account: SEPA::CreditorAccount.new(
470
+ name: 'Creditor Inc.',
471
+ bic: 'RABONL2U',
472
+ iban: 'NL08RABO0135742099',
473
+ creditor_identifier: 'NL53ZZZ091734220000'))
474
+ )
475
+
476
+ sdd.to_xml
477
+ end
478
+
479
+ it 'should contain two payment_informations with <Cdtr>' do
480
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[1]/Cdtr/Nm', 'Gläubiger GmbH')
481
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[2]/Cdtr/Nm', 'Creditor Inc.')
482
+ end
483
+ end
484
+
485
+ context 'with mandate amendments' do
486
+ subject do
487
+ sdd = direct_debit
488
+
489
+ sdd.add_transaction(direct_debt_transaction.merge(original_debtor_account: 'NL08RABO0135742099'))
490
+ sdd.add_transaction(direct_debt_transaction.merge(same_mandate_new_debtor_agent: true))
491
+ sdd.add_transaction(direct_debt_transaction.merge(original_creditor_account: SEPA::CreditorAccount.new(creditor_identifier: 'NL53ZZZ091734220000', name: 'Creditor Inc.')))
492
+ sdd.to_xml
493
+ end
494
+
495
+ it 'should include amendment indicator' do
496
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/DrctDbtTx/MndtRltdInf/AmdmntInd', 'true')
497
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[2]/DrctDbtTx/MndtRltdInf/AmdmntInd', 'true')
498
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[3]/DrctDbtTx/MndtRltdInf/AmdmntInd', 'true')
499
+ end
500
+
501
+ it 'should include amendment information details' do
502
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/DrctDbtTx/MndtRltdInf/AmdmntInfDtls/OrgnlDbtrAcct/Id/IBAN', 'NL08RABO0135742099')
503
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[2]/DrctDbtTx/MndtRltdInf/AmdmntInfDtls/OrgnlDbtrAgt/FinInstnId/Othr/Id', 'SMNDA')
504
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[3]/DrctDbtTx/MndtRltdInf/AmdmntInfDtls/OrgnlCdtrSchmeId/Nm', 'Creditor Inc.')
505
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[3]/DrctDbtTx/MndtRltdInf/AmdmntInfDtls/OrgnlCdtrSchmeId/Id/PrvtId/Othr/Id', 'NL53ZZZ091734220000')
506
+ end
507
+ end
508
+
509
+ context 'with instruction given' do
510
+ subject do
511
+ sct = direct_debit
512
+
513
+ sct.add_transaction(direct_debt_transaction.merge(instruction: '1234/ABC'))
514
+
515
+ sct.to_xml
516
+ end
517
+
518
+ it 'should create valid XML file' do
519
+ expect(subject).to validate_against('pain.008.003.02.xsd')
520
+ end
521
+
522
+ it 'should contain <InstrId>' do
523
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/PmtId/InstrId', '1234/ABC')
524
+ end
525
+ end
526
+
527
+ context 'with large message identification' do
528
+ subject do
529
+ sct = direct_debit
530
+ sct.message_identification = 'A' * 35
531
+ sct.add_transaction(direct_debt_transaction.merge(instruction: '1234/ABC'))
532
+ sct
533
+ end
534
+
535
+ it 'should fail as the payment identification becomes too large' do
536
+ expect { subject.to_xml }.to raise_error(SEPA::Error)
537
+ end
538
+ end
539
+
540
+ context 'with a different currency given' do
541
+ subject do
542
+ sct = direct_debit
543
+
544
+ sct.add_transaction(direct_debt_transaction.merge(instruction: '1234/ABC', currency: 'SEK'))
545
+
546
+ sct
547
+ end
548
+
549
+ it 'should validate against pain.001.001.03' do
550
+ expect(subject.to_xml(SEPA::PAIN_008_001_02)).to validate_against('pain.008.001.02.xsd')
551
+ end
552
+
553
+ it 'should have a CHF Ccy' do
554
+ doc = Nokogiri::XML(subject.to_xml('pain.008.001.02'))
555
+ doc.remove_namespaces!
556
+
557
+ nodes = doc.xpath('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/InstdAmt')
558
+ expect(nodes.length).to eql(1)
559
+ expect(nodes.first.attribute('Ccy').value).to eql('SEK')
560
+ end
561
+
562
+ it 'should fail for pain.008.002.02' do
563
+ expect {
564
+ subject.to_xml(SEPA::PAIN_008_002_02)
565
+ }.to raise_error(SEPA::Error)
566
+ end
567
+
568
+ it 'should fail for pain.008.003.02' do
569
+ expect {
570
+ subject.to_xml(SEPA::PAIN_008_003_02)
571
+ }.to raise_error(SEPA::Error)
572
+ end
573
+ end
574
+ end
575
+
576
+ context 'xml_schema_header' do
577
+ subject { sepa_direct_debit.to_xml(format) }
578
+
579
+ let(:sepa_direct_debit) do
580
+ SEPA::DirectDebit.new name: 'Gläubiger GmbH',
581
+ iban: 'DE87200500001234567890',
582
+ creditor_identifier: 'DE98ZZZ09999999999'
583
+ end
584
+
585
+ let(:xml_header) do
586
+ '<?xml version="1.0" encoding="UTF-8"?>' +
587
+ "\n<Document xmlns=\"urn:iso:std:iso:20022:tech:xsd:#{format}\"" +
588
+ ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' +
589
+ " xsi:schemaLocation=\"urn:iso:std:iso:20022:tech:xsd:#{format} #{format}.xsd\">\n"
590
+ end
591
+
592
+ let(:transaction) do
593
+ {
594
+ name: 'Zahlemann & Söhne GbR',
595
+ bic: 'SPUEDE2UXXX',
596
+ iban: 'DE21500500009876543210',
597
+ amount: 39.99,
598
+ reference: 'XYZ/2013-08-ABO/12345',
599
+ remittance_information: 'Unsere Rechnung vom 10.08.2013',
600
+ mandate_id: 'K-02-2011-12345',
601
+ mandate_date_of_signature: Date.new(2011, 1, 25)
602
+ }
603
+ end
604
+
605
+ before do
606
+ sepa_direct_debit.add_transaction transaction
607
+ end
608
+
609
+ context "when format is #{SEPA::PAIN_008_001_02}" do
610
+ let(:format) { SEPA::PAIN_008_001_02 }
611
+
612
+ it 'should return correct header' do
613
+ is_expected.to start_with(xml_header)
614
+ end
615
+ end
616
+
617
+ context "when format is #{SEPA::PAIN_008_002_02}" do
618
+ let(:format) { SEPA::PAIN_008_002_02 }
619
+ let(:sepa_direct_debit) do
620
+ SEPA::DirectDebit.new name: 'Gläubiger GmbH',
621
+ bic: 'SPUEDE2UXXX',
622
+ iban: 'DE87200500001234567890',
623
+ creditor_identifier: 'DE98ZZZ09999999999'
624
+ end
625
+ let(:transaction) do
626
+ {
627
+ name: 'Zahlemann & Söhne GbR',
628
+ bic: 'SPUEDE2UXXX',
629
+ iban: 'DE21500500009876543210',
630
+ amount: 39.99,
631
+ reference: 'XYZ/2013-08-ABO/12345',
632
+ remittance_information: 'Unsere Rechnung vom 10.08.2013',
633
+ mandate_id: 'K-02-2011-12345',
634
+ debtor_address: SEPA::DebtorAddress.new(
635
+ country_code: 'CH',
636
+ address_line1: 'Mustergasse 123',
637
+ address_line2: '1234 Musterstadt'
638
+ ),
639
+ mandate_date_of_signature: Date.new(2011, 1, 25)
640
+ }
641
+ end
642
+
643
+ it 'should return correct header' do
644
+ is_expected.to start_with(xml_header)
645
+ end
646
+ end
647
+
648
+ context "when format is #{SEPA::PAIN_008_003_02}" do
649
+ let(:format) { SEPA::PAIN_008_003_02 }
650
+
651
+ it 'should return correct header' do
652
+ is_expected.to start_with(xml_header)
653
+ end
654
+ end
655
+ end
656
+ end
657
+ end