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()) |