decodar 2.3.0.pre

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,167 @@
1
+ Copyright (C) 2012 Thibault Poncelet <thibaultponcelet@gmail.com>
2
+
3
+ GNU LESSER GENERAL PUBLIC LICENSE
4
+ Version 3, 29 June 2007
5
+
6
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
7
+ Everyone is permitted to copy and distribute verbatim copies
8
+ of this license document, but changing it is not allowed.
9
+
10
+
11
+ This version of the GNU Lesser General Public License incorporates
12
+ the terms and conditions of version 3 of the GNU General Public
13
+ License, supplemented by the additional permissions listed below.
14
+
15
+ 0. Additional Definitions.
16
+
17
+ As used herein, "this License" refers to version 3 of the GNU Lesser
18
+ General Public License, and the "GNU GPL" refers to version 3 of the GNU
19
+ General Public License.
20
+
21
+ "The Library" refers to a covered work governed by this License,
22
+ other than an Application or a Combined Work as defined below.
23
+
24
+ An "Application" is any work that makes use of an interface provided
25
+ by the Library, but which is not otherwise based on the Library.
26
+ Defining a subclass of a class defined by the Library is deemed a mode
27
+ of using an interface provided by the Library.
28
+
29
+ A "Combined Work" is a work produced by combining or linking an
30
+ Application with the Library. The particular version of the Library
31
+ with which the Combined Work was made is also called the "Linked
32
+ Version".
33
+
34
+ The "Minimal Corresponding Source" for a Combined Work means the
35
+ Corresponding Source for the Combined Work, excluding any source code
36
+ for portions of the Combined Work that, considered in isolation, are
37
+ based on the Application, and not on the Linked Version.
38
+
39
+ The "Corresponding Application Code" for a Combined Work means the
40
+ object code and/or source code for the Application, including any data
41
+ and utility programs needed for reproducing the Combined Work from the
42
+ Application, but excluding the System Libraries of the Combined Work.
43
+
44
+ 1. Exception to Section 3 of the GNU GPL.
45
+
46
+ You may convey a covered work under sections 3 and 4 of this License
47
+ without being bound by section 3 of the GNU GPL.
48
+
49
+ 2. Conveying Modified Versions.
50
+
51
+ If you modify a copy of the Library, and, in your modifications, a
52
+ facility refers to a function or data to be supplied by an Application
53
+ that uses the facility (other than as an argument passed when the
54
+ facility is invoked), then you may convey a copy of the modified
55
+ version:
56
+
57
+ a) under this License, provided that you make a good faith effort to
58
+ ensure that, in the event an Application does not supply the
59
+ function or data, the facility still operates, and performs
60
+ whatever part of its purpose remains meaningful, or
61
+
62
+ b) under the GNU GPL, with none of the additional permissions of
63
+ this License applicable to that copy.
64
+
65
+ 3. Object Code Incorporating Material from Library Header Files.
66
+
67
+ The object code form of an Application may incorporate material from
68
+ a header file that is part of the Library. You may convey such object
69
+ code under terms of your choice, provided that, if the incorporated
70
+ material is not limited to numerical parameters, data structure
71
+ layouts and accessors, or small macros, inline functions and templates
72
+ (ten or fewer lines in length), you do both of the following:
73
+
74
+ a) Give prominent notice with each copy of the object code that the
75
+ Library is used in it and that the Library and its use are
76
+ covered by this License.
77
+
78
+ b) Accompany the object code with a copy of the GNU GPL and this license
79
+ document.
80
+
81
+ 4. Combined Works.
82
+
83
+ You may convey a Combined Work under terms of your choice that,
84
+ taken together, effectively do not restrict modification of the
85
+ portions of the Library contained in the Combined Work and reverse
86
+ engineering for debugging such modifications, if you also do each of
87
+ the following:
88
+
89
+ a) Give prominent notice with each copy of the Combined Work that
90
+ the Library is used in it and that the Library and its use are
91
+ covered by this License.
92
+
93
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
94
+ document.
95
+
96
+ c) For a Combined Work that displays copyright notices during
97
+ execution, include the copyright notice for the Library among
98
+ these notices, as well as a reference directing the user to the
99
+ copies of the GNU GPL and this license document.
100
+
101
+ d) Do one of the following:
102
+
103
+ 0) Convey the Minimal Corresponding Source under the terms of this
104
+ License, and the Corresponding Application Code in a form
105
+ suitable for, and under terms that permit, the user to
106
+ recombine or relink the Application with a modified version of
107
+ the Linked Version to produce a modified Combined Work, in the
108
+ manner specified by section 6 of the GNU GPL for conveying
109
+ Corresponding Source.
110
+
111
+ 1) Use a suitable shared library mechanism for linking with the
112
+ Library. A suitable mechanism is one that (a) uses at run time
113
+ a copy of the Library already present on the user's computer
114
+ system, and (b) will operate properly with a modified version
115
+ of the Library that is interface-compatible with the Linked
116
+ Version.
117
+
118
+ e) Provide Installation Information, but only if you would otherwise
119
+ be required to provide such information under section 6 of the
120
+ GNU GPL, and only to the extent that such information is
121
+ necessary to install and execute a modified version of the
122
+ Combined Work produced by recombining or relinking the
123
+ Application with a modified version of the Linked Version. (If
124
+ you use option 4d0, the Installation Information must accompany
125
+ the Minimal Corresponding Source and Corresponding Application
126
+ Code. If you use option 4d1, you must provide the Installation
127
+ Information in the manner specified by section 6 of the GNU GPL
128
+ for conveying Corresponding Source.)
129
+
130
+ 5. Combined Libraries.
131
+
132
+ You may place library facilities that are a work based on the
133
+ Library side by side in a single library together with other library
134
+ facilities that are not Applications and are not covered by this
135
+ License, and convey such a combined library under terms of your
136
+ choice, if you do both of the following:
137
+
138
+ a) Accompany the combined library with a copy of the same work based
139
+ on the Library, uncombined with any other library facilities,
140
+ conveyed under the terms of this License.
141
+
142
+ b) Give prominent notice with the combined library that part of it
143
+ is a work based on the Library, and explaining where to find the
144
+ accompanying uncombined form of the same work.
145
+
146
+ 6. Revised Versions of the GNU Lesser General Public License.
147
+
148
+ The Free Software Foundation may publish revised and/or new versions
149
+ of the GNU Lesser General Public License from time to time. Such new
150
+ versions will be similar in spirit to the present version, but may
151
+ differ in detail to address new problems or concerns.
152
+
153
+ Each version is given a distinguishing version number. If the
154
+ Library as you received it specifies that a certain numbered version
155
+ of the GNU Lesser General Public License "or any later version"
156
+ applies to it, you have the option of following the terms and
157
+ conditions either of that published version or of any later version
158
+ published by the Free Software Foundation. If the Library as you
159
+ received it does not specify a version number of the GNU Lesser
160
+ General Public License, you may choose any version of the GNU Lesser
161
+ General Public License ever published by the Free Software Foundation.
162
+
163
+ If the Library as you received it specifies that a proxy can decide
164
+ whether future versions of the GNU Lesser General Public License shall
165
+ apply, that proxy's public statement of acceptance of any version is
166
+ permanent authorization for you to choose that version for the
167
+ Library.
@@ -0,0 +1,25 @@
1
+ Decodar [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/thibaultponcelet/decodar)
2
+ =======
3
+
4
+ Coded statement of account (CODA) Wrapper Library
5
+
6
+ Please refer to http://www.febelfin.be/sites/default/files/Payments/Standard-CODA-23-EN.pdf for the standard definition.
7
+
8
+ ##Install
9
+
10
+ Install it on your system:
11
+
12
+ gem install decodar
13
+
14
+ ## Contributions
15
+
16
+ If you want to contribute, please open an issue or:
17
+
18
+ * Fork the project.
19
+ * Make your feature addition or bug fix, alongside the matching new tests.
20
+ * Send a pull request on Github with a clear description.
21
+
22
+ ## Copyright
23
+
24
+ Copyright 2012 Thibault Poncelet - See LICENCE for details.
25
+
@@ -0,0 +1,5 @@
1
+ desc "Run tests"
2
+ task :default => :spec
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new('spec')
@@ -0,0 +1,45 @@
1
+ require "date"
2
+ require "singleton"
3
+ require 'bigdecimal'
4
+
5
+ # Version
6
+ require_relative "./decodar/version.rb"
7
+
8
+ #Error
9
+ require_relative "./decodar/error.rb"
10
+
11
+
12
+
13
+ # File
14
+ require_relative "./decodar/file.rb"
15
+
16
+ # Transaction
17
+ require_relative "./decodar/transaction.rb"
18
+
19
+ # Parser
20
+ require_relative "./decodar/parser/parser.rb"
21
+
22
+ # Lexer
23
+ require_relative "./decodar/lexer/lexer.rb"
24
+
25
+ # Helpers
26
+ require_relative "./decodar/lexer/helpers/amount.rb"
27
+ require_relative "./decodar/lexer/helpers/link.rb"
28
+ require_relative "./decodar/lexer/helpers/currency.rb"
29
+
30
+ # Code specification
31
+ require_relative "./decodar/lexer/code_specification.rb"
32
+
33
+ # Records
34
+ require_relative "./decodar/lexer/records/base.rb"
35
+ require_relative "./decodar/lexer/records/header.rb"
36
+ require_relative "./decodar/lexer/records/old_balance.rb"
37
+ require_relative "./decodar/lexer/records/movement1.rb"
38
+ require_relative "./decodar/lexer/records/movement2.rb"
39
+ require_relative "./decodar/lexer/records/movement3.rb"
40
+ require_relative "./decodar/lexer/records/information1.rb"
41
+ require_relative "./decodar/lexer/records/information2.rb"
42
+ require_relative "./decodar/lexer/records/information3.rb"
43
+ require_relative "./decodar/lexer/records/new_balance.rb"
44
+ require_relative "./decodar/lexer/records/free_communications.rb"
45
+ require_relative "./decodar/lexer/records/trailer.rb"
@@ -0,0 +1,13 @@
1
+ module Decodar
2
+ class Error < StandardError
3
+ UNEXPECTED_BLANK_RECORD = "The record contains an unexpect blank code"
4
+ UNKNOWN_ACCOUNT_TYPE = "Unknown account type"
5
+ INVALID_DATE = "Invalid date"
6
+ INVALID_TYPE = "Invalid type specified"
7
+ VERSION_MISMATCH = "This file does not use the appropriate CODA version:"
8
+
9
+ def initialize(message, *args)
10
+ super("#{message}: #{args.join(" ")}")
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,57 @@
1
+ module Decodar
2
+ class File
3
+ def initialize
4
+ @records = []
5
+ end
6
+
7
+ def add_record(record)
8
+ if record.is_a?(Decodar::Record::Header)
9
+ @header = record
10
+ elsif record.is_a?(Decodar::Record::OldBalance)
11
+ @old_balance = record
12
+ elsif record.is_a?(Decodar::Record::NewBalance)
13
+ @new_balance = record
14
+ elsif record.is_a?(Decodar::Record::Trailer)
15
+ @trailer = record
16
+ else
17
+ store_transaction(record)
18
+ end
19
+ end
20
+
21
+ def creation_date
22
+ @header.creation_date
23
+ end
24
+
25
+ def transactions
26
+ @transactions ||= extract_transactions
27
+ end
28
+
29
+ def old_balance
30
+ @old_balance.signed_amount
31
+ end
32
+
33
+ def new_balance
34
+ @new_balance.signed_amount
35
+ end
36
+
37
+ def duplicate?
38
+ @header.duplicate?
39
+ end
40
+
41
+ def reference
42
+ @header.file_reference.to_i
43
+ end
44
+
45
+ def holder_id
46
+ @header.holder_id.to_i
47
+ end
48
+
49
+ private
50
+ def store_transactions(record)
51
+ if @current_transaction.nil?
52
+ @current_transaction = Decodar::Transaction.new
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,57 @@
1
+ module Decodar
2
+ class CodeSpecification
3
+ attr_accessor :record_type, :name, :position, :type, :allow_blank
4
+
5
+ def initialize(record_type, name, position, type, allow_blank)
6
+ @record_type = record_type
7
+ @name = name
8
+ @position = position
9
+ @type = type
10
+ @allow_blank = allow_blank
11
+ end
12
+
13
+ def extract_formatted_code(raw_record)
14
+ raw_code = raw_record[position]
15
+ cast(raw_code)
16
+ end
17
+
18
+ private
19
+ def cast(raw_code)
20
+ if !allow_blank && raw_code.strip == ""
21
+ raise Error.new(Error::UNEXPECTED_BLANK_RECORD, "#{record_type}##{name} at #{position}")
22
+ end
23
+
24
+ if type == :integer
25
+ format_integer(raw_code)
26
+ elsif type == :string
27
+ format_string(raw_code)
28
+ elsif type == :decimal
29
+ format_decimal(raw_code)
30
+ elsif type == :date
31
+ format_date(raw_code)
32
+ else
33
+ raise Error.new(Error::INVALID_TYPE, "#{record_type}##{name}: #{type}")
34
+ end
35
+ end
36
+
37
+ def format_integer(raw_code)
38
+ raw_code.to_i
39
+ end
40
+
41
+ def format_string(raw_code)
42
+ raw_code.strip
43
+ end
44
+
45
+ def format_decimal(raw_code)
46
+ BigDecimal.new("#{raw_code[0..11]}.#{raw_code[12..14].to_i * 0.001}")
47
+ end
48
+
49
+ def format_date(raw_code)
50
+ begin
51
+ Date.strptime(raw_code, "%d%m%y")
52
+ rescue
53
+ raise Error.new(Error::INVALID_DATE, "#{record_type}##{name}: #{raw_code}")
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,18 @@
1
+ module Decodar
2
+ module Helper
3
+ module Amount
4
+ # This module assumes that the class including it defines a sign and a amount code
5
+ def credit?
6
+ sign == 0
7
+ end
8
+
9
+ def debit?
10
+ !credit?
11
+ end
12
+
13
+ def signed_amount
14
+ credit? ? amount : -amount
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ module Decodar
2
+ module Helper
3
+ module Currency
4
+ def extract_currency(target)
5
+ target[target.size-3..target.size]
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ module Decodar
2
+ module Helper
3
+ module Link
4
+ # This module assumes that the class including it defines a link code
5
+ def linked?
6
+ link_code == 1
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,117 @@
1
+ module Decodar
2
+ class Lexer
3
+ include Singleton
4
+
5
+ def register_record(record_class)
6
+ if record_class.article_identifier
7
+ @records[record_class.identifier.to_s] ||= {}
8
+ @records[record_class.identifier.to_s][record_class.article_identifier.to_s] = record_class
9
+ else
10
+ @records[record_class.identifier.to_s] = record_class
11
+ end
12
+ end
13
+
14
+ def analyze(filepath)
15
+ lines = ::File.readlines(filepath)
16
+ check_version(lines)
17
+ lines.map! do |line|
18
+ code = line[0]
19
+ klass = @records[code]
20
+ if klass.is_a? Hash
21
+ article = line[1]
22
+ klass = @records[code][article]
23
+ end
24
+ result = klass.new(line)
25
+ # puts "_"*128
26
+ # puts
27
+ # puts (" "*50) + klass.name
28
+ # puts "_"*128
29
+ # puts line
30
+ # puts "="*128
31
+ # puts result
32
+ result
33
+ end
34
+ end
35
+
36
+ private
37
+ def initialize
38
+ @records = {}
39
+ end
40
+
41
+ def check_version(lines)
42
+ file_version = lines.first[127]
43
+ gem_version = VERSION[0]
44
+ if file_version != gem_version
45
+ raise Error.new(Error::VERSION_MISMATCH, file_version, "instead of", gem_version)
46
+ end
47
+ end
48
+ # Records:
49
+ # ====
50
+ #
51
+ # 0: Header
52
+ # 1: Old balance
53
+ # 2: Movement
54
+ # 3: Additional infos (on preceding record 2)
55
+ # (4): Free communication
56
+ # 8: New balance
57
+ # 9: Trailer record
58
+ #
59
+ # Empty file: record 0 (header), 1 (old_balance), 9 (trailer)
60
+ #
61
+ # Transactions
62
+ # ====
63
+ #
64
+ # Each transaction get its own code:
65
+ # +-------------+---------------+----------------+---------------------+
66
+ # + 1st + 2nd + 3rd + 4th + 5th + 6th + 7th + 8th +
67
+ # +=============+===============+================+=====================+
68
+ # | record type | family | transaction | category |
69
+ # +-------------+---------------+----------------+---------------------+
70
+ #
71
+ # Type
72
+ # ---
73
+ # |0| | | Simple amount without details
74
+ # |1| | | Amount totalised by the customer
75
+ # | |5| | Detail of 1
76
+ # |2| | | Amount totalised by the bank
77
+ # | |6| | Detail of 2, simple amount without detailed data
78
+ # | |7| | Detail of 2, simple amount with detailed data
79
+ # | | |9| Detail of 7,
80
+ # |3| | | Simple amount with detailed data
81
+ # | |8| | Detail of 2
82
+ #
83
+ # Family
84
+ # ---
85
+ # Broad division a transaction belongs to
86
+ #
87
+ # Transaction
88
+ # ---
89
+ # Identify a transaction within a family, for each family, there are a number of
90
+ # debit/credit transaction code
91
+ #
92
+ # Category
93
+ # ---
94
+ # Additional info about the nature of the transaction, clearly distinguishes
95
+ # the different item relating a single transaction
96
+ #
97
+ # Note: For unclassified transaction, the 39 or 89 code should be given into the
98
+ # 30 family
99
+ # In each family, 40-48 & 90-98 are reserved for transaction proper to each bank
100
+ # 49 & 99 identify corrections and cancellation entries
101
+ #
102
+ # Structured communications
103
+ # ---
104
+ # May occur in record 2 (movement) or in record 3 (information)
105
+ # Communication format zone indicate wether it is free (0) or structured (1)
106
+ # When structured: A three position code indicate the type of communication
107
+ #
108
+ # Other code
109
+ # ---
110
+ # Separate application: Specify the content of the file agreed with the customer
111
+ # Version code: Specify the version of the standard
112
+ # Multiple file code: It is possible to record multiple file on one physical file
113
+ # 1: Another file is next
114
+ # 2: Last file
115
+
116
+ end
117
+ end
@@ -0,0 +1,54 @@
1
+ module Decodar
2
+ module Record
3
+ class Base
4
+ class << self
5
+ attr_accessor :specified_codes
6
+ attr_reader :identifier, :article_identifier
7
+ end
8
+
9
+ def self.inherited(base)
10
+ base.instance_eval do
11
+ @specified_codes = {}
12
+ end
13
+ end
14
+
15
+ def self.specify_code(name, position, type, allow_blank = false)
16
+ code_reader(name)
17
+ @specified_codes[name] = CodeSpecification.new(self.name, name, position, type, allow_blank)
18
+ end
19
+
20
+ def self.code_reader(name)
21
+ define_method(name) do
22
+ @codes[name]
23
+ end
24
+ end
25
+
26
+ def self.specify_identifier(identifier, article_identifier = nil)
27
+ @identifier = identifier
28
+ @article_identifier = article_identifier
29
+ Decodar::Lexer.instance.register_record(self)
30
+ end
31
+
32
+ def initialize(raw_record)
33
+ @codes = {}
34
+ @raw_record = raw_record
35
+ read
36
+ end
37
+
38
+ def to_s
39
+ result = ""
40
+ @codes.each do |k, v|
41
+ result << ":#{k} => #{v.inspect}\n"
42
+ end
43
+ result
44
+ end
45
+
46
+ private
47
+ def read
48
+ self.class.specified_codes.each do |name, specification|
49
+ @codes[name] = specification.extract_formatted_code(@raw_record)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,14 @@
1
+ module Decodar
2
+ module Record
3
+ class FreeCommunications < Base
4
+ include Helper::Link
5
+
6
+ specify_identifier 4
7
+
8
+ specify_code :sequence_number, 2..5, :integer
9
+ specify_code :detail_number, 6..9, :integer
10
+ specify_code :free_communication, 32..111, :string
11
+ specify_code :link_code, 127, :integer
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,24 @@
1
+ module Decodar
2
+ module Record
3
+ class Header < Base
4
+ specify_identifier 0
5
+
6
+ specify_code :creation_date , 5..10 , :date
7
+ specify_code :bank_id , 11..13 , :integer
8
+ specify_code :application , 14..15 , :integer
9
+ specify_code :duplicate_code , 16 , :string , true
10
+ specify_code :file_reference , 24..33 , :string , true
11
+ specify_code :name_addressee , 34..59 , :string
12
+ specify_code :bic , 60..70 , :string
13
+ specify_code :holder_id , 71..81 , :integer
14
+ specify_code :separate_application , 83..87 , :integer
15
+ specify_code :transaction_reference , 88..103 , :string , true
16
+ specify_code :related_reference , 104..119 , :string , true
17
+ specify_code :version , 127 , :integer
18
+
19
+ def duplicate?
20
+ duplicate_code == "D"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+
2
+ module Decodar
3
+ module Record
4
+ class Information1 < Base
5
+ include Helper::Link
6
+
7
+ specify_identifier 3, 1
8
+
9
+ specify_code :sequence_number, 2..5, :integer
10
+ specify_code :detail_number, 6..9, :integer
11
+ specify_code :reference_number, 10..30, :string
12
+ specify_code :transaction_code, 31..38, :integer
13
+ specify_code :communication_structure_code, 39, :integer
14
+ specify_code :communication, 40..112, :string
15
+ specify_code :next_code, 125, :integer
16
+ specify_code :link_code, 127, :integer
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ module Decodar
2
+ module Record
3
+ class Information2 < Base
4
+ include Helper::Link
5
+
6
+ specify_identifier 3, 2
7
+
8
+ specify_code :sequence_number, 2..5, :integer
9
+ specify_code :detail_number, 6..9, :integer
10
+ specify_code :ctd_communication, 10..114, :string
11
+ specify_code :next_code, 125, :integer
12
+ specify_code :link_code, 127, :integer
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ module Decodar
2
+ module Record
3
+ class Information3 < Base
4
+ include Helper::Link
5
+
6
+ specify_identifier 3, 3
7
+ specify_code :sequence_number, 2..5, :integer
8
+ specify_code :detail_number, 6..9, :integer
9
+ specify_code :ctd_communication, 10..99, :string
10
+ specify_code :next_code, 125, :integer
11
+ specify_code :link_code, 127, :integer
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,25 @@
1
+ module Decodar
2
+ module Record
3
+ class Movement1 < Base
4
+ include Helper::Amount
5
+ include Helper::Link
6
+
7
+ specify_identifier 2, 1
8
+
9
+ specify_code :sequence_number , 2..5 , :integer
10
+ specify_code :detail_number, 6..9, :integer
11
+ specify_code :bank_reference_number, 10..30, :string, true
12
+ specify_code :sign, 31, :integer
13
+ specify_code :amount, 32..46, :decimal
14
+ specify_code :value_date, 47..52, :date
15
+ specify_code :transaction_code, 53..60, :integer
16
+ specify_code :communication_type, 61, :integer
17
+ specify_code :raw_communication, 62..114, :string, true
18
+ specify_code :entry_date, 115..120, :date
19
+ specify_code :statement_sequence_number, 121..123, :integer
20
+ specify_code :globalisation_code, 124, :integer
21
+ specify_code :next_code, 125, :integer
22
+ specify_code :link_code, 127, :integer
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ module Decodar
2
+ module Record
3
+ class Movement2 < Base
4
+ include Helper::Link
5
+
6
+ specify_identifier 2, 2
7
+
8
+ specify_code :sequence_number, 2..5, :integer
9
+ specify_code :detail_number, 6..9, :integer
10
+ specify_code :ctd_communication, 10..62, :string, true
11
+ specify_code :customer_reference, 63..97, :string, true
12
+ specify_code :counterparty_bic, 98..108, :string, true
13
+ specify_code :category_purpose, 117..120, :string, true
14
+ specify_code :purpose, 121..124, :string,true
15
+ specify_code :next_code, 125, :integer
16
+ specify_code :link_code, 127, :integer
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ module Decodar
2
+ module Record
3
+ class Movement3 < Base
4
+ include Helper::Link
5
+ include Helper::Currency
6
+
7
+ specify_identifier 2, 3
8
+ specify_code :sequence_number, 2..5, :integer
9
+ specify_code :detail_number, 6..9, :integer
10
+ specify_code :counterparty_account_number_and_currency, 10..46, :string, true
11
+ specify_code :counterparty_name, 47..82, :string, true
12
+ specify_code :ctd_communication, 82..124, :string, true
13
+ specify_code :next_code, 125, :integer
14
+ specify_code :link_code, 127, :integer
15
+
16
+ def counterparty_currency
17
+ target = counterparty_account_number_and_currency
18
+ extract_currency(target)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ module Decodar
2
+ module Record
3
+ class NewBalance < Base
4
+ include Helper::Amount
5
+ include Helper::Link
6
+ include Helper::Currency
7
+
8
+ specify_identifier 8
9
+
10
+ specify_code :sequence_number, 1..3, :integer
11
+ specify_code :account_number_and_currency, 4..40, :string
12
+ specify_code :sign, 41, :integer
13
+ specify_code :amount, 42..56, :decimal
14
+ specify_code :date, 57..62, :date
15
+ specify_code :link_code, 127, :integer
16
+
17
+ def currency
18
+ target = account_number_and_currency
19
+ extract_currency(target)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,39 @@
1
+ module Decodar
2
+ module Record
3
+ class OldBalance < Base
4
+ include Helper::Amount
5
+ include Helper::Currency
6
+
7
+ specify_identifier 1
8
+
9
+ specify_code :account_structure_code , 1 , :integer
10
+ specify_code :account_sequence_number , 2..4 , :integer
11
+ specify_code :account_number_and_currency , 5..41 , :string
12
+ specify_code :sign , 42 , :integer
13
+ specify_code :amount , 43..57 , :decimal
14
+ specify_code :date , 58..63 , :date
15
+ specify_code :account_holder_name , 64..89 , :string
16
+ specify_code :account_description , 90..124 , :string , true
17
+ specify_code :movement_sequence_number , 125..128 , :integer
18
+
19
+ def account_structure # TODO How to model ?
20
+ if account_strucure_code == 0
21
+ :belgian
22
+ elsif account_strucure_code == 1
23
+ :foreign
24
+ elsif account_strucure_code == 2
25
+ :belgian_iban
26
+ elsif account_strucure_code == 3
27
+ :foreign_iban
28
+ else
29
+ raise Error.new(Error::UNKNOWN_ACCOUNT_TYPE, account_strucure_code)
30
+ end
31
+ end
32
+
33
+ def currency
34
+ target = account_number_and_currency
35
+ extract_currency(target)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,16 @@
1
+ module Decodar
2
+ module Record
3
+ class Trailer < Base
4
+ specify_identifier 9
5
+
6
+ specify_code :number_of_records, 16..21, :integer
7
+ specify_code :debit_movement, 22..36, :decimal
8
+ specify_code :credit_movement, 37..51, :decimal
9
+ specify_code :multiple_file_code, 127, :integer
10
+
11
+ def last_file?
12
+ multiple_file_code == 2
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ module Decodar
2
+ class Parser
3
+ attr_reader :files
4
+
5
+ def initialize(filepath)
6
+ @filepath = filepath
7
+ parse
8
+ end
9
+
10
+ private
11
+ def parse
12
+ @records = Decodar::Lexer.instance.analyze(@filepath)
13
+ @files = extract_files
14
+ end
15
+
16
+ def extract_files
17
+ files = []
18
+ file = Decodar::File.new
19
+ @records.each do |record|
20
+ file.add_record(record)
21
+ if record.is_a?(Decodar::Record::Trailer)
22
+ files.push(file)
23
+ file = Decodar::File.new
24
+ end
25
+ end
26
+ files
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,11 @@
1
+ module Decodar
2
+ module Transaction
3
+ def initialize
4
+ @records = []
5
+ end
6
+
7
+ def add_record(record)
8
+ @records.push(record)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module Decodar
2
+ VERSION = "2.3.0.pre"
3
+ end
@@ -0,0 +1,6 @@
1
+ require 'rspec'
2
+
3
+ RSpec.configure do |config|
4
+ config.color_enabled = true
5
+ config.formatter = 'progress'
6
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: decodar
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.3.0.pre
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - Thibault Poncelet
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.11.0
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 2.11.0
30
+ description: A Coded statement of account (CODA) Wrapper Library
31
+ email: thibaultponcelet@gmail.com
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - lib/decodar/error.rb
37
+ - lib/decodar/file.rb
38
+ - lib/decodar/lexer/code_specification.rb
39
+ - lib/decodar/lexer/helpers/amount.rb
40
+ - lib/decodar/lexer/helpers/currency.rb
41
+ - lib/decodar/lexer/helpers/link.rb
42
+ - lib/decodar/lexer/lexer.rb
43
+ - lib/decodar/lexer/records/base.rb
44
+ - lib/decodar/lexer/records/free_communications.rb
45
+ - lib/decodar/lexer/records/header.rb
46
+ - lib/decodar/lexer/records/information1.rb
47
+ - lib/decodar/lexer/records/information2.rb
48
+ - lib/decodar/lexer/records/information3.rb
49
+ - lib/decodar/lexer/records/movement1.rb
50
+ - lib/decodar/lexer/records/movement2.rb
51
+ - lib/decodar/lexer/records/movement3.rb
52
+ - lib/decodar/lexer/records/new_balance.rb
53
+ - lib/decodar/lexer/records/old_balance.rb
54
+ - lib/decodar/lexer/records/trailer.rb
55
+ - lib/decodar/parser/parser.rb
56
+ - lib/decodar/transaction.rb
57
+ - lib/decodar/version.rb
58
+ - lib/decodar.rb
59
+ - LICENSE
60
+ - Rakefile
61
+ - README.md
62
+ - spec/spec_helper.rb
63
+ homepage: https://github.com/thibaultponcelet/decodar
64
+ licenses: []
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: 1.9.2
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>'
79
+ - !ruby/object:Gem::Version
80
+ version: 1.3.1
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 1.8.24
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: A CODA Wrapper Library
87
+ test_files:
88
+ - spec/spec_helper.rb