-
Notifications
You must be signed in to change notification settings - Fork 0
/
io_txt.py
177 lines (139 loc) · 4.49 KB
/
io_txt.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
import os
import StringIO
import cPickle
def replace_in_file(old_f, encoding='utf-8'):
"""Just replacing fancy quotes, for now."""
new_f = StringIO.StringIO()
for old_line in old_f:
new_f.write(
old_line.\
decode(encoding).\
replace(u'\u201c', '"').\
replace(u'\u201d', '"').\
encode(encoding)
)
new_f.seek(0)
return new_f
def get_report_name(invoice):
return '{:%Y%m%d}_{:%Y%m%d}_{}'.format(
invoice.payperiod_start, invoice.payperiod_end, invoice.company)
def get_invoice_path(invoice):
return 'io/fs/invoices/{}.pkl'.format(invoice.id)
def get_report_path(invoice):
return 'io/fs/reports/{}.txt'.format(get_report_name(invoice))
def print_hours_for_ken(invoice):
print_str = invoice.company + '\n'
grand_total = 0
for job_id in sorted(invoice.job_ids.keys()):
print_str += invoice.jobs.get_name_by_id(job_id) + ':\n'
entries = invoice.job_ids[job_id]
job_hours = 0
for entry in entries:
# like, Fr 02/01/19: 1.5
dt = entry.dt
day_date = '{} {}'.format(
dt.strftime('%a')[:2], dt.strftime('%m/%d/%y')
)
print_str += '{}: {:.4g}\n'.format(day_date, entry.hours)
job_hours += entry.hours
print_str += '----\n'
print_str += 'total: {:.5g}\n\n'.format(job_hours)
grand_total += job_hours
print_str += '----\n'
print_str += 'total: {:.5g}\n\n'.format(grand_total)
return print_str
def print_entries(invoice):
print_str = ''
for entry in invoice.entries:
print_str += str(entry) + '\n'
total = invoice.hours_total
invoiced = invoice.invoiced_dt
payment_due = invoice.payment_dt
gross_pay = total * invoice.jobs.wage
print_str += '\nTotal: {} | Invoiced: {} | Payment due: {} | Gross $: {}'.format(
total, invoiced, payment_due, gross_pay
)
print_str += '\n----\n'
return print_str
def open_invoice(path):
return unpickle(path)
def write_invoice(invoice):
path = get_invoice_path(invoice)
if os.path.exists(path):
raise IOError(1024, 'File already exists: %s' % path)
pickle(invoice, path)
def write_report(invoice):
path = get_report_path(invoice)
with open(path, 'w') as f:
f.write(print_hours_for_ken(invoice))
f.write(print_entries(invoice))
def parse_entries_from_note(note_data, jobs):
from time_entry import TimeEntry
def _assert_field_count(row, field_count):
assert len(row) == field_count, \
'Expected %s field(s) in row, got %d: %s' % (field_count, len(row), row)
def cast_date(s):
if not s:
return None
mo, day, yr = map(int, s.split('/'))
return datetime.datetime(2000 + yr, mo, day)
def cast_float(s):
if not s:
return None
return float(s)
def cast_int(s):
if not s:
return None
return int(s)
def _unicode(s):
if not s:
return None
return unicode(s, 'utf-8')
def _job_id(s):
if not s:
return None
id_or_name = _unicode(s)
if jobs.get_name_by_id(id_or_name):
return id_or_name
job_id = jobs.get_id_by_name(id_or_name)
if job_id:
return job_id
return None
import csv
import datetime
if not note_data.read().strip():
raise ValueError('no data in note_data')
note_data.seek(0)
note_data = replace_in_file(note_data)
reader = csv.reader(note_data, delimiter=',', quotechar='"')
entries = []
for row in reader:
if not row:
continue
_assert_field_count(row, 5)
entries.append(TimeEntry(
cast_float(row[0]),
cast_date(row[1]),
_unicode(row[2]),
_unicode(row[3]),
_job_id(row[4])
)
)
return entries
def get_entry_name(entry):
return str(entry.id)
def get_entry_path(entry):
return 'io/fs/entries/' + get_entry_name(entry) + '.pkl'
def open_entry(path):
return unpickle(path)
def write_entry(entry):
path = get_entry_path(entry)
if os.path.exists(path):
raise IOError(1024, 'File already exists: %s' % path)
pickle(entry, path)
def unpickle(fname):
with open(fname, 'r+b') as f:
return cPickle.load(f)
def pickle(obj, fname):
with open(fname, 'w+b') as f:
return cPickle.dump(obj, f, protocol=-1)