From 1458e3d77ff46cf4671ed9f0adb9cf9805b439fd Mon Sep 17 00:00:00 2001 From: Fang Lin Date: Mon, 15 Apr 2019 17:20:54 -0700 Subject: [PATCH 01/10] hrp V2 --- .travis.yml | 7 +- setup.py | 6 +- uw_hrp/__init__.py | 15 +- uw_hrp/appointee.py | 93 ------- uw_hrp/models.py | 262 +++++++++--------- .../10000000000000000000000000000015.json | 250 +++++++++++++++++ .../hrpws/file/hrp/v2/worker/100000015.json | 250 +++++++++++++++++ .../hrpws/file/hrp/v2/worker/chair.json | 250 +++++++++++++++++ .../hrpws/file/hrp/v2/worker/faculty.json | 217 +++++++++++++++ uw_hrp/tests/test_appointee.py | 62 ----- uw_hrp/tests/test_models.py | 123 ++++++++ uw_hrp/tests/test_worker.py | 57 ++++ uw_hrp/worker.py | 42 +++ 13 files changed, 1331 insertions(+), 303 deletions(-) delete mode 100644 uw_hrp/appointee.py create mode 100644 uw_hrp/resources/hrpws/file/hrp/v2/worker/10000000000000000000000000000015.json create mode 100644 uw_hrp/resources/hrpws/file/hrp/v2/worker/100000015.json create mode 100644 uw_hrp/resources/hrpws/file/hrp/v2/worker/chair.json create mode 100644 uw_hrp/resources/hrpws/file/hrp/v2/worker/faculty.json delete mode 100644 uw_hrp/tests/test_appointee.py create mode 100644 uw_hrp/tests/test_models.py create mode 100644 uw_hrp/tests/test_worker.py create mode 100644 uw_hrp/worker.py diff --git a/.travis.yml b/.travis.yml index 18970b2..ce7cf5c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ sudo: false language: python python: -- '2.7' - '3.6' before_script: - pip install -e . @@ -9,10 +8,12 @@ before_script: - pip install nose2 - pip install coverage - pip install commonconf -- pip install python-coveralls +- pip install coveralls + script: -- pycodestyle uw_hrp/ --exclude=uw_hrp/tests +- pycodestyle uw_hrp/ - coverage run --source=uw_hrp uw_hrp/test.py -v + after_script: - coveralls before_deploy: diff --git a/setup.py b/setup.py index fb01452..15355de 100644 --- a/setup.py +++ b/setup.py @@ -22,8 +22,9 @@ author_email="aca-it@uw.edu", include_package_data=True, install_requires=[ - 'UW-RestClients-Core>=0.9.6,<1.0', - 'UW-RestClients-PWS>=0.6,<1.0', + 'UW-RestClients-Core<2.0', + 'UW-RestClients-PWS<3.0', + 'python-dateutil' ], license='Apache License, Version 2.0', description=('A library for connecting to the UW Human Resources API'), @@ -34,7 +35,6 @@ 'License :: OSI Approved :: Apache Software License', 'Operating System :: OS Independent', 'Programming Language :: Python', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.6', ], ) diff --git a/uw_hrp/__init__.py b/uw_hrp/__init__.py index 1c26850..6dcab46 100644 --- a/uw_hrp/__init__.py +++ b/uw_hrp/__init__.py @@ -4,20 +4,27 @@ """ import logging -import json +from dateutil.parser import parse from uw_hrp.dao import HRP_DAO from restclients_core.exceptions import DataFailureException logger = logging.getLogger(__name__) +hrp_dao = HRP_DAO() def get_resource(url): - response = HRP_DAO().getURL(url, {'Accept': 'application/json'}) - logger.info("%s ==status==> %s" % (url, response.status)) + response = hrp_dao.getURL(url, {'Accept': 'application/json'}) + logger.debug("{0} ==status==> {1}".format(url, response.status)) if response.status != 200: raise DataFailureException(url, response.status, response.data) - logger.debug("%s ==data==> %s" % (url, response.data)) + logger.debug("{0} ==data==> {1}".format(url, response.data)) return response.data + + +def parse_date(date_str): + if date_str is not None: + return parse(date_str) + return None diff --git a/uw_hrp/appointee.py b/uw_hrp/appointee.py deleted file mode 100644 index c711777..0000000 --- a/uw_hrp/appointee.py +++ /dev/null @@ -1,93 +0,0 @@ -""" -This is the interface for interacting with the HRP Web Service. -""" - -from datetime import datetime -import logging -import json -from restclients_core.exceptions import InvalidRegID, InvalidNetID,\ - InvalidEmployeeID -from uw_pws import PWS -from uw_hrp.models import Appointment, Appointee -from uw_hrp import get_resource - - -URL_PREFIX = "/hrp/v1/appointee/" -logger = logging.getLogger(__name__) - - -def get_appointee_by_eid(employee_id): - if not PWS().valid_employee_id(employee_id): - raise InvalidEmployeeID(employee_id) - return _get_appointee(employee_id) - - -def get_appointee_by_netid(netid): - if not PWS().valid_uwnetid(netid): - raise InvalidNetID(netid) - return _get_appointee(netid) - - -def get_appointee_by_regid(regid): - if not PWS().valid_uwregid(regid): - raise InvalidRegID(regid) - return _get_appointee(regid) - - -def _get_appointee(id): - """ - Return a restclients.models.hrp.AppointeePerson object - """ - url = "%s%s.json" % (URL_PREFIX, id) - response = get_resource(url) - return process_json(response) - - -def process_json(response_body): - json_data = json.loads(response_body) - person_data = json_data.get("Person") - if not person_data: - return None - - appointee = create_appointee(person_data) - - if json_data.get("Appointments"): - apps = [] - for app in json_data.get("Appointments"): - if float(app.get("PayRate")) > 0.000: - # only those currently having a salary - apps.append(create_appointment(app)) - appointee.appointments = apps - return appointee - - -def create_appointee(person): - ap = Appointee() - ap.netid = person.get("UWNetID") - ap.regid = person.get("UWRegID") - ap.employee_id = person.get("EmployeeID") - ap.status = person.get("EmploymentStatus") - ap.status_desc = person.get("EmploymentStatusDescription") - ap.home_dept_budget_number = person.get("HomeDepartmentBudgetNumber") - ap.home_dept_budget_name = person.get("HomeDepartmentBudgetName") - ap.home_dept_org_code = person.get("HomeDepartmentOrganizationCode") - ap.home_dept_org_name = person.get("HomeDepartmentOrganizationName") - ap.onoff_campus_code = person.get("OnOffCampusCode") - ap.onoff_campus_code_desc = person.get("OnOffCampusCodeDescription") - return ap - - -def create_appointment(appointment): - app = Appointment() - app.app_number = int(appointment.get("AppointmentNumber")) - app.app_state = appointment.get("AppointmentState") - app.dept_budget_name = appointment.get("DepartmentBudgetName") - app.dept_budget_number = appointment.get("DepartmentBudgetNumber") - app.job_class_code = appointment.get("JobClassCode") - app.job_class_title = appointment.get("JobClassTitle") - app.org_code = appointment.get("OrganizationCode") - app.org_name = appointment.get("OrganizationName") - app.paid_app_code = appointment.get("PaidAppointmentCode") - app.status = appointment.get("Status") - app.status_desc = appointment.get("StatusDescription") - return app diff --git a/uw_hrp/models.py b/uw_hrp/models.py index 88b8d29..9cb2797 100644 --- a/uw_hrp/models.py +++ b/uw_hrp/models.py @@ -1,169 +1,155 @@ +import json +from uw_hrp import parse_date from restclients_core import models -class Appointment(models.Model): - CURRENT_STATE = 'CURRENT' - ACTIVE_STATUS = 'A' - - app_number = models.PositiveSmallIntegerField() - app_state = models.CharField(max_length=16) - dept_budget_name = models.CharField(max_length=96) - dept_budget_number = models.CharField(max_length=16) - job_class_code = models.CharField(max_length=16) - job_class_title = models.CharField(max_length=96) - org_code = models.CharField(max_length=16) - org_name = models.CharField(max_length=96) - paid_app_code = models.CharField(max_length=8) - status = models.CharField(max_length=8) - status_desc = models.CharField(max_length=16) - - def __cmp__(self, other): - if other is not None: - return self.app_number.__cmp__(other.app_number) - - def __lt__(self, other): - return self.app_number < other.app_number - - def is_active_app_status(self): - return self.status == Appointment.ACTIVE_STATUS - - def is_current_app_state(self): - return self.app_state.upper() == Appointment.CURRENT_STATE +def date_to_str(d_obj): + if d_obj is not None: + return str(d_obj) + return None + + +class WorkerPosition(models.Model): + effective_date = models.DateField(null=True, default=None) + end_date = models.DateField(null=True, default=None) + ecs_job_cla_code_desc = models.CharField(max_length=64, + null=True, default=None) + location = models.CharField(max_length=96, null=True, default=None) + is_primary = models.BooleanField(default=False) + org_code = models.CharField(max_length=16, null=True, default=None) + org_desc = models.CharField(max_length=128, null=True, default=None) + busi_title = models.CharField(max_length=128, null=True, default=None) + pos_type = models.CharField(max_length=64, null=True, default=None) + supervisor_eid = models.CharField(max_length=16, + null=True, default=None) + pos_time_type_id = models.CharField(max_length=64, + null=True, default=None) + supervisory_org_code = models.CharField(max_length=32, + null=True, default=None) + supervisory_org_id = models.CharField(max_length=96, + null=True, default=None) + supervisory_org_desc = models.CharField(max_length=256, + null=True, default=None) def json_data(self): return { - 'app_number': self.app_number, - 'app_state': self.app_state, - 'dept_budget_name': self.dept_budget_name, - 'dept_budget_number': self.dept_budget_number, - 'job_class_code': self.job_class_code, - 'job_class_title': self.job_class_title, + 'effective_date': date_to_str(self.effective_date), + 'end_date': date_to_str(self.end_date), + 'is_primary': self.is_primary, + 'busi_title': self.busi_title, + 'pos_type': self.pos_type, + 'ecs_job_cla_code_desc': self.ecs_job_cla_code_desc, + 'location': self.location, 'org_code': self.org_code, - 'org_name': self.org_name, - 'paid_app_code': self.paid_app_code, - 'status': self.status, - 'status_desc': self.status_desc, + 'org_desc': self.org_desc, + 'pos_time_type_id': self.pos_time_type_id, + 'supervisor_eid': self.supervisor_eid, + 'supervisory_org_code': self.supervisory_org_code, + 'supervisory_org_id': self.supervisory_org_id, + 'supervisory_org_desc': self.supervisory_org_desc, } def __str__(self): - return ("{%s: %s, %s: %s, %s: %s, %s: %s," + - " %s: %s, %s: %s, %s: %s, %s: %s," - " %s: %s, %s: %s, %s: %s}") % ( - 'app_number', self.app_number, - 'app_state', self.app_state, - 'dept_budget_name', self.dept_budget_name, - 'dept_budget_number', self.dept_budget_number, - 'job_class_code', self.job_class_code, - 'job_class_title', self.job_class_title, - 'org_code', self.org_code, - 'org_name', self.org_name, - 'paid_app_code', self.paid_app_code, - 'status', self.status, - 'status_desc', self.status_desc - ) + return json.dumps(self.json_data()) + + def __init__(self, *args, **kwargs): + data = kwargs.get("data") + if data is None: + return super(WorkerPosition, self).__init__(*args, **kwargs) + + if data.get("CostCenter") is not None: + self.org_code = data["CostCenter"]["OrganizationCode"] + self.org_desc = data["CostCenter"]["OrganizationDescription"] + + self.ecs_job_cla_code_desc = \ + data["EcsJobClassificationCodeDescription"] + self.is_primary = data["IsPrimaryPosition"] + + if data.get("Location") is not None: + self.location = data["Location"]["ID"] + + self.busi_title = data["PositionBusinessTitle"] + + if data.get("PositionType") is not None: + self.pos_type = data["PositionType"] + + if data.get("PositionTimeTypeID") is not None: + self.pos_time_type_id = data["PositionTimeTypeID"] + + self.effective_date = parse_date(data["PositionEffectiveDate"]) + self.end_date = parse_date(data["PositionEndDate"]) + + self.supervisor_eid = data["PositionSupervisor"]["EmployeeID"] + + if data.get("SupervisoryOrganization") is not None: + self.supervisory_org_code = \ + data["SupervisoryOrganization"]["Code"] + self.supervisory_org_id = \ + data["SupervisoryOrganization"]["ID"] + self.supervisory_org_desc = \ + data["SupervisoryOrganization"]["Description"] class Meta: - db_table = 'restclients_hrp_appointment' - - -class Appointee(models.Model): - # employment status codes - STATUS_ACTIVE = "A" - STATUS_RETIREE = "R" - STATUS_SEPARATED = "S" - - # On Off Campus codes - ON_SEATTLE_CAMPUS = "1" - JOINT_CENTER_FOR_GRADUATE_STUDY = "3" - FRIDAY_HARBOR_LABORATORIES = "4" - REGIONAL_MEDICAL_LIBRARY = "6" - COMPOSITE_LOCATIONS = "7" - HARBORVIEW_MEDICAL_CENTER = "A" - VETERANS_HOSPITAL = "B" - US_PUBLIC_HEALTH_SERVICE_HOSPITAL = "C" - CHILDRENS_ORTHOPEDIC_MEDICAL_CENTER = "D" - FIRCREST_LABORATORY = "E" - PROVIDENCE_MEDICAL_CENTER = "F" - APPLIED_PHYSIC_LABORATORY = "G" - PRIMATE_CENTER_SPECIAL_LOCATION = "H" - ON_SEATTLE_CAMPUS_OTHER = "N" - TACOMA_CAMPUS = "T" - BOTHELL_WOODINVILLE_CAMPUS = "W" - OFF_CAMPUS_ASSIGNMENT = "Y" - OFF_CAMPUS_OTHER = "Z" - - # home_dept_org_code 1st digit" - UW_SEATTLE = "2" - MEDICAL_HEALTH_SCIENCES = "3" - ADMIN_MANAGEMENT = "4" - UW_BOTHELL = "5" - UW_TACOMA = "6" - - netid = models.SlugField(max_length=32, + db_table = 'restclients_hrp_worker_position' + + +class Worker(models.Model): + netid = models.CharField(max_length=32, db_index=True, unique=True) regid = models.CharField(max_length=32, db_index=True, unique=True) - employee_id = models.CharField(max_length=9, + employee_id = models.CharField(max_length=16, db_index=True, unique=True) - status = models.CharField(max_length=2) - status_desc = models.CharField(max_length=16) - home_dept_budget_number = models.CharField(max_length=16) - home_dept_budget_name = models.CharField(max_length=96, - null=True) - home_dept_org_code = models.CharField(max_length=16) - home_dept_org_name = models.CharField(max_length=96, - null=True) - onoff_campus_code = models.CharField(max_length=2) - onoff_campus_code_desc = models.CharField(max_length=32) - - def __init__(self): - self.appointments = [] - - def is_active_emp_status(self): - return self.status == Appointee.STATUS_ACTIVE + employee_status = models.CharField(max_length=32) + is_active = models.BooleanField(default=False) + is_retired = models.BooleanField(default=False) + is_terminated = models.BooleanField(default=False) def json_data(self): - apps = [] - for app in self.appointments: - apps.append(app.json_data()) + positions = [] + for pos in self.worker_positions: + positions.append(pos.json_data()) return { "netid": self.netid, 'regid': self.regid, 'employee_id': self.employee_id, - 'status': self.status, - 'is_active': self.is_active_emp_status(), - 'status_desc': self.status_desc, - 'home_dept_budget_number': self.home_dept_budget_number, - 'home_dept_budget_name': self.home_dept_budget_name, - 'home_dept_org_code': self.home_dept_org_code, - 'home_dept_org_name': self.home_dept_org_name, - 'onoff_campus_code': self.onoff_campus_code, - 'onoff_campus_code_desc': self.onoff_campus_code_desc, - 'appointments': apps + 'employee_status': self.employee_status, + 'is_active': self.is_active, + 'is_retired': self.is_retired, + 'is_terminated': self.is_terminated, + 'worker_positions': positions } def __str__(self): - return ("{%s: %s, %s: %s, %s: %s, %s: %s," + - " %s: %s, %s: %s, %s: %s, %s: %s," - " %s: %s, %s: %s, %s: %s, %s: %s, %s: [%s]}") % ( - "netid", self.netid, - 'regid', self.regid, - 'employee_id', self.employee_id, - 'status', self.status, - 'is_active', self.is_active_emp_status(), - 'status_desc', self.status_desc, - 'home_dept_budget_number', self.home_dept_budget_number, - 'home_dept_budget_name', self.home_dept_budget_name, - 'home_dept_org_code', self.home_dept_org_code, - 'home_dept_org_name', self.home_dept_org_name, - 'onoff_campus_code', self.onoff_campus_code, - 'onoff_campus_code_desc', self.onoff_campus_code_desc, - 'appointments', ','.join(map(str, self.appointments)) - ) + json_data = self.json_data() + json_data['worker_positions'] = ','.join( + map(str, self.worker_positions)) + return json.dumps(json_data) + + def __init__(self, *args, **kwargs): + data = kwargs.get("data") + if data is None: + return super(WorkerPosition, self).__init__(*args, **kwargs) + + self.netid = data["NetID"] + self.regid = data["RegID"] + self.employee_id = data["EmployeeID"] + + if data.get("WorkerEmploymentStatus") is not None: + self.employee_status = \ + data["WorkerEmploymentStatus"]["EmployeeStatus"] + self.is_active = data["WorkerEmploymentStatus"]["IsActive"] + self.is_retired = data["WorkerEmploymentStatus"]["IsRetired"] + self.is_terminated = data["WorkerEmploymentStatus"]["IsTerminated"] + + self.worker_positions = [] + if data.get("WorkerPositions") is not None: + for position in data["WorkerPositions"]: + self.worker_positions.append(WorkerPosition(data=position)) class Meta: - db_table = 'restclients_hrp_appointee' + db_table = 'restclients_hrp_worker' diff --git a/uw_hrp/resources/hrpws/file/hrp/v2/worker/10000000000000000000000000000015.json b/uw_hrp/resources/hrpws/file/hrp/v2/worker/10000000000000000000000000000015.json new file mode 100644 index 0000000..9a97b84 --- /dev/null +++ b/uw_hrp/resources/hrpws/file/hrp/v2/worker/10000000000000000000000000000015.json @@ -0,0 +1,250 @@ +{ + "AcademicAppointments": + [{"AcademicAppointmentCompletedDate":"2017-06-22T07:00:00.000Z", + "AcademicAppointmentEndDate":null, + "AcademicAppointmentIdentifierID":"A", + "AcademicAppointmentIdentifierTypeID":"Administrative", + "AcademicAppointmentStartDate":"2017-04-01T07:00:00.000Z", + "AcademicAppointmentState":"Current", + "AcademicAppointmentTitle":"Chair", + "AcademicAppointmentTrackID":"AC-000000015-2", + "AcademicUnitID":"050", + "AcademicUnitName":"Family Medicine", + "AcademicUnitSupervisoryOrganizations": + [{"AcademicUnitID":"050", + "Code":"SOM:", + "CostCenter": + {"Description":"WORKDAY DEFAULT DEPTBG", + "ID":"681925", + "OrganizationCode":"3040111000", + "OrganizationDescription":"FAMILY MEDICINE"}, + "Description":"SOM: Family Medicine (Visor, Super1)", + "Href":"\/hrp\/v2\/organization\/SOM_000420.json", + "ID":"SOM_000420", + "Name":"Family Medicine"}, + {"AcademicUnitID":"081", + "Code":"SOM:", + "CostCenter": + {"Description":"DOM PAYROLL SUSPENSE", + "ID":"656131", + "OrganizationCode":"3040510019", + "OrganizationDescription":"FINANCE ABC\/DEANS HR"}, + "Description":"School of Medicine (Dean, Bill)", + "Href":"\/hrp\/v2\/organization\/SOM_000001.json", + "ID":"SOM_000001", + "Name":"School of Medicine"} + ], + "ActualAcademicAppointmentEndDate":null, + "AppointmentPositionID":null, + "PositionSupervisoryOrganization":null, + "PrimaryPositionID":"PN-0000809", + "SuperiorAcademicUnitID":"081"}, + {"AcademicAppointmentCompletedDate":"2017-06-22T07:00:00.000Z", + "AcademicAppointmentEndDate":null, + "AcademicAppointmentIdentifierID":"P", + "AcademicAppointmentIdentifierTypeID":"Primary", + "AcademicAppointmentStartDate":"2017-04-01T07:00:00.000Z", + "AcademicAppointmentState":"Current", + "AcademicAppointmentTitle":"Professor", + "AcademicAppointmentTrackID":"AC-000000015-1", + "AcademicUnitID":"050", + "AcademicUnitName":"Family Medicine", + "AcademicUnitSupervisoryOrganizations": + [{"AcademicUnitID":"050", + "Code":"SOM:", + "CostCenter": + {"Description":"WORKDAY DEFAULT DEPTBG", + "ID":"681925", + "OrganizationCode":"3040111000", + "OrganizationDescription":"FAMILY MEDICINE"}, + "Description":"SOM: Family Medicine (Visor, Super1)", + "Href":"\/hrp\/v2\/organization\/SOM_000420.json", + "ID":"SOM_000420", + "Name":"Family Medicine"}, + {"AcademicUnitID":"081", + "Code":"SOM:", + "CostCenter": + {"Description":"DOM PAYROLL SUSPENSE", + "ID":"656131", + "OrganizationCode":"3040510019", + "OrganizationDescription":"FINANCE ABC\/DEANS HR"}, + "Description":"School of Medicine (Dean, Bill)", + "Href":"\/hrp\/v2\/organization\/SOM_000001.json", + "ID":"SOM_000001", + "Name":"School of Medicine"} + ], + "ActualAcademicAppointmentEndDate":null, + "AppointmentPositionID":"PN-0000809", + "PositionSupervisoryOrganization": + {"AcademicUnitID":null, + "Code":"SOM:", + "CostCenter": + {"Description":"DOM PAYROLL SUSPENSE", + "ID":"656131", + "OrganizationCode":"3040510019", + "OrganizationDescription":"FINANCE ABC\/DEANS HR"}, + "Description":"School of Medicine (Dean, Bill)", + "Href":"\/hrp\/v2\/organization\/SOM_000001.json", + "ID":"SOM_000001", + "Name":"School of Medicine"}, + "PrimaryPositionID":"PN-0000809", + "SuperiorAcademicUnitID":"081"}], + "DisplayFirstName":"Super1", + "DisplayLastName":"Visor", + "DisplayMiddleName":null, + "DisplayName":"Super1 Visor", + "EmployeeID":"100000015", + "EmployeeIDPrior":null, + "FormattedLegalNameFirstLast":"Super1 Visor", + "FormattedLegalNameFirstMiddleLast":"Super1 Visor", + "FormattedLegalNameLastFirstMiddle":"Visor, Super1", + "FormattedPreferredNameFirstLast":"Super1 Visor", + "FormattedPreferredNameFirstMiddleLast":"Super1 Visor", + "FormattedPreferredNameLastFirstMiddle":"Visor, Super1", + "HuskyCardOverride":null, + "IsCurrentFaculty":true, + "IsFutureDate":false, + "LegalFirstName":"Super1", + "LegalLastName":"Visor", + "LegalMiddleName":"A", + "LegalNameSuffix":null, + "NetID":"jamespa", + "PreferredFirstName":"Super1", + "PreferredLastName":"Visor", + "PreferredMiddleName":null, + "PreferredNameSuffix":null, + "RegID":"10000000000000000000000000000015", + "RepositoryTimeStamp":"2019-03-06T16:12:12.214Z", + "SystemMetadata":{"LastModified":null}, + "WorkdayPersonType":"Employee", + "WorkerContact": + {"Addresses":[ + {"Country":"United States of America", + "CountryCodeISO2":"US", + "IsPrimary":true, + "IsPubliclyAvailable":true, + "Lines":["Seattle Main Campus"], + "Municipality":"Seattle", + "PostalCode":"98195", + "Region":"Washington", + "Type":"WORK"}, + {"Country":"United States of America", + "CountryCodeISO2":"US", + "IsPrimary":false, + "IsPubliclyAvailable":true, + "Lines":["1705 NE Pacific St"], + "Municipality":"Seattle", + "PostalCode":"98195-0000", + "Region":"Washington", + "Type":"WORK"}], + "CampusBox":"356390", + "EmailAddresses":[ + {"Address":"jamespa@uw.edu", + "IsPrimary":true, + "IsPubliclyAvailable":true, + "Type":"WORK"}], + "Phones":[{"AreaCode":"206", + "DeviceType":"Telephone", + "InternationalCode":"1", + "IsPrimary":true, + "IsPubliclyAvailable":true, + "NANPPhoneNumber":"+1 (206) 685-3466", + "Number":"685-3466", + "Type":"WORK"}, + {"AreaCode":"206", + "DeviceType":"Telephone", + "InternationalCode":"1", + "IsPrimary":false, + "IsPubliclyAvailable":true, + "NANPPhoneNumber":"+1 (206) 543-5563", + "Number":"543-5563", + "Type":"WORK"} + ] + }, + "WorkerEmploymentStatus": + {"ActiveStatusDate":"2017-04-01T07:00:00.000Z", + "EmployeeStatus":"Active", + "EmployeeStatusCode":"A", + "EndEmploymentDate":null, + "EstimatedLastDayOfLeave":null, + "FirstDayOfLeave":null, + "FirstDayOfWork":"2017-04-01T07:00:00.000Z", + "HireDate":"2017-04-01T07:00:00.000Z", + "IsActive":true, + "IsRetired":false, + "IsTerminated":false, + "LastDayOfWorkForLeave":null, + "OriginalHireDate":"2017-03-31T07:00:00.000Z", + "RetirementDate":null, + "TerminationDate":null}, + "WorkerPositions":[ + {"CostCenter": + {"Description":"WORKDAY DEFAULT DEPTBG", + "ID":"681925", + "OrganizationCode":"3040111000", + "OrganizationDescription":"FAMILY MEDICINE" + }, + "EcsJobClassificationCode":"F", + "EcsJobClassificationCodeDescription":"Academic Personnel", + "FutureTransactions":[], + "IsFutureDate":false, + "IsMedicalCenterPosition":false, + "IsOnLeaveFromPosition":false, + "IsPrimaryPosition":true, + "JobProfileSummary": + {"Href":"\/hrp\/v2\/jobProfile\/10101.json", + "JobCategory":"Faculty", + "JobFamilies":[ + {"JobFamilyID":"Faculty - Indefinite and Multi-Year", + "JobFamilyName":"01 - Academic Personnel - Faculty - Indefinite and Multi-Year", + "JobFamilySummary":"Academic positions designated as faculty under the Faculty Code Chapter 21"} + ], + "JobProfileDescription":"Professor", + "JobProfileID":"10101" + }, + "Location": + {"ID":"Seattle Campus", + "Name":"Seattle Campus" + }, + "ObjectCode":"01", + "PayRateType":"Salary", + "PayrollUnitCode":"00753", + "PlannedDistributions":{}, + "PositionBusinessTitle":"Chair", + "PositionEffectiveDate":"2017-04-01T07:00:00.000Z", + "PositionEndDate":null, + "PositionFTEPercent":"100.00000", + "PositionID":"PN-0000809", + "PositionStartDate":"2017-04-01T00:00:00.000Z", + "PositionSupervisor": + {"EmployeeID":"100000115", + "Href":"\/hrp\/v2\/worker\/100000115.json" + }, + "PositionTimeTypeID":"Full_time", + "PositionTitle":"PROFESSOR, School of Medicine", + "PositionType":"Regular_Practice_Plan", + "ServicePeriodDescription":"Service_Period_12.00", + "ServicePeriodID":"12", + "SubObjectCode":"10", + "SupervisoryOrganization": + {"AcademicUnitID":null, + "Code":"SOM:", + "CostCenter": + {"Description":"DOM PAYROLL SUSPENSE", + "ID":"656131", + "OrganizationCode":"3040510019", + "OrganizationDescription":"FINANCE ABC\/DEANS HR" + }, + "Description":"School of Medicine (Dean, Bill)", + "Href":"\/hrp\/v2\/organization\/SOM_000001.json", + "ID":"SOM_000001", + "Name":"School of Medicine" + }, + "TotalBasePayAmount":"0.00000", + "TotalBasePayAnnualizedAmount":"0.00000", + "TotalBasePayFrequency":"Monthly", + "TotalPayAnnualizedAmount":"0.00000", + "WorkShift":"First Shift" + } + ] +} diff --git a/uw_hrp/resources/hrpws/file/hrp/v2/worker/100000015.json b/uw_hrp/resources/hrpws/file/hrp/v2/worker/100000015.json new file mode 100644 index 0000000..9a97b84 --- /dev/null +++ b/uw_hrp/resources/hrpws/file/hrp/v2/worker/100000015.json @@ -0,0 +1,250 @@ +{ + "AcademicAppointments": + [{"AcademicAppointmentCompletedDate":"2017-06-22T07:00:00.000Z", + "AcademicAppointmentEndDate":null, + "AcademicAppointmentIdentifierID":"A", + "AcademicAppointmentIdentifierTypeID":"Administrative", + "AcademicAppointmentStartDate":"2017-04-01T07:00:00.000Z", + "AcademicAppointmentState":"Current", + "AcademicAppointmentTitle":"Chair", + "AcademicAppointmentTrackID":"AC-000000015-2", + "AcademicUnitID":"050", + "AcademicUnitName":"Family Medicine", + "AcademicUnitSupervisoryOrganizations": + [{"AcademicUnitID":"050", + "Code":"SOM:", + "CostCenter": + {"Description":"WORKDAY DEFAULT DEPTBG", + "ID":"681925", + "OrganizationCode":"3040111000", + "OrganizationDescription":"FAMILY MEDICINE"}, + "Description":"SOM: Family Medicine (Visor, Super1)", + "Href":"\/hrp\/v2\/organization\/SOM_000420.json", + "ID":"SOM_000420", + "Name":"Family Medicine"}, + {"AcademicUnitID":"081", + "Code":"SOM:", + "CostCenter": + {"Description":"DOM PAYROLL SUSPENSE", + "ID":"656131", + "OrganizationCode":"3040510019", + "OrganizationDescription":"FINANCE ABC\/DEANS HR"}, + "Description":"School of Medicine (Dean, Bill)", + "Href":"\/hrp\/v2\/organization\/SOM_000001.json", + "ID":"SOM_000001", + "Name":"School of Medicine"} + ], + "ActualAcademicAppointmentEndDate":null, + "AppointmentPositionID":null, + "PositionSupervisoryOrganization":null, + "PrimaryPositionID":"PN-0000809", + "SuperiorAcademicUnitID":"081"}, + {"AcademicAppointmentCompletedDate":"2017-06-22T07:00:00.000Z", + "AcademicAppointmentEndDate":null, + "AcademicAppointmentIdentifierID":"P", + "AcademicAppointmentIdentifierTypeID":"Primary", + "AcademicAppointmentStartDate":"2017-04-01T07:00:00.000Z", + "AcademicAppointmentState":"Current", + "AcademicAppointmentTitle":"Professor", + "AcademicAppointmentTrackID":"AC-000000015-1", + "AcademicUnitID":"050", + "AcademicUnitName":"Family Medicine", + "AcademicUnitSupervisoryOrganizations": + [{"AcademicUnitID":"050", + "Code":"SOM:", + "CostCenter": + {"Description":"WORKDAY DEFAULT DEPTBG", + "ID":"681925", + "OrganizationCode":"3040111000", + "OrganizationDescription":"FAMILY MEDICINE"}, + "Description":"SOM: Family Medicine (Visor, Super1)", + "Href":"\/hrp\/v2\/organization\/SOM_000420.json", + "ID":"SOM_000420", + "Name":"Family Medicine"}, + {"AcademicUnitID":"081", + "Code":"SOM:", + "CostCenter": + {"Description":"DOM PAYROLL SUSPENSE", + "ID":"656131", + "OrganizationCode":"3040510019", + "OrganizationDescription":"FINANCE ABC\/DEANS HR"}, + "Description":"School of Medicine (Dean, Bill)", + "Href":"\/hrp\/v2\/organization\/SOM_000001.json", + "ID":"SOM_000001", + "Name":"School of Medicine"} + ], + "ActualAcademicAppointmentEndDate":null, + "AppointmentPositionID":"PN-0000809", + "PositionSupervisoryOrganization": + {"AcademicUnitID":null, + "Code":"SOM:", + "CostCenter": + {"Description":"DOM PAYROLL SUSPENSE", + "ID":"656131", + "OrganizationCode":"3040510019", + "OrganizationDescription":"FINANCE ABC\/DEANS HR"}, + "Description":"School of Medicine (Dean, Bill)", + "Href":"\/hrp\/v2\/organization\/SOM_000001.json", + "ID":"SOM_000001", + "Name":"School of Medicine"}, + "PrimaryPositionID":"PN-0000809", + "SuperiorAcademicUnitID":"081"}], + "DisplayFirstName":"Super1", + "DisplayLastName":"Visor", + "DisplayMiddleName":null, + "DisplayName":"Super1 Visor", + "EmployeeID":"100000015", + "EmployeeIDPrior":null, + "FormattedLegalNameFirstLast":"Super1 Visor", + "FormattedLegalNameFirstMiddleLast":"Super1 Visor", + "FormattedLegalNameLastFirstMiddle":"Visor, Super1", + "FormattedPreferredNameFirstLast":"Super1 Visor", + "FormattedPreferredNameFirstMiddleLast":"Super1 Visor", + "FormattedPreferredNameLastFirstMiddle":"Visor, Super1", + "HuskyCardOverride":null, + "IsCurrentFaculty":true, + "IsFutureDate":false, + "LegalFirstName":"Super1", + "LegalLastName":"Visor", + "LegalMiddleName":"A", + "LegalNameSuffix":null, + "NetID":"jamespa", + "PreferredFirstName":"Super1", + "PreferredLastName":"Visor", + "PreferredMiddleName":null, + "PreferredNameSuffix":null, + "RegID":"10000000000000000000000000000015", + "RepositoryTimeStamp":"2019-03-06T16:12:12.214Z", + "SystemMetadata":{"LastModified":null}, + "WorkdayPersonType":"Employee", + "WorkerContact": + {"Addresses":[ + {"Country":"United States of America", + "CountryCodeISO2":"US", + "IsPrimary":true, + "IsPubliclyAvailable":true, + "Lines":["Seattle Main Campus"], + "Municipality":"Seattle", + "PostalCode":"98195", + "Region":"Washington", + "Type":"WORK"}, + {"Country":"United States of America", + "CountryCodeISO2":"US", + "IsPrimary":false, + "IsPubliclyAvailable":true, + "Lines":["1705 NE Pacific St"], + "Municipality":"Seattle", + "PostalCode":"98195-0000", + "Region":"Washington", + "Type":"WORK"}], + "CampusBox":"356390", + "EmailAddresses":[ + {"Address":"jamespa@uw.edu", + "IsPrimary":true, + "IsPubliclyAvailable":true, + "Type":"WORK"}], + "Phones":[{"AreaCode":"206", + "DeviceType":"Telephone", + "InternationalCode":"1", + "IsPrimary":true, + "IsPubliclyAvailable":true, + "NANPPhoneNumber":"+1 (206) 685-3466", + "Number":"685-3466", + "Type":"WORK"}, + {"AreaCode":"206", + "DeviceType":"Telephone", + "InternationalCode":"1", + "IsPrimary":false, + "IsPubliclyAvailable":true, + "NANPPhoneNumber":"+1 (206) 543-5563", + "Number":"543-5563", + "Type":"WORK"} + ] + }, + "WorkerEmploymentStatus": + {"ActiveStatusDate":"2017-04-01T07:00:00.000Z", + "EmployeeStatus":"Active", + "EmployeeStatusCode":"A", + "EndEmploymentDate":null, + "EstimatedLastDayOfLeave":null, + "FirstDayOfLeave":null, + "FirstDayOfWork":"2017-04-01T07:00:00.000Z", + "HireDate":"2017-04-01T07:00:00.000Z", + "IsActive":true, + "IsRetired":false, + "IsTerminated":false, + "LastDayOfWorkForLeave":null, + "OriginalHireDate":"2017-03-31T07:00:00.000Z", + "RetirementDate":null, + "TerminationDate":null}, + "WorkerPositions":[ + {"CostCenter": + {"Description":"WORKDAY DEFAULT DEPTBG", + "ID":"681925", + "OrganizationCode":"3040111000", + "OrganizationDescription":"FAMILY MEDICINE" + }, + "EcsJobClassificationCode":"F", + "EcsJobClassificationCodeDescription":"Academic Personnel", + "FutureTransactions":[], + "IsFutureDate":false, + "IsMedicalCenterPosition":false, + "IsOnLeaveFromPosition":false, + "IsPrimaryPosition":true, + "JobProfileSummary": + {"Href":"\/hrp\/v2\/jobProfile\/10101.json", + "JobCategory":"Faculty", + "JobFamilies":[ + {"JobFamilyID":"Faculty - Indefinite and Multi-Year", + "JobFamilyName":"01 - Academic Personnel - Faculty - Indefinite and Multi-Year", + "JobFamilySummary":"Academic positions designated as faculty under the Faculty Code Chapter 21"} + ], + "JobProfileDescription":"Professor", + "JobProfileID":"10101" + }, + "Location": + {"ID":"Seattle Campus", + "Name":"Seattle Campus" + }, + "ObjectCode":"01", + "PayRateType":"Salary", + "PayrollUnitCode":"00753", + "PlannedDistributions":{}, + "PositionBusinessTitle":"Chair", + "PositionEffectiveDate":"2017-04-01T07:00:00.000Z", + "PositionEndDate":null, + "PositionFTEPercent":"100.00000", + "PositionID":"PN-0000809", + "PositionStartDate":"2017-04-01T00:00:00.000Z", + "PositionSupervisor": + {"EmployeeID":"100000115", + "Href":"\/hrp\/v2\/worker\/100000115.json" + }, + "PositionTimeTypeID":"Full_time", + "PositionTitle":"PROFESSOR, School of Medicine", + "PositionType":"Regular_Practice_Plan", + "ServicePeriodDescription":"Service_Period_12.00", + "ServicePeriodID":"12", + "SubObjectCode":"10", + "SupervisoryOrganization": + {"AcademicUnitID":null, + "Code":"SOM:", + "CostCenter": + {"Description":"DOM PAYROLL SUSPENSE", + "ID":"656131", + "OrganizationCode":"3040510019", + "OrganizationDescription":"FINANCE ABC\/DEANS HR" + }, + "Description":"School of Medicine (Dean, Bill)", + "Href":"\/hrp\/v2\/organization\/SOM_000001.json", + "ID":"SOM_000001", + "Name":"School of Medicine" + }, + "TotalBasePayAmount":"0.00000", + "TotalBasePayAnnualizedAmount":"0.00000", + "TotalBasePayFrequency":"Monthly", + "TotalPayAnnualizedAmount":"0.00000", + "WorkShift":"First Shift" + } + ] +} diff --git a/uw_hrp/resources/hrpws/file/hrp/v2/worker/chair.json b/uw_hrp/resources/hrpws/file/hrp/v2/worker/chair.json new file mode 100644 index 0000000..9a97b84 --- /dev/null +++ b/uw_hrp/resources/hrpws/file/hrp/v2/worker/chair.json @@ -0,0 +1,250 @@ +{ + "AcademicAppointments": + [{"AcademicAppointmentCompletedDate":"2017-06-22T07:00:00.000Z", + "AcademicAppointmentEndDate":null, + "AcademicAppointmentIdentifierID":"A", + "AcademicAppointmentIdentifierTypeID":"Administrative", + "AcademicAppointmentStartDate":"2017-04-01T07:00:00.000Z", + "AcademicAppointmentState":"Current", + "AcademicAppointmentTitle":"Chair", + "AcademicAppointmentTrackID":"AC-000000015-2", + "AcademicUnitID":"050", + "AcademicUnitName":"Family Medicine", + "AcademicUnitSupervisoryOrganizations": + [{"AcademicUnitID":"050", + "Code":"SOM:", + "CostCenter": + {"Description":"WORKDAY DEFAULT DEPTBG", + "ID":"681925", + "OrganizationCode":"3040111000", + "OrganizationDescription":"FAMILY MEDICINE"}, + "Description":"SOM: Family Medicine (Visor, Super1)", + "Href":"\/hrp\/v2\/organization\/SOM_000420.json", + "ID":"SOM_000420", + "Name":"Family Medicine"}, + {"AcademicUnitID":"081", + "Code":"SOM:", + "CostCenter": + {"Description":"DOM PAYROLL SUSPENSE", + "ID":"656131", + "OrganizationCode":"3040510019", + "OrganizationDescription":"FINANCE ABC\/DEANS HR"}, + "Description":"School of Medicine (Dean, Bill)", + "Href":"\/hrp\/v2\/organization\/SOM_000001.json", + "ID":"SOM_000001", + "Name":"School of Medicine"} + ], + "ActualAcademicAppointmentEndDate":null, + "AppointmentPositionID":null, + "PositionSupervisoryOrganization":null, + "PrimaryPositionID":"PN-0000809", + "SuperiorAcademicUnitID":"081"}, + {"AcademicAppointmentCompletedDate":"2017-06-22T07:00:00.000Z", + "AcademicAppointmentEndDate":null, + "AcademicAppointmentIdentifierID":"P", + "AcademicAppointmentIdentifierTypeID":"Primary", + "AcademicAppointmentStartDate":"2017-04-01T07:00:00.000Z", + "AcademicAppointmentState":"Current", + "AcademicAppointmentTitle":"Professor", + "AcademicAppointmentTrackID":"AC-000000015-1", + "AcademicUnitID":"050", + "AcademicUnitName":"Family Medicine", + "AcademicUnitSupervisoryOrganizations": + [{"AcademicUnitID":"050", + "Code":"SOM:", + "CostCenter": + {"Description":"WORKDAY DEFAULT DEPTBG", + "ID":"681925", + "OrganizationCode":"3040111000", + "OrganizationDescription":"FAMILY MEDICINE"}, + "Description":"SOM: Family Medicine (Visor, Super1)", + "Href":"\/hrp\/v2\/organization\/SOM_000420.json", + "ID":"SOM_000420", + "Name":"Family Medicine"}, + {"AcademicUnitID":"081", + "Code":"SOM:", + "CostCenter": + {"Description":"DOM PAYROLL SUSPENSE", + "ID":"656131", + "OrganizationCode":"3040510019", + "OrganizationDescription":"FINANCE ABC\/DEANS HR"}, + "Description":"School of Medicine (Dean, Bill)", + "Href":"\/hrp\/v2\/organization\/SOM_000001.json", + "ID":"SOM_000001", + "Name":"School of Medicine"} + ], + "ActualAcademicAppointmentEndDate":null, + "AppointmentPositionID":"PN-0000809", + "PositionSupervisoryOrganization": + {"AcademicUnitID":null, + "Code":"SOM:", + "CostCenter": + {"Description":"DOM PAYROLL SUSPENSE", + "ID":"656131", + "OrganizationCode":"3040510019", + "OrganizationDescription":"FINANCE ABC\/DEANS HR"}, + "Description":"School of Medicine (Dean, Bill)", + "Href":"\/hrp\/v2\/organization\/SOM_000001.json", + "ID":"SOM_000001", + "Name":"School of Medicine"}, + "PrimaryPositionID":"PN-0000809", + "SuperiorAcademicUnitID":"081"}], + "DisplayFirstName":"Super1", + "DisplayLastName":"Visor", + "DisplayMiddleName":null, + "DisplayName":"Super1 Visor", + "EmployeeID":"100000015", + "EmployeeIDPrior":null, + "FormattedLegalNameFirstLast":"Super1 Visor", + "FormattedLegalNameFirstMiddleLast":"Super1 Visor", + "FormattedLegalNameLastFirstMiddle":"Visor, Super1", + "FormattedPreferredNameFirstLast":"Super1 Visor", + "FormattedPreferredNameFirstMiddleLast":"Super1 Visor", + "FormattedPreferredNameLastFirstMiddle":"Visor, Super1", + "HuskyCardOverride":null, + "IsCurrentFaculty":true, + "IsFutureDate":false, + "LegalFirstName":"Super1", + "LegalLastName":"Visor", + "LegalMiddleName":"A", + "LegalNameSuffix":null, + "NetID":"jamespa", + "PreferredFirstName":"Super1", + "PreferredLastName":"Visor", + "PreferredMiddleName":null, + "PreferredNameSuffix":null, + "RegID":"10000000000000000000000000000015", + "RepositoryTimeStamp":"2019-03-06T16:12:12.214Z", + "SystemMetadata":{"LastModified":null}, + "WorkdayPersonType":"Employee", + "WorkerContact": + {"Addresses":[ + {"Country":"United States of America", + "CountryCodeISO2":"US", + "IsPrimary":true, + "IsPubliclyAvailable":true, + "Lines":["Seattle Main Campus"], + "Municipality":"Seattle", + "PostalCode":"98195", + "Region":"Washington", + "Type":"WORK"}, + {"Country":"United States of America", + "CountryCodeISO2":"US", + "IsPrimary":false, + "IsPubliclyAvailable":true, + "Lines":["1705 NE Pacific St"], + "Municipality":"Seattle", + "PostalCode":"98195-0000", + "Region":"Washington", + "Type":"WORK"}], + "CampusBox":"356390", + "EmailAddresses":[ + {"Address":"jamespa@uw.edu", + "IsPrimary":true, + "IsPubliclyAvailable":true, + "Type":"WORK"}], + "Phones":[{"AreaCode":"206", + "DeviceType":"Telephone", + "InternationalCode":"1", + "IsPrimary":true, + "IsPubliclyAvailable":true, + "NANPPhoneNumber":"+1 (206) 685-3466", + "Number":"685-3466", + "Type":"WORK"}, + {"AreaCode":"206", + "DeviceType":"Telephone", + "InternationalCode":"1", + "IsPrimary":false, + "IsPubliclyAvailable":true, + "NANPPhoneNumber":"+1 (206) 543-5563", + "Number":"543-5563", + "Type":"WORK"} + ] + }, + "WorkerEmploymentStatus": + {"ActiveStatusDate":"2017-04-01T07:00:00.000Z", + "EmployeeStatus":"Active", + "EmployeeStatusCode":"A", + "EndEmploymentDate":null, + "EstimatedLastDayOfLeave":null, + "FirstDayOfLeave":null, + "FirstDayOfWork":"2017-04-01T07:00:00.000Z", + "HireDate":"2017-04-01T07:00:00.000Z", + "IsActive":true, + "IsRetired":false, + "IsTerminated":false, + "LastDayOfWorkForLeave":null, + "OriginalHireDate":"2017-03-31T07:00:00.000Z", + "RetirementDate":null, + "TerminationDate":null}, + "WorkerPositions":[ + {"CostCenter": + {"Description":"WORKDAY DEFAULT DEPTBG", + "ID":"681925", + "OrganizationCode":"3040111000", + "OrganizationDescription":"FAMILY MEDICINE" + }, + "EcsJobClassificationCode":"F", + "EcsJobClassificationCodeDescription":"Academic Personnel", + "FutureTransactions":[], + "IsFutureDate":false, + "IsMedicalCenterPosition":false, + "IsOnLeaveFromPosition":false, + "IsPrimaryPosition":true, + "JobProfileSummary": + {"Href":"\/hrp\/v2\/jobProfile\/10101.json", + "JobCategory":"Faculty", + "JobFamilies":[ + {"JobFamilyID":"Faculty - Indefinite and Multi-Year", + "JobFamilyName":"01 - Academic Personnel - Faculty - Indefinite and Multi-Year", + "JobFamilySummary":"Academic positions designated as faculty under the Faculty Code Chapter 21"} + ], + "JobProfileDescription":"Professor", + "JobProfileID":"10101" + }, + "Location": + {"ID":"Seattle Campus", + "Name":"Seattle Campus" + }, + "ObjectCode":"01", + "PayRateType":"Salary", + "PayrollUnitCode":"00753", + "PlannedDistributions":{}, + "PositionBusinessTitle":"Chair", + "PositionEffectiveDate":"2017-04-01T07:00:00.000Z", + "PositionEndDate":null, + "PositionFTEPercent":"100.00000", + "PositionID":"PN-0000809", + "PositionStartDate":"2017-04-01T00:00:00.000Z", + "PositionSupervisor": + {"EmployeeID":"100000115", + "Href":"\/hrp\/v2\/worker\/100000115.json" + }, + "PositionTimeTypeID":"Full_time", + "PositionTitle":"PROFESSOR, School of Medicine", + "PositionType":"Regular_Practice_Plan", + "ServicePeriodDescription":"Service_Period_12.00", + "ServicePeriodID":"12", + "SubObjectCode":"10", + "SupervisoryOrganization": + {"AcademicUnitID":null, + "Code":"SOM:", + "CostCenter": + {"Description":"DOM PAYROLL SUSPENSE", + "ID":"656131", + "OrganizationCode":"3040510019", + "OrganizationDescription":"FINANCE ABC\/DEANS HR" + }, + "Description":"School of Medicine (Dean, Bill)", + "Href":"\/hrp\/v2\/organization\/SOM_000001.json", + "ID":"SOM_000001", + "Name":"School of Medicine" + }, + "TotalBasePayAmount":"0.00000", + "TotalBasePayAnnualizedAmount":"0.00000", + "TotalBasePayFrequency":"Monthly", + "TotalPayAnnualizedAmount":"0.00000", + "WorkShift":"First Shift" + } + ] +} diff --git a/uw_hrp/resources/hrpws/file/hrp/v2/worker/faculty.json b/uw_hrp/resources/hrpws/file/hrp/v2/worker/faculty.json new file mode 100644 index 0000000..9843d9c --- /dev/null +++ b/uw_hrp/resources/hrpws/file/hrp/v2/worker/faculty.json @@ -0,0 +1,217 @@ +{ + "AcademicAppointments":[ + { + "AcademicAppointmentCompletedDate":"2018-05-17T07:00:00.000Z", + "AcademicAppointmentEndDate":"2019-06-30T07:00:00.000Z", + "AcademicAppointmentIdentifierID":"P", + "AcademicAppointmentIdentifierTypeID":"Primary", + "AcademicAppointmentStartDate":"2012-07-01T07:00:00.000Z", + "AcademicAppointmentState":"Current", + "AcademicAppointmentTitle":"Clinical Associate Professor", + "AcademicAppointmentTrackID":"AC-000000005-1", + "AcademicUnitID":"050", + "AcademicUnitName":"Family Medicine", + "AcademicUnitSupervisoryOrganizations":[ + {"AcademicUnitID":"050", + "Code":"SOM:", + "CostCenter": + {"Description":"WORKDAY DEFAULT DEPTBG", + "ID":"681925", + "OrganizationCode":"3040111000", + "OrganizationDescription":"FAMILY MEDICINE" + }, + "Description":"SOM: Family Medicine (Visor, Super1)", + "Href":"\/hrp\/v2\/organization\/SOM_000420.json", + "ID":"SOM_000420", + "Name":"Family Medicine"}, + {"AcademicUnitID":"081", + "Code":"SOM:", + "CostCenter": + { + "Description":"DOM PAYROLL SUSPENSE", + "ID":"656131", + "OrganizationCode":"3040510019", + "OrganizationDescription":"FINANCE ABC\/DEANS HR" + }, + "Description":"School of Medicine (Dean, Bill)", + "Href":"\/hrp\/v2\/organization\/SOM_000001.json", + "ID":"SOM_000001", + "Name":"School of Medicine" + } + ], + "ActualAcademicAppointmentEndDate":"2019-06-30T07:00:00.000Z", + "AppointmentPositionID":"PN-0054525", + "PositionSupervisoryOrganization": + { + "AcademicUnitID":null, + "Code":"SOM:", + "CostCenter": + {"Description":"WORKDAY DEFAULT DEPTBG", + "ID":"681925", + "OrganizationCode":"3040111000", + "OrganizationDescription":"FAMILY MEDICINE" + }, + "Description":"SOM: Family Medicine: Volunteer (Visor, Super1)", + "Href":"\/hrp\/v2\/organization\/SOM_000420.json", + "ID":"SOM_000420", + "Name":"Family Medicine: Volunteer JM Academic" + }, + "PrimaryPositionID":"PN-0054525", + "SuperiorAcademicUnitID":"081" + } + ], + "DisplayFirstName":"William E", + "DisplayLastName":"Faculty", + "DisplayMiddleName":null, + "DisplayName":"William E Faculty", + "EmployeeID":"000000005", + "EmployeeIDPrior":null, + "FormattedLegalNameFirstLast":"William Faculty", + "FormattedLegalNameFirstMiddleLast":"William E Faculty", + "FormattedLegalNameLastFirstMiddle":"Faculty, William E", + "FormattedPreferredNameFirstLast":"William E Faculty", + "FormattedPreferredNameFirstMiddleLast":"William E Faculty", + "FormattedPreferredNameLastFirstMiddle":"Faculty, William E", + "HuskyCardOverride":null, + "IsCurrentFaculty":true, + "IsFutureDate":false, + "LegalFirstName":"William", + "LegalLastName":"Faculty", + "LegalMiddleName":"E", + "LegalNameSuffix":null, + "NetID":"faculty", + "PreferredFirstName":"William E", + "PreferredLastName":"Faculty", + "PreferredMiddleName":null, + "PreferredNameSuffix":null, + "RegID":"10000000000000000000000000000005", + "RepositoryTimeStamp":"2019-01-25T16:05:03.721Z", + "SystemMetadata":{"LastModified":null}, + "WorkdayPersonType":"Academic Affiliate", + "WorkerContact": + {"Addresses":[ + {"Country":"United States of America", + "CountryCodeISO2":"US", + "IsPrimary":true, + "IsPubliclyAvailable":true, + "Lines":["Seattle Main Campus"], + "Municipality":"Seattle", + "PostalCode":"98195", + "Region":"Washington", + "Type":"WORK"}, + {"Country":"United States of America", + "CountryCodeISO2":"US", + "IsPrimary":false, + "IsPubliclyAvailable":true, + "Lines":["1705 NE Pacific St"], + "Municipality":"Seattle", + "PostalCode":"98195-0000", + "Region":"Washington", + "Type":"WORK"} + ], + "CampusBox":"356390", + "EmailAddresses":[ + {"Address":"faculty@uw.edu", + "IsPrimary":true, + "IsPubliclyAvailable":true, + "Type":"WORK"}], + "Phones":[ + {"AreaCode":"253", + "DeviceType":"Telephone", + "InternationalCode":"1", + "IsPrimary":true, + "IsPubliclyAvailable":true, + "NANPPhoneNumber":"+1 (206) 123-1234", + "Number":"123-1234", + "Type":"WORK"}, + {"AreaCode":"203", + "DeviceType":"Telephone", + "InternationalCode":"1", + "IsPrimary":false, + "IsPubliclyAvailable":true, + "NANPPhoneNumber":"+1 (203) 678-1234", + "Number":"678-1234", + "Type":"WORK"} + ] + }, + "WorkerEmploymentStatus":{ + "ActiveStatusDate":"2006-05-16T07:00:00.000Z", + "EmployeeStatus":"Active", + "EmployeeStatusCode":"A", + "EndEmploymentDate":null, + "EstimatedLastDayOfLeave":null, + "FirstDayOfLeave":null, + "FirstDayOfWork":"2006-05-16T07:00:00.000Z", + "HireDate":"2006-05-16T07:00:00.000Z", + "IsActive":true, + "IsRetired":false, + "IsTerminated":false, + "LastDayOfWorkForLeave":null, + "OriginalHireDate":"2006-05-16T07:00:00.000Z", + "RetirementDate":null, + "TerminationDate":null}, + "WorkerPositions":[ + {"CostCenter": + {"Description":"WORKDAY DEFAULT DEPTBG", + "ID":"681925", + "OrganizationCode":"3040111000", + "OrganizationDescription":"FAMILY MEDICINE"}, + "EcsJobClassificationCode":"F", + "EcsJobClassificationCodeDescription":"Academic Personnel", + "FutureTransactions":[], + "IsFutureDate":false, + "IsMedicalCenterPosition":false, + "IsOnLeaveFromPosition":false, + "IsPrimaryPosition":true, + "JobProfileSummary":{ + "Href":"\/hrp\/v2\/jobProfile\/21184.json", + "JobCategory":"Faculty", + "JobFamilies":[ + {"JobFamilyID":"Faculty - Annual or Shorter", + "JobFamilyName":"01 - Academic Personnel - Faculty - Annual or Shorter", + "JobFamilySummary":null}], + "JobProfileDescription":"Unpaid Academic", + "JobProfileID":"21184"}, + "Location":{ + "ID":"Seattle Campus", + "Name":"Seattle Campus"}, + "ObjectCode":null, + "PayRateType":"N\/A", + "PayrollUnitCode":"00753", + "PlannedDistributions":{ + "PeriodActivityAssignments":[], + "PlannedCompensationAllocations":[]}, + "PositionBusinessTitle":"Clinical Associate Professor", + "PositionEffectiveDate":"2012-07-01T07:00:00.000Z", + "PositionEndDate":null, + "PositionFTEPercent":"0.00000", + "PositionID":"PN-0054525", + "PositionStartDate":"2012-07-01T00:00:00.000Z", + "PositionSupervisor":{ + "EmployeeID":"100000015", + "Href":"\/hrp\/v2\/worker\/100000015.json"}, + "PositionTimeTypeID":"Part_time", + "PositionTitle":"CLINICAL ASSOCIATE PROFESSOR, Family Medicine JM Academic", + "PositionType":"Unpaid_Academic", + "ServicePeriodDescription":"Service_Period_12.00", + "ServicePeriodID":"12", + "SubObjectCode":null, + "SupervisoryOrganization":{ + "AcademicUnitID":null, + "Code":"SOM", + "CostCenter": + {"Description":"WORKDAY DEFAULT DEPTBG", + "ID":"681925", + "OrganizationCode":"3040111000", + "OrganizationDescription":"FAMILY MEDICINE"}, + "Description":"SOM: Family Medicine: Volunteer (Visor, Super1)", + "Href":"\/hrp\/v2\/organization\/SOM_000420.json", + "ID":"SOM_000420", + "Name":"Family Medicine: Volunteer"}, + "TotalBasePayAmount":"0.00000", + "TotalBasePayAnnualizedAmount":"0.00000", + "TotalBasePayFrequency":null, + "TotalPayAnnualizedAmount":"0.00000", + "WorkShift":"First Shift"} + ] +} diff --git a/uw_hrp/tests/test_appointee.py b/uw_hrp/tests/test_appointee.py deleted file mode 100644 index 66cef60..0000000 --- a/uw_hrp/tests/test_appointee.py +++ /dev/null @@ -1,62 +0,0 @@ -from unittest import TestCase -from uw_hrp.appointee import get_appointee_by_netid,\ - get_appointee_by_eid, get_appointee_by_regid -from restclients_core.exceptions import DataFailureException -from uw_hrp.util import fdao_hrp_override - - -@fdao_hrp_override -class AppointeeTest(TestCase): - - def test_get_appointee(self): - self.eval(get_appointee_by_netid("javerage")) - self.eval(get_appointee_by_eid("123456789")) - self.eval(get_appointee_by_regid( - "9136CCB8F66711D5BE060004AC494FFE")) - - def eval(self, ap): - self.assertTrue(ap.is_active_emp_status()) - self.assertEqual(ap.netid, - "javerage") - self.assertEqual(ap.regid, - "9136CCB8F66711D5BE060004AC494FFE") - self.assertEqual(ap.employee_id, - "123456789") - self.assertEqual(ap.status, "A") - self.assertEqual(ap.status_desc, "ACTIVE") - self.assertEqual(ap.home_dept_budget_number, "100001") - self.assertEqual(ap.home_dept_budget_name, "UWIT GOF") - self.assertEqual(ap.home_dept_org_code, "2100101000") - self.assertEqual(ap.home_dept_org_name, "OVP - UW-IT") - self.assertEqual(ap.onoff_campus_code, "1") - self.assertEqual(ap.onoff_campus_code_desc, "On Campus") - self.assertEqual(len(ap.appointments), 1) - appointments = ap.appointments - self.assertEqual(len(appointments), 1) - self.assertEqual(appointments[0].app_number, 1) - self.assertEqual(appointments[0].app_state, "Current") - self.assertTrue(appointments[0].is_current_app_state()) - self.assertEqual(appointments[0].dept_budget_name, - "ACAD. & COLLAB. APP'S") - self.assertEqual(appointments[0].dept_budget_number, - "100001") - self.assertEqual(appointments[0].job_class_code, - "0875") - self.assertEqual(appointments[0].job_class_title, - "STUDENT ASSISTANT") - self.assertEqual(appointments[0].org_code, - "2101002000") - self.assertEqual(appointments[0].org_name, - "ACAD. & COLLAB. APPL.") - self.assertEqual(appointments[0].paid_app_code, "P") - self.assertEqual(appointments[0].status, "A") - self.assertEqual(appointments[0].status_desc, "ACTIVE") - - def test_invalid_user(self): - self.assertRaises(DataFailureException, - get_appointee_by_regid, - "00000000000000000000000000000001") - - self.assertRaises(DataFailureException, - get_appointee_by_eid, - "100000000") diff --git a/uw_hrp/tests/test_models.py b/uw_hrp/tests/test_models.py new file mode 100644 index 0000000..52c86f0 --- /dev/null +++ b/uw_hrp/tests/test_models.py @@ -0,0 +1,123 @@ +from unittest import TestCase +from uw_hrp import parse_date +from uw_hrp.models import Worker, WorkerPosition +from uw_hrp.util import fdao_hrp_override + + +@fdao_hrp_override +class WorkerTest(TestCase): + + def test_parse_date(self): + self.assertIsNotNone(parse_date("2017-09-16T07:00:00.000Z")) + + def test_workerposition(self): + data = { + "CostCenter": + {"Description": "INFORMATION SCHOOL", + "ID": "061630", + "OrganizationCode": "2670001000", + "OrganizationDescription": "THE INFORMATION SCHOOL"}, + "EcsJobClassificationCodeDescription": "Undergraduate Student", + "IsPrimaryPosition": True, + "Location": + {"ID": "Seattle Campus", + "Name": "Seattle Campus"}, + "PositionBusinessTitle": "Reader/Grader", + "PositionEffectiveDate": "2017-09-16T07:00:00.000Z", + "PositionEndDate": "2018-06-15T00:00:00.000Z", + "PositionSupervisor": + {"EmployeeID": "000000005", + "Href": "/hrp/v2/worker/000000005.json"}, + "PositionTimeTypeID": "Part_time", + "PositionTitle": "Reader/Grader", + "PositionType": "Temporary", + "SupervisoryOrganization": None, + "WorkShift": "First Shift" + } + work_position = WorkerPosition(data=data) + self.assertEqual( + work_position.json_data(), + {'busi_title': 'Reader/Grader', + 'ecs_job_cla_code_desc': 'Undergraduate Student', + 'effective_date': '2017-09-16 07:00:00+00:00', + 'end_date': '2018-06-15 00:00:00+00:00', + 'is_primary': True, + 'location': 'Seattle Campus', + 'org_code': '2670001000', + 'org_desc': 'THE INFORMATION SCHOOL', + 'pos_time_type_id': 'Part_time', + 'pos_type': 'Temporary', + 'supervisor_eid': '000000005', + 'supervisory_org_code': None, + 'supervisory_org_desc': None, + 'supervisory_org_id': None}) + self.assertIsNotNone(str(work_position)) + + def test_worker(self): + data = { + "NetID": "dean", + "RegID": "10000000000000000000000000000115", + "EmployeeID": "100000115", + "WorkerEmploymentStatus": + {"ActiveStatusDate": "1980-07-01T07:00:00.000Z", + "EmployeeStatus": "Active", + "EmployeeStatusCode": "A", + "EndEmploymentDate": None, + "EstimatedLastDayOfLeave": None, + "FirstDayOfLeave": None, + "FirstDayOfWork": "1980-07-01T07:00:00.000Z", + "HireDate": "1980-07-01T07:00:00.000Z", + "IsActive": True, + "IsRetired": False, + "IsTerminated": False, + "LastDayOfWorkForLeave": None, + "OriginalHireDate": "1980-07-01T07:00:00.000Z", + "RetirementDate": None, + "TerminationDate": None}, + "WorkerPositions": [ + {"CostCenter": + {"Description": "SOM ADMINISTRATION", + "ID": "652791", + "OrganizationCode": "3040501060", + "OrganizationDescription": "EXEC MGMT OEVP ADMIN"}, + "EcsJobClassificationCode": "F", + "EcsJobClassificationCodeDescription": "Academic Personnel", + "IsPrimaryPosition": True, + "Location": + {"ID": "Seattle Campus", + "Name": "Seattle Campus"}, + "PositionBusinessTitle": + "CEO, UW Medicine and Dean of the School of Medicine", + "PositionEffectiveDate": "1999-06-13T07:00:00.000Z", + "PositionEndDate": None, + "PositionSupervisor": + {"EmployeeID": "100001115"}, + "WorkShift": "First Shift"}]} + worker = Worker(data=data) + self.assertEqual( + worker.json_data(), + {'netid': 'dean', + 'regid': "10000000000000000000000000000115", + 'employee_id': '100000115', + 'employee_status': 'Active', + 'is_active': True, + 'is_retired': False, + 'is_terminated': False, + 'worker_positions': [ + {'effective_date': '1999-06-13 07:00:00+00:00', + 'end_date': None, + 'is_primary': True, + 'busi_title': + 'CEO, UW Medicine and Dean of the School of Medicine', + 'pos_type': None, + 'ecs_job_cla_code_desc': 'Academic Personnel', + 'location': 'Seattle Campus', + 'org_code': '3040501060', + 'org_desc': 'EXEC MGMT OEVP ADMIN', + 'pos_time_type_id': None, + 'supervisor_eid': '100001115', + 'supervisory_org_code': None, + 'supervisory_org_id': None, + 'supervisory_org_desc': None} + ]}) + self.assertIsNotNone(str(worker)) diff --git a/uw_hrp/tests/test_worker.py b/uw_hrp/tests/test_worker.py new file mode 100644 index 0000000..59075c8 --- /dev/null +++ b/uw_hrp/tests/test_worker.py @@ -0,0 +1,57 @@ +from unittest import TestCase +from uw_hrp.worker import ( + get_worker_by_netid, get_worker_by_employee_id, get_worker_by_regid) +from restclients_core.exceptions import DataFailureException +from uw_hrp.util import fdao_hrp_override + + +@fdao_hrp_override +class WorkerTest(TestCase): + + def test_get_worker_by_netid(self): + worker = get_worker_by_netid("faculty") + self.assertEqual(worker.netid, "faculty") + self.assertEqual(worker.regid, + "10000000000000000000000000000005") + self.assertEqual(worker.employee_id, "000000005") + self.assertEqual(worker.employee_status, "Active") + self.assertTrue(worker.is_active) + self.assertFalse(worker.is_retired) + self.assertFalse(worker.is_terminated) + + self.assertEqual(len(worker.worker_positions), 1) + work_position = worker.worker_positions[0] + self.assertEqual(work_position.org_code, '3040111000') + self.assertEqual(work_position.org_desc, "FAMILY MEDICINE") + self.assertEqual(work_position.ecs_job_cla_code_desc, + "Academic Personnel") + self.assertEqual(str(work_position.effective_date), + "2012-07-01 07:00:00+00:00") + self.assertIsNone(work_position.end_date) + self.assertEqual(work_position.busi_title, + "Clinical Associate Professor") + self.assertEqual(work_position.pos_type, "Unpaid_Academic") + self.assertEqual(work_position.supervisor_eid, "100000015") + self.assertEqual(work_position.pos_time_type_id, "Part_time") + self.assertEqual(work_position.supervisory_org_code, "SOM") + self.assertEqual(work_position.supervisory_org_id, "SOM_000420") + self.assertEqual(work_position.supervisory_org_desc, + "SOM: Family Medicine: Volunteer (Visor, Super1)") + self.assertEqual(work_position.location, "Seattle Campus") + self.assertTrue(work_position.is_primary) + + def test_get_worker_by_employee_id(self): + worker = get_worker_by_employee_id("100000015") + self.assertTrue(worker.netid, 'chair') + + def test_get_worker_by_regid(self): + worker = get_worker_by_regid("10000000000000000000000000000015") + self.assertTrue(worker.netid, 'chair') + + def test_invalid_user(self): + self.assertRaises(DataFailureException, + get_worker_by_regid, + "00000000000000000000000000000001") + + self.assertRaises(DataFailureException, + get_worker_by_employee_id, "100000000") diff --git a/uw_hrp/worker.py b/uw_hrp/worker.py new file mode 100644 index 0000000..e1c1008 --- /dev/null +++ b/uw_hrp/worker.py @@ -0,0 +1,42 @@ +""" +This is the interface for interacting with the HRP Web Service. +""" + +from datetime import datetime +import logging +import json +from restclients_core.exceptions import InvalidRegID, InvalidNetID,\ + InvalidEmployeeID +from uw_pws import PWS +from uw_hrp import get_resource +from uw_hrp.models import Worker + + +logger = logging.getLogger(__name__) +URL_PREFIX = "/hrp/v2/worker" + + +def get_worker_by_employee_id(employee_id): + if not PWS().valid_employee_id(employee_id): + raise InvalidEmployeeID(employee_id) + return _get_worker(employee_id) + + +def get_worker_by_netid(netid): + if not PWS().valid_uwnetid(netid): + raise InvalidNetID(netid) + return _get_worker(netid) + + +def get_worker_by_regid(regid): + if not PWS().valid_uwregid(regid): + raise InvalidRegID(regid) + return _get_worker(regid) + + +def _get_worker(id): + """ + Return a restclients.models.hrp.WorkerPerson object + """ + url = "{0}/{1}.json".format(URL_PREFIX, id) + return Worker(data=json.loads(get_resource(url))) From 802b72847de695c13ca4b3ddc824fc70bd975daa Mon Sep 17 00:00:00 2001 From: Fang Lin Date: Tue, 16 Apr 2019 10:14:48 -0700 Subject: [PATCH 02/10] Add list in Worker string --- uw_hrp/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uw_hrp/models.py b/uw_hrp/models.py index 9cb2797..be6300d 100644 --- a/uw_hrp/models.py +++ b/uw_hrp/models.py @@ -126,8 +126,8 @@ def json_data(self): def __str__(self): json_data = self.json_data() - json_data['worker_positions'] = ','.join( - map(str, self.worker_positions)) + json_data['worker_positions'] = "[{0}]".format(','.join( + map(str, self.worker_positions))) return json.dumps(json_data) def __init__(self, *args, **kwargs): From 8fbc15101198f8186f36596d2d93bbbb6a696dba Mon Sep 17 00:00:00 2001 From: Fang Lin Date: Tue, 16 Apr 2019 10:37:53 -0700 Subject: [PATCH 03/10] change mock phone number --- .../hrp/v2/worker/10000000000000000000000000000015.json | 8 ++++---- uw_hrp/resources/hrpws/file/hrp/v2/worker/100000015.json | 8 ++++---- uw_hrp/resources/hrpws/file/hrp/v2/worker/chair.json | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/uw_hrp/resources/hrpws/file/hrp/v2/worker/10000000000000000000000000000015.json b/uw_hrp/resources/hrpws/file/hrp/v2/worker/10000000000000000000000000000015.json index 9a97b84..4701a57 100644 --- a/uw_hrp/resources/hrpws/file/hrp/v2/worker/10000000000000000000000000000015.json +++ b/uw_hrp/resources/hrpws/file/hrp/v2/worker/10000000000000000000000000000015.json @@ -148,16 +148,16 @@ "InternationalCode":"1", "IsPrimary":true, "IsPubliclyAvailable":true, - "NANPPhoneNumber":"+1 (206) 685-3466", - "Number":"685-3466", + "NANPPhoneNumber":"+1 (206) 123-1234", + "Number":"123-1234", "Type":"WORK"}, {"AreaCode":"206", "DeviceType":"Telephone", "InternationalCode":"1", "IsPrimary":false, "IsPubliclyAvailable":true, - "NANPPhoneNumber":"+1 (206) 543-5563", - "Number":"543-5563", + "NANPPhoneNumber":"+1 (206) 123-1235", + "Number":"123-1235", "Type":"WORK"} ] }, diff --git a/uw_hrp/resources/hrpws/file/hrp/v2/worker/100000015.json b/uw_hrp/resources/hrpws/file/hrp/v2/worker/100000015.json index 9a97b84..4701a57 100644 --- a/uw_hrp/resources/hrpws/file/hrp/v2/worker/100000015.json +++ b/uw_hrp/resources/hrpws/file/hrp/v2/worker/100000015.json @@ -148,16 +148,16 @@ "InternationalCode":"1", "IsPrimary":true, "IsPubliclyAvailable":true, - "NANPPhoneNumber":"+1 (206) 685-3466", - "Number":"685-3466", + "NANPPhoneNumber":"+1 (206) 123-1234", + "Number":"123-1234", "Type":"WORK"}, {"AreaCode":"206", "DeviceType":"Telephone", "InternationalCode":"1", "IsPrimary":false, "IsPubliclyAvailable":true, - "NANPPhoneNumber":"+1 (206) 543-5563", - "Number":"543-5563", + "NANPPhoneNumber":"+1 (206) 123-1235", + "Number":"123-1235", "Type":"WORK"} ] }, diff --git a/uw_hrp/resources/hrpws/file/hrp/v2/worker/chair.json b/uw_hrp/resources/hrpws/file/hrp/v2/worker/chair.json index 9a97b84..4701a57 100644 --- a/uw_hrp/resources/hrpws/file/hrp/v2/worker/chair.json +++ b/uw_hrp/resources/hrpws/file/hrp/v2/worker/chair.json @@ -148,16 +148,16 @@ "InternationalCode":"1", "IsPrimary":true, "IsPubliclyAvailable":true, - "NANPPhoneNumber":"+1 (206) 685-3466", - "Number":"685-3466", + "NANPPhoneNumber":"+1 (206) 123-1234", + "Number":"123-1234", "Type":"WORK"}, {"AreaCode":"206", "DeviceType":"Telephone", "InternationalCode":"1", "IsPrimary":false, "IsPubliclyAvailable":true, - "NANPPhoneNumber":"+1 (206) 543-5563", - "Number":"543-5563", + "NANPPhoneNumber":"+1 (206) 123-1235", + "Number":"123-1235", "Type":"WORK"} ] }, From 37c2d6d2e45cb1d2f290eb2b0c466d5eb08bbf4f Mon Sep 17 00:00:00 2001 From: Fang Lin Date: Tue, 16 Apr 2019 11:23:53 -0700 Subject: [PATCH 04/10] Add dao test --- uw_hrp/tests/test_dao.py | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 uw_hrp/tests/test_dao.py diff --git a/uw_hrp/tests/test_dao.py b/uw_hrp/tests/test_dao.py new file mode 100644 index 0000000..9602f3b --- /dev/null +++ b/uw_hrp/tests/test_dao.py @@ -0,0 +1,10 @@ +from unittest import TestCase +from uw_hrp.dao import HRP_DAO + + +class DaoTest(TestCase): + + def test_dao(self): + dao = HRP_DAO() + self.assertEqual(dao.service_name(), "hrpws") + self.assertTrue(len(dao.service_mock_paths()) > 0) From 7d51d5f7aa5bb7882fcda068ec0508d137a4ce48 Mon Sep 17 00:00:00 2001 From: Fang Lin Date: Tue, 16 Apr 2019 13:38:03 -0700 Subject: [PATCH 05/10] change date to datetime field --- uw_hrp/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uw_hrp/models.py b/uw_hrp/models.py index be6300d..70be2f8 100644 --- a/uw_hrp/models.py +++ b/uw_hrp/models.py @@ -10,8 +10,8 @@ def date_to_str(d_obj): class WorkerPosition(models.Model): - effective_date = models.DateField(null=True, default=None) - end_date = models.DateField(null=True, default=None) + effective_date = models.DateTimeField(null=True, default=None) + end_date = models.DateTimeField(null=True, default=None) ecs_job_cla_code_desc = models.CharField(max_length=64, null=True, default=None) location = models.CharField(max_length=96, null=True, default=None) From e5e7e626e88c1c1bd49bb0bd7171405b7d64688e Mon Sep 17 00:00:00 2001 From: Fang Lin Date: Tue, 16 Apr 2019 14:52:19 -0700 Subject: [PATCH 06/10] Only collect active worker positions --- uw_hrp/models.py | 21 ++++++++++++++------- uw_hrp/tests/test_models.py | 7 ++++++- uw_hrp/tests/test_worker.py | 4 ++-- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/uw_hrp/models.py b/uw_hrp/models.py index 70be2f8..a5c9fd3 100644 --- a/uw_hrp/models.py +++ b/uw_hrp/models.py @@ -1,3 +1,4 @@ +from datetime import datetime, timezone import json from uw_hrp import parse_date from restclients_core import models @@ -31,6 +32,10 @@ class WorkerPosition(models.Model): supervisory_org_desc = models.CharField(max_length=256, null=True, default=None) + def is_active_position(self): + now = datetime.now(timezone.utc) + return self.end_date is None or self.end_date > now + def json_data(self): return { 'effective_date': date_to_str(self.effective_date), @@ -110,7 +115,7 @@ class Worker(models.Model): def json_data(self): positions = [] - for pos in self.worker_positions: + for pos in self.worker_active_positions: positions.append(pos.json_data()) return { @@ -121,13 +126,13 @@ def json_data(self): 'is_active': self.is_active, 'is_retired': self.is_retired, 'is_terminated': self.is_terminated, - 'worker_positions': positions + 'worker_active_positions': positions } def __str__(self): json_data = self.json_data() - json_data['worker_positions'] = "[{0}]".format(','.join( - map(str, self.worker_positions))) + json_data['worker_active_positions'] = "[{0}]".format(','.join( + map(str, self.worker_active_positions))) return json.dumps(json_data) def __init__(self, *args, **kwargs): @@ -146,10 +151,12 @@ def __init__(self, *args, **kwargs): self.is_retired = data["WorkerEmploymentStatus"]["IsRetired"] self.is_terminated = data["WorkerEmploymentStatus"]["IsTerminated"] - self.worker_positions = [] - if data.get("WorkerPositions") is not None: + self.worker_active_positions = [] + if self.is_active and data.get("WorkerPositions") is not None: for position in data["WorkerPositions"]: - self.worker_positions.append(WorkerPosition(data=position)) + position = WorkerPosition(data=position) + if position.is_active_position(): + self.worker_active_positions.append(position) class Meta: db_table = 'restclients_hrp_worker' diff --git a/uw_hrp/tests/test_models.py b/uw_hrp/tests/test_models.py index 52c86f0..cfaf77b 100644 --- a/uw_hrp/tests/test_models.py +++ b/uw_hrp/tests/test_models.py @@ -1,4 +1,5 @@ from unittest import TestCase +from datetime import datetime, timedelta, timezone from uw_hrp import parse_date from uw_hrp.models import Worker, WorkerPosition from uw_hrp.util import fdao_hrp_override @@ -51,6 +52,10 @@ def test_workerposition(self): 'supervisory_org_code': None, 'supervisory_org_desc': None, 'supervisory_org_id': None}) + self.assertFalse(work_position.is_active_position()) + work_position.end_date = (datetime.now(timezone.utc) + + timedelta(seconds=5)) + self.assertTrue(work_position.is_active_position()) self.assertIsNotNone(str(work_position)) def test_worker(self): @@ -103,7 +108,7 @@ def test_worker(self): 'is_active': True, 'is_retired': False, 'is_terminated': False, - 'worker_positions': [ + 'worker_active_positions': [ {'effective_date': '1999-06-13 07:00:00+00:00', 'end_date': None, 'is_primary': True, diff --git a/uw_hrp/tests/test_worker.py b/uw_hrp/tests/test_worker.py index 59075c8..7a1d44b 100644 --- a/uw_hrp/tests/test_worker.py +++ b/uw_hrp/tests/test_worker.py @@ -19,8 +19,8 @@ def test_get_worker_by_netid(self): self.assertFalse(worker.is_retired) self.assertFalse(worker.is_terminated) - self.assertEqual(len(worker.worker_positions), 1) - work_position = worker.worker_positions[0] + self.assertEqual(len(worker.worker_active_positions), 1) + work_position = worker.worker_active_positions[0] self.assertEqual(work_position.org_code, '3040111000') self.assertEqual(work_position.org_desc, "FAMILY MEDICINE") self.assertEqual(work_position.ecs_job_cla_code_desc, From 976300d7ad2712a62a0d3a725283b4456721d98f Mon Sep 17 00:00:00 2001 From: Fang Lin Date: Tue, 16 Apr 2019 15:01:49 -0700 Subject: [PATCH 07/10] inc test coverage --- uw_hrp/tests/test_worker.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/uw_hrp/tests/test_worker.py b/uw_hrp/tests/test_worker.py index 7a1d44b..24e69f3 100644 --- a/uw_hrp/tests/test_worker.py +++ b/uw_hrp/tests/test_worker.py @@ -1,7 +1,8 @@ from unittest import TestCase from uw_hrp.worker import ( get_worker_by_netid, get_worker_by_employee_id, get_worker_by_regid) -from restclients_core.exceptions import DataFailureException +from restclients_core.exceptions import ( + DataFailureException, InvalidEmployeeID, InvalidRegID, InvalidNetID) from uw_hrp.util import fdao_hrp_override @@ -55,3 +56,8 @@ def test_invalid_user(self): self.assertRaises(DataFailureException, get_worker_by_employee_id, "100000000") + + self.assertRaises(InvalidRegID, get_worker_by_regid, "000") + self.assertRaises(InvalidNetID, get_worker_by_netid, "#&$^&$") + self.assertRaises(InvalidEmployeeID, get_worker_by_employee_id, + "0") From 7fb4a6452c08f309475a9027d6fdab2e98eac520 Mon Sep 17 00:00:00 2001 From: Fang Lin Date: Fri, 24 May 2019 23:00:33 -0700 Subject: [PATCH 08/10] Reorg worker data --- uw_hrp/__init__.py | 7 - uw_hrp/models.py | 238 ++++++++++++++++++++------------ uw_hrp/tests/test_models.py | 261 ++++++++++++++++++++++-------------- uw_hrp/tests/test_worker.py | 101 +++++++++++--- 4 files changed, 389 insertions(+), 218 deletions(-) diff --git a/uw_hrp/__init__.py b/uw_hrp/__init__.py index 6dcab46..09a09fc 100644 --- a/uw_hrp/__init__.py +++ b/uw_hrp/__init__.py @@ -4,7 +4,6 @@ """ import logging -from dateutil.parser import parse from uw_hrp.dao import HRP_DAO from restclients_core.exceptions import DataFailureException @@ -22,9 +21,3 @@ def get_resource(url): logger.debug("{0} ==data==> {1}".format(url, response.data)) return response.data - - -def parse_date(date_str): - if date_str is not None: - return parse(date_str) - return None diff --git a/uw_hrp/models.py b/uw_hrp/models.py index a5c9fd3..99654c1 100644 --- a/uw_hrp/models.py +++ b/uw_hrp/models.py @@ -1,6 +1,6 @@ from datetime import datetime, timezone +from dateutil.parser import parse import json -from uw_hrp import parse_date from restclients_core import models @@ -10,153 +10,215 @@ def date_to_str(d_obj): return None +def parse_date(date_str): + if date_str is not None: + return parse(date_str) + return None + + +class EmploymentStatus(models.Model): + status = models.CharField(max_length=32) + status_code = models.CharField(max_length=8) + is_active = models.BooleanField(default=False) + is_retired = models.BooleanField(default=False) + is_terminated = models.BooleanField(default=False) + hire_date = models.DateTimeField(null=True, default=None) + end_emp_date = models.DateTimeField(null=True, default=None) + retirement_date = models.DateTimeField(null=True, default=None) + termination_date = models.DateTimeField(null=True, default=None) + + def to_json(self): + return {'end_emp_date': date_to_str(self.end_emp_date), + 'hire_date': date_to_str(self.hire_date), + 'is_active': self.is_active, + 'is_retired': self.is_retired, + 'is_terminated': self.is_terminated, + 'retirement_date': date_to_str(self.retirement_date), + 'status': self.status, + 'status_code': self.status_code, + 'termination_date': date_to_str(self.termination_date)} + + def __init__(self, *args, **kwargs): + data = kwargs.get("data") + if data is None: + return super(WorkerPosition, self).__init__(*args, **kwargs) + + self.status = data.get("EmployeeStatus") + self.status_code = data.get("EmployeeStatusCode") + if data.get("EndEmploymentDate") is not None: + self.end_emp_date = parse_date(data["EndEmploymentDate"]) + self.is_active = data.get("IsActive") + self.is_retired = data.get("IsRetired") + self.is_terminated = data.get("IsTerminated") + if data.get("HireDate") is not None: + self.hire_date = parse_date(data["HireDate"]) + if data.get("RetirementDate") is not None: + self.retirement_date = parse_date(data["RetirementDate"]) + if data.get("TerminationDate") is not None: + self.termination_date = parse_date(data["TerminationDate"]) + + def __str__(self): + return json.dumps(self.to_json()) + + +class JobProfile(models.Model): + job_code = models.CharField(max_length=16, null=True, default=None) + description = models.CharField(max_length=96, null=True, default=None) + + def to_json(self): + return {'job_code': self.job_code, + 'description': self.description} + + def __init__(self, *args, **kwargs): + data = kwargs.get("data") + if data is None: + return super(WorkerPosition, self).__init__(*args, **kwargs) + + self.job_code = data.get("JobProfileID") + self.description = data.get("JobProfileDescription") + + def __str__(self): + return json.dumps(self.to_json()) + + +class SupervisoryOrganization(models.Model): + budget_code = models.CharField(max_length=16, null=True, default=None) + org_code = models.CharField(max_length=16, null=True, default=None) + org_name = models.CharField(max_length=128, null=True, default=None) + + def to_json(self): + return {'budget_code': self.budget_code, + 'org_code': self.org_code, + 'org_name': self.org_name} + + def __init__(self, *args, **kwargs): + data = kwargs.get("data") + if data is None: + return super(WorkerPosition, self).__init__(*args, **kwargs) + + if data.get("CostCenter") is not None: + self.budget_code = data["CostCenter"].get("OrganizationCode") + self.org_code = data.get("Code") + self.org_name = data.get("Name") + + def __str__(self): + return json.dumps(self.to_json()) + + class WorkerPosition(models.Model): - effective_date = models.DateTimeField(null=True, default=None) + start_date = models.DateTimeField(null=True, default=None) end_date = models.DateTimeField(null=True, default=None) - ecs_job_cla_code_desc = models.CharField(max_length=64, + ecs_job_cla_code_desc = models.CharField(max_length=96, null=True, default=None) - location = models.CharField(max_length=96, null=True, default=None) is_primary = models.BooleanField(default=False) - org_code = models.CharField(max_length=16, null=True, default=None) - org_desc = models.CharField(max_length=128, null=True, default=None) - busi_title = models.CharField(max_length=128, null=True, default=None) + location = models.CharField(max_length=96, null=True, default=None) pos_type = models.CharField(max_length=64, null=True, default=None) - supervisor_eid = models.CharField(max_length=16, - null=True, default=None) pos_time_type_id = models.CharField(max_length=64, null=True, default=None) - supervisory_org_code = models.CharField(max_length=32, - null=True, default=None) - supervisory_org_id = models.CharField(max_length=96, - null=True, default=None) - supervisory_org_desc = models.CharField(max_length=256, - null=True, default=None) + fte_percent = models.FloatField(null=True, blank=True, default=None) + supervisor_eid = models.CharField(max_length=16, + null=True, default=None) + title = models.CharField(max_length=128, null=True, default=None) def is_active_position(self): now = datetime.now(timezone.utc) return self.end_date is None or self.end_date > now - def json_data(self): + def to_json(self): return { - 'effective_date': date_to_str(self.effective_date), + 'start_date': date_to_str(self.start_date), 'end_date': date_to_str(self.end_date), - 'is_primary': self.is_primary, - 'busi_title': self.busi_title, - 'pos_type': self.pos_type, 'ecs_job_cla_code_desc': self.ecs_job_cla_code_desc, + 'fte_percent': self.fte_percent, + 'is_primary': self.is_primary, 'location': self.location, - 'org_code': self.org_code, - 'org_desc': self.org_desc, + 'pos_type': self.pos_type, 'pos_time_type_id': self.pos_time_type_id, + 'title': self.title, 'supervisor_eid': self.supervisor_eid, - 'supervisory_org_code': self.supervisory_org_code, - 'supervisory_org_id': self.supervisory_org_id, - 'supervisory_org_desc': self.supervisory_org_desc, + 'job_profile': self.job_profile.to_json(), + 'supervisory_org': self.supervisory_org.to_json(), } def __str__(self): - return json.dumps(self.json_data()) + return json.dumps(self.to_json()) def __init__(self, *args, **kwargs): data = kwargs.get("data") if data is None: return super(WorkerPosition, self).__init__(*args, **kwargs) - if data.get("CostCenter") is not None: - self.org_code = data["CostCenter"]["OrganizationCode"] - self.org_desc = data["CostCenter"]["OrganizationDescription"] - self.ecs_job_cla_code_desc = \ - data["EcsJobClassificationCodeDescription"] - self.is_primary = data["IsPrimaryPosition"] - + data.get("EcsJobClassificationCodeDescription") + self.is_primary = data.get("IsPrimaryPosition") if data.get("Location") is not None: self.location = data["Location"]["ID"] + self.title = data.get("PositionBusinessTitle") + self.pos_type = data.get("PositionType") + self.pos_time_type_id = data.get("PositionTimeTypeID") + self.fte_percent = float(data.get("PositionFTEPercent")) + if data.get("PositionStartDate") is not None: + self.start_date = parse_date(data["PositionStartDate"]) - self.busi_title = data["PositionBusinessTitle"] + if data.get("PositionEndDate") is not None: + self.end_date = parse_date(data["PositionEndDate"]) - if data.get("PositionType") is not None: - self.pos_type = data["PositionType"] - - if data.get("PositionTimeTypeID") is not None: - self.pos_time_type_id = data["PositionTimeTypeID"] - - self.effective_date = parse_date(data["PositionEffectiveDate"]) - self.end_date = parse_date(data["PositionEndDate"]) - - self.supervisor_eid = data["PositionSupervisor"]["EmployeeID"] + if data.get("PositionSupervisor") is not None: + self.supervisor_eid = data["PositionSupervisor"]["EmployeeID"] if data.get("SupervisoryOrganization") is not None: - self.supervisory_org_code = \ - data["SupervisoryOrganization"]["Code"] - self.supervisory_org_id = \ - data["SupervisoryOrganization"]["ID"] - self.supervisory_org_desc = \ - data["SupervisoryOrganization"]["Description"] + self.supervisory_org = SupervisoryOrganization( + data=data["SupervisoryOrganization"]) + else: + self.supervisory_org = SupervisoryOrganization() - class Meta: - db_table = 'restclients_hrp_worker_position' + if data.get("JobProfileSummary") is not None: + self.job_profile = JobProfile(data=data["JobProfileSummary"]) + else: + self.job_profile = JobProfile() class Worker(models.Model): - netid = models.CharField(max_length=32, - db_index=True, - unique=True) - regid = models.CharField(max_length=32, - db_index=True, - unique=True) - employee_id = models.CharField(max_length=16, - db_index=True, - unique=True) - employee_status = models.CharField(max_length=32) - is_active = models.BooleanField(default=False) - is_retired = models.BooleanField(default=False) - is_terminated = models.BooleanField(default=False) + netid = models.CharField(max_length=32) + regid = models.CharField(max_length=32) + employee_id = models.CharField(max_length=16) + primary_manager_id = models.CharField(max_length=16) - def json_data(self): + def to_json(self): positions = [] for pos in self.worker_active_positions: - positions.append(pos.json_data()) + positions.append(pos.to_json()) return { "netid": self.netid, 'regid': self.regid, 'employee_id': self.employee_id, - 'employee_status': self.employee_status, - 'is_active': self.is_active, - 'is_retired': self.is_retired, - 'is_terminated': self.is_terminated, + 'employee_status': self.employee_status.to_json(), + 'primary_manager_id': self.primary_manager_id, 'worker_active_positions': positions } def __str__(self): - json_data = self.json_data() - json_data['worker_active_positions'] = "[{0}]".format(','.join( - map(str, self.worker_active_positions))) - return json.dumps(json_data) + return json.dumps(self.to_json()) def __init__(self, *args, **kwargs): data = kwargs.get("data") if data is None: return super(WorkerPosition, self).__init__(*args, **kwargs) - self.netid = data["NetID"] - self.regid = data["RegID"] - self.employee_id = data["EmployeeID"] + self.netid = data.get("NetID") + self.regid = data.get("RegID") + self.employee_id = data.get("EmployeeID") - if data.get("WorkerEmploymentStatus") is not None: - self.employee_status = \ - data["WorkerEmploymentStatus"]["EmployeeStatus"] - self.is_active = data["WorkerEmploymentStatus"]["IsActive"] - self.is_retired = data["WorkerEmploymentStatus"]["IsRetired"] - self.is_terminated = data["WorkerEmploymentStatus"]["IsTerminated"] + self.employee_status = EmploymentStatus( + data=data.get("WorkerEmploymentStatus")) self.worker_active_positions = [] - if self.is_active and data.get("WorkerPositions") is not None: + if (self.employee_status.is_active and + data.get("WorkerPositions") is not None): for position in data["WorkerPositions"]: position = WorkerPosition(data=position) if position.is_active_position(): self.worker_active_positions.append(position) - - class Meta: - db_table = 'restclients_hrp_worker' + if position.is_primary: + self.primary_manager_id = position.supervisor_eid diff --git a/uw_hrp/tests/test_models.py b/uw_hrp/tests/test_models.py index cfaf77b..1d12eb4 100644 --- a/uw_hrp/tests/test_models.py +++ b/uw_hrp/tests/test_models.py @@ -1,7 +1,6 @@ from unittest import TestCase from datetime import datetime, timedelta, timezone -from uw_hrp import parse_date -from uw_hrp.models import Worker, WorkerPosition +from uw_hrp.models import Worker, WorkerPosition, parse_date from uw_hrp.util import fdao_hrp_override @@ -13,116 +12,174 @@ def test_parse_date(self): def test_workerposition(self): data = { - "CostCenter": - {"Description": "INFORMATION SCHOOL", - "ID": "061630", - "OrganizationCode": "2670001000", - "OrganizationDescription": "THE INFORMATION SCHOOL"}, - "EcsJobClassificationCodeDescription": "Undergraduate Student", + "PositionBusinessTitle": "Program Operations Specialist (E S 8)", + "PositionSupervisor": { + "EmployeeID": "000000005", + "Href": "/hrp/v2/worker/000000005.json"}, + "PositionTimeTypeID": "Full_time", + "PositionTitle": "Operations Specialist (E S 8)", + "SupervisoryOrganization": { + "AcademicUnitID": None, + "Code": "HSA: ", + "ID": "HSA_000204", + "Name": "EHS: Occl Health - Acc Prevention", + "Description": "HSA: ENV Health & Safety: ...", + "Href": "/hrp/v2/organization/HSA_000204.json", + "CostCenter": { + "Description": "ENV HEALTH & SAFETY", + "ID": "015020", + "OrganizationCode": "3010105000", + "OrganizationDescription": "ENV HEALTH & SAFETY"}}, + "PositionID": "PN-0025953", + "PositionEffectiveDate": "1994-10-01T07:00:00.000Z", "IsPrimaryPosition": True, - "Location": - {"ID": "Seattle Campus", - "Name": "Seattle Campus"}, - "PositionBusinessTitle": "Reader/Grader", - "PositionEffectiveDate": "2017-09-16T07:00:00.000Z", - "PositionEndDate": "2018-06-15T00:00:00.000Z", - "PositionSupervisor": - {"EmployeeID": "000000005", - "Href": "/hrp/v2/worker/000000005.json"}, - "PositionTimeTypeID": "Part_time", - "PositionTitle": "Reader/Grader", - "PositionType": "Temporary", - "SupervisoryOrganization": None, - "WorkShift": "First Shift" - } + "PositionStartDate": "1994-10-01T00:00:00.000Z", + "PositionEndDate": None, + "PositionType": "Regular", + "PositionFTEPercent": "100.00000", + "PayRateType": "Salary", + "TotalBasePayAmount": "6066.00000", + "TotalBasePayFrequency": "Monthly", + "WorkShift": "First Shift", + "ServicePeriodID": "12", + "ServicePeriodDescription": "Service_Period_12.00", + "JobProfileSummary": { + "JobProfileDescription": "Operations Specialist (E S 8)", + "JobProfileID": "11541", + "Href": "/hrp/v2/jobProfile/11541.json", + "JobCategory": "Professional Staff & Librarians", + "JobFamilies": [ + {"JobFamilyName": "01 - Staff - Professional Staff", + "JobFamilyID": "Professional", + "JobFamilySummary": None}]}, + "CostCenter": { + "Description": "ENV HEALTH & SAFETY", + "ID": "015020", + "OrganizationCode": "3010105000", + "OrganizationDescription": "ENV HEALTH & SAFETY"}, + "EcsJobClassificationCode": "E", + "EcsJobClassificationCodeDescription": "Professional Staff", + "ObjectCode": "01", + "SubObjectCode": "70", + "PayrollUnitCode": "00702", + "IsOnLeaveFromPosition": False, + "IsFutureDate": False, + "IsMedicalCenterPosition": False, + "PlannedDistributions": { + "PlannedCompensationAllocations": [], + "PeriodActivityAssignments": []}, + "Location": {"ID": "Seattle Campus", + "Name": "Seattle Campus"}, + "FutureTransactions": []} + work_position = WorkerPosition(data=data) self.assertEqual( - work_position.json_data(), - {'busi_title': 'Reader/Grader', - 'ecs_job_cla_code_desc': 'Undergraduate Student', - 'effective_date': '2017-09-16 07:00:00+00:00', - 'end_date': '2018-06-15 00:00:00+00:00', - 'is_primary': True, - 'location': 'Seattle Campus', - 'org_code': '2670001000', - 'org_desc': 'THE INFORMATION SCHOOL', - 'pos_time_type_id': 'Part_time', - 'pos_type': 'Temporary', - 'supervisor_eid': '000000005', - 'supervisory_org_code': None, - 'supervisory_org_desc': None, - 'supervisory_org_id': None}) - self.assertFalse(work_position.is_active_position()) - work_position.end_date = (datetime.now(timezone.utc) + - timedelta(seconds=5)) + work_position.to_json(), + { + "start_date": "1994-10-01 00:00:00+00:00", + "end_date": None, + "ecs_job_cla_code_desc": "Professional Staff", + "fte_percent": 100.0, + "is_primary": True, + "location": "Seattle Campus", + "pos_type": "Regular", + "pos_time_type_id": "Full_time", + "title": "Program Operations Specialist (E S 8)", + "supervisor_eid": "000000005", + "job_profile": { + "job_code": "11541", + "description": "Operations Specialist (E S 8)"}, + "supervisory_org": { + "budget_code": "3010105000", + "org_code": "HSA: ", + "org_name": "EHS: Occl Health - Acc Prevention"}}) self.assertTrue(work_position.is_active_position()) self.assertIsNotNone(str(work_position)) def test_worker(self): data = { - "NetID": "dean", + "NetID": "webmaster", "RegID": "10000000000000000000000000000115", "EmployeeID": "100000115", - "WorkerEmploymentStatus": - {"ActiveStatusDate": "1980-07-01T07:00:00.000Z", - "EmployeeStatus": "Active", - "EmployeeStatusCode": "A", - "EndEmploymentDate": None, - "EstimatedLastDayOfLeave": None, - "FirstDayOfLeave": None, - "FirstDayOfWork": "1980-07-01T07:00:00.000Z", - "HireDate": "1980-07-01T07:00:00.000Z", - "IsActive": True, - "IsRetired": False, - "IsTerminated": False, - "LastDayOfWorkForLeave": None, - "OriginalHireDate": "1980-07-01T07:00:00.000Z", - "RetirementDate": None, - "TerminationDate": None}, - "WorkerPositions": [ - {"CostCenter": - {"Description": "SOM ADMINISTRATION", - "ID": "652791", - "OrganizationCode": "3040501060", - "OrganizationDescription": "EXEC MGMT OEVP ADMIN"}, - "EcsJobClassificationCode": "F", - "EcsJobClassificationCodeDescription": "Academic Personnel", - "IsPrimaryPosition": True, - "Location": - {"ID": "Seattle Campus", - "Name": "Seattle Campus"}, - "PositionBusinessTitle": - "CEO, UW Medicine and Dean of the School of Medicine", - "PositionEffectiveDate": "1999-06-13T07:00:00.000Z", - "PositionEndDate": None, - "PositionSupervisor": - {"EmployeeID": "100001115"}, - "WorkShift": "First Shift"}]} + "WorkerEmploymentStatus": { + "ActiveStatusDate": "1980-07-01T07:00:00.000Z", + "EmployeeStatus": "Active", + "EmployeeStatusCode": "A", + "EndEmploymentDate": None, + "EstimatedLastDayOfLeave": None, + "FirstDayOfLeave": None, + "FirstDayOfWork": "1980-07-01T07:00:00.000Z", + "HireDate": "1980-07-01T07:00:00.000Z", + "IsActive": True, + "IsRetired": False, + "IsTerminated": False, + "LastDayOfWorkForLeave": None, + "OriginalHireDate": "1980-07-01T07:00:00.000Z", + "RetirementDate": None, + "TerminationDate": None}, + "WorkerPositions": [{ + "PositionBusinessTitle": "Web Support Specialist", + "PositionSupervisor": { + "EmployeeID": "000000005", + "Href": "/hrp/v2/worker/000000005.json"}, + "PositionTimeTypeID": "Full_time", + "PositionTitle": "COM SUP ANA 2, Web and Social Media", + "SupervisoryOrganization": { + "AcademicUnitID": None, + "Code": "UWB: ", + "ID": "UWB_000066", + "Name": "Web and Social Media", + "Description": "UWB: Web and Social Media ()", + "Href": "/hrp/v2/organization/UWB_000066.json", + "CostCenter": { + "Description": "ADV & EXT RELATIONS -B", + "ID": "060304", + "OrganizationCode": "5014010000", + "OrganizationDescription": "BR-B OFFICE OF ADV"}}, + "PositionID": "PN-0036224", + "PositionEffectiveDate": "2015-12-21T08:00:00.000Z", + "IsPrimaryPosition": True, + "PositionStartDate": "2015-12-21T00:00:00.000Z", + "PositionEndDate": None, + "PositionType": "Regular", + "PositionFTEPercent": "100.00000", + "PayRateType": "Salary", + "TotalBasePayFrequency": "Monthly", + "WorkShift": "First Shift", + "ServicePeriodID": "12", + "ServicePeriodDescription": "Service_Period_12.00", + "JobProfileSummary": {}, + "CostCenter": { + "Description": "ADV & EXT RELATIONS -B", + "ID": "060304", + "OrganizationCode": "5014010000", + "OrganizationDescription": "BR-B OFFICE OF ADV"}, + "EcsJobClassificationCode": "B", + "EcsJobClassificationCodeDescription": "Classified Staff", + "ObjectCode": "01", + "SubObjectCode": "60", + "PayrollUnitCode": "00356", + "IsOnLeaveFromPosition": False, + "IsFutureDate": False, + "IsMedicalCenterPosition": False, + "Location": {"ID": "Bothell Campus", + "Name": "Bothell Campus"}, + "FutureTransactions": []}], + "AcademicAppointments": [], + "SystemMetadata": {"LastModified": None}} worker = Worker(data=data) + self.assertEqual(worker.netid, 'webmaster') + self.assertEqual(worker.employee_id, '100000115') + self.assertEqual(worker.primary_manager_id, '000000005') self.assertEqual( - worker.json_data(), - {'netid': 'dean', - 'regid': "10000000000000000000000000000115", - 'employee_id': '100000115', - 'employee_status': 'Active', - 'is_active': True, - 'is_retired': False, - 'is_terminated': False, - 'worker_active_positions': [ - {'effective_date': '1999-06-13 07:00:00+00:00', - 'end_date': None, - 'is_primary': True, - 'busi_title': - 'CEO, UW Medicine and Dean of the School of Medicine', - 'pos_type': None, - 'ecs_job_cla_code_desc': 'Academic Personnel', - 'location': 'Seattle Campus', - 'org_code': '3040501060', - 'org_desc': 'EXEC MGMT OEVP ADMIN', - 'pos_time_type_id': None, - 'supervisor_eid': '100001115', - 'supervisory_org_code': None, - 'supervisory_org_id': None, - 'supervisory_org_desc': None} - ]}) + worker.employee_status.to_json(), + {"end_emp_date": None, + "hire_date": "1980-07-01 07:00:00+00:00", + "is_active": True, + "is_retired": False, + "is_terminated": False, + "retirement_date": None, + "status": "Active", + "status_code": "A", + "termination_date": None}) self.assertIsNotNone(str(worker)) diff --git a/uw_hrp/tests/test_worker.py b/uw_hrp/tests/test_worker.py index 24e69f3..7c7763d 100644 --- a/uw_hrp/tests/test_worker.py +++ b/uw_hrp/tests/test_worker.py @@ -11,43 +11,100 @@ class WorkerTest(TestCase): def test_get_worker_by_netid(self): worker = get_worker_by_netid("faculty") + self.assertEqual( + worker.to_json(), + {"netid": "faculty", + "regid": "10000000000000000000000000000005", + "employee_id": "000000005", + "employee_status": { + "end_emp_date": None, + "hire_date": "2006-05-16 07:00:00+00:00", + "is_active": True, + "is_retired": False, + "is_terminated": False, + "retirement_date": None, + "status": "Active", + "status_code": "A", + "termination_date": None}, + "primary_manager_id": "100000015", + "worker_active_positions": [{ + "start_date": "2012-07-01 00:00:00+00:00", + "end_date": None, + "ecs_job_cla_code_desc": "Academic Personnel", + 'fte_percent': 0.0, + "is_primary": True, + "location": "Seattle Campus", + "pos_type": "Unpaid_Academic", + "pos_time_type_id": "Part_time", + "title": "Clinical Associate Professor", + "supervisor_eid": "100000015", + "job_profile": { + "job_code": "21184", + "description": "Unpaid Academic"}, + "supervisory_org": { + "budget_code": "3040111000", + "org_code": "SOM", + "org_name": "Family Medicine: Volunteer"}}]}) + self.assertIsNotNone(str(worker)) + self.assertEqual(worker.netid, "faculty") self.assertEqual(worker.regid, "10000000000000000000000000000005") self.assertEqual(worker.employee_id, "000000005") - self.assertEqual(worker.employee_status, "Active") - self.assertTrue(worker.is_active) - self.assertFalse(worker.is_retired) - self.assertFalse(worker.is_terminated) + self.assertTrue(worker.employee_status.is_active) + self.assertFalse(worker.employee_status.is_retired) + self.assertFalse(worker.employee_status.is_terminated) + self.assertEqual(str(worker.employee_status.hire_date), + "2006-05-16 07:00:00+00:00") + self.assertIsNotNone(str(worker.employee_status.to_json())) self.assertEqual(len(worker.worker_active_positions), 1) work_position = worker.worker_active_positions[0] - self.assertEqual(work_position.org_code, '3040111000') - self.assertEqual(work_position.org_desc, "FAMILY MEDICINE") + self.assertIsNotNone(str(work_position)) + + sup_org = work_position.supervisory_org + self.assertEqual(sup_org.org_code, 'SOM') + self.assertEqual(sup_org.org_name, + "Family Medicine: Volunteer") + self.assertEqual(sup_org.budget_code, + '3040111000') + self.assertIsNotNone(str(sup_org)) + self.assertEqual(work_position.ecs_job_cla_code_desc, "Academic Personnel") - self.assertEqual(str(work_position.effective_date), - "2012-07-01 07:00:00+00:00") + self.assertEqual(str(work_position.start_date), + "2012-07-01 00:00:00+00:00") self.assertIsNone(work_position.end_date) - self.assertEqual(work_position.busi_title, + self.assertEqual(work_position.title, "Clinical Associate Professor") - self.assertEqual(work_position.pos_type, "Unpaid_Academic") - self.assertEqual(work_position.supervisor_eid, "100000015") - self.assertEqual(work_position.pos_time_type_id, "Part_time") - self.assertEqual(work_position.supervisory_org_code, "SOM") - self.assertEqual(work_position.supervisory_org_id, "SOM_000420") - self.assertEqual(work_position.supervisory_org_desc, - "SOM: Family Medicine: Volunteer (Visor, Super1)") - self.assertEqual(work_position.location, "Seattle Campus") + self.assertEqual(work_position.pos_type, + "Unpaid_Academic") + self.assertEqual(work_position.supervisor_eid, + "100000015") + self.assertEqual(work_position.pos_time_type_id, + "Part_time") + self.assertEqual(work_position.location, + "Seattle Campus") self.assertTrue(work_position.is_primary) + self.assertEqual(work_position.job_profile.job_code, + '21184') + self.assertEqual(work_position.job_profile.description, + 'Unpaid Academic') + self.assertEqual(work_position.job_profile.to_json(), + {'job_code': '21184', + 'description': 'Unpaid Academic'}) + self.assertIsNotNone(str(work_position.job_profile)) + def test_get_worker_by_employee_id(self): worker = get_worker_by_employee_id("100000015") - self.assertTrue(worker.netid, 'chair') + self.assertTrue(worker.netid, + 'chair') def test_get_worker_by_regid(self): worker = get_worker_by_regid("10000000000000000000000000000015") - self.assertTrue(worker.netid, 'chair') + self.assertTrue(worker.netid, + 'chair') def test_invalid_user(self): self.assertRaises(DataFailureException, @@ -55,9 +112,11 @@ def test_invalid_user(self): "00000000000000000000000000000001") self.assertRaises(DataFailureException, - get_worker_by_employee_id, "100000000") + get_worker_by_employee_id, + "100000000") - self.assertRaises(InvalidRegID, get_worker_by_regid, "000") + self.assertRaises(InvalidRegID, + get_worker_by_regid, "000") self.assertRaises(InvalidNetID, get_worker_by_netid, "#&$^&$") self.assertRaises(InvalidEmployeeID, get_worker_by_employee_id, "0") From b9181bff083cb543874a5c4a5e6c03af9604f9e6 Mon Sep 17 00:00:00 2001 From: Fang Lin Date: Sat, 25 May 2019 17:21:18 -0700 Subject: [PATCH 09/10] refactor, increase coverage. --- uw_hrp/models.py | 100 +++++++++++++++++-------------- uw_hrp/tests/test_models.py | 116 +++++++++++++++++++++++++++++++++--- uw_hrp/tests/test_worker.py | 94 ++++++++++------------------- 3 files changed, 195 insertions(+), 115 deletions(-) diff --git a/uw_hrp/models.py b/uw_hrp/models.py index 99654c1..fadd50f 100644 --- a/uw_hrp/models.py +++ b/uw_hrp/models.py @@ -41,7 +41,7 @@ def to_json(self): def __init__(self, *args, **kwargs): data = kwargs.get("data") if data is None: - return super(WorkerPosition, self).__init__(*args, **kwargs) + return super(EmploymentStatus, self).__init__(*args, **kwargs) self.status = data.get("EmployeeStatus") self.status_code = data.get("EmployeeStatusCode") @@ -72,7 +72,7 @@ def to_json(self): def __init__(self, *args, **kwargs): data = kwargs.get("data") if data is None: - return super(WorkerPosition, self).__init__(*args, **kwargs) + return super(JobProfile, self).__init__(*args, **kwargs) self.job_code = data.get("JobProfileID") self.description = data.get("JobProfileDescription") @@ -94,12 +94,13 @@ def to_json(self): def __init__(self, *args, **kwargs): data = kwargs.get("data") if data is None: - return super(WorkerPosition, self).__init__(*args, **kwargs) + return super(SupervisoryOrganization, self).__init__(*args, + **kwargs) if data.get("CostCenter") is not None: self.budget_code = data["CostCenter"].get("OrganizationCode") - self.org_code = data.get("Code") - self.org_name = data.get("Name") + self.org_code = data.get("Code").strip() + self.org_name = data.get("Name").strip() def __str__(self): return json.dumps(self.to_json()) @@ -125,29 +126,40 @@ def is_active_position(self): return self.end_date is None or self.end_date > now def to_json(self): - return { - 'start_date': date_to_str(self.start_date), - 'end_date': date_to_str(self.end_date), - 'ecs_job_cla_code_desc': self.ecs_job_cla_code_desc, - 'fte_percent': self.fte_percent, - 'is_primary': self.is_primary, - 'location': self.location, - 'pos_type': self.pos_type, - 'pos_time_type_id': self.pos_time_type_id, - 'title': self.title, - 'supervisor_eid': self.supervisor_eid, - 'job_profile': self.job_profile.to_json(), - 'supervisory_org': self.supervisory_org.to_json(), - } + data = {'start_date': date_to_str(self.start_date), + 'end_date': date_to_str(self.end_date), + 'ecs_job_cla_code_desc': self.ecs_job_cla_code_desc, + 'fte_percent': self.fte_percent, + 'is_primary': self.is_primary, + 'location': self.location, + 'pos_type': self.pos_type, + 'pos_time_type_id': self.pos_time_type_id, + 'title': self.title, + 'supervisor_eid': self.supervisor_eid, + 'job_profile': None, + 'supervisory_org': None} + if self.job_profile is not None: + data['job_profile'] = self.job_profile.to_json() + if self.supervisory_org is not None: + data['supervisory_org'] = self.supervisory_org.to_json() + return data def __str__(self): return json.dumps(self.to_json()) def __init__(self, *args, **kwargs): data = kwargs.get("data") + self.job_profile = None + self.supervisory_org = None if data is None: return super(WorkerPosition, self).__init__(*args, **kwargs) + self.job_profile = JobProfile( + data=data.get("JobProfileSummary")) + + self.supervisory_org = SupervisoryOrganization( + data=data.get("SupervisoryOrganization")) + self.ecs_job_cla_code_desc = \ data.get("EcsJobClassificationCodeDescription") self.is_primary = data.get("IsPrimaryPosition") @@ -166,59 +178,57 @@ def __init__(self, *args, **kwargs): if data.get("PositionSupervisor") is not None: self.supervisor_eid = data["PositionSupervisor"]["EmployeeID"] - if data.get("SupervisoryOrganization") is not None: - self.supervisory_org = SupervisoryOrganization( - data=data["SupervisoryOrganization"]) - else: - self.supervisory_org = SupervisoryOrganization() - - if data.get("JobProfileSummary") is not None: - self.job_profile = JobProfile(data=data["JobProfileSummary"]) - else: - self.job_profile = JobProfile() - class Worker(models.Model): netid = models.CharField(max_length=32) regid = models.CharField(max_length=32) employee_id = models.CharField(max_length=16) - primary_manager_id = models.CharField(max_length=16) + primary_manager_id = models.CharField(max_length=16, + null=True, default=None) def to_json(self): + data = {"netid": self.netid, + 'regid': self.regid, + 'employee_id': self.employee_id, + 'employee_status': None, + 'primary_manager_id': self.primary_manager_id} + + if self.employee_status is not None: + data['employee_status'] = self.employee_status.to_json() + positions = [] - for pos in self.worker_active_positions: + if self.primary_position is not None: + positions.append(self.primary_position.to_json()) + for pos in self.other_active_positions: positions.append(pos.to_json()) - - return { - "netid": self.netid, - 'regid': self.regid, - 'employee_id': self.employee_id, - 'employee_status': self.employee_status.to_json(), - 'primary_manager_id': self.primary_manager_id, - 'worker_active_positions': positions - } + data['active_positions'] = positions + return data def __str__(self): return json.dumps(self.to_json()) def __init__(self, *args, **kwargs): data = kwargs.get("data") + self.employee_status = None + self.primary_position = None + self.other_active_positions = [] + if data is None: - return super(WorkerPosition, self).__init__(*args, **kwargs) + return super(Worker, self).__init__(*args, **kwargs) self.netid = data.get("NetID") self.regid = data.get("RegID") self.employee_id = data.get("EmployeeID") - self.employee_status = EmploymentStatus( data=data.get("WorkerEmploymentStatus")) - self.worker_active_positions = [] if (self.employee_status.is_active and data.get("WorkerPositions") is not None): for position in data["WorkerPositions"]: position = WorkerPosition(data=position) if position.is_active_position(): - self.worker_active_positions.append(position) if position.is_primary: self.primary_manager_id = position.supervisor_eid + self.primary_position = position + else: + self.other_active_positions.append(position) diff --git a/uw_hrp/tests/test_models.py b/uw_hrp/tests/test_models.py index 1d12eb4..8e59a10 100644 --- a/uw_hrp/tests/test_models.py +++ b/uw_hrp/tests/test_models.py @@ -1,6 +1,8 @@ from unittest import TestCase from datetime import datetime, timedelta, timezone -from uw_hrp.models import Worker, WorkerPosition, parse_date +from uw_hrp.models import ( + EmploymentStatus, JobProfile, SupervisoryOrganization, + Worker, WorkerPosition, parse_date) from uw_hrp.util import fdao_hrp_override @@ -10,7 +12,38 @@ class WorkerTest(TestCase): def test_parse_date(self): self.assertIsNotNone(parse_date("2017-09-16T07:00:00.000Z")) - def test_workerposition(self): + def test_employment_status(self): + emp_status = EmploymentStatus(status="Active", + status_code='A') + self.assertIsNotNone(str(emp_status)) + + emp_status = EmploymentStatus( + data={ + "ActiveStatusDate": "1980-07-01T07:00:00.000Z", + "EmployeeStatus": "Active", + "EmployeeStatusCode": "A", + "EndEmploymentDate": "2017-09-16T07:00:00.000Z", + "HireDate": "1980-07-01T07:00:00.000Z", + "IsActive": True, + "OriginalHireDate": "1980-07-01T07:00:00.000Z", + "RetirementDate": "2017-09-16T07:00:00.000Z", + "TerminationDate": "2017-09-16T07:00:00.000Z"}) + self.assertIsNotNone(str(emp_status)) + + def test_job_profile(self): + job_prof = JobProfile(job_code="1", description="A") + self.assertIsNotNone(str(job_prof)) + + def test_supervisory_organization(self): + super_org = SupervisoryOrganization( + budget_code="3010105000", + org_code="HSA:", + org_name="EHS: Occl Health - Acc Prevention") + self.assertIsNotNone(str(super_org)) + + def test_worker_position(self): + pos = WorkerPosition() + self.assertIsNotNone(str(pos)) data = { "PositionBusinessTitle": "Program Operations Specialist (E S 8)", "PositionSupervisor": { @@ -34,7 +67,7 @@ def test_workerposition(self): "PositionEffectiveDate": "1994-10-01T07:00:00.000Z", "IsPrimaryPosition": True, "PositionStartDate": "1994-10-01T00:00:00.000Z", - "PositionEndDate": None, + "PositionEndDate": "1997-10-01T00:00:00.000Z", "PositionType": "Regular", "PositionFTEPercent": "100.00000", "PayRateType": "Salary", @@ -77,7 +110,7 @@ def test_workerposition(self): work_position.to_json(), { "start_date": "1994-10-01 00:00:00+00:00", - "end_date": None, + "end_date": "1997-10-01 00:00:00+00:00", "ecs_job_cla_code_desc": "Professional Staff", "fte_percent": 100.0, "is_primary": True, @@ -91,12 +124,16 @@ def test_workerposition(self): "description": "Operations Specialist (E S 8)"}, "supervisory_org": { "budget_code": "3010105000", - "org_code": "HSA: ", + "org_code": "HSA:", "org_name": "EHS: Occl Health - Acc Prevention"}}) - self.assertTrue(work_position.is_active_position()) + self.assertFalse(work_position.is_active_position()) self.assertIsNotNone(str(work_position)) def test_worker(self): + worker = Worker(netid='none', + regid="10000000", + employee_id="100000115") + self.assertIsNotNone(str(worker)) data = { "NetID": "webmaster", "RegID": "10000000000000000000000000000115", @@ -164,13 +201,77 @@ def test_worker(self): "IsMedicalCenterPosition": False, "Location": {"ID": "Bothell Campus", "Name": "Bothell Campus"}, - "FutureTransactions": []}], + "FutureTransactions": []}, + {"CostCenter": { + "Description": "INFORMATION SCHOOL", + "ID": "061630", + "OrganizationCode": "2670001000", + "OrganizationDescription": "THE INFORMATION SCHOOL"}, + "EcsJobClassificationCode": "U", + "EcsJobClassificationCodeDescription": "Undergrad Student", + "FutureTransactions": [], + "IsFutureDate": False, + "IsMedicalCenterPosition": False, + "IsOnLeaveFromPosition": False, + "IsPrimaryPosition": True, + "JobProfileSummary": { + "Href": "/hrp/v2/jobProfile/10886.json", + "JobCategory": "Hourly and Other", + "JobFamilies": [], + "JobProfileDescription": "Reader/Grader (NE H UAW ASE)", + "JobProfileID": "10886"}, + "Location": {"ID": "Seattle Campus", + "Name": "Seattle Campus"}, + "ObjectCode": "01", + "PayRateType": "Hourly", + "PayrollUnitCode": "00652", + "PlannedDistributions": { + "PeriodActivityAssignments": [], + "PlannedCompensationAllocations": [], + }, + "PositionBusinessTitle": "Reader/Grader", + "PositionEffectiveDate": "2017-09-16T07:00:00.000Z", + "PositionEndDate": "2018-06-15T00:00:00.000Z", + "PositionFTEPercent": "0.00000", + "PositionID": "PN-0086428", + "PositionStartDate": "2017-09-16T00:00:00.000Z", + "PositionSupervisor": { + "EmployeeID": "000004000", + "Href": "/hrp/v2/worker/000004000.json"}, + "PositionTimeTypeID": "Part_time", + "PositionTitle": "Reader/Grader", + "PositionType": "Temporary", + "ServicePeriodDescription": "Service_Period_12.00", + "ServicePeriodID": "12", + "SubObjectCode": "80", + "SupervisoryOrganization": None, + "WorkShift": "First Shift"}], "AcademicAppointments": [], "SystemMetadata": {"LastModified": None}} worker = Worker(data=data) self.assertEqual(worker.netid, 'webmaster') self.assertEqual(worker.employee_id, '100000115') self.assertEqual(worker.primary_manager_id, '000000005') + self.assertEqual( + worker.primary_position.to_json(), + {'ecs_job_cla_code_desc': 'Classified Staff', + 'end_date': None, + 'fte_percent': 100.0, + 'is_primary': True, + 'job_profile': {'description': None, 'job_code': None}, + 'location': 'Bothell Campus', + 'pos_time_type_id': 'Full_time', + 'pos_type': 'Regular', + 'start_date': '2015-12-21 00:00:00+00:00', + 'supervisor_eid': '000000005', + 'supervisory_org': { + 'budget_code': '5014010000', + 'org_code': 'UWB:', + 'org_name': 'Web and Social Media'}, + 'title': 'Web Support Specialist'}) + self.assertIsNotNone(str(worker.primary_position)) + self.assertEqual(len(worker.other_active_positions), 0) + self.assertIsNotNone(str(worker.employee_status)) self.assertEqual( worker.employee_status.to_json(), {"end_emp_date": None, @@ -182,4 +283,3 @@ def test_worker(self): "status": "Active", "status_code": "A", "termination_date": None}) - self.assertIsNotNone(str(worker)) diff --git a/uw_hrp/tests/test_worker.py b/uw_hrp/tests/test_worker.py index 7c7763d..aeb778a 100644 --- a/uw_hrp/tests/test_worker.py +++ b/uw_hrp/tests/test_worker.py @@ -1,8 +1,8 @@ from unittest import TestCase -from uw_hrp.worker import ( - get_worker_by_netid, get_worker_by_employee_id, get_worker_by_regid) from restclients_core.exceptions import ( DataFailureException, InvalidEmployeeID, InvalidRegID, InvalidNetID) +from uw_hrp.worker import ( + get_worker_by_netid, get_worker_by_employee_id, get_worker_by_regid) from uw_hrp.util import fdao_hrp_override @@ -10,6 +10,12 @@ class WorkerTest(TestCase): def test_get_worker_by_netid(self): + self.assertRaises(DataFailureException, + get_worker_by_netid, + "None") + self.assertRaises(InvalidNetID, + get_worker_by_netid, + "") worker = get_worker_by_netid("faculty") self.assertEqual( worker.to_json(), @@ -27,7 +33,7 @@ def test_get_worker_by_netid(self): "status_code": "A", "termination_date": None}, "primary_manager_id": "100000015", - "worker_active_positions": [{ + "active_positions": [{ "start_date": "2012-07-01 00:00:00+00:00", "end_date": None, "ecs_job_cla_code_desc": "Academic Personnel", @@ -46,77 +52,41 @@ def test_get_worker_by_netid(self): "org_code": "SOM", "org_name": "Family Medicine: Volunteer"}}]}) self.assertIsNotNone(str(worker)) - - self.assertEqual(worker.netid, "faculty") - self.assertEqual(worker.regid, - "10000000000000000000000000000005") - self.assertEqual(worker.employee_id, "000000005") - self.assertTrue(worker.employee_status.is_active) - self.assertFalse(worker.employee_status.is_retired) - self.assertFalse(worker.employee_status.is_terminated) - self.assertEqual(str(worker.employee_status.hire_date), - "2006-05-16 07:00:00+00:00") - self.assertIsNotNone(str(worker.employee_status.to_json())) - - self.assertEqual(len(worker.worker_active_positions), 1) - work_position = worker.worker_active_positions[0] - self.assertIsNotNone(str(work_position)) - - sup_org = work_position.supervisory_org - self.assertEqual(sup_org.org_code, 'SOM') - self.assertEqual(sup_org.org_name, - "Family Medicine: Volunteer") - self.assertEqual(sup_org.budget_code, - '3040111000') - self.assertIsNotNone(str(sup_org)) - - self.assertEqual(work_position.ecs_job_cla_code_desc, - "Academic Personnel") - self.assertEqual(str(work_position.start_date), - "2012-07-01 00:00:00+00:00") - self.assertIsNone(work_position.end_date) - self.assertEqual(work_position.title, - "Clinical Associate Professor") - self.assertEqual(work_position.pos_type, - "Unpaid_Academic") - self.assertEqual(work_position.supervisor_eid, - "100000015") - self.assertEqual(work_position.pos_time_type_id, - "Part_time") - self.assertEqual(work_position.location, - "Seattle Campus") - self.assertTrue(work_position.is_primary) - - self.assertEqual(work_position.job_profile.job_code, - '21184') - self.assertEqual(work_position.job_profile.description, - 'Unpaid Academic') - self.assertEqual(work_position.job_profile.to_json(), - {'job_code': '21184', - 'description': 'Unpaid Academic'}) - self.assertIsNotNone(str(work_position.job_profile)) + self.assertEqual( + worker.primary_position.to_json(), + {"start_date": "2012-07-01 00:00:00+00:00", + "end_date": None, + "ecs_job_cla_code_desc": "Academic Personnel", + 'fte_percent': 0.0, + "is_primary": True, + "location": "Seattle Campus", + "pos_type": "Unpaid_Academic", + "pos_time_type_id": "Part_time", + "title": "Clinical Associate Professor", + "supervisor_eid": "100000015", + "job_profile": { + "job_code": "21184", + "description": "Unpaid Academic"}, + "supervisory_org": { + "budget_code": "3040111000", + "org_code": "SOM", + "org_name": "Family Medicine: Volunteer"}}) + self.assertEqual(len(worker.other_active_positions), 0) def test_get_worker_by_employee_id(self): worker = get_worker_by_employee_id("100000015") self.assertTrue(worker.netid, 'chair') + self.assertRaises(InvalidEmployeeID, + get_worker_by_employee_id, + "") def test_get_worker_by_regid(self): worker = get_worker_by_regid("10000000000000000000000000000015") self.assertTrue(worker.netid, 'chair') - - def test_invalid_user(self): self.assertRaises(DataFailureException, get_worker_by_regid, "00000000000000000000000000000001") - - self.assertRaises(DataFailureException, - get_worker_by_employee_id, - "100000000") - self.assertRaises(InvalidRegID, get_worker_by_regid, "000") - self.assertRaises(InvalidNetID, get_worker_by_netid, "#&$^&$") - self.assertRaises(InvalidEmployeeID, get_worker_by_employee_id, - "0") From 38bcc2cdb032398ef51ad42d3790e2f60bf62d2c Mon Sep 17 00:00:00 2001 From: Fang Lin Date: Tue, 28 May 2019 11:20:59 -0700 Subject: [PATCH 10/10] Changed to initialize HRP_DAO object after configuration settings are ready --- uw_hrp/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/uw_hrp/__init__.py b/uw_hrp/__init__.py index 09a09fc..c016ec4 100644 --- a/uw_hrp/__init__.py +++ b/uw_hrp/__init__.py @@ -9,11 +9,10 @@ logger = logging.getLogger(__name__) -hrp_dao = HRP_DAO() def get_resource(url): - response = hrp_dao.getURL(url, {'Accept': 'application/json'}) + response = HRP_DAO().getURL(url, {'Accept': 'application/json'}) logger.debug("{0} ==status==> {1}".format(url, response.status)) if response.status != 200: