def _extract_error(node: Element, settings: Settings) -> Message: error = XP.build(ERROR, node) return Message( # context info carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, # carrier error info code=error.CODE, message=error.DESCRIPTION, )
def parse_shipment_response( response: Element, settings: Settings) -> Tuple[ShipmentDetails, List[Message]]: shipment = XP.build( Shipment, next( iter(response.xpath(".//*[local-name() = $name]", name="shipment")), None)) success = (shipment is not None and shipment.id is not None) shipment_details = _extract_details(response, settings) if success else None return shipment_details, parse_error_response(response, settings)
def parse_tracking_response( response, settings: Settings) -> Tuple[List[TrackingDetails], List[Message]]: non_existents = next((XP.build(ArrayOfstring, n) for n in response.xpath(".//*[local-name() = $name]", name="NonExistingWaybills")), ArrayOfstring()) results = response.xpath(".//*[local-name() = $name]", name="TrackingResult") tracking_details = [_extract_detail(node, settings) for node in results] errors = _extract_errors(non_existents, settings) + parse_error_response( response, settings) return tracking_details, errors
def parse_error_response(response: Element, settings: Settings) -> List[Message]: error_nodes = ([response] if response.tag == 'Error' else response.xpath( ".//*[local-name() = $name]", name="Error")) errors = [XP.build(Error, node) for node in error_nodes] return [ Message( carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, code=str(error.Number), message=error.Description, ) for error in errors ]
def _get_label(shipment_response: str, settings: Settings) -> Job: response = XP.to_xml(shipment_response) shipment = XP.build( Shipment, next( iter(response.xpath(".//*[local-name() = $name]", name="shipment")), None)) success = (shipment is not None and shipment.id is not None) data = (get_label_request(LabelRequest( shipment_id=shipment.id), settings) if success else None) return Job(id="get_label", data=data, fallback=("" if not success else None))
def parse_address_validation_response( response: Element, settings: Settings) -> Tuple[AddressValidationDetails, List[Message]]: notes = response.xpath(".//*[local-name() = $name]", name="Note") success = next( (True for note in notes if XP.build(Note, note).ActionNote == "Success"), False) validation_details = AddressValidationDetails( carrier_id=settings.carrier_id, carrier_name=settings.carrier_name, success=success) return validation_details, parse_error_response(response, settings)
def _refund_if_submitted(shipment_details: str): shipment = XP.build(ShipmentInfoType, XP.to_xml(shipment_details)) transmitted = shipment.shipment_status == 'transmitted' data = dict( id=payload.shipment_identifier, payload=Serializable( ShipmentRefundRequestType( email=payload.options.get('email')), lambda request: XP. export(request, name_='shipment-refund-request', namespacedef_= 'xmlns="http://www.canadapost.ca/ws/shipment-v8"')) ) if transmitted else None return Job(id="refund", data=data, fallback=shipment_details)
def parse_shipment_cancel_response( response: Element, settings: Settings) -> Tuple[ConfirmationDetails, List[Message]]: errors: List[Message] = parse_error_response(response, settings) if response.tag == 'eVSCancelResponse': cancel_response = XP.build(eVSCancelResponse, response) else: cancel_response = XP.build(eVSICancelResponse, response) if cancel_response.Status != "Cancelled": errors.append( Message(carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, message=cancel_response.Reason, code=cancel_response.Status)) details = (ConfirmationDetails( carrier_id=settings.carrier_id, carrier_name=settings.carrier_name, operation="Shipment Cancel", success=True, ) if not any(errors) else None) return details, errors
def parse_pickup_response( response: Element, settings: Settings) -> Tuple[PickupDetails, List[Message]]: reply = XP.build( CreatePickupReply, next( iter( response.xpath(".//*[local-name() = $name]", name="CreatePickupReply")), None, ), ) pickup = (_extract_pickup_details(reply, settings) if reply.HighestSeverity == NotificationSeverityType.SUCCESS.value else None) return pickup, parse_error_response(response, settings)
def parse_pickup_response( response: Element, settings: Settings) -> Tuple[PickupDetails, List[Message]]: pickup_node = next( iter(response.xpath(".//*[local-name() = $name]", name="pickup")), None) pickup = XP.build(PickupV2, pickup_node) details: PickupDetails = PickupDetails(carrier_id=settings.carrier_id, carrier_name=settings.carrier_name, confirmation_number=str(pickup.id), pickup_date=DF.fdatetime( pickup.pickup_date, '%Y-%m-%dT%H:%M:%S')) return details, parse_error_response(response, settings)
def _cancel_pickup_request(response: str, payload: PickupUpdateRequest, settings: Settings): reply = next( iter( XP.to_xml(response).xpath(".//*[local-name() = $name]", name="CreatePickupReply")), None, ) new_pickup = XP.build(CreatePickupReply, reply) data = (pickup_cancel_request( PickupCancelRequest(confirmation_number=payload.confirmation_number), settings, ) if new_pickup is not None and new_pickup.HighestSeverity == NotificationSeverityType.SUCCESS.value else None) return Job(id="cancel_pickup", data=data, fallback="")
def _extract_detail(node: Element, settings: Settings) -> TrackingDetails: detail = XP.build(TrackingResult, node) return TrackingDetails( carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, tracking_number=detail.WaybillNumber, events=[ TrackingEvent( date=DF.date(detail.UpdateDateTime, '%Y-%m-%dT%H:%M:%S'), description=detail.UpdateDescription, location=detail.UpdateLocation, code=detail.UpdateCode, time=DF.ftime(detail.UpdateDateTime, '%Y-%m-%dT%H:%M:%S'), ) ], )
def parse_rate_response( response: Element, settings: Settings) -> Tuple[List[RateDetails], List[Message]]: price_node = next( response.xpath(".//*[local-name() = $name]", name="priceResponse"), None) price_response = XP.build(priceResponse, price_node) if price_response is not None and price_response.ratedServices is not None: rate_details = [ _extract_detail((price_response.ratedServices, service), settings) for service in price_response.ratedServices.ratedService ] else: rate_details = [] return rate_details, parse_error_response(response, settings)
def _extract_details(response: Element, settings: Settings) -> ShipmentDetails: shipment_node = next( iter(response.xpath(".//*[local-name() = $name]", name="shipment")), None) label = next( iter(response.xpath(".//*[local-name() = $name]", name="labels")), None) shipment = XP.build(Shipment, shipment_node) tracking_number = next(iter(shipment.packages), Package()).barcode return ShipmentDetails( carrier_id=settings.carrier_id, carrier_name=settings.carrier_name, label=str(label.text), tracking_number=tracking_number, shipment_identifier=str(shipment.id), selected_rate=_extract_rate_details(shipment_node, settings), )
def parse_shipment_cancel_response( response: Element, settings: Settings) -> Tuple[ConfirmationDetails, List[Message]]: void_response = XP.build( VoidShipmentResponse, next( iter( response.xpath(".//*[local-name() = $name]", name="VoidShipmentResponse")), None)) voided = void_response is not None and void_response.ShipmentVoided cancellation = ConfirmationDetails( carrier_id=settings.carrier_id, carrier_name=settings.carrier_name, success=True, operation="Cancel Shipment", ) if voided else None return cancellation, parse_error_response(response, settings)
def parse_address_validation_response( response: Element, settings: Settings) -> Tuple[AddressValidationDetails, List[Message]]: status = XP.build( Response, next( iter(response.xpath(".//*[local-name() = $name]", name="Response")), None, ), ) success = status is not None and status.ResponseStatusCode == "1" validation_details = AddressValidationDetails( carrier_id=settings.carrier_id, carrier_name=settings.carrier_name, success=success) if success else None return validation_details, parse_error_response(response, settings)
def _extract_detail(node: Element, settings: Settings) -> TrackingDetails: detail = XP.build(ConsignmentType, node) return TrackingDetails( carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, tracking_number=detail.ConsignmentNumber, events=[ TrackingEvent( date=DF.fdate(status.LocalEventDate.valueOf_, '%Y%m%d'), description=status.StatusDescription, location=SF.concat_str(status.Depot, status.DepotName, join=True, separator='-'), code=status.StatusCode, time=DF.ftime(status.LocalEventTime.valueOf_, '%H%M') ) for status in cast(List[StatusStructure], detail.StatusData) ], delivered=(detail.SummaryCode == "DEL") )
def _extract_shipment(node: Element, settings: Settings) -> ShipmentDetails: shipping = XP.build(ShippingReplyType, node) quote: QuoteType = shipping.Quote tracking_number = getattr(next(iter(shipping.Package), None), 'trackingNumber', None) rate_provider, service, service_name = Service.info( quote.serviceId, quote.carrierId, quote.serviceName, quote.carrierName) surcharges = [ ChargeDetails( name=charge.name, currency=quote.currency, amount=NF.decimal(charge.amount), ) for charge in cast(List[SurchargeType], quote.Surcharge) ] fuel_surcharge = (ChargeDetails( name="Fuel surcharge", currency=quote.currency, amount=NF.decimal(quote.fuelSurcharge), ) if quote.fuelSurcharge is not None else None) return ShipmentDetails( carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, tracking_number=tracking_number, shipment_identifier=shipping.Order.id, label=shipping.Labels, selected_rate=(RateDetails( carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, service=service, currency=quote.currency, base_charge=NF.decimal(quote.baseCharge), total_charge=NF.decimal(quote.totalCharge), transit_days=quote.transitDays, extra_charges=([fuel_surcharge] + surcharges), meta=dict(rate_provider=rate_provider, service_name=service_name)) if quote is not None else None), meta=dict(rate_provider=rate_provider, service_name=service_name, tracking_url=shipping.TrackingURL))
def parse_pickup_cancel_response( response: Element, settings: Settings) -> Tuple[ConfirmationDetails, List[Message]]: status = XP.build( CodeDescriptionType, next( iter( response.xpath(".//*[local-name() = $name]", name="ResponseStatus")), None, ), ) success = status is not None and status.Code == "1" cancellation = (ConfirmationDetails( carrier_id=settings.carrier_id, carrier_name=settings.carrier_name, success=success, operation="Cancel Pickup", ) if success else None) return cancellation, parse_error_response(response, settings)
def parse_pickup_response( response: Element, settings: Settings ) -> Tuple[PickupDetails, List[Message]]: reply = XP.build( PickupCreationResponse, next( iter( response.xpath( ".//*[local-name() = $name]", name="PickupCreationResponse" ) ), None, ), ) pickup = ( _extract_pickup_details(response, settings) if reply is not None and reply.PRN is not None else None ) return pickup, parse_error_response(response, settings)
def parse_pickup_update_response( response: Element, settings: Settings ) -> Tuple[PickupDetails, List[Message]]: reply = XP.build( ModifyPickUpResponse, next( iter( response.xpath( ".//*[local-name() = $name]", name="ModifyPickUpResponse" ) ), None, ), ) pickup = ( _extract_pickup_details(reply, settings) if reply is not None and reply.PickUpConfirmationNumber is not None else None ) return pickup, parse_error_response(response, settings)
def parse_pickup_cancel_response( response: Element, settings: Settings) -> Tuple[ConfirmationDetails, List[Message]]: reply = XP.build( CancelPickupReply, next( iter( response.xpath(".//*[local-name() = $name]", name="CancelPickupReply")), None, ), ) cancellation = ConfirmationDetails( carrier_id=settings.carrier_id, carrier_name=settings.carrier_name, success=reply.HighestSeverity == NotificationSeverityType.SUCCESS.value, operation="Cancel Pickup", ) return cancellation, parse_error_response(response, settings)
def _extract_tracking_details(node: Element, settings: Settings) -> TrackingDetails: result = XP.build(TrackingResult, node) is_en = settings.language == "en" events = [ TrackingEvent( date=DF.fdate(event.local_date_time, '%Y%m%d %H%M%S'), description=(event.code_description_en if is_en else event.code_description_fr), location=_format_location(event.address), code=event.code, time=DF.ftime(event.local_date_time, '%Y%m%d %H%M%S'), ) for event in cast(List[CanparTrackingEvent], result.events) ] return TrackingDetails(carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, tracking_number=result.barcode, events=events, delivered=any(event.code == 'DEL' for event in events))
def _cancel_pickup_request( response: str, payload: PickupUpdateRequest, settings: Settings ): reply = next( iter( XP.to_xml(response).xpath( ".//*[local-name() = $name]", name="PickupCreationResponse" ) ), None, ) new_pickup = XP.build(PickupCreationResponse, reply) data = ( pickup_cancel_request( PickupCancelRequest(confirmation_number=payload.confirmation_number), settings, ) if new_pickup is not None and new_pickup.PRN is not None else None ) return Job(id="cancel_pickup", data=data, fallback="")
def _extract_details(response: Element, settings: Settings) -> ShipmentDetails: shipment = XP.build(eVSPriorityMailIntlResponse, response) charges: List[ExtraServiceType] = shipment.ExtraServices.ExtraService return ShipmentDetails(carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, label=shipment.LabelImage, tracking_number=shipment.BarcodeNumber, shipment_identifier=shipment.BarcodeNumber, selected_rate=RateDetails( carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, currency=Currency.USD.value, total_charge=NF.decimal(shipment.TotalValue), base_charge=NF.decimal(shipment.Postage), extra_charges=[ ChargeDetails(name=charge.ServiceName, amount=NF.decimal( charge.Price), currency=Currency.USD.value) for charge in charges ]))
def _extract_rate(node: Element, settings: Settings) -> RateDetails: quote = XP.build(QuoteType, node) rate_provider, service, service_name = Service.info( quote.serviceId, quote.carrierId, quote.serviceName, quote.carrierName ) surcharges = [ ChargeDetails( name=charge.name, amount=NF.decimal(charge.amount), currency=quote.currency ) for charge in cast(List[SurchargeType], quote.Surcharge) ] fuel_surcharge = ( ChargeDetails( name="Fuel surcharge", amount=NF.decimal(quote.fuelSurcharge), currency=quote.currency, ) if quote.fuelSurcharge is not None else None ) return RateDetails( carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, currency=quote.currency, service=service, base_charge=NF.decimal(quote.baseCharge), total_charge=NF.decimal(quote.totalCharge), transit_days=quote.transitDays, extra_charges=([fuel_surcharge] + surcharges), meta=dict( rate_provider=rate_provider, service_name=service_name ) )
def _create_pickup(rate_response: str, payload: PickupRequest, settings: Settings): rate_result = XP.build(RateResultType, XP.to_xml(rate_response)) data = _create_pickup_request(payload, settings) if rate_result else None return Job(id="create_pickup", data=data, fallback="")