-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathreporter.py
153 lines (131 loc) · 5.93 KB
/
reporter.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
import os
import datetime
import json
import tkinter
import tkinter.filedialog
import functools
from log_handler import LogHandler
def select_log():
tkinter.Tk().withdraw()
filename = tkinter.filedialog.askopenfilename(
initialdir=LogHandler.get_log_dir())
assert bool(filename), 'file not selected'
logs = LogHandler.load_month_logs(os.path.basename(filename))
LogHandler.check_logs(logs)
return logs
def select_output():
tkinter.Tk().withdraw()
ext = '.rtf'
filename = tkinter.filedialog.asksaveasfilename(initialdir='.',
filetypes=((ext, ext), ))
assert bool(filename), 'file not selected'
if not filename.endswith(ext):
filename += ext
return filename
def report(path: str, logs: list, name: str, should_hour_per_day: float):
assert len(logs) > 0, 'empty log'
done = set()
timedelta_should_per_day = datetime.timedelta(hours=should_hour_per_day)
duration_in_day = LogHandler.count_duration_per_day(logs)
total_duration = functools.reduce(
lambda s, d: s + d,
(duration for duration in duration_in_day.values()))
def format_cell(content: str):
return f'\\intbl {content} \\cell '
def format_row(log):
date_id = LogHandler.get_date_id(log['from'])
date = date_id if date_id not in done else ''
start = LogHandler.format_clocktime(log['from'])
end = LogHandler.format_clocktime(log['to'])
elapsed = LogHandler.format_duration(log['to'] - log['from'])
elapsed_in_day = LogHandler.format_duration(
duration_in_day[date_id]) if date_id not in done else ''
delta = LogHandler.format_duration_difference(
duration_in_day[date_id],
timedelta_should_per_day) if date_id not in done else ''
content = os.linesep.join([
format_cell(elem)
for elem in [date, start, end, elapsed, elapsed_in_day, delta]
])
done.add(date_id)
return content
cells = [f'\\cellx{r}' for r in (800, 1800, 2800, 3800, 4900, 6000)]
table_head = '\\trowd\\pard\\trqc ' + ' '.join(cells)
with open(path, 'w') as fs:
fs.write('{\\rtf1\\ansi\\deff0' + os.linesep)
fs.write('\\qr \\sb300 {\\loch %s}' %
(LogHandler.format_date(LogHandler.get_now()), ) + os.linesep)
fs.write('\\par\\pard\\sb300\\plain {\\loch Dear %s,}' % (name, ) +
os.linesep)
fs.write(
'\\par\\pard\\sb300\\sa300\\plain {\\loch your working time in %s from %s to %s is as follows:}'
% (LogHandler.get_month_id(logs[0]['from']),
LogHandler.format_date(logs[0]['from']),
LogHandler.format_date(logs[-1]['from'])) + os.linesep)
fs.write('\\par\\pard\\sb100\\sa100\\qc' + os.linesep)
fs.write(
table_head.replace(
'\\cellx', '\\clbrdrt\\brdrth\\clbrdrb\\brdrs\\cellx').replace(
'\\pard', '') + os.linesep)
fs.write(''.join([
f'\\intbl {title} \\cell '
for title in ['Date', 'Start', 'End', 'Elapsed', 'Sum', 'Change']
]) + '\\row' + os.linesep)
for id_log, log in enumerate(logs, 1):
fs.write((table_head if id_log < len(logs) else table_head.
replace('\\cellx', '\\clbrdrb\\brdrth\\cellx')) +
os.linesep)
fs.write(format_row(log) + os.linesep)
fs.write('\\row\\pard' + os.linesep)
fs.write(
'\\par\\pard\\sb100\\plain {\\loch The total working time for the %d days with time tracking is %s, the balance for this period is %s (with %s planned per day).}'
%
(len(duration_in_day), LogHandler.format_duration(total_duration),
LogHandler.format_duration_difference(
total_duration,
datetime.timedelta(hours=(should_hour_per_day *
len(duration_in_day)))),
LogHandler.format_duration(timedelta_should_per_day)) +
os.linesep)
fs.write('\\par\\pard\\sb300\\plain {\\loch Sincerely yours}' +
os.linesep)
fs.write('\\par\\pard\\sb300\\plain {\\loch clock_in}' + os.linesep)
fs.write('}' + os.linesep)
def get_config():
path = '.config'
if not os.path.isfile(path) or set(json.loads(
open(path).read()).keys()) != set(['name', 'hours']):
width = 20
height = 2
root = tkinter.Tk()
tkinter.Label(root,
text='name',
width=width,
height=height,
justify=tkinter.LEFT).pack(side=tkinter.TOP)
text_field_name = tkinter.Text(root, height=height, width=width)
text_field_name.pack(side=tkinter.TOP)
tkinter.Label(root,
text='hours per day',
width=width,
height=height,
justify=tkinter.LEFT).pack(side=tkinter.TOP)
text_field_dura = tkinter.Text(root, height=height, width=width)
text_field_dura.pack(side=tkinter.TOP)
def exec(event):
name = text_field_name.get('1.0', tkinter.END).strip()
hours = text_field_dura.get('1.0', tkinter.END).strip()
with open(path, 'w') as fs:
fs.write(json.dumps({'name': name, 'hours': float(hours)}))
root.destroy()
root.bind('<Return>', exec)
text_field_name.focus()
tkinter.mainloop()
return json.loads(open(path).read())
if __name__ == '__main__':
config = get_config()
logs = select_log()
path = select_output()
name = config['name']
should_hour_per_day = config['hours']
report(path, logs, name, should_hour_per_day)