ofx_parser 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +4 -0
- data/Gemfile.lock +24 -0
- data/History.txt +14 -0
- data/Manifest.txt +14 -0
- data/README.txt +105 -0
- data/Rakefile +2 -0
- data/lib/class-extension.rb +154 -0
- data/lib/ofx_parser.rb +3 -0
- data/lib/ofx_parser/mcc.rb +674 -0
- data/lib/ofx_parser/ofx.rb +128 -0
- data/lib/ofx_parser/ofx_parser.rb +188 -0
- data/ofx-parser.gemspec +23 -0
- data/pkg/ofx_parser-1.0.4.gem +0 -0
- data/pkg/ofx_parser-1.0.5.gem +0 -0
- data/pkg/ofx_parser-1.0.6.gem +0 -0
- data/test/fixtures/banking.ofx.sgml +87 -0
- data/test/fixtures/creditcard.ofx.sgml +79 -0
- data/test/fixtures/list.ofx.sgml +53 -0
- data/test/fixtures/malformed_header.ofx.sgml +106 -0
- data/test/fixtures/with_spaces.ofx.sgml +28 -0
- data/test/test_ofx_parser.rb +213 -0
- metadata +93 -0
@@ -0,0 +1,128 @@
|
|
1
|
+
module OfxParser
|
2
|
+
# This class is returned when a parse is successful.
|
3
|
+
# == General Notes
|
4
|
+
# * currency symbols are an iso4217 3-letter code
|
5
|
+
# * language is defined by iso639 3-letter code
|
6
|
+
class Ofx
|
7
|
+
attr_accessor :header, :sign_on, :signup_account_info,
|
8
|
+
:bank_account, :credit_card, :investment
|
9
|
+
|
10
|
+
def accounts
|
11
|
+
accounts = []
|
12
|
+
[:bank_account, :credit_card, :investment].each do |method|
|
13
|
+
val = send(method)
|
14
|
+
accounts << val if val
|
15
|
+
end
|
16
|
+
accounts
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class SignOn
|
21
|
+
attr_accessor :status, :date, :language, :institute
|
22
|
+
end
|
23
|
+
|
24
|
+
class AccountInfo
|
25
|
+
attr_accessor :desc, :number
|
26
|
+
end
|
27
|
+
|
28
|
+
class Account
|
29
|
+
attr_accessor :number, :statement, :transaction_uid, :routing_number
|
30
|
+
end
|
31
|
+
|
32
|
+
class BankAccount < Account
|
33
|
+
TYPE = [:CHECKING, :SAVINGS, :MONEYMRKT, :CREDITLINE]
|
34
|
+
attr_accessor :type, :balance, :balance_date
|
35
|
+
|
36
|
+
undef type
|
37
|
+
def type
|
38
|
+
@type.to_s.upcase.to_sym
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class CreditAccount < Account
|
43
|
+
attr_accessor :remaining_credit, :remaining_credit_date, :balance, :balance_date
|
44
|
+
end
|
45
|
+
|
46
|
+
class InvestmentAccount < Account
|
47
|
+
attr_accessor :broker_id, :positions, :margin_balance, :short_balance, :cash_balance
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
class Statement
|
52
|
+
attr_accessor :currency, :transactions, :start_date, :end_date
|
53
|
+
end
|
54
|
+
|
55
|
+
class Transaction
|
56
|
+
attr_accessor :type, :date, :amount, :fit_id, :check_number, :sic, :memo, :payee
|
57
|
+
|
58
|
+
TYPE = {
|
59
|
+
:CREDIT => "Generic credit",
|
60
|
+
:DEBIT => "Generic debit",
|
61
|
+
:INT => "Interest earned or paid ",
|
62
|
+
:DIV => "Dividend",
|
63
|
+
:FEE => "FI fee",
|
64
|
+
:SRVCHG => "Service charge",
|
65
|
+
:DEP => "Deposit",
|
66
|
+
:ATM => "ATM debit or credit",
|
67
|
+
:POS => "Point of sale debit or credit ",
|
68
|
+
:XFER => "Transfer",
|
69
|
+
:CHECK => "Check",
|
70
|
+
:PAYMENT => "Electronic payment",
|
71
|
+
:CASH => "Cash withdrawal",
|
72
|
+
:DIRECTDEP => "Direct deposit",
|
73
|
+
:DIRECTDEBIT => "Merchant initiated debit",
|
74
|
+
:REPEATPMT => "Repeating payment/standing order",
|
75
|
+
:OTHER => "Other"
|
76
|
+
}
|
77
|
+
|
78
|
+
def type_desc
|
79
|
+
TYPE[type]
|
80
|
+
end
|
81
|
+
|
82
|
+
undef type
|
83
|
+
def type
|
84
|
+
@type.to_s.strip.upcase.to_sym
|
85
|
+
end
|
86
|
+
|
87
|
+
undef sic
|
88
|
+
def sic
|
89
|
+
@sic == "" ? nil : @sic
|
90
|
+
end
|
91
|
+
|
92
|
+
def sic_desc
|
93
|
+
Mcc::CODES[sic]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class Position
|
98
|
+
end
|
99
|
+
|
100
|
+
# Status of a sign on
|
101
|
+
class Status
|
102
|
+
attr_accessor :code, :severity, :message
|
103
|
+
|
104
|
+
CODES = {
|
105
|
+
'0' => 'Success',
|
106
|
+
'2000' => 'General error',
|
107
|
+
'15000' => 'Must change USERPASS',
|
108
|
+
'15500' => 'Signon invalid',
|
109
|
+
'15501' => 'Customer account already in use',
|
110
|
+
'15502' => 'USERPASS Lockout'
|
111
|
+
}
|
112
|
+
|
113
|
+
def code_desc
|
114
|
+
CODES[code]
|
115
|
+
end
|
116
|
+
|
117
|
+
undef code
|
118
|
+
def code
|
119
|
+
@code.to_s.strip
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
class Institute
|
125
|
+
attr_accessor :name, :id
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'hpricot'
|
3
|
+
require 'time'
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
module OfxParser
|
7
|
+
VERSION = '1.0.6'
|
8
|
+
|
9
|
+
class OfxParser
|
10
|
+
|
11
|
+
# Creates and returns an Ofx instance when given a well-formed OFX document,
|
12
|
+
# complete with the mandatory key:pair header.
|
13
|
+
def self.parse(ofx)
|
14
|
+
ofx = ofx.respond_to?(:read) ? ofx.read.to_s : ofx.to_s
|
15
|
+
|
16
|
+
return Ofx.new if ofx == ""
|
17
|
+
|
18
|
+
header, body = pre_process(ofx)
|
19
|
+
|
20
|
+
ofx_out = parse_body(body)
|
21
|
+
ofx_out.header = header
|
22
|
+
ofx_out
|
23
|
+
end
|
24
|
+
|
25
|
+
# Designed to make the main OFX body parsable. This means adding closing tags
|
26
|
+
# to the SGML to make it parsable by hpricot.
|
27
|
+
#
|
28
|
+
# Returns an array of 2 elements:
|
29
|
+
# * header as a hash,
|
30
|
+
# * body as an evily pre-processed string ready for parsing by hpricot.
|
31
|
+
def self.pre_process(ofx)
|
32
|
+
header, body = ofx.split(/\n{2,}|:?<OFX>/, 2)
|
33
|
+
|
34
|
+
header = Hash[*header.gsub(/^\r?\n+/,'').split(/\r\n/).collect do |e|
|
35
|
+
e.split(/:/,2)
|
36
|
+
end.flatten]
|
37
|
+
|
38
|
+
body.gsub!(/>\s+</m, '><')
|
39
|
+
body.gsub!(/\s+</m, '<')
|
40
|
+
body.gsub!(/>\s+/m, '>')
|
41
|
+
body.gsub!(/<(\w+?)>([^<]+)/m, '<\1>\2</\1>')
|
42
|
+
|
43
|
+
[header, body]
|
44
|
+
end
|
45
|
+
|
46
|
+
# Takes an OFX datetime string of the format:
|
47
|
+
# * YYYYMMDDHHMMSS.XXX[gmt offset:tz name]
|
48
|
+
# * YYYYMMDD
|
49
|
+
# * YYYYMMDDHHMMSS
|
50
|
+
# * YYYYMMDDHHMMSS.XXX
|
51
|
+
#
|
52
|
+
# Returns a DateTime object. Milliseconds (XXX) are ignored.
|
53
|
+
def self.parse_datetime(date)
|
54
|
+
if /\A\s*
|
55
|
+
(\d{4})(\d{2})(\d{2}) ?# YYYYMMDD 1,2,3
|
56
|
+
(?:(\d{2})(\d{2})(\d{2}))? ?# HHMMSS - optional 4,5,6
|
57
|
+
(?:\.(\d{3}))? ?# .XXX - optional 7
|
58
|
+
(?:\[([-+]?[\.\d]+)\:\w{3}\])? ?# [-n:TZ] - optional 8,9
|
59
|
+
\s*\z/ix =~ date
|
60
|
+
year = $1.to_i
|
61
|
+
mon = $2.to_i
|
62
|
+
day = $3.to_i
|
63
|
+
hour = $4.to_i
|
64
|
+
min = $5.to_i
|
65
|
+
sec = $6.to_i
|
66
|
+
# DateTime does not support usecs.
|
67
|
+
# usec = 0
|
68
|
+
# usec = $7.to_f * 1000000 if $7
|
69
|
+
off = Rational($8.to_i, 24) # offset as a fraction of day. :|
|
70
|
+
DateTime.civil(year, mon, day, hour, min, sec, off)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
def self.parse_body(body)
|
76
|
+
doc = Hpricot.XML(body)
|
77
|
+
|
78
|
+
ofx = Ofx.new
|
79
|
+
|
80
|
+
ofx.sign_on = build_signon((doc/"SIGNONMSGSRSV1/SONRS"))
|
81
|
+
ofx.signup_account_info = build_info((doc/"SIGNUPMSGSRSV1/ACCTINFOTRNRS"))
|
82
|
+
ofx.bank_account = build_bank((doc/"BANKMSGSRSV1/STMTTRNRS")) unless (doc/"BANKMSGSRSV1").empty?
|
83
|
+
ofx.credit_card = build_credit((doc/"CREDITCARDMSGSRSV1/CCSTMTTRNRS")) unless (doc/"CREDITCARDMSGSRSV1").empty?
|
84
|
+
#build_investment((doc/"SIGNONMSGSRQV1"))
|
85
|
+
|
86
|
+
ofx
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.build_signon(doc)
|
90
|
+
sign_on = SignOn.new
|
91
|
+
sign_on.status = build_status((doc/"STATUS"))
|
92
|
+
sign_on.date = parse_datetime((doc/"DTSERVER").inner_text)
|
93
|
+
sign_on.language = (doc/"LANGUAGE").inner_text
|
94
|
+
|
95
|
+
sign_on.institute = Institute.new
|
96
|
+
sign_on.institute.name = ((doc/"FI")/"ORG").inner_text
|
97
|
+
sign_on.institute.id = ((doc/"FI")/"FID").inner_text
|
98
|
+
sign_on
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.build_info(doc)
|
102
|
+
account_infos = []
|
103
|
+
|
104
|
+
(doc/"ACCTINFO").each do |info_doc|
|
105
|
+
acc_info = AccountInfo.new
|
106
|
+
acc_info.desc = (info_doc/"DESC").inner_text
|
107
|
+
acc_info.number = (info_doc/"ACCTID").inner_text
|
108
|
+
account_infos << acc_info
|
109
|
+
end
|
110
|
+
|
111
|
+
account_infos
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.build_bank(doc)
|
115
|
+
acct = BankAccount.new
|
116
|
+
|
117
|
+
acct.transaction_uid = (doc/"TRNUID").inner_text.strip
|
118
|
+
acct.number = (doc/"STMTRS/BANKACCTFROM/ACCTID").inner_text
|
119
|
+
acct.routing_number = (doc/"STMTRS/BANKACCTFROM/BANKID").inner_text
|
120
|
+
acct.type = (doc/"STMTRS/BANKACCTFROM/ACCTTYPE").inner_text.strip
|
121
|
+
acct.balance = (doc/"STMTRS/LEDGERBAL/BALAMT").inner_text
|
122
|
+
acct.balance_date = parse_datetime((doc/"STMTRS/LEDGERBAL/DTASOF").inner_text)
|
123
|
+
|
124
|
+
statement = Statement.new
|
125
|
+
statement.currency = (doc/"STMTRS/CURDEF").inner_text
|
126
|
+
statement.start_date = parse_datetime((doc/"STMTRS/BANKTRANLIST/DTSTART").inner_text)
|
127
|
+
statement.end_date = parse_datetime((doc/"STMTRS/BANKTRANLIST/DTEND").inner_text)
|
128
|
+
acct.statement = statement
|
129
|
+
|
130
|
+
statement.transactions = (doc/"STMTRS/BANKTRANLIST/STMTTRN").collect do |t|
|
131
|
+
build_transaction(t)
|
132
|
+
end
|
133
|
+
|
134
|
+
acct
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.build_credit(doc)
|
138
|
+
acct = CreditAccount.new
|
139
|
+
|
140
|
+
acct.number = (doc/"CCSTMTRS/CCACCTFROM/ACCTID").inner_text
|
141
|
+
acct.transaction_uid = (doc/"TRNUID").inner_text.strip
|
142
|
+
acct.balance = (doc/"CCSTMTRS/LEDGERBAL/BALAMT").inner_text
|
143
|
+
acct.balance_date = parse_datetime((doc/"CCSTMTRS/LEDGERBAL/DTASOF").inner_text)
|
144
|
+
acct.remaining_credit = (doc/"CCSTMTRS/AVAILBAL/BALAMT").inner_text
|
145
|
+
acct.remaining_credit_date = parse_datetime((doc/"CCSTMTRS/AVAILBAL/DTASOF").inner_text)
|
146
|
+
|
147
|
+
statement = Statement.new
|
148
|
+
statement.currency = (doc/"CCSTMTRS/CURDEF").inner_text
|
149
|
+
statement.start_date = parse_datetime((doc/"CCSTMTRS/BANKTRANLIST/DTSTART").inner_text)
|
150
|
+
statement.end_date = parse_datetime((doc/"CCSTMTRS/BANKTRANLIST/DTEND").inner_text)
|
151
|
+
acct.statement = statement
|
152
|
+
|
153
|
+
statement.transactions = (doc/"CCSTMTRS/BANKTRANLIST/STMTTRN").collect do |t|
|
154
|
+
build_transaction(t)
|
155
|
+
end
|
156
|
+
|
157
|
+
acct
|
158
|
+
end
|
159
|
+
|
160
|
+
# for credit and bank transactions.
|
161
|
+
def self.build_transaction(t)
|
162
|
+
transaction = Transaction.new
|
163
|
+
transaction.type = (t/"TRNTYPE").inner_text
|
164
|
+
transaction.date = parse_datetime((t/"DTPOSTED").inner_text)
|
165
|
+
transaction.amount = (t/"TRNAMT").inner_text
|
166
|
+
transaction.fit_id = (t/"FITID").inner_text
|
167
|
+
transaction.payee = (t/"PAYEE").inner_text + (t/"NAME").inner_text
|
168
|
+
transaction.memo = (t/"MEMO").inner_text
|
169
|
+
transaction.sic = (t/"SIC").inner_text
|
170
|
+
transaction.check_number = (t/"CHECKNUM").inner_text if transaction.type == :CHECK
|
171
|
+
transaction
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
def self.build_investment(doc)
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
def self.build_status(doc)
|
180
|
+
status = Status.new
|
181
|
+
status.code = (doc/"CODE").inner_text
|
182
|
+
status.severity = (doc/"SEVERITY").inner_text
|
183
|
+
status.message = (doc/"MESSAGE").inner_text
|
184
|
+
status
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
end
|
data/ofx-parser.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "ofx_parser"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "ofx_parser"
|
7
|
+
s.version = OfxParser::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Andrew A. Smith", "Armand du Plessis"]
|
10
|
+
s.email = ["adp@bank.io"]
|
11
|
+
s.homepage = "http://ofx-parser.rubyforge.org/"
|
12
|
+
s.summary = %q{ofx-parser is an OFX 1.x parser written in Ruby. Forked from original ofx-parser gem to remove UK monetary support}
|
13
|
+
s.description = %q{ofx-parser is an OFX 1.x parser written in Ruby. Forked from original ofx-parser gem to remove UK monetary support}
|
14
|
+
|
15
|
+
s.rubyforge_project = "ofx_parser"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_runtime_dependency 'hpricot'
|
23
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,87 @@
|
|
1
|
+
OFXHEADER:100
|
2
|
+
DATA:OFXSGML
|
3
|
+
VERSION:102
|
4
|
+
SECURITY:NONE
|
5
|
+
ENCODING:USASCII
|
6
|
+
CHARSET:1252
|
7
|
+
COMPRESSION:NONE
|
8
|
+
OLDFILEUID:
|
9
|
+
NEWFILEUID:NONE
|
10
|
+
|
11
|
+
<OFX>
|
12
|
+
<SIGNONMSGSRSV1>
|
13
|
+
<SONRS>
|
14
|
+
<STATUS>
|
15
|
+
<CODE>0</CODE>
|
16
|
+
<SEVERITY>INFO</SEVERITY>
|
17
|
+
<MESSAGE>The user is authentic; operation succeeded.</MESSAGE>
|
18
|
+
</STATUS>
|
19
|
+
<DTSERVER>20070623142635.169[-5:CDT]</DTSERVER>
|
20
|
+
<LANGUAGE>ENG</LANGUAGE>
|
21
|
+
<FI>
|
22
|
+
<ORG>U.S. Bank</ORG>
|
23
|
+
<FID>1402</FID>
|
24
|
+
</FI>
|
25
|
+
<INTU.BID>1402</INTU.BID>
|
26
|
+
</SONRS>
|
27
|
+
</SIGNONMSGSRSV1>
|
28
|
+
<BANKMSGSRSV1>
|
29
|
+
<STMTTRNRS>
|
30
|
+
<TRNUID>9C24229A0077EAA50000011353C9E00743FC</TRNUID>
|
31
|
+
<STATUS>
|
32
|
+
<CODE>0</CODE>
|
33
|
+
<SEVERITY>INFO</SEVERITY>
|
34
|
+
</STATUS>
|
35
|
+
<STMTRS>
|
36
|
+
<CURDEF>USD</CURDEF>
|
37
|
+
<BANKACCTFROM>
|
38
|
+
<BANKID>033000033</BANKID>
|
39
|
+
<ACCTID>103333333333</ACCTID>
|
40
|
+
<ACCTTYPE>CHECKING</ACCTTYPE>
|
41
|
+
</BANKACCTFROM>
|
42
|
+
<BANKTRANLIST>
|
43
|
+
<DTSTART>20070604190000.000[-5:CDT]</DTSTART>
|
44
|
+
<DTEND>20070622190000.000[-5:CDT]</DTEND>
|
45
|
+
<STMTTRN>
|
46
|
+
<TRNTYPE>PAYMENT</TRNTYPE>
|
47
|
+
<DTPOSTED>20070606120000.000</DTPOSTED>
|
48
|
+
<TRNAMT>-11.11</TRNAMT>
|
49
|
+
<FITID>11111111 22</FITID>
|
50
|
+
<NAME>WEB AUTHORIZED PMT FOO INC</NAME>
|
51
|
+
<MEMO>Download from usbank.com. FOO INC</MEMO>
|
52
|
+
</STMTTRN>
|
53
|
+
<STMTTRN>
|
54
|
+
<TRNTYPE>CHECK</TRNTYPE>
|
55
|
+
<DTPOSTED>20070607120000.000</DTPOSTED>
|
56
|
+
<TRNAMT>-111.11</TRNAMT>
|
57
|
+
<FITID>22222A</FITID>
|
58
|
+
<CHECKNUM>0000009611</CHECKNUM>
|
59
|
+
<NAME>CHECK</NAME>
|
60
|
+
<MEMO>Download from usbank.com.</MEMO>
|
61
|
+
</STMTTRN>
|
62
|
+
<STMTTRN>
|
63
|
+
<TRNTYPE>DIRECTDEP</TRNTYPE>
|
64
|
+
<DTPOSTED>20070614120000.000</DTPOSTED>
|
65
|
+
<TRNAMT>1111.11</TRNAMT>
|
66
|
+
<FITID>X34AE33</FITID>
|
67
|
+
<NAME>ELECTRONIC DEPOSIT BAR INC</NAME>
|
68
|
+
<MEMO>Download from usbank.com. BAR INC</MEMO>
|
69
|
+
</STMTTRN>
|
70
|
+
<STMTTRN>
|
71
|
+
<TRNTYPE>CREDIT</TRNTYPE>
|
72
|
+
<DTPOSTED>20070619120000.000</DTPOSTED>
|
73
|
+
<TRNAMT>11.11</TRNAMT>
|
74
|
+
<FITID>8 8 9089743</FITID>
|
75
|
+
<NAME>ATM DEPOSIT US BANK ANYTOWNAS</NAME>
|
76
|
+
<MEMO>Download from usbank.com. US BANK ANYTOWN ASUS1</MEMO>
|
77
|
+
</STMTTRN>
|
78
|
+
</BANKTRANLIST>
|
79
|
+
<LEDGERBAL>
|
80
|
+
<BALAMT>1234.09</BALAMT>
|
81
|
+
<DTASOF>20070623142635.369[-5:CDT]</DTASOF>
|
82
|
+
</LEDGERBAL>
|
83
|
+
</STMTRS>
|
84
|
+
</STMTTRNRS>
|
85
|
+
</BANKMSGSRSV1>
|
86
|
+
</OFX>
|
87
|
+
|
@@ -0,0 +1,79 @@
|
|
1
|
+
OFXHEADER:100
|
2
|
+
DATA:OFXSGML
|
3
|
+
VERSION:102
|
4
|
+
SECURITY:NONE
|
5
|
+
ENCODING:USASCII
|
6
|
+
CHARSET:1252
|
7
|
+
COMPRESSION:NONE
|
8
|
+
OLDFILEUID:NONE
|
9
|
+
NEWFILEUID:NONE
|
10
|
+
|
11
|
+
<OFX>
|
12
|
+
<SIGNONMSGSRSV1>
|
13
|
+
<SONRS>
|
14
|
+
<STATUS>
|
15
|
+
<CODE>0</CODE>
|
16
|
+
<SEVERITY>INFO</SEVERITY>
|
17
|
+
</STATUS>
|
18
|
+
<DTSERVER>20070623192010</DTSERVER>
|
19
|
+
<LANGUAGE>ENG</LANGUAGE>
|
20
|
+
<FI>
|
21
|
+
<ORG>Citigroup</ORG>
|
22
|
+
<FID>24909</FID>
|
23
|
+
</FI>
|
24
|
+
<INTU.BID>24909</INTU.BID>
|
25
|
+
</SONRS>
|
26
|
+
</SIGNONMSGSRSV1>
|
27
|
+
<CREDITCARDMSGSRSV1>
|
28
|
+
<CCSTMTTRNRS>
|
29
|
+
<TRNUID>0</TRNUID>
|
30
|
+
<STATUS>
|
31
|
+
<CODE>0</CODE>
|
32
|
+
<SEVERITY>INFO</SEVERITY>
|
33
|
+
</STATUS>
|
34
|
+
<CCSTMTRS>
|
35
|
+
<CURDEF>USD</CURDEF>
|
36
|
+
<CCACCTFROM>
|
37
|
+
<ACCTID>XXXXXXXXXXXX1111</ACCTID>
|
38
|
+
</CCACCTFROM>
|
39
|
+
<BANKTRANLIST>
|
40
|
+
<DTSTART>20070509120000</DTSTART>
|
41
|
+
<DTEND>20070608120000</DTEND>
|
42
|
+
<STMTTRN>
|
43
|
+
<TRNTYPE>DEBIT</TRNTYPE>
|
44
|
+
<DTPOSTED>20070510170000</DTPOSTED>
|
45
|
+
<TRNAMT>-19.17</TRNAMT>
|
46
|
+
<FITID>xx</FITID>
|
47
|
+
<SIC>5912</SIC>
|
48
|
+
<NAME>WALGREEN 34638675 ANYTOWN</NAME>
|
49
|
+
</STMTTRN>
|
50
|
+
<STMTTRN>
|
51
|
+
<TRNTYPE>DEBIT</TRNTYPE>
|
52
|
+
<DTPOSTED>20070512170000</DTPOSTED>
|
53
|
+
<TRNAMT>-12.0</TRNAMT>
|
54
|
+
<FITID>yy-56</FITID>
|
55
|
+
<SIC>7933</SIC>
|
56
|
+
<NAME>SUNSET BOWL ANYTOWN</NAME>
|
57
|
+
</STMTTRN>
|
58
|
+
<STMTTRN>
|
59
|
+
<TRNTYPE>CREDIT</TRNTYPE>
|
60
|
+
<DTPOSTED>20070526170000</DTPOSTED>
|
61
|
+
<TRNAMT>11.01</TRNAMT>
|
62
|
+
<FITID>78-9</FITID>
|
63
|
+
<SIC>0000</SIC>
|
64
|
+
<NAME>ELECTRONIC PAYMENT-THANK YOU</NAME>
|
65
|
+
</STMTTRN>
|
66
|
+
</BANKTRANLIST>
|
67
|
+
<LEDGERBAL>
|
68
|
+
<BALAMT>-1111.01</BALAMT>
|
69
|
+
<DTASOF>20070623192013</DTASOF>
|
70
|
+
</LEDGERBAL>
|
71
|
+
<AVAILBAL>
|
72
|
+
<BALAMT>19000.99</BALAMT>
|
73
|
+
<DTASOF>20070623192013</DTASOF>
|
74
|
+
</AVAILBAL>
|
75
|
+
</CCSTMTRS>
|
76
|
+
</CCSTMTTRNRS>
|
77
|
+
</CREDITCARDMSGSRSV1>
|
78
|
+
</OFX>
|
79
|
+
|