def get_quotes(self, parcel_quote_request: ParcelQuoteRequest) -> dict: query_string = urllib.parse.urlencode(to_dict(parcel_quote_request)) response = http( url=f"{self.client.server_url}/quote?{query_string}", headers={ "Content-Type": "application/json", "Authorization": f"Basic {self.authorization}", }, method="GET", ) return to_dict(response)
def _process_quotes( args: Tuple[RateRequest, Proxy]) -> Tuple[List[QuoteDetails], List[Error]]: payload, proxy = args try: custom_payload = RateRequest(**to_dict(payload)) if custom_payload.shipper.account_number is None: custom_payload.shipper.account_number = DEFAULTS.get( proxy.client.carrier_name, {}).get("account_number", "") request = proxy.mapper.create_quote_request(custom_payload) response = proxy.get_quotes(request) logger.debug( (proxy.client.carrier_name, parse(request), parse(response))) return proxy.mapper.parse_quote_response(response) except OriginNotServicedError as e: logger.error(('error', proxy.client.carrier_name, f"{e}")) return [[], [ Error(carrier=proxy.client.carrier_name, code="400", message=f"{e}") ]] except Exception as e: logger.error(('error', e.args, proxy.client.carrier_name)) return [[], [ Error(carrier=proxy.client.carrier_name, code="500", message="An error occured while processing quotes") ]]
def get_quotes( self, request: Union[ShippingPriceRequest, Type[PostageRequest]]) -> dict: response = (self._get_shipping_price if isinstance( request, ShippingPriceRequest) else self._get_postage_service)(request) return to_dict(response)
def pickup_request(request, carrier=None): """ For creating an updating a pickup request * Only 'dhl' carrier is currently supported """ try: if carrier is None or carrier not in Proxies: return Response("Please specify a valid carrier", status=status.HTTP_400_BAD_REQUEST) reqData = serializers.PickupRequest(data=request.data) if reqData.is_valid(raise_exception=True): update = request.method == 'PUT' operation = Gateway.modify_pickup if update else Gateway.request_pickup pickup, errors = operation(PickupRequest(**reqData.data), Proxies.get(carrier)) if pickup is None and len(errors) > 0: rstatus = status.HTTP_400_BAD_REQUEST else: rstatus = status.HTTP_200_OK if update else status.HTTP_201_CREATED return Response( to_dict({ "pickup": pickup, "errors": errors }), status=rstatus ) else: return Response(reqData.errors, status=status.HTTP_400_BAD_REQUEST) except Exception as e: return Response(e.args, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
def _ensure_converted(rate: QuoteDetails, expected_currency: str): if rate.currency == expected_currency: return rate return QuoteDetails( **{ **to_dict(rate), **dict(currency=expected_currency, base_charge=Currency.convert(rate.base_charge, rate.currency, expected_currency), duties_and_taxes=Currency.convert(rate.duties_and_taxes, rate.currency, expected_currency), total_charge=Currency.convert(rate.total_charge, rate.currency, expected_currency), discount=Currency.convert(rate.discount, rate.currency, expected_currency), extra_charges=[ ChargeDetails( **{ **to_dict(charge), **dict(currency=expected_currency, amount=Currency.convert( charge.amount, charge.currency, expected_currency)) }) for charge in rate.extra_charges ]) })
def parse(entity: ISerializable): try: return export(entity) except: pass try: return etree.tostring(entity) except: pass try: return to_dict(entity) except: return None
def parse_error_response(self, response: dict) -> List[Error]: if "errors" not in response and "error" not in response: return [] error_response: ErrorResponse = ErrorResponse(**response) errors: List[ Union[APIError, PostageError]] = error_response.error + error_response.errors return [ Error(carrier=self.client.carrier_name, code=error.get('code'), message=error.get('message') or error.get('errorMessage')) for error in to_dict(errors) ]
def _get_shipping_price( self, shipping_price_request: ShippingPriceRequest) -> str: data = jsonify(to_dict(shipping_price_request)) return http( url=f"{self.client.server_url}/shipping/v1/prices/shipments", data=bytearray(data, "utf-8"), headers={ "Content-Type": "application/json", "Accept": "application/json", "Account-Number": self.client.account_number, "Authorization": f"Basic {self.authorization}", }, method="POST", ).replace('from', 'from_')
def get_tracking(self, tracking_ids: List[str]) -> dict: ids = ','.join(tracking_ids) result = http( url= f"{self.client.server_url}/shipping/v1/track?tracking_ids={ids}", headers={ "Content-Type": "application/json", "Accept": "application/json", "Account-Number": self.client.account_number, "Authorization": f"Basic {self.authorization}", }, method="GET", ) return to_dict(result)
def track(tracking_id): return { "ref": tracking_id, "response": to_dict( http( url=f"{self.client.server_url}/tracking/{tracking_id}", headers={ "Content-Type": "application/json", "Authorization": f"Basic {self.authorization}", }, method="GET", ) ) }
def _get_postage_service(self, postage_request: PostageRequest) -> str: route: str = { DomesticParcelServiceRequest: "/parcel/domestic/service.json", DomesticLetterServiceRequest: "/letter/domestic/service.json", IntlParcelServiceRequest: "/parcel/international/service.json", IntlLetterServiceRequest: "/letter/international/service.json", }[type(postage_request)] query_string = urllib.parse.urlencode(to_dict(postage_request)) return http( url=f"{self.client.server_url}/postage{route}?{query_string}", headers={ "Content-Type": "application/json", "AUTH-KEY": self.client.api_key, }, method="GET", )
def create(self, request): try: reqData = serializers.RateRequest(data=request.data) if reqData.is_valid(raise_exception=True): data, proxies = prune_carrier(reqData.data) payload = RateRequest(**data) rates, errors = Gateway.get_quotes(payload, proxies) sanitized_rates = sanitize_currency(rates, payload) return Response(to_dict({ **data, "rates": sanitized_rates, "errors": errors }), status=status.HTTP_207_MULTI_STATUS if len(errors) > 0 else status.HTTP_200_OK) else: return Response(reqData.errors, status=status.HTTP_400_BAD_REQUEST) except Exception as e: return Response(e.args, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
def create(request, carrier=None): """ For creating shipment and obtain label * Only 'dhl' carrier is currently supported """ try: if carrier is None or carrier not in Proxies: return Response("Please specify a valid carrier", status=status.HTTP_400_BAD_REQUEST) reqData = serializers.ShipmentRequest(data=request.data) if reqData.is_valid(raise_exception=True): shipment, errors = Gateway.create_shipment( ShipmentRequest(**reqData.data), Proxies.get(carrier) ) response = to_dict({ "shipment": shipment, "errors": errors }) return Response(response, status=status.HTTP_201_CREATED) else: return Response(reqData.errors, status=status.HTTP_400_BAD_REQUEST) except Exception as e: return Response(e.args, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
def request(request, carrier: str = None): try: carriers = ([carrier] if carrier is not None else request.data.get('carriers')) or [] reqData = extended_tracking_request( data=dict(list(request.data.items()) + [('carriers', carriers)])) if reqData.is_valid(raise_exception=True): data, request_proxies = prune_carrier(reqData.data) payload = TrackingRequest(**data) trackings = Gateway.get_tracking(payload, request_proxies) rstatus = status.HTTP_207_MULTI_STATUS if len( trackings[1]) > 0 else status.HTTP_200_OK response = to_dict({ "tracking": trackings[0], "errors": trackings[1] }) return Response(response, status=rstatus) else: return Response(reqData.errors, status=status.HTTP_400_BAD_REQUEST) except Exception as e: return Response(e.args, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
def _process_shipment(payload: ShipmentRequest, proxy: Proxy) -> Tuple[ShipmentDetails, List[Error]]: try: custom_payload = RateRequest(**to_dict(payload)) if custom_payload.shipper.account_number is None: custom_payload.shipper.account_number = DEFAULTS.get( proxy.client.carrier_name, {}).get("account_number", "") request = proxy.mapper.create_shipment_request(custom_payload) response = proxy.create_shipment(request) logger.debug((proxy.client.carrier_name, parse(request), response)) return proxy.mapper.parse_shipment_response(response) except Exception as e: logger.error((e.args, payload, proxy)) return [ [], [ Error(carrier=proxy.client.carrier_name, code="500", message= f"An error occured while processing shipping: {e.args}") ] ]
def track(request, carrier: str = None, tracking_number: str = None): """ """ error = None try: if carrier is None or carrier not in Proxies: error = "Please specify a valid carrier" if tracking_number is None: error = "tracking number should be specified" if error is None: payload = TrackingRequest(tracking_numbers=[tracking_number]) trackings, errors = Gateway.get_tracking(payload, filter_proxies([carrier])) tracking = trackings[0] if len(trackings) > 0 else None return Response(to_dict({ "tracking": tracking, "errors": errors }), status=status.HTTP_200_OK if tracking is not None else status.HTTP_404_NOT_FOUND) else: return Response(error, status=status.HTTP_400_BAD_REQUEST) except Exception as e: return Response(e.args, status=status.HTTP_500_INTERNAL_SERVER_ERROR)