sepa_king_codeur 0.12.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +37 -0
- data/CONTRIBUTING.md +38 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +22 -0
- data/README.md +297 -0
- data/Rakefile +6 -0
- data/gemfiles/Gemfile-activemodel-3.1.x +5 -0
- data/gemfiles/Gemfile-activemodel-3.2.x +5 -0
- data/gemfiles/Gemfile-activemodel-4.0.x +5 -0
- data/gemfiles/Gemfile-activemodel-4.1.x +5 -0
- data/gemfiles/Gemfile-activemodel-4.2.x +5 -0
- data/gemfiles/Gemfile-activemodel-5.0.x +5 -0
- data/gemfiles/Gemfile-activemodel-5.1.x +5 -0
- data/gemfiles/Gemfile-activemodel-5.2.x +5 -0
- data/gemfiles/Gemfile-activemodel-6.0.x +5 -0
- data/lib/schema/pain.001.001.03.ch.02.xsd +1212 -0
- data/lib/schema/pain.001.001.03.xsd +921 -0
- data/lib/schema/pain.001.002.03.xsd +450 -0
- data/lib/schema/pain.001.003.03.xsd +474 -0
- data/lib/schema/pain.008.001.02.xsd +879 -0
- data/lib/schema/pain.008.002.02.xsd +597 -0
- data/lib/schema/pain.008.003.02.xsd +614 -0
- data/lib/sepa_king.rb +19 -0
- data/lib/sepa_king/account.rb +19 -0
- data/lib/sepa_king/account/creditor_account.rb +8 -0
- data/lib/sepa_king/account/creditor_address.rb +37 -0
- data/lib/sepa_king/account/debtor_account.rb +5 -0
- data/lib/sepa_king/account/debtor_address.rb +37 -0
- data/lib/sepa_king/converter.rb +51 -0
- data/lib/sepa_king/error.rb +4 -0
- data/lib/sepa_king/message.rb +169 -0
- data/lib/sepa_king/message/credit_transfer.rb +137 -0
- data/lib/sepa_king/message/direct_debit.rb +207 -0
- data/lib/sepa_king/transaction.rb +56 -0
- data/lib/sepa_king/transaction/credit_transfer_transaction.rb +31 -0
- data/lib/sepa_king/transaction/direct_debit_transaction.rb +56 -0
- data/lib/sepa_king/validator.rb +57 -0
- data/lib/sepa_king/version.rb +3 -0
- data/sepa_king.gemspec +33 -0
- data/spec/account_spec.rb +42 -0
- data/spec/converter_spec.rb +74 -0
- data/spec/credit_transfer_spec.rb +520 -0
- data/spec/credit_transfer_transaction_spec.rb +74 -0
- data/spec/creditor_account_spec.rb +23 -0
- data/spec/debtor_account_spec.rb +12 -0
- data/spec/debtor_address_spec.rb +12 -0
- data/spec/direct_debit_spec.rb +657 -0
- data/spec/direct_debit_transaction_spec.rb +69 -0
- data/spec/examples/pain.001.001.03.ch.02.xml +172 -0
- data/spec/examples/pain.001.001.03.xml +89 -0
- data/spec/examples/pain.001.002.03.xml +89 -0
- data/spec/examples/pain.001.003.03.xml +89 -0
- data/spec/examples/pain.008.002.02.xml +134 -0
- data/spec/examples/pain.008.003.02.xml +134 -0
- data/spec/message_spec.rb +128 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/support/active_model.rb +30 -0
- data/spec/support/custom_matcher.rb +60 -0
- data/spec/support/factories.rb +24 -0
- data/spec/support/validations.rb +27 -0
- data/spec/transaction_spec.rb +134 -0
- data/spec/validation_spec.rb +25 -0
- data/spec/validator_spec.rb +99 -0
- metadata +250 -0
@@ -0,0 +1,207 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module SEPA
|
4
|
+
class DirectDebit < Message
|
5
|
+
self.account_class = CreditorAccount
|
6
|
+
self.transaction_class = DirectDebitTransaction
|
7
|
+
self.xml_main_tag = 'CstmrDrctDbtInitn'
|
8
|
+
self.known_schemas = [ PAIN_008_003_02, PAIN_008_002_02, PAIN_008_001_02 ]
|
9
|
+
|
10
|
+
validate do |record|
|
11
|
+
if record.transactions.map(&:local_instrument).uniq.size > 1
|
12
|
+
errors.add(:base, 'CORE, COR1 AND B2B must not be mixed in one message!')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
# Find groups of transactions which share the same values of some attributes
|
18
|
+
def transaction_group(transaction)
|
19
|
+
{ requested_date: transaction.requested_date,
|
20
|
+
local_instrument: transaction.local_instrument,
|
21
|
+
sequence_type: transaction.sequence_type,
|
22
|
+
batch_booking: transaction.batch_booking,
|
23
|
+
account: transaction.creditor_account || account
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def build_payment_informations(builder)
|
28
|
+
# Build a PmtInf block for every group of transactions
|
29
|
+
grouped_transactions.each do |group, transactions|
|
30
|
+
builder.PmtInf do
|
31
|
+
builder.PmtInfId(payment_information_identification(group))
|
32
|
+
builder.PmtMtd('DD')
|
33
|
+
builder.BtchBookg(group[:batch_booking])
|
34
|
+
builder.NbOfTxs(transactions.length)
|
35
|
+
builder.CtrlSum('%.2f' % amount_total(transactions))
|
36
|
+
builder.PmtTpInf do
|
37
|
+
builder.SvcLvl do
|
38
|
+
builder.Cd('SEPA')
|
39
|
+
end
|
40
|
+
builder.LclInstrm do
|
41
|
+
builder.Cd(group[:local_instrument])
|
42
|
+
end
|
43
|
+
builder.SeqTp(group[:sequence_type])
|
44
|
+
end
|
45
|
+
builder.ReqdColltnDt(group[:requested_date].iso8601)
|
46
|
+
builder.Cdtr do
|
47
|
+
builder.Nm(group[:account].name)
|
48
|
+
end
|
49
|
+
builder.CdtrAcct do
|
50
|
+
builder.Id do
|
51
|
+
builder.IBAN(group[:account].iban)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
builder.CdtrAgt do
|
55
|
+
builder.FinInstnId do
|
56
|
+
if group[:account].bic
|
57
|
+
builder.BIC(group[:account].bic)
|
58
|
+
else
|
59
|
+
builder.Othr do
|
60
|
+
builder.Id('NOTPROVIDED')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
builder.ChrgBr('SLEV')
|
66
|
+
builder.CdtrSchmeId do
|
67
|
+
builder.Id do
|
68
|
+
builder.PrvtId do
|
69
|
+
builder.Othr do
|
70
|
+
builder.Id(group[:account].creditor_identifier)
|
71
|
+
builder.SchmeNm do
|
72
|
+
builder.Prtry('SEPA')
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
transactions.each do |transaction|
|
80
|
+
build_transaction(builder, transaction)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def build_amendment_informations(builder, transaction)
|
87
|
+
builder.AmdmntInd(true)
|
88
|
+
builder.AmdmntInfDtls do
|
89
|
+
if transaction.original_debtor_account
|
90
|
+
builder.OrgnlDbtrAcct do
|
91
|
+
builder.Id do
|
92
|
+
builder.IBAN(transaction.original_debtor_account)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
elsif transaction.same_mandate_new_debtor_agent
|
96
|
+
builder.OrgnlDbtrAgt do
|
97
|
+
builder.FinInstnId do
|
98
|
+
builder.Othr do
|
99
|
+
builder.Id('SMNDA')
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
if transaction.original_creditor_account
|
105
|
+
builder.OrgnlCdtrSchmeId do
|
106
|
+
if transaction.original_creditor_account.name
|
107
|
+
builder.Nm(transaction.original_creditor_account.name)
|
108
|
+
end
|
109
|
+
if transaction.original_creditor_account.creditor_identifier
|
110
|
+
builder.Id do
|
111
|
+
builder.PrvtId do
|
112
|
+
builder.Othr do
|
113
|
+
builder.Id(transaction.original_creditor_account.creditor_identifier)
|
114
|
+
builder.SchmeNm do
|
115
|
+
builder.Prtry('SEPA')
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def build_transaction(builder, transaction)
|
127
|
+
builder.DrctDbtTxInf do
|
128
|
+
builder.PmtId do
|
129
|
+
if transaction.instruction.present?
|
130
|
+
builder.InstrId(transaction.instruction)
|
131
|
+
end
|
132
|
+
builder.EndToEndId(transaction.reference)
|
133
|
+
end
|
134
|
+
builder.InstdAmt('%.2f' % transaction.amount, Ccy: transaction.currency)
|
135
|
+
builder.DrctDbtTx do
|
136
|
+
builder.MndtRltdInf do
|
137
|
+
builder.MndtId(transaction.mandate_id)
|
138
|
+
builder.DtOfSgntr(transaction.mandate_date_of_signature.iso8601)
|
139
|
+
build_amendment_informations(builder, transaction) if transaction.amendment_informations?
|
140
|
+
end
|
141
|
+
end
|
142
|
+
builder.DbtrAgt do
|
143
|
+
builder.FinInstnId do
|
144
|
+
if transaction.bic
|
145
|
+
builder.BIC(transaction.bic)
|
146
|
+
else
|
147
|
+
builder.Othr do
|
148
|
+
builder.Id('NOTPROVIDED')
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
builder.Dbtr do
|
154
|
+
builder.Nm(transaction.name)
|
155
|
+
if transaction.debtor_address
|
156
|
+
builder.PstlAdr do
|
157
|
+
# Only set the fields that are actually provided.
|
158
|
+
# StrtNm, BldgNb, PstCd, TwnNm provide a structured address
|
159
|
+
# separated into its individual fields.
|
160
|
+
# AdrLine provides the address in free format text.
|
161
|
+
# Both are currently allowed and the actual preference depends on the bank.
|
162
|
+
# Also the fields that are required legally may vary depending on the country
|
163
|
+
# or change over time.
|
164
|
+
if transaction.debtor_address.street_name
|
165
|
+
builder.StrtNm transaction.debtor_address.street_name
|
166
|
+
end
|
167
|
+
|
168
|
+
if transaction.debtor_address.building_number
|
169
|
+
builder.BldgNb transaction.debtor_address.building_number
|
170
|
+
end
|
171
|
+
|
172
|
+
if transaction.debtor_address.post_code
|
173
|
+
builder.PstCd transaction.debtor_address.post_code
|
174
|
+
end
|
175
|
+
|
176
|
+
if transaction.debtor_address.town_name
|
177
|
+
builder.TwnNm transaction.debtor_address.town_name
|
178
|
+
end
|
179
|
+
|
180
|
+
if transaction.debtor_address.country_code
|
181
|
+
builder.Ctry transaction.debtor_address.country_code
|
182
|
+
end
|
183
|
+
|
184
|
+
if transaction.debtor_address.address_line1
|
185
|
+
builder.AdrLine transaction.debtor_address.address_line1
|
186
|
+
end
|
187
|
+
|
188
|
+
if transaction.debtor_address.address_line2
|
189
|
+
builder.AdrLine transaction.debtor_address.address_line2
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
builder.DbtrAcct do
|
195
|
+
builder.Id do
|
196
|
+
builder.IBAN(transaction.iban)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
if transaction.remittance_information
|
200
|
+
builder.RmtInf do
|
201
|
+
builder.Ustrd(transaction.remittance_information)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module SEPA
|
3
|
+
class Transaction
|
4
|
+
include ActiveModel::Validations
|
5
|
+
extend Converter
|
6
|
+
|
7
|
+
DEFAULT_REQUESTED_DATE = Date.new(1999, 1, 1).freeze
|
8
|
+
|
9
|
+
attr_accessor :name,
|
10
|
+
:iban,
|
11
|
+
:bic,
|
12
|
+
:amount,
|
13
|
+
:instruction,
|
14
|
+
:reference,
|
15
|
+
:remittance_information,
|
16
|
+
:requested_date,
|
17
|
+
:batch_booking,
|
18
|
+
:currency,
|
19
|
+
:debtor_address,
|
20
|
+
:creditor_address
|
21
|
+
|
22
|
+
convert :name, :instruction, :reference, :remittance_information, to: :text
|
23
|
+
convert :amount, to: :decimal
|
24
|
+
|
25
|
+
validates_length_of :name, within: 1..70
|
26
|
+
validates_length_of :currency, is: 3
|
27
|
+
validates_length_of :instruction, within: 1..35, allow_nil: true
|
28
|
+
validates_length_of :reference, within: 1..35, allow_nil: true
|
29
|
+
validates_length_of :remittance_information, within: 1..140, allow_nil: true
|
30
|
+
validates_numericality_of :amount, greater_than: 0
|
31
|
+
validates_presence_of :requested_date
|
32
|
+
validates_inclusion_of :batch_booking, :in => [true, false]
|
33
|
+
validates_with BICValidator, IBANValidator, message: "%{value} is invalid"
|
34
|
+
|
35
|
+
def initialize(attributes = {})
|
36
|
+
attributes.each do |name, value|
|
37
|
+
send("#{name}=", value)
|
38
|
+
end
|
39
|
+
|
40
|
+
self.requested_date ||= DEFAULT_REQUESTED_DATE
|
41
|
+
self.reference ||= 'NOTPROVIDED'
|
42
|
+
self.batch_booking = true if self.batch_booking.nil?
|
43
|
+
self.currency ||= 'EUR'
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
def validate_requested_date_after(min_requested_date)
|
49
|
+
return unless requested_date.is_a?(Date)
|
50
|
+
|
51
|
+
if requested_date != DEFAULT_REQUESTED_DATE && requested_date < min_requested_date
|
52
|
+
errors.add(:requested_date, "must be greater or equal to #{min_requested_date}, or nil")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module SEPA
|
3
|
+
class CreditTransferTransaction < Transaction
|
4
|
+
attr_accessor :service_level,
|
5
|
+
:creditor_address,
|
6
|
+
:category_purpose
|
7
|
+
|
8
|
+
validates_inclusion_of :service_level, :in => %w(SEPA URGP), :allow_nil => true
|
9
|
+
validates_length_of :category_purpose, within: 1..4, allow_nil: true
|
10
|
+
|
11
|
+
validate { |t| t.validate_requested_date_after(Date.today) }
|
12
|
+
|
13
|
+
def initialize(attributes = {})
|
14
|
+
super
|
15
|
+
self.service_level ||= 'SEPA' if self.currency == 'EUR'
|
16
|
+
end
|
17
|
+
|
18
|
+
def schema_compatible?(schema_name)
|
19
|
+
case schema_name
|
20
|
+
when PAIN_001_001_03
|
21
|
+
!self.service_level || (self.service_level == 'SEPA' && self.currency == 'EUR')
|
22
|
+
when PAIN_001_002_03
|
23
|
+
self.bic.present? && self.service_level == 'SEPA' && self.currency == 'EUR'
|
24
|
+
when PAIN_001_003_03
|
25
|
+
self.currency == 'EUR'
|
26
|
+
when PAIN_001_001_03_CH_02
|
27
|
+
self.currency == 'CHF'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module SEPA
|
3
|
+
class DirectDebitTransaction < Transaction
|
4
|
+
SEQUENCE_TYPES = %w(FRST OOFF RCUR FNAL)
|
5
|
+
LOCAL_INSTRUMENTS = %w(CORE COR1 B2B)
|
6
|
+
|
7
|
+
attr_accessor :mandate_id,
|
8
|
+
:mandate_date_of_signature,
|
9
|
+
:local_instrument,
|
10
|
+
:sequence_type,
|
11
|
+
:creditor_account,
|
12
|
+
:original_debtor_account,
|
13
|
+
:same_mandate_new_debtor_agent,
|
14
|
+
:original_creditor_account,
|
15
|
+
:debtor_address
|
16
|
+
|
17
|
+
validates_with MandateIdentifierValidator, field_name: :mandate_id, message: "%{value} is invalid"
|
18
|
+
validates_presence_of :mandate_date_of_signature
|
19
|
+
validates_inclusion_of :local_instrument, in: LOCAL_INSTRUMENTS
|
20
|
+
validates_inclusion_of :sequence_type, in: SEQUENCE_TYPES
|
21
|
+
validate { |t| t.validate_requested_date_after(Date.today.next) }
|
22
|
+
|
23
|
+
validate do |t|
|
24
|
+
if creditor_account
|
25
|
+
errors.add(:creditor_account, 'is not correct') unless creditor_account.valid?
|
26
|
+
end
|
27
|
+
|
28
|
+
if t.mandate_date_of_signature.is_a?(Date)
|
29
|
+
errors.add(:mandate_date_of_signature, 'is in the future') if t.mandate_date_of_signature > Date.today
|
30
|
+
else
|
31
|
+
errors.add(:mandate_date_of_signature, 'is not a Date')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(attributes = {})
|
36
|
+
super
|
37
|
+
self.local_instrument ||= 'CORE'
|
38
|
+
self.sequence_type ||= 'OOFF'
|
39
|
+
end
|
40
|
+
|
41
|
+
def amendment_informations?
|
42
|
+
original_debtor_account || same_mandate_new_debtor_agent || original_creditor_account
|
43
|
+
end
|
44
|
+
|
45
|
+
def schema_compatible?(schema_name)
|
46
|
+
case schema_name
|
47
|
+
when PAIN_008_002_02
|
48
|
+
self.bic.present? && %w(CORE B2B).include?(self.local_instrument) && self.currency == 'EUR'
|
49
|
+
when PAIN_008_003_02
|
50
|
+
self.currency == 'EUR'
|
51
|
+
when PAIN_008_001_02
|
52
|
+
true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SEPA
|
4
|
+
class IBANValidator < ActiveModel::Validator
|
5
|
+
# IBAN2007Identifier (taken from schema)
|
6
|
+
REGEX = /\A[A-Z]{2,2}[0-9]{2,2}[a-zA-Z0-9]{1,30}\z/.freeze
|
7
|
+
|
8
|
+
def validate(record)
|
9
|
+
field_name = options[:field_name] || :iban
|
10
|
+
value = record.send(field_name).to_s
|
11
|
+
|
12
|
+
record.errors.add(field_name, :invalid, message: options[:message]) unless value.match(REGEX)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class BICValidator < ActiveModel::Validator
|
17
|
+
# AnyBICIdentifier (taken from schema)
|
18
|
+
REGEX = /\A[A-Z]{6,6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3,3}){0,1}\z/.freeze
|
19
|
+
|
20
|
+
def validate(record)
|
21
|
+
field_name = options[:field_name] || :bic
|
22
|
+
value = record.send(field_name)
|
23
|
+
|
24
|
+
record.errors.add(field_name, :invalid, message: options[:message]) if value && !value.to_s.match(REGEX)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class CreditorIdentifierValidator < ActiveModel::Validator
|
29
|
+
REGEX = %r{\A[a-zA-Z]{2,2}[0-9]{2,2}([A-Za-z0-9]|[+|?|/|\-|:|(|)|.|,|']){3,3}([A-Za-z0-9]|[+|?|/|\-|:|(|)|.|,|']){1,28}\z}.freeze
|
30
|
+
|
31
|
+
def validate(record)
|
32
|
+
field_name = options[:field_name] || :creditor_identifier
|
33
|
+
value = record.send(field_name)
|
34
|
+
|
35
|
+
record.errors.add(field_name, :invalid, message: options[:message]) unless valid?(value)
|
36
|
+
end
|
37
|
+
|
38
|
+
def valid?(creditor_identifier)
|
39
|
+
if ok = creditor_identifier.to_s.match(REGEX) && creditor_identifier[0..1].match(/DE/i)
|
40
|
+
# In Germany, the identifier has to be exactly 18 chars long
|
41
|
+
ok = creditor_identifier.length == 18
|
42
|
+
end
|
43
|
+
ok
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class MandateIdentifierValidator < ActiveModel::Validator
|
48
|
+
REGEX = %r{\A([A-Za-z0-9]|[+|?|/|\-|:|(|)|.|,|']){1,35}\z}.freeze
|
49
|
+
|
50
|
+
def validate(record)
|
51
|
+
field_name = options[:field_name] || :mandate_id
|
52
|
+
value = record.send(field_name)
|
53
|
+
|
54
|
+
record.errors.add(field_name, :invalid, message: options[:message]) unless value.to_s.match(REGEX)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/sepa_king.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'sepa_king/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'sepa_king_codeur'
|
7
|
+
s.version = SEPA::VERSION
|
8
|
+
s.authors = ['Georg Leciejewski', 'Georg Ledermann', 'Codeur']
|
9
|
+
s.email = ['gl@salesking.eu', 'mail@georg-ledermann.de', 'dev@codeur.com']
|
10
|
+
s.description = 'Implemention of pain.001.002.03 and pain.008.002.02 (ISO 20022)'
|
11
|
+
s.summary = 'Ruby gem for creating SEPA XML files'
|
12
|
+
s.homepage = 'http://github.com/codeur/sepa_king'
|
13
|
+
s.license = 'MIT'
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split($/)
|
16
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
17
|
+
s.require_paths = ['lib']
|
18
|
+
|
19
|
+
s.metadata['homepage_uri'] = s.homepage
|
20
|
+
s.metadata['source_code_uri'] = 'https://github.com/codeur/sepa_king'
|
21
|
+
|
22
|
+
s.required_ruby_version = '>= 2.2'
|
23
|
+
|
24
|
+
s.add_runtime_dependency 'activemodel', '>= 3.1'
|
25
|
+
s.add_runtime_dependency 'iban-tools'
|
26
|
+
s.add_runtime_dependency 'nokogiri'
|
27
|
+
|
28
|
+
s.add_development_dependency 'bundler'
|
29
|
+
s.add_development_dependency 'coveralls'
|
30
|
+
s.add_development_dependency 'rake'
|
31
|
+
s.add_development_dependency 'rspec'
|
32
|
+
s.add_development_dependency 'simplecov'
|
33
|
+
end
|