reckon 0.3.8 → 0.3.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,150 @@
1
+ #coding: utf-8
2
+ require 'pp'
3
+
4
+ module Reckon
5
+ class Money
6
+ include Comparable
7
+ attr_accessor :amount, :currency, :suffixed
8
+ def initialize( amount, options = {} )
9
+ if options[:inverse]
10
+ @amount = -1*amount.to_f
11
+ else
12
+ @amount = amount.to_f
13
+ end
14
+ @currency = options[:currency] || "$"
15
+ @suffixed = options[:suffixed]
16
+ end
17
+
18
+ def to_f
19
+ return @amount
20
+ end
21
+
22
+ def -@
23
+ Money.new( -@amount, :currency => @currency, :suffixed => @suffixed )
24
+ end
25
+
26
+ def <=>( mon )
27
+ other_amount = mon.to_f
28
+ if @amount < other_amount
29
+ -1
30
+ elsif @amount > other_amount
31
+ 1
32
+ else
33
+ 0
34
+ end
35
+ end
36
+
37
+ def pretty( negate = false )
38
+ if @suffixed
39
+ (@amount >= 0 ? " " : "") + sprintf("%0.2f #{@currency}", @amount * (negate ? -1 : 1))
40
+ else
41
+ (@amount >= 0 ? " " : "") + sprintf("%0.2f", @amount * (negate ? -1 : 1)).gsub(/^((\-)|)(?=\d)/, "\\1#{@currency}")
42
+ end
43
+ end
44
+
45
+ def Money::from_s( value, options = {} )
46
+ return nil if value.empty?
47
+ value = value.gsub(/\./, '').gsub(/,/, '.') if options[:comma_separates_cents]
48
+ amount = value.gsub(/[^\d\.]/, '').to_f
49
+ amount *= -1 if value =~ /[\(\-]/
50
+ Money.new( amount, options )
51
+ end
52
+
53
+ def Money::likelihood( entry )
54
+ money_score = 0
55
+ money_score += 20 if entry[/^[\-\+\(]{0,2}\$/]
56
+ money_score += 10 if entry[/^\$?\-?\$?\d+[\.,\d]*?[\.,]\d\d$/]
57
+ money_score += 10 if entry[/\d+[\.,\d]*?[\.,]\d\d$/]
58
+ money_score += entry.gsub(/[^\d\.\-\+,\(\)]/, '').length if entry.length < 7
59
+ money_score -= entry.length if entry.length > 8
60
+ money_score -= 20 if entry !~ /^[\$\+\.\-,\d\(\)]+$/
61
+ money_score
62
+ end
63
+ end
64
+
65
+ class MoneyColumn < Array
66
+ def initialize( arr = [], options = {} )
67
+ arr.each { |str| self.push( Money.from_s( str, options ) ) }
68
+ end
69
+
70
+ def positive?
71
+ self.each do |money|
72
+ return false if money < 0 if money
73
+ end
74
+ true
75
+ end
76
+
77
+ def merge!( other_column )
78
+ invert = false
79
+ invert = true if self.positive? && other_column.positive?
80
+ self.each_with_index do |mon, i|
81
+ other = other_column[i]
82
+ if mon && !other
83
+ if invert
84
+ self[i]= -mon
85
+ end
86
+ elsif !mon && other
87
+ self[i] = other
88
+ else
89
+ return nil
90
+ end
91
+ end
92
+ self
93
+ end
94
+ end
95
+
96
+ class DateColumn < Array
97
+ attr_accessor :endian_precedence
98
+ def initialize( arr = [], options = {} )
99
+ arr.each do |value|
100
+ if options[:date_format]
101
+ begin
102
+ value = Date.strptime(value, options[:date_format])
103
+ rescue
104
+ puts "I'm having trouble parsing #{value} with the desired format: #{options[:date_format]}"
105
+ exit 1
106
+ end
107
+ else
108
+ value = [$1, $2, $3].join("/") if value =~ /^(\d{4})(\d{2})(\d{2})\d+\[\d+\:GMT\]$/ # chase format
109
+ value = [$3, $2, $1].join("/") if value =~ /^(\d{2})\.(\d{2})\.(\d{4})$/ # german format
110
+ value = [$3, $2, $1].join("/") if value =~ /^(\d{2})\-(\d{2})\-(\d{4})$/ # nordea format
111
+ value = [$1, $2, $3].join("/") if value =~ /^(\d{4})(\d{2})(\d{2})/ # yyyymmdd format
112
+
113
+ unless @endian_precedence # Try to detect endian_precedence
114
+ reg_match = value.match( /^(\d\d)\/(\d\d)\/\d\d\d?\d?/ )
115
+ # If first one is not \d\d/\d\d/\d\d\d?\d set it to default
116
+ if !reg_match
117
+ @endian_precedence = [:middle, :little]
118
+ elsif reg_match[1].to_i > 12
119
+ @endian_precedence = [:little]
120
+ elsif reg_match[2].to_i > 12
121
+ @endian_precedence = [:middle]
122
+ end
123
+ end
124
+ end
125
+ self.push( value )
126
+ end
127
+ # if endian_precedence still nil, raise error
128
+ unless @endian_precedence || options[:date_format]
129
+ raise( "Unable to determine date format. Please specify using --date-format" )
130
+ end
131
+ end
132
+
133
+ def for( index )
134
+ value = self.at( index )
135
+ guess = Chronic.parse(value, :context => :past,
136
+ :endian_precedence => @endian_precedence )
137
+ if guess.to_i < 953236800 && value =~ /\//
138
+ guess = Chronic.parse((value.split("/")[0...-1] + [(2000 + value.split("/").last.to_i).to_s]).join("/"), :context => :past,
139
+ :endian_precedence => @endian_precedence)
140
+ end
141
+ guess
142
+ end
143
+
144
+ def pretty_for(index)
145
+ self.for(index).strftime("%Y/%m/%d")
146
+ end
147
+
148
+ end
149
+ end
150
+
data/reckon.gemspec CHANGED
@@ -3,8 +3,8 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = %q{reckon}
6
- s.version = "0.3.8"
7
- s.authors = ["Andrew Cantino"]
6
+ s.version = "0.3.9"
7
+ s.authors = ["Andrew Cantino", "BlackEdder"]
8
8
  s.email = %q{andrew@iterationlabs.com}
9
9
  s.homepage = %q{https://github.com/cantino/reckon}
10
10
  s.description = %q{Reckon automagically converts CSV files for use with the command-line accounting tool Ledger. It also helps you to select the correct accounts associated with the CSV data using Bayesian machine learning.}
@@ -5,204 +5,26 @@ require "spec_helper"
5
5
  require 'rubygems'
6
6
  require 'reckon'
7
7
 
8
- Reckon::App.settings[:testing] = true
9
-
10
8
  describe Reckon::App do
11
9
  before do
12
- @chase = Reckon::App.new(:string => CHASE_CSV)
13
- @some_other_bank = Reckon::App.new(:string => SOME_OTHER_CSV)
14
- @two_money_columns = Reckon::App.new(:string => TWO_MONEY_COLUMNS_BANK)
15
- @simple_csv = Reckon::App.new(:string => SIMPLE_CSV)
16
- @german_date = Reckon::App.new(:string => GERMAN_DATE_EXAMPLE)
17
- @danish_kroner_nordea = Reckon::App.new(:string => DANISH_KRONER_NORDEA_EXAMPLE, :csv_separator => ';', :comma_separates_cents => true)
18
- @yyyymmdd_date = Reckon::App.new(:string => YYYYMMDD_DATE_EXAMPLE)
19
- @spanish_date = Reckon::App.new(:string => SPANISH_DATE_EXAMPLE, :date_format => '%d/%m/%Y')
20
- @english_date = Reckon::App.new(:string => ENGLISH_DATE_EXAMPLE)
21
- end
22
-
23
- it "should be in testing mode" do
24
- @chase.settings[:testing].should be_true
25
- Reckon::App.settings[:testing].should be_true
26
- end
27
-
28
- describe "parse" do
29
- it "should work with foreign character encodings" do
30
- app = Reckon::App.new(:file => File.expand_path(File.join(File.dirname(__FILE__), "..", "data_fixtures", "extratofake.csv")))
31
- app.columns[0][0..2].should == ["Data", "10/31/2012", "11/01/2012"]
32
- app.columns[2].first.should == "Hist?rico"
33
- end
34
-
35
- it "should work with other separators" do
36
- Reckon::App.new(:string => "one;two\nthree;four", :csv_separator => ';').columns.should == [['one', 'three'], ['two', 'four']]
37
- end
38
- end
39
-
40
- describe "columns" do
41
- it "should return the csv transposed" do
42
- @simple_csv.columns.should == [["entry1", "entry4"], ["entry2", "entry5"], ["entry3", "entry6"]]
43
- @chase.columns.length.should == 4
44
- end
45
-
46
- it "should be ok with empty lines" do
47
- lambda {
48
- Reckon::App.new(:string => "one,two\nthree,four\n\n\n\n\n").columns.should == [['one', 'three'], ['two', 'four']]
49
- }.should_not raise_error
50
- end
51
- end
52
-
53
- describe "detect_columns" do
54
- before do
55
- @harder_date_example_csv = Reckon::App.new(:string => HARDER_DATE_EXAMPLE)
56
- end
57
-
58
- it "should detect the money column" do
59
- @chase.money_column_indices.should == [3]
60
- @some_other_bank.money_column_indices.should == [3]
61
- @two_money_columns.money_column_indices.should == [3, 4]
62
- @harder_date_example_csv.money_column_indices.should == [1]
63
- @danish_kroner_nordea.money_column_indices.should == [3]
64
- @yyyymmdd_date.money_column_indices.should == [3]
65
- end
66
-
67
- it "should detect the date column" do
68
- @chase.date_column_index.should == 1
69
- @some_other_bank.date_column_index.should == 1
70
- @two_money_columns.date_column_index.should == 0
71
- @harder_date_example_csv.date_column_index.should == 0
72
- @danish_kroner_nordea.date_column_index.should == 0
73
- @yyyymmdd_date.date_column_index.should == 1
74
- end
75
-
76
- it "should consider all other columns to be description columns" do
77
- @chase.description_column_indices.should == [0, 2]
78
- @some_other_bank.description_column_indices.should == [0, 2]
79
- @two_money_columns.description_column_indices.should == [1, 2, 5]
80
- @harder_date_example_csv.description_column_indices.should == [2, 3, 4, 5, 6, 7]
81
- @danish_kroner_nordea.description_column_indices.should == [1, 2, 4]
82
- @yyyymmdd_date.description_column_indices.should == [0, 2]
83
- end
84
- end
85
-
86
- describe "each_index_backwards" do
87
- it "should hit every index" do
88
- count = 0
89
- @chase.each_row_backwards { count += 1}
90
- count.should == 9
91
- end
92
- end
93
-
94
- describe "money_for" do
95
- it "should return the appropriate fields" do
96
- @chase.money_for(1).should == -20
97
- @chase.money_for(4).should == 1558.52
98
- @chase.money_for(7).should == -116.22
99
- @some_other_bank.money_for(1).should == -20
100
- @some_other_bank.money_for(4).should == 1558.52
101
- @some_other_bank.money_for(7).should == -116.22
102
- @two_money_columns.money_for(0).should == -76
103
- @two_money_columns.money_for(1).should == 327.49
104
- @two_money_columns.money_for(2).should == -800
105
- @two_money_columns.money_for(3).should == -88.55
106
- @two_money_columns.money_for(4).should == 88.55
107
- @danish_kroner_nordea.money_for(0).should == -48.00
108
- @danish_kroner_nordea.money_for(1).should == -79.00
109
- @danish_kroner_nordea.money_for(2).should == 497.90
110
- @danish_kroner_nordea.money_for(3).should == -995.00
111
- @danish_kroner_nordea.money_for(4).should == -3452.90
112
- @danish_kroner_nordea.money_for(5).should == -655.00
113
- @yyyymmdd_date.money_for(0).should == -123.45
114
- end
115
-
116
- it "should handle the comma_separates_cents option correctly" do
117
- european_csv = Reckon::App.new(:string => "$2,00;something\n1.025,67;something else", :csv_separator => ';', :comma_separates_cents => true)
118
- european_csv.money_for(0).should == 2.00
119
- european_csv.money_for(1).should == 1025.67
120
- end
121
-
122
- it "should return negated values if the inverse option is passed" do
123
- inversed_csv = Reckon::App.new(:string => INVERSED_CREDIT_CARD, :inverse => true)
124
- inversed_csv.money_for(0).should == -30.00
125
- inversed_csv.money_for(3).should == 500.00
126
- end
127
- end
128
-
129
- describe "date_for" do
130
- it "should return a parsed date object" do
131
- @chase.date_for(1).year.should == Time.parse("2009/12/24").year
132
- @chase.date_for(1).month.should == Time.parse("2009/12/24").month
133
- @chase.date_for(1).day.should == Time.parse("2009/12/24").day
134
- @some_other_bank.date_for(1).year.should == Time.parse("2010/12/24").year
135
- @some_other_bank.date_for(1).month.should == Time.parse("2010/12/24").month
136
- @some_other_bank.date_for(1).day.should == Time.parse("2010/12/24").day
137
- @german_date.date_for(1).year.should == Time.parse("2009/12/24").year
138
- @german_date.date_for(1).month.should == Time.parse("2009/12/24").month
139
- @german_date.date_for(1).day.should == Time.parse("2009/12/24").day
140
- @danish_kroner_nordea.date_for(0).year.should == Time.parse("2012/11/16").year
141
- @danish_kroner_nordea.date_for(0).month.should == Time.parse("2012/11/16").month
142
- @danish_kroner_nordea.date_for(0).day.should == Time.parse("2012/11/16").day
143
- @yyyymmdd_date.date_for(0).year.should == Time.parse("2012/12/31").year
144
- @yyyymmdd_date.date_for(0).month.should == Time.parse("2012/12/31").month
145
- @yyyymmdd_date.date_for(0).day.should == Time.parse("2012/12/31").day
146
- @spanish_date.date_for(1).year.should == Time.parse("2009/12/02").year
147
- @spanish_date.date_for(1).month.should == Time.parse("2009/12/02").month
148
- @spanish_date.date_for(1).day.should == Time.parse("2009/12/02").day
149
- @english_date.date_for(1).year.should == Time.parse("2009/12/24").year
150
- @english_date.date_for(1).month.should == Time.parse("2009/12/24").month
151
- @english_date.date_for(1).day.should == Time.parse("2009/12/24").day
152
- end
153
- end
154
-
155
- describe "description_for" do
156
- it "should return the combined fields that are not money for date fields" do
157
- @chase.description_for(1).should == "CHECK; CHECK 2656"
158
- @chase.description_for(7).should == "CREDIT; PAYPAL TRANSFER PPD ID: PAYPALSDSL"
159
- end
10
+ @chase = Reckon::App.new(:string => BANK_CSV)
11
+ @rows = []
12
+ @chase.each_row_backwards { |row| @rows.push( row ) }
160
13
  end
161
14
 
162
- describe "pretty_money_for" do
163
- it "work with negative and positive numbers" do
164
- @some_other_bank.pretty_money_for(1).should == "-$20.00"
165
- @some_other_bank.pretty_money_for(4).should == " $1558.52"
166
- @some_other_bank.pretty_money_for(7).should == "-$116.22"
167
- @some_other_bank.pretty_money_for(5).should == " $0.23"
168
- @some_other_bank.pretty_money_for(6).should == "-$0.96"
169
- end
170
-
171
- it "work with other currencies such as €" do
172
- euro_bank = Reckon::App.new(:string => SOME_OTHER_CSV, :currency => "€", :suffixed => false )
173
- euro_bank.pretty_money_for(1).should == "-€20.00"
174
- euro_bank.pretty_money_for(4).should == " €1558.52"
175
- euro_bank.pretty_money_for(7).should == "-€116.22"
176
- euro_bank.pretty_money_for(5).should == " €0.23"
177
- euro_bank.pretty_money_for(6).should == "-€0.96"
178
- end
179
-
180
- it "work with suffixed currencies such as SEK" do
181
- swedish_bank = Reckon::App.new(:string => SOME_OTHER_CSV, :currency => 'SEK', :suffixed => true )
182
- swedish_bank.pretty_money_for(1).should == "-20.00 SEK"
183
- swedish_bank.pretty_money_for(4).should == " 1558.52 SEK"
184
- swedish_bank.pretty_money_for(7).should == "-116.22 SEK"
185
- swedish_bank.pretty_money_for(5).should == " 0.23 SEK"
186
- swedish_bank.pretty_money_for(6).should == "-0.96 SEK"
15
+ describe "each_row_backwards" do
16
+ it "should return rows with hashes" do
17
+ @rows[0][:pretty_date].should == "2009/12/10"
18
+ @rows[0][:pretty_money].should == " $2105.00"
19
+ @rows[0][:description].should == "CREDIT; Some Company vendorpymt PPD ID: 5KL3832735"
20
+ @rows[1][:pretty_date].should == "2009/12/11"
21
+ @rows[1][:pretty_money].should == "-$116.22"
22
+ @rows[1][:description].should == "CREDIT; PAYPAL TRANSFER PPD ID: PAYPALSDSL"
187
23
  end
188
24
  end
189
-
190
- describe "merge_columns" do
191
- it "should work on adjacent columns" do
192
- @simple_csv.merge_columns(0,1).should == [["entry1 entry2", "entry4 entry5"], ["entry3", "entry6"]]
193
- end
194
-
195
- it "should work on non-adjacent columns" do
196
- @simple_csv.merge_columns(0,2).should == [["entry1 entry3", "entry4 entry6"], ["entry2", "entry5"]]
197
- end
198
- end
199
-
200
-
201
- # Data
202
-
203
- SIMPLE_CSV = "entry1,entry2,entry3\nentry4,entry5,entry6"
204
-
205
- CHASE_CSV = (<<-CSV).strip
25
+
26
+ #DATA
27
+ BANK_CSV = (<<-CSV).strip
206
28
  DEBIT,20091224120000[0:GMT],"HOST 037196321563 MO 12/22SLICEHOST",-85.00
207
29
  CHECK,20091224120000[0:GMT],"CHECK 2656",-20.00
208
30
  DEBIT,20091224120000[0:GMT],"GITHUB 041287430274 CA 12/22GITHUB 04",-7.00
@@ -213,82 +35,4 @@ describe Reckon::App do
213
35
  CREDIT,20091211120000[0:GMT],"PAYPAL TRANSFER PPD ID: PAYPALSDSL",-116.22
214
36
  CREDIT,20091210120000[0:GMT],"Some Company vendorpymt PPD ID: 5KL3832735",2105.00
215
37
  CSV
216
-
217
- SOME_OTHER_CSV = (<<-CSV).strip
218
- DEBIT,2011/12/24,"HOST 037196321563 MO 12/22SLICEHOST",($85.00)
219
- CHECK,2010/12/24,"CHECK 2656",($20.00)
220
- DEBIT,2009/12/24,"GITHUB 041287430274 CA 12/22GITHUB 04",($7.00)
221
- CREDIT,2008/12/24,"Some Company vendorpymt PPD ID: 59728JSL20",$3520.00
222
- CREDIT,2007/12/24,"Blarg BLARG REVENUE PPD ID: 00jah78563",$1558.52
223
- DEBIT,2006/12/24,"WEBSITE-BALANCE-17DEC09 12 12/17WEBSITE-BAL",$.23
224
- DEBIT,2005/12/24,"WEBSITE-BALANCE-10DEC09 12 12/10WEBSITE-BAL",($0.96)
225
- CREDIT,2004/12/24,"PAYPAL TRANSFER PPD ID: PAYPALSDSL",($116.22)
226
- CREDIT,2003/12/24,"Some Company vendorpymt PPD ID: 5KL3832735",$2105.00
227
- CSV
228
-
229
- INVERSED_CREDIT_CARD = (<<-CSV).strip
230
- 2013/01/17,2013/01/16,2013011702,DEBIT,2226,"VODAFONE PREPAY VISA M AUCKLAND NZL",30.00
231
- 2013/01/18,2013/01/17,2013011801,DEBIT,2226,"WILSON PARKING AUCKLAND NZL",4.60
232
- 2013/01/18,2013/01/17,2013011802,DEBIT,2226,"AUCKLAND TRANSPORT HENDERSON NZL",2.00
233
- 2013/01/19,2013/01/19,2013011901,CREDIT,2226,"INTERNET PAYMENT RECEIVED ",-500.00
234
- 2013/01/26,2013/01/23,2013012601,DEBIT,2226,"ITUNES NZ CORK IRL",64.99
235
- 2013/01/26,2013/01/25,2013012602,DEBIT,2226,"VODAFONE FXFLNE BBND R NEWTON NZL",90.26
236
- 2013/01/29,2013/01/29,2013012901,CREDIT,2101,"PAYMENT RECEIVED THANK YOU ",-27.75
237
- 2013/01/30,2013/01/29,2013013001,DEBIT,2226,"AUCKLAND TRANSPORT HENDERSON NZL",3.50
238
- 2013/02/05,2013/02/03,2013020501,DEBIT,2226,"Z BEACH RD AUCKLAND NZL",129.89
239
- 2013/02/05,2013/02/03,2013020502,DEBIT,2226,"TOURNAMENT KHYBER PASS AUCKLAND NZL",8.00
240
- 2013/02/05,2013/02/04,2013020503,DEBIT,2226,"VODAFONE PREPAY VISA M AUCKLAND NZL",30.00
241
- 2013/02/08,2013/02/07,2013020801,DEBIT,2226,"AKLD TRANSPORT PARKING AUCKLAND NZL",2.50
242
- 2013/02/08,2013/02/07,2013020802,DEBIT,2226,"AUCKLAND TRANSPORT HENDERSON NZL",3.50
243
- 2013/02/12,2013/02/11,2013021201,DEBIT,2226,"AKLD TRANSPORT PARKING AUCKLAND NZL",1.50
244
- 2013/02/17,2013/02/17,2013021701,CREDIT,2226,"INTERNET PAYMENT RECEIVED ",-12.00
245
- 2013/02/17,2013/02/17,2013021702,CREDIT,2226,"INTERNET PAYMENT RECEIVED ",-18.00
246
- CSV
247
-
248
- TWO_MONEY_COLUMNS_BANK = (<<-CSV).strip
249
- 4/1/2008,Check - 0000000122,122,-$76.00,"","$1,750.06"
250
- 3/28/2008,BLARG R SH 456930,"","",+$327.49,"$1,826.06"
251
- 3/27/2008,Check - 0000000112,112,-$800.00,"","$1,498.57"
252
- 3/26/2008,Check - 0000000251,251,-$88.55,"","$1,298.57"
253
- 3/26/2008,Check - 0000000251,251,"","+$88.55","$1,298.57"
254
- CSV
255
-
256
- HARDER_DATE_EXAMPLE = (<<-CSV).strip
257
- 10-Nov-9,-123.12,,,TRANSFER DEBIT INTERNET TRANSFER,INTERNET TRANSFER MORTGAGE,0.00,
258
- 09-Nov-10,123.12,,,SALARY SALARY,NGHSKS46383BGDJKD FOO BAR,432.12,
259
- 04-Nov-11,-1234.00,,,TRANSFER DEBIT INTERNET TRANSFER,INTERNET TRANSFER SAV TO MECU,0.00,
260
- 04-Nov-9,1234.00,,,TRANSFER CREDIT INTERNET TRANSFER,INTERNET TRANSFER,1234.00,
261
- 28-Oct-10,-123.12,,,TRANSFER DEBIT INTERNET TRANSFER,INTERNET TRANSFER SAV TO MORTGAGE,0.00,
262
- CSV
263
- GERMAN_DATE_EXAMPLE = (<<-CSV).strip
264
- 24.12.2009,Check - 0000000122,122,-$76.00,"","$1,750.06"
265
- 24.12.2009,BLARG R SH 456930,"","",+$327.49,"$1,826.06"
266
- 24.12.2009,Check - 0000000112,112,-$800.00,"","$1,498.57"
267
- CSV
268
-
269
- DANISH_KRONER_NORDEA_EXAMPLE = (<<-CSV).strip
270
- 16-11-2012;Dankort-nota DSB Kobenhavn 15149;16-11-2012;-48,00;26550,33
271
- 26-10-2012;Dankort-nota Ziggy Cafe 19471;26-10-2012;-79,00;26054,54
272
- 22-10-2012;Dankort-nota H&M Hennes & M 10681;23-10-2012;497,90;25433,54
273
- 12-10-2012;Visa kob DKK 995,00 WWW.ASOS.COM 00000 ;12-10-2012;-995,00;27939,54
274
- 12-09-2012;Dankort-nota B.J. TRADING E 14660;12-09-2012;-3452,90;26164,80
275
- 27-08-2012;Dankort-nota MATAS - 20319 18230;27-08-2012;-655,00;21127,45
276
- CSV
277
-
278
- YYYYMMDD_DATE_EXAMPLE = (<<-CSV).strip
279
- DEBIT,20121231,"ODESK***BAL-27DEC12 650-12345 CA 12/28",-123.45
280
- CSV
281
-
282
- SPANISH_DATE_EXAMPLE = (<<-CSV).strip
283
- 02/12/2009,Check - 0000000122,122,-$76.00,"","$1,750.06"
284
- 02/12/2009,BLARG R SH 456930,"","",+$327.49,"$1,826.06"
285
- 02/12/2009,Check - 0000000112,112,-$800.00,"","$1,498.57"
286
- CSV
287
-
288
- ENGLISH_DATE_EXAMPLE = (<<-CSV).strip
289
- 24/12/2009,Check - 0000000122,122,-$76.00,"","$1,750.06"
290
- 24/12/2009,BLARG R SH 456930,"","",+$327.49,"$1,826.06"
291
- 24/12/2009,Check - 0000000112,112,-$800.00,"","$1,498.57"
292
- CSV
293
-
294
38
  end