qiflib 0.0.2alpha → 0.0.4alpha
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +12 -1
- data/lib/qiflib.rb +3 -2
- data/lib/qiflib_category.rb +34 -0
- data/lib/qiflib_constants.rb +44 -0
- data/lib/qiflib_money.rb +1 -1
- data/lib/qiflib_transaction.rb +99 -21
- data/lib/qiflib_util.rb +87 -16
- metadata +6 -5
- data/lib/qiflib_version.rb +0 -6
data/README.md
CHANGED
@@ -1 +1,12 @@
|
|
1
|
-
README for qiflib
|
1
|
+
README for qiflib
|
2
|
+
|
3
|
+
file data/New_IMac_2009.qif
|
4
|
+
data/New_IMac_2009.qif: ISO-8859 English text, with CR line terminators
|
5
|
+
|
6
|
+
file data/ibank_20120328.qif
|
7
|
+
data/ibank_20120328.qif: ASCII English text
|
8
|
+
|
9
|
+
iconv -c -f ISO-8859 -t ASCII New_IMac_2009.qif > quicken_ascii.qif
|
10
|
+
iconv -c -f ISO-8859-15 -t ASCII New_IMac_2009.qif > quicken_ascii.qif
|
11
|
+
iconv -c -f ISO-8859-15 -t UTF-8 New_IMac_2009.qif > quicken_utf8.qif
|
12
|
+
|
data/lib/qiflib.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
|
2
2
|
# standard libraries
|
3
|
-
require 'csv'
|
3
|
+
require 'csv'
|
4
4
|
|
5
5
|
# third-party libs
|
6
6
|
|
7
7
|
# application code
|
8
|
+
require 'qiflib_constants'
|
9
|
+
require 'qiflib_category'
|
8
10
|
require 'qiflib_date'
|
9
11
|
require 'qiflib_money'
|
10
12
|
require 'qiflib_transaction'
|
11
13
|
require 'qiflib_util'
|
12
|
-
require 'qiflib_version'
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
module Qiflib
|
3
|
+
|
4
|
+
class Category
|
5
|
+
|
6
|
+
attr_accessor :id
|
7
|
+
attr_accessor :name
|
8
|
+
|
9
|
+
def self.csv_header
|
10
|
+
CSV.generate do | csv |
|
11
|
+
csv << Qiflib::csv_category_field_names
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(n)
|
16
|
+
@id, @name = 0, "#{n}".strip.downcase
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_csv(idx=0)
|
20
|
+
CSV.generate do | csv |
|
21
|
+
csv << as_array(idx)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def as_array(idx=0)
|
26
|
+
array = []
|
27
|
+
array << idx + 1
|
28
|
+
array << name
|
29
|
+
array
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Qiflib
|
2
|
+
VERSION = '0.0.4alpha'
|
3
|
+
DATE = '2012-04-07'
|
4
|
+
SOURCE_QUICKEN = 'quicken'
|
5
|
+
SOURCE_IBANK = 'ibank'
|
6
|
+
|
7
|
+
def self.csv_category_field_names
|
8
|
+
%w( id name )
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.csv_transaction_field_names
|
12
|
+
%w(
|
13
|
+
id
|
14
|
+
acct_owner
|
15
|
+
acct_name
|
16
|
+
acct_type
|
17
|
+
date
|
18
|
+
amount
|
19
|
+
number
|
20
|
+
ibank_n
|
21
|
+
cleared
|
22
|
+
payee
|
23
|
+
category
|
24
|
+
memo
|
25
|
+
split1_amount
|
26
|
+
split1_category
|
27
|
+
split1_memo
|
28
|
+
split2_amount
|
29
|
+
split2_category
|
30
|
+
split2_memo
|
31
|
+
split3_amount
|
32
|
+
split3_category
|
33
|
+
split3_memo
|
34
|
+
address1
|
35
|
+
address2
|
36
|
+
address3
|
37
|
+
address4
|
38
|
+
address5
|
39
|
+
address6
|
40
|
+
eol_ind
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/lib/qiflib_money.rb
CHANGED
data/lib/qiflib_transaction.rb
CHANGED
@@ -1,28 +1,62 @@
|
|
1
1
|
|
2
|
+
=begin
|
3
|
+
|
4
|
+
Quicken:
|
5
|
+
D3/10/09
|
6
|
+
PDuke Energy
|
7
|
+
M$61.01 due 3/23
|
8
|
+
T-62.00
|
9
|
+
A
|
10
|
+
A
|
11
|
+
A
|
12
|
+
A
|
13
|
+
A
|
14
|
+
A
|
15
|
+
N4548
|
16
|
+
L120 Electric
|
17
|
+
^
|
18
|
+
|
19
|
+
iBank:
|
20
|
+
D3/10/09
|
21
|
+
PDuke Energy
|
22
|
+
M$61.01 due 3/23
|
23
|
+
T-62.
|
24
|
+
C4548
|
25
|
+
NCheck
|
26
|
+
L120 Electric
|
27
|
+
^
|
28
|
+
|
29
|
+
=end
|
30
|
+
|
2
31
|
module Qiflib
|
3
32
|
|
4
33
|
class Transaction
|
5
34
|
|
6
|
-
|
7
|
-
|
8
|
-
attr_reader
|
9
|
-
attr_reader :address
|
10
|
-
|
35
|
+
attr_accessor :id # computed field
|
36
|
+
attr_accessor :acct_owner, :acct_name, :acct_type, :source_app # constructor arg fields
|
37
|
+
attr_reader :date, :amount, :cleared, :category, :number, :payee, :memo # data fields
|
38
|
+
attr_reader :splits, :address, :ibank_n
|
11
39
|
|
12
|
-
def
|
40
|
+
def self.csv_header
|
41
|
+
CSV.generate do | csv |
|
42
|
+
csv << Qiflib::csv_transaction_field_names
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def initialize(acct_owner=nil, acct_name=nil, acct_type=nil, source_app='quicken')
|
13
47
|
if acct_owner
|
14
48
|
@acct_owner = "#{acct_owner}".downcase
|
15
49
|
@acct_name = "#{acct_name}".downcase
|
16
50
|
@acct_type = "#{acct_type}".downcase
|
51
|
+
@source_app = "#{source_app}".downcase
|
17
52
|
@id, @date, @amount, @cleared, @category, @number, @memo, @payee = 0, nil, nil, '', '', '', '', ''
|
18
|
-
@splits, @curr_split, @address = [], {}, []
|
53
|
+
@splits, @curr_split, @address, @ibank_n = [], {}, [], ''
|
19
54
|
end
|
20
55
|
end
|
21
56
|
|
22
57
|
def add_line(line)
|
23
58
|
if line
|
24
59
|
stripped = line.strip
|
25
|
-
puts "Transaction.add_line: #{stripped}"
|
26
60
|
if stripped.size > 0
|
27
61
|
# Field Indicator Explanations:
|
28
62
|
# D Date
|
@@ -44,17 +78,24 @@ module Qiflib
|
|
44
78
|
elsif (stripped.match(/^P/))
|
45
79
|
@payee = line_value(stripped)
|
46
80
|
elsif (stripped.match(/^C/))
|
47
|
-
|
81
|
+
if ibank?
|
82
|
+
@number = line_value(stripped)
|
83
|
+
else
|
84
|
+
@cleared = line_value(stripped)
|
85
|
+
end
|
48
86
|
elsif (stripped.match(/^N/))
|
49
|
-
|
87
|
+
if ibank?
|
88
|
+
@ibank_n = line_value(stripped)
|
89
|
+
else
|
90
|
+
@number = line_value(stripped)
|
91
|
+
end
|
50
92
|
elsif (stripped.match(/^M/))
|
51
93
|
@memo = line_value(stripped)
|
52
94
|
elsif (stripped.match(/^L/))
|
53
|
-
@category = line_value(stripped)
|
95
|
+
@category = line_value(stripped).downcase
|
54
96
|
elsif (stripped.match(/^S/))
|
55
|
-
current_split['category'] = line_value(stripped)
|
97
|
+
current_split['category'] = line_value(stripped).downcase
|
56
98
|
elsif (stripped.match(/^E/))
|
57
|
-
puts "E lv: #{line_value(stripped)}"
|
58
99
|
current_split['memo'] = line_value(stripped)
|
59
100
|
elsif (stripped.match(/^A/))
|
60
101
|
@address << line_value(stripped)
|
@@ -67,8 +108,14 @@ module Qiflib
|
|
67
108
|
end
|
68
109
|
end
|
69
110
|
|
111
|
+
def ibank?
|
112
|
+
@source_app == 'ibank'
|
113
|
+
end
|
114
|
+
|
70
115
|
def valid?
|
71
|
-
return false if
|
116
|
+
return false if date.nil?
|
117
|
+
return false if date.to_s.size < 8
|
118
|
+
return false if date.to_s == '0000-00-00'
|
72
119
|
true
|
73
120
|
end
|
74
121
|
|
@@ -77,17 +124,48 @@ module Qiflib
|
|
77
124
|
@curr_split
|
78
125
|
end
|
79
126
|
|
80
|
-
def
|
81
|
-
@splits = [] if @splits.nil?
|
82
|
-
@splits
|
83
|
-
end
|
84
|
-
|
85
|
-
def to_csv
|
127
|
+
def to_csv(idx=0)
|
86
128
|
CSV.generate do | csv |
|
87
|
-
csv <<
|
129
|
+
csv << as_array(idx)
|
88
130
|
end
|
89
131
|
end
|
90
132
|
|
133
|
+
def as_array(idx=0)
|
134
|
+
array = []
|
135
|
+
array << idx + 1
|
136
|
+
array << acct_owner.downcase
|
137
|
+
array << acct_name.downcase
|
138
|
+
array << acct_type.downcase
|
139
|
+
array << date.to_s
|
140
|
+
array << amount.to_s
|
141
|
+
array << number
|
142
|
+
array << ibank_n
|
143
|
+
array << cleared
|
144
|
+
array << payee
|
145
|
+
array << category
|
146
|
+
array << memo
|
147
|
+
3.times { | i |
|
148
|
+
if i < splits.size
|
149
|
+
array << splits[i]['amount']
|
150
|
+
array << splits[i]['category']
|
151
|
+
array << splits[i]['memo']
|
152
|
+
else
|
153
|
+
array << ''
|
154
|
+
array << ''
|
155
|
+
array << ''
|
156
|
+
end
|
157
|
+
}
|
158
|
+
6.times { | i |
|
159
|
+
if i < address.size
|
160
|
+
array << address[i]
|
161
|
+
else
|
162
|
+
array << ''
|
163
|
+
end
|
164
|
+
}
|
165
|
+
array << 'x'
|
166
|
+
array
|
167
|
+
end
|
168
|
+
|
91
169
|
def line_value(s)
|
92
170
|
return '' if s.nil? || s.size < 1
|
93
171
|
s[1, s.size].strip
|
data/lib/qiflib_util.rb
CHANGED
@@ -3,40 +3,111 @@ module Qiflib
|
|
3
3
|
|
4
4
|
class Util
|
5
5
|
|
6
|
-
def self.
|
6
|
+
def self.catetory_names(files_list)
|
7
|
+
categories, csv_lines = [], []
|
8
|
+
csv_lines << Qiflib::Category.csv_header
|
9
|
+
if files_list
|
10
|
+
files_list.each { | filename |
|
11
|
+
begin
|
12
|
+
file, in_cats = File.new(filename, 'r'), false
|
13
|
+
while (line = file.gets)
|
14
|
+
stripped = line.strip
|
15
|
+
if stripped.match(/^!Type:Cat/)
|
16
|
+
in_cats = true
|
17
|
+
else
|
18
|
+
if (stripped.match(/^!/)) && (stripped.size > 1)
|
19
|
+
in_cats = false
|
20
|
+
else
|
21
|
+
if in_cats
|
22
|
+
if (stripped.match(/^N/))
|
23
|
+
categories << line_value(stripped)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
file.close if file
|
30
|
+
rescue => err
|
31
|
+
file.close if file
|
32
|
+
puts "Exception: #{err.class.name} #{err.message} #{err.inspect}"
|
33
|
+
end
|
34
|
+
}
|
35
|
+
end
|
36
|
+
categories.uniq.sort.each_with_index { | name, idx |
|
37
|
+
cat = Qiflib::Category.new(name)
|
38
|
+
csv_lines << cat.to_csv(idx)
|
39
|
+
}
|
40
|
+
csv_lines
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.transactions_to_csv(input_list)
|
7
44
|
transactions, csv_lines = [], []
|
8
|
-
|
9
|
-
|
10
|
-
|
45
|
+
csv_lines << Qiflib::Transaction.csv_header
|
46
|
+
if input_list
|
47
|
+
input_list.each { | input_hash |
|
48
|
+
owner = input_hash[:owner]
|
49
|
+
filename = input_hash[:filename]
|
50
|
+
source = input_hash[:source]
|
51
|
+
process_file_for_transactions(owner, filename, source, transactions)
|
11
52
|
}
|
12
|
-
transactions.
|
13
|
-
csv_lines << tran.to_csv
|
53
|
+
transactions.each_with_index { | tran, idx |
|
54
|
+
csv_lines << tran.to_csv(idx)
|
14
55
|
}
|
15
56
|
end
|
16
57
|
csv_lines
|
17
58
|
end
|
18
59
|
|
19
|
-
def self.
|
60
|
+
def self.process_file_for_transactions(owner, filename, source, transactions)
|
20
61
|
begin
|
21
62
|
file = File.new(filename, 'r')
|
22
|
-
|
63
|
+
in_acct_header, in_type_header, acct_name, acct_type = false, false, '?', '?'
|
64
|
+
current_tran = Qiflib::Transaction.new(owner, acct_name, acct_type, source)
|
65
|
+
line_number = 0
|
23
66
|
while (line = file.gets)
|
67
|
+
line_number = line_number + 1
|
24
68
|
stripped = line.strip
|
25
|
-
if stripped
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
current_tran = Qiflib::Transaction.new
|
69
|
+
if stripped.match(/^!Account/)
|
70
|
+
in_acct_header = true
|
71
|
+
elsif stripped.match(/^!Type/)
|
72
|
+
in_type_header = true
|
30
73
|
else
|
31
|
-
|
74
|
+
if in_acct_header
|
75
|
+
if stripped.match(/^N/)
|
76
|
+
acct_name = line_value(stripped)
|
77
|
+
current_tran.acct_name = acct_name
|
78
|
+
elsif stripped.match(/^T/)
|
79
|
+
acct_type = line_value(stripped)
|
80
|
+
current_tran.acct_type = acct_type
|
81
|
+
elsif stripped == '^'
|
82
|
+
in_acct_header = false
|
83
|
+
end
|
84
|
+
elsif in_type_header
|
85
|
+
if stripped == '^'
|
86
|
+
in_type_header = false
|
87
|
+
end
|
88
|
+
else
|
89
|
+
if stripped == '^'
|
90
|
+
if current_tran.valid?
|
91
|
+
transactions << current_tran
|
92
|
+
end
|
93
|
+
current_tran = Qiflib::Transaction.new(owner, acct_name, acct_type, source)
|
94
|
+
else
|
95
|
+
current_tran.add_line(stripped)
|
96
|
+
end
|
97
|
+
end
|
32
98
|
end
|
33
99
|
end
|
34
|
-
file.close
|
100
|
+
file.close if file
|
35
101
|
rescue => err
|
36
102
|
puts "Exception: #{err.class.name} #{err.message} #{err.inspect}"
|
37
103
|
end
|
38
104
|
end
|
39
|
-
|
105
|
+
|
106
|
+
def self.line_value(s)
|
107
|
+
return '' if s.nil? || s.size < 1
|
108
|
+
s[1, s.size].strip
|
109
|
+
end
|
110
|
+
|
40
111
|
end
|
41
112
|
|
42
113
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qiflib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4alpha
|
5
5
|
prerelease: 5
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-04-
|
12
|
+
date: 2012-04-07 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70361534557220 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: 2.9.0
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70361534557220
|
25
25
|
description: A ruby library for qif file processing.
|
26
26
|
email: cjoakim@bellsouth.net
|
27
27
|
executables: []
|
@@ -29,11 +29,12 @@ extensions: []
|
|
29
29
|
extra_rdoc_files: []
|
30
30
|
files:
|
31
31
|
- lib/qiflib.rb
|
32
|
+
- lib/qiflib_category.rb
|
33
|
+
- lib/qiflib_constants.rb
|
32
34
|
- lib/qiflib_date.rb
|
33
35
|
- lib/qiflib_money.rb
|
34
36
|
- lib/qiflib_transaction.rb
|
35
37
|
- lib/qiflib_util.rb
|
36
|
-
- lib/qiflib_version.rb
|
37
38
|
- README.md
|
38
39
|
homepage: http://rubygems.org/gems/qiflib
|
39
40
|
licenses:
|