diff --git a/lib/sepa_king/message/credit_transfer.rb b/lib/sepa_king/message/credit_transfer.rb index 1153bfb..af4734a 100644 --- a/lib/sepa_king/message/credit_transfer.rb +++ b/lib/sepa_king/message/credit_transfer.rb @@ -13,7 +13,8 @@ def transaction_group(transaction) { requested_date: transaction.requested_date, batch_booking: transaction.batch_booking, service_level: transaction.service_level, - category_purpose: transaction.category_purpose + category_purpose: transaction.category_purpose, + local_instrument: transaction.local_instrument } end @@ -33,6 +34,11 @@ def build_payment_informations(builder, schema_name) builder.Cd(group[:service_level]) end end + if group[:local_instrument] + builder.LclInstrm do + builder.Cd(group[:local_instrument]) + end + end if group[:category_purpose] builder.CtgyPurp do builder.Cd(group[:category_purpose]) diff --git a/lib/sepa_king/transaction/credit_transfer_transaction.rb b/lib/sepa_king/transaction/credit_transfer_transaction.rb index 8c031c2..96c5f0f 100644 --- a/lib/sepa_king/transaction/credit_transfer_transaction.rb +++ b/lib/sepa_king/transaction/credit_transfer_transaction.rb @@ -1,12 +1,18 @@ # encoding: utf-8 module SEPA class CreditTransferTransaction < Transaction + LOCAL_INSTRUMENTS = %w(INST) + attr_accessor :service_level, :creditor_address, - :category_purpose + :category_purpose, + :local_instrument validates_inclusion_of :service_level, :in => %w(SEPA URGP), :allow_nil => true validates_length_of :category_purpose, within: 1..4, allow_nil: true + validates_inclusion_of :local_instrument, in: LOCAL_INSTRUMENTS, :allow_nil => true + + validate :inst_valid_for_sepa_service_level validate { |t| t.validate_requested_date_after(Date.today) } @@ -20,11 +26,19 @@ def schema_compatible?(schema_name) when PAIN_001_001_03 !self.service_level || (self.service_level == 'SEPA' && self.currency == 'EUR') when PAIN_001_002_03 - self.bic.present? && self.service_level == 'SEPA' && self.currency == 'EUR' + self.bic.present? && self.service_level == 'SEPA' && self.currency == 'EUR' && self.local_instrument.nil? when PAIN_001_003_03 - self.currency == 'EUR' + self.currency == 'EUR' && self.local_instrument.nil? when PAIN_001_001_03_CH_02 - self.currency == 'CHF' + self.currency == 'CHF' && self.local_instrument.nil? + end + end + + private + + def inst_valid_for_sepa_service_level + if self.local_instrument == 'INST' && self.service_level != 'SEPA' + errors.add(:local_instrument, 'INST can only be used with SEPA service level') end end end diff --git a/spec/credit_transfer_spec.rb b/spec/credit_transfer_spec.rb index 547546d..3609dc0 100644 --- a/spec/credit_transfer_spec.rb +++ b/spec/credit_transfer_spec.rb @@ -525,5 +525,44 @@ end end end + + context 'when SEPA INST' do + context 'with local instrument INST' do + subject do + sct = credit_transfer + + sct.add_transaction name: 'Telekomiker AG', + iban: 'FR7630003012340001234567854', + bic: 'SOGEFRPP', + amount: 345.87, + currency: 'EUR', + local_instrument: 'INST' + + sct + end + + it 'should validate against pain.001.001.03' do + expect(subject.to_xml(SEPA::PAIN_001_001_03)).to validate_against('pain.001.001.03.xsd') + end + + it 'should validate against pain.001.002.03' do + expect { + subject.to_xml(SEPA::PAIN_001_002_03) + }.to raise_error(SEPA::Error, /Incompatible with schema/) + end + + it 'should validate against pain.001.003.03' do + expect { + subject.to_xml(SEPA::PAIN_001_003_03) + }.to raise_error(SEPA::Error, /Incompatible with schema/) + end + + it 'should fail for pain.001.001.03.CH.02' do + expect { + subject.to_xml(SEPA::PAIN_001_001_03_CH_02) + }.to raise_error(SEPA::Error, /Incompatible with schema/) + end + end + end end end diff --git a/spec/credit_transfer_transaction_spec.rb b/spec/credit_transfer_transaction_spec.rb index 3fdd2e7..9a0f902 100644 --- a/spec/credit_transfer_transaction_spec.rb +++ b/spec/credit_transfer_transaction_spec.rb @@ -71,4 +71,87 @@ expect(SEPA::CreditTransferTransaction).not_to accept('', 'X' * 5, for: :category_purpose) end end + + context 'Local Instrument' do + it 'should allow valid value' do + expect(SEPA::CreditTransferTransaction).to accept(nil, 'INST', for: :local_instrument) + end + + it 'should not allow invalid value' do + expect(SEPA::CreditTransferTransaction).not_to accept('SEPA', 'X' * 5, for: :local_instrument) + end + + context 'for pain.001.001.03' do + it 'should be valid' do + expect(SEPA::CreditTransferTransaction.new(:currency => 'EUR', :local_instrument => 'INST')).to be_schema_compatible('pain.001.001.03') + end + end + + context 'for pain.001.002.03' do + it 'should not be valid' do + expect(SEPA::CreditTransferTransaction.new(:currency => 'EUR', :local_instrument => 'INST')).not_to be_schema_compatible('pain.001.002.03') + end + end + + context 'for pain.001.003.03' do + it 'should not be valid' do + expect(SEPA::CreditTransferTransaction.new(:currency => 'EUR', :local_instrument => 'INST')).not_to be_schema_compatible('pain.001.003.03') + end + end + + context 'when Local Instrument is INST' do + context 'when service level is SEPA' do + it 'should be valid' do + expect( + SEPA::CreditTransferTransaction.new name: 'Telekomiker AG', + iban: 'FR7630003012340001234567854', + bic: 'SOGEFRPP', + amount: 406.57, + currency: 'EUR', + service_level: 'SEPA', + reference: 'XYZ-1234/123', + remittance_information: 'Rechnung 123 vom 22.08.2013', + local_instrument: 'INST' + ).to be_valid + end + end + + context 'when currency is EUR' do + it 'should be valid' do + expect( + SEPA::CreditTransferTransaction.new name: 'Telekomiker AG', + iban: 'FR7630003012340001234567854', + bic: 'SOGEFRPP', + amount: 142.50, + currency: 'EUR', + reference: 'XYZ-1234/123', + remittance_information: 'Rechnung 123 vom 22.08.2013', + local_instrument: 'INST' + ).to be_valid + end + end + + context 'when service level is URGP' do + subject { + SEPA::CreditTransferTransaction.new name: 'Telekomiker AG', + iban: 'FR7630003012340001234567854', + bic: 'SOGEFRPP', + amount: 102.53, + reference: 'XYZ-1234/123', + remittance_information: 'Rechnung 123 vom 22.08.2013', + local_instrument: 'INST', + service_level: 'URGP' + } + + it 'should not be valid' do + expect(subject).not_to be_valid + end + + it 'returns errors' do + subject.valid? + expect(subject.errors_on(:local_instrument).size).to eq(1) + end + end + end + end end