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..c016ec4 100644 --- a/uw_hrp/__init__.py +++ b/uw_hrp/__init__.py @@ -4,7 +4,6 @@ """ import logging -import json from uw_hrp.dao import HRP_DAO from restclients_core.exceptions import DataFailureException @@ -14,10 +13,10 @@ def get_resource(url): response = HRP_DAO().getURL(url, {'Accept': 'application/json'}) - logger.info("%s ==status==> %s" % (url, response.status)) + 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 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..fadd50f 100644 --- a/uw_hrp/models.py +++ b/uw_hrp/models.py @@ -1,169 +1,234 @@ +from datetime import datetime, timezone +from dateutil.parser import parse +import json 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 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, - '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, - } +def date_to_str(d_obj): + if d_obj is not None: + return 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(EmploymentStatus, 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 ("{%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 - ) - - 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_index=True, - unique=True) - regid = models.CharField(max_length=32, - db_index=True, - unique=True) - employee_id = models.CharField(max_length=9, - 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 - - def json_data(self): - apps = [] - for app in self.appointments: - apps.append(app.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 - } + 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(JobProfile, 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(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").strip() + self.org_name = data.get("Name").strip() + + def __str__(self): + return json.dumps(self.to_json()) + + +class WorkerPosition(models.Model): + 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=96, + null=True, default=None) + is_primary = models.BooleanField(default=False) + location = models.CharField(max_length=96, null=True, default=None) + pos_type = models.CharField(max_length=64, null=True, default=None) + pos_time_type_id = models.CharField(max_length=64, + 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 to_json(self): + 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") + 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"]) + + if data.get("PositionEndDate") is not None: + self.end_date = parse_date(data["PositionEndDate"]) + + if data.get("PositionSupervisor") is not None: + self.supervisor_eid = data["PositionSupervisor"]["EmployeeID"] + + +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, + 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 = [] + 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()) + data['active_positions'] = positions + return data 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)) - ) - - class Meta: - db_table = 'restclients_hrp_appointee' + 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(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")) + + 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(): + 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/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..4701a57 --- /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) 123-1234", + "Number":"123-1234", + "Type":"WORK"}, + {"AreaCode":"206", + "DeviceType":"Telephone", + "InternationalCode":"1", + "IsPrimary":false, + "IsPubliclyAvailable":true, + "NANPPhoneNumber":"+1 (206) 123-1235", + "Number":"123-1235", + "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..4701a57 --- /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) 123-1234", + "Number":"123-1234", + "Type":"WORK"}, + {"AreaCode":"206", + "DeviceType":"Telephone", + "InternationalCode":"1", + "IsPrimary":false, + "IsPubliclyAvailable":true, + "NANPPhoneNumber":"+1 (206) 123-1235", + "Number":"123-1235", + "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..4701a57 --- /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) 123-1234", + "Number":"123-1234", + "Type":"WORK"}, + {"AreaCode":"206", + "DeviceType":"Telephone", + "InternationalCode":"1", + "IsPrimary":false, + "IsPubliclyAvailable":true, + "NANPPhoneNumber":"+1 (206) 123-1235", + "Number":"123-1235", + "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_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) diff --git a/uw_hrp/tests/test_models.py b/uw_hrp/tests/test_models.py new file mode 100644 index 0000000..8e59a10 --- /dev/null +++ b/uw_hrp/tests/test_models.py @@ -0,0 +1,285 @@ +from unittest import TestCase +from datetime import datetime, timedelta, timezone +from uw_hrp.models import ( + EmploymentStatus, JobProfile, SupervisoryOrganization, + Worker, WorkerPosition, parse_date) +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_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": { + "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, + "PositionStartDate": "1994-10-01T00:00:00.000Z", + "PositionEndDate": "1997-10-01T00:00:00.000Z", + "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.to_json(), + { + "start_date": "1994-10-01 00:00:00+00:00", + "end_date": "1997-10-01 00:00:00+00:00", + "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.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", + "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": [{ + "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": []}, + {"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, + "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}) diff --git a/uw_hrp/tests/test_worker.py b/uw_hrp/tests/test_worker.py new file mode 100644 index 0000000..aeb778a --- /dev/null +++ b/uw_hrp/tests/test_worker.py @@ -0,0 +1,92 @@ +from unittest import TestCase +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 + + +@fdao_hrp_override +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(), + {"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", + "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.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') + self.assertRaises(DataFailureException, + get_worker_by_regid, + "00000000000000000000000000000001") + self.assertRaises(InvalidRegID, + get_worker_by_regid, "000") 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)))