From 3245850eaa8f290a1307730b391bea42b6cb6e76 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sun, 4 Feb 2018 06:38:18 +0100 Subject: Check that there are time entries for every day in the week Before submitting the time sheet for approval (and before doing anything with Selenium), ensure that there's at least one time entry logged for each day in the week. To do this, we query the Harvest API with newly-required account ID and API token values. This gives us a bunch of time entries. We check them to see if they fell in the last week. If all weekdays from the last week have at least one time entry, then the rest of the program executes and we run Selenium to submit the time sheet. If any day had missing entries, an exception is raised and the program exits. --- harvester_submit_week_for_approval.py | 71 +++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/harvester_submit_week_for_approval.py b/harvester_submit_week_for_approval.py index 6f9e047..b52f6c9 100644 --- a/harvester_submit_week_for_approval.py +++ b/harvester_submit_week_for_approval.py @@ -3,6 +3,7 @@ import argparse from datetime import datetime, timedelta import subprocess +import sys from selenium.webdriver import Firefox from selenium.webdriver.common.by import By @@ -11,6 +12,8 @@ from selenium.webdriver.firefox.options import Options from selenium.webdriver.support import expected_conditions as expected from selenium.webdriver.support.wait import WebDriverWait +import requests + def login(driver, wait, email, password): driver.get('https://id.getharvest.com/harvest/sign_in') @@ -89,6 +92,61 @@ def get_password(command): return str(result.stdout, 'utf-8').rstrip() +class WeekIsComplete(object): + + def __init__(self, account_id, api_token, friday): + self.account_id = account_id + self.api_token = api_token + self.friday = friday + self._monday = None + self.days = {} + + # Add `self.days['2018-01-31'] = 0` for all weekdays + for i in range(5): + self.days[(self.monday + timedelta(days=i)).strftime('%F')] = 0 + + def check(self): + time_entries = self._fetch_week() + days = self.days.keys() + + for entry in time_entries['time_entries']: + if entry['spent_date'] in days: + self.days[entry['spent_date']] += 1 + + for _, count in self.days.items(): + if count == 0: + raise IncompleteWeekError + + return True + + def _fetch_week(self): + r = requests.get( + 'https://api.harvestapp.com/api/v2/time_entries', + headers={ + 'Harvest-Account-ID': self.account_id, + 'Authorization': 'Bearer {}'.format(self.api_token), + 'User-Agent': 'harvester-submit-week-for-approval (TODO email address or link to app)', + 'Content-Type': 'application/json', + }, + params={ + 'from': self.monday.strftime('%F'), + 'to': self.friday.strftime('%F'), + }) + + return r.json() + + @property + def monday(self): + if not self._monday: + self._monday = self.friday - timedelta(days=4) + + return self._monday + + +class IncompleteWeekError(RuntimeError): + pass + + if __name__ == "__main__": parser = argparse.ArgumentParser( description='Submit the most recent Harvest timesheet for approval.') @@ -107,6 +165,19 @@ if __name__ == "__main__": args = parser.parse_args() + # Don't submit unless there is at least 1 time sheet logged for each day + # that week + try: + WeekIsComplete( + account_id='', + api_token='', + friday=most_recent_friday() + ).check() + except IncompleteWeekError: + print('Week was incomplete') + + sys.exit(1) + options = Options() options.add_argument('-headless') driver = Firefox( -- cgit v1.2.3