|
@@ -1,6 +1,10 @@
|
1
|
1
|
# coding=utf-8
|
2
|
2
|
"""Convert Bank statement CSV to Gnucash-acceptable format"""
|
3
|
3
|
|
|
4
|
+from collections import namedtuple
|
|
5
|
+
|
|
6
|
+ParserState = namedtuple('ParserState', 'ths nxt')
|
|
7
|
+
|
4
|
8
|
|
5
|
9
|
def valid_formats():
|
6
|
10
|
return _parsers.keys()
|
|
@@ -53,14 +57,13 @@ class BaseTransactionParser(object):
|
53
|
57
|
|
54
|
58
|
def __init__(self):
|
55
|
59
|
self.transactions = []
|
56
|
|
- self.state = False
|
57
|
|
- self.next_state = False
|
|
60
|
+ self.state = ParserState(ths=False, nxt=False)
|
58
|
61
|
|
59
|
62
|
def is_open(self):
|
60
|
|
- return self.state
|
|
63
|
+ return self.state.ths
|
61
|
64
|
|
62
|
65
|
def is_closed(self):
|
63
|
|
- return not self.state
|
|
66
|
+ return not self.state.ths
|
64
|
67
|
|
65
|
68
|
def parse_file(self, fpath, encoding='utf-8'):
|
66
|
69
|
lines_read = 0
|
|
@@ -68,7 +71,7 @@ class BaseTransactionParser(object):
|
68
|
71
|
for line in f.readlines():
|
69
|
72
|
line = line.decode(encoding).strip()
|
70
|
73
|
lines_read += 1
|
71
|
|
- self.state = self.pick_state(line, lineno=lines_read)
|
|
74
|
+ self.state = self.advance(line, lineno=lines_read)
|
72
|
75
|
if self.is_open():
|
73
|
76
|
self.transactions.append(self.parse_line(line).to_gc())
|
74
|
77
|
|
|
@@ -153,16 +156,14 @@ class MbankTransactionParser(BaseTransactionParser):
|
153
|
156
|
def parse_line(self, line):
|
154
|
157
|
return MbankTransaction(line)
|
155
|
158
|
|
156
|
|
- def pick_state(self, line, lineno=None):
|
|
159
|
+ def advance(self, line, lineno=None):
|
157
|
160
|
"""Choose parser state according to current line and line no."""
|
158
|
|
- if self.next_state:
|
159
|
|
- self.next_state = False
|
160
|
|
- return True
|
|
161
|
+ if self.state.nxt:
|
|
162
|
+ return ParserState(ths=True, nxt=False)
|
161
|
163
|
if self.is_closed() and line.startswith(u'#Datum uskute'):
|
162
|
|
- self.next_state = True
|
163
|
|
- return False
|
|
164
|
+ return ParserState(ths=False, nxt=True)
|
164
|
165
|
if self.is_open() and not line:
|
165
|
|
- return False
|
|
166
|
+ return ParserState(ths=False, nxt=False)
|
166
|
167
|
return self.state
|
167
|
168
|
|
168
|
169
|
|
|
@@ -252,14 +253,12 @@ class FioTransactionParser(BaseTransactionParser):
|
252
|
253
|
def parse_line(self, line):
|
253
|
254
|
return FioTransaction(line)
|
254
|
255
|
|
255
|
|
- def pick_state(self, line, lineno=None):
|
|
256
|
+ def advance(self, line, lineno=None):
|
256
|
257
|
"""Choose parser state according to current line and line no."""
|
257
|
|
- if self.next_state:
|
258
|
|
- self.next_state = False
|
259
|
|
- return True
|
260
|
|
- if self.is_closed() and line.startswith(u'"ID operace";"Datum";'):
|
261
|
|
- self.next_state = True
|
262
|
|
- return False
|
|
258
|
+ if self.state.nxt:
|
|
259
|
+ return ParserState(ths=True, nxt=False)
|
|
260
|
+ if self.is_open() and line.startswith(u'"ID operace";"Datum";'):
|
|
261
|
+ return ParserState(ths=False, nxt=True)
|
263
|
262
|
return self.state
|
264
|
263
|
|
265
|
264
|
|