-
-
How to get an API token Click your name in the left bottom corner. Select My Profile in the drop-down list. On the My Profile page, click the Get new API token link. Copy the newly created token and use it to make API requests. Note: An API token will be valid for 1 year. If you generate a new token, the previous one becomes invalid.
-
To get {accountId} value: Open the Time page in the TMetric web app Copy the number from the browser's address line. The only number if the {accountId} parameter value you need.
-
To get {userId} value: Open the Project Summary report in the TMetric web app. Select a user in the dropdown Team filter (don't select the dynamic 'Me' parameter). Apply the filter. You will get the following string in the browser's address line. https://app.tmetric.com/#/reports/2345/projects?range=thismonth&user=7882 Copy the user parameter value from the address line.
-
-
Missing feature: If holiday was requested/approved, then don't write hours during/over that time period.
-
I extended the code to also support timesheets submission:
import time import random import requests from datetime import date, datetime, timedelta class ATmetric: def __init__(self, api_token, user_id, acc_id): self.api_token = api_token self.user_id = user_id self.acc_id = acc_id self.api_url = 'https://app.tmetric.com/api/v3' self.headers = headers = { 'Authorization': f'Bearer {self.api_token}', 'Content-Type': 'application/json' } def _dt_range(self, start_dt, end_dt): for n in range(int((end_dt - start_dt).days) + 1): yield start_dt + timedelta(n) def _dt_weeks_range(self, start_dt, end_dt): for n in range(0, int((end_dt - start_dt).days) + 1, 7): yield start_dt + timedelta(n) def _is_bday(self, dt): return dt.weekday() >= 0 and dt.weekday() <= 4 def _req(self, method, path, params=None, json=None): r = requests.request( method=method, url=f'{self.api_url}/accounts/{self.acc_id}/{path}', params=params, json=json, headers=self.headers ) #print(r, f'{self.api_url}/accounts/{self.acc_id}/{path}') return r.json() def _get(self, path, params=None): return self._req('GET', path=path, params=params) def _post(self, path, params=None, json=None): return self._req('POST', path=path, params=params, json=json) def _put(self, path, params=None, json=None): return self._req('PUT', path=path, params=params, json=json) def _del(self, path, params=None): return self._req('DELETE', path=path, params=params) def wait(self, min_sec=4, max_sec=9): secs = random.randint(min_sec, max_sec) + random.random() print(f"Wating some time to avoid to be blocked: {secs:0.2f} secs") time.sleep(secs) def fill_time_entries(self, start_dt, end_dt = datetime.today(), weeks_back = 1): start_dt = datetime.strptime(start_dt, '%Y-%m-%d') if isinstance(end_dt,str): end_dt = datetime.strptime(end_dt, '%Y-%m-%d') ndays_back = weeks_back * 7 * -1 for dt in self._dt_range(start_dt, end_dt): if self._is_bday(dt): dt7 = dt + timedelta(days=ndays_back) params7 = dict( startDate=dt7.strftime("%Y-%m-%d"), endDate=dt7.strftime("%Y-%m-%d"), userId=self.user_id ) print(f"Filing {dt.date()} using time entries from {dt7.date()}") for new_entry in self._get('timeentries', params7): del new_entry['id'] dt_startTime = datetime.combine(dt, datetime.fromisoformat(new_entry['startTime']).time()) dt_endTime = datetime.combine(dt, datetime.fromisoformat(new_entry['endTime']).time()) new_entry['startTime'] = datetime.strftime(dt_startTime, "%Y-%m-%dT%H:%M:%S") new_entry['endTime'] = datetime.strftime(dt_endTime, "%Y-%m-%dT%H:%M:%S") self.wait() new_entry = self._post('timeentries', json=new_entry) if 'id' in new_entry[0]: print(f' New entry {new_entry[0]["id"]} created') else: print('Return:', new_entry) def submit_timesheets(self, start_dt, end_dt = datetime.today()): start_dt = datetime.strptime(start_dt, '%Y-%m-%d') if isinstance(end_dt,str): end_dt = datetime.strptime(end_dt, '%Y-%m-%d') for dt in self._dt_weeks_range(start_dt, end_dt): date = dt.strftime("%Y-%m-%d") print(f"Submitting timesheet for the week of the day {date}") r_json = self._get(f'timesheets/user/{self.user_id}?date={date}') self.wait() status = r_json['status'] if status == 'Unsubmitted': del r_json['id'] r_json['status'] = 'Submitted' self._post(path=f'timesheets/user/{self.user_id}', json=r_json) self.wait() r_json_new = self._get(f'timesheets/user/{self.user_id}?date={date}') self.wait() new_status = r_json_new['status'] if new_status == 'Submitted': print(f" - Timesheet correctly submitted") else: print(f" - Something went wrong with the submission, new status {new_status}") else: print(f" - Current status {status}, not submitting") API_TOKEN = <check_above_how_to_get_it> USER_ID = <check_above_how_to_get_it> OGH_ACC_ID = <check_above_how_to_get_it> tMetric = ATmetric(API_TOKEN, USER_ID, OGH_ACC_ID) tMetric.submit_timesheets('2023-03-27','2023-04-27')
Please register or sign in to comment