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)
예제 #2
0
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")
                ]]
예제 #3
0
 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)
예제 #4
0
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)
예제 #5
0
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
                   ])
        })
예제 #6
0
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
예제 #7
0
 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)
     ]
예제 #8
0
 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_')
예제 #9
0
 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)
예제 #10
0
 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",
             )
         )
     }
예제 #11
0
 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",
     )
예제 #12
0
 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)
예제 #13
0
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)
예제 #14
0
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)
예제 #15
0
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}")
            ]
        ]
예제 #16
0
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)