-
Notifications
You must be signed in to change notification settings - Fork 0
/
webhelper_generate_financial_diff.py
218 lines (187 loc) · 9.38 KB
/
webhelper_generate_financial_diff.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
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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
import datetime
import sys
import os
from webhelper import parse_rules
from webhelper_csv import CSVSpreadsheet
DATE_THRESHOLD = 3 * 24 * 60 * 60
def date_to_sec(date):
split = date.split('/')
if len(split) == 3:
try:
return (datetime.datetime(int(split[2]),int(split[0]),int(split[1])) - datetime.datetime(1970,1,1)).total_seconds()
except ValueError:
return 0
else:
return 0
def main():
verbose = False
spreadsheet_name = "Webhelper"
webhelper_rulefile = os.path.dirname(os.path.realpath(__file__)) + os.sep + "webhelper_rules.txt"
if '-v' in sys.argv:
sys.argv.remove('-v')
verbose = True
if '-n' in sys.argv:
spreadsheet_name = sys.argv[sys.argv.index('-n') + 1]
sys.argv.remove('-n')
sys.argv.remove(spreadsheet_name)
if '-r' in sys.argv:
webhelper_rulefile = sys.argv[sys.argv.index('-r') + 1]
sys.argv.remove('-r')
sys.argv.remove(webhelper_rulefile)
if '-h' in sys.argv or '--help' in sys.argv:
print "Usage: %s [-h] [--help] [-v] [--import-google] [--export-google] [-r <webhelper rule file>] [-n <CSV file prefix or spreadsheet name>]" % (
sys.argv[0],)
sys.exit(1)
import_spreadsheet = None
if '--import-google' in sys.argv:
sys.argv.remove('--import-google')
from webhelper_google import GoogleSpreadsheet
import_spreadsheet = GoogleSpreadsheet(spreadsheet_name)
else:
import_spreadsheet = CSVSpreadsheet(spreadsheet_name)
export_spreadsheet = None
if '--export-google' in sys.argv:
sys.argv.remove('--export-google')
from webhelper_google import GoogleSpreadsheet
# If we have already opened this google spreadsheet, just use the same handle
if import_spreadsheet.__class__ == GoogleSpreadsheet:
export_spreadsheet = import_spreadsheet
else:
export_spreadsheet = GoogleSpreadsheet(spreadsheet_name)
else:
export_spreadsheet = CSVSpreadsheet(spreadsheet_name)
f = open(webhelper_rulefile)
rule = f.read()
f.close()
rules = parse_rules(rule)
values = {}
exportrules = []
for rule in rules:
for step in rule['steps']:
if step['command'].find("export") >= 0 and rule['name'] not in exportrules:
exportrules.append(rule['name'])
for rule in exportrules:
if verbose:
print "Importing %s__financial data from %s" % (rule, import_spreadsheet,)
rows = import_spreadsheet.import_data("%s__financial" % (rule,))
if verbose:
print "Finished importing %s__financial data from %s" % (rule, import_spreadsheet,)
if verbose:
print "Importing %s__financial_recent data from %s" % (rule, import_spreadsheet,)
recentrows = import_spreadsheet.import_data("%s__financial_recent" % (rule,))
if verbose:
print "Finished importing %s__financial_recent data from %s" % (rule, import_spreadsheet,)
if verbose:
print "Reading previous %s__financial_diff data from %s" % (rule, export_spreadsheet,)
data_rows_diff = export_spreadsheet.import_data("%s__financial_diff" % (rule,))
if verbose:
print "Finished reading previous %s__financial_diff data from %s" % (rule, export_spreadsheet,)
lresolved = {}
rresolved = {}
if len(rows) > 1 and len(recentrows) > 1 and rows[0] != recentrows[0]:
print "ERROR: The headers on the data from %s__financial_recent do not match the headers from %s__financial" % (
rule, rule)
continue
# Check for equals
for ind, row in enumerate(recentrows[1:]):
for ind2, row2 in enumerate(rows[1:]):
if row == row2:
lresolved[ind] = ind2
rresolved[ind2] = ind
if len(lresolved.keys()) < len(recentrows) and len(rows) > 1 and len(recentrows) > 1 and "Note" in rows[
0] and "Date" in rows[0] and "Amount" in rows[0]:
# Make header for special Date/Amount/Note case
lnote = recentrows[0].index("Note")
rnote = rows[0].index("Note")
ldate = recentrows[0].index("Date")
rdate = rows[0].index("Date")
lamount = recentrows[0].index("Amount")
ramount = rows[0].index("Amount")
header = ["Change Type", "Date", "Amount", "Note", "New Date", "New Note"]
if len(data_rows_diff) > 0:
if data_rows_diff[0] != header:
print "ERROR: The nature of the data seems to have changed such that we now have Date/Amount/Note but we formerly didn't. Skipping %s__financial." % (
rule,)
continue
else:
data_rows_diff.append(header)
# Check for note-only changes
for ind, row in enumerate(recentrows[1:]):
if lresolved.has_key(ind):
continue
for ind2, row2 in enumerate(rows[1:]):
if rresolved.has_key(ind2):
continue
if row[ldate] == row2[rdate] and row[lamount] == row2[ramount]:
data_rows_diff.append(["Modify", row[ldate], row[lamount], row[lnote], "", row2[rnote]])
lresolved[ind] = ind2
rresolved[ind2] = ind
if len(lresolved.keys()) < len(recentrows):
# Check for date-only changes by a certain threshold
for ind, row in enumerate(recentrows[1:]):
if lresolved.has_key(ind):
continue
for ind2, row2 in enumerate(rows[1:]):
if rresolved.has_key(ind2):
continue
if abs(date_to_sec(row[ldate]) - date_to_sec(row2[rdate])) < DATE_THRESHOLD and row[lamount] == \
row2[ramount] and row[lnote] == row2[rnote]:
data_rows_diff.append(["Modify", row[ldate], row[lamount], row[lnote], row2[rdate], ""])
lresolved[ind] = ind2
rresolved[ind2] = ind
if len(lresolved.keys()) < len(recentrows):
# Check for note and date changes by a certain threshold
for ind, row in enumerate(recentrows[1:]):
if lresolved.has_key(ind):
continue
for ind2, row2 in enumerate(rows[1:]):
if rresolved.has_key(ind2):
continue
if abs(date_to_sec(row[ldate]) - date_to_sec(row2[rdate])) < DATE_THRESHOLD and row[lamount] == \
row2[ramount]:
data_rows_diff.append(
["Modify", row[ldate], row[lamount], row[lnote], row2[rdate], row2[rnote]])
lresolved[ind] = ind2
rresolved[ind2] = ind
elif len(lresolved.keys()) < len(recentrows) or len(rresolved.keys()) < len(rows):
# Make diff header for normal case
header = []
if len(rows) > 1:
header = ["Change Type"] + rows[0]
elif len(recentrows) > 1:
header = ["Change Type"] + recentrows[0]
if "Date" in header and "Amount" in header and "Note" in header:
header.extend(["New Date", "New Note"])
if len(data_rows_diff) > 0:
if data_rows_diff[0] != header:
print "ERROR: The nature of the data seems to have changed such that we now have different columns than we used to. Skipping %s__financial." % (
rule,)
continue
else:
data_rows_diff.append(header)
# Check for deleted rows
for ind, row in enumerate(recentrows[1:]):
if not lresolved.has_key(ind):
data_rows_diff.append(["Delete"] + row)
# Add blank spots to end of row if we are in the special Date/Amount/Note case
if len(data_rows_diff[-1]) < len(data_rows_diff[0]):
data_rows_diff[-1].extend([""] * (len(data_rows_diff[0]) - len(data_rows_diff[-1])))
# Check for new rows
for ind, row in enumerate(rows[1:]):
if not rresolved.has_key(ind):
data_rows_diff.append(["Add"] + row)
# Add blank spots to end of row if we are in the special Date/Amount/Note case
if len(data_rows_diff[-1]) < len(data_rows_diff[0]):
data_rows_diff[-1].extend([""] * (len(data_rows_diff[0]) - len(data_rows_diff[-1])))
if verbose:
print "Exporting %s__financial_diff data to %s" % (rule, export_spreadsheet,)
export_spreadsheet.export_data(data_rows_diff, "%s__financial_diff" % (rule,))
if verbose:
print "Finished exporting %s__financial_diff data to %s" % (rule, export_spreadsheet,)
if verbose:
print "Saving %s__financial_recent data to %s" % (rule, import_spreadsheet,)
import_spreadsheet.export_data(rows, "%s__financial_recent" % (rule,))
if verbose:
print "Finished saving %s__financial_recent data to %s" % (rule, import_spreadsheet,)
if __name__ == "__main__":
main()