def get_api_data(url, body, token): """ This function use to get data from API. Args: url (string): required api url. body (dict): required request body Returns: json: The return value. """ # Initialize return value. return_value = {"statusCode": None, "body": None} try: headers = {"Content-Type": "application/json", "Authorization": token} response = requests.post(url, data=json.dumps(body), headers=headers) return_value["body"] = response return_value["statusCode"] = response.status_code if response.status_code == 200: logger.info("Successfully called %s with response code of %s", url, response.status_code) else: logger.error("Error calling %s, response code was: %s", url, response.status_code) except RequestException as ex: return_value["statusCode"] = 500 return_value["body"] = str(RequestException) logger.error("Error calling %s, error was %s", url, str(ex)) return return_value
def re_handler(event, context): """ This handler function return recommendation acording to vacated shift, shifter parameter. Args: event["body"] (dict): request body to get recommendation. Returns: json: The return value. """ logger.debug("Received new event: %s", repr(event)) response = { 'statusCode': None, 'headers': { 'Content-Type': 'application/json' }, 'body': str(context) + str(event) } vacated_params = event['body'] if vacated_params: vacated_params = json.loads(vacated_params) result = recommendations(vacated_params) response['statusCode'] = result['statusCode'] response['body'] = json.dumps(result) else: response['body'] = "Unprocessable Entity" response['statusCode'] = 422 logger.error("Unable to parse request paramaters") logger.debug("Lambda Response: %s", repr(response)) return response
def recommendations(vacated_params): """ This function used to get recommended shifter according to request params. Args: vacated_params (dict): vacated shift and shifter data. Returns: dict: (List of recommended shifter) The return value. """ # Initialize return value return_value = {"statusCode": None, "message": None, "body": None} try: patterns = ConfigLoaders.get_organizationsetting( vacated_params["jobProviderId"]) qualified_shifter = get_qualified_shifter( vacated_params, patterns["disqualify_structures"]) return_value = get_recommended_shifter(qualified_shifter, vacated_params, patterns['scoring_structures']) except BaseException as ex: logger.error("Error in recommendation function. %s", str(ex)) return_value['statusCode'] = 500 return_value["message"] = "Internal server error!" return_value['body'] = [] return return_value
def day_overtime_risk(instance): """ This function used to filter shifter shift and vacated shift over time risk for same day. Args: instance (dict): { shifter_day_hour: shifter shift duration from start to end. vacated_hour: vacated shift duration from start to end. disqualify_params: params for filter overtime risk for the same day. } Returns: boolean: The filter status. """ # Initialize return value. return_value = "qualified" try: shifter_shift_hour = instance["shifter_day_hour"] vacated_shift_hour = instance["vacated_hour"] disqualify_params = instance["disqualify_params"] shift_duration_count = shifter_shift_hour + vacated_shift_hour if shift_duration_count > disqualify_params["day_overtime_range"]: logger.info("Disqualified Reason: day_overtime_risk") return_value = "disqualified" except BaseException as ex: logger.error( "Disqualified Reason: EXCEPTION in day_overtime_risk: %s", str(ex)) return_value = "disqualified" return return_value
def week_overtime_risk(instance): """ This function used to filter shifter shift and vacated shift over time risk for a week. Args: instance (dict): { shifter_week_hour: Total conformed shift duration hour in week. vacated_hour: vacated shift duration from start to end. disqualify_params: params for filter week over time risk. Returns: boolean: The filter status. """ # Initialize return value. return_value = "qualified" try: shifter_week_hour = instance["shifter_week_hour"] vacated_shift_hour = instance["vacated_hour"] disqualify_params = instance["disqualify_params"] week_duration = shifter_week_hour + vacated_shift_hour if week_duration > disqualify_params["week_overtime_range"]: logger.info("Disqualified Reason: week_overtime_risk") return_value = "disqualified" except BaseException as ex: logger.error( "Disqualified Reason: EXCEPTION in week_overtime_risk: %s", str(ex)) return_value = "disqualified" return return_value
def shift_overlap(instance): """ This function used to filter shifter shift time and vacated shift time overlap each other. Args: instance (dict): { shifter_hour_list: List of hours between shifter start and end time. vacated_hour_list: List of hours between vacated start and end time. disqualify_params: Status to filter Example: True/False } Returns: boolean: The disqualify status. """ # Initialize return value. return_value = "qualified" try: disqualify_params = instance["disqualify_params"] overlap = [] if disqualify_params: shifter_hour_list = instance["shifter_hour_list"] vacated_hour_list = instance["vacated_hour_list"] overlap = [ value for value in shifter_hour_list if value in vacated_hour_list ] if overlap: logger.info("Disqualified Reason: shift_overlap") return_value = "disqualified" except BaseException as ex: logger.error("Disqualified Reason: EXCEPTION in shift_overlap: %s", str(ex)) return_value = "disqualified" return return_value
def openconnection(connection_key): """ This function return connection object acording to connection params. Args: connection_key (dic): have following keys { username, host, password, port, authentication_source, db_name }. Returns: Object: The return value. """ return_value = {"statusCode": None, "message": None, "body": None} try: # Initialize connection string. mongo_port = int(27017) try: mongo_port = int(connection_key["port"]) except ValueError: logger.error( "Mongo DB Port should be an integer. Provided value was: %s", connection_key["port"]) connection_kwargs = { 'username': connection_key['username'], 'host': connection_key['host'], 'password': connection_key['password'], 'port': mongo_port, 'authentication_source': connection_key['authSource'] } # Get connection. connect(connection_key['db_name'], **connection_kwargs) # Get connection object. connection = get_connection() # Get database. database = get_db() if database.name == connection_key['db_name']: logger.info("Database connected successfully.") return_value["statusCode"] = 200 return_value["message"] = "Success" return_value["body"] = connection except BaseException as exceptions: message = str(exceptions) logger.error("Database connection failed!: %s", message) return_value["statusCode"] = 500 return_value["message"] = "Internal server error!" return_value["body"] = None return return_value
def get_shifters_from_db(vacated_params, disqualify_params): """ This function used to get filtered shifters data from database. Args: vacated_params (dict): Vacated shift, shifter data. disqualify_params (dict): paramiters to filter data Returns: dict: The return value. """ # Initialize return value. return_value = {"statusCode": None, "message": None, "body": None} try: # Check if class Shifters has no objects member. if 'objects' not in dir(Shifters): # Assign objects member. Shifters.objects = QuerySetManager() # Initialize database connection response = DbConnection.openconnection(CONNECTION_KEY) if response["statusCode"] == 200: # Get data from database result = Shifters.objects.get_shifters( vacated_params, disqualify_params).to_json(indent=0) shifters = json.loads(result) if shifters: logger.info("Get shifters data from database success.") return_value["statusCode"] = 200 return_value["message"] = "Seccess" return_value["body"] = shifters else: logger.info("Shifters not found in database!") return_value["statusCode"] = 404 return_value["message"] = "Shifters not found in database!" return_value["body"] = [] else: return_value = response except BaseException as ex: logger.error("Error retrieving data from MongoDB. %s", repr(ex)) return_value["statusCode"] = 500 return_value["message"] = "Internal server error!" return_value["body"] = [] return return_value
def get_disqualify_status(disqualify_instances): """ This function used to perform disqualify filter and return status. Args: disqualify_instances (List): list of all filter function and associated params. Returns: List: The status of disqualify filter. """ # Initialize qualify shifter disqualify_status = [] try: for method, inputs in disqualify_instances.items(): status = FILTER.execute(method, inputs) logger.debug("QualityFilter %s returned status of: %s", method, status) disqualify_status.append(status) return disqualify_status except BaseException as exceptions: message = str(exceptions) logger.error("Error while getting disqualify status: %s", message) return None
def position_filter(instance): """ This function used to filter shift position completed for vacated shift. Args: shifter (dict): shifter, vacated shift data. Returns: boolean: The return value. """ # Initialize return value. return_value = "qualified" try: completed_position_count = instance["completed_position_count"] completed_position_range = instance["completed_position_range"] if completed_position_count == completed_position_range: logger.info("Disqualified Reason: position_filter") return_value = "disqualified" except BaseException as ex: logger.error( "Disqualified Reason: EXCEPTION in position_filter: %s", str(ex)) return_value = "disqualified" return return_value
def reliability_filter(instance): """ This function used to check reliability of shifter on the basis of nowshow count. Args: shifter (dict): shifter, vacated shift data. Returns: boolean: The return value. """ # Initialize return value. return_value = "qualified" try: noshow_count = instance["noshowcount"] noshow_range = instance["noshow_range"] if noshow_count >= noshow_range: logger.info("Disqualified Reason: reliability_filter") return_value = "disqualified" except BaseException as ex: logger.error( "Disqualified Reason: EXCEPTION in reliability_filter: %s", str(ex)) return_value = "disqualified" return return_value
def save_shifter(data): """ This function used to save shifter data into database. Args: data (dict): Shifter data. Returns: dict: The return value. """ # Initialize return value return_value = {"statusCode": None, "body": None} try: response = DbConnection.openconnection(CONNECTION_KEY) if response["statusCode"] == 200: # Initialize shifter object. shifter = Shifters( id=data['id'], shifterid=data['id'], existingshifterjpid=data['existingshifterjpid'], position=data['position'], location=[float(data['longitude']), float(data['latitude'])], rating=data['rating'], shifteravailability=data['shifteravailability']) # To save shifter data in database. shifter.save() logger.info("Saved data successfully") return_value["statusCode"] = 200 return_value["body"] = "Success" else: return_value = response except BaseException as exceptions: message = str(exceptions) logger.error("Shifter data not saved! Error: %s", message) return_value["statusCode"] = 500 return_value["body"] = message return return_value
def duration_difference(instance): """ This function used to filter shifter shift and vacated shift difference time risk. Args: instance (dict): shifter, vacated shift data. Returns: boolean: The return value. """ # Initialize return value return_value = "qualified" try: duration_difference_list = instance["duration_difference_list"] disqualify_params = instance["duration_difference_range"] for difference in duration_difference_list: if difference <= disqualify_params: logger.info("Disqualified Reason: duration_difference") return_value = "disqualified" except BaseException as ex: logger.error( "Disqualified Reason: EXCEPTION in duration_difference: %s", str(ex)) return_value = "disqualified" return return_value
def save_shift(data): """ This function used to save shift data into database. Args: data (dict): Shift data. Returns: dict: The return value. """ # Initialize return value return_value = {"statusCode": None, "body": None} try: # Initialize database connection response = DbConnection.openconnection(CONNECTION_KEY) if response["statusCode"] == 200: # Initialize shift object. shift = Shifts( id=data['shiftid'], shiftid=data['shiftid'], jobproviderid=data['jobproviderid'], location=[float(data['longitude']), float(data['latitude'])], shiftdetail=data["shiftdetail"]) # To save shift data in database. shift.save() logger.info("Saved data successfully") return_value["statusCode"] = 200 return_value["body"] = "Success" else: return_value = response except BaseException as exceptions: message = str(exceptions) logger.error("Shift data not saved! Error: %s", message) return_value["statusCode"] = 500 return_value["body"] = message return return_value
def recommended_filter(instance): """ This function used to filter shifter recommended on the basis of recommended count. Args: shifter (dict): shifter, vacated shift data. Returns: boolean: The return value. """ # Initialize return value. return_value = "qualified" try: recommended_count = instance["recommendedcount"] invited_count = instance["invitedcount"] recommended_range = instance["recommended_range"] invited_range = instance["invited_range"] if recommended_count >= recommended_range and invited_count == invited_range: logger.info("Disqualified Reason: recommend_filter") return_value = "disqualified" except BaseException as ex: logger.error( "Disqualified Reason: EXCEPTION in recommend_filter: %s", str(ex)) return_value = "disqualified" return return_value
def flexibility_filter(instance): """ This function used to check flexibility of shifter on the basis of invited and accepted count. Args: instance (dict): shifter, vacated shift data. Returns: boolean: The return value. """ # Initialize return value. return_value = "qualified" try: invited_count = instance["invitedcount"] accepted_count = instance["acceptedcount"] accepted_range = instance["accepted_range"] invited_range = instance["invited_range"] if invited_count >= invited_range and accepted_count == accepted_range: logger.info("Disqualified Reason: day_overtime_risk") return_value = "disqualified" except BaseException as ex: logger.error( "Disqualified Reason: EXCEPTION in flexibility_filter: %s", str(ex)) return_value = "disqualified" return return_value
def sqs(body): """ This function used to call dal api and save response into mongo db according to request params. Notes: 'This function use helper function to save shift and shifter data Args: body (dict): required for call dal api. Returns: dict: The return value. """ # initialize return value. return_value = {"statusCode": None, "body": None} try: # Initialize request body to call dal api. request_body = {"ID": body['Id'], "Type": body['nType']} # To parse as string and log the request body comming from sqs. request_body_string = str(body) logger.debug("Request body from sqs %s", request_body_string) # To call dal api and store response in result variable. result = get_api_data(DAL_URL['base_url'], request_body, DAL_URL["token"]) # To check if dal api call success. if result["statusCode"] == 200: logger.info("DAL api called success for type %s", body['nType']) data = result["body"].json() if data['data']: data = data['data'][0] logger.info("Get data from dal api succeeded") # To switch according to type. if body['nType'] == 'shifter': # Call shifter function to save shifter data. response = save_shifter(data) return_value = response elif body['nType'] == 'shift': # Call shift function to save shift data. response = save_shift(data) return_value = response else: logger.error("Response %s %s.", data["status"], data["message"]) return_value["statusCode"] = data['status'] return_value["body"] = data['message'] else: logger.error("Error during call dal api!") return_value = result except BaseException as exceptions: message = str(exceptions) logger.error("Error ! %s", message) return_value['statusCode'] = 500 return_value['body'] = message return return_value
def get_shifter_volatile_data(shifters, vacated_params): """ This function is used to get shifters voatile data from dal api. Args: shifters (List): List of filtered shifter data. Returns: dict: The return value. """ # Initialize return value. return_value = {"statusCode": None, "message": None, "body": {}} try: # Initialize request body for call dal api type: "qualify". shifter_ids_list = [] for shifter in shifters: shifter_ids_list.append(shifter["shifterid"]) shifter_ids = ", ".join(shifter_ids_list) request_body = { "ID": shifter_ids, "Type": "qualify", "VacatedShiftDate": vacated_params["startTime"] } result = get_api_data(DAL_URL['base_url'], request_body, DAL_URL["token"]) # To check if dal api call success. if result["statusCode"] == 200: logger.info("DAL api called successfully for type qualify.") data = result["body"].json() # To check data found. if data["data"]: logger.info("Shifters volatile data get success.") return_value["statusCode"] = 200 return_value["message"] = "Success" return_value["body"] = data["data"] else: logger.error("Shifters volatile data not found!") return_value["statusCode"] = data['status'] return_value["message"] = "Shifters volatile data not found!" return_value["body"] = [] else: logger.error("Error calling DAL http response was: %s", result["statusCode"]) return_value["statusCode"] = result["statusCode"] return_value["message"] = "Internal server error!" return_value["body"] = [] except BaseException as exceptions: message = str(exceptions) logger.error("Error while gatting shifters volatile data %s", message) return_value["statusCode"] = 500 return_value["message"] = "Internal server error!" return_value["body"] = [] return return_value
def get_qualified_shifter(vacated_params, patterns): """ This function used to get qualified shifter. Args: vacated_params (dict): vacated shifter, shift data. Returns: dict: The return value. """ # Initialize return value. return_value = {"statusCode": None, "message": None, "body": None} # Initialize array to store list of shifter with volatile data. shifters_data = [] try: # To get filtered shifter from database. shifter_from_db = get_shifters_from_db(vacated_params, patterns["static_data_filter"]) shifter_volatile_data = get_shifter_volatile_data( shifter_from_db["body"], vacated_params) shifters_data = get_combined_shifter(shifter_from_db, shifter_volatile_data) if shifters_data["statusCode"] == 200: qualified_shifter = [] instance_builder = DisqualifyInstanceBuilder() logger.info( "Getting qualified shifter for shiftId: %s and positionId: %s", vacated_params["shiftId"], vacated_params["positionId"]) for data in shifters_data["body"]: logger.info(LOG_HEADER, data["shifterid"]) instances = {} inputs = {"shifter": data, "vacated_params": vacated_params} for method, pattern in patterns["volatile_data_filter"].items( ): instance = instance_builder.execute( method, inputs, pattern) if instance and instance != "Invalid": instances.update(instance) filter_status = get_disqualify_status(instances) if "disqualified" not in filter_status: instances.clear() filter_status.clear() qualified_shifter.append(data) if qualified_shifter: return_value["statusCode"] = 200 return_value["message"] = "Success" return_value["body"] = qualified_shifter logger.info("Shifter is qualified") else: return_value["statusCode"] = 404 return_value[ "message"] = "No qualified shifters found for this shift" return_value["body"] = [] logger.info("Shifter was not qualified for the vacated shift") else: return_value = shifters_data except AttributeError as ex: return_value["statusCode"] = 500 return_value["message"] = "Internal server error!" return_value["body"] = [] logger.error("Error %s", repr(ex)) return return_value