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_pickup(update_response: str, payload: PickupUpdateRequest, settings: Settings) -> Job: errors = parse_error_response(XP.to_xml(XP.bundle_xml([update_response])), settings) data = None if any( errors ) else f"/enab/{settings.customer_number}/pickuprequest/{payload.confirmation_number}/details" return Job(id="get_pickup", data=Serializable(data), fallback="" if data is None else "")
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("/pickup", job.data) pipeline: Pipeline = request.serialize() response = pipeline.apply(process) return Deserializable(XP.bundle_xml(response), XP.to_xml)
def get_rates(self, request: Serializable[Envelope]) -> Deserializable[str]: product, data = request.serialize() responses = [ f'<product>{product}</product>', self._send_request( soapaction="http://www.icscourier.ca/GetEstimatedCharges", request=Serializable(data), ) ] return Deserializable(XP.bundle_xml(responses), XP.to_xml)
def get_tracking( self, request: Serializable[List[Envelope]]) -> Deserializable[str]: """ get_tracking make parallel request for each TrackRequest """ def get_tracking(track_request: str): return self._send_request("/Track", Serializable(track_request)) response: List[str] = exec_parrallel(get_tracking, request.serialize()) return Deserializable(XP.bundle_xml(xml_strings=response), XP.to_xml)
def create_shipment(self, request: Serializable) -> Deserializable[str]: def process(job: Job): if job.data is None: return job.fallback return self._send_request( request=job.data, path=dict( create="/expressconnect/shipping/ship", get_label="/expresslabel/documentation/getlabel")[job.id], ) pipeline: Pipeline = request.serialize() response = pipeline.apply(process) return Deserializable(XP.bundle_xml(response), XP.to_xml)
def create_shipment( self, request: Serializable[Envelope]) -> Deserializable[str]: response = self._send_request( soapaction="http://www.icscourier.ca/CreateShipment", request=request, ) labelURL = XP.find(XP.to_xml(response), "PackageIDAndLink", first=True) if labelURL is not None: label = http( labelURL, decoder=lambda b: base64.encodebytes(b).decode("utf-8")) responses = [f'<label>{label}</label>', response] return Deserializable(XP.bundle_xml(responses), XP.to_xml) return Deserializable(response, XP.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 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": f"{self.settings.language}-CA", }, method="GET", ) response: List[str] = exec_parrallel(track, request.serialize()) return Deserializable(XP.bundle_xml(xml_strings=response), XP.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 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": f"{self.settings.language}-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": f"{self.settings.language}-CA", }, method="POST", ) def _get_label(job: Job): label_string = http( decoder=lambda b: base64.encodebytes(b).decode("utf-8"), url=job.data["href"], headers={ "Accept": job.data["media"], "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(XP.bundle_xml(response), XP.to_xml)