diff options
| -rwxr-xr-x | overlays/worktime/worktime.py | 57 |
1 files changed, 50 insertions, 7 deletions
diff --git a/overlays/worktime/worktime.py b/overlays/worktime/worktime.py index 310fa084..166bea1c 100755 --- a/overlays/worktime/worktime.py +++ b/overlays/worktime/worktime.py | |||
| @@ -46,9 +46,10 @@ class TogglAPIError(Exception): | |||
| 46 | return self.response.text | 46 | return self.response.text |
| 47 | 47 | ||
| 48 | class TogglAPI(object): | 48 | class TogglAPI(object): |
| 49 | def __init__(self, api_token, workspace_id): | 49 | def __init__(self, api_token, workspace_id, client_ids): |
| 50 | self._api_token = api_token | 50 | self._api_token = api_token |
| 51 | self._workspace_id = workspace_id | 51 | self._workspace_id = workspace_id |
| 52 | self._client_ids = set(map(int, client_ids.split(','))) if client_ids else None | ||
| 52 | 53 | ||
| 53 | def _make_url(self, api=TogglAPISection.TOGGL, section=['time_entries', 'current'], params={}): | 54 | def _make_url(self, api=TogglAPISection.TOGGL, section=['time_entries', 'current'], params={}): |
| 54 | if api is TogglAPISection.REPORTS: | 55 | if api is TogglAPISection.REPORTS: |
| @@ -87,11 +88,35 @@ class TogglAPI(object): | |||
| 87 | elif req_start > start_date: | 88 | elif req_start > start_date: |
| 88 | req_start = datetime.combine(req_start.astimezone(timezone.utc).date(), time(tzinfo=timezone.utc)) + timedelta(days = 1) | 89 | req_start = datetime.combine(req_start.astimezone(timezone.utc).date(), time(tzinfo=timezone.utc)) + timedelta(days = 1) |
| 89 | 90 | ||
| 90 | url = self._make_url(api = TogglAPISection.REPORTS, section = ['summary'], params={'since': req_start.astimezone(timezone.utc).isoformat(), 'until': req_end.astimezone(timezone.utc).isoformat(), 'rounding': rounding}) | 91 | def get_report(client_ids = self._client_ids): |
| 91 | r = self._query(url = url, method='GET') | 92 | nonlocal req_start, req_end, rounding, self |
| 92 | if not r or not r.json(): | 93 | |
| 93 | raise TogglAPIError(r) | 94 | if client_ids is not None and not client_ids: |
| 94 | billable_acc += timedelta(milliseconds=r.json()['total_billable']) if r.json()['total_billable'] else timedelta(milliseconds=0) | 95 | return timedelta(milliseconds = 0) |
| 96 | |||
| 97 | params = { 'since': req_start.astimezone(timezone.utc).isoformat(), | ||
| 98 | 'until': req_end.astimezone(timezone.utc).isoformat(), | ||
| 99 | 'rounding': rounding, | ||
| 100 | 'billable': 'yes' | ||
| 101 | } | ||
| 102 | if client_ids is not None: | ||
| 103 | params |= { 'client_ids': ','.join(map(str, client_ids)) } | ||
| 104 | url = self._make_url(api = TogglAPISection.REPORTS, section = ['summary'], params = params) | ||
| 105 | r = self._query(url = url, method='GET') | ||
| 106 | if not r or not r.json(): | ||
| 107 | raise TogglAPIError(r) | ||
| 108 | res = timedelta(milliseconds=r.json()['total_billable']) if r.json()['total_billable'] else timedelta(milliseconds=0) | ||
| 109 | return res | ||
| 110 | |||
| 111 | if 0 in self._client_ids: | ||
| 112 | url = self._make_url(api = TogglAPISection.TOGGL, section = ['workspaces', self._workspace_id, 'clients']) | ||
| 113 | r = self._query(url = url, method = 'GET') | ||
| 114 | if not r or not r.json(): | ||
| 115 | raise TogglAPIError(r) | ||
| 116 | |||
| 117 | billable_acc += get_report(None) - get_report(set(map(lambda c: c['id'], r.json()))) | ||
| 118 | |||
| 119 | billable_acc += get_report(self._client_ids - {0}) | ||
| 95 | 120 | ||
| 96 | return billable_acc | 121 | return billable_acc |
| 97 | 122 | ||
| @@ -105,6 +130,24 @@ class TogglAPI(object): | |||
| 105 | if not r.json()['data'] or not r.json()['data']['billable']: | 130 | if not r.json()['data'] or not r.json()['data']['billable']: |
| 106 | return None | 131 | return None |
| 107 | 132 | ||
| 133 | if self._client_ids is not None: | ||
| 134 | if 'pid' in r.json()['data'] and r.json()['data']['pid']: | ||
| 135 | url = self._make_url(api = TogglAPISection.TOGGL, section = ['projects', str(r.json()['data']['pid'])]) | ||
| 136 | pr = self._query(url = url, method = 'GET') | ||
| 137 | if not pr or not pr.json(): | ||
| 138 | raise TogglAPIError(pr) | ||
| 139 | |||
| 140 | if not pr.json()['data']: | ||
| 141 | return None | ||
| 142 | |||
| 143 | if 'cid' in pr.json()['data'] and pr.json()['data']['cid']: | ||
| 144 | if pr.json()['data']['cid'] not in self._client_ids: | ||
| 145 | return None | ||
| 146 | elif 0 not in self._client_ids: | ||
| 147 | return None | ||
| 148 | elif 0 not in self._client_ids: | ||
| 149 | return None | ||
| 150 | |||
| 108 | start = isoparse(r.json()['data']['start']) | 151 | start = isoparse(r.json()['data']['start']) |
| 109 | 152 | ||
| 110 | return now - start if start <= now else None | 153 | return now - start if start <= now else None |
| @@ -170,7 +213,7 @@ class Worktime(object): | |||
| 170 | 213 | ||
| 171 | config = Worktime.config() | 214 | config = Worktime.config() |
| 172 | config_dir = BaseDirectory.load_first_config('worktime') | 215 | config_dir = BaseDirectory.load_first_config('worktime') |
| 173 | api = TogglAPI(api_token=config['TOGGL']['ApiToken'], workspace_id=config['TOGGL']['Workspace']) | 216 | api = TogglAPI(api_token=config['TOGGL']['ApiToken'], workspace_id=config['TOGGL']['Workspace'], client_ids=config.get('TOGGL', 'ClientIds', fallback=None)) |
| 174 | date_format = config.get('WORKTIME', 'DateFormat', fallback='%Y-%m-%d') | 217 | date_format = config.get('WORKTIME', 'DateFormat', fallback='%Y-%m-%d') |
| 175 | 218 | ||
| 176 | start_date = start_datetime or datetime.strptime(config['WORKTIME']['StartDate'], date_format).replace(tzinfo=tzlocal()) | 219 | start_date = start_datetime or datetime.strptime(config['WORKTIME']['StartDate'], date_format).replace(tzinfo=tzlocal()) |
