def find_rate(service_type: str, zone: int, package: Package) -> float: """ After obtaining the zone, it finds the rate it needs and calculates the prices of the shipment even if it haves an exceeded weight it calculates it. :param service_type: str of service type to calculate :param zone: int of the calculated zone :param package: Package detail :return: float of shipment price """ exceeded_price = 0 if package.weight % 1 > 0: package_weight = int( package.weight ) + 1 # if it has more than an int weight it must add 1 else: package_weight = int(package.weight) # finds the exceeded weight and rate, with that it calculates the exceeded price if TYPE_KG_LIMIT[service_type] < package_weight: exceeded_weight = package_weight - TYPE_KG_LIMIT[service_type] package_weight = TYPE_KG_LIMIT[service_type] exceeded_query = { 'type': service_type, 'rates_by_zone.zone': zone, 'rates_by_zone.kg': '+' } exceeded_project = { '_id': 0, 'rates_by_zone': { '$elemMatch': { 'zone': zone, 'kg': '+' } }, 'rates_by_zone.rate': 1 } exceeded_rate = Database.find( ZONE_TO_RATE, exceeded_query, exceeded_project).next()['rates_by_zone'][0]['rate'] exceeded_price = exceeded_rate * exceeded_weight query = { 'type': service_type, 'rates_by_zone.zone': zone, 'rates_by_zone.kg': package_weight } project = { '_id': 0, 'rates_by_zone': { '$elemMatch': { 'zone': zone, 'kg': package_weight } }, 'rates_by_zone.rate': 1 } rate = Database.find(ZONE_TO_RATE, query, project).next()['rates_by_zone'][0]['rate'] return rate + exceeded_price
def find_rate(cls, service_type: str, package: Package) -> dict: if package.weight % 1 > 0: package_weight = int( package.weight ) + 1 # if it has more than an int weight it must add 1 else: package_weight = int(package.weight) if package_weight >= TYPE_KG_LIMIT and service_type == SPECIAL_TYPE: service_type = "5522411" if (package.origin_zipcode in DF_ZIP_CODES and package.destiny_zipcode in DF_ZIP_CODES) and service_type != \ TYPES_STR_TO_ID['ESTAFETA_DIA_SIGUIENTE']: service_type = "8608731" if service_type == SPECIAL_TYPE: price, descriptions = cls.Graph.dijkstra(0, package_weight) result_descriptions = dict() for description in descriptions: if result_descriptions.get(description) is None: result_descriptions[description] = 1 if "TERRESTRE" in description: rate_data = list( Database.find("Estafeta_rates", {"type": description}))[0] result_descriptions["cuenta"] = rate_data['_id'] result_descriptions['covered_kg'] = rate_data['kg'] result_descriptions['extra_kg_rate'] = rate_data[ 'adicional'] # TODO Delete THIS when needed if result_descriptions["cuenta"] in ['8646027']: result_descriptions["cuenta"] = '8622603' else: result_descriptions[description] += 1 return {"price": price, "options": result_descriptions} rate = Database.find("Estafeta_rates", {"_id": service_type}).next() exceeded_price = 0 exceeded_weight = 0 if package_weight > rate['kg']: exceeded_weight = package_weight - rate['kg'] exceeded_price = rate['adicional'] * exceeded_weight final_rate = rate['total'] + exceeded_price # TODO Delete THIS when needed if service_type in ['8646027']: service_type = '8622603' options = { rate['type']: 1, 'adicional': exceeded_weight, "cuenta": service_type, 'extra_kg_rate': rate['adicional'], 'covered_kg': rate['kg'] } return {'price': final_rate, "options": options}
def is_available(package: Package) -> (dict, dict): try: area_from = Database.find(AREAS_COLLECTION, { 'zip_codes': package.origin_zipcode }).next() area_to = Database.find(AREAS_COLLECTION, { 'zip_codes': package.destiny_zipcode }).next() except StopIteration: raise ZipCodesNotFound("No Hay Disponibilidad") return area_from, area_to
def discard_types(self, package): option_types = list( Database.find("STF_ZP", {"zip_code": package.destiny_zipcode})) terrain_flag = False for opt in option_types: if opt['service_type'] == 'TERRESTRE': terrain_flag = True break if not option_types or not terrain_flag: option_types += [{ 'zip_code': package.destiny_zipcode, 'periodicity': 'SEMANAL', 'extra': 1, 'service_type': 'TERRESTRE', 'availability': [1, 1, 1, 1, 1, 0, 0] }] result = list() if isinstance(self.type, list): for type in self.type: for opt_type in option_types: if TYPES_ID_TOSERVICE_TYPE.get( opt_type['service_type']) == type: result.append(type) continue if result: self.type = result
def create_graph() -> GraphUndirectedWeighted: rates = list( Database.find("Estafeta_rates", { "description": "TERRESTRE", "type": { "$ne": "METROPOLITANO" } }, {"_id": 0})) rates = {rate.pop('type'): dict(**rate) for rate in rates} graph = GraphUndirectedWeighted(22) for i in range(1, 21): if i <= rates['TERRESTRE_2']['kg']: description = 'TERRESTRE_2' rate = rates[description]['total'] elif rates['TERRESTRE_2']['kg'] < i <= rates['TERRESTRE_5']['kg']: description = 'TERRESTRE_5' rate = rates[description]['total'] elif rates['TERRESTRE_5']['kg'] < i <= rates['TERRESTRE_10']['kg']: description = 'TERRESTRE_10' rate = rates[description]['total'] else: description = 'TERRESTRE_20' rate = rates[description]['total'] graph.add_edge(0, i, rate, description) if i == 1: continue graph.add_edge(i, i + 1, rates['TERRESTRE_2']['adicional'], "adicional") return graph
def find_area(package: Package) -> (int, int): """ Given the package it determines the area of the destiny zipcode and the origin zipcode :param package: Package :return: tuple of areas """ try: area_from = Database.find(AREAS_COLLECTION, { 'zip_codes': package.origin_zipcode }).next()['Area'] area_to = Database.find(AREAS_COLLECTION, { 'zip_codes': package.destiny_zipcode }).next()['Area'] except StopIteration: raise ZipCodesNotFound("No Hay Disponibilidad") return area_from, area_to
def find_zone(area_from: int, area_to: int) -> int: """ given the areas from which they are sending and receiving it gets the zone to which the rate will be calculates :param area_from: :param area_to: :return: """ zone = Database.find(AREA_TO_ZONE_COLLECTION, { 'x': area_from, 'y': area_to }).next() return zone['value']
def find_delivery_data(package: Package) -> dict: try: return Database.find("STF_ZP", { "zip_code": package.destiny_zipcode }).next() except StopIteration: not_found_dict = { 'zip_code': package.destiny_zipcode, 'periodicity': 'SEMANAL', 'extra': 1, 'service_type': 'TERRESTRE', 'availability': [1, 1, 1, 1, 1, 0, 0] } return not_found_dict
def _get_extra_fees(self, package: Package) -> float: ext_zone = list( Database.find('DHL_EXT', {"_id": package.destiny_zipcode})) extra_fees = 0 if ext_zone: extra_fees += 133.67 if package.weight > 70.0: extra_fees += 244.90 if package.width > 120 or package.length > 120 or package.height > 120: extra_fees += 244.90 return extra_fees