cmxl 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: db1917122b50744544c13bdb1bcb82841df8f909
4
- data.tar.gz: a7576890df969cc890c953d348a419bef20c3994
3
+ metadata.gz: 82b72d8655b552c6a10bae7df6882bf313ea472b
4
+ data.tar.gz: 630a7f8c31eee13bec9ca238ea492f0bad384515
5
5
  SHA512:
6
- metadata.gz: 7d69bc9388edbea99a3746841df29df16cf6df0d7e523a8b4bee3e6c563b7554e83eecb0b9595022182bebdad171562a2f5eb118f0a67ab19647aab161ecb518
7
- data.tar.gz: cbb697ecf01433464585ae77766c647f9cc8be0348bc20ab835c5ac5f84666eac7fc0c5f9cb54e09f0b984a6d87332aa03b97943ef1e69ec548e10bdf2ec9d6e
6
+ metadata.gz: dcfab68cd74b8c40ccd21799693f20be692ae3a38c2edfc02c06972ebd0148e06a91c3031d715fb5f97b6d8d923d7802db2763ee01d91e5ba34f3b201f678438
7
+ data.tar.gz: f7936f2ba25cd820f81241a46588ff03dd66f8cf9b3dd4165e9eb5c372eec020a0f82b0053d5a39756e1c554471299fd6879501663ff2e4343de115191374a2c
@@ -1,3 +1,6 @@
1
+ # 1.1.0
2
+ * [FEATURE] adds support for supplementary details in transactions (Field 61, Subfield 9) (#18)
3
+
1
4
  # 1.0.0
2
5
  * [FEATURE] adds support for storno transactions (#14)
3
6
  * [NOTE] full backwards compatibility
@@ -44,8 +44,8 @@ module Cmxl
44
44
  # Cmxl::Field.parse(':60F:C031002PLN40000,00') #=> returns an AccountBalance instance
45
45
  #
46
46
  def self.parse(line)
47
- if line.match(/^:(\d{2,2})(\w)?:(.*)$/)
48
- tag, modifier, content = $1, $2, $3
47
+ if line.match(/\A:(\d{2,2})(\w)?:(.*)\z/m)
48
+ tag, modifier, content = $1, $2, $3.gsub(/\r?\n\z/, '') # remove trailing line break to prevent empty field parsing
49
49
  Field.parsers[tag.to_s].new(content, modifier, tag)
50
50
  else
51
51
  raise LineFormatError, "Wrong line format: #{line.dump}" if Cmxl.config[:raise_line_format_errors]
@@ -4,6 +4,13 @@ module Cmxl
4
4
  self.tag = 86
5
5
  self.parser = /(?<transaction_code>\w{3})(?<details>(?<seperator>.).*)/
6
6
 
7
+ class << self
8
+ def parse(line)
9
+ # remove line breaks as they are allowed via documentation but not needed for data-parsing
10
+ super line.gsub(/\n/, '')
11
+ end
12
+ end
13
+
7
14
  def sub_fields
8
15
  @sub_fields ||= if self.data['details'] =~ /#{Regexp.escape(self.data['seperator'])}(\d{2})/
9
16
  Hash[self.data['details'].scan(/#{Regexp.escape(self.data['seperator'])}(\d{2})([^#{Regexp.escape(self.data['seperator'])}]*)/)]
@@ -2,7 +2,7 @@ module Cmxl
2
2
  module Fields
3
3
  class Transaction < Field
4
4
  self.tag = 61
5
- 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
5
+ 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}))$}
6
6
 
7
7
  attr_accessor :details
8
8
 
@@ -68,6 +68,25 @@ module Cmxl
68
68
  end
69
69
  end
70
70
 
71
+ def supplementary
72
+ @supplementary ||= Cmxl::Fields::TransactionSupplementary.parse(data['supplementary'])
73
+ end
74
+
75
+ # Fields from supplementary
76
+
77
+ def initial_amount_in_cents
78
+ supplementary.initial_amount_in_cents
79
+ end
80
+ def initial_currency
81
+ supplementary.initial_currency
82
+ end
83
+ def charges_in_cents
84
+ supplementary.charges_in_cents
85
+ end
86
+ def charges_currency
87
+ supplementary.charges_currency
88
+ end
89
+
71
90
  # Fields from details
72
91
 
73
92
  def description
@@ -107,8 +126,11 @@ module Cmxl
107
126
  'swift_code' => swift_code,
108
127
  'reference' => reference,
109
128
  'bank_reference' => bank_reference,
110
- 'currency_letter' => currency_letter
111
- }.merge(details ? details.to_h : {})
129
+ 'currency_letter' => currency_letter,
130
+ }.tap do |h|
131
+ h.merge!(details.to_h) if details
132
+ h.merge!(supplementary.to_h) unless supplementary.source.empty?
133
+ end
112
134
  end
113
135
 
114
136
  def to_hash
@@ -0,0 +1,53 @@
1
+ module Cmxl
2
+ module Fields
3
+ class TransactionSupplementary < Field
4
+
5
+ attr_accessor :source, :initial, :charges
6
+
7
+ class << self
8
+ def parse(line)
9
+ initial = $1 if line.match(initial_parser)
10
+ charges = $1 if line.match(charges_parser)
11
+ new(line, initial, charges)
12
+ end
13
+
14
+ def initial_parser; %r{((?:\/OCMT\/)(?<initial>[a-zA-Z]{3}[\d,]{1,15}))} end
15
+ def charges_parser; %r{((?:\/CHGS\/)(?<charges>[a-zA-Z]{3}[\d,]{1,15}))} end
16
+ end
17
+
18
+
19
+ def initialize(line, initial, charges)
20
+ self.source = line
21
+ self.initial = initial
22
+ self.charges = charges
23
+ end
24
+
25
+ def initial_amount_in_cents
26
+ to_amount_in_cents(initial[3..-1]) if initial
27
+ end
28
+
29
+ def initial_currency
30
+ initial[0..2] if initial
31
+ end
32
+
33
+ def charges_in_cents
34
+ to_amount_in_cents(charges[3..-1]) if charges
35
+ end
36
+
37
+ def charges_currency
38
+ charges[0..2] if charges
39
+ end
40
+
41
+ def to_h
42
+ {
43
+ source: source,
44
+ initial_amount_in_cents: initial_amount_in_cents,
45
+ initial_currency: initial_currency,
46
+ charges_in_cents: charges_in_cents,
47
+ charges_currency: charges_currency,
48
+ }
49
+ end
50
+ alias_method :to_hash, :to_h
51
+ end
52
+ end
53
+ end
@@ -23,17 +23,14 @@ module Cmxl
23
23
  # Internal: Parse a single MT940 statement and extract the line data
24
24
  #
25
25
  def parse!
26
- # first we clean uo the source and make concat wraped lines (lines not starting with a ":")
27
- self.source.split("\n").each do |line|
28
- if line.start_with?(':') || self.lines.last.nil?
29
- self.lines << line.strip
30
- else
31
- self.lines.last << line.strip
32
- end
33
- end
34
-
35
26
  self.fields = []
36
- lines.each do |line|
27
+
28
+ # split transactions, each transaction starts with a colon after a linebreak
29
+ # do not remove line breaks within transaction lines as they are used to determine field details
30
+ # e.g. :61:-supplementary
31
+ source.split("\n:").each(&:strip!).each do |line|
32
+ line = ":#{line}" unless line =~ %r{^:} # prepend lost : via split
33
+
37
34
  if line.match(/\A:86:/)
38
35
  if field = fields.last
39
36
  field.add_meta_data(line)
@@ -43,21 +40,6 @@ module Cmxl
43
40
  self.fields << field unless field.nil?
44
41
  end
45
42
  end
46
-
47
- # puts "Fixed Fields"
48
- # puts fields.inspect
49
- #
50
- # # 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
51
- # self.lines.each do |line|
52
- # if line.match(/\A:61:/)
53
- # self.transactions << Cmxl::Transaction.new(line)
54
- # elsif line.match(/\A:86:/) && !self.transactions.last.nil?
55
- # self.transactions.last.details = line
56
- # else
57
- # field = Field.parse(line)
58
- # self.fields << field unless field.nil?
59
- # end
60
- # end
61
43
  end
62
44
 
63
45
  # Public: SHA2 of the provided source
@@ -1,3 +1,3 @@
1
1
  module Cmxl
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.0'
3
3
  end
@@ -3,6 +3,9 @@ require 'spec_helper'
3
3
  describe Cmxl::Fields::Transaction do
4
4
  subject(:debit_transaction) { Cmxl::Fields::Transaction.parse(fixture.first) }
5
5
  subject(:storno_credit_transaction) { Cmxl::Fields::Transaction.parse(fixture.last) }
6
+ subject(:ocmt_transaction) { Cmxl::Fields::Transaction.parse(fixture_line(:statement_ocmt)) }
7
+ subject(:ocmt_cghs_transaction) { Cmxl::Fields::Transaction.parse(fixture_line(:statement_ocmt_chgs)) }
8
+ subject(:supplementary_transaction) { Cmxl::Fields::Transaction.parse(fixture_line(:statement_supplementary_plain)) }
6
9
 
7
10
  let(:fixture) { fixture_line(:statement_line).split(/\n/) }
8
11
 
@@ -38,4 +41,27 @@ describe Cmxl::Fields::Transaction do
38
41
  it { expect(storno_credit_transaction).to be_storno }
39
42
  it { expect(storno_credit_transaction.sign).to eql(1) }
40
43
  end
44
+
45
+ context 'statement with initial amount and currency' do
46
+ it { expect(ocmt_transaction.initial_amount_in_cents).to eql(4711) }
47
+ it { expect(ocmt_transaction.initial_currency).to eql('CAD') }
48
+ end
49
+
50
+ context 'statement with initial amount and currency and also charges' do
51
+ it { expect(ocmt_cghs_transaction.initial_amount_in_cents).to eql(4711) }
52
+ it { expect(ocmt_cghs_transaction.initial_currency).to eql('CAD') }
53
+
54
+ it { expect(ocmt_cghs_transaction.charges_in_cents).to eql(123) }
55
+ it { expect(ocmt_cghs_transaction.charges_currency).to eql('EUR') }
56
+ end
57
+
58
+ context 'statement with plain supplementary' do
59
+ it { expect(supplementary_transaction.initial_amount_in_cents).to eql(nil) }
60
+ it { expect(supplementary_transaction.initial_currency).to eql(nil) }
61
+
62
+ it { expect(supplementary_transaction.charges_in_cents).to eql(nil) }
63
+ it { expect(supplementary_transaction.charges_currency).to eql(nil) }
64
+
65
+ it { expect(supplementary_transaction.supplementary.source).to eql('Card Transaction') }
66
+ end
41
67
  end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Cmxl::Fields::TransactionSupplementary do
4
+ let(:fixture) { 'Card Transaction/OCMT/CAD47,11/CHGS/EUR123,45' }
5
+ subject(:supplementary) { described_class.parse(fixture) }
6
+
7
+ it { expect(supplementary.initial_amount_in_cents).to eql(4711) }
8
+ it { expect(supplementary.initial_currency).to eql('CAD') }
9
+
10
+ it { expect(supplementary.charges_in_cents).to eql(12345) }
11
+ it { expect(supplementary.charges_currency).to eql('EUR') }
12
+
13
+ describe '.to_h' do
14
+ it 'returns expected hash' do
15
+ expect(supplementary.to_h).to eql({
16
+ source: 'Card Transaction/OCMT/CAD47,11/CHGS/EUR123,45',
17
+ initial_amount_in_cents: 4711,
18
+ initial_currency: 'CAD',
19
+ charges_in_cents: 12345,
20
+ charges_currency: 'EUR'
21
+ })
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,2 @@
1
+ :61:1804090409DR000000000012,34NTRF0000549855700010//025498557/000001
2
+ /OCMT/CAD47,11
@@ -0,0 +1,2 @@
1
+ :61:1804090409DR000000000056,78NTRF0000549855700010//025498557/000001
2
+ /OCMT/CAD47,11/CHGS/EUR1,23
@@ -0,0 +1,2 @@
1
+ :61:0306280628D21,00FMSCNONREF//98327000090031789
2
+ Card Transaction
@@ -3,6 +3,7 @@
3
3
  :28:27/01
4
4
  :60F:C131016DEM84349,74
5
5
  :61:131017D6800,NCHK16703074
6
+ /OCMT/CAD47,11
6
7
  :86:999PN5477SCHECK-NR. 0000016703074
7
8
  :61:131017D620,3NSTON
8
9
  :86:999PN0911DAUERAUFTR.NR. 14
@@ -66,5 +67,5 @@ STORY-?26300 SZT GR544 I OPORNIKI-5?2700 SZT GTX847 FAKTURA 333/
66
67
  :61:0310201020C40,00FTRFNONREF//8327000090031791
67
68
  Interest credit
68
69
  :86: 844?00Uznanie kwotą odsetek?20Odsetki od lokaty nr 101000?21022086
69
- :62F:C020325PLN50040,00
70
+ :62F:C020325PLN50040,00
70
71
  -
@@ -46,30 +46,30 @@ GmbH?3050060400?31084756
46
46
 
47
47
  -
48
48
 
49
- :20:TELEWIZORY S.A.
50
- :25:BPHKPLPK/320000546101
51
- :28C:00084/001
52
- :60F:C031002PLN40000,00
53
- :61:0310201020C20000,00FMSCNONREF//8327000090031789
54
- Card transaction
49
+ :20:TELEWIZORY S.A.
50
+ :25:BPHKPLPK/320000546101
51
+ :28C:00084/001
52
+ :60F:C031002PLN40000,00
53
+ :61:0310201020C20000,00FMSCNONREF//8327000090031789
54
+ Card transaction
55
55
  :86: 020?00Wyplata-(dysp/przel)?2008106000760000777777777777?2115617?
56
- 22INFO INFO INFO INFO INFO INFO 1 END?23INFO INFO INFO INFO INFO
57
- INFO 2 END?24ZAPLATA ZA FABRYKATY DO TUB?25 - 200 S ZTUK, TRANZY
58
- STORY-?26300 SZT GR544 I OPORNIKI-5?2700 SZT GTX847 FAKTURA 333/
59
- 2?28003.?3010600076?310000777777777777?32HUTA SZKLA TOPIC UL
60
- PRZEMY?33SLOWA 67 32-669 WROCLAW?38PL081060007600007777777
61
- 77777
62
- :61:0310201020D10000,00FTRFREF 25611247//8327000090031790
63
- Transfer
56
+ 22INFO INFO INFO INFO INFO INFO 1 END?23INFO INFO INFO INFO INFO
57
+ INFO 2 END?24ZAPLATA ZA FABRYKATY DO TUB?25 - 200 S ZTUK, TRANZY
58
+ STORY-?26300 SZT GR544 I OPORNIKI-5?2700 SZT GTX847 FAKTURA 333/
59
+ 2?28003.?3010600076?310000777777777777?32HUTA SZKLA TOPIC UL
60
+ PRZEMY?33SLOWA 67 32-669 WROCLAW?38PL081060007600007777777
61
+ 77777
62
+ :61:0310201020D10000,00FTRFREF 25611247//8327000090031790
63
+ Transfer
64
64
  :86: 020?00Wyplata-(dysp/przel)?2008106000760000777777777777?2115617?
65
- 22INFO INFO INFO INFO INFO INFO 1 END?23INFO INFO INFO INFO INFO
66
- INFO 2 END?24ZAPLATA ZA FABRYKATY DO TUB?25 - 200 S ZTUK, TRANZY
67
- STORY-?26300 SZT GR544 I OPORNIKI-5?2700 SZT GTX847 FAKTURA 333/
68
- 2?28003.?3010600076?310000777777777777?38PL081060007600007777777
69
- 77777
70
- :61:0310201020C40,00FTRFNONREF//8327000090031791
65
+ 22INFO INFO INFO INFO INFO INFO 1 END?23INFO INFO INFO INFO INFO
66
+ INFO 2 END?24ZAPLATA ZA FABRYKATY DO TUB?25 - 200 S ZTUK, TRANZY
67
+ STORY-?26300 SZT GR544 I OPORNIKI-5?2700 SZT GTX847 FAKTURA 333/
68
+ 2?28003.?3010600076?310000777777777777?38PL081060007600007777777
69
+ 77777
70
+ :61:0310201020C40,00FTRFNONREF//8327000090031791
71
71
  Interest credit
72
- :86: 844?00Uznanie kwotą odsetek?20Odsetki od lokaty nr 101000?21022086
73
- :62F:C020325PLN50040,00
72
+ :86: 844?00Uznanie kwotą odsetek?20Odsetki od lokaty nr 101000?21022086
73
+ :62F:C020325PLN50040,00
74
74
 
75
75
  -
@@ -57,7 +57,7 @@ describe Cmxl do
57
57
  "34" => "171"
58
58
  },
59
59
  "transaction_code" => "171",
60
- "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"
60
+ "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",
61
61
  }
62
62
  )
63
63
  }
@@ -87,7 +87,7 @@ describe Cmxl do
87
87
  "sign" => -1,
88
88
  "debit" => true,
89
89
  "credit" => false,
90
- "storno" => false
90
+ "storno" => false,
91
91
  })
92
92
  end
93
93
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cmxl
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Bumann
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-03 00:00:00.000000000 Z
11
+ date: 2018-04-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -122,6 +122,7 @@ files:
122
122
  - lib/cmxl/fields/statement_details.rb
123
123
  - lib/cmxl/fields/statement_number.rb
124
124
  - lib/cmxl/fields/transaction.rb
125
+ - lib/cmxl/fields/transaction_supplementary.rb
125
126
  - lib/cmxl/statement.rb
126
127
  - lib/cmxl/version.rb
127
128
  - spec/field_spec.rb
@@ -134,6 +135,7 @@ files:
134
135
  - spec/fields/statement_details_spec.rb
135
136
  - spec/fields/statement_number_spec.rb
136
137
  - spec/fields/transaction_spec.rb
138
+ - spec/fields/transaction_supplementary_spec.rb
137
139
  - spec/fields/unknown_spec.rb
138
140
  - spec/fixtures/lines/account_balance_credit.txt
139
141
  - spec/fixtures/lines/account_balance_debit.txt
@@ -147,6 +149,9 @@ files:
147
149
  - spec/fixtures/lines/statement_details_empty_fields.txt
148
150
  - spec/fixtures/lines/statement_line.txt
149
151
  - spec/fixtures/lines/statement_number.txt
152
+ - spec/fixtures/lines/statement_ocmt.txt
153
+ - spec/fixtures/lines/statement_ocmt_chgs.txt
154
+ - spec/fixtures/lines/statement_supplementary_plain.txt
150
155
  - spec/fixtures/mt940-deutsche_bank.txt
151
156
  - spec/fixtures/mt940-iso8859-1.txt
152
157
  - spec/fixtures/mt940-with-detailed-end-balance.txt
@@ -194,6 +199,7 @@ test_files:
194
199
  - spec/fields/statement_details_spec.rb
195
200
  - spec/fields/statement_number_spec.rb
196
201
  - spec/fields/transaction_spec.rb
202
+ - spec/fields/transaction_supplementary_spec.rb
197
203
  - spec/fields/unknown_spec.rb
198
204
  - spec/fixtures/lines/account_balance_credit.txt
199
205
  - spec/fixtures/lines/account_balance_debit.txt
@@ -207,6 +213,9 @@ test_files:
207
213
  - spec/fixtures/lines/statement_details_empty_fields.txt
208
214
  - spec/fixtures/lines/statement_line.txt
209
215
  - spec/fixtures/lines/statement_number.txt
216
+ - spec/fixtures/lines/statement_ocmt.txt
217
+ - spec/fixtures/lines/statement_ocmt_chgs.txt
218
+ - spec/fixtures/lines/statement_supplementary_plain.txt
210
219
  - spec/fixtures/mt940-deutsche_bank.txt
211
220
  - spec/fixtures/mt940-iso8859-1.txt
212
221
  - spec/fixtures/mt940-with-detailed-end-balance.txt