cmxl 1.0.0 → 1.1.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.
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