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,350 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe SPS::CreditTransfer do
5
+ let(:message_id_regex) { /SPS-KING\/[0-9a-z_]{22}/ }
6
+ let(:credit_transfer) {
7
+ SPS::CreditTransfer.new(
8
+ name: 'Schuldner GmbH',
9
+ bic: 'RAIFCH22',
10
+ iban: 'CH5481230000001998736'
11
+ )
12
+ }
13
+
14
+ describe :new do
15
+ it 'should accept missing options' do
16
+ expect {
17
+ SPS::CreditTransfer.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
+ credit_transfer.add_transaction(credit_transfer_transaction)
26
+ end
27
+
28
+ expect(credit_transfer.transactions.size).to eq(3)
29
+ end
30
+
31
+ it 'should fail for invalid transaction' do
32
+ expect {
33
+ credit_transfer.add_transaction name: ''
34
+ }.to raise_error(ArgumentError)
35
+ end
36
+ end
37
+
38
+ describe :to_xml do
39
+ context 'for invalid debtor' do
40
+ it 'should fail' do
41
+ expect {
42
+ SPS::CreditTransfer.new.to_xml
43
+ }.to raise_error(SPS::Error)
44
+ end
45
+ end
46
+
47
+ context 'setting creditor address with adrline' do
48
+ subject do
49
+ sct = SPS::CreditTransfer.new(
50
+ name: 'Schuldner GmbH',
51
+ iban: 'CH5481230000001998736',
52
+ bic: 'RAIFCH22'
53
+ )
54
+
55
+ sca = SPS::CreditorAddress.new(
56
+ country_code: 'CH',
57
+ address_line1: 'Mustergasse 123',
58
+ address_line2: '1234 Musterstadt'
59
+ )
60
+
61
+ sct.add_transaction(
62
+ name: 'Contoso AG',
63
+ bic: 'CRESCHZZ80A',
64
+ iban: 'CH9300762011623852957',
65
+ currency: 'CHF',
66
+ amount: 102.50,
67
+ reference: 'XYZ-1234/123',
68
+ remittance_information: 'Rechnung vom 22.08.2013',
69
+ creditor_address: sca
70
+ )
71
+
72
+ sct
73
+ end
74
+
75
+ it 'should validate against pain.001.001.03.ch.02' do
76
+ expect(
77
+ subject.to_xml(SPS::PAIN_001_001_03_CH_02)
78
+ ).to validate_against('pain.001.001.03.ch.02.xsd')
79
+ end
80
+ end
81
+
82
+ context 'setting creditor address with structured fields' do
83
+ subject do
84
+ sct = SPS::CreditTransfer.new(
85
+ name: 'Schuldner GmbH',
86
+ iban: 'CH5481230000001998736',
87
+ bic: 'RAIFCH22'
88
+ )
89
+
90
+ sca = SPS::CreditorAddress.new(
91
+ country_code: 'CH',
92
+ street_name: 'Mustergasse',
93
+ building_number: '123',
94
+ post_code: '1234',
95
+ town_name: 'Musterstadt'
96
+ )
97
+
98
+ sct.add_transaction(
99
+ name: 'Contoso AG',
100
+ bic: 'CRESCHZZ80A',
101
+ iban: 'CH9300762011623852957',
102
+ amount: 102.50,
103
+ reference: 'XYZ-1234/123',
104
+ remittance_information: 'Rechnung vom 22.08.2013',
105
+ creditor_address: sca
106
+ )
107
+
108
+ sct
109
+ end
110
+
111
+ it "should validate against pain.001.001.03.ch.02" do
112
+ expect(subject.to_xml(SPS::PAIN_001_001_03_CH_02))
113
+ .to validate_against("pain.001.001.03.ch.02.xsd")
114
+ end
115
+ end
116
+
117
+ context 'for valid debtor' do
118
+ context 'with BIC' do
119
+ subject do
120
+ sct = credit_transfer
121
+
122
+ sct.add_transaction(
123
+ name: 'Contoso AG',
124
+ bic: 'CRESCHZZ80A',
125
+ iban: 'CH9300762011623852957',
126
+ service_level: 'SEPA',
127
+ amount: 102.50,
128
+ reference: 'XYZ-1234/123',
129
+ remittance_information: 'Rechnung vom 22.08.2013'
130
+ )
131
+
132
+ sct
133
+ end
134
+
135
+ it 'should validate against pain.001.001.03.ch.02' do
136
+ expect(subject.to_xml('pain.001.001.03.ch.02')).to validate_against('pain.001.001.03.ch.02.xsd')
137
+ end
138
+ end
139
+
140
+ context 'without requested_date given' do
141
+ subject do
142
+ sct = credit_transfer
143
+
144
+ sct.add_transaction(
145
+ name: 'Contoso AG',
146
+ bic: 'CRESCHZZ80A',
147
+ iban: 'CH9300762011623852957',
148
+ amount: 102.50,
149
+ reference: 'XYZ-1234/123',
150
+ remittance_information: 'Rechnung vom 22.08.2013'
151
+ )
152
+
153
+ sct.add_transaction(
154
+ name: 'Amazonas GmbH',
155
+ bic: 'RAIFCH22C32',
156
+ iban: 'CH7081232000001998736',
157
+ amount: 59.00,
158
+ reference: 'XYZ-5678/456',
159
+ remittance_information: 'Rechnung vom 21.08.2013'
160
+ )
161
+
162
+ sct.to_xml
163
+ end
164
+
165
+ it 'should create valid XML file' do
166
+ expect(subject).to validate_against('pain.001.001.03.ch.02.xsd')
167
+ end
168
+
169
+ it 'should have message_identification' do
170
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/GrpHdr/MsgId', message_id_regex)
171
+ end
172
+
173
+ it 'should contain <PmtInfId>' do
174
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/PmtInfId', /#{message_id_regex}\/1/)
175
+ end
176
+
177
+ it 'should contain <ReqdExctnDt>' do
178
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/ReqdExctnDt', Date.new(1999, 1, 1).iso8601)
179
+ end
180
+
181
+ it 'should contain <PmtMtd>' do
182
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/PmtMtd', 'TRF')
183
+ end
184
+
185
+ it 'should contain <BtchBookg>' do
186
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/BtchBookg', 'true')
187
+ end
188
+
189
+ it 'should contain <NbOfTxs>' do
190
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/NbOfTxs', '2')
191
+ end
192
+
193
+ it 'should contain <CtrlSum>' do
194
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CtrlSum', '161.50')
195
+ end
196
+
197
+ it 'should contain <Dbtr>' do
198
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/Dbtr/Nm', 'Schuldner GmbH')
199
+ end
200
+
201
+ it 'should contain <DbtrAcct>' do
202
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/DbtrAcct/Id/IBAN', 'CH5481230000001998736')
203
+ end
204
+
205
+ it 'should contain <DbtrAgt>' do
206
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/DbtrAgt/FinInstnId/BIC', 'RAIFCH22')
207
+ end
208
+
209
+ it 'should contain <EndToEndId>' do
210
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[1]/PmtId/EndToEndId', 'XYZ-1234/123')
211
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[2]/PmtId/EndToEndId', 'XYZ-5678/456')
212
+ end
213
+
214
+ it 'should contain <Amt>' do
215
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[1]/Amt/InstdAmt', '102.50')
216
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[2]/Amt/InstdAmt', '59.00')
217
+ end
218
+
219
+ it 'should contain <CdtrAgt> for every BIC given' do
220
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[1]/CdtrAgt/FinInstnId/BIC', 'CRESCHZZ80A')
221
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[2]/CdtrAgt/FinInstnId/BIC', 'RAIFCH22C32')
222
+ end
223
+
224
+ it 'should contain <Cdtr>' do
225
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[1]/Cdtr/Nm', 'Contoso AG')
226
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[2]/Cdtr/Nm', 'Amazonas GmbH')
227
+ end
228
+
229
+ it 'should contain <CdtrAcct>' do
230
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[1]/CdtrAcct/Id/IBAN', 'CH9300762011623852957')
231
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[2]/CdtrAcct/Id/IBAN', 'CH7081232000001998736')
232
+ end
233
+
234
+ it 'should contain <RmtInf>' do
235
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[1]/RmtInf/Ustrd', 'Rechnung vom 22.08.2013')
236
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[2]/RmtInf/Ustrd', 'Rechnung vom 21.08.2013')
237
+ end
238
+ end
239
+
240
+ context 'with different requested_date given' do
241
+ subject do
242
+ sct = credit_transfer
243
+
244
+ sct.add_transaction(credit_transfer_transaction.merge requested_date: Date.today + 1)
245
+ sct.add_transaction(credit_transfer_transaction.merge requested_date: Date.today + 2)
246
+ sct.add_transaction(credit_transfer_transaction.merge requested_date: Date.today + 2)
247
+
248
+ sct.to_xml
249
+ end
250
+
251
+ it 'should contain two payment_informations with <ReqdExctnDt>' do
252
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[1]/ReqdExctnDt', (Date.today + 1).iso8601)
253
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[2]/ReqdExctnDt', (Date.today + 2).iso8601)
254
+
255
+ expect(subject).not_to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[3]')
256
+ end
257
+
258
+ it 'should contain two payment_informations with different <PmtInfId>' do
259
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[1]/PmtInfId', /#{message_id_regex}\/1/)
260
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[2]/PmtInfId', /#{message_id_regex}\/2/)
261
+ end
262
+ end
263
+
264
+ context 'with different batch_booking given' do
265
+ subject do
266
+ sct = credit_transfer
267
+
268
+ sct.add_transaction(credit_transfer_transaction.merge batch_booking: false)
269
+ sct.add_transaction(credit_transfer_transaction.merge batch_booking: true)
270
+ sct.add_transaction(credit_transfer_transaction.merge batch_booking: true)
271
+
272
+ sct.to_xml
273
+ end
274
+
275
+ it 'should contain two payment_informations with <BtchBookg>' do
276
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[1]/BtchBookg', 'false')
277
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[2]/BtchBookg', 'true')
278
+
279
+ expect(subject).not_to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[3]')
280
+ end
281
+ end
282
+
283
+ context 'with transactions containing different group criteria' do
284
+ subject do
285
+ sct = credit_transfer
286
+
287
+ sct.add_transaction(credit_transfer_transaction.merge requested_date: Date.today + 1, batch_booking: false, amount: 1)
288
+ sct.add_transaction(credit_transfer_transaction.merge requested_date: Date.today + 1, batch_booking: true, amount: 2)
289
+ sct.add_transaction(credit_transfer_transaction.merge requested_date: Date.today + 2, batch_booking: false, amount: 4)
290
+ sct.add_transaction(credit_transfer_transaction.merge requested_date: Date.today + 2, batch_booking: true, amount: 8)
291
+ sct.add_transaction(credit_transfer_transaction.merge requested_date: Date.today + 2, batch_booking: true, category_purpose: 'SALA', amount: 6)
292
+
293
+ sct.to_xml
294
+ end
295
+
296
+ it 'should contain multiple payment_informations' do
297
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[1]/ReqdExctnDt', (Date.today + 1).iso8601)
298
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[1]/BtchBookg', 'false')
299
+
300
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[2]/ReqdExctnDt', (Date.today + 1).iso8601)
301
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[2]/BtchBookg', 'true')
302
+
303
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[3]/ReqdExctnDt', (Date.today + 2).iso8601)
304
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[3]/BtchBookg', 'false')
305
+
306
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[4]/ReqdExctnDt', (Date.today + 2).iso8601)
307
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[4]/BtchBookg', 'true')
308
+
309
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[5]/ReqdExctnDt', (Date.today + 2).iso8601)
310
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[5]/PmtTpInf/CtgyPurp/Cd', 'SALA')
311
+ end
312
+
313
+ it 'should have multiple control sums' do
314
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[1]/CtrlSum', '1.00')
315
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[2]/CtrlSum', '2.00')
316
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[3]/CtrlSum', '4.00')
317
+ expect(subject).to have_xml('//Document/CstmrCdtTrfInitn/PmtInf[4]/CtrlSum', '8.00')
318
+ end
319
+ end
320
+
321
+ context 'with instruction given' do
322
+ subject do
323
+ sct = credit_transfer
324
+
325
+ sct.add_transaction(
326
+ name: 'Contoso AG',
327
+ iban: 'CH5481230000001998736',
328
+ bic: 'RAIFCH22',
329
+ amount: 102.50,
330
+ instruction: '1234/ABC'
331
+ )
332
+
333
+ sct.to_xml
334
+ end
335
+
336
+ it 'should create valid XML file' do
337
+ expect(subject).to validate_against('pain.001.001.03.ch.02.xsd')
338
+ end
339
+
340
+ it 'should contain <InstrId>' do
341
+ expect(subject)
342
+ .to have_xml(
343
+ '//Document/CstmrCdtTrfInitn/PmtInf/CdtTrfTxInf[1]/PmtId/InstrId',
344
+ '1234/ABC'
345
+ )
346
+ end
347
+ end
348
+ end
349
+ end
350
+ end
@@ -0,0 +1,483 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe SPS::DirectDebit do
5
+ let(:message_id_regex) { /SPS-KING\/[0-9a-z_]{22}/ }
6
+
7
+ let(:direct_debit) {
8
+ SPS::DirectDebit.new(
9
+ name: 'Gläubiger GmbH',
10
+ iban: 'CH5481230000001998736',
11
+ creditor_identifier: 'DE98ZZZ09999999999'
12
+ )
13
+ }
14
+
15
+ describe :new do
16
+ it 'should accept missing options' do
17
+ expect {
18
+ SPS::DirectDebit.new
19
+ }.to_not raise_error
20
+ end
21
+ end
22
+
23
+ describe :add_transaction do
24
+ it 'should add valid transactions' do
25
+ 3.times do
26
+ direct_debit.add_transaction(direct_debt_transaction)
27
+ end
28
+
29
+ expect(direct_debit.transactions.size).to eq(3)
30
+ end
31
+
32
+ it 'should fail for invalid transaction' do
33
+ expect {
34
+ direct_debit.add_transaction name: ''
35
+ }.to raise_error(ArgumentError)
36
+ end
37
+ end
38
+
39
+ describe :batch_id do
40
+ it 'returns the id of the batch where the given transactions belongs to (1 batch)' do
41
+ direct_debit.add_transaction(direct_debt_transaction(reference: "EXAMPLE REFERENCE"))
42
+
43
+ expect(direct_debit.batch_id("EXAMPLE REFERENCE")).to match(/#{message_id_regex}\/1/)
44
+ end
45
+
46
+ it 'returns the id of the batch where the given transactions belongs to (2 batches)' do
47
+ direct_debit.add_transaction(direct_debt_transaction(reference: "EXAMPLE REFERENCE 1"))
48
+ direct_debit.add_transaction(direct_debt_transaction(reference: "EXAMPLE REFERENCE 2", requested_date: Date.today.next.next))
49
+ direct_debit.add_transaction(direct_debt_transaction(reference: "EXAMPLE REFERENCE 3"))
50
+
51
+ expect(direct_debit.batch_id("EXAMPLE REFERENCE 1")).to match(/#{message_id_regex}\/1/)
52
+ expect(direct_debit.batch_id("EXAMPLE REFERENCE 2")).to match(/#{message_id_regex}\/2/)
53
+ expect(direct_debit.batch_id("EXAMPLE REFERENCE 3")).to match(/#{message_id_regex}\/1/)
54
+ end
55
+ end
56
+
57
+ describe :batches do
58
+ it 'returns an array of batch ids in the sepa message' do
59
+ direct_debit.add_transaction(direct_debt_transaction(reference: "EXAMPLE REFERENCE 1"))
60
+ direct_debit.add_transaction(direct_debt_transaction(reference: "EXAMPLE REFERENCE 2", requested_date: Date.today.next.next))
61
+ direct_debit.add_transaction(direct_debt_transaction(reference: "EXAMPLE REFERENCE 3"))
62
+
63
+ expect(direct_debit.batches.size).to eq(2)
64
+ expect(direct_debit.batches[0]).to match(/#{message_id_regex}\/[0-9]+/)
65
+ expect(direct_debit.batches[1]).to match(/#{message_id_regex}\/[0-9]+/)
66
+ end
67
+ end
68
+
69
+ describe :to_xml do
70
+ context 'for invalid creditor' do
71
+ it 'should fail' do
72
+ expect {
73
+ SPS::DirectDebit.new.to_xml
74
+ }.to raise_error(SPS::Error)
75
+ end
76
+ end
77
+
78
+ context 'setting debtor address with adrline' do
79
+ subject do
80
+ sdd = SPS::DirectDebit.new(
81
+ name: 'Gläubiger GmbH',
82
+ iban: 'CH7081232000001998736',
83
+ creditor_identifier: 'ABC1W'
84
+ )
85
+
86
+ sda = SPS::DebtorAddress.new(
87
+ country_code: 'CH',
88
+ address_line1: 'Mustergasse 123',
89
+ address_line2: '1234 Musterstadt'
90
+ )
91
+
92
+ sdd.add_transaction(
93
+ name: 'Zahlemann & Söhne GbR',
94
+ iban: 'CH9804835011062385295',
95
+ amount: 39.99,
96
+ instruction: '12',
97
+ reference: 'XYZ/2013-08-ABO/12345',
98
+ remittance_information: 'Unsere Rechnung vom 10.08.2013',
99
+ debtor_address: sda,
100
+ structured_remittance_information: structured_remittance_information
101
+ )
102
+
103
+ sdd
104
+ end
105
+
106
+ it 'should validate against pain.008.001.02.ch.03' do
107
+ expect(subject.to_xml(SPS::PAIN_008_001_02_CH_03))
108
+ .to validate_against('pain.008.001.02.ch.03.xsd')
109
+ end
110
+ end
111
+
112
+ context 'setting debtor address with structured fields' do
113
+ subject do
114
+ sdd = SPS::DirectDebit.new(
115
+ name: 'Gläubiger GmbH',
116
+ iban: 'CH7081232000001998736',
117
+ creditor_identifier: 'ABC1W'
118
+ )
119
+
120
+ sda = SPS::DebtorAddress.new(
121
+ country_code: 'CH',
122
+ street_name: 'Mustergasse 123',
123
+ post_code: '1234',
124
+ town_name: 'Musterstadt'
125
+ )
126
+
127
+ sdd.add_transaction(
128
+ name: 'Zahlemann & Söhne GbR',
129
+ iban: 'CH9804835011062385295',
130
+ amount: 39.99,
131
+ instruction: '12',
132
+ reference: 'XYZ/2013-08-ABO/12345',
133
+ remittance_information: 'Unsere Rechnung vom 10.08.2013',
134
+ debtor_address: sda,
135
+ structured_remittance_information: structured_remittance_information
136
+ )
137
+
138
+ sdd
139
+ end
140
+
141
+ it 'should validate against pain.008.001.02.ch.03' do
142
+ expect(subject.to_xml(SPS::PAIN_008_001_02_CH_03))
143
+ .to validate_against('pain.008.001.02.ch.03.xsd')
144
+ end
145
+ end
146
+
147
+ context 'for valid creditor' do
148
+ context 'for swiss direct debits' do
149
+ let(:creditor_iban) { 'CH7081232000001998736' }
150
+ let(:debtior_iban) { 'CH9804835011062385295' }
151
+
152
+ let(:direct_debit) do
153
+ sdd = SPS::DirectDebit.new(
154
+ name: 'Muster AG',
155
+ isr_participant_number: '010001456',
156
+ iban: creditor_iban,
157
+ creditor_identifier: 'ABC1W'
158
+ )
159
+
160
+ sda = SPS::DebtorAddress.new(
161
+ country_code: 'CH',
162
+ address_line1: 'Mustergasse 123',
163
+ address_line2: '1234 Musterstadt'
164
+ )
165
+
166
+ sdd.add_transaction(
167
+ {
168
+ name: 'HANS TESTER',
169
+ iban: debtior_iban,
170
+ currency: 'CHF',
171
+ amount: '100.0',
172
+ remittance_information: 'According to invoice 4712',
173
+ reference: 'XYZ/2013-08-ABO/12345',
174
+ service_level: service_level,
175
+ local_instrument: local_instrument,
176
+ requested_date: requested_date,
177
+ instruction: 23,
178
+ debtor_address: sda,
179
+ structured_remittance_information: SPS::StructuredRemittanceInformation.new(
180
+ proprietary: 'ESR',
181
+ reference: '185744810000000000200800628'
182
+ )
183
+ }.merge(additional_fields)
184
+ )
185
+
186
+ sdd
187
+ end
188
+
189
+ let(:service_level) { 'CHTA' }
190
+ let(:local_instrument) { 'LSV+' }
191
+
192
+ let(:additional_fields) { {} }
193
+
194
+ let(:requested_date) { Date.today.next }
195
+
196
+ context 'as xml' do
197
+ subject do
198
+ direct_debit.to_xml(SPS::PAIN_008_001_02_CH_03)
199
+ end
200
+
201
+ it 'should have creditor identifier' do
202
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/GrpHdr/InitgPty/Id/OrgId/Othr/Id', direct_debit.account.creditor_identifier)
203
+ end
204
+
205
+ it 'should contain <PmtInfId>' do
206
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/PmtInfId', /#{message_id_regex}\/1/)
207
+ end
208
+
209
+ it 'should contain <ReqdColltnDt>' do
210
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/ReqdColltnDt', requested_date.iso8601)
211
+ end
212
+
213
+ it 'should contain <PmtMtd>' do
214
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/PmtMtd', 'DD')
215
+ end
216
+
217
+ it 'should not contain <BtchBookg>' do
218
+ expect(subject).not_to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/BtchBookg')
219
+ end
220
+
221
+ it 'should not contain <NbOfTxs>' do
222
+ expect(subject).not_to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/NbOfTxs')
223
+ end
224
+
225
+ it 'should not contain <CtrlSum>' do
226
+ expect(subject).not_to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/CtrlSum')
227
+ end
228
+
229
+ it 'should contain <Cdtr>' do
230
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/Cdtr/Nm', 'Muster AG')
231
+ end
232
+
233
+ it 'should contain <CdtrAcct>' do
234
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/CdtrAcct/Id/IBAN', 'CH7081232000001998736')
235
+ end
236
+
237
+ it 'should contain <CdtrAgt>' do
238
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/CdtrAgt/FinInstnId/ClrSysMmbId/MmbId', '81232')
239
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/CdtrAgt/FinInstnId/Othr/Id', '010001456')
240
+ end
241
+
242
+ it 'should not contain <ChrgBr>' do
243
+ expect(subject).not_to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/ChrgBr')
244
+ end
245
+
246
+ context 'when service_level is CHTA' do
247
+ it 'should contain <CdtrSchmeId>' do
248
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/CdtrSchmeId/Id/PrvtId/Othr/Id', direct_debit.account.creditor_identifier)
249
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/CdtrSchmeId/Id/PrvtId/Othr/SchmeNm/Prtry', 'CHLS')
250
+ end
251
+ end
252
+
253
+ context 'when service_level is CHDD' do
254
+ let(:service_level) { 'CHDD' }
255
+ let(:local_instrument) { 'DDCOR1' }
256
+
257
+ it 'should contain <CdtrSchmeId>' do
258
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/CdtrSchmeId/Id/PrvtId/Othr/Id', direct_debit.account.creditor_identifier)
259
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/CdtrSchmeId/Id/PrvtId/Othr/SchmeNm/Prtry', 'CHDD')
260
+ end
261
+ end
262
+
263
+ it 'should contain <EndToEndId>' do
264
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/PmtId/EndToEndId', 'XYZ/2013-08-ABO/12345')
265
+ end
266
+
267
+ it 'should contain <InstdAmt>' do
268
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/InstdAmt', '100.00')
269
+ end
270
+
271
+ it 'should contain <DbtrAgt>' do
272
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/DbtrAgt/FinInstnId/ClrSysMmbId/MmbId', '4835')
273
+ end
274
+
275
+ it 'should contain <Dbtr>' do
276
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/Dbtr/Nm', 'HANS TESTER')
277
+ end
278
+
279
+ it 'should contain <DbtrAcct>' do
280
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/DbtrAcct/Id/IBAN', 'CH9804835011062385295')
281
+ end
282
+
283
+ it 'should contain <Ustrd>' do
284
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/RmtInf/Ustrd', 'According to invoice 4712')
285
+ end
286
+
287
+ it 'should contain <Strd>' do
288
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/RmtInf/Strd/CdtrRefInf/Tp/CdOrPrtry/Prtry', 'ESR')
289
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/DrctDbtTxInf[1]/RmtInf/Strd/CdtrRefInf/Ref', '185744810000000000200800628')
290
+ end
291
+ end
292
+
293
+ context 'with service_level CHDD' do
294
+ let(:service_level) { 'CHDD' }
295
+
296
+ context 'with local_instrument DDCOR1' do
297
+ let(:local_instrument) { 'DDCOR1' }
298
+
299
+ it 'should validate against pain.008.001.02.ch.03' do
300
+ expect(direct_debit.to_xml(SPS::PAIN_008_001_02_CH_03)).to validate_against('pain.008.001.02.ch.03.xsd')
301
+ end
302
+ end
303
+
304
+ context 'with local_instrument DDB2B' do
305
+ let(:local_instrument) { 'DDB2B' }
306
+
307
+ it 'should validate against pain.008.001.02.ch.03' do
308
+ expect(direct_debit.to_xml(SPS::PAIN_008_001_02_CH_03)).to validate_against('pain.008.001.02.ch.03.xsd')
309
+ end
310
+ end
311
+ end
312
+
313
+ context 'with service_level CHTA' do
314
+ let(:service_level) { 'CHTA' }
315
+
316
+ context 'with local_instrument LSV+' do
317
+ let(:local_instrument) { 'LSV+' }
318
+
319
+ it 'should validate against pain.008.001.02.ch.03' do
320
+ expect(direct_debit.to_xml(SPS::PAIN_008_001_02_CH_03)).to validate_against('pain.008.001.02.ch.03.xsd')
321
+ end
322
+ end
323
+
324
+ context 'with local_instrument BDD' do
325
+ let(:local_instrument) { 'BDD' }
326
+
327
+ it 'should validate against pain.008.001.02.ch.03' do
328
+ expect(direct_debit.to_xml(SPS::PAIN_008_001_02_CH_03)).to validate_against('pain.008.001.02.ch.03.xsd')
329
+ end
330
+ end
331
+ end
332
+
333
+ context 'without structured_remittance_information' do
334
+ it 'should not be schema compatible' do
335
+ direct_debit.transactions.first.structured_remittance_information = nil
336
+
337
+ expect {
338
+ direct_debit.to_xml(SPS::PAIN_008_001_02_CH_03)
339
+ }.to raise_error(SPS::Error, "Incompatible with schema pain.008.001.02.ch.03!")
340
+ end
341
+ end
342
+ end
343
+
344
+ context 'without requested_date given' do
345
+ subject do
346
+ sdd = direct_debit
347
+
348
+ sdd.add_transaction(
349
+ name: 'Zahlemann & Söhne GbR',
350
+ iban: 'CH9804835011062385295',
351
+ amount: 39.99,
352
+ instruction: '12',
353
+ reference: 'XYZ/2013-08-ABO/12345',
354
+ remittance_information: 'Unsere Rechnung vom 10.08.2013',
355
+ structured_remittance_information: structured_remittance_information
356
+ )
357
+
358
+ sdd.add_transaction(
359
+ name: 'Meier & Schulze oHG',
360
+ iban: 'CH7081232000001998736',
361
+ amount: 750.00,
362
+ instruction: '34',
363
+ reference: 'XYZ/2013-08-ABO/6789',
364
+ remittance_information: 'Vielen Dank für Ihren Einkauf!',
365
+ structured_remittance_information: structured_remittance_information
366
+ )
367
+
368
+ sdd.to_xml
369
+ end
370
+
371
+ it 'should create valid XML file' do
372
+ expect(subject).to validate_against('pain.008.001.02.ch.03.xsd')
373
+ end
374
+
375
+ it 'should contain <ReqdColltnDt>' do
376
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf/ReqdColltnDt', Date.new(1999, 1, 1).iso8601)
377
+ end
378
+ end
379
+
380
+ context 'with different requested_date given' do
381
+ subject do
382
+ sdd = direct_debit
383
+
384
+ sdd.add_transaction(direct_debt_transaction.merge requested_date: Date.today + 1)
385
+ sdd.add_transaction(direct_debt_transaction.merge requested_date: Date.today + 2)
386
+ sdd.add_transaction(direct_debt_transaction.merge requested_date: Date.today + 2)
387
+
388
+ sdd.to_xml
389
+ end
390
+
391
+ it 'should contain two payment_informations with <ReqdColltnDt>' do
392
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[1]/ReqdColltnDt', (Date.today + 1).iso8601)
393
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[2]/ReqdColltnDt', (Date.today + 2).iso8601)
394
+
395
+ expect(subject).not_to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[3]')
396
+ end
397
+
398
+ it 'should contain two payment_informations with different <PmtInfId>' do
399
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[1]/PmtInfId', /#{message_id_regex}\/1/)
400
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[2]/PmtInfId', /#{message_id_regex}\/2/)
401
+ end
402
+ end
403
+
404
+ context 'with different local_instrument given' do
405
+ subject do
406
+ sdd = direct_debit
407
+
408
+ sdd.add_transaction(direct_debt_transaction.merge local_instrument: 'LSV+')
409
+ sdd.add_transaction(direct_debt_transaction.merge local_instrument: 'BDD')
410
+
411
+ sdd
412
+ end
413
+
414
+ it 'should have errors' do
415
+ expect(subject.errors_on(:base).size).to eq(1)
416
+ end
417
+
418
+ it 'should raise error on XML generation' do
419
+ expect {
420
+ subject.to_xml
421
+ }.to raise_error(SPS::Error)
422
+ end
423
+ end
424
+
425
+ context 'with mismatching local_instrument given' do
426
+ subject do
427
+ sdd = direct_debit
428
+
429
+
430
+ sdd.add_transaction(direct_debt_transaction.merge(local_instrument: 'DDCOR1'))
431
+
432
+ sdd
433
+ end
434
+
435
+ it 'raises an ArgumentError' do
436
+ expect {
437
+ subject.add_transaction(direct_debt_transaction.merge(local_instrument: 'DDB2B'))
438
+ }.to raise_error(
439
+ ArgumentError,
440
+ 'Local instrument is not correct. Must be one of LSV+, BDD'
441
+ )
442
+ end
443
+ end
444
+
445
+ context 'with transactions containing different creditor_account' do
446
+ subject do
447
+ sdd = direct_debit
448
+
449
+ sdd.add_transaction(direct_debt_transaction)
450
+ sdd.add_transaction(
451
+ direct_debt_transaction.merge(
452
+ creditor_account: SPS::CreditorAccount.new(
453
+ name: 'Creditor Inc.',
454
+ iban: 'CH5604835012345678009',
455
+ creditor_identifier: 'ABC1W'
456
+ )
457
+ )
458
+ )
459
+
460
+ sdd.to_xml
461
+ end
462
+
463
+ it 'should contain two payment_informations with <Cdtr>' do
464
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[1]/Cdtr/Nm', 'Gläubiger GmbH')
465
+ expect(subject).to have_xml('//Document/CstmrDrctDbtInitn/PmtInf[2]/Cdtr/Nm', 'Creditor Inc.')
466
+ end
467
+ end
468
+
469
+ context 'with large message identification' do
470
+ subject do
471
+ sct = direct_debit
472
+ sct.message_identification = 'A' * 35
473
+ sct.add_transaction(direct_debt_transaction.merge(instruction: '1234/ABC'))
474
+ sct
475
+ end
476
+
477
+ it 'should fail as the payment identification becomes too large' do
478
+ expect { subject.to_xml }.to raise_error(SPS::Error)
479
+ end
480
+ end
481
+ end
482
+ end
483
+ end