From d02aa6fea6a858adc6d7f6f23d4dfcd49c780542 Mon Sep 17 00:00:00 2001 From: Greg Steel Date: Wed, 9 Sep 2020 00:54:46 +1000 Subject: [PATCH 1/2] add methods to get time off policies and calculations --- PyBambooHR/PyBambooHR.py | 60 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/PyBambooHR/PyBambooHR.py b/PyBambooHR/PyBambooHR.py index 732b030..b6f1dbd 100644 --- a/PyBambooHR/PyBambooHR.py +++ b/PyBambooHR/PyBambooHR.py @@ -87,7 +87,7 @@ def __init__(self, subdomain='', api_key='', datatype='JSON', underscore_keys=Fa # We are focusing on JSON for now. if self.datatype == 'XML': - raise NotImplemented("Returning XML is not currently supported.") + raise NotImplementedError("Returning XML is not currently supported.") if self.datatype == 'JSON': self.headers.update({'Accept': 'application/json'}) @@ -181,7 +181,6 @@ def __init__(self, subdomain='', api_key='', datatype='JSON', underscore_keys=Fa "commisionDate": ("date", ""), "commissionAmount": ("currency", ""), "commissionComment": ("text", ""), - "commissionComment": ("text", ""), "benefitClassDate": ("date", ""), "benefitClassClass": ("list", ""), "benefitClassChangeReason": ("list", ""), @@ -647,6 +646,31 @@ def get_time_off_requests(self, start_date=None, end_date=None, status=None, typ return r.json() # return utils.transform_time_off(r.content) + def get_time_off_policies(self, employee_id=None): + + params = {} + if employee_id == None: + raise ValueError("Employee_id argument is required") + if not(employee_id.isdigit()): + raise ValueError("Employee_id must be a number") + + r = self._query('employees/' + employee_id + '/time_off/policies', params, raw=True) + return r.json() + + def get_time_off_calculations(self, employee_id=None, end_date=None): + end_date = utils.resolve_date_argument(end_date) + + params = {} + if end_date: + params['end'] = end_date + if employee_id == None: + raise ValueError("Employee_id argument is required") + if not(employee_id.isdigit()): + raise ValueError("Employee_id must be a number") + + r = self._query('employees/' + employee_id + '/time_off/calculator', params, raw=True) + return r.json() + def get_meta_fields(self): """ API method for returning a list of fields info. @@ -712,6 +736,38 @@ def get_meta_users(self): return r.json() + def get_meta_time_off_types(self): + """ + API method for returning a dictionary of time off types. + https://www.bamboohr.com/api/documentation/metadata.php#getTimeOffTypes + Success Response: 200 + The HTTP Content-type header will be set with the mime type for the response. + + @return: dictionary containing users information + """ + + url = self.base_url + "meta/time_off/types/" + r = requests.get(url, timeout=self.timeout, headers=self.headers, auth=(self.api_key, '')) + r.raise_for_status() + + return r.json() + + def get_meta_time_off_policies(self): + """ + API method for returning a dictionary of time off policies. + https://www.bamboohr.com/api/documentation/metadata.php#getTimeOffPolicies + Success Response: 200 + The HTTP Content-type header will be set with the mime type for the response. + + @return: dictionary containing users information + """ + + url = self.base_url + "meta/time_off/policies/" + r = requests.get(url, timeout=self.timeout, headers=self.headers, auth=(self.api_key, '')) + r.raise_for_status() + + return r.json() + def _query(self, url, params, raw=False): url = self.base_url + url r = requests.get(url, timeout=self.timeout, params=params, headers=self.headers, auth=(self.api_key, '')) From 02e15e2d7517eb2579e9dcf999f0ce84cd77833f Mon Sep 17 00:00:00 2001 From: Greg Steel Date: Sun, 25 Oct 2020 11:43:02 +1100 Subject: [PATCH 2/2] handle xml response for tables --- PyBambooHR/PyBambooHR.py | 10 ++++++++-- PyBambooHR/utils.py | 4 +++- tests/test_misc.py | 8 ++++---- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/PyBambooHR/PyBambooHR.py b/PyBambooHR/PyBambooHR.py index b6f1dbd..e83cc02 100644 --- a/PyBambooHR/PyBambooHR.py +++ b/PyBambooHR/PyBambooHR.py @@ -12,6 +12,7 @@ import datetime import requests +import copy from . import utils from . import config from .utils import make_field_xml @@ -571,10 +572,15 @@ def get_tabular_data(self, table_name, employee_id='all'): the values of the table's fields for a particular date, which is stored by key 'date' in the dictionary. """ url = self.base_url + 'employees/{}/tables/{}'.format(employee_id, table_name) - r = requests.get(url, timeout=self.timeout, headers=self.headers, auth=(self.api_key, '')) + + #Make a copy of headers and replace JSON with XML + xmlheaders = copy.copy(self.headers) + xmlheaders.update({'Accept': 'application/xml'}) + + r = requests.get(url, timeout=self.timeout, headers=xmlheaders, auth=(self.api_key, '')) r.raise_for_status() - return utils.transform_tabular_data(r.content) + return utils.transform_tabular_data(r.content, table_name) def get_employee_changed_table(self, table_name='jobInfo', since=None): """ diff --git a/PyBambooHR/utils.py b/PyBambooHR/utils.py index c2d1380..4a17c5f 100644 --- a/PyBambooHR/utils.py +++ b/PyBambooHR/utils.py @@ -77,7 +77,7 @@ def resolve_date_argument(arg): return None raise ValueError("Date argument {} must be either datetime, date, or string in form YYYY-MM-DD".format(arg)) -def transform_tabular_data(xml_input): +def transform_tabular_data(xml_input, table_name): """ Converts table data (xml) from BambooHR into a dictionary with employee id as key and a list of dictionaries. @@ -105,6 +105,8 @@ def transform_tabular_data(xml_input): rows = _extract(obj, 'table', 'row') by_employee_id = {} for row in rows: + if not('field' in row): + raise ValueError("User does not have access to the {} table".format(table_name)) eid = row['@employeeId'] field_list = row['field'] if type(row['field']) is list \ else [row['field']] diff --git a/tests/test_misc.py b/tests/test_misc.py index 2a77018..356de37 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -104,7 +104,7 @@ def test_transform_tabular_data(self): '321': [{ 'customFieldA': '321 & Value A', 'row_id': '999'}]} - self.assertEqual(table, utils.transform_tabular_data(xml)) + self.assertEqual(table, utils.transform_tabular_data(xml, 'test')) def test_transform_tabular_data_single_row(self): xml = """ @@ -114,13 +114,13 @@ def test_transform_tabular_data_single_row(self): """ table = {'123': [{'customFieldA': '123 Value A', 'row_id': '321'}]} - self.assertEqual(table, utils.transform_tabular_data(xml)) + self.assertEqual(table, utils.transform_tabular_data(xml, 'test')) def test_transform_tabular_data_empty_table(self): xml = """ """ table = {} - self.assertEqual(table, utils.transform_tabular_data(xml)) + self.assertEqual(table, utils.transform_tabular_data(xml, 'test')) def test_transform_tabular_data_empty_field(self): xml = """ @@ -139,4 +139,4 @@ def test_transform_tabular_data_empty_field(self): '321': [{'customFieldB': '321 Value B', 'row_id': '999'}]} - self.assertEqual(table, utils.transform_tabular_data(xml)) + self.assertEqual(table, utils.transform_tabular_data(xml, 'test'))