Created
January 25, 2018 22:38
-
-
Save danallison/61afbe4bc1ac3703860448a27442f807 to your computer and use it in GitHub Desktop.
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
import requests | |
import datetime | |
auth_token = '** replace this with your auth token **' | |
def get_time_entries_for_project(project_id, date_range=None): | |
''' | |
Fetches time entries from the API, including suggestions and phases | |
''' | |
base_url = 'https://api.10000ft.com' | |
url = '{0}/api/v1/projects/{1}'.format(base_url, project_id) | |
project = requests.get(url, params={ | |
'auth': auth_token, | |
'fields': 'children', | |
'per_page': 9999 | |
}).json() | |
assignable_ids = [phase['id'] for phase in project['children']['data']] | |
assignable_ids.append(project['id']) | |
time_entries = [] | |
url = '{0}/api/v1/time_entries'.format(base_url) | |
params = { | |
'auth': auth_token, | |
'with_suggestions': 'true', | |
'per_page': 9999 | |
} | |
if date_range: | |
params['from'] = date_range['from'] | |
params['to'] = date_range['to'] | |
for assignable_id in assignable_ids: | |
params['assignable_id'] = assignable_id | |
response = requests.get(url, params).json() | |
time_entries += response['data'] | |
return time_entries | |
def group_time_entries_by(group_attr_name, time_entries, get_group_attr=None): | |
''' | |
This function takes a list of time entries and returns | |
a list of sums of: | |
- confirmed_hours | |
- confirmed_amount | |
- scheduled_hours | |
- scheduled_amount | |
grouped by the return value of get_group_attr | |
''' | |
groups = {} | |
if not get_group_attr: get_group_attr = lambda te: te[group_attr_name] | |
for time_entry in time_entries: | |
attr = get_group_attr(time_entry) | |
attr_key = str(attr) | |
group = groups.get(attr_key) | |
if not group: | |
group = groups[attr_key] = { | |
group_attr_name: attr, | |
'confirmed_hours': 0, | |
'confirmed_amount': 0, | |
'scheduled_hours': 0, | |
'scheduled_amount': 0 | |
} | |
hours = time_entry['hours'] or 0 | |
scheduled_hours = time_entry['scheduled_hours'] or 0 | |
bill_rate = time_entry['bill_rate'] or 0 | |
group['confirmed_hours'] += hours | |
group['confirmed_amount'] += hours * bill_rate | |
group['scheduled_hours'] += scheduled_hours | |
group['scheduled_amount'] += scheduled_hours * bill_rate | |
return list(groups.values()) | |
def get_time_fees_report_for_project(project_id, date_range=None): | |
''' | |
Returns a representation of a time and fees report for a single project, | |
grouped by user_id. | |
''' | |
time_entries = get_time_entries_for_project(project_id, date_range) | |
get_date_user_assignable = lambda te: (te['date'], te['user_id'], te['assignable_id']) | |
summarized_time_entries = group_time_entries_by('date_user_assignable', time_entries, get_date_user_assignable) | |
# Today's date in the format "YYYY-MM-DD" | |
today = str(datetime.date.today()) | |
row_template = { | |
'incurred_hours': 0, | |
'incurred_amount': 0, | |
'past_scheduled_hours': 0, | |
'past_scheduled_amount': 0, | |
'future_scheduled_hours': 0, | |
'future_scheduled_amount': 0 | |
} | |
totals = dict(row_template) | |
user_rows = {} | |
for s_te in summarized_time_entries: | |
date = s_te['date_user_assignable'][0] | |
user_id = s_te['date_user_assignable'][1] | |
user_row = user_rows.get(user_id) | |
if not user_row: | |
user_row = user_rows[user_id] = dict(row_template) | |
user_row['user_id'] = user_id | |
for row in [user_row, totals]: | |
if date <= today: | |
# NOTE The meaning of "incurred" can be different depending on your account settings. | |
# The simplest case is just past confimed time, which is used here. | |
row['incurred_hours'] += s_te['confirmed_hours'] | |
row['incurred_amount'] += s_te['confirmed_amount'] | |
row['past_scheduled_hours'] += s_te['scheduled_hours'] | |
row['past_scheduled_amount'] += s_te['scheduled_amount'] | |
else: | |
row['future_scheduled_hours'] += s_te['scheduled_hours'] | |
row['future_scheduled_amount'] += s_te['scheduled_amount'] | |
return { | |
'project_id': project_id, | |
'rows': list(user_rows.values()), | |
'totals': totals | |
} | |
project_id = 123 | |
# date_range is optional | |
date_range = {'from':'2018-01-01', 'to':'2018-02-01'} | |
get_time_fees_report_for_project(project_id, date_range) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment