-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathQifStatement.py
125 lines (111 loc) · 3.9 KB
/
QifStatement.py
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
#!/usr/bin/python
"""
A simple class to represent a Quicken (QIF) file, and a parser to
load a QIF file into a sequence of those classes.
It's enough to be useful for writing conversions.
"""
from datetime import datetime, date
from decimal import Decimal
import md5
import sys
class QifItem:
def __init__(self):
self.order = ['date', 'amount', 'cleared', 'num', 'payee', 'memo', 'address', 'category', 'categoryInSplit', 'memoInSplit', 'amountOfSplit']
self.date = None
self.amount = None
self.cleared = None
self.num = None
self.payee = None
self.memo = None
self.address = None
self.category = None
self.categoryInSplit = None
self.memoInSplit = None
self.amountOfSplit = None
def show(self):
pass
def __repr__(self):
titles = ','.join(self.order)
tmpstring = ','.join( [str(self.__dict__[field]) for field in self.order] )
tmpstring = tmpstring.replace('None', '')
return titles + "," + tmpstring
def dataString(self):
"""
Returns the data of this QIF without a header row
"""
tmpstring = ','.join( [str(self.__dict__[field]) for field in self.order] )
tmpstring = tmpstring.replace('None', '')
return tmpstring
def parseQif(infile):
"""
Parse a qif file and return a list of entries.
infile should be open file-like object (supporting readline() ).
"""
inItem = False
items = []
curItem = QifItem()
line = infile.readline()
while line != '':
if line[0] == '\n': # blank line
pass
elif line[0] == '^': # end of item
# save the item
items.append(curItem)
curItem = QifItem()
elif line[0] == 'D':
curItem.date = line[1:-1]
elif line[0] == 'T':
curItem.amount = line[1:-1]
elif line[0] == 'C':
curItem.cleared = line[1:-1]
elif line[0] == 'P':
curItem.payee = line[1:-1]
elif line[0] == 'M':
curItem.memo = line[1:-1]
elif line[0] == 'A':
curItem.address = line[1:-1]
elif line[0] == 'L':
curItem.category = line[1:-1]
elif line[0] == 'S':
try:
curItem.categoryInSplit.append(";" + line[1:-1])
except AttributeError:
curItem.categoryInSplit = line[1:-1]
elif line[0] == 'E':
try:
curItem.memoInSplit.append(";" + line[1:-1])
except AttributeError:
curItem.memoInSplit = line[1:-1]
elif line[0] == '$':
try:
curItem.amountInSplit.append(";" + line[1:-1])
except AttributeError:
curItem.amountInSplit = line[1:-1]
else:
# don't recognise this line; ignore it
print >> sys.stderr, "Skipping unknown line:\n", line
line = infile.readline()
return items
class Transaction(object):
def __init__(self, qifItem, indexInStatement):
self.date = datetime.strptime(qifItem.date, '%d/%m/%Y').date()
self.type = 'UNKNOWN'
self.description = ''
self.creditAmount = Decimal(qifItem.amount)
self.memo = qifItem.payee
hash = md5.md5()
for v in [self.date, indexInStatement]:
hash.update(str(v))
self.fitid = hash.hexdigest()
class QifStatement(object):
def __init__(self, qifFile):
self.transactions = [Transaction(entry, i)
for i, entry in enumerate(parseQif(qifFile))]
self.beginDate = min([t.date for t in self.transactions])
self.endDate = max([t.date for t in self.transactions])
if __name__ == "__main__":
# read from stdin and write CSV to stdout
items = parseQif(sys.stdin)
print repr(items[0])
for item in items[1:]:
print item.dataString()