def get_rates( self, request: Serializable[Union[RateV4Request, IntlRateV2Request]] ) -> Deserializable[str]: query = urllib.parse.urlencode(request.serialize()) response = http(url=f"{self.settings.server_url}?{query}", method="GET") return Deserializable(response, to_xml)
def get_tracking( self, request: Serializable[TrackFieldRequest]) -> Deserializable[str]: query = urllib.parse.urlencode(request.serialize()) response = http(url=f"{self.settings.server_url}?{query}", method="GET") return Deserializable(response, to_xml)
def get_tracking(self, request: Serializable[List[str]]) -> Deserializable[str]: """ get_tracking make parallel request for each pin """ _throttle = 0.0 def track(tracking_pin: str) -> str: nonlocal _throttle time.sleep(_throttle) _throttle += 0.025 return http( url= f"{self.settings.server_url}/vis/track/pin/{tracking_pin}/detail", headers={ "Accept": "application/vnd.cpc.track-v2+xml", "Authorization": f"Basic {self.settings.authorization}", "Accept-language": f"{self.settings.language}-CA", }, method="GET", ) response: List[str] = exec_async(track, request.serialize()) return Deserializable(XP.bundle_xml(xml_strings=response), XP.to_xml)
def create_shipment( self, request: Serializable[Pipeline]) -> Deserializable[str]: def process(job: Job): if job.data is None: return job.fallback return self._send_request( request=job.data, path=dict( create="/EWS/V2/Shipping/ShippingService.asmx", validate="/EWS/V2/Shipping/ShippingService.asmx", document= "/EWS/V1/ShippingDocuments/ShippingDocumentsService.asmx", )[job.id], soapaction=dict( create="http://purolator.com/pws/service/v2/CreateShipment", validate= "http://purolator.com/pws/service/v2/ValidateShipment", document="http://purolator.com/pws/service/v1/GetDocuments", )[job.id], ) pipeline: Pipeline = request.serialize() _, *response = pipeline.apply(process) return Deserializable(XP.bundle_xml(response), XP.to_xml)
def get_rates(self, request: Serializable) -> Deserializable[str]: response = http( url=self.settings.server_url, data=bytearray(request.serialize(), "utf-8"), headers={"Content-Type": "application/xml"}, method="POST", ) return Deserializable(response, XP.to_xml)
def cancel_shipment(self, request: Serializable) -> Deserializable: response = self._send_request( path="/EWS/V2/Shipping/ShippingService.asmx", soapaction="http://purolator.com/pws/service/v2/VoidShipment", request=request, ) return Deserializable(response, XP.to_xml)
def get_tracking(self, request: Serializable[Envelope]) -> Deserializable[str]: response = self._send_request( path="/PWS/V1/Tracking/TrackingService.asmx", soapaction="http://purolator.com/pws/service/v1/TrackPackagesByPin", request=request, ) return Deserializable(response, XP.to_xml)
def get_rates(self, request: Serializable[Envelope]) -> Deserializable[str]: response = self._send_request( path="/EWS/V2/Estimating/EstimatingService.asmx", soapaction="http://purolator.com/pws/service/v2/GetFullEstimate", request=request, ) return Deserializable(response, XP.to_xml)
def cancel_pickup(self, request: Serializable[Envelope]) -> Deserializable[str]: response = self._send_request( path="/EWS/V1/PickUp/PickUpService.asmx", soapaction="http://purolator.com/pws/service/v1/VoidPickUp", request=request, ) return Deserializable(response, XP.to_xml)
def create_shipment(self, request: Serializable[Pipeline]) -> Deserializable[str]: def _contract_shipment(job: Job): return http( url=f"{self.settings.server_url}/rs/{self.settings.customer_number}/{self.settings.customer_number}/shipment", data=bytearray(job.data.serialize(), "utf-8"), headers={ "Content-Type": "application/vnd.cpc.shipment-v8+xml", "Accept": "application/vnd.cpc.shipment-v8+xml", "Authorization": f"Basic {self.settings.authorization}", "Accept-language": "en-CA", }, method="POST", ) def _non_contract_shipment(job: Job): return http( url=f"{self.settings.server_url}/rs/{self.settings.customer_number}/ncshipment", data=bytearray(job.data.serialize(), "utf-8"), headers={ "Accept": "application/vnd.cpc.ncshipment-v4+xml", "Content-Type": "application/vnd.cpc.ncshipment-v4+xml", "Authorization": f"Basic {self.settings.authorization}", "Accept-language": "en-CA", }, method="POST", ) def _get_label(job: Job): label_string = http( decoder=lambda b: base64.encodebytes(b).decode("utf-8"), url=job.data, headers={ "Accept": "application/pdf", "Authorization": f"Basic {self.settings.authorization}", }, method="GET", ) return f'<label>{label_string}</label>' def process(job: Job): if job.data is None: return job.fallback subprocess = { 'contract_shipment': _contract_shipment, 'non_contract_shipment': _non_contract_shipment, 'shipment_label': _get_label } if job.id not in subprocess: raise PurplShipError(f"Unknown shipment request job id: {job.id}") return subprocess[job.id](job) pipeline: Pipeline = request.serialize() response = pipeline.apply(process) return Deserializable(bundle_xml(response), to_xml)
def get_tracking( self, request: Serializable[TrackRequest]) -> Deserializable[str]: response = http( url=f"{self.settings.server_url}/track", data=bytearray(request.serialize(), "utf-8"), headers={"Content-Type": "application/xml"}, method="POST", ) return Deserializable(response, to_xml)
def cancel_pickup( self, request: Serializable[CancelPURequest]) -> Deserializable[str]: response = http( url=self.settings.server_url, data=bytearray(request.serialize(), "utf-8"), headers={"Content-Type": "application/xml"}, method="POST", ) return Deserializable(response, to_xml)
def validate_address( self, request: Serializable[Envelope]) -> Deserializable[str]: response = self._send_request( path="/EWS/V2/ServiceAvailability/ServiceAvailabilityService.asmx", soapaction= "http://purolator.com/pws/service/v2/ValidateCityPostalCodeZip", request=request, ) return Deserializable(response, XP.to_xml)
def create_shipment( self, request: Serializable[ProcessShipmentRequest] ) -> Deserializable[str]: response = http( url=self.settings.server_url, data=bytearray(request.serialize(), "utf-8"), headers={"Content-Type": "application/xml"}, method="POST", ) return Deserializable(response, to_xml)
def cancel_pickup(self, request: Serializable[str]) -> Deserializable[str]: pickuprequest = request.serialize() response = http( url= f"{self.settings.server_url}/enab/{self.settings.customer_number}/pickuprequest/{pickuprequest}", headers={ "Accept": "application/vnd.cpc.pickuprequest+xml", "Authorization": f"Basic {self.settings.authorization}", "Accept-language": f"{self.settings.language}-CA", }, method="DELETE", ) return Deserializable(response or "<wrapper></wrapper>", XP.to_xml)
def get_rates(self, request: Serializable[mailing_scenario]) -> Deserializable[str]: response = http( url=f"{self.settings.server_url}/rs/ship/price", data=bytearray(request.serialize(), "utf-8"), headers={ "Content-Type": "application/vnd.cpc.ship.rate-v4+xml", "Accept": "application/vnd.cpc.ship.rate-v4+xml", "Authorization": f"Basic {self.settings.authorization}", "Accept-language": "en-CA", }, method="POST", ) return Deserializable(response, to_xml)
def get_tracking(self, request: Serializable[Envelope]) -> Deserializable[str]: response = http( url= f"{self.settings.server_url}/PWS/V1/Tracking/TrackingService.asmx", data=request.serialize().encode("utf-8"), headers={ "Content-Type": "text/xml; charset=utf-8", "soapaction": "http://purolator.com/pws/service/v1/TrackPackagesByPin", "Authorization": f"Basic {self.settings.authorization}", }, method="POST", ) return Deserializable(response, to_xml)
def get_rates(self, request: Serializable[Envelope]) -> Deserializable[str]: response = http( url= f"{self.settings.server_url}/EWS/V2/Estimating/EstimatingService.asmx", data=bytearray(request.serialize(), "utf-8"), headers={ "Content-Type": "text/xml; charset=utf-8", "soapaction": "http://purolator.com/pws/service/v2/GetFullEstimate", "Authorization": f"Basic {self.settings.authorization}", }, method="POST", ) return Deserializable(response, to_xml)
def get_tracking( self, request: Serializable[List[TrackRequest]]) -> Deserializable[str]: """ get_tracking make parrallel request for each TrackRequest """ def get_tracking(track_request: str): return http( url=f"{self.settings.server_url}/Track", data=bytearray(track_request, "utf-8"), headers={"Content-Type": "application/xml"}, method="POST", ) response: List[str] = exec_parrallel(get_tracking, request.serialize()) return Deserializable(bundle_xml(xml_strings=response), to_xml)
def schedule_pickup( self, request: Serializable[Pipeline]) -> Deserializable[str]: def _availability(job: Job) -> str: return http( url= f"{self.settings.server_url}/ad/pickup/pickupavailability/{job.data}", headers={ "Accept": "application/vnd.cpc.pickup+xml", "Authorization": f"Basic {self.settings.authorization}", "Accept-language": f"{self.settings.language}-CA", }, method="GET", ) def _create_pickup(job: Job) -> str: return http( url= f"{self.settings.server_url}/enab/{self.settings.customer_number}/pickuprequest", data=bytearray(job.data.serialize(), "utf-8"), headers={ "Accept": "application/vnd.cpc.pickuprequest+xml", "Content-Type": "application/vnd.cpc.pickuprequest+xml", "Authorization": f"Basic {self.settings.authorization}", "Accept-language": f"{self.settings.language}-CA", }, method="POST", ) def process(job: Job): if job.data is None: return job.fallback subprocess = { "create_pickup": _create_pickup, "availability": _availability, } if job.id not in subprocess: raise PurplShipError( f"Unknown pickup request job id: {job.id}") return subprocess[job.id](job) pipeline: Pipeline = request.serialize() response = pipeline.apply(process) return Deserializable(XP.bundle_xml(response), XP.to_xml)
def modify_pickup(self, request: Serializable[dict]) -> Deserializable[str]: def _get_pickup(job: Job) -> str: return http( url=f"{self.settings.server_url}{job.data.serialize()}", headers={ "Accept": "application/vnd.cpc.pickup+xml", "Authorization": f"Basic {self.settings.authorization}", "Accept-language": f"{self.settings.language}-CA", }, method="GET", ) def _update_pickup(job: Job) -> str: payload = job.data.serialize() return http( url= f"{self.settings.server_url}/enab/{self.settings.customer_number}/pickuprequest/{payload['pickuprequest']}", data=bytearray(payload["data"], "utf-8"), headers={ "Accept": "application/vnd.cpc.pickuprequest+xml", "Authorization": f"Basic {self.settings.authorization}", "Accept-language": f"{self.settings.language}-CA", }, method="PUT", ) def process(job: Job): if job.data is None: return job.fallback subprocess = { "update_pickup": _update_pickup, "get_pickup": _get_pickup, } if job.id not in subprocess: raise PurplShipError( f"Unknown pickup request job id: {job.id}") return subprocess[job.id](job) pipeline: Pipeline = request.serialize() response = pipeline.apply(process) return Deserializable(XP.bundle_xml(response), XP.to_xml)
def create_shipment( self, request: Serializable[Pipeline]) -> Deserializable[str]: def process(job: Job): return (http( url= f"{self.settings.server_url}{SHIPPING_SERVICES[job.id]['path']}", data=bytearray(job.data, "utf-8"), headers={ "Content-Type": "text/xml; charset=utf-8", "soapaction": SHIPPING_SERVICES[job.id]['action'], "Authorization": f"Basic {self.settings.authorization}", }, method="POST", ) if job.data is not None else job.fallback) pipeline: Pipeline = request.serialize() _, *response = pipeline.apply(process) return Deserializable(bundle_xml(response), to_xml)
def get_tracking(self, request: Serializable[List[str]]) -> Deserializable[str]: """ get_tracking make parallel request for each pin """ def track(tracking_pin: str) -> str: return http( url=f"{self.settings.server_url}/vis/track/pin/{tracking_pin}/summary", headers={ "Accept": "application/vnd.cpc.track+xml", "Authorization": f"Basic {self.settings.authorization}", "Accept-language": "en-CA", }, method="GET", ) response: List[str] = exec_parrallel(track, request.serialize()) return Deserializable(bundle_xml(xml_strings=response), to_xml)
def modify_pickup(self, request: Serializable[Pipeline]) -> Deserializable[str]: def process(job: Job): if job.data is None: return job.fallback return self._send_request( path="/EWS/V1/PickUp/PickUpService.asmx", request=job.data, soapaction=dict( validate= "http://purolator.com/pws/service/v1/ValidatePickUp", modify="http://purolator.com/pws/service/v1/ModifyPickUp", )[job.id], ) pipeline: Pipeline = request.serialize() response = pipeline.apply(process) return Deserializable(XP.bundle_xml(response), XP.to_xml)
def cancel_shipment(self, request: Serializable) -> Deserializable: def _request(method: str, shipment_id: str, path: str = '', **kwargs): return http( url= f"{self.settings.server_url}/rs/{self.settings.customer_number}/{self.settings.customer_number}/shipment/{shipment_id}{path}", headers={ "Content-Type": "application/vnd.cpc.shipment-v8+xml", "Accept": "application/vnd.cpc.shipment-v8+xml", "Authorization": f"Basic {self.settings.authorization}", "Accept-language": f"{self.settings.language}-CA", }, method=method, **kwargs) def process(job: Job): if job.data is None: return job.fallback subprocess = { "info": lambda _: _request('GET', job.data.serialize()), "refund": lambda _: _request( 'POST', job.data['id'], '/refund', data=bytearray(job.data['payload'].serialize(), "utf-8")), "cancel": lambda _: _request('DELETE', job.data.serialize()), } if job.id not in subprocess: raise PurplShipError( f"Unknown shipment cancel request job id: {job.id}") return subprocess[job.id](job) pipeline: Pipeline = request.serialize() response = pipeline.apply(process) return Deserializable(XP.bundle_xml(response), XP.to_xml)
def parse_cancel_shipment_response( self, response: Deserializable ) -> Tuple[ConfirmationDetails, List[Message]]: return parse_shipment_cancel_response(response.deserialize(), self.settings)
def parse_address_validation_response( self, response: Deserializable ) -> Tuple[AddressValidationDetails, List[Message]]: return parse_address_validation_response(response.deserialize(), self.settings)