aba 0.3.1 → 0.4.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: 035b4d53937aa04c7e72ef453991925a744533eb
4
- data.tar.gz: 3f80ba614237f025a5a269ae2f7485ad6805ac6c
3
+ metadata.gz: f11f3830479ca1fad3b854bb9459f99ce7dc8f5a
4
+ data.tar.gz: f793d6648ffc17e7589b2c5db57b26f548c5800e
5
5
  SHA512:
6
- metadata.gz: db7069fdba989915c2abfe634991af7443d3f24cbdd1b95bd1f4001118e7f369b2f4cd0cdcf3ca8833f0801e42beeaf4cf639c18c0efc3ee47dc0010ce72de27
7
- data.tar.gz: c9591d89dfe8f8c9177debc5791603f4ef923e2c48176887b98e4e040ed6d125ea294af654b367e61b03b487bed2d571e4118e8c4759c718f546bf6d33b5e767
6
+ metadata.gz: b350430aa9ee2c21cfa6d239c6871fcb3626f724dbd67d5cc5d58dac4d627c16b1e2873d1d4c4e9e80e0ca11acec6a5dfede5bae8b8184fcd8ab182ced99e7d9
7
+ data.tar.gz: 356d63f3de331b90a69fc8d586690eb793fa606c8544f4bfc481a8a055ee96811c98a76158617db3e773f13a126eab2a0b53f62d5ac0ddcf0985e1f09ce8bec3
data/.rspec CHANGED
@@ -1 +1,3 @@
1
- --color
1
+ --color
2
+ --require spec_helper
3
+ --format d
@@ -2,6 +2,6 @@ language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
4
  - 2.0.0
5
- - 2.1.2
6
- - 2.2.2
7
- script: bundle exec rspec spec
5
+ - 2.1.7
6
+ - 2.2.3
7
+ script: bundle exec rspec spec
data/README.md CHANGED
@@ -10,29 +10,29 @@ Generates ABA (Australian Banking Association) file format output
10
10
  require 'aba'
11
11
 
12
12
  # Initialise ABA
13
- aba = Aba.new(
13
+ aba = Aba.batch(
14
14
  bsb: "123-345", # Optional (Not required by NAB)
15
- financial_institution: "WPC",
15
+ financial_institution: "WPC",
16
16
  user_name: "John Doe",
17
- user_id: "466364",
18
- description: "Payroll",
17
+ user_id: "466364",
18
+ description: "Payroll",
19
19
  process_at: Time.now.strftime("%d%m%y")
20
20
  )
21
21
 
22
22
  # Add transactions
23
23
  10.times do
24
24
  aba.add_transaction(
25
- Aba::Transaction.new(
26
- bsb: "342-342",
27
- account_number: "3244654",
25
+ {
26
+ bsb: "342-342",
27
+ account_number: "3244654",
28
28
  amount: 10000, # Amount in cents
29
- account_name: "John Doe",
29
+ account_name: "John Doe",
30
30
  transaction_code: 53,
31
- lodgement_reference: "R435564",
32
- trace_bsb: "453-543",
33
- trace_account_number: "45656733",
31
+ lodgement_reference: "R435564",
32
+ trace_bsb: "453-543",
33
+ trace_account_number: "45656733",
34
34
  name_of_remitter: "Remitter"
35
- )
35
+ }
36
36
  )
37
37
  end
38
38
 
@@ -40,6 +40,66 @@ puts aba.to_s # View output
40
40
  File.write("/Users/me/dd_#{Time.now.to_i}.aba", aba.to_s) # or write output to file
41
41
  ```
42
42
 
43
+ There are a few ways to create a complete set of ABA data:
44
+
45
+ ```ruby
46
+ # Transactions added to the defined ABA object variable
47
+ aba = Aba.batch financial_institution: 'ANZ', user_name: 'Joe Blow', user_id: 123456, process_at: 200615
48
+ aba.add_transaction bsb: '123-456', account_number: '000-123-456', amount: 50000
49
+ aba.add_transaction bsb: '456-789', account_number: '123-456-789', amount: '-10000', transaction_code: 13
50
+
51
+ # Transactions passed individually inside a block
52
+ aba = Aba.batch financial_institution: 'ANZ', user_name: 'Joe Blow', user_id: 123456, process_at: 200615 do |a|
53
+ a.add_transaction bsb: '123-456', account_number: '000-123-456', amount: 50000
54
+ a.add_transaction bsb: '456-789', account_number: '123-456-789', amount: '-10000', transaction_code: 13
55
+ end
56
+
57
+ # Transactions as an array passed to the second param of Aba.batch
58
+ aba = Aba.batch(
59
+ { financial_institution: 'ANZ', user_name: 'Joe Blow', user_id: 123456, process_at: 200615 },
60
+ [
61
+ { bsb: '123-456', account_number: '000-123-456', amount: 50000 },
62
+ { bsb: '456-789', account_number: '123-456-789', amount: '-10000', transaction_code: 13 }
63
+ ]
64
+ )
65
+
66
+ # NOTE: Be careful with negative transaction amounts! transaction_code will not
67
+ # be set to debit automatically!
68
+ ```
69
+
70
+ Validation errors can be caught in several ways:
71
+
72
+ ```ruby
73
+ # Create an ABA object with invalid character in the user_name
74
+ aba = Aba.batch(
75
+ financial_institution: "ANZ",
76
+ user_name: "Jøhn Doe",
77
+ user_id: "123456",
78
+ process_at: Time.now.strftime("%d%m%y")
79
+ )
80
+
81
+ # Add a transaction with a bad BSB
82
+ aba.add_transaction(
83
+ bsb: "abc-123",
84
+ account_number: "000123456"
85
+ )
86
+
87
+ # Is the data valid?
88
+ aba.valid?
89
+ # Returns: false
90
+
91
+ # Return a structured array of errors
92
+ puts aba.errors
93
+ # Returns:
94
+ # {:aba => ["user_name must not contain invalid characters"],
95
+ # :transactions =>
96
+ # {0 => ["bsb format is incorrect", "trace_bsb format is incorrect"]}}
97
+ ```
98
+
99
+ Validation errors will stop parsing of the data to an ABA formatted string using
100
+ `to_s`. `aba.to_s` will raise a `RuntimeError` instead of returning output.
101
+
102
+
43
103
  ## Installation
44
104
 
45
105
  Add this line to your application's Gemfile:
data/lib/aba.rb CHANGED
@@ -1,159 +1,10 @@
1
1
  require "aba/version"
2
2
  require "aba/validations"
3
+ require "aba/batch"
3
4
  require "aba/transaction"
4
5
 
5
6
  class Aba
6
- include Aba::Validations
7
-
8
- attr_accessor :bsb, :financial_institution, :user_name, :user_id, :description, :process_at
9
-
10
- validates_bsb :bsb, allow_blank: true
11
-
12
- validates_max_length :user_name, 26
13
- validates_max_length :user_id, 6
14
- validates_max_length :description, 12
15
-
16
- validates_length :financial_institution, 3
17
- validates_length :process_at, 6
18
-
19
- def initialize(attrs = {})
20
- attrs.each do |key, value|
21
- send("#{key}=", value)
22
- end
23
-
24
- @transactions = []
25
-
26
- yield self if block_given?
27
- end
28
-
29
- def to_s
30
- # Descriptive record
31
- output = "#{descriptive_record}\r\n"
32
-
33
- # Transactions records
34
- output += @transactions.map{ |t| t.to_s }.join("\r\n")
35
-
36
- # Batch control record
37
- output += "\r\n#{batch_control_record}"
38
- end
39
-
40
- def add_transaction(transaction)
41
- @transactions << transaction
42
- end
43
-
44
- private
45
-
46
- def descriptive_record
47
- # Record type
48
- # Max: 1
49
- # Char position: 1
50
- output = "0"
51
-
52
- # Optional branch number of the funds account with a hyphen in the 4th character position
53
- # Char position: 2-18
54
- # Max: 17
55
- # Blank filled
56
- output += self.bsb.nil? ? " " * 17 : self.bsb.to_s.ljust(17)
57
-
58
- # Sequence number
59
- # Char position: 19-20
60
- # Max: 2
61
- # Zero padded
62
- output += "01"
63
-
64
- # Name of user financial instituion
65
- # Max: 3
66
- # Char position: 21-23
67
- output += self.financial_institution.to_s
68
-
69
- # Reserved
70
- # Max: 7
71
- # Char position: 24-30
72
- output += " " * 7
73
-
74
- # Name of User supplying File
75
- # Char position: 31-56
76
- # Max: 26
77
- # Blank filled
78
- output += self.user_name.to_s.ljust(26)
79
-
80
- # Direct Entry User ID
81
- # Char position: 57-62
82
- # Max: 6
83
- # Zero padded
84
- output += self.user_id.to_s.rjust(6, "0")
85
-
86
- # Description of payments in the file (e.g. Payroll, Creditors etc.)
87
- # Char position: 63-74
88
- # Max: 12
89
- # Blank filled
90
- output += self.description.to_s.ljust(12)
91
-
92
- # Date on which the payment is to be processed
93
- # Char position: 75-80
94
- # Max: 6
95
- output += self.process_at.rjust(6, "0")
96
-
97
- # Reserved
98
- # Max: 40
99
- # Char position: 81-120
100
- output += " " * 40
101
- end
102
-
103
- def batch_control_record
104
- net_total_amount = 0
105
- credit_total_amount = 0
106
- debit_total_amount = 0
107
-
108
- @transactions.each do |t|
109
- net_total_amount += t.amount
110
- credit_total_amount += t.amount if t.amount > 0
111
- debit_total_amount += t.amount if t.amount < 0
112
- end
113
-
114
- # Record type
115
- # Max: 1
116
- # Char position: 1
117
- output = "7"
118
-
119
- # BSB Format Filler
120
- # Max: 7
121
- # Char position: 2-8
122
- output += "999-999"
123
-
124
- # Reserved
125
- # Max: 12
126
- # Char position: 9-20
127
- output += " " * 12
128
-
129
- # Net total
130
- # Max: 10
131
- # Char position: 21-30
132
- output += net_total_amount.abs.to_s.rjust(10, "0")
133
-
134
- # Credit Total Amount
135
- # Max: 10
136
- # Char position: 31-40
137
- output += credit_total_amount.abs.to_s.rjust(10, "0")
138
-
139
- # Debit Total Amount
140
- # Max: 10
141
- # Char position: 41-50
142
- output += debit_total_amount.abs.to_s.rjust(10, "0")
143
-
144
- # Reserved
145
- # Max: 24
146
- # Char position: 51-74
147
- output += " " * 24
148
-
149
- # Total Item Count
150
- # Max: 6
151
- # Char position: 75-80
152
- output += @transactions.size.to_s.rjust(6, "0")
153
-
154
- # Reserved
155
- # Max: 40
156
- # Char position: 81-120
157
- output += " " * 40
7
+ def self.batch(attrs = {}, transactions = [])
8
+ Aba::Batch.new(attrs, transactions)
158
9
  end
159
10
  end
@@ -0,0 +1,218 @@
1
+ class Aba
2
+ class Batch
3
+ include Aba::Validations
4
+
5
+ attr_accessor :bsb, :financial_institution, :user_name, :user_id, :description, :process_at, :transactions
6
+
7
+ # BSB
8
+ validates_bsb :bsb, allow_blank: true
9
+
10
+ # Financial Institution
11
+ validates_length :financial_institution, 3
12
+
13
+ # User Name
14
+ validates_presence_of :user_name
15
+ validates_max_length :user_name, 26
16
+ validates_becs :user_name
17
+
18
+ # User ID
19
+ validates_presence_of :user_id
20
+ validates_max_length :user_id, 6
21
+ validates_integer :user_id, false
22
+
23
+ # Description
24
+ validates_max_length :description, 12
25
+ validates_becs :description
26
+
27
+ # Process at Date
28
+ validates_length :process_at, 6
29
+ validates_integer :process_at, false
30
+
31
+
32
+ def initialize(attrs = {}, transactions = [])
33
+ attrs.each do |key, value|
34
+ send("#{key}=", value)
35
+ end
36
+
37
+ @transaction_index = 0
38
+ @transactions = {}
39
+
40
+ unless transactions.nil? || transactions.empty?
41
+ transactions.to_a.each do |t|
42
+ self.add_transaction(t) unless t.nil? || t.empty?
43
+ end
44
+ end
45
+
46
+ yield self if block_given?
47
+ end
48
+
49
+ def to_s
50
+ raise RuntimeError, 'No transactions present - add one using `add_transaction`' if @transactions.empty?
51
+ raise RuntimeError, 'ABA data is invalid - check the contents of `errors`' unless valid?
52
+
53
+ # Descriptive record
54
+ output = "#{descriptive_record}\r\n"
55
+
56
+ # Transactions records
57
+ output += @transactions.map{ |t| t[1].to_s }.join("\r\n")
58
+
59
+ # Batch control record
60
+ output += "\r\n#{batch_control_record}"
61
+ end
62
+
63
+ def add_transaction(attrs = {})
64
+ if attrs.instance_of?(Aba::Transaction)
65
+ transaction = attrs
66
+ else
67
+ transaction = Aba::Transaction.new(attrs)
68
+ end
69
+ @transactions[@transaction_index] = transaction
70
+ @transaction_index += 1
71
+ transaction
72
+ end
73
+
74
+ def transactions_valid?
75
+ !has_transaction_errors?
76
+ end
77
+
78
+ def valid?
79
+ !has_errors? && transactions_valid?
80
+ end
81
+
82
+ def errors
83
+ # Run validations
84
+ has_errors?
85
+ has_transaction_errors?
86
+
87
+ # Build errors
88
+ all_errors = {}
89
+ all_errors[:aba] = self.error_collection unless self.error_collection.empty?
90
+ transaction_error_collection = @transactions.each_with_index.map{ |(k, t), i| [k, t.error_collection] }.reject{ |e| e[1].nil? || e[1].empty? }.to_h
91
+ all_errors[:transactions] = transaction_error_collection unless transaction_error_collection.empty?
92
+
93
+ all_errors unless all_errors.empty?
94
+ end
95
+
96
+ private
97
+
98
+ def has_transaction_errors?
99
+ @transactions.map{ |t| t[1].valid? }.include?(false)
100
+ end
101
+
102
+ def descriptive_record
103
+ # Record type
104
+ # Max: 1
105
+ # Char position: 1
106
+ output = "0"
107
+
108
+ # Optional branch number of the funds account with a hyphen in the 4th character position
109
+ # Char position: 2-18
110
+ # Max: 17
111
+ # Blank filled
112
+ output += self.bsb.nil? ? " " * 17 : self.bsb.to_s.ljust(17)
113
+
114
+ # Sequence number
115
+ # Char position: 19-20
116
+ # Max: 2
117
+ # Zero padded
118
+ output += "01"
119
+
120
+ # Name of user financial instituion
121
+ # Max: 3
122
+ # Char position: 21-23
123
+ output += self.financial_institution.to_s
124
+
125
+ # Reserved
126
+ # Max: 7
127
+ # Char position: 24-30
128
+ output += " " * 7
129
+
130
+ # Name of User supplying File
131
+ # Char position: 31-56
132
+ # Max: 26
133
+ # Full BECS character set valid
134
+ # Blank filled
135
+ output += self.user_name.to_s.ljust(26)
136
+
137
+ # Direct Entry User ID
138
+ # Char position: 57-62
139
+ # Max: 6
140
+ # Zero padded
141
+ output += self.user_id.to_s.rjust(6, "0")
142
+
143
+ # Description of payments in the file (e.g. Payroll, Creditors etc.)
144
+ # Char position: 63-74
145
+ # Max: 12
146
+ # Full BECS character set valid
147
+ # Blank filled
148
+ output += self.description.to_s.ljust(12)
149
+
150
+ # Date on which the payment is to be processed
151
+ # Char position: 75-80
152
+ # Max: 6
153
+ output += self.process_at.to_s.rjust(6, "0")
154
+
155
+ # Reserved
156
+ # Max: 40
157
+ # Char position: 81-120
158
+ output += " " * 40
159
+ end
160
+
161
+ def batch_control_record
162
+ net_total_amount = 0
163
+ credit_total_amount = 0
164
+ debit_total_amount = 0
165
+
166
+ @transactions.each do |t|
167
+ net_total_amount += t[1].amount.to_i
168
+ credit_total_amount += t[1].amount.to_i if t[1].amount.to_i > 0
169
+ debit_total_amount += t[1].amount.to_i if t[1].amount.to_i < 0
170
+ end
171
+
172
+ # Record type
173
+ # Max: 1
174
+ # Char position: 1
175
+ output = "7"
176
+
177
+ # BSB Format Filler
178
+ # Max: 7
179
+ # Char position: 2-8
180
+ output += "999-999"
181
+
182
+ # Reserved
183
+ # Max: 12
184
+ # Char position: 9-20
185
+ output += " " * 12
186
+
187
+ # Net total
188
+ # Max: 10
189
+ # Char position: 21-30
190
+ output += net_total_amount.abs.to_s.rjust(10, "0")
191
+
192
+ # Credit Total Amount
193
+ # Max: 10
194
+ # Char position: 31-40
195
+ output += credit_total_amount.abs.to_s.rjust(10, "0")
196
+
197
+ # Debit Total Amount
198
+ # Max: 10
199
+ # Char position: 41-50
200
+ output += debit_total_amount.abs.to_s.rjust(10, "0")
201
+
202
+ # Reserved
203
+ # Max: 24
204
+ # Char position: 51-74
205
+ output += " " * 24
206
+
207
+ # Total Item Count
208
+ # Max: 6
209
+ # Char position: 75-80
210
+ output += @transactions.size.to_s.rjust(6, "0")
211
+
212
+ # Reserved
213
+ # Max: 40
214
+ # Char position: 81-120
215
+ output += " " * 40
216
+ end
217
+ end
218
+ end
@@ -2,30 +2,95 @@ class Aba
2
2
  class Transaction
3
3
  include Aba::Validations
4
4
 
5
- attr_accessor :account_number, :transaction_code, :amount, :account_name,
5
+ attr_accessor :account_number, :transaction_code, :amount, :account_name,
6
6
  :bsb, :trace_bsb, :trace_account_number, :name_of_remitter,
7
7
  :witholding_amount, :indicator, :lodgement_reference
8
8
 
9
- validates_bsb :bsb
10
- validates_bsb :trace_bsb
11
-
12
- validates_integer :amount
9
+ # BSB
10
+ validates_bsb :bsb
11
+
12
+ # Account Number
13
+ validates_account_number :account_number
14
+
15
+ # Indicator
16
+ validates_indicator :indicator
17
+
18
+ # Transaction Code
19
+ validates_transaction_code :transaction_code
20
+
21
+ # Amount
22
+ validates_integer :amount
23
+
24
+ # Account Name
25
+ validates_max_length :account_name, 32
26
+ validates_becs :account_name
27
+
28
+ # Lodgement Reference
29
+ validates_max_length :lodgement_reference, 18
30
+ validates_becs :lodgement_reference
31
+
32
+ # Trace Record
33
+ validates_bsb :trace_bsb
34
+ validates_account_number :trace_account_number
35
+
36
+ # Name of Remitter
37
+ validates_max_length :name_of_remitter, 16
38
+ validates_becs :name_of_remitter
13
39
 
14
- validates_max_length :account_number, 9
15
- validates_max_length :indicator, 1
16
- validates_max_length :transaction_code, 2
17
- validates_max_length :account_name, 32
18
- validates_max_length :lodgement_reference, 18
19
- validates_max_length :trace_account_number, 9
20
- validates_max_length :name_of_remitter, 16
21
40
 
22
41
  def initialize(attrs = {})
23
42
  attrs.each do |key, value|
24
43
  send("#{key}=", value)
25
44
  end
26
45
  end
27
-
46
+
47
+ # Allow dashes to be input, but remove them from output
48
+ def account_number
49
+ @account_number ? @account_number.to_s.gsub('-', '') : nil
50
+ end
51
+
52
+ # Fall back to blank string
53
+ def indicator
54
+ @indicator || Aba::Validations::INDICATORS.first
55
+ end
56
+
57
+ # Fall back to 50
58
+ def transaction_code
59
+ @transaction_code || 50
60
+ end
61
+
62
+ # Fall back to 0
63
+ def amount
64
+ @amount || 0
65
+ end
66
+
67
+ # Fall back to empty string
68
+ def account_name
69
+ @account_name || ''
70
+ end
71
+
72
+ # Fall back to empty string
73
+ def lodgement_reference
74
+ @lodgement_reference || ''
75
+ end
76
+
77
+ # Fall back to BSB
78
+ def trace_bsb
79
+ @trace_bsb || bsb
80
+ end
81
+
82
+ # Fall back to Account Number
83
+ def trace_account_number
84
+ @trace_account_number ? @trace_account_number.to_s.gsub('-', '') : account_number
85
+ end
86
+
87
+ def name_of_remitter
88
+ @name_of_remitter || ''
89
+ end
90
+
28
91
  def to_s
92
+ raise RuntimeError, 'Transaction data is invalid - check the contents of `errors`' unless valid?
93
+
29
94
  # Record type
30
95
  output = "1"
31
96
 
@@ -33,41 +98,46 @@ class Aba
33
98
  output += bsb
34
99
 
35
100
  # Account number
101
+ #raise RuntimeError, 'Transaction is missing account_number' unless account_number
36
102
  output += account_number.to_s.rjust(9, " ")
37
103
 
38
104
  # Withholding Tax Indicator
39
105
  # "N" – for new or varied Bank/State/Branch number or name details, otherwise blank filled.
106
+ # "T" - for a drawing under a Transaction Negotiation Authority.
40
107
  # "W" – dividend paid to a resident of a country where a double tax agreement is in force.
41
108
  # "X" – dividend paid to a resident of any other country.
42
109
  # "Y" – interest paid to all non-residents.
43
110
  output += indicator.to_s.ljust(1, " ")
44
111
 
45
112
  # Transaction Code
46
- # 50 General Credit.
47
- # 53 Payroll.
48
- # 54 Pension.
49
- # 56 Dividend.
50
- # 57 Debenture Interest.
113
+ # 50 General Credit.
114
+ # 53 Payroll.
115
+ # 54 Pension.
116
+ # 56 Dividend.
117
+ # 57 Debenture Interest.
51
118
  # 13 General Debit.
52
119
  output += transaction_code.to_s
53
120
 
54
121
  # Amount to be credited or debited
55
- output += amount.abs.to_s.rjust(10, "0")
122
+ output += amount.to_i.abs.to_s.rjust(10, "0")
56
123
 
57
124
  # Title of Account
58
- output += account_name.ljust(32, " ")
125
+ # Full BECS character set valid
126
+ output += account_name.to_s.ljust(32, " ")
59
127
 
60
- # Lodgement Reference Produced on the recipient’s Account Statement.
61
- output += lodgement_reference.ljust(18, " ")
128
+ # Lodgement Reference Produced on the recipient’s Account Statement.
129
+ # Full BECS character set valid
130
+ output += lodgement_reference.to_s.ljust(18, " ")
62
131
 
63
132
  # Trace BSB Number
64
133
  output += trace_bsb
65
134
 
66
- # Trace Account Number
135
+ # Trace Account Number
67
136
  output += trace_account_number.to_s.rjust(9, " ")
68
137
 
69
138
  # Name of Remitter Produced on the recipient’s Account Statement
70
- output += name_of_remitter.ljust(16, " ")
139
+ # Full BECS character set valid
140
+ output += name_of_remitter.to_s.ljust(16, " ")
71
141
 
72
142
  # Withholding amount in cents
73
143
  output += (witholding_amount || 0).abs.to_s.rjust(8, "0")
@@ -1,6 +1,9 @@
1
1
  class Aba
2
2
  module Validations
3
- attr_accessor :errors
3
+ attr_accessor :error_collection
4
+
5
+ BECS_PATTERN = /\A[\w\+\-\@\ \$\!\%\&\(\)\*\.\/\#\=\:\;\?\,\'\[\]\_\^]*\Z/
6
+ INDICATORS = [' ', 'N', 'T', 'W', 'X', 'Y']
4
7
 
5
8
  def self.included(base)
6
9
  base.instance_eval do
@@ -10,9 +13,17 @@ class Aba
10
13
  base.send :extend, ClassMethods
11
14
  end
12
15
 
13
- # Run all validations
14
16
  def valid?
15
- self.errors = []
17
+ !has_errors?
18
+ end
19
+
20
+ alias_method 'errors', 'error_collection'
21
+
22
+ private
23
+
24
+ # Run all validations
25
+ def has_errors?
26
+ self.error_collection = []
16
27
 
17
28
  self.class.instance_variable_get(:@_validations).each do |attribute, validations|
18
29
  value = send(attribute)
@@ -20,27 +31,42 @@ class Aba
20
31
  validations.each do |type, param|
21
32
  case type
22
33
  when :presence
23
- self.errors << "#{attribute} is empty" if value.nil? || value.to_s.empty?
34
+ self.error_collection << "#{attribute} is empty" if value.nil? || value.to_s.empty?
24
35
  when :bsb
25
36
  unless((param && value.nil?) || value =~ /^\d{3}-\d{3}$/)
26
- self.errors << "#{attribute} format is incorrect"
37
+ self.error_collection << "#{attribute} format is incorrect"
27
38
  end
28
39
  when :max_length
29
- self.errors << "#{attribute} length must not exceed #{param} characters" if value.to_s.length > param
40
+ self.error_collection << "#{attribute} length must not exceed #{param} characters" if value.to_s.length > param
30
41
  when :length
31
- self.errors << "#{attribute} length must be exactly #{param} characters" if value.to_s.length != param
42
+ self.error_collection << "#{attribute} length must be exactly #{param} characters" if value.to_s.length != param
32
43
  when :integer
33
- self.errors << "#{attribute} must be an integer" unless value.to_s =~ /\A[+-]?\d+\Z/
44
+ if param
45
+ self.error_collection << "#{attribute} must be a number" unless value.to_s =~ /\A[+-]?\d+\Z/
46
+ else
47
+ self.error_collection << "#{attribute} must be an unsigned number" unless value.to_s =~ /\A\d+\Z/
48
+ end
49
+ when :account_number
50
+ if value.to_s =~ /\A[0\ ]+\Z/ || value.to_s !~ /\A[a-z\d\ ]{1,9}\Z/
51
+ self.error_collection << "#{attribute} must be a valid account number"
52
+ end
53
+ when :becs
54
+ self.error_collection << "#{attribute} must not contain invalid characters" unless value.to_s =~ BECS_PATTERN
55
+ when :indicator
56
+ list = INDICATORS.join('\', \'')
57
+ self.error_collection << "#{attribute} must be a one of '#{list}'" unless INDICATORS.include?(value.to_s)
58
+ when :transaction_code
59
+ self.error_collection << "#{attribute} must be a 2 digit number" unless value.to_s =~ /\A\d{2,2}\Z/
34
60
  end
35
61
  end
36
62
  end
37
63
 
38
- self.errors.empty?
64
+ !self.error_collection.empty?
39
65
  end
40
-
66
+
41
67
  module ClassMethods
42
68
  def validates_presence_of(*attributes)
43
- attributes.each do |a|
69
+ attributes.each do |a|
44
70
  add_validation_attribute(a, :presence)
45
71
  end
46
72
  end
@@ -58,8 +84,24 @@ class Aba
58
84
  add_validation_attribute(attribute, :length, length)
59
85
  end
60
86
 
61
- def validates_integer(attribute)
62
- add_validation_attribute(attribute, :integer)
87
+ def validates_integer(attribute, signed = true)
88
+ add_validation_attribute(attribute, :integer, signed)
89
+ end
90
+
91
+ def validates_account_number(attribute)
92
+ add_validation_attribute(attribute, :account_number)
93
+ end
94
+
95
+ def validates_becs(attribute)
96
+ add_validation_attribute(attribute, :becs)
97
+ end
98
+
99
+ def validates_indicator(attribute)
100
+ add_validation_attribute(attribute, :indicator)
101
+ end
102
+
103
+ def validates_transaction_code(attribute)
104
+ add_validation_attribute(attribute, :transaction_code)
63
105
  end
64
106
 
65
107
  private
@@ -1,3 +1,3 @@
1
1
  class Aba
2
- VERSION = "0.3.1"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -1,7 +1,9 @@
1
+ # encoding: UTF-8
2
+
1
3
  require "spec_helper"
2
4
 
3
- describe Aba do
4
- let(:aba) { Aba.new(financial_institution: "WPC", user_name: "John Doe",
5
+ describe Aba::Batch do
6
+ let(:aba) { Aba::Batch.new(financial_institution: "WPC", user_name: "John Doe",
5
7
  user_id: "466364", description: "Payroll", process_at: "190615") }
6
8
  let(:transaction_values) { [30, -20] }
7
9
  let(:transactions) do
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+
1
3
  require "spec_helper"
2
4
 
3
5
  describe Aba::Transaction do
@@ -10,8 +12,8 @@ describe Aba::Transaction do
10
12
  :witholding_amount => 87,
11
13
  :indicator => "W",
12
14
  :lodgement_reference => "R45343",
13
- :trace_bsb => "123-234",
14
- :trace_account_number => "4647642",
15
+ :trace_bsb => "123-234",
16
+ :trace_account_number => "4647642",
15
17
  :name_of_remitter => "Remitter"
16
18
  } }
17
19
  subject(:transaction) { Aba::Transaction.new(transaction_params) }
@@ -0,0 +1,215 @@
1
+ # encoding: UTF-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Aba::Validations do
6
+ let(:clean_room) do
7
+ Class.new(Object) do
8
+ include Aba::Validations
9
+ end
10
+ end
11
+
12
+ subject(:test_instance) { clean_room.new }
13
+
14
+ describe "#valid?" do
15
+ it "should validate presence of attrs" do
16
+ clean_room.instance_eval do
17
+ attr_accessor :attr1
18
+ validates_presence_of :attr1
19
+ end
20
+
21
+ expect(subject.valid?).to eq false
22
+ expect(subject.errors).to eq ["attr1 is empty"]
23
+
24
+ subject.attr1 = "hello!"
25
+ expect(subject.valid?).to eq true
26
+ end
27
+
28
+ it "should validate bsb format" do
29
+ clean_room.instance_eval do
30
+ attr_accessor :attr1
31
+ validates_bsb :attr1
32
+ end
33
+
34
+ subject.attr1 = "234456"
35
+ expect(subject.valid?).to eq false
36
+ expect(subject.errors).to eq ["attr1 format is incorrect"]
37
+
38
+ subject.attr1 = "234-456"
39
+ expect(subject.valid?).to eq true
40
+ end
41
+
42
+ it "should validate max length" do
43
+ clean_room.instance_eval do
44
+ attr_accessor :attr1
45
+ validates_max_length :attr1, 5
46
+ end
47
+
48
+ subject.attr1 = "234456642"
49
+ expect(subject.valid?).to eq false
50
+ expect(subject.errors).to eq ["attr1 length must not exceed 5 characters"]
51
+
52
+ subject.attr1 = "23445"
53
+ expect(subject.valid?).to eq true
54
+
55
+ subject.attr1 = "2344"
56
+ expect(subject.valid?).to eq true
57
+ end
58
+
59
+ it "should validate length" do
60
+ clean_room.instance_eval do
61
+ attr_accessor :attr1
62
+ validates_length :attr1, 5
63
+ end
64
+
65
+ subject.attr1 = "234456642"
66
+ expect(subject.valid?).to eq false
67
+ expect(subject.errors).to eq ["attr1 length must be exactly 5 characters"]
68
+
69
+ subject.attr1 = "23445"
70
+ expect(subject.valid?).to eq true
71
+
72
+ subject.attr1 = "2344"
73
+ expect(subject.valid?).to eq false
74
+ expect(subject.errors).to eq ["attr1 length must be exactly 5 characters"]
75
+ end
76
+
77
+ it "should validate signed integer" do
78
+ clean_room.instance_eval do
79
+ attr_accessor :attr1
80
+ validates_integer :attr1
81
+ end
82
+
83
+ subject.attr1 = "+1234A"
84
+ expect(subject.valid?).to eq false
85
+ expect(subject.errors).to eq ["attr1 must be a number"]
86
+
87
+ subject.attr1 = "+1234"
88
+ expect(subject.valid?).to eq true
89
+
90
+ subject.attr1 = "-1234"
91
+ expect(subject.valid?).to eq true
92
+
93
+ subject.attr1 = "1234"
94
+ expect(subject.valid?).to eq true
95
+ end
96
+
97
+ it "should validate unsigned integer" do
98
+ clean_room.instance_eval do
99
+ attr_accessor :attr1
100
+ validates_integer :attr1, false
101
+ end
102
+
103
+ subject.attr1 = "1234A"
104
+ expect(subject.valid?).to eq false
105
+ expect(subject.errors).to eq ["attr1 must be an unsigned number"]
106
+
107
+ subject.attr1 = "+1234"
108
+ expect(subject.valid?).to eq false
109
+ expect(subject.errors).to eq ["attr1 must be an unsigned number"]
110
+
111
+ subject.attr1 = "-1234"
112
+ expect(subject.valid?).to eq false
113
+ expect(subject.errors).to eq ["attr1 must be an unsigned number"]
114
+
115
+ subject.attr1 = "1234"
116
+ expect(subject.valid?).to eq true
117
+
118
+ subject.attr1 = 1234
119
+ expect(subject.valid?).to eq true
120
+ end
121
+
122
+ it "should validate account number" do
123
+ clean_room.instance_eval do
124
+ attr_accessor :attr1
125
+ validates_account_number :attr1
126
+ end
127
+
128
+ subject.attr1 = " "
129
+ expect(subject.valid?).to eq false
130
+ expect(subject.errors).to eq ["attr1 must be a valid account number"]
131
+
132
+ subject.attr1 = "000000"
133
+ expect(subject.valid?).to eq false
134
+ expect(subject.errors).to eq ["attr1 must be a valid account number"]
135
+
136
+ subject.attr1 = "00 0 0"
137
+ expect(subject.valid?).to eq false
138
+ expect(subject.errors).to eq ["attr1 must be a valid account number"]
139
+
140
+ subject.attr1 = "00 0A0"
141
+ expect(subject.valid?).to eq false
142
+ expect(subject.errors).to eq ["attr1 must be a valid account number"]
143
+
144
+ subject.attr1 = "00 111"
145
+ expect(subject.valid?).to eq true
146
+
147
+ subject.attr1 = "0a 111"
148
+ expect(subject.valid?).to eq true
149
+
150
+ subject.attr1 = "aaaaaa"
151
+ expect(subject.valid?).to eq true
152
+
153
+ subject.attr1 = "aa aaa"
154
+ expect(subject.valid?).to eq true
155
+ end
156
+
157
+ it "should validate becs" do
158
+ clean_room.instance_eval do
159
+ attr_accessor :attr1
160
+ validates_becs :attr1
161
+ end
162
+
163
+ subject.attr1 = "abc123 é"
164
+ expect(subject.valid?).to eq false
165
+ expect(subject.errors).to eq ["attr1 must not contain invalid characters"]
166
+
167
+ subject.attr1 = "abc123 ~"
168
+ expect(subject.valid?).to eq false
169
+ expect(subject.errors).to eq ["attr1 must not contain invalid characters"]
170
+
171
+ subject.attr1 = "abc123"
172
+ expect(subject.valid?).to eq true
173
+ end
174
+
175
+ it "should validate indicator" do
176
+ clean_room.instance_eval do
177
+ attr_accessor :attr1
178
+ validates_indicator :attr1
179
+ end
180
+
181
+ subject.attr1 = "$"
182
+ expect(subject.valid?).to eq false
183
+ list = Aba::Validations::INDICATORS.join('\', \'')
184
+ expect(subject.errors).to eq ["attr1 must be a one of '#{list}'"]
185
+
186
+ subject.attr1 = Aba::Validations::INDICATORS.sample
187
+ expect(subject.valid?).to eq true
188
+ end
189
+
190
+ it "should validate transaction code" do
191
+ clean_room.instance_eval do
192
+ attr_accessor :attr1
193
+ validates_transaction_code :attr1
194
+ end
195
+
196
+ subject.attr1 = "AA"
197
+ expect(subject.valid?).to eq false
198
+ expect(subject.errors).to eq ["attr1 must be a 2 digit number"]
199
+
200
+ subject.attr1 = "123"
201
+ expect(subject.valid?).to eq false
202
+ expect(subject.errors).to eq ["attr1 must be a 2 digit number"]
203
+
204
+ subject.attr1 = "1"
205
+ expect(subject.valid?).to eq false
206
+ expect(subject.errors).to eq ["attr1 must be a 2 digit number"]
207
+
208
+ subject.attr1 = "15"
209
+ expect(subject.valid?).to eq true
210
+
211
+ subject.attr1 = 15
212
+ expect(subject.valid?).to eq true
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: UTF-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Aba do
6
+ describe ".batch" do
7
+ it "initialize instance of Aba::Batch with passed arguments" do
8
+ attributes = double.as_null_object
9
+ transactions = double.as_null_object
10
+
11
+ expect(Aba::Batch).to receive(:new).with(attributes, transactions)
12
+ described_class.batch(attributes, transactions)
13
+ end
14
+
15
+ it "returns instance of Aba::Batch" do
16
+ obj = described_class.batch(double.as_null_object, double.as_null_object)
17
+
18
+ expect(obj).to be_a(Aba::Batch)
19
+ end
20
+ end
21
+ end
@@ -5,4 +5,6 @@ require "aba"
5
5
 
6
6
  RSpec.configure do |config|
7
7
  config.order = :random
8
+ config.filter_run :focus
9
+ config.run_all_when_everything_filtered = true
8
10
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aba
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrey Bazhutkin
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-06-16 00:00:00.000000000 Z
12
+ date: 2015-09-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -84,13 +84,15 @@ files:
84
84
  - Rakefile
85
85
  - aba.gemspec
86
86
  - lib/aba.rb
87
+ - lib/aba/batch.rb
87
88
  - lib/aba/transaction.rb
88
89
  - lib/aba/validations.rb
89
90
  - lib/aba/version.rb
90
- - spec/aba_spec.rb
91
+ - spec/lib/aba/batch_spec.rb
92
+ - spec/lib/aba/transaction_spec.rb
93
+ - spec/lib/aba/validations_spec.rb
94
+ - spec/lib/aba_spec.rb
91
95
  - spec/spec_helper.rb
92
- - spec/transaction_spec.rb
93
- - spec/validations_spec.rb
94
96
  homepage: https://github.com/andrba/aba
95
97
  licenses:
96
98
  - MIT
@@ -116,7 +118,8 @@ signing_key:
116
118
  specification_version: 4
117
119
  summary: ABA File Generator
118
120
  test_files:
119
- - spec/aba_spec.rb
121
+ - spec/lib/aba/batch_spec.rb
122
+ - spec/lib/aba/transaction_spec.rb
123
+ - spec/lib/aba/validations_spec.rb
124
+ - spec/lib/aba_spec.rb
120
125
  - spec/spec_helper.rb
121
- - spec/transaction_spec.rb
122
- - spec/validations_spec.rb
@@ -1,47 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe Aba::Validations do
4
- let(:clean_room) do
5
- Class.new(Object) do
6
- include Aba::Validations
7
- end
8
- end
9
-
10
- subject(:test_instance) { clean_room.new }
11
-
12
- describe "#valid?" do
13
- it "should validate presence of attrs" do
14
- clean_room.instance_eval do
15
- attr_accessor :attr1
16
- validates_presence_of :attr1
17
- end
18
-
19
- expect(subject.valid?).to eq false
20
- expect(subject.errors).to eq ["attr1 is empty"]
21
- end
22
-
23
- it "should validate bsb format" do
24
- clean_room.instance_eval do
25
- attr_accessor :attr1
26
- validates_bsb :attr1
27
- end
28
-
29
- subject.attr1 = "234456"
30
-
31
- expect(subject.valid?).to eq false
32
- expect(subject.errors).to eq ["attr1 format is incorrect"]
33
- end
34
-
35
- it "should validate length" do
36
- clean_room.instance_eval do
37
- attr_accessor :attr1
38
- validates_max_length :attr1, 5
39
- end
40
-
41
- subject.attr1 = "234456642"
42
-
43
- expect(subject.valid?).to eq false
44
- expect(subject.errors).to eq ["attr1 length must not exceed 5 characters"]
45
- end
46
- end
47
- end