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 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 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 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 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 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 get_shift_by_id(shift_id): """ This function used to get shift by shift id. Args: shift_id (string): shift id as string. Returns: dict: (shift associated with given shift id) The return value. """ # Initialize return value. return_value = {"statusCode": None, "message": None, "body": None} try: # Check if class Shifts has no objects member. if 'objects' not in dir(Shifts): # Assign objects member. Shifts.objects = QuerySetManager() # Initialize database connection response = DbConnection.openconnection(CONNECTION_KEY) if response["statusCode"] == 200: response = Shifts.objects(shiftid=shift_id).to_json(indent=0) shift_data = json.loads(response) if shift_data: logger.info("Get Shift data from database success.") return_value["statusCode"] = 200 return_value["message"] = "Success" return_value["body"] = shift_data else: logger.info( "Shift data associated with vacated shift not found!.") return_value["statusCode"] = 404 return_value[ "message"] = "Shift data not found for vacated shift" return_value["body"] = [] else: return_value = response except KeyError: message = str(KeyError) logger.info("Error found in get_shift_by_id function! Error: %s", message) return_value["statusCode"] = 500 return_value["message"] = "Internal server error" return_value["body"] = [] return return_value
def dal_handler(event, context): """ This function use to handle post request from sqs trigger. Args: body (json): Required 'nType', 'Id' Returns: json: The return value. """ logger.debug("Received new event: %s", repr(event)) # Initialize response object. response = { 'statusCode': None, 'headers': { 'Content-Type': 'application/json' }, 'body': str(context) } logger.info("dal_handler called seccess") # Get request body. if "body" in event: body = event['body'] else: body = event['Records'][0]['body'] body = json.loads(body) # Check if Type and ID exist in request body. if 'nType' in body and 'Id' in body: logger.info("Get nType, Id successfully") result = sqs(body) response['statusCode'] = result['statusCode'] response['body'] = result['body'] else: logger.info("Bad request formate") response['body'] = "Can't get 'nType' and 'Id' from request body!" response['statusCode'] = 400 logger.debug("Lambda Response: %s", repr(response)) return response
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