clieop 0.2.2 → 1.0.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.
- data/.gitignore +1 -0
- data/README.rdoc +2 -0
- data/clieop.gemspec +6 -6
- data/doc/VERWINFO_NL_4.1_11-2009.pdf +0 -0
- data/lib/clieop/payment/batch.rb +128 -0
- data/lib/clieop/payment/file.rb +45 -0
- data/lib/clieop/payment/record.rb +124 -0
- data/lib/clieop/process_info/batch.rb +27 -0
- data/lib/clieop/process_info/file.rb +51 -0
- data/lib/clieop/process_info/record.rb +221 -0
- data/lib/clieop/process_info/transaction.rb +24 -0
- data/lib/clieop.rb +13 -4
- data/lib/core_ext/hash.rb +13 -0
- data/lib/core_ext/string.rb +19 -0
- data/spec/clieop/{batch_spec.rb → payment/batch_spec.rb} +55 -12
- data/spec/clieop/{file_spec.rb → payment/file_spec.rb} +1 -1
- data/spec/clieop/{record_spec.rb → payment/record_spec.rb} +27 -13
- data/spec/clieop/process_info/batch_spec.rb +26 -0
- data/spec/clieop/process_info/file_spec.rb +35 -0
- data/spec/clieop/process_info/record_spec.rb +32 -0
- data/spec/clieop/process_info/transaction_spec.rb +22 -0
- data/spec/clieop_spec.rb +2 -2
- data/spec/files/VERWINFO.txt +97 -0
- metadata +57 -20
- data/lib/clieop/batch.rb +0 -112
- data/lib/clieop/file.rb +0 -43
- data/lib/clieop/record.rb +0 -110
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
= CLIEOP
|
2
2
|
|
3
|
+
{<img src="https://secure.travis-ci.org/wvanbergen/clieop.png?branch=master" alt="Build Status" />}[http://travis-ci.org/wvanbergen/clieop]
|
4
|
+
|
3
5
|
This library is a pure Ruby implementation of the *CLIEOP03* format. Currently,
|
4
6
|
it only supports writing CLIEOP files with accounts receivable transactions.
|
5
7
|
Accounts payable transactions, and reading existing CLIEOP files is planned to be
|
data/clieop.gemspec
CHANGED
@@ -3,14 +3,14 @@ Gem::Specification.new do |s|
|
|
3
3
|
|
4
4
|
# Do not set version and date yourself, this will be done automatically
|
5
5
|
# by the gem release script.
|
6
|
-
s.version = "0.
|
7
|
-
s.date = "
|
6
|
+
s.version = "1.0.0"
|
7
|
+
s.date = "2012-07-20"
|
8
8
|
|
9
9
|
s.summary = "A pure Ruby implementation to write CLIEOP files"
|
10
10
|
s.description = "This library is a pure Ruby, MIT licensed implementation of the CLIEOP03 transaction format. CLIEOP03 can be used to communicate direct debt transactions with your (Dutch) bank."
|
11
11
|
|
12
|
-
s.authors = ['Willem van Bergen', 'Leon Berenschot']
|
13
|
-
s.email = ['willem@vanbergen.org', 'LeipeLeon@gmail.com']
|
12
|
+
s.authors = ['Willem van Bergen', 'Leon Berenschot', 'Reinier de Lange']
|
13
|
+
s.email = ['willem@vanbergen.org', 'LeipeLeon@gmail.com', 'r.j.delange@nedforce.nl']
|
14
14
|
s.homepage = 'http://github.com/wvanbergen/clieop/wiki'
|
15
15
|
|
16
16
|
s.add_development_dependency('rake')
|
@@ -19,6 +19,6 @@ Gem::Specification.new do |s|
|
|
19
19
|
|
20
20
|
# Do not set files and test_files yourself, this will be done automatically
|
21
21
|
# by the gem release script.
|
22
|
-
s.files = %w(.gitignore .infinity_test .rspec Gemfile MIT-LICENSE README.rdoc Rakefile autotest/discover.rb clieop.gemspec doc/clieop03.pdf lib/clieop.rb lib/clieop/batch.rb lib/clieop/file.rb lib/clieop/record.rb spec/clieop/batch_spec.rb spec/clieop/file_spec.rb spec/clieop/record_spec.rb spec/clieop_spec.rb spec/spec_helper.rb tasks/github-gem.rake)
|
23
|
-
s.test_files = %w(spec/clieop/batch_spec.rb spec/clieop/file_spec.rb spec/clieop/record_spec.rb spec/clieop_spec.rb)
|
22
|
+
s.files = %w(.gitignore .infinity_test .rspec Gemfile MIT-LICENSE README.rdoc Rakefile autotest/discover.rb clieop.gemspec doc/VERWINFO_NL_4.1_11-2009.pdf doc/clieop03.pdf lib/clieop.rb lib/clieop/payment/batch.rb lib/clieop/payment/file.rb lib/clieop/payment/record.rb lib/clieop/process_info/batch.rb lib/clieop/process_info/file.rb lib/clieop/process_info/record.rb lib/clieop/process_info/transaction.rb lib/core_ext/hash.rb lib/core_ext/string.rb spec/clieop/payment/batch_spec.rb spec/clieop/payment/file_spec.rb spec/clieop/payment/record_spec.rb spec/clieop/process_info/batch_spec.rb spec/clieop/process_info/file_spec.rb spec/clieop/process_info/record_spec.rb spec/clieop/process_info/transaction_spec.rb spec/clieop_spec.rb spec/files/VERWINFO.txt spec/spec_helper.rb tasks/github-gem.rake)
|
23
|
+
s.test_files = %w(spec/clieop/payment/batch_spec.rb spec/clieop/payment/file_spec.rb spec/clieop/payment/record_spec.rb spec/clieop/process_info/batch_spec.rb spec/clieop/process_info/file_spec.rb spec/clieop/process_info/record_spec.rb spec/clieop/process_info/transaction_spec.rb spec/clieop_spec.rb)
|
24
24
|
end
|
Binary file
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module Clieop
|
2
|
+
module Payment
|
3
|
+
|
4
|
+
class Batch
|
5
|
+
|
6
|
+
attr_accessor :transactions, :batch_info
|
7
|
+
|
8
|
+
def initialize(batch_info)
|
9
|
+
raise "Required: :description, :account_nr, :account_owner" unless ([:account_nr, :account_owner] - batch_info.keys).empty?
|
10
|
+
@transactions = []
|
11
|
+
@batch_info = batch_info
|
12
|
+
end
|
13
|
+
|
14
|
+
# Adds a transaction to the batch
|
15
|
+
#
|
16
|
+
# :amount The amount involved with this transaction
|
17
|
+
# :account_nr The bank account from the other party
|
18
|
+
# :account_owner The name of the owner of the bank account
|
19
|
+
# :reference_number A reference number to identify this transaction
|
20
|
+
# :description A description for this transaction (4 lines max)
|
21
|
+
def add_transaction (transaction)
|
22
|
+
raise "No :account_nr given" if transaction[:account_nr].nil?
|
23
|
+
raise "No :amount given" if transaction[:amount].nil?
|
24
|
+
raise "No :account_owner given" if transaction[:account_owner].nil?
|
25
|
+
@transactions << transaction
|
26
|
+
end
|
27
|
+
|
28
|
+
alias_method :<<, :add_transaction
|
29
|
+
|
30
|
+
def to_clieop
|
31
|
+
|
32
|
+
# generate batch header records
|
33
|
+
batch_data = ""
|
34
|
+
batch_data << Clieop::Payment::Record.new(:batch_header,
|
35
|
+
:transaction_group => @batch_info[:transaction_group] || 0,
|
36
|
+
:acount_nr => @batch_info[:account_nr] || 0,
|
37
|
+
:serial_nr => @batch_info[:serial_nr] || 1,
|
38
|
+
:currency => @batch_info[:currency] || "EUR").to_clieop
|
39
|
+
|
40
|
+
# split batch discription into lines and make a record for the first 4 lines
|
41
|
+
unless @batch_info[:description].nil? || @batch_info[:description] == ''
|
42
|
+
@batch_info[:description].split(/\r?\n/)[0, 4].each do |line| # FIXME raise warning when line is longer than 32 chars/description longer than 4 lines
|
43
|
+
batch_data << Clieop::Payment::Record.new(:batch_description, :description => line.strip).to_s unless line == ''
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
batch_data << Clieop::Payment::Record.new(:batch_owner,
|
48
|
+
:process_date => @batch_info[:process_date] || 0,
|
49
|
+
:owner => @batch_info[:account_owner]).to_clieop
|
50
|
+
|
51
|
+
# initialize checksums
|
52
|
+
total_account = @batch_info[:account_nr].to_i * @transactions.length
|
53
|
+
total_amount = 0
|
54
|
+
|
55
|
+
# add transactions to batch
|
56
|
+
@transactions.each do |tr|
|
57
|
+
|
58
|
+
# prepare data for this transaction's records
|
59
|
+
transaction_type = tr[:transaction_type] || (transaction_is_payment? ? 1002 : 0)
|
60
|
+
to_account = transaction_is_payment? ? @batch_info[:account_nr] : tr[:account_nr]
|
61
|
+
from_account = transaction_is_payment? ? tr[:account_nr] : @batch_info[:account_nr]
|
62
|
+
amount_in_cents = (tr[:amount] * 100).round.to_i
|
63
|
+
|
64
|
+
# update checksums
|
65
|
+
total_account += tr[:account_nr].to_i
|
66
|
+
total_amount += amount_in_cents
|
67
|
+
|
68
|
+
# generate transaction record
|
69
|
+
batch_data << Clieop::Payment::Record.new(:transaction_info,
|
70
|
+
:transaction_type => transaction_type, :amount => amount_in_cents,
|
71
|
+
:to_account => to_account, :from_account => from_account).to_clieop
|
72
|
+
|
73
|
+
# generate record with transaction information
|
74
|
+
if transaction_is_payment?
|
75
|
+
batch_data << Clieop::Payment::Record.new(:invoice_name, :name => tr[:account_owner]).to_clieop
|
76
|
+
batch_data << Clieop::Payment::Record.new(:invoice_city, :city => tr[:account_city]).to_clieop unless tr[:account_city].nil?
|
77
|
+
end
|
78
|
+
|
79
|
+
batch_data << Clieop::Payment::Record.new(:transaction_reference, :reference_number => tr[:reference_number]).to_clieop unless tr[:reference_number].nil?
|
80
|
+
|
81
|
+
# split discription into lines and make a record for the first 4 lines
|
82
|
+
unless tr[:description].nil? || tr[:description] == ''
|
83
|
+
tr[:description].split(/\r?\n/)[0, 4].each do |line| # FIXME raise warning when line is longer than 32 chars/description longer than 4 lines
|
84
|
+
batch_data << Clieop::Payment::Record.new(:transaction_description, :description => line.strip).to_s unless line == ''
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
unless transaction_is_payment?
|
89
|
+
batch_data << Clieop::Payment::Record.new(:payment_name, :name => tr[:account_owner]).to_clieop
|
90
|
+
batch_data << Clieop::Payment::Record.new(:payment_city, :city => tr[:account_city]).to_clieop unless tr[:account_city].nil?
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
# generate batch footer record including some checks
|
96
|
+
batch_data << Clieop::Payment::Record.new(:batch_footer, :transaction_count => @transactions.length,
|
97
|
+
:total_amount => total_amount, :account_checksum => account_checksum(total_account)).to_clieop
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
alias_method :to_s, :to_clieop
|
102
|
+
|
103
|
+
# creates a batch for payments from a given account
|
104
|
+
def self.payment_batch(batch_info = {})
|
105
|
+
batch_info[:transaction_group] ||= 0
|
106
|
+
Clieop::Payment::Batch.new(batch_info)
|
107
|
+
end
|
108
|
+
|
109
|
+
# creates a batch for invoices to a given account
|
110
|
+
def self.invoice_batch(batch_info = {})
|
111
|
+
batch_info[:transaction_group] ||= 10
|
112
|
+
Clieop::Payment::Batch.new(batch_info)
|
113
|
+
end
|
114
|
+
|
115
|
+
# the checksum on the total of accounts is in fact the last 10 chars of total amount
|
116
|
+
def account_checksum(total)
|
117
|
+
total.to_s.split('').last(10).join('') # ruby 1.8.6
|
118
|
+
# total.to_s.chars.last(10).join('') # ruby 1.8.7
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
def transaction_is_payment?
|
124
|
+
@batch_info[:transaction_group] == 10
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Clieop
|
2
|
+
module Payment
|
3
|
+
|
4
|
+
class File
|
5
|
+
|
6
|
+
attr_accessor :batches
|
7
|
+
attr_reader :file_info
|
8
|
+
|
9
|
+
def initialize(file_info = {})
|
10
|
+
file_info[:date] = Date.today unless file_info[:date]
|
11
|
+
file_info[:date] = file_info[:date].strftime('%d%m%y') if file_info[:date].respond_to?(:strftime)
|
12
|
+
@file_info = file_info
|
13
|
+
@batches = []
|
14
|
+
end
|
15
|
+
|
16
|
+
# renders this file as a CLIEOP03 formatted string
|
17
|
+
def to_clieop
|
18
|
+
clieop_data = Clieop::Payment::Record.new(:file_header, @file_info).to_clieop
|
19
|
+
@batches.each { |batch| clieop_data << batch.to_clieop }
|
20
|
+
clieop_data << Clieop::Payment::Record.new(:file_footer).to_clieop
|
21
|
+
end
|
22
|
+
|
23
|
+
# Alias for to_clieop
|
24
|
+
alias_method :to_s, :to_clieop
|
25
|
+
|
26
|
+
def payment_batch(options)
|
27
|
+
@batches << Clieop::Payment::Batch.payment_batch(options)
|
28
|
+
yield(@batches.last) if block_given?
|
29
|
+
return @batches.last
|
30
|
+
end
|
31
|
+
|
32
|
+
def invoice_batch(options)
|
33
|
+
@batches << Clieop::Payment::Batch.invoice_batch(options)
|
34
|
+
yield(@batches.last) if block_given?
|
35
|
+
return @batches.last
|
36
|
+
end
|
37
|
+
|
38
|
+
def save(filename)
|
39
|
+
::File.open(filename, 'w') do |f|
|
40
|
+
f.write(self.to_clieop)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Clieop
|
2
|
+
module Payment
|
3
|
+
|
4
|
+
class Record
|
5
|
+
|
6
|
+
LINE_SEPARATOR = "\r\n"
|
7
|
+
|
8
|
+
TYPE_DEFINITIONS = {
|
9
|
+
:file_header => [
|
10
|
+
[:record_code, :numeric, 4, 1],
|
11
|
+
[:record_variant, :alpha, 1, 'A'],
|
12
|
+
[:date, :numeric, 6],
|
13
|
+
[:filename, :alpha, 8, 'CLIEOP03'],
|
14
|
+
[:sender_identification, :alpha, 5],
|
15
|
+
[:file_identification, :alpha, 4],
|
16
|
+
[:duplicate_code, :numeric, 1, 1]
|
17
|
+
],
|
18
|
+
:file_footer => [
|
19
|
+
[:record_code, :numeric, 4, 9999],
|
20
|
+
[:record_variant, :alpha, 1, 'A'],
|
21
|
+
],
|
22
|
+
:batch_header => [
|
23
|
+
[:record_code, :numeric, 4, 10],
|
24
|
+
[:record_variant, :alpha, 1, 'B'],
|
25
|
+
[:transaction_group, :numeric, 2],
|
26
|
+
[:acount_nr, :numeric, 10],
|
27
|
+
[:serial_nr, :numeric, 4],
|
28
|
+
[:currency, :alpha, 3, 'EUR']
|
29
|
+
],
|
30
|
+
:batch_footer => [
|
31
|
+
[:record_code, :numeric, 4, 9990],
|
32
|
+
[:record_variant, :alpha, 1, 'A'],
|
33
|
+
[:total_amount, :numeric, 18],
|
34
|
+
[:account_checksum, :numeric, 10],
|
35
|
+
[:transaction_count, :numeric, 7],
|
36
|
+
],
|
37
|
+
:batch_description => [
|
38
|
+
[:record_code, :numeric, 4, 20],
|
39
|
+
[:record_variant, :alpha, 1, 'A'],
|
40
|
+
[:description, :alpha, 32]
|
41
|
+
],
|
42
|
+
:batch_owner => [
|
43
|
+
[:record_code, :numeric, 4, 30],
|
44
|
+
[:record_variant, :alpha, 1, 'B'],
|
45
|
+
[:naw_code, :numeric, 1, 1],
|
46
|
+
[:process_date, :numeric, 6, 0],
|
47
|
+
[:owner, :alpha, 35],
|
48
|
+
[:test, :alpha, 1, 'P']
|
49
|
+
],
|
50
|
+
:transaction_info => [
|
51
|
+
[:record_code, :numeric, 4, 100],
|
52
|
+
[:record_variant, :alpha, 1, 'A'],
|
53
|
+
[:transaction_type, :numeric, 4, 1002],
|
54
|
+
[:amount, :numeric, 12],
|
55
|
+
[:from_account, :numeric, 10],
|
56
|
+
[:to_account, :numeric, 10],
|
57
|
+
],
|
58
|
+
:invoice_name => [
|
59
|
+
[:record_code, :numeric, 4, 110],
|
60
|
+
[:record_variant, :alpha, 1, 'B'],
|
61
|
+
[:name, :alpha, 35],
|
62
|
+
],
|
63
|
+
:invoice_city => [
|
64
|
+
[:record_code, :numeric, 4, 113],
|
65
|
+
[:record_variant, :alpha, 1, 'B'],
|
66
|
+
[:city, :alpha, 35],
|
67
|
+
],
|
68
|
+
:transaction_reference => [
|
69
|
+
[:record_code, :numeric, 4, 150],
|
70
|
+
[:record_variant, :alpha, 1, 'A'],
|
71
|
+
[:reference_number, :alpha, 16],
|
72
|
+
],
|
73
|
+
:transaction_description => [
|
74
|
+
[:record_code, :numeric, 4, 160],
|
75
|
+
[:record_variant, :alpha, 1, 'A'],
|
76
|
+
[:description, :alpha, 32],
|
77
|
+
],
|
78
|
+
:payment_name =>[
|
79
|
+
[:record_code, :numeric, 4, 170],
|
80
|
+
[:record_variant, :alpha, 1, 'B'],
|
81
|
+
[:name, :alpha, 35],
|
82
|
+
],
|
83
|
+
:payment_city =>[
|
84
|
+
[:record_code, :numeric, 4, 173],
|
85
|
+
[:record_variant, :alpha, 1, 'B'],
|
86
|
+
[:city, :alpha, 35],
|
87
|
+
],
|
88
|
+
}
|
89
|
+
|
90
|
+
attr_accessor :definition, :data
|
91
|
+
|
92
|
+
def initialize record_type, record_data = {}
|
93
|
+
|
94
|
+
# load record definition
|
95
|
+
raise "Unknown record type" unless Clieop::Payment::Record::TYPE_DEFINITIONS[record_type.to_sym]
|
96
|
+
@definition = Clieop::Payment::Record::TYPE_DEFINITIONS[record_type.to_sym]
|
97
|
+
|
98
|
+
# set default values according to definition
|
99
|
+
@data = @definition.inject({}) { |memo, field| memo[field[0]] = field[3] if field[3] ; memo }
|
100
|
+
|
101
|
+
# set values for all the provided data
|
102
|
+
record_data.each { |field, value| @data[field] = value }
|
103
|
+
end
|
104
|
+
|
105
|
+
def to_clieop
|
106
|
+
line = ""
|
107
|
+
# format each field
|
108
|
+
@definition.each do |field, type, length, content|
|
109
|
+
fmt = '%'
|
110
|
+
fmt << (type == :numeric ? '0' : '-')
|
111
|
+
fmt << (length.to_s)
|
112
|
+
fmt << (type == :numeric ? 'd' : 's')
|
113
|
+
raw_data = (type == :numeric) ? @data[field].to_i : @data[field]
|
114
|
+
value = sprintf(fmt, raw_data)
|
115
|
+
line << (type == :numeric ? value[0 - length, length] : value[0, length])
|
116
|
+
end
|
117
|
+
# fill each line with spaces up to 50 characters and close with a CR/LF
|
118
|
+
line.ljust(50) + LINE_SEPARATOR
|
119
|
+
end
|
120
|
+
|
121
|
+
alias_method :to_s, :to_clieop
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Clieop
|
2
|
+
module ProcessInfo
|
3
|
+
|
4
|
+
class Batch
|
5
|
+
|
6
|
+
attr_accessor :info, :transactions
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
self.transactions = []
|
10
|
+
self.info = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_record record, current_transaction = nil
|
14
|
+
if [:batch_header, :batch_info, :batch_footer].include?(record.type)
|
15
|
+
info.merge!(record.data.except(:record_code, :filler))
|
16
|
+
elsif current_transaction
|
17
|
+
if record == current_transaction.record
|
18
|
+
transactions << current_transaction
|
19
|
+
else
|
20
|
+
current_transaction.add_record(record)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Clieop
|
2
|
+
module ProcessInfo
|
3
|
+
|
4
|
+
# Reads VERWINFO 4.1 process info, see record.rb for details
|
5
|
+
class File
|
6
|
+
|
7
|
+
attr_accessor :records, :batches, :info
|
8
|
+
|
9
|
+
def initialize(verwinfo_string, whiny_mode = false)
|
10
|
+
self.records = verwinfo_string.split(Clieop::ProcessInfo::Record::LINE_SEPARATOR).map do |record_line|
|
11
|
+
unless record_line.size < 3 # No record code available
|
12
|
+
begin
|
13
|
+
Clieop::ProcessInfo::Record.new(record_line)
|
14
|
+
rescue Exception => e
|
15
|
+
whiny_mode ? raise(e) : nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end.compact
|
19
|
+
|
20
|
+
raise 'No valid records found in VERWINFO data' unless @records.any?
|
21
|
+
|
22
|
+
self.batches = []
|
23
|
+
self.info = records.first.data.merge(records.last.data).except(:record_code, :filler) # Get file header and footer
|
24
|
+
|
25
|
+
current_batch = nil; current_transaction = nil
|
26
|
+
records.each do |record|
|
27
|
+
case record.type
|
28
|
+
when :batch_header
|
29
|
+
current_batch = Clieop::ProcessInfo::Batch.new
|
30
|
+
current_transaction = nil
|
31
|
+
batches << current_batch
|
32
|
+
when :transaction_info, :changed_account_info
|
33
|
+
current_transaction = Clieop::ProcessInfo::Transaction.new(record)
|
34
|
+
end
|
35
|
+
|
36
|
+
current_batch.add_record(record, current_transaction) if current_batch
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.from_file(verwinfo_file, whiny_mode = false)
|
41
|
+
verwinfo_file = File.open(verwinfo_file) if verwinfo_file.is_a?(String)
|
42
|
+
self.from_string(verwinfo_file.read, whiny_mode)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.from_string(verwinfo_string, whiny_mode = false)
|
46
|
+
self.new(verwinfo_string, whiny_mode)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'bigdecimal'
|
3
|
+
|
4
|
+
module Clieop
|
5
|
+
module ProcessInfo
|
6
|
+
|
7
|
+
# Reads VERWINFO 4.1 process info
|
8
|
+
# Docs: http://www.equens.com/Images/VERWINFO%20NL%204.1_11-2009.pdf
|
9
|
+
class Record
|
10
|
+
|
11
|
+
attr_accessor :type, :raw_line, :definition, :data
|
12
|
+
|
13
|
+
LINE_SEPARATOR = "\r\n"
|
14
|
+
|
15
|
+
TYPE_DEFINITIONS = {
|
16
|
+
:file_header => [
|
17
|
+
[:record_code, :numeric, 3, 10],
|
18
|
+
[:filename, :alpha, 8, 'VERWINFO'],
|
19
|
+
[:filler, :alpha, 1, 'A'],
|
20
|
+
[:file_version, :alpha, 3, '4.1'],
|
21
|
+
[:date, :date, 6],
|
22
|
+
[:run_number, :numeric, 4],
|
23
|
+
[:account_nr, :numeric, 10],
|
24
|
+
[:serial_nr, :numeric, 4],
|
25
|
+
[:file_nr, :numeric, 2]
|
26
|
+
],
|
27
|
+
:file_footer => [
|
28
|
+
[:record_code, :numeric, 3, 990],
|
29
|
+
[:batches_count, :numeric, 6],
|
30
|
+
[:next_file_nr, :numeric, 2]
|
31
|
+
],
|
32
|
+
:batch_header => [
|
33
|
+
[:record_code, :numeric, 3, 50],
|
34
|
+
[:account_nr, :numeric, 10],
|
35
|
+
[:filler, :alpha, 3],
|
36
|
+
[:total_amount, :amount, 18],
|
37
|
+
[:transaction_count, :numeric, 7],
|
38
|
+
[:test_code, :alpha, 1], # P(roduction), T(est)
|
39
|
+
[:batch_type, :alpha, 1],
|
40
|
+
[:period_type, :alpha, 1],
|
41
|
+
[:period_length, :numeric, 2],
|
42
|
+
[:period_nr, :numeric, 3]
|
43
|
+
],
|
44
|
+
:batch_info => [
|
45
|
+
[:record_code, :numeric, 3, 51],
|
46
|
+
[:currency, :alpha, 3],
|
47
|
+
[:batch_identifier, :alpha, 16]
|
48
|
+
],
|
49
|
+
:batch_footer => [
|
50
|
+
[:record_code, :numeric, 3, 950],
|
51
|
+
[:total_rejected, :numeric, 7],
|
52
|
+
[:total_reversed, :numeric, 7],
|
53
|
+
[:transaction_count, :numeric, 7],
|
54
|
+
[:total_amount, :amount, 18]
|
55
|
+
],
|
56
|
+
:transaction_info => [
|
57
|
+
[:record_code, :numeric, 3, 100],
|
58
|
+
[:amount, :amount, 13],
|
59
|
+
[:from_account, :numeric, 10],
|
60
|
+
[:to_account, :numeric, 10],
|
61
|
+
[:entry_account, :numeric, 10],
|
62
|
+
|
63
|
+
# from_account_verification_nr - Controlecijfer rekeningnummer betaler
|
64
|
+
# 0 – 9 als Rekeningnummer betaler een rekeningnummer met maximaal 7 cijfers bevat
|
65
|
+
# spatie als Rekeningnummer betaler een gewoon rekeningnummer bevat
|
66
|
+
[:from_account_verification_nr, :numeric, 1],
|
67
|
+
|
68
|
+
# transaction_reference_ok - Betalingskenmerkgoed
|
69
|
+
# J controlecijfer juist
|
70
|
+
# N controlecijfer onjuist
|
71
|
+
# spatie geen controlecijfer aanwezig
|
72
|
+
[:transaction_reference_ok, :alpha, 1]
|
73
|
+
],
|
74
|
+
:euro_record => [
|
75
|
+
[:record_code, :numeric, 3, 101],
|
76
|
+
[:currency, :alpha, 3],
|
77
|
+
[:amount_nlg, :amount, 13],
|
78
|
+
[:amount_eur, :amount, 13]
|
79
|
+
],
|
80
|
+
:reverse_info => [
|
81
|
+
[:record_code, :numeric, 3, 105],
|
82
|
+
[:transaction_reference, :alpha, 16],
|
83
|
+
[:inquiry_identifier, :alpha, 19],
|
84
|
+
|
85
|
+
# reason - Redenstorno Signaalcode Signaaltekst
|
86
|
+
#
|
87
|
+
# 01 0010 Administratieve reden
|
88
|
+
# 02 0011 Rekeningnummer vervallen
|
89
|
+
# 03 0001 Rekeningnummer onbekend
|
90
|
+
# 05 0012 Geen incassomachtiging verstrekt
|
91
|
+
# 06 0013 Niet akkoord met afschrijving
|
92
|
+
# 07 0014 Dubbel betaald
|
93
|
+
# 08 0005 Naam/nummer stemmen niet overeen
|
94
|
+
# 09 0007 Rekeningnummer geblokkeerd
|
95
|
+
# 10 0008 Selektieve incasso blokkade
|
96
|
+
# 11 0009 Rekeningnummer WKA
|
97
|
+
[:reason, :numeric, 2],
|
98
|
+
|
99
|
+
[:original_to_account, :numeric, 10]
|
100
|
+
],
|
101
|
+
:transaction_description => [
|
102
|
+
[:record_code, :numeric, 3, 110],
|
103
|
+
[:description, :alpha, 32]
|
104
|
+
],
|
105
|
+
:bank_info => [
|
106
|
+
[:record_code, :numeric, 3, 115],
|
107
|
+
[:description, :alpha, 30]
|
108
|
+
],
|
109
|
+
:settle_info => [
|
110
|
+
[:record_code, :numeric, 3, 500],
|
111
|
+
|
112
|
+
# status - Poststatus
|
113
|
+
# 00 niet van toepassing (Batchsoorten B en C)
|
114
|
+
# 01 geweigerde post
|
115
|
+
# 02 teruggebogen post
|
116
|
+
[:status, :numeric, 2],
|
117
|
+
|
118
|
+
[:original_settle_date, :date, 6],
|
119
|
+
[:filler, :alpha, 14],
|
120
|
+
[:run_nr, :numeric, 4],
|
121
|
+
[:settle_date, :date, 6],
|
122
|
+
|
123
|
+
# transaction_type - Transactiesoort
|
124
|
+
# 0000 crediteuren betalingen
|
125
|
+
# 0001 door bank geconverteerde opdrachten
|
126
|
+
# 0002 periodieke overboekingen
|
127
|
+
# 0003 salarissen
|
128
|
+
# 0006 iDEAL internet betalingen
|
129
|
+
# 0009 Digitale Nota betalingen
|
130
|
+
# 0092 EBALink betaling
|
131
|
+
# 0220 doorlopende machtiging algemeen
|
132
|
+
# 0221 eenmalige machtiging
|
133
|
+
# 0222 doorlopende machtiging bedrijven
|
134
|
+
# 0223 doorlopende machtiging kansspelen
|
135
|
+
# 0227 doorlopende machtiging bedrijven zonder terugboekingsrecht debiteur
|
136
|
+
# 0228 doorlopende telefonische machtiging
|
137
|
+
# 0229 eenmalige telefonische machtiging
|
138
|
+
# 0284 doorlopende telefonische machtiging kansspelen
|
139
|
+
# 0285 overheidsvordering
|
140
|
+
# 0330 terugboeking op doorlopende machtiging algemeen
|
141
|
+
# 0331 terugboeking op eenmalige machtiging
|
142
|
+
# 0332 terugboeking op doorlopende machtiging bedrijven
|
143
|
+
# 0333 terugboeking op doorlopende machtiging kansspelen
|
144
|
+
# 0337 terugboeking op doorlopende machtiging bedrijven zonder terugboekingsrecht debiteur
|
145
|
+
# 0338 terugboeking op doorlopende telefonische machtiging
|
146
|
+
# 0339 terugboeking op eenmalige telefonische machtiging
|
147
|
+
# 0394 terugboeking op doorlopende telefonische machtiging kansspelen
|
148
|
+
# 0395 terugboeking op Overheidsvordering
|
149
|
+
# 1010 betaalautomaat transactie
|
150
|
+
# 1144 acceptgiro zonder bedrag in coderegel
|
151
|
+
# 1145 acceptgiro met bedrag in coderegel
|
152
|
+
[:transaction_type, :numeric, 4]
|
153
|
+
],
|
154
|
+
:changed_account_info => [
|
155
|
+
[:record_code, :numeric, 3, 503],
|
156
|
+
[:account_nr, :numeric, 10],
|
157
|
+
[:original_account_nr, :numeric, 10]
|
158
|
+
],
|
159
|
+
:name_info => [
|
160
|
+
[:record_code, :numeric, 3, 505],
|
161
|
+
[:name, :alpha, 35]
|
162
|
+
],
|
163
|
+
:street_info => [
|
164
|
+
[:record_code, :numeric, 3, 510],
|
165
|
+
[:street, :alpha, 35]
|
166
|
+
],
|
167
|
+
:city_info => [
|
168
|
+
[:record_code, :numeric, 3, 515],
|
169
|
+
[:city, :alpha, 35]
|
170
|
+
],
|
171
|
+
|
172
|
+
# See 'Bijlage 1'
|
173
|
+
:reject_info => [
|
174
|
+
[:record_code, :numeric, 3, 600],
|
175
|
+
[:code, :numeric, 4],
|
176
|
+
[:description, :alpha, 32]
|
177
|
+
]
|
178
|
+
}
|
179
|
+
|
180
|
+
TYPE_FOR_RECORD_CODE = TYPE_DEFINITIONS.inject({}){|m, (k,v)| m[v.first.last] = k; m }
|
181
|
+
|
182
|
+
def initialize record_line
|
183
|
+
self.raw_line = record_line
|
184
|
+
self.type = TYPE_FOR_RECORD_CODE[raw_line[0,3].to_i]
|
185
|
+
self.data = {}
|
186
|
+
self.definition = TYPE_DEFINITIONS[type]
|
187
|
+
|
188
|
+
skip = 0
|
189
|
+
definition.each do |attribute_definition|
|
190
|
+
# Get the right substring
|
191
|
+
attribute_line = raw_line[skip, attribute_definition[2]]
|
192
|
+
# Parse the attribute
|
193
|
+
data[attribute_definition[0]] = attribute_line.to_s.present? ? self.class.send("parse_#{attribute_definition[1]}_value", attribute_line) : nil
|
194
|
+
# Update the skip
|
195
|
+
skip += attribute_definition[2]
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
private
|
200
|
+
|
201
|
+
def self.parse_alpha_value attribute_line
|
202
|
+
attribute_line.strip
|
203
|
+
end
|
204
|
+
|
205
|
+
def self.parse_numeric_value attribute_line
|
206
|
+
attribute_line.to_i
|
207
|
+
end
|
208
|
+
|
209
|
+
def self.parse_amount_value attribute_line
|
210
|
+
(BigDecimal(attribute_line) / 100).round(2)
|
211
|
+
end
|
212
|
+
|
213
|
+
# Format: jjmmdd
|
214
|
+
def self.parse_date_value attribute_line
|
215
|
+
Time.parse(attribute_line).send(:to_date)
|
216
|
+
end
|
217
|
+
|
218
|
+
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Clieop
|
2
|
+
module ProcessInfo
|
3
|
+
|
4
|
+
class Transaction
|
5
|
+
|
6
|
+
attr_accessor :info, :descriptions, :record
|
7
|
+
|
8
|
+
def initialize(record)
|
9
|
+
self.record = record
|
10
|
+
self.info = record.data.except(:record_code)
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_record record
|
14
|
+
unless record.type == :transaction_description
|
15
|
+
info[record.type] = record.data.except(:record_code, :filler)
|
16
|
+
else
|
17
|
+
info[:transaction_descriptions] ||= []
|
18
|
+
info[:transaction_descriptions] << record.data[:description]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|