Connect Create Share Repeat

    1. 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.

    2. 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.

    3. 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')
    
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment