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,42 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe SEPA::Account do
5
+ describe :new do
6
+ it 'should not accept unknown keys' do
7
+ expect {
8
+ SEPA::Account.new foo: 'bar'
9
+ }.to raise_error(NoMethodError)
10
+ end
11
+ end
12
+
13
+ describe :name do
14
+ it 'should accept valid value' do
15
+ expect(SEPA::Account).to accept('Gläubiger GmbH', 'Zahlemann & Söhne GbR', 'X' * 70, for: :name)
16
+ end
17
+
18
+ it 'should not accept invalid value' do
19
+ expect(SEPA::Account).not_to accept(nil, '', 'X' * 71, for: :name)
20
+ end
21
+ end
22
+
23
+ describe :iban do
24
+ it 'should accept valid value' do
25
+ expect(SEPA::Account).to accept('DE21500500009876543210', 'PL61109010140000071219812874', for: :iban)
26
+ end
27
+
28
+ it 'should not accept invalid value' do
29
+ expect(SEPA::Account).not_to accept(nil, '', 'invalid', for: :iban)
30
+ end
31
+ end
32
+
33
+ describe :bic do
34
+ it 'should accept valid value' do
35
+ expect(SEPA::Account).to accept('DEUTDEFF', 'DEUTDEFF500', 'SPUEDE2UXXX', for: :bic)
36
+ end
37
+
38
+ it 'should not accept invalid value' do
39
+ expect(SEPA::Account).not_to accept('', 'invalid', for: :bic)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,74 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe SEPA::Converter do
5
+ include SEPA::Converter::InstanceMethods
6
+
7
+ describe :convert_text do
8
+ it 'should convert special chars' do
9
+ expect(convert_text('10€')).to eq('10E')
10
+ expect(convert_text('info@bundesbank.de')).to eq('info(at)bundesbank.de')
11
+ expect(convert_text('abc_def')).to eq('abc-def')
12
+ end
13
+
14
+ it 'should not change allowed special character' do
15
+ expect(convert_text('üöäÜÖÄß')).to eq('üöäÜÖÄß')
16
+ expect(convert_text('&*$%')).to eq('&*$%')
17
+ end
18
+
19
+ it 'should convert line breaks' do
20
+ expect(convert_text("one\ntwo")) .to eq('one two')
21
+ expect(convert_text("one\ntwo\n")) .to eq('one two')
22
+ expect(convert_text("\none\ntwo\n")).to eq('one two')
23
+ expect(convert_text("one\n\ntwo")) .to eq('one two')
24
+ end
25
+
26
+ it 'should convert number' do
27
+ expect(convert_text(1234)).to eq('1234')
28
+ end
29
+
30
+ it 'should remove invalid chars' do
31
+ expect(convert_text('"=<>!')).to eq('')
32
+ end
33
+
34
+ it 'should not touch valid chars' do
35
+ expect(convert_text("abc-ABC-0123- ':?,-(+.)/")).to eq("abc-ABC-0123- ':?,-(+.)/")
36
+ end
37
+
38
+ it 'should not touch nil' do
39
+ expect(convert_text(nil)).to eq(nil)
40
+ end
41
+ end
42
+
43
+ describe :convert_decimal do
44
+ it "should convert Integer to BigDecimal" do
45
+ expect(convert_decimal(42)).to eq(BigDecimal('42.00'))
46
+ end
47
+
48
+ it "should convert Float to BigDecimal" do
49
+ expect(convert_decimal(42.12)).to eq(BigDecimal('42.12'))
50
+ end
51
+
52
+ it 'should round' do
53
+ expect(convert_decimal(1.345)).to eq(BigDecimal('1.35'))
54
+ end
55
+
56
+ it 'should not touch nil' do
57
+ expect(convert_decimal(nil)).to eq(nil)
58
+ end
59
+
60
+ it 'should not convert zero value' do
61
+ expect(convert_decimal(0)).to eq(nil)
62
+ end
63
+
64
+ it 'should not convert negative value' do
65
+ expect(convert_decimal(-3)).to eq(nil)
66
+ end
67
+
68
+ it 'should not convert invalid value' do
69
+ expect(convert_decimal('xyz')).to eq(nil)
70
+ expect(convert_decimal('NaN')).to eq(nil)
71
+ expect(convert_decimal('Infinity')).to eq(nil)
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,520 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe SEPA::CreditTransfer do
5
+ let(:message_id_regex) { /SEPA-KING\/[0-9a-z_]{22}/ }
6
+ let(:credit_transfer) {
7
+ SEPA::CreditTransfer.new name: 'Schuldner GmbH',
8
+ bic: 'BANKDEFFXXX',
9
+ iban: 'DE87200500001234567890'
10
+ }
11
+
12
+ describe :new do
13
+ it 'should accept missing options' do
14
+ expect {
15
+ SEPA::CreditTransfer.new
16
+ }.to_not raise_error
17
+ end
18
+ end
19
+
20
+ describe :add_transaction do
21
+ it 'should add valid transactions' do
22
+ 3.times do
23
+ credit_transfer.add_transaction(credit_transfer_transaction)
24
+ end
25
+
26
+ expect(credit_transfer.transactions.size).to eq(3)
27
+ end
28
+
29
+ it 'should fail for invalid transaction' do
30
+ expect {
31
+ credit_transfer.add_transaction name: ''
32
+ }.to raise_error(ArgumentError)
33
+ end
34
+ end
35
+
36
+ describe :to_xml do
37
+ context 'for invalid debtor' do
38
+ it 'should fail' do
39
+ expect {
40
+ SEPA::CreditTransfer.new.to_xml
41
+ }.to raise_error(SEPA::Error)
42
+ end
43
+ end
44
+
45
+ context 'setting creditor address with adrline' do
46
+ subject do
47
+ sct = SEPA::CreditTransfer.new name: 'Schuldner GmbH',
48
+ iban: 'DE87200500001234567890'
49
+
50
+ sca = SEPA::CreditorAddress.new country_code: 'CH',
51
+ address_line1: 'Mustergasse 123',
52
+ address_line2: '1234 Musterstadt'
53
+
54
+ sct.add_transaction name: 'Telekomiker AG',
55
+ bic: 'PBNKDEFF370',
56
+ iban: 'DE37112589611964645802',
57
+ amount: 102.50,
58
+ reference: 'XYZ-1234/123',
59
+ remittance_information: 'Rechnung vom 22.08.2013',
60
+ creditor_address: sca
61
+
62
+ sct
63
+ end
64
+
65
+ it 'should validate against pain.001.003.01' do
66
+ expect(subject.to_xml(SEPA::PAIN_001_003_03)).to validate_against('pain.001.003.03.xsd')
67
+ end
68
+ end
69
+
70
+ context 'setting creditor address with structured fields' do
71
+ subject do
72
+ sct = SEPA::CreditTransfer.new name: 'Schuldner GmbH',
73
+ iban: 'DE87200500001234567890',
74
+ bic: 'BANKDEFFXXX'
75
+
76
+ sca = SEPA::CreditorAddress.new country_code: 'CH',
77
+ street_name: 'Mustergasse',
78
+ building_number: '123',
79
+ post_code: '1234',
80
+ town_name: 'Musterstadt'
81
+
82
+ sct.add_transaction name: 'Telekomiker AG',
83
+ bic: 'PBNKDEFF370',
84
+ iban: 'DE37112589611964645802',
85
+ amount: 102.50,
86
+ reference: 'XYZ-1234/123',
87
+ remittance_information: 'Rechnung vom 22.08.2013',
88
+ creditor_address: sca
89
+
90
+ sct
91
+ end
92
+
93
+ it 'should validate against pain.001.001.01' do
94
+ expect(subject.to_xml(SEPA::PAIN_001_001_03)).to validate_against('pain.001.001.03.xsd')
95
+ end
96
+ end
97
+
98
+ context 'for valid debtor' do
99
+ context 'without BIC (IBAN-only)' do
100
+ subject do
101
+ sct = SEPA::CreditTransfer.new name: 'Schuldner GmbH',
102
+ iban: 'DE87200500001234567890'
103
+
104
+ sct.add_transaction name: 'Telekomiker AG',
105
+ bic: 'PBNKDEFF370',
106
+ iban: 'DE37112589611964645802',
107
+ amount: 102.50,
108
+ reference: 'XYZ-1234/123',
109
+ remittance_information: 'Rechnung vom 22.08.2013'
110
+
111
+ sct
112
+ end
113
+
114
+ it 'should create valid XML file' do
115
+ expect(subject.to_xml).to validate_against('pain.001.003.03.xsd')
116
+ end
117
+
118
+ it 'should fail for pain.001.001.03' do
119
+ expect {
120
+ subject.to_xml(SEPA::PAIN_001_001_03)
121
+ }.to raise_error(SEPA::Error)
122
+ end
123
+
124
+ it 'should fail for pain.001.002.03' do
125
+ expect {
126
+ subject.to_xml(SEPA::PAIN_001_002_03)
127
+ }.to raise_error(SEPA::Error)
128
+ end
129
+ end
130
+
131
+ context 'with BIC' do
132
+ subject do
133
+ sct = credit_transfer
134
+
135
+ sct.add_transaction name: 'Telekomiker AG',
136
+ bic: 'PBNKDEFF370',
137
+ iban: 'DE37112589611964645802',
138
+ amount: 102.50,
139
+ reference: 'XYZ-1234/123',
140
+ remittance_information: 'Rechnung vom 22.08.2013'
141
+
142
+ sct
143
+ end
144
+
145
+ it 'should validate against pain.001.001.03' do
146
+ expect(subject.to_xml('pain.001.001.03')).to validate_against('pain.001.001.03.xsd')
147
+ end
148
+
149
+ it 'should validate against pain.001.002.03' do
150
+ expect(subject.to_xml('pain.001.002.03')).to validate_against('pain.001.002.03.xsd')
151
+ end
152
+
153
+ it 'should validate against pain.001.003.03' do
154
+ expect(subject.to_xml('pain.001.003.03')).to validate_against('pain.001.003.03.xsd')
155
+ end
156
+ end
157
+
158
+ context 'without requested_date given' do
159
+ subject do
160
+ sct = credit_transfer
161
+
162
+ sct.add_transaction name: 'Telekomiker AG',
163
+ bic: 'PBNKDEFF370',
164
+ iban: 'DE37112589611964645802',
165
+ amount: 102.50,
166
+ reference: 'XYZ-1234/123',
167
+ remittance_information: 'Rechnung vom 22.08.2013'
168
+
169
+ sct.add_transaction name: 'Amazonas GmbH',
170
+ iban: 'DE27793589132923472195',
171
+ amount: 59.00,
172
+ reference: 'XYZ-5678/456',
173
+ remittance_information: 'Rechnung vom 21.08.2013'
174
+
175
+ sct.to_xml
176
+ end
177
+
178
+ it 'should create valid XML file' do
179
+ expect(subject).to validate_against('pain.001.003.03.xsd')
180
+ end
181
+
182
+ it 'should have message_identification' do
183
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/GrpHdr/MsgId', message_id_regex)
184
+ end
185
+
186
+ it 'should contain <PmtInfId>' do
187
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/PmtInfId', /#{message_id_regex}\/1/)
188
+ end
189
+
190
+ it 'should contain <ReqdExctnDt>' do
191
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/ReqdExctnDt', Date.new(1999, 1, 1).iso8601)
192
+ end
193
+
194
+ it 'should contain <PmtMtd>' do
195
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/PmtMtd', 'TRF')
196
+ end
197
+
198
+ it 'should contain <BtchBookg>' do
199
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/BtchBookg', 'true')
200
+ end
201
+
202
+ it 'should contain <NbOfTxs>' do
203
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/NbOfTxs', '2')
204
+ end
205
+
206
+ it 'should contain <CtrlSum>' do
207
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CtrlSum', '161.50')
208
+ end
209
+
210
+ it 'should contain <Dbtr>' do
211
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/Dbtr/Nm', 'Schuldner GmbH')
212
+ end
213
+
214
+ it 'should contain <DbtrAcct>' do
215
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/DbtrAcct/Id/IBAN', 'DE87200500001234567890')
216
+ end
217
+
218
+ it 'should contain <DbtrAgt>' do
219
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/DbtrAgt/FinInstnId/BIC', 'BANKDEFFXXX')
220
+ end
221
+
222
+ it 'should contain <EndToEndId>' do
223
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[1]/PmtId/EndToEndId', 'XYZ-1234/123')
224
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[2]/PmtId/EndToEndId', 'XYZ-5678/456')
225
+ end
226
+
227
+ it 'should contain <Amt>' do
228
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[1]/Amt/InstdAmt', '102.50')
229
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[2]/Amt/InstdAmt', '59.00')
230
+ end
231
+
232
+ it 'should contain <CdtrAgt> for every BIC given' do
233
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[1]/CdtrAgt/FinInstnId/BIC', 'PBNKDEFF370')
234
+ expect(subject).not_to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[2]/CdtrAgt')
235
+ end
236
+
237
+ it 'should contain <Cdtr>' do
238
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[1]/Cdtr/Nm', 'Telekomiker AG')
239
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[2]/Cdtr/Nm', 'Amazonas GmbH')
240
+ end
241
+
242
+ it 'should contain <CdtrAcct>' do
243
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[1]/CdtrAcct/Id/IBAN', 'DE37112589611964645802')
244
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[2]/CdtrAcct/Id/IBAN', 'DE27793589132923472195')
245
+ end
246
+
247
+ it 'should contain <RmtInf>' do
248
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[1]/RmtInf/Ustrd', 'Rechnung vom 22.08.2013')
249
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[2]/RmtInf/Ustrd', 'Rechnung vom 21.08.2013')
250
+ end
251
+ end
252
+
253
+ context 'with different requested_date given' do
254
+ subject do
255
+ sct = credit_transfer
256
+
257
+ sct.add_transaction(credit_transfer_transaction.merge requested_date: Date.today + 1)
258
+ sct.add_transaction(credit_transfer_transaction.merge requested_date: Date.today + 2)
259
+ sct.add_transaction(credit_transfer_transaction.merge requested_date: Date.today + 2)
260
+
261
+ sct.to_xml
262
+ end
263
+
264
+ it 'should contain two payment_informations with <ReqdExctnDt>' do
265
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[1]/ReqdExctnDt', (Date.today + 1).iso8601)
266
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[2]/ReqdExctnDt', (Date.today + 2).iso8601)
267
+
268
+ expect(subject).not_to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[3]')
269
+ end
270
+
271
+ it 'should contain two payment_informations with different <PmtInfId>' do
272
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[1]/PmtInfId', /#{message_id_regex}\/1/)
273
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[2]/PmtInfId', /#{message_id_regex}\/2/)
274
+ end
275
+ end
276
+
277
+ context 'with different batch_booking given' do
278
+ subject do
279
+ sct = credit_transfer
280
+
281
+ sct.add_transaction(credit_transfer_transaction.merge batch_booking: false)
282
+ sct.add_transaction(credit_transfer_transaction.merge batch_booking: true)
283
+ sct.add_transaction(credit_transfer_transaction.merge batch_booking: true)
284
+
285
+ sct.to_xml
286
+ end
287
+
288
+ it 'should contain two payment_informations with <BtchBookg>' do
289
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[1]/BtchBookg', 'false')
290
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[2]/BtchBookg', 'true')
291
+
292
+ expect(subject).not_to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[3]')
293
+ end
294
+ end
295
+
296
+ context 'with transactions containing different group criteria' do
297
+ subject do
298
+ sct = credit_transfer
299
+
300
+ sct.add_transaction(credit_transfer_transaction.merge requested_date: Date.today + 1, batch_booking: false, amount: 1)
301
+ sct.add_transaction(credit_transfer_transaction.merge requested_date: Date.today + 1, batch_booking: true, amount: 2)
302
+ sct.add_transaction(credit_transfer_transaction.merge requested_date: Date.today + 2, batch_booking: false, amount: 4)
303
+ sct.add_transaction(credit_transfer_transaction.merge requested_date: Date.today + 2, batch_booking: true, amount: 8)
304
+ sct.add_transaction(credit_transfer_transaction.merge requested_date: Date.today + 2, batch_booking: true, category_purpose: 'SALA', amount: 6)
305
+
306
+ sct.to_xml
307
+ end
308
+
309
+ it 'should contain multiple payment_informations' do
310
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[1]/ReqdExctnDt', (Date.today + 1).iso8601)
311
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[1]/BtchBookg', 'false')
312
+
313
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[2]/ReqdExctnDt', (Date.today + 1).iso8601)
314
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[2]/BtchBookg', 'true')
315
+
316
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[3]/ReqdExctnDt', (Date.today + 2).iso8601)
317
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[3]/BtchBookg', 'false')
318
+
319
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[4]/ReqdExctnDt', (Date.today + 2).iso8601)
320
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[4]/BtchBookg', 'true')
321
+
322
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[5]/ReqdExctnDt', (Date.today + 2).iso8601)
323
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[5]/PmtTpInf/CtgyPurp/Cd', 'SALA')
324
+ end
325
+
326
+ it 'should have multiple control sums' do
327
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[1]/CtrlSum', '1.00')
328
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[2]/CtrlSum', '2.00')
329
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[3]/CtrlSum', '4.00')
330
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[4]/CtrlSum', '8.00')
331
+ end
332
+ end
333
+
334
+ context 'with instruction given' do
335
+ subject do
336
+ sct = credit_transfer
337
+
338
+ sct.add_transaction name: 'Telekomiker AG',
339
+ iban: 'DE37112589611964645802',
340
+ amount: 102.50,
341
+ instruction: '1234/ABC'
342
+
343
+ sct.to_xml
344
+ end
345
+
346
+ it 'should create valid XML file' do
347
+ expect(subject).to validate_against('pain.001.003.03.xsd')
348
+ end
349
+
350
+ it 'should contain <InstrId>' do
351
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[1]/PmtId/InstrId', '1234/ABC')
352
+ end
353
+ end
354
+
355
+ context 'with a different currency given' do
356
+ subject do
357
+ sct = credit_transfer
358
+
359
+ sct.add_transaction name: 'Telekomiker AG',
360
+ iban: 'DE37112589611964645802',
361
+ bic: 'PBNKDEFF370',
362
+ amount: 102.50,
363
+ currency: 'CHF'
364
+
365
+ sct
366
+ end
367
+
368
+ it 'should validate against pain.001.001.03' do
369
+ expect(subject.to_xml('pain.001.001.03')).to validate_against('pain.001.001.03.xsd')
370
+ end
371
+
372
+ it 'should have a CHF Ccy' do
373
+ doc = Nokogiri::XML(subject.to_xml('pain.001.001.03'))
374
+ doc.remove_namespaces!
375
+
376
+ nodes = doc.xpath('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[1]/Amt/InstdAmt')
377
+ expect(nodes.length).to eql(1)
378
+ expect(nodes.first.attribute('Ccy').value).to eql('CHF')
379
+ end
380
+
381
+ it 'should fail for pain.001.002.03' do
382
+ expect {
383
+ subject.to_xml(SEPA::PAIN_001_002_03)
384
+ }.to raise_error(SEPA::Error)
385
+ end
386
+
387
+ it 'should fail for pain.001.003.03' do
388
+ expect {
389
+ subject.to_xml(SEPA::PAIN_001_003_03)
390
+ }.to raise_error(SEPA::Error)
391
+ end
392
+ end
393
+
394
+ context 'with a transaction without a bic' do
395
+ subject do
396
+ sct = credit_transfer
397
+
398
+ sct.add_transaction name: 'Telekomiker AG',
399
+ iban: 'DE37112589611964645802',
400
+ amount: 102.50
401
+
402
+ sct
403
+ end
404
+
405
+ it 'should validate against pain.001.001.03' do
406
+ expect(subject.to_xml('pain.001.001.03')).to validate_against('pain.001.001.03.xsd')
407
+ end
408
+
409
+ it 'should fail for pain.001.002.03' do
410
+ expect {
411
+ subject.to_xml(SEPA::PAIN_001_002_03)
412
+ }.to raise_error(SEPA::Error)
413
+ end
414
+
415
+ it 'should validate against pain.001.003.03' do
416
+ expect(subject.to_xml(SEPA::PAIN_001_003_03)).to validate_against('pain.001.003.03.xsd')
417
+ end
418
+ end
419
+ end
420
+
421
+ context 'xml_schema_header' do
422
+ subject { credit_transfer.to_xml(format) }
423
+
424
+ let(:xml_header) do
425
+ '<?xml version="1.0" encoding="UTF-8"?>' +
426
+ "\n<Document xmlns=\"urn:iso:std:iso:20022:tech:xsd:#{format}\"" +
427
+ ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' +
428
+ " xsi:schemaLocation=\"urn:iso:std:iso:20022:tech:xsd:#{format} #{format}.xsd\">\n"
429
+ end
430
+
431
+ let(:transaction) do
432
+ {
433
+ name: 'Telekomiker AG',
434
+ iban: 'DE37112589611964645802',
435
+ bic: 'PBNKDEFF370',
436
+ amount: 102.50,
437
+ currency: 'CHF'
438
+ }
439
+ end
440
+
441
+ before do
442
+ credit_transfer.add_transaction transaction
443
+ end
444
+
445
+ context "when format is #{SEPA::PAIN_001_001_03}" do
446
+ let(:format) { SEPA::PAIN_001_001_03 }
447
+
448
+ it 'should return correct header' do
449
+ is_expected.to start_with(xml_header)
450
+ end
451
+ end
452
+
453
+ context "when format is #{SEPA::PAIN_001_002_03}" do
454
+ let(:format) { SEPA::PAIN_001_002_03 }
455
+ let(:transaction) do
456
+ {
457
+ name: 'Telekomiker AG',
458
+ bic: 'PBNKDEFF370',
459
+ iban: 'DE37112589611964645802',
460
+ amount: 102.50,
461
+ reference: 'XYZ-1234/123',
462
+ remittance_information: 'Rechnung vom 22.08.2013'
463
+ }
464
+ end
465
+
466
+ it 'should return correct header' do
467
+ is_expected.to start_with(xml_header)
468
+ end
469
+ end
470
+
471
+ context "when format is #{SEPA::PAIN_001_003_03}" do
472
+ let(:format) { SEPA::PAIN_001_003_03 }
473
+ let(:transaction) do
474
+ {
475
+ name: 'Telekomiker AG',
476
+ bic: 'PBNKDEFF370',
477
+ iban: 'DE37112589611964645802',
478
+ amount: 102.50,
479
+ reference: 'XYZ-1234/123',
480
+ remittance_information: 'Rechnung vom 22.08.2013'
481
+ }
482
+ end
483
+
484
+ it 'should return correct header' do
485
+ is_expected.to start_with(xml_header)
486
+ end
487
+ end
488
+
489
+ context "when format is #{SEPA::PAIN_001_001_03_CH_02}" do
490
+ let(:format) { SEPA::PAIN_001_001_03_CH_02 }
491
+ let(:credit_transfer) do
492
+ SEPA::CreditTransfer.new name: 'Schuldner GmbH',
493
+ iban: 'CH5481230000001998736',
494
+ bic: 'RAIFCH22'
495
+ end
496
+ let(:transaction) do
497
+ {
498
+ name: 'Telekomiker AG',
499
+ iban: 'DE62007620110623852957',
500
+ amount: 102.50,
501
+ currency: 'CHF',
502
+ reference: 'XYZ-1234/123',
503
+ remittance_information: 'Rechnung vom 22.08.2013'
504
+ }
505
+ end
506
+
507
+ let(:xml_header) do
508
+ '<?xml version="1.0" encoding="UTF-8"?>' +
509
+ "\n<Document xmlns=\"http://www.six-interbank-clearing.com/de/#{format}.xsd\"" +
510
+ ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' +
511
+ " xsi:schemaLocation=\"http://www.six-interbank-clearing.com/de/#{format}.xsd #{format}.xsd\">\n"
512
+ end
513
+
514
+ it 'should return correct header' do
515
+ is_expected.to start_with(xml_header)
516
+ end
517
+ end
518
+ end
519
+ end
520
+ end