Skip to content

Commit

Permalink
first draft of supplementary details for transaction
Browse files Browse the repository at this point in the history
- changes line parsing. neccessary for transactions as they can have
  newlines within their details field
- includes initial amount details
- includes charges

Co-authored-by: Lars Brillert <lars@railslove.com>
  • Loading branch information
Maxim and Lars Brillert committed Apr 9, 2018
1 parent bad2a01 commit dafcc43
Show file tree
Hide file tree
Showing 12 changed files with 144 additions and 54 deletions.
4 changes: 2 additions & 2 deletions lib/cmxl/field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ def self.tag
# Cmxl::Field.parse(':60F:C031002PLN40000,00') #=> returns an AccountBalance instance
#
def self.parse(line)
if line.match(/^:(\d{2,2})(\w)?:(.*)$/)
tag, modifier, content = $1, $2, $3
if line.match(/\A:(\d{2,2})(\w)?:(.*)\z/m)
tag, modifier, content = $1, $2, $3.gsub(/\r?\n\z/, '') # gsub last line break
Field.parsers[tag.to_s].new(content, modifier, tag)
else
raise LineFormatError, "Wrong line format: #{line.dump}" if Cmxl.config[:raise_line_format_errors]
Expand Down
6 changes: 6 additions & 0 deletions lib/cmxl/fields/statement_details.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ class StatementDetails < Field
self.tag = 86
self.parser = /(?<transaction_code>\w{3})(?<details>(?<seperator>.).*)/

class << self
def parse(line)
super line.gsub(/\n/, '')
end
end

def sub_fields
@sub_fields ||= if self.data['details'] =~ /#{Regexp.escape(self.data['seperator'])}(\d{2})/
Hash[self.data['details'].scan(/#{Regexp.escape(self.data['seperator'])}(\d{2})([^#{Regexp.escape(self.data['seperator'])}]*)/)]
Expand Down
27 changes: 25 additions & 2 deletions lib/cmxl/fields/transaction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Cmxl
module Fields
class Transaction < Field
self.tag = 61
self.parser = /^(?<date>\d{6})(?<entry_date>\d{4})?(?<storno_flag>R?)(?<funds_code>[CD]{1})(?<currency_letter>[a-zA-Z])?(?<amount>\d{1,12},\d{0,2})(?<swift_code>(?:N|F).{3})(?<reference>NONREF|.{0,16})(?:$|\/\/)(?<bank_reference>.*)/i
self.parser = %r{^(?<date>\d{6})(?<entry_date>\d{4})?(?<storno_flag>R?)(?<funds_code>[CD]{1})(?<currency_letter>[a-zA-Z])?(?<amount>\d{1,12},\d{0,2})(?<swift_code>(?:N|F).{3})(?<reference>NONREF|.{0,16})((?:\/\/)(?<bank_reference>[^\n]*))?((?:[\n])?(?<supplementary>.{,34}))$}

attr_accessor :details

Expand Down Expand Up @@ -68,6 +68,25 @@ def entry_date
end
end

def supplementary
@supplementary ||= Cmxl::Fields::TransactionSupplementary.parse(data['supplementary'])
end

# Fields from supplementary

def initial_amount_in_cents
supplementary.initial_amount_in_cents
end
def initial_currency
supplementary.initial_currency
end
def charges_in_cents
supplementary.charges_in_cents
end
def charges_currency
supplementary.charges_currency
end

# Fields from details

def description
Expand Down Expand Up @@ -107,7 +126,11 @@ def to_h
'swift_code' => swift_code,
'reference' => reference,
'bank_reference' => bank_reference,
'currency_letter' => currency_letter
'currency_letter' => currency_letter,
'initial_amount_in_cents' => initial_amount_in_cents,
'initial_currency' => initial_currency,
'charges_in_cents' => charges_in_cents,
'charges_currency' => charges_currency,
}.merge(details ? details.to_h : {})
end

Expand Down
42 changes: 42 additions & 0 deletions lib/cmxl/fields/transaction_supplementary.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
module Cmxl
module Fields
class TransactionSupplementary < Field

attr_accessor :source, :initial, :charges

class << self
def parse(line)
initial = $1 if line.match(initial_parser)
charges = $1 if line.match(charges_parser)
new(line, initial, charges)
end

def initial_parser; %r{((?:\/OCMT\/)(?<initial>[a-zA-Z]{3}[\d,]{1,15}))} end
def charges_parser; %r{((?:\/CHGS\/)(?<charges>[a-zA-Z]{3}[\d,]{1,15}))} end
end


def initialize(line, initial, charges)
self.source = line
self.initial = initial
self.charges = charges
end

def initial_amount_in_cents
to_amount_in_cents(initial[3..-1]) if initial
end

def initial_currency
initial[0..2] if initial
end

def charges_in_cents
to_amount_in_cents(charges[3..-1]) if charges
end

def charges_currency
charges[0..2] if charges
end
end
end
end
29 changes: 4 additions & 25 deletions lib/cmxl/statement.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,11 @@ def transactions
# Internal: Parse a single MT940 statement and extract the line data
#
def parse!
# first we clean uo the source and make concat wraped lines (lines not starting with a ":")
self.source.split("\n").each do |line|
if line.start_with?(':') || self.lines.last.nil?
self.lines << line.strip
else
self.lines.last << line.strip
end
end

self.fields = []
lines.each do |line|

source.split("\n:").each(&:strip!).each do |line|
line = ":#{line}" unless line =~ %r{^:} # prepend lost : via split

if line.match(/\A:86:/)
if field = fields.last
field.add_meta_data(line)
Expand All @@ -43,21 +37,6 @@ def parse!
self.fields << field unless field.nil?
end
end

# puts "Fixed Fields"
# puts fields.inspect
#
# # Now we check each line for its content ans structure it for further use. If it is part of a transaction we initate or update a transaction else we parse the field and add it to the fields collection
# self.lines.each do |line|
# if line.match(/\A:61:/)
# self.transactions << Cmxl::Transaction.new(line)
# elsif line.match(/\A:86:/) && !self.transactions.last.nil?
# self.transactions.last.details = line
# else
# field = Field.parse(line)
# self.fields << field unless field.nil?
# end
# end
end

# Public: SHA2 of the provided source
Expand Down
16 changes: 16 additions & 0 deletions spec/fields/transaction_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
describe Cmxl::Fields::Transaction do
subject(:debit_transaction) { Cmxl::Fields::Transaction.parse(fixture.first) }
subject(:storno_credit_transaction) { Cmxl::Fields::Transaction.parse(fixture.last) }
subject(:ocmt_transaction) { Cmxl::Fields::Transaction.parse(fixture_line(:statement_ocmt)) }
subject(:ocmt_cghs_transaction) { Cmxl::Fields::Transaction.parse(fixture_line(:statement_ocmt_chgs)) }

let(:fixture) { fixture_line(:statement_line).split(/\n/) }

Expand Down Expand Up @@ -38,4 +40,18 @@
it { expect(storno_credit_transaction).to be_storno }
it { expect(storno_credit_transaction.sign).to eql(1) }
end

context 'statement with initial amount and currency' do
it { expect(ocmt_transaction.initial_amount_in_cents).to eql(4711) }
it { expect(ocmt_transaction.initial_currency).to eql('CAD') }
end

context 'statement with initial amount and currency and also charges' do
it {
expect(ocmt_cghs_transaction.initial_amount_in_cents).to eql(4711) }
it { expect(ocmt_cghs_transaction.initial_currency).to eql('CAD') }

it { expect(ocmt_cghs_transaction.charges_in_cents).to eql(123) }
it { expect(ocmt_cghs_transaction.charges_currency).to eql('EUR') }
end
end
11 changes: 11 additions & 0 deletions spec/fields/transaction_supplementary_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require 'spec_helper'

describe Cmxl::Fields::TransactionSupplementary do
let(:fixture) { 'Card Transaction/OCMT/CAD47,11/CHGS/EUR123,45' }

it { expect(described_class.parse(fixture).initial_amount_in_cents).to eql(4711) }
it { expect(described_class.parse(fixture).initial_currency).to eql('CAD') }

it { expect(described_class.parse(fixture).charges_in_cents).to eql(12345) }
it { expect(described_class.parse(fixture).charges_currency).to eql('EUR') }
end
2 changes: 2 additions & 0 deletions spec/fixtures/lines/statement_ocmt.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:61:1804090409DR000000000012,34NTRF0000549855700010//025498557/000001
/OCMT/CAD47,11
2 changes: 2 additions & 0 deletions spec/fixtures/lines/statement_ocmt_chgs.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:61:1804090409DR000000000056,78NTRF0000549855700010//025498557/000001
/OCMT/CAD47,11/CHGS/EUR1,23
3 changes: 2 additions & 1 deletion spec/fixtures/mt940-deutsche_bank.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
:28:27/01
:60F:C131016DEM84349,74
:61:131017D6800,NCHK16703074
/OCMT/CAD47,11
:86:999PN5477SCHECK-NR. 0000016703074
:61:131017D620,3NSTON
:86:999PN0911DAUERAUFTR.NR. 14
Expand Down Expand Up @@ -66,5 +67,5 @@ STORY-?26300 SZT GR544 I OPORNIKI-5?2700 SZT GTX847 FAKTURA 333/
:61:0310201020C40,00FTRFNONREF//8327000090031791
Interest credit
:86: 844?00Uznanie kwotą odsetek?20Odsetki od lokaty nr 101000?21022086
:62F:C020325PLN50040,00
:62F:C020325PLN50040,00
-
44 changes: 22 additions & 22 deletions spec/fixtures/mt940.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,30 +46,30 @@ GmbH?3050060400?31084756

-

:20:TELEWIZORY S.A.
:25:BPHKPLPK/320000546101
:28C:00084/001
:60F:C031002PLN40000,00
:61:0310201020C20000,00FMSCNONREF//8327000090031789
Card transaction
:20:TELEWIZORY S.A.
:25:BPHKPLPK/320000546101
:28C:00084/001
:60F:C031002PLN40000,00
:61:0310201020C20000,00FMSCNONREF//8327000090031789
Card transaction
:86: 020?00Wyplata-(dysp/przel)?2008106000760000777777777777?2115617?
22INFO INFO INFO INFO INFO INFO 1 END?23INFO INFO INFO INFO INFO
INFO 2 END?24ZAPLATA ZA FABRYKATY DO TUB?25 - 200 S ZTUK, TRANZY
STORY-?26300 SZT GR544 I OPORNIKI-5?2700 SZT GTX847 FAKTURA 333/
2?28003.?3010600076?310000777777777777?32HUTA SZKLA TOPIC UL
PRZEMY?33SLOWA 67 32-669 WROCLAW?38PL081060007600007777777
77777
:61:0310201020D10000,00FTRFREF 25611247//8327000090031790
Transfer
22INFO INFO INFO INFO INFO INFO 1 END?23INFO INFO INFO INFO INFO
INFO 2 END?24ZAPLATA ZA FABRYKATY DO TUB?25 - 200 S ZTUK, TRANZY
STORY-?26300 SZT GR544 I OPORNIKI-5?2700 SZT GTX847 FAKTURA 333/
2?28003.?3010600076?310000777777777777?32HUTA SZKLA TOPIC UL
PRZEMY?33SLOWA 67 32-669 WROCLAW?38PL081060007600007777777
77777
:61:0310201020D10000,00FTRFREF 25611247//8327000090031790
Transfer
:86: 020?00Wyplata-(dysp/przel)?2008106000760000777777777777?2115617?
22INFO INFO INFO INFO INFO INFO 1 END?23INFO INFO INFO INFO INFO
INFO 2 END?24ZAPLATA ZA FABRYKATY DO TUB?25 - 200 S ZTUK, TRANZY
STORY-?26300 SZT GR544 I OPORNIKI-5?2700 SZT GTX847 FAKTURA 333/
2?28003.?3010600076?310000777777777777?38PL081060007600007777777
77777
:61:0310201020C40,00FTRFNONREF//8327000090031791
22INFO INFO INFO INFO INFO INFO 1 END?23INFO INFO INFO INFO INFO
INFO 2 END?24ZAPLATA ZA FABRYKATY DO TUB?25 - 200 S ZTUK, TRANZY
STORY-?26300 SZT GR544 I OPORNIKI-5?2700 SZT GTX847 FAKTURA 333/
2?28003.?3010600076?310000777777777777?38PL081060007600007777777
77777
:61:0310201020C40,00FTRFNONREF//8327000090031791
Interest credit
:86: 844?00Uznanie kwotą odsetek?20Odsetki od lokaty nr 101000?21022086
:62F:C020325PLN50040,00
:86: 844?00Uznanie kwotą odsetek?20Odsetki od lokaty nr 101000?21022086
:62F:C020325PLN50040,00

-
12 changes: 10 additions & 2 deletions spec/statement_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@
"34" => "171"
},
"transaction_code" => "171",
"details" => "?00SEPA LASTSCHRIFT KUNDE?10281?20KREF+EREF+TRX-0A4A47C3-F846-4729?21-8A1B-5DF620F?22MREF+CAC97D2144174318AC18D9?23BF815BD4FB?24CRED+DE98ZZZ09999999999?25SVWZ+FOO TRX-0A4A47C3-F84?266-4729-8A1B-5DF620F?30HYVEDEMMXXX?31HUkkbbbsssskcccccccccccccccx?32Peter Pan?99?34171"
"details" => "?00SEPA LASTSCHRIFT KUNDE?10281?20KREF+EREF+TRX-0A4A47C3-F846-4729?21-8A1B-5DF620F?22MREF+CAC97D2144174318AC18D9?23BF815BD4FB?24CRED+DE98ZZZ09999999999?25SVWZ+FOO TRX-0A4A47C3-F84?266-4729-8A1B-5DF620F?30HYVEDEMMXXX?31HUkkbbbsssskcccccccccccccccx?32Peter Pan?99?34171",
'initial_amount_in_cents' => nil,
'initial_currency' => nil,
'charges_in_cents' => nil,
'charges_currency' => nil,
}
)
}
Expand Down Expand Up @@ -87,7 +91,11 @@
"sign" => -1,
"debit" => true,
"credit" => false,
"storno" => false
"storno" => false,
'initial_amount_in_cents' => nil,
'initial_currency' => nil,
'charges_in_cents' => nil,
'charges_currency' => nil,
})
end
end
Expand Down

0 comments on commit dafcc43

Please sign in to comment.