Last active
March 2, 2020 20:43
-
-
Save jhargis/7239063 to your computer and use it in GitHub Desktop.
Python based timesheet report generation utility for toggl.com api This generates CSV and HTML files from an api call filtered on client and date range.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import os | |
import csv | |
import sys | |
import datetime | |
import string | |
import requests | |
# replace these: API_KEY, CLIENTNAME1, CLIENTNAME2 , CLIENT_ID1, CLIENT_ID2 , WORKSPACE_ID | |
if len(sys.argv) < 4 : | |
sys.stderr.write("usage: timesheet-processor.py <client name> <since date> <until date>\n" ) | |
sys.stderr.write("produces to files. hours.csv and hours.html in current directory\n") | |
sys.stderr.write("Clients [CLIENTNAME1, CLIENTNAME2]. Date format [YYYY-MM-DD]\n" ) # replace here | |
sys.stderr.write("""example: pull-toggl-timesheet.py CLIENTNAME1 2013-10-14 2013-10-20\n""") # replace here | |
sys.exit() | |
CLIENT = sys.argv[1].lower() | |
if CLIENT == 'CLIENTNAME1': # replace here | |
CLIENT = 'CLIENT_ID1' # replace here | |
elif CLIENT == 'CLIENTNAME2': # replace here | |
CLIENT == 'CLIENT_ID2' # replace here | |
else: | |
sys.stderr.write("Unknown client; valid clients:(CLIENTNAME1, CLIENTNAME2)\n") # replace here | |
sys.exit() | |
SINCE = sys.argv[2] # 2013-10-28 | |
UNTIL = sys.argv[3] # 2013-10-31 | |
WORKSPACE_ID = 'XXXXXXX' # replace here | |
API_KEY = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' # replace here | |
API_URL = 'https://toggl.com/reports/api/v2/details?workspace_id=%s&since=%s&until=%s&user_agent=api_test&client_ids=%s,' % (WORKSPACE_ID, SINCE, UNTIL, CLIENT) | |
CWD = os.path.abspath(os.curdir) | |
out_file_csv = CWD + '/hours.csv' | |
out_file_html = CWD + '/hours.html' | |
def call_api(page=None): | |
url = API_URL | |
if page: | |
url = url + '&page=%s' % page | |
data = requests.get(url, auth=(API_KEY, 'api_token')) | |
if data.status_code != 200: | |
sys.stderr.write("API error status_code: %s" % data.status_code) | |
return data.json() | |
datadict = call_api() | |
# load multiple pages if necessary | |
total_count = int(datadict['total_count']) | |
if total_count > 50: | |
loop_count = total_count / 50 | |
remainder = total_count % 50 | |
if remainder > 0: | |
loop_count = loop_count + 1 | |
for i in range(2, loop_count + 1): | |
dd = call_api(i) | |
datadict['data'].extend(dd['data']) | |
# reverse the data - oldest date first | |
line_list = [] | |
for line in datadict['data']: | |
line_list.append(line) | |
line_list.reverse() | |
def humanize_secs(seconds=0, milliseconds=0): | |
td = datetime.timedelta(seconds=seconds, milliseconds=milliseconds) | |
total_seconds = int(td.total_seconds()) | |
hours, remainder = divmod(total_seconds,60*60) | |
minutes, seconds = divmod(remainder,60) | |
hours = "%02d" % hours | |
minutes = "%02d" % minutes | |
seconds = "%02d" % seconds | |
return ':'.join([str(hours),str(minutes),str(seconds)]) | |
# get total duration | |
total_duration = datetime.timedelta(seconds=0) | |
for row in line_list: | |
total_duration = total_duration + datetime.timedelta(milliseconds=int(row['dur'])) | |
total_duration = humanize_secs(seconds=total_duration.total_seconds()) | |
# write new csv format | |
with open(out_file_csv, 'wb') as f: | |
writer = csv.writer(f) | |
# write header line | |
writer.writerow(["Project Task", "Description", "Start Date", "End Date", "Duration"]) | |
for row in line_list: | |
writer.writerow([row['project'], row['description'], row['start'], row['end'], humanize_secs(milliseconds=int(row['dur']))]) | |
writer.writerow(["", "", "", "", ""]) | |
writer.writerow(["", "", "", "", ""]) | |
writer.writerow(["", "", "", "total:", total_duration]) | |
# build html | |
with open(out_file_csv, 'rb') as csvfile: | |
table_string = """<html> | |
<head> | |
<style type="text/css"> | |
html { font: 4px, Verdana, Arial, 'sans-serif'; } | |
table.myTable { border-collapse:collapse; } | |
table.myTable td, table.myTable th { border:1px solid #CCC; padding:5px; } | |
</style> | |
</head> | |
<body> | |
<table class="myTable" cellspacing="3">""" | |
reader = csv.reader(csvfile) | |
for row in reader: | |
table_string += "<tr>" + \ | |
"<td>" + \ | |
string.join( row, "</td><td>" ) + \ | |
"</td>" + \ | |
"</tr>\n" | |
table_string += "</table></body></html>" | |
with open(out_file_html, 'w') as fh: | |
fh.write(table_string) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment