mt940_parser 1.5.3 → 1.5.5

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
  SHA256:
3
- metadata.gz: '092f1e507213d85a4c94c5685e55a49c7dc9246ee6188c4c5d2cc7609355fa31'
4
- data.tar.gz: 021d003331e57253a8e05e20847ebcdb0bbfbc173062960014cb99cf4cae081b
3
+ metadata.gz: 83c746f0f3871275400a75662a116760798fa3212f443588965c03cb53bfc7a5
4
+ data.tar.gz: f96ef50e6f342890620391ade43d1034a34df62e7320f95502b473abe9d71a3b
5
5
  SHA512:
6
- metadata.gz: 54df6bec1b0ed2b7e6e8b63b3ef710ab886b78df5da253e977ad68f893d5118c8f189faaeca400305f01cf34fdd8368a12ccdf6934aca454a1a702e71ae63533
7
- data.tar.gz: ac777c871fd6c0fd1e51461cf5ee2509085197e7036cda2aa297ebe05dfa90d473e61c45da9633f63c8670e3d30cd6e94001ce39a833dbc70b2157658c9a0190
6
+ metadata.gz: a9ba3439db4b3e5bb1595ac608c9060a453d0a0b3a3b56a4dd41e5f9eb68d017834932723ad574b0f07f0828935313dd966bec679de825060ca746fec2f84432
7
+ data.tar.gz: 2eacc5076f62817e7b1822426573ae8c2efddc6ecaf8af9d7642cb378490fd9d3d40c481ec7a3483c36077dc191eeac3aab5b05e6f28d0d6953256e379ab450d
@@ -0,0 +1,29 @@
1
+ # based on https://github.com/rails/rails/blob/4a78dcb/.github/workflows/rubocop.yml
2
+
3
+ name: rubocop linting
4
+
5
+ on: [push, pull_request]
6
+
7
+ jobs:
8
+ build:
9
+ runs-on: ubuntu-latest
10
+
11
+ steps:
12
+ - uses: actions/checkout@v2
13
+ - name: Set up Ruby
14
+ uses: ruby/setup-ruby@v1
15
+ with:
16
+ ruby-version: 2.7
17
+ - name: Cache gems
18
+ uses: actions/cache@v1
19
+ with:
20
+ path: vendor/bundle
21
+ key: ${{ runner.os }}-rubocop-${{ hashFiles('**/Gemfile.lock') }}
22
+ restore-keys: |
23
+ ${{ runner.os }}-rubocop-
24
+ - name: Install gems
25
+ run: |
26
+ bundle config path vendor/bundle
27
+ bundle install --jobs 4 --retry 3
28
+ - name: Run rubocop
29
+ run: bundle exec rubocop --lint
@@ -0,0 +1,22 @@
1
+ name: tests
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+
9
+ strategy:
10
+ matrix:
11
+ ruby: [ '2.7', 'ruby-head', 'jruby-head' ]
12
+
13
+ steps:
14
+ - uses: actions/checkout@v2
15
+ - name: Set up Ruby ${{ matrix.ruby }}
16
+ uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby }}
19
+ - name: Install dependencies
20
+ run: bundle install --jobs 4
21
+ - name: Test with Rake
22
+ run: bundle exec rake
data/.rubocop.yml ADDED
@@ -0,0 +1,61 @@
1
+ # usage: `rubocop --lint`
2
+
3
+ AllCops:
4
+ NewCops: enable
5
+
6
+ # disable some linters that are not so likely to indicate bugs
7
+
8
+ Lint/AmbiguousAssignment:
9
+ Enabled: false
10
+ Lint/AmbiguousBlockAssociation:
11
+ Enabled: false
12
+ Lint/AmbiguousOperator:
13
+ Enabled: false
14
+ Lint/AmbiguousRegexpLiteral:
15
+ Enabled: false
16
+ Lint/AssignmentInCondition:
17
+ Enabled: false
18
+ Lint/ConstantDefinitionInBlock:
19
+ Enabled: false
20
+ Lint/ConstantResolution:
21
+ Enabled: false
22
+ Lint/DuplicateBranch:
23
+ Enabled: false
24
+ Lint/EmptyBlock:
25
+ Enabled: false
26
+ Lint/EmptyClass:
27
+ Enabled: false
28
+ Lint/EmptyConditionalBody:
29
+ Enabled: false
30
+ Lint/EmptyExpression:
31
+ Enabled: false
32
+ Lint/EmptyFile:
33
+ Enabled: false
34
+ Lint/EmptyWhen:
35
+ Enabled: false
36
+ Lint/EnsureReturn:
37
+ Enabled: false
38
+ Lint/Loop:
39
+ Enabled: false
40
+ Lint/MissingSuper:
41
+ Enabled: false
42
+ Lint/MixedRegexpCaptureTypes:
43
+ Enabled: false
44
+ Lint/NumberConversion:
45
+ Enabled: false
46
+ Lint/ParenthesesAsGroupedExpression:
47
+ Enabled: false
48
+ Lint/RedundantStringCoercion:
49
+ Enabled: false
50
+ Lint/ShadowedArgument:
51
+ Enabled: false
52
+ Lint/ShadowedException:
53
+ Enabled: false
54
+ Lint/ShadowingOuterLocalVariable:
55
+ Enabled: false
56
+ Lint/SuppressedException:
57
+ Enabled: false
58
+ Lint/UnusedBlockArgument:
59
+ Enabled: false
60
+ Lint/UnusedMethodArgument:
61
+ Enabled: false
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 3.1.0
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
- [![Gem Version](https://badge.fury.io/rb/mt940_parser.svg)](http://badge.fury.io/rb/mt940_parser) [![Build Status](https://secure.travis-ci.org/betterplace/mt940_parser.svg?branch=master)](http://travis-ci.org/betterplace/mt940_parser)
1
+ [![Gem Version](https://badge.fury.io/rb/mt940_parser.svg)](http://badge.fury.io/rb/mt940_parser)
2
+ [![Build Status](https://github.com/betterplace/mt940_parser/workflows/tests/badge.svg)](https://github.com/betterplace/mt940_parser/actions)
2
3
 
3
4
  # mt940_parser
4
5
 
data/Rakefile CHANGED
@@ -22,6 +22,7 @@ GemHadar do
22
22
  licenses 'MIT'
23
23
 
24
24
  development_dependency 'test-unit'
25
+ development_dependency 'rubocop'
25
26
  end
26
27
 
27
28
  task :default => :test
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.5.3
1
+ 1.5.5
@@ -3,11 +3,10 @@
3
3
  # the data easier
4
4
  class MT940
5
5
  class CustomerStatementMessage
6
-
7
- attr_reader :account, :statement_lines
6
+ attr_reader :account, :statement_lines, :opening_balance, :closing_balance
8
7
 
9
8
  def self.parse_file(file)
10
- self.parse(File.read(file))
9
+ parse(File.read(file))
11
10
  end
12
11
 
13
12
  def self.parse(data)
@@ -16,12 +15,15 @@ class MT940
16
15
  end
17
16
 
18
17
  def initialize(lines)
19
- @account = lines.find { |line| line.class == MT940::AccountIdentification }
18
+ @account = select_by_type(lines, MT940::AccountIdentification)
19
+ @opening_balance = select_by_type(lines, MT940::AccountBalance)
20
+ @closing_balance = select_by_type(lines, MT940::ClosingBalance)
20
21
  @statement_lines = []
21
22
  lines.each_with_index do |line, i|
22
23
  next unless line.class == MT940::StatementLine
23
- ensure_is_info_line!(lines[i+1])
24
- @statement_lines << StatementLineBundle.new(lines[i], lines[i+1])
24
+
25
+ ensure_is_info_line!(lines[i + 1])
26
+ @statement_lines << StatementLineBundle.new(lines[i], lines[i + 1])
25
27
  end
26
28
  end
27
29
 
@@ -33,36 +35,45 @@ class MT940
33
35
  @account.account_number
34
36
  end
35
37
 
38
+ def signature
39
+ Digest::SHA256.hexdigest(opening_balance.content.to_s + closing_balance.content.to_s)
40
+ end
41
+
36
42
  private
37
43
 
44
+ def select_by_type(lines, line_klass)
45
+ lines.select { |line| line.instance_of?(line_klass) }.first
46
+ end
47
+
38
48
  def ensure_is_info_line!(line)
39
- unless line.is_a? MT940::StatementLineInformation
40
- raise Errors::UnexpectedStructureError,
41
- "Unexpected Structure; expected StatementLineInformation, "\
42
- "but was #{line.class}"
43
- end
49
+ return if line.is_a? MT940::StatementLineInformation
50
+
51
+ raise Errors::UnexpectedStructureError,
52
+ 'Unexpected Structure; expected StatementLineInformation, ' \
53
+ "but was #{line.class}"
44
54
  end
45
55
  end
46
56
 
47
57
  class StatementLineBundle
48
58
  METHOD_MAP = {
49
- :amount => :line,
50
- :funds_code => :line,
51
- :value_date => :line,
52
- :entry_date => :line,
53
- :account_holder => :info,
54
- :details => :info,
55
- :account_number => :info,
56
- :bank_code => :info,
57
- :code => :info,
58
- :transaction_description => :info,
59
+ amount: :line,
60
+ funds_code: :line,
61
+ value_date: :line,
62
+ entry_date: :line,
63
+ account_holder: :info,
64
+ details: :info,
65
+ account_number: :info,
66
+ bank_code: :info,
67
+ code: :info,
68
+ transaction_description: :info
59
69
  }
60
70
 
61
71
  def initialize(statement_line, statement_line_info)
62
- @line, @info = statement_line, statement_line_info
72
+ @line = statement_line
73
+ @info = statement_line_info
63
74
  end
64
75
 
65
- def method_missing(method, *args, &block)
76
+ def method_missing(method, *args, &)
66
77
  super unless METHOD_MAP.has_key?(method)
67
78
  object = instance_variable_get("@#{METHOD_MAP[method.to_sym]}")
68
79
  object.send(method)
data/lib/mt940/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  class MT940
2
2
  # MT940 version
3
- VERSION = '1.5.3'
3
+ VERSION = '1.5.5'
4
4
  VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
5
5
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
6
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
data/lib/mt940.rb CHANGED
@@ -4,6 +4,7 @@ require 'mt940/customer_statement_message'
4
4
  require 'bigdecimal'
5
5
  require 'bigdecimal/util'
6
6
  require 'date'
7
+ require 'digest/sha2'
7
8
 
8
9
  class MT940
9
10
  class Field
@@ -13,10 +14,13 @@ class MT940
13
14
  SHORT_DATE = /(\d{2})(\d{2})/
14
15
 
15
16
  class << self
17
+ LINE = /^:(\d{2})(\w)?:(.*)$/
16
18
 
17
19
  def for(line)
18
- if line.match(/^:(\d{2})(\w)?:(.*)$/)
19
- number, modifier, content = $1, $2, $3
20
+ if line.match(LINE)
21
+ number = ::Regexp.last_match(1)
22
+ modifier = ::Regexp.last_match(2)
23
+ content = ::Regexp.last_match(3)
20
24
  klass = {
21
25
  '20' => Job,
22
26
  '21' => Reference,
@@ -34,7 +38,9 @@ class MT940
34
38
 
35
39
  klass.new(modifier, content)
36
40
  else
37
- raise Errors::WrongLineFormatError, "Wrong line format: #{line.dump}"
41
+ raise Errors::WrongLineFormatError,
42
+ "Wrong line format does not match #{LINE.inspect}. Got: " \
43
+ "#{line.dump[0...80]}#{'[...]' if line.dump.size > 80}"
38
44
  end
39
45
  end
40
46
  end
@@ -55,15 +61,14 @@ class MT940
55
61
 
56
62
  def parse_date(date)
57
63
  date.match(DATE)
58
- ::Date.new("20#{$1}".to_i, $2.to_i, $3.to_i)
64
+ ::Date.new("20#{::Regexp.last_match(1)}".to_i, ::Regexp.last_match(2).to_i, ::Regexp.last_match(3).to_i)
59
65
  end
60
66
 
61
67
  def parse_entry_date(raw_entry_date, value_date)
62
68
  raw_entry_date.match(SHORT_DATE)
63
- entry_date = ::Date.new(value_date.year, $1.to_i, $2.to_i)
64
- unless entry_date.year == value_date.year
65
- raise "Unhandled case: value date and entry date are in different years"
66
- end
69
+ entry_date = ::Date.new(value_date.year, ::Regexp.last_match(1).to_i, ::Regexp.last_match(2).to_i)
70
+ raise 'Unhandled case: value date and entry date are in different years' unless entry_date.year == value_date.year
71
+
67
72
  entry_date
68
73
  end
69
74
  end
@@ -84,20 +89,21 @@ class MT940
84
89
  # 25
85
90
  class AccountIdentification < Field
86
91
  attr_reader :account_identifier
87
- CONTENT = /(.{1,35})/ #any 35 chars (35x from the docs)
92
+
93
+ CONTENT = /(.{1,35})/ # any 35 chars (35x from the docs)
88
94
 
89
95
  def parse_content(content)
90
96
  content.match(CONTENT)
91
- @account_identifier = $1
97
+ @account_identifier = ::Regexp.last_match(1)
92
98
  end
93
99
 
94
100
  # fail over to the old Account class
95
- def method_missing(method, *args, &block)
101
+ def method_missing(method, *args, &)
96
102
  @fail_over_implementation ||= Account.new(@modifier, @content)
97
103
  value = @fail_over_implementation.send(method)
98
- warn "[DEPRECATION]:"
104
+ warn '[DEPRECATION]:'
99
105
  warn "You used '#{method}' on the Account/AccountIdentification class"
100
- warn "This field is not part of the MT940 specification but implementation specific"
106
+ warn 'This field is not part of the MT940 specification but implementation specific'
101
107
  warn "Please use the 'account_identifier' and parse yourself."
102
108
 
103
109
  value
@@ -109,11 +115,13 @@ class MT940
109
115
  class Account < Field
110
116
  attr_reader :bank_code, :account_number, :account_currency
111
117
 
112
- CONTENT = /^(.{8,11})\/(\d{0,23})([A-Z]{3})?$/
118
+ CONTENT = %r{^(.{8,11})/(\d{0,23})([A-Z]{3})?$}
113
119
 
114
120
  def parse_content(content)
115
121
  content.match(CONTENT)
116
- @bank_code, @account_number, @account_currency = $1, $2, $3
122
+ @bank_code = ::Regexp.last_match(1)
123
+ @account_number = ::Regexp.last_match(2)
124
+ @account_currency = ::Regexp.last_match(3)
117
125
  end
118
126
  end
119
127
 
@@ -121,14 +129,15 @@ class MT940
121
129
  class Statement < Field
122
130
  attr_reader :number, :sheet
123
131
 
124
- CONTENT = /^(0|(\d{5,5})\/(\d{2,5}))$/
132
+ CONTENT = %r{^(0|(\d{5,5})/(\d{2,5}))$}
125
133
 
126
134
  def parse_content(content)
127
135
  content.match(CONTENT)
128
- if $1 == '0'
136
+ if ::Regexp.last_match(1) == '0'
129
137
  @number = @sheet = 0
130
138
  else
131
- @number, @sheet = $2.to_i, $3.to_i
139
+ @number = ::Regexp.last_match(2).to_i
140
+ @sheet = ::Regexp.last_match(3).to_i
132
141
  end
133
142
  end
134
143
  end
@@ -151,23 +160,23 @@ class MT940
151
160
  end
152
161
 
153
162
  @sign =
154
- case $1
163
+ case ::Regexp.last_match(1)
155
164
  when 'C'
156
165
  :credit
157
166
  when 'D'
158
167
  :debit
159
168
  end
160
169
 
161
- raw_date = $2
162
- @currency = $3
163
- @amount = parse_amount_in_cents($4)
170
+ raw_date = ::Regexp.last_match(2)
171
+ @currency = ::Regexp.last_match(3)
172
+ @amount = parse_amount_in_cents(::Regexp.last_match(4))
164
173
 
165
174
  @date =
166
175
  case raw_date
167
176
  when 'ALT', '0'
168
177
  nil
169
178
  when DATE
170
- ::Date.new("20#{$1}".to_i, $2.to_i, $3.to_i)
179
+ ::Date.new("20#{::Regexp.last_match(1)}".to_i, ::Regexp.last_match(2).to_i, ::Regexp.last_match(3).to_i)
171
180
  end
172
181
  end
173
182
  end
@@ -176,15 +185,15 @@ class MT940
176
185
  class StatementLine < Field
177
186
  attr_reader :date, :entry_date, :funds_code, :amount, :swift_code, :reference, :transaction_description
178
187
 
179
- CONTENT = /^(\d{6})(\d{4})?(C|D|RC|RD)\D?(\d{1,12},\d{0,2})((?:N|F).{3})(NONREF|.{0,16})(?:$|\/\/)(.*)/
188
+ CONTENT = %r{^(\d{6})(\d{4})?(C|D|RC|RD)\D?(\d{1,12},\d{0,2})((?:N|F).{3})(NONREF|.{0,16})(?:$|//)(.*)}
180
189
 
181
190
  def parse_content(content)
182
191
  content.match(CONTENT)
183
192
 
184
- raw_date = $1
185
- raw_entry_date = $2
193
+ raw_date = ::Regexp.last_match(1)
194
+ raw_entry_date = ::Regexp.last_match(2)
186
195
  @funds_code =
187
- case $3
196
+ case ::Regexp.last_match(3)
188
197
  when 'C'
189
198
  :credit
190
199
  when 'D'
@@ -195,10 +204,10 @@ class MT940
195
204
  :return_debit
196
205
  end
197
206
 
198
- @amount = parse_amount_in_cents($4)
199
- @swift_code = $5
200
- @reference = $6
201
- @transaction_description = $7
207
+ @amount = parse_amount_in_cents(::Regexp.last_match(4))
208
+ @swift_code = ::Regexp.last_match(5)
209
+ @reference = ::Regexp.last_match(6)
210
+ @transaction_description = ::Regexp.last_match(7)
202
211
 
203
212
  @date = parse_date(raw_date)
204
213
  @entry_date = parse_entry_date(raw_entry_date, @date) if raw_entry_date
@@ -224,17 +233,17 @@ class MT940
224
233
  # 86
225
234
  class StatementLineInformation < Field
226
235
  attr_reader :code, :transaction_description, :prima_nota, :details, :bank_code, :account_number,
227
- :account_holder, :text_key_extension, :not_implemented_fields
236
+ :account_holder, :text_key_extension, :not_implemented_fields
228
237
 
229
238
  def parse_content(content)
230
239
  content.match(/^(\d{3})((.).*)$/)
231
- @code = $1.to_i
240
+ @code = ::Regexp.last_match(1).to_i
232
241
 
233
242
  details = []
234
243
  account_holder = []
235
244
 
236
- if seperator = $3
237
- sub_fields = $2.scan(
245
+ if seperator = ::Regexp.last_match(3)
246
+ sub_fields = ::Regexp.last_match(2).scan(
238
247
  /#{Regexp.escape(seperator)}(\d{2})([^#{Regexp.escape(seperator)}]*)/
239
248
  )
240
249
 
@@ -256,10 +265,8 @@ class MT940
256
265
  @text_key_extension = content
257
266
  else
258
267
  @not_implemented_fields ||= []
259
- @not_implemented_fields << [ code, content ]
260
- if $DEBUG
261
- warn "code not implemented: code:#{code} content: #{content.inspect}"
262
- end
268
+ @not_implemented_fields << [code, content]
269
+ warn "code not implemented: code:#{code} content: #{content.inspect}" if $DEBUG
263
270
  end
264
271
  end
265
272
  end
@@ -276,15 +283,14 @@ class MT940
276
283
  raw_sheets = new_text.split(/^-\s*\r\n/).map do |sheet|
277
284
  sheet.gsub(/\r\n(?!:\d{2}\w?:)/, '')
278
285
  end
279
- sheets = raw_sheets.map { |raw_sheet| parse_sheet(raw_sheet) }
286
+ raw_sheets.map { |raw_sheet| parse_sheet(raw_sheet) }
280
287
  end
281
288
 
282
289
  private
283
290
 
284
291
  def parse_sheet(sheet)
285
292
  lines = sheet.split("\r\n")
286
- fields = lines.reject { |line| line.empty? }.map { |line| Field.for(line) }
287
- fields
293
+ lines.reject { |line| line.empty? }.map { |line| Field.for(line) }
288
294
  end
289
295
  end
290
296
  end
@@ -0,0 +1,3 @@
1
+ # this is here so the gem can be required by the same name its installed with
2
+
3
+ require 'mt940'
data/mt940_parser.gemspec CHANGED
@@ -1,22 +1,22 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: mt940_parser 1.5.3 ruby lib
2
+ # stub: mt940_parser 1.5.5 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "mt940_parser".freeze
6
- s.version = "1.5.3"
6
+ s.version = "1.5.5"
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
10
10
  s.authors = ["Thies C. Arntzen".freeze, "Phillip Oertel".freeze]
11
- s.date = "2021-06-17"
11
+ s.date = "2025-05-21"
12
12
  s.description = "Ruby library that parses account statements in the SWIFT MT940 format.".freeze
13
13
  s.email = "developers@betterplace.org".freeze
14
- s.extra_rdoc_files = ["README.md".freeze, "lib/mt940.rb".freeze, "lib/mt940/customer_statement_message.rb".freeze, "lib/mt940/errors.rb".freeze, "lib/mt940/version.rb".freeze]
15
- s.files = [".document".freeze, ".gitignore".freeze, ".specification".freeze, ".travis.yml".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "docs/0E0Y00DNY.pdf".freeze, "docs/FinTS_4.0_Formals.pdf".freeze, "docs/FinTS_4.0_Messages_Finanzdatenformate.pdf".freeze, "docs/MT940_Deutschland_Structure2002.pdf".freeze, "docs/SEPA_20MT940__Schnittstellenbeschreibung.pdf".freeze, "docs/mt940.pdf".freeze, "docs/swift_mt940_942.pdf".freeze, "docs/uebersicht_der_geschaeftsvorfallcodes_und_buchungs_textschluessel.pdf".freeze, "lib/mt940.rb".freeze, "lib/mt940/customer_statement_message.rb".freeze, "lib/mt940/errors.rb".freeze, "lib/mt940/version.rb".freeze, "mt940_parser.gemspec".freeze, "test/fixtures/amount_formats.txt".freeze, "test/fixtures/amount_formats.yml".freeze, "test/fixtures/colon_in_descriptor.txt".freeze, "test/fixtures/colon_in_descriptor.yml".freeze, "test/fixtures/currency_in_25.txt".freeze, "test/fixtures/currency_in_25.yml".freeze, "test/fixtures/empty_86.txt".freeze, "test/fixtures/empty_86.yml".freeze, "test/fixtures/empty_entry_date.txt".freeze, "test/fixtures/empty_entry_date.yml".freeze, "test/fixtures/empty_line.txt".freeze, "test/fixtures/empty_line.yml".freeze, "test/fixtures/missing_crlf_at_end.txt".freeze, "test/fixtures/missing_crlf_at_end.yml".freeze, "test/fixtures/sepa_mt9401.txt".freeze, "test/fixtures/sepa_mt9401.yml".freeze, "test/fixtures/sepa_snippet.txt".freeze, "test/fixtures/sepa_snippet_broken.txt".freeze, "test/fixtures/with_binary_character.txt".freeze, "test/fixtures/with_binary_character.yml".freeze, "test/test_account_identifier.rb".freeze, "test/test_customer_statement_message.rb".freeze, "test/test_helper.rb".freeze, "test/test_mt940.rb".freeze]
14
+ s.extra_rdoc_files = ["README.md".freeze, "lib/mt940.rb".freeze, "lib/mt940/customer_statement_message.rb".freeze, "lib/mt940/errors.rb".freeze, "lib/mt940/version.rb".freeze, "lib/mt940_parser.rb".freeze]
15
+ s.files = [".document".freeze, ".github/workflows/lint.yml".freeze, ".github/workflows/tests.yml".freeze, ".gitignore".freeze, ".rubocop.yml".freeze, ".specification".freeze, ".tool-versions".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "docs/0E0Y00DNY.pdf".freeze, "docs/FinTS_4.0_Formals.pdf".freeze, "docs/FinTS_4.0_Messages_Finanzdatenformate.pdf".freeze, "docs/MT940_Deutschland_Structure2002.pdf".freeze, "docs/SEPA_20MT940__Schnittstellenbeschreibung.pdf".freeze, "docs/mt940.pdf".freeze, "docs/swift_mt940_942.pdf".freeze, "docs/uebersicht_der_geschaeftsvorfallcodes_und_buchungs_textschluessel.pdf".freeze, "lib/mt940.rb".freeze, "lib/mt940/customer_statement_message.rb".freeze, "lib/mt940/errors.rb".freeze, "lib/mt940/version.rb".freeze, "lib/mt940_parser.rb".freeze, "mt940_parser.gemspec".freeze, "test/fixtures/amount_formats.txt".freeze, "test/fixtures/amount_formats.yml".freeze, "test/fixtures/colon_in_descriptor.txt".freeze, "test/fixtures/colon_in_descriptor.yml".freeze, "test/fixtures/currency_in_25.txt".freeze, "test/fixtures/currency_in_25.yml".freeze, "test/fixtures/empty_86.txt".freeze, "test/fixtures/empty_86.yml".freeze, "test/fixtures/empty_entry_date.txt".freeze, "test/fixtures/empty_entry_date.yml".freeze, "test/fixtures/empty_line.txt".freeze, "test/fixtures/empty_line.yml".freeze, "test/fixtures/missing_crlf_at_end.txt".freeze, "test/fixtures/missing_crlf_at_end.yml".freeze, "test/fixtures/sepa_mt9401.txt".freeze, "test/fixtures/sepa_mt9401.yml".freeze, "test/fixtures/sepa_snippet.txt".freeze, "test/fixtures/sepa_snippet_broken.txt".freeze, "test/fixtures/with_binary_character.txt".freeze, "test/fixtures/with_binary_character.yml".freeze, "test/test_account_identifier.rb".freeze, "test/test_customer_statement_message.rb".freeze, "test/test_helper.rb".freeze, "test/test_mt940.rb".freeze]
16
16
  s.homepage = "http://github.com/betterplace/mt940_parser".freeze
17
17
  s.licenses = ["MIT".freeze]
18
18
  s.rdoc_options = ["--title".freeze, "Mt940Parser - MT940 parses account statements in the SWIFT MT940 format.".freeze, "--main".freeze, "README.md".freeze]
19
- s.rubygems_version = "3.2.3".freeze
19
+ s.rubygems_version = "3.3.3".freeze
20
20
  s.summary = "MT940 parses account statements in the SWIFT MT940 format.".freeze
21
21
  s.test_files = ["test/test_account_identifier.rb".freeze, "test/test_customer_statement_message.rb".freeze, "test/test_helper.rb".freeze, "test/test_mt940.rb".freeze]
22
22
 
@@ -27,8 +27,10 @@ Gem::Specification.new do |s|
27
27
  if s.respond_to? :add_runtime_dependency then
28
28
  s.add_development_dependency(%q<gem_hadar>.freeze, ["~> 1.11.0"])
29
29
  s.add_development_dependency(%q<test-unit>.freeze, [">= 0"])
30
+ s.add_development_dependency(%q<rubocop>.freeze, [">= 0"])
30
31
  else
31
32
  s.add_dependency(%q<gem_hadar>.freeze, ["~> 1.11.0"])
32
33
  s.add_dependency(%q<test-unit>.freeze, [">= 0"])
34
+ s.add_dependency(%q<rubocop>.freeze, [">= 0"])
33
35
  end
34
36
  end
@@ -1,22 +1,20 @@
1
1
  require_relative 'test_helper'
2
2
 
3
-
4
3
  # $DEBUG = true
5
4
  class TestCustomerStatementMessage < Test::Unit::TestCase
6
-
7
5
  def setup
8
- file = File.dirname(__FILE__) + "/fixtures/sepa_snippet.txt"
6
+ file = File.dirname(__FILE__) + '/fixtures/sepa_snippet.txt'
9
7
  messages = MT940::CustomerStatementMessage.parse_file(file)
10
8
  @message = messages.first
11
9
  @message_2 = messages.last
12
10
  end
13
11
 
14
12
  def test_it_should_know_the_bank_code
15
- assert_equal "50880050", @message.bank_code
13
+ assert_equal '50880050', @message.bank_code
16
14
  end
17
15
 
18
16
  def test_it_should_know_the_account_number
19
- assert_equal "0194787400888", @message.account_number
17
+ assert_equal '0194787400888', @message.account_number
20
18
  end
21
19
 
22
20
  def test_it_should_have_an_account_identification
@@ -30,7 +28,7 @@ class TestCustomerStatementMessage < Test::Unit::TestCase
30
28
 
31
29
  def test_statement_lines_should_have_amount_info_credit
32
30
  line = @message.statement_lines.first
33
- assert_equal 5099005, line.amount
31
+ assert_equal 5_099_005, line.amount
34
32
  assert_equal :credit, line.funds_code
35
33
  end
36
34
 
@@ -47,12 +45,12 @@ class TestCustomerStatementMessage < Test::Unit::TestCase
47
45
 
48
46
  def test_statement_lines_info_should_have_bank_code
49
47
  line = @message.statement_lines.first
50
- assert_equal "DRESDEFF508", line.bank_code
48
+ assert_equal 'DRESDEFF508', line.bank_code
51
49
  end
52
50
 
53
51
  def test_statement_lines_info_should_have_account_number
54
52
  line = @message.statement_lines.first
55
- assert_equal "DE14508800500194785000", line.account_number
53
+ assert_equal 'DE14508800500194785000', line.account_number
56
54
  end
57
55
 
58
56
  def test_statement_lines_should_have_details
@@ -62,32 +60,45 @@ class TestCustomerStatementMessage < Test::Unit::TestCase
62
60
 
63
61
  def test_statement_lines_should_have_an_entry_date
64
62
  line = @message.statement_lines.first
65
- assert_equal Date.parse("2007-09-04"), line.entry_date
63
+ assert_equal Date.parse('2007-09-04'), line.entry_date
66
64
  end
67
65
 
68
66
  def test_statement_lines_should_have_a_value_date
69
67
  line = @message.statement_lines.first
70
- assert_equal Date.parse("2007-09-07"), line.value_date
68
+ assert_equal Date.parse('2007-09-07'), line.value_date
71
69
  end
72
70
 
73
71
  def test_parsing_the_file_should_return_two_message_objects
74
- file = File.dirname(__FILE__) + "/fixtures/sepa_snippet.txt"
72
+ file = File.dirname(__FILE__) + '/fixtures/sepa_snippet.txt'
75
73
  messages = MT940::CustomerStatementMessage.parse_file(file)
76
74
  assert_equal 2, messages.size
77
- assert_equal "0194787400888", messages[0].account_number
78
- assert_equal "0194791600888", messages[1].account_number
75
+ assert_equal '0194787400888', messages[0].account_number
76
+ assert_equal '0194791600888', messages[1].account_number
79
77
  end
80
78
 
81
79
  def test_parsing_a_file_with_broken_structure_should_raise_an_exception
82
- file = File.dirname(__FILE__) + "/fixtures/sepa_snippet_broken.txt"
80
+ file = File.dirname(__FILE__) + '/fixtures/sepa_snippet_broken.txt'
83
81
  assert_raise(MT940::Errors::UnexpectedStructureError) do
84
82
  MT940::CustomerStatementMessage.parse_file(file)
85
83
  end
86
84
  end
87
85
 
88
86
  def test_should_raise_method_missing_when_asking_statement_lines_for_unknown_stuff
89
- file = File.dirname(__FILE__) + "/fixtures/sepa_snippet.txt"
87
+ file = File.dirname(__FILE__) + '/fixtures/sepa_snippet.txt'
88
+ message = MT940::CustomerStatementMessage.parse_file(file).first
89
+ assert_raise(NoMethodError) { message.statement_lines.first.foo }
90
+ end
91
+
92
+ def test_should_parse_opening_and_closing_saldo
93
+ file = File.dirname(__FILE__) + '/fixtures/sepa_snippet.txt'
94
+ message = MT940::CustomerStatementMessage.parse_file(file).first
95
+ assert_equal(message.opening_balance.amount, 76_665_649)
96
+ assert_equal(message.closing_balance.amount, 112_525_040)
97
+ end
98
+
99
+ def test_should_have_signature
100
+ file = File.dirname(__FILE__) + '/fixtures/sepa_snippet.txt'
90
101
  message = MT940::CustomerStatementMessage.parse_file(file).first
91
- assert_raise(NoMethodError) { message.statement_lines.first.foo }
102
+ assert_equal(message.signature, 'b16439633c7c52fed8e28f717f364e7ec1936f123aa56ab66b15662093cb60ca')
92
103
  end
93
104
  end
data/test/test_mt940.rb CHANGED
@@ -9,8 +9,11 @@ class TestMt940 < Test::Unit::TestCase
9
9
  data = MT940.parse(IO.read(file))
10
10
 
11
11
  generated_structure_file = file.gsub(/.txt$/, ".yml")
12
+ # ruby 3.1 / psych 4 disallows loading classes from YAML by default
13
+ load_method = YAML.respond_to?(:unsafe_load_file) ? :unsafe_load_file : :load_file
12
14
 
13
- assert_equal YAML::load_file(generated_structure_file).to_yaml, data.to_yaml
15
+ assert_equal YAML.send(load_method, generated_structure_file).to_yaml,
16
+ data.to_yaml
14
17
  end
15
18
  end
16
19
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mt940_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.3
4
+ version: 1.5.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thies C. Arntzen
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-06-17 00:00:00.000000000 Z
12
+ date: 2025-05-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: gem_hadar
@@ -39,6 +39,20 @@ dependencies:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
41
  version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rubocop
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
42
56
  description: Ruby library that parses account statements in the SWIFT MT940 format.
43
57
  email: developers@betterplace.org
44
58
  executables: []
@@ -49,11 +63,15 @@ extra_rdoc_files:
49
63
  - lib/mt940/customer_statement_message.rb
50
64
  - lib/mt940/errors.rb
51
65
  - lib/mt940/version.rb
66
+ - lib/mt940_parser.rb
52
67
  files:
53
68
  - ".document"
69
+ - ".github/workflows/lint.yml"
70
+ - ".github/workflows/tests.yml"
54
71
  - ".gitignore"
72
+ - ".rubocop.yml"
55
73
  - ".specification"
56
- - ".travis.yml"
74
+ - ".tool-versions"
57
75
  - Gemfile
58
76
  - LICENSE
59
77
  - README.md
@@ -71,6 +89,7 @@ files:
71
89
  - lib/mt940/customer_statement_message.rb
72
90
  - lib/mt940/errors.rb
73
91
  - lib/mt940/version.rb
92
+ - lib/mt940_parser.rb
74
93
  - mt940_parser.gemspec
75
94
  - test/fixtures/amount_formats.txt
76
95
  - test/fixtures/amount_formats.yml
@@ -119,7 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
138
  - !ruby/object:Gem::Version
120
139
  version: '0'
121
140
  requirements: []
122
- rubygems_version: 3.2.3
141
+ rubygems_version: 3.3.3
123
142
  signing_key:
124
143
  specification_version: 4
125
144
  summary: MT940 parses account statements in the SWIFT MT940 format.
data/.travis.yml DELETED
@@ -1,18 +0,0 @@
1
- before_install:
2
- - gem update --system
3
- - gem update bundler
4
-
5
- rvm:
6
- - 2.1
7
- - 2.2
8
- - 2.3
9
- - 2.4
10
- - 2.5
11
- - ruby-head
12
- - jruby-head
13
- matrix:
14
- allow_failures:
15
- - rvm: ruby-head
16
- - rvm: jruby-head
17
-
18
- sudo: false