My favorites | Sign in
Project Logo
                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#!/usr/bin/env python
import sys
import csv
import os
import base64
import getpass
import getopt
import platform
import re
import urllib
import urllib2
import xml.etree.ElementTree as ET

client_id = "Abn2Wesabe-Uploader" # Change this to the name of your application
client_version = "0.2" # Give your application a version number
system_name = platform.system()
system_release = platform.release()
api_version = "1.0.0" # Document which API version you're using

user_agent = "%s/%s (%s %s) Wesabe-API/%s" % \
(client_id, client_version, system_name, system_release,
api_version)
accounts_list = {}
accounts_url = "https://www.wesabe.com/accounts.xml"
upload_url = "https://api.wesabe.com/rest/upload/statement"

# Functions and classes

def ask_for_credentials():
sys.stdout.write("Wesabe username: ")
username = sys.stdin.readline().rstrip()
password = getpass.getpass("Password: ")
return (username, password)

def ask_for_accid():
sys.stdout.write("Id of the account to be updated: ")
id = sys.stdin.readline().rstrip()
return id

def get_accounts_list(username, password):
credentials = base64.encodestring('%s:%s' % (username, password))[:-1]
request = urllib2.Request(accounts_url)
request.add_header("User-Agent", user_agent)
request.add_header("Authorization", "Basic %s" % credentials)

stream = urllib2.urlopen(request)
response = stream.read()
stream.close()

return [
{
'id' : account.find('id').text,
'number' : account.find('account-number').text,
'type' : account.find('account-type').text,
'wesabe_id' : account.find('financial-institution').find('id').text,
'name' : account.find('name').text,
'balance' : account.find('current-balance').text
}
# Filtering out the Cash accounts
for account in ET.fromstring(response).findall('account')
if account.find('account-type').text != 'Cash'
]

def upload_data(xml, acctid, accttype, balance, wesabe_id, username, password):
root = ET.Element('upload')
statement = ET.SubElement(root, 'statement', acctid=acctid, accttype=accttype, balance=balance, wesabe_id=wesabe_id)
statement.text = xml
credentials = base64.encodestring('%s:%s' % (username, password))[:-1]
headers = {
"Authorization" : "Basic %s" % credentials,
"User-Agent" : user_agent,
"Content-type" : "application/xml",
"Accept" : "*/* application/xml"
}
request = urllib2.Request(upload_url, ET.tostring(root), headers)
return urllib2.urlopen(request).read()

##
# The following function uses part of the "ABN Amro 2 QIF Converter" by Johan Kool.
# More information at http://www.johankool.nl/software/abnamro2qif/
#
# It converts ABN AMRO bank statements into qif files.
#
# @param inputfile The statement file generated by the bank
# @param tempfile Temporary file
# @return string containing the QIF converted statement

def convert2qif(inputfile_name):
output = "!Type:Bank\n"
inputfile = open(inputfile_name, 'rb')
tempfile_name = inputfile_name + '.temp'
tempfile = open(tempfile_name, 'w')

class Custom(csv.excel_tab):
skipinitialspace = True
delimiter = '\t'

csv.register_dialect('custom', Custom)

# add account currency date1 misc1 misc2 date2 amount description line to inputfile
tempfile.write("account\tcurrency\tdate1\tmisc1\tmisc2\tdate2\tamount\tdescription\r\n")

# zap useless ascii control characters
identity_map = ''.join([chr(x) for x in range(256)])
bad_map = ''.join([chr(x) for x in range(8)] + [chr(x) for x in range(11,32)] + [chr(124)])

clean_text = inputfile.read().translate(identity_map, bad_map)

tempfile.write(clean_text)
tempfile.close()

tempfile = open(tempfile_name, 'rb')

reader = csv.DictReader(tempfile, dialect='custom')

for row in reader:
# convert date from yyyymmdd to dd/mm/yyyy
date = row["date1"][6:8]+"/"+row["date1"][4:6]+"/"+row["date1"][0:4]
# convert amount from -nnn,nn to -nnn.nn
amount = row["amount"].replace(",",".")
data = "D%s\nP%s\nT%s\n^\n" % (date, row["description"], amount)
output += data

# cleanup temp file
os.remove(tempfile_name)
return output

def uploadFile(username, password, inputfile_name):
finalbalance = ''
for account in get_accounts_list(username, password):
accounts_list[account['id']] = account
print "%s:\t%s\t%s" % (account['id'], account['name'], account['balance'])

chosen_acc = ask_for_accid()
if (chosen_acc in accounts_list):
print "Uploading data to Wesabe account..."
try:
# Get current final balance from bank statement
inputfile = open(inputfile_name, 'rb')
r = re.compile("^\d+\s[A-Z]{3}\s\d{8}\s[\d,]+\s(\d+,\d+)")
finalbalance = re.match(r, inputfile.read()).group(1)
inputfile.close()
except:
print >>sys.stderr, "\Warning:\nThe final balance could not be retrieved."

acc = accounts_list[chosen_acc]
return upload_data(convert2qif(inputfile_name),
acc['number'],
acc['type'],
finalbalance.replace(',', '.'),
acc['wesabe_id'],
username, password)
else:
return ''

def main(argv=None):
if argv is None:
argv = sys.argv

if len(argv) < 2:
print >>sys.stderr, "No statement file provided\nUsage: abn2wesabe STATEMENTFILE.TAB"
sys.exit()

inputfile_name = argv[1]
accountlist = ''
while 1:
try:
(username, password) = ask_for_credentials()
accountlist = uploadFile(username, password, inputfile_name)
if not accountlist == '':
if ET.fromstring(accountlist).get('status') == 'failed':
print >>sys.stderr, "Error: Wesabe could not process the transaction."
else:
print "Success!"
break
else:
print >>sys.stderr, "\nError:\nWrong account ID. Try again."
except urllib2.HTTPError, ex:
if (ex.code == 401):
print >>sys.stderr, "The username and password combination is not valid, try again."
except:
print >>sys.stderr, "Unexpected error: ", sys.exc_info()[0]
break

if __name__ == "__main__":
sys.exit(main())
Show details Hide details

Change log

r5 by sergi.mansilla on Feb 25, 2009   Diff
Deleted some debug messages and fixed
informative message at the end
Go to: 

Older revisions

r4 by sergi.mansilla on Feb 25, 2009   Diff
Now it submits the correct Accound ID
and parses the current account balance
from the input file
r2 by sergi.mansilla on Feb 24, 2009   Diff
Initial commit
All revisions of this file

File info

Size: 6773 bytes, 186 lines

File properties

svn:executable
*
Hosted by Google Code