sps_king 0.5.0 → 0.6.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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +3 -3
  3. data/CHANGELOG.md +9 -0
  4. data/README.md +17 -14
  5. data/gemfiles/{Gemfile-activemodel-6.1.x → Gemfile-activemodel-7.2.x} +1 -1
  6. data/gemfiles/{Gemfile-activemodel-7.0.x → Gemfile-activemodel-8.0.x} +1 -1
  7. data/lib/sps_king/account/address.rb +55 -0
  8. data/lib/sps_king/account/creditor_account.rb +3 -0
  9. data/lib/sps_king/account/creditor_address.rb +2 -34
  10. data/lib/sps_king/account/debtor_account.rb +1 -0
  11. data/lib/sps_king/account/debtor_address.rb +2 -31
  12. data/lib/sps_king/account.rb +3 -0
  13. data/lib/sps_king/converter.rb +14 -10
  14. data/lib/sps_king/message/credit_transfer.rb +114 -111
  15. data/lib/sps_king/message/direct_debit.rb +121 -118
  16. data/lib/sps_king/message.rb +54 -48
  17. data/lib/sps_king/structured_remittance_information.rb +2 -0
  18. data/lib/sps_king/transaction/credit_transfer_transaction.rb +3 -0
  19. data/lib/sps_king/transaction/direct_debit_transaction.rb +9 -6
  20. data/lib/sps_king/transaction.rb +10 -7
  21. data/lib/sps_king/validator.rb +9 -0
  22. data/lib/sps_king/version.rb +3 -1
  23. data/lib/sps_king.rb +1 -0
  24. data/spec/lib/sps_king/account/address_spec.rb +85 -0
  25. data/spec/lib/sps_king/account/creditor_account_spec.rb +14 -13
  26. data/spec/lib/sps_king/account/debtor_account_spec.rb +1 -0
  27. data/spec/lib/sps_king/account_spec.rb +12 -2
  28. data/spec/lib/sps_king/converter_spec.rb +25 -5
  29. data/spec/lib/sps_king/message/credit_transfer_spec.rb +184 -45
  30. data/spec/lib/sps_king/message/direct_debit_spec.rb +218 -102
  31. data/spec/lib/sps_king/message_spec.rb +23 -8
  32. data/spec/lib/sps_king/structured_remittance_information_spec.rb +7 -2
  33. data/spec/lib/sps_king/transaction/credit_transfer_transaction_spec.rb +14 -2
  34. data/spec/lib/sps_king/transaction/direct_debit_transaction_spec.rb +8 -7
  35. data/spec/lib/sps_king/transaction_spec.rb +62 -27
  36. data/spec/lib/sps_king/validator_spec.rb +38 -9
  37. data/spec/spec_helper.rb +8 -4
  38. data/spec/support/active_model.rb +3 -1
  39. data/spec/support/factories.rb +11 -10
  40. data/spec/support/validations.rb +2 -0
  41. data/sps_king.gemspec +1 -0
  42. metadata +8 -12
  43. data/spec/lib/sps_king/account/creditor_address_spec.rb +0 -14
  44. data/spec/lib/sps_king/account/debtor_address_spec.rb +0 -14
@@ -2,6 +2,7 @@
2
2
 
3
3
  module SPS
4
4
  class CreditTransfer < Message
5
+
5
6
  self.account_class = DebtorAccount
6
7
  self.transaction_class = CreditTransferTransaction
7
8
  self.xml_main_tag = 'CstmrCdtTrfInitn'
@@ -9,150 +10,152 @@ module SPS
9
10
  PAIN_001_001_03_CH_02
10
11
  ]
11
12
 
12
- private
13
- # Find groups of transactions which share the same values of some attributes
14
- def transaction_group(transaction)
15
- {
16
- requested_date: transaction.requested_date,
17
- batch_booking: transaction.batch_booking,
18
- service_level: transaction.service_level,
19
- category_purpose: transaction.category_purpose,
20
- charge_bearer: transaction.charge_bearer,
21
- }
22
- end
13
+ private
14
+
15
+ # Find groups of transactions which share the same values of some attributes
16
+ def transaction_group(transaction)
17
+ {
18
+ requested_date: transaction.requested_date,
19
+ batch_booking: transaction.batch_booking,
20
+ service_level: transaction.service_level,
21
+ category_purpose: transaction.category_purpose,
22
+ charge_bearer: transaction.charge_bearer,
23
+ }
24
+ end
23
25
 
24
- def build_payment_informations(builder)
25
- # Build a PmtInf block for every group of transactions
26
- grouped_transactions.each do |group, transactions|
27
- # All transactions with the same requested_date are placed into the same PmtInf block
28
- builder.PmtInf do
29
- builder.PmtInfId(payment_information_identification(group))
30
- builder.PmtMtd('TRF')
31
- builder.BtchBookg(group[:batch_booking])
32
- builder.NbOfTxs(transactions.length)
33
- builder.CtrlSum('%.2f' % amount_total(transactions))
34
- builder.PmtTpInf do
35
- if group[:service_level]
36
- builder.SvcLvl do
37
- builder.Cd(group[:service_level])
26
+ def build_payment_informations(builder)
27
+ # Build a PmtInf block for every group of transactions
28
+ grouped_transactions.each do |group, transactions|
29
+ # All transactions with the same requested_date are placed into the same PmtInf block
30
+ builder.PmtInf do
31
+ builder.PmtInfId(payment_information_identification(group))
32
+ builder.PmtMtd('TRF')
33
+ builder.BtchBookg(group[:batch_booking])
34
+ builder.NbOfTxs(transactions.length)
35
+ builder.CtrlSum('%.2f' % amount_total(transactions))
36
+ builder.PmtTpInf do
37
+ if group[:service_level]
38
+ builder.SvcLvl do
39
+ builder.Cd(group[:service_level])
40
+ end
41
+ end
42
+ if group[:category_purpose]
43
+ builder.CtgyPurp do
44
+ builder.Cd(group[:category_purpose])
45
+ end
38
46
  end
39
47
  end
40
- if group[:category_purpose]
41
- builder.CtgyPurp do
42
- builder.Cd(group[:category_purpose])
48
+ builder.ReqdExctnDt(group[:requested_date].iso8601)
49
+ builder.Dbtr do
50
+ builder.Nm(account.name)
51
+ end
52
+ builder.DbtrAcct do
53
+ builder.Id do
54
+ builder.IBAN(account.iban)
43
55
  end
44
56
  end
45
- end
46
- builder.ReqdExctnDt(group[:requested_date].iso8601)
47
- builder.Dbtr do
48
- builder.Nm(account.name)
49
- end
50
- builder.DbtrAcct do
51
- builder.Id do
52
- builder.IBAN(account.iban)
57
+ builder.DbtrAgt do
58
+ builder.FinInstnId do
59
+ builder.BIC(account.bic)
60
+ end
53
61
  end
54
- end
55
- builder.DbtrAgt do
56
- builder.FinInstnId do
57
- builder.BIC(account.bic)
62
+ if group[:charge_bearer]
63
+ builder.ChrgBr(group[:charge_bearer])
58
64
  end
59
- end
60
- if group[:charge_bearer]
61
- builder.ChrgBr(group[:charge_bearer])
62
- end
63
65
 
64
- transactions.each do |transaction|
65
- build_transaction(builder, transaction)
66
+ transactions.each do |transaction|
67
+ build_transaction(builder, transaction)
68
+ end
66
69
  end
67
70
  end
68
71
  end
69
- end
70
72
 
71
- def build_transaction(builder, transaction)
72
- builder.CdtTrfTxInf do
73
- builder.PmtId do
74
- if transaction.instruction.present?
75
- builder.InstrId(transaction.instruction)
76
- end
77
- builder.EndToEndId(transaction.reference)
78
- end
79
- builder.Amt do
80
- builder.InstdAmt('%.2f' % transaction.amount, Ccy: transaction.currency)
81
- end
82
- if transaction.bic
83
- builder.CdtrAgt do
84
- builder.FinInstnId do
85
- builder.BIC(transaction.bic)
73
+ def build_transaction(builder, transaction)
74
+ builder.CdtTrfTxInf do
75
+ builder.PmtId do
76
+ if transaction.instruction.present?
77
+ builder.InstrId(transaction.instruction)
86
78
  end
79
+ builder.EndToEndId(transaction.reference)
87
80
  end
88
- end
89
- builder.Cdtr do
90
- builder.Nm(transaction.name)
91
- if transaction.creditor_address
92
- builder.PstlAdr do
93
- # Only set the fields that are actually provided.
94
- # StrtNm, BldgNb, PstCd, TwnNm provide a structured address
95
- # separated into its individual fields.
96
- # AdrLine provides the address in free format text.
97
- # Both are currently allowed and the actual preference depends on the bank.
98
- # Also the fields that are required legally may vary depending on the country
99
- # or change over time.
100
- if transaction.creditor_address.street_name
101
- builder.StrtNm transaction.creditor_address.street_name
81
+ builder.Amt do
82
+ builder.InstdAmt('%.2f' % transaction.amount, Ccy: transaction.currency)
83
+ end
84
+ if transaction.bic
85
+ builder.CdtrAgt do
86
+ builder.FinInstnId do
87
+ builder.BIC(transaction.bic)
102
88
  end
89
+ end
90
+ end
91
+ builder.Cdtr do
92
+ builder.Nm(transaction.name)
93
+ if transaction.creditor_address
94
+ builder.PstlAdr do
95
+ # Only set the fields that are actually provided.
96
+ # StrtNm, BldgNb, PstCd, TwnNm provide a structured address
97
+ # separated into its individual fields.
98
+ # AdrLine provides the address in free format text.
99
+ # Both are currently allowed and the actual preference depends on the bank.
100
+ # Also the fields that are required legally may vary depending on the country
101
+ # or change over time.
102
+ if transaction.creditor_address.street_name
103
+ builder.StrtNm transaction.creditor_address.street_name
104
+ end
103
105
 
104
- if transaction.creditor_address.building_number
105
- builder.BldgNb transaction.creditor_address.building_number
106
- end
106
+ if transaction.creditor_address.building_number
107
+ builder.BldgNb transaction.creditor_address.building_number
108
+ end
107
109
 
108
- if transaction.creditor_address.post_code
109
- builder.PstCd transaction.creditor_address.post_code
110
- end
110
+ if transaction.creditor_address.post_code
111
+ builder.PstCd transaction.creditor_address.post_code
112
+ end
111
113
 
112
- if transaction.creditor_address.town_name
113
- builder.TwnNm transaction.creditor_address.town_name
114
- end
114
+ if transaction.creditor_address.town_name
115
+ builder.TwnNm transaction.creditor_address.town_name
116
+ end
115
117
 
116
- if transaction.creditor_address.country_code
117
- builder.Ctry transaction.creditor_address.country_code
118
- end
118
+ if transaction.creditor_address.country_code
119
+ builder.Ctry transaction.creditor_address.country_code
120
+ end
119
121
 
120
- if transaction.creditor_address.address_line1
121
- builder.AdrLine transaction.creditor_address.address_line1
122
- end
122
+ if transaction.creditor_address.address_line1
123
+ builder.AdrLine transaction.creditor_address.address_line1
124
+ end
123
125
 
124
- if transaction.creditor_address.address_line2
125
- builder.AdrLine transaction.creditor_address.address_line2
126
+ if transaction.creditor_address.address_line2
127
+ builder.AdrLine transaction.creditor_address.address_line2
128
+ end
126
129
  end
127
130
  end
128
131
  end
129
- end
130
- builder.CdtrAcct do
131
- builder.Id do
132
- builder.IBAN(transaction.iban)
133
- end
134
- end
135
- if transaction.remittance_information || transaction.structured_remittance_information
136
- builder.RmtInf do
137
- if transaction.remittance_information
138
- builder.Ustrd(transaction.remittance_information)
132
+ builder.CdtrAcct do
133
+ builder.Id do
134
+ builder.IBAN(transaction.iban)
139
135
  end
136
+ end
137
+ if transaction.remittance_information || transaction.structured_remittance_information
138
+ builder.RmtInf do
139
+ if transaction.remittance_information
140
+ builder.Ustrd(transaction.remittance_information)
141
+ end
140
142
 
141
- if transaction.structured_remittance_information
142
- builder.Strd do
143
- builder.CdtrRefInf do
144
- builder.Tp do
145
- builder.CdOrPrtry do
146
- builder.Prtry(transaction.structured_remittance_information.proprietary)
143
+ if transaction.structured_remittance_information
144
+ builder.Strd do
145
+ builder.CdtrRefInf do
146
+ builder.Tp do
147
+ builder.CdOrPrtry do
148
+ builder.Prtry(transaction.structured_remittance_information.proprietary)
149
+ end
147
150
  end
151
+ builder.Ref(transaction.structured_remittance_information.reference)
148
152
  end
149
- builder.Ref(transaction.structured_remittance_information.reference)
150
153
  end
151
154
  end
152
155
  end
153
156
  end
154
157
  end
155
158
  end
156
- end
159
+
157
160
  end
158
161
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module SPS
4
4
  class DirectDebit < Message
5
+
5
6
  self.account_class = CreditorAccount
6
7
  self.transaction_class = DirectDebitTransaction
7
8
  self.xml_main_tag = 'CstmrDrctDbtInitn'
@@ -18,160 +19,162 @@ module SPS
18
19
  end
19
20
  end
20
21
 
21
- private
22
- # Find groups of transactions which share the same values of some attributes
23
- def transaction_group(transaction)
24
- {
25
- requested_date: transaction.requested_date,
26
- service_level: transaction.service_level,
27
- local_instrument: transaction.local_instrument,
28
- account: transaction.creditor_account || account
29
- }
30
- end
22
+ private
31
23
 
32
- def creditor_scheme_name(service_level)
33
- case service_level
34
- when 'CHDD' # PAIN_008_001_02_CH_03 only
35
- return 'CHDD'
36
- when 'CHTA' # PAIN_008_001_02_CH_03 only
37
- return 'CHLS'
24
+ # Find groups of transactions which share the same values of some attributes
25
+ def transaction_group(transaction)
26
+ {
27
+ requested_date: transaction.requested_date,
28
+ service_level: transaction.service_level,
29
+ local_instrument: transaction.local_instrument,
30
+ account: transaction.creditor_account || account
31
+ }
38
32
  end
39
- end
40
33
 
41
- # For IBANs from Switzerland or Liechtenstein the clearing system member id can be retrieved
42
- # as the 5th to 9th digit of the IBAN, which is the local bank code.
43
- def clearing_system_member_id_from_iban(iban)
44
- return iban.to_s[4..8].sub(/^0*/, '')
45
- end
34
+ def creditor_scheme_name(service_level)
35
+ case service_level
36
+ when 'CHDD' # PAIN_008_001_02_CH_03 only
37
+ return 'CHDD'
38
+ when 'CHTA' # PAIN_008_001_02_CH_03 only
39
+ return 'CHLS'
40
+ end
41
+ end
46
42
 
47
- def build_payment_informations(builder)
48
- # Build a PmtInf block for every group of transactions
49
- grouped_transactions.each do |group, transactions|
50
- builder.PmtInf do
51
- builder.PmtInfId(payment_information_identification(group))
52
- builder.PmtMtd('DD')
53
- builder.PmtTpInf do
54
- builder.SvcLvl do
55
- builder.Prtry(group[:service_level])
56
- end
57
- builder.LclInstrm do
58
- builder.Prtry(group[:local_instrument])
43
+ # For IBANs from Switzerland or Liechtenstein the clearing system member id can be retrieved
44
+ # as the 5th to 9th digit of the IBAN, which is the local bank code.
45
+ def clearing_system_member_id_from_iban(iban)
46
+ return iban.to_s[4..8].sub(/^0*/, '')
47
+ end
48
+
49
+ def build_payment_informations(builder)
50
+ # Build a PmtInf block for every group of transactions
51
+ grouped_transactions.each do |group, transactions|
52
+ builder.PmtInf do
53
+ builder.PmtInfId(payment_information_identification(group))
54
+ builder.PmtMtd('DD')
55
+ builder.PmtTpInf do
56
+ builder.SvcLvl do
57
+ builder.Prtry(group[:service_level])
58
+ end
59
+ builder.LclInstrm do
60
+ builder.Prtry(group[:local_instrument])
61
+ end
59
62
  end
60
- end
61
- builder.ReqdColltnDt(group[:requested_date].iso8601)
62
- builder.Cdtr do
63
- builder.Nm(group[:account].name)
64
- end
65
- builder.CdtrAcct do
66
- builder.Id do
67
- builder.IBAN(group[:account].iban)
63
+ builder.ReqdColltnDt(group[:requested_date].iso8601)
64
+ builder.Cdtr do
65
+ builder.Nm(group[:account].name)
68
66
  end
69
- end
70
- builder.CdtrAgt do
71
- builder.FinInstnId do
72
- builder.ClrSysMmbId do
73
- builder.MmbId(clearing_system_member_id_from_iban(group[:account].iban))
67
+ builder.CdtrAcct do
68
+ builder.Id do
69
+ builder.IBAN(group[:account].iban)
74
70
  end
75
- if group[:account].isr_participant_number
76
- builder.Othr do
77
- builder.Id(group[:account].isr_participant_number)
71
+ end
72
+ builder.CdtrAgt do
73
+ builder.FinInstnId do
74
+ builder.ClrSysMmbId do
75
+ builder.MmbId(clearing_system_member_id_from_iban(group[:account].iban))
76
+ end
77
+ if group[:account].isr_participant_number
78
+ builder.Othr do
79
+ builder.Id(group[:account].isr_participant_number)
80
+ end
78
81
  end
79
82
  end
80
83
  end
81
- end
82
- builder.CdtrSchmeId do
83
- builder.Id do
84
- builder.PrvtId do
85
- builder.Othr do
86
- builder.Id(group[:account].creditor_identifier)
87
- builder.SchmeNm do
88
- builder.Prtry(creditor_scheme_name(group[:service_level]))
84
+ builder.CdtrSchmeId do
85
+ builder.Id do
86
+ builder.PrvtId do
87
+ builder.Othr do
88
+ builder.Id(group[:account].creditor_identifier)
89
+ builder.SchmeNm do
90
+ builder.Prtry(creditor_scheme_name(group[:service_level]))
91
+ end
89
92
  end
90
93
  end
91
94
  end
92
95
  end
93
- end
94
96
 
95
- transactions.each do |transaction|
96
- build_transaction(builder, transaction)
97
+ transactions.each do |transaction|
98
+ build_transaction(builder, transaction)
99
+ end
97
100
  end
98
101
  end
99
102
  end
100
- end
101
103
 
102
- def build_transaction(builder, transaction)
103
- builder.DrctDbtTxInf do
104
- builder.PmtId do
105
- builder.InstrId(transaction.instruction)
106
- builder.EndToEndId(transaction.reference)
107
- end
108
- builder.InstdAmt('%.2f' % transaction.amount, Ccy: transaction.currency)
109
- builder.DbtrAgt do
110
- builder.FinInstnId do
111
- builder.ClrSysMmbId do
112
- builder.MmbId(clearing_system_member_id_from_iban(transaction.iban))
113
- end
104
+ def build_transaction(builder, transaction)
105
+ builder.DrctDbtTxInf do
106
+ builder.PmtId do
107
+ builder.InstrId(transaction.instruction)
108
+ builder.EndToEndId(transaction.reference)
114
109
  end
115
- end
116
- builder.Dbtr do
117
- builder.Nm(transaction.name)
118
- if transaction.debtor_address
119
- builder.PstlAdr do
120
- # Only set the fields that are actually provided.
121
- # StrtNm, BldgNb, PstCd, TwnNm provide a structured address
122
- # separated into its individual fields.
123
- # AdrLine provides the address in free format text.
124
- # Both are currently allowed and the actual preference depends on the bank.
125
- # Also the fields that are required legally may vary depending on the country
126
- # or change over time.
127
- if transaction.debtor_address.street_name
128
- builder.StrtNm transaction.debtor_address.street_name
110
+ builder.InstdAmt('%.2f' % transaction.amount, Ccy: transaction.currency)
111
+ builder.DbtrAgt do
112
+ builder.FinInstnId do
113
+ builder.ClrSysMmbId do
114
+ builder.MmbId(clearing_system_member_id_from_iban(transaction.iban))
129
115
  end
116
+ end
117
+ end
118
+ builder.Dbtr do
119
+ builder.Nm(transaction.name)
120
+ if transaction.debtor_address
121
+ builder.PstlAdr do
122
+ # Only set the fields that are actually provided.
123
+ # StrtNm, BldgNb, PstCd, TwnNm provide a structured address
124
+ # separated into its individual fields.
125
+ # AdrLine provides the address in free format text.
126
+ # Both are currently allowed and the actual preference depends on the bank.
127
+ # Also the fields that are required legally may vary depending on the country
128
+ # or change over time.
129
+ if transaction.debtor_address.street_name
130
+ builder.StrtNm transaction.debtor_address.street_name
131
+ end
130
132
 
131
- if transaction.debtor_address.post_code
132
- builder.PstCd transaction.debtor_address.post_code
133
- end
133
+ if transaction.debtor_address.post_code
134
+ builder.PstCd transaction.debtor_address.post_code
135
+ end
134
136
 
135
- if transaction.debtor_address.town_name
136
- builder.TwnNm transaction.debtor_address.town_name
137
- end
137
+ if transaction.debtor_address.town_name
138
+ builder.TwnNm transaction.debtor_address.town_name
139
+ end
138
140
 
139
- if transaction.debtor_address.country_code
140
- builder.Ctry transaction.debtor_address.country_code
141
- end
141
+ if transaction.debtor_address.country_code
142
+ builder.Ctry transaction.debtor_address.country_code
143
+ end
142
144
 
143
- if transaction.debtor_address.address_line1
144
- builder.AdrLine transaction.debtor_address.address_line1
145
- end
145
+ if transaction.debtor_address.address_line1
146
+ builder.AdrLine transaction.debtor_address.address_line1
147
+ end
146
148
 
147
- if transaction.debtor_address.address_line2
148
- builder.AdrLine transaction.debtor_address.address_line2
149
+ if transaction.debtor_address.address_line2
150
+ builder.AdrLine transaction.debtor_address.address_line2
151
+ end
149
152
  end
150
153
  end
151
154
  end
152
- end
153
- builder.DbtrAcct do
154
- builder.Id do
155
- builder.IBAN(transaction.iban)
156
- end
157
- end
158
- builder.RmtInf do
159
- if transaction.remittance_information
160
- builder.Ustrd(transaction.remittance_information)
155
+ builder.DbtrAcct do
156
+ builder.Id do
157
+ builder.IBAN(transaction.iban)
158
+ end
161
159
  end
160
+ builder.RmtInf do
161
+ if transaction.remittance_information
162
+ builder.Ustrd(transaction.remittance_information)
163
+ end
162
164
 
163
- builder.Strd do
164
- builder.CdtrRefInf do
165
- builder.Tp do
166
- builder.CdOrPrtry do
167
- builder.Prtry(transaction.structured_remittance_information.proprietary)
165
+ builder.Strd do
166
+ builder.CdtrRefInf do
167
+ builder.Tp do
168
+ builder.CdOrPrtry do
169
+ builder.Prtry(transaction.structured_remittance_information.proprietary)
170
+ end
168
171
  end
172
+ builder.Ref(transaction.structured_remittance_information.reference)
169
173
  end
170
- builder.Ref(transaction.structured_remittance_information.reference)
171
174
  end
172
175
  end
173
176
  end
174
177
  end
175
- end
178
+
176
179
  end
177
180
  end