def _extract_details(postage_node: Element, settings: Settings) -> RateDetails: postage: PostageType = XP.to_object(PostageType, postage_node) service = ServiceClassID.map(str(postage.CLASSID)) charges: List[SpecialServiceType] = getattr(postage.SpecialServices, 'SpecialService', []) rate = NF.decimal(XP.find('Rate', postage_node, first=True).text) estimated_date = DF.date( getattr(XP.find('CommitmentDate', postage_node, first=True), 'text', None)) transit = ((estimated_date.date() - datetime.now().date()).days if estimated_date is not None else None) return RateDetails( carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, service=service.name_or_key, base_charge=rate, total_charge=rate, currency=Currency.USD.name, transit_days=transit, extra_charges=[ ChargeDetails( name=charge.ServiceName, amount=NF.decimal(charge.Price), currency=Currency.USD.name, ) for charge in charges ], meta=dict(service_name=(service.name or postage.MailService)))
def parse_shipment_response(response: Element, settings: Settings) -> Tuple[ShipmentDetails, List[Message]]: package = XP.find("PackageID", response, ArrayOfString, first=True) label = XP.find("label", response, first=True) details = ( _extract_details((package.string[0], str(label.text)), settings) if getattr(package, 'string', [None])[0] is not None else None ) return details, parse_error_response(response, settings)
def extract(rates: List[RateDetails], detail_node: Element) -> List[RateDetails]: rate = XP.to_object(RatedShipmentType, detail_node) if rate.NegotiatedRateCharges is not None: total_charges = (rate.NegotiatedRateCharges.TotalChargesWithTaxes or rate.NegotiatedRateCharges.TotalCharge) taxes = rate.NegotiatedRateCharges.TaxCharges itemized_charges = rate.NegotiatedRateCharges.ItemizedCharges + taxes else: total_charges = rate.TotalChargesWithTaxes or rate.TotalCharges taxes = rate.TaxCharges itemized_charges = rate.ItemizedCharges + taxes extra_charges = itemized_charges + [rate.ServiceOptionsCharges] estimated_arrival = (XP.find( "EstimatedArrival", detail_node, EstimatedArrivalType, first=True) or EstimatedArrivalType()) transit_days = (rate.GuaranteedDelivery.BusinessDaysInTransit if rate.GuaranteedDelivery is not None else estimated_arrival.BusinessDaysInTransit) currency = XP.find("CurrencyCode", detail_node, first=True).text service = ServiceCode.map(rate.Service.Code) return rates + [ RateDetails( carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, currency=currency, service=service.name_or_key, base_charge=NF.decimal( rate.TransportationCharges.MonetaryValue), total_charge=NF.decimal(total_charges.MonetaryValue), duties_and_taxes=reduce( lambda total, charge: total + NF.decimal(charge. MonetaryValue), taxes or [], 0.0, ), extra_charges=reduce( lambda total, charge: (total + [ ChargeDetails( name=charge.Code, amount=NF.decimal(charge.MonetaryValue), currency=charge.CurrencyCode, ) ]), [ charge for charge in extra_charges if charge is not None and charge.Code is not None ], [], ), transit_days=NF.integer(transit_days), meta=dict(service_name=service.name_or_key)) ]
def parse_tracking_response( response: Element, settings: Settings ) -> Tuple[List[TrackingDetails], List[Message]]: details = XP.find("tracking-detail", response) tracking_details: List[TrackingDetails] = [ _extract_tracking(node, settings) for node in details if len(XP.find("occurrence", node)) > 0 ] return tracking_details, parse_error_response(response, settings)
def _extract_structure_error(node: Element, settings: Settings) -> Message: return Message( # context info carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, # carrier error info code=XP.find("Code", node, first=True).text, message=XP.find("Message", node, first=True).text, )
def _extract_shipment(response: Element, settings: Settings) -> ShipmentDetails: info = XP.find("shipment-info", response, ShipmentInfoType, first=True) label = XP.find("label", response, first=True) return ShipmentDetails( carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, tracking_number=info.tracking_pin, shipment_identifier=info.tracking_pin, label=getattr(label, "text", None), )
def _extract_shipment(response: Element, settings: Settings) -> ShipmentDetails: pin: PIN = XP.find("ShipmentPIN", response, PIN, first=True) document = XP.find("DocumentDetail", response, DocumentDetail, first=True) or DocumentDetail() return ShipmentDetails( carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, tracking_number=pin.Value, shipment_identifier=pin.Value, label=document.Data, )
def parse_error_response(response: Element, settings: Settings) -> List[Message]: errors = XP.find("Error", response, ErrorType) carrier_errors = XP.find("CarrierErrorMessage", response, CarrierErrorMessageType) return [ *[_extract_error(er, settings) for er in errors if er.Message != ""], *[ _extract_carrier_error(er, settings) for er in carrier_errors if er.errorMessage0 != "" ] ]
def parse_rate_response( response: Element, settings: Settings) -> Tuple[List[RateDetails], List[Message]]: estimate = XP.find("GetEstimatedChargesResult", response, ResponseGetCharges, first=True) product = XP.find("product", response, first=True) details: List[RateDetails] = [ _extract_rate_details((product, estimate), settings) ] return details, parse_error_response(response, settings)
def parse_error_response(response, settings: Settings) -> List[Message]: structure_errors = XP.find("ErrorStructure", response) broken_rules_nodes = XP.find("brokenRules", response) broken_rule_nodes = XP.find("brokenRule", response) runtime_errors = XP.find("runtime_error", response) parse_errors = XP.find("parse_error", response) ERRORS = XP.find("ERROR", response) errors = XP.find("Error", response) faults = XP.find("fault", response) return [ *[ _extract_structure_error(node, settings) for node in structure_errors ], *[ _extract_broken_rules(node, settings) for node in broken_rules_nodes ], *[_extract_broken_rule(node, settings) for node in broken_rule_nodes], *[_extract_runtime_error(node, settings) for node in runtime_errors], *[_extract_parse_error(node, settings) for node in parse_errors], *[_extract_structure_error(node, settings) for node in errors], *[_extract_error(node, settings) for node in ERRORS], *[_extract_faut(node, settings) for node in faults], ]
def parse_rate_response( response: Element, settings: Settings) -> Tuple[List[RateDetails], List[Message]]: rate_reply = XP.find("RatedShipment", response) rates: List[RateDetails] = reduce(_extract_package_rate(settings), rate_reply, []) return rates, parse_error_response(response, settings)
def _extract_pickup_details(response: Element, settings: Settings) -> PickupDetails: pickup = XP.find( "PickupCreationResponse", response, PickupCreationResponse, first=True ) rate = XP.find("RateResult", response, RateResultType, first=True) return PickupDetails( carrier_id=settings.carrier_id, carrier_name=settings.carrier_name, confirmation_number=pickup.PRN, pickup_charge=ChargeDetails( name=rate.RateType, currency=rate.CurrencyCode, amount=NF.decimal(rate.GrandTotalOfAllCharge), ), )
def parse_shipment_response( response: Element, settings: Settings) -> Tuple[ShipmentDetails, List[Message]]: details = XP.find("ShipmentResults", response, first=True) shipment = _extract_shipment(details, settings) if details is not None else None return shipment, parse_error_response(response, settings)
def parse_rate_response( response: Element, settings: Settings ) -> Tuple[List[RateDetails], List[Message]]: replys = XP.find("RateReplyDetails", response) rates: List[RateDetails] = [ _extract_rate(detail_node, settings) for detail_node in replys ] return rates, parse_error_response(response, settings)
def parse_shipment_response( response: Element, settings: Settings ) -> Tuple[ShipmentDetails, List[Message]]: detail = XP.find("CompletedShipmentDetail", response, first=True) shipment = ( _extract_shipment(detail, settings) if detail is not None else None ) return shipment, parse_error_response(response, settings)
def parse_shipment_response( response: Element, settings: Settings) -> Tuple[ShipmentDetails, List[Message]]: pin = XP.find("ShipmentPIN", response, PIN, first=True) shipment = (_extract_shipment(response, settings) if (getattr(pin, 'Value', None) is not None) else None) return shipment, parse_error_response(response, settings)
def parse_rate_response( response: Element, settings: Settings ) -> Tuple[List[RateDetails], List[Message]]: price_quotes = XP.find("price-quote", response) quotes: List[RateDetails] = [ _extract_quote(price_quote_node, settings) for price_quote_node in price_quotes ] return quotes, parse_error_response(response, settings)
def parse_rate_response( response: Element, settings: Settings) -> Tuple[List[RateDetails], List[Message]]: rate_replys = XP.find("Rate", response, RateType) rates: List[RateDetails] = [ _extract_package_rate(rate, settings) for rate in rate_replys ] return rates, parse_error_response(response, settings)
def parse_rate_response( response: Element, settings: Settings) -> Tuple[List[RateDetails], List[Message]]: shipment_nodes = XP.find("shipment", response) rates: List[RateDetails] = [ _extract_rate_details(node, settings) for node in shipment_nodes ] return rates, parse_error_response(response, settings)
def parse_rate_response( response: Element, settings: Settings) -> Tuple[List[RateDetails], List[Message]]: rates: List[RateDetails] = [ _extract_details(package, settings) for package in XP.find("Postage", response) ] return rates, parse_error_response(response, settings)
def parse_shipping_reply( response: Element, settings: Settings) -> Tuple[ShipmentDetails, List[Message]]: shipping_node = XP.find("ShippingReply", response, first=True) shipment = (_extract_shipment(shipping_node, settings) if shipping_node is not None else None) return shipment, parse_error_response(response, settings)
def parse_rate_response( response: Element, settings: Settings) -> Tuple[List[RateDetails], List[Message]]: estimates = XP.find("ShipmentEstimate", response) return ( [_extract_rate(node, settings) for node in estimates], parse_error_response(response, settings), )
def parse_shipment_response( response: Element, settings: Settings ) -> Tuple[ShipmentDetails, List[Message]]: shipment = ( _extract_shipment(response, settings) if len(XP.find("shipment-id", response)) > 0 else None ) return shipment, parse_error_response(response, settings)
def parse_shipment_response( response: Element, settings: Settings) -> Tuple[ShipmentDetails, List[Message]]: air_way_bill = XP.find("AirwayBillNumber", response, first=True) return ( _extract_shipment(response, settings) if air_way_bill is not None else None, parse_error_response(response, settings), )
def _get_shipment_label(create_response: str, payload: ShipmentRequest, settings: Settings) -> Job: response = XP.to_xml(create_response) valid = len(parse_error_response(response, settings)) == 0 shipment_pin = (getattr(XP.find("ShipmentPIN", response, PIN, first=True), 'Value', None) if valid else None) data = (get_shipping_documents_request(shipment_pin, payload, settings) if valid else None) return Job(id="document", data=data, fallback="")
def _extract_tracking(detail_node: Element, settings: Settings) -> TrackingDetails: pin = XP.find("pin", detail_node, first=True) events: List[occurrenceType] = XP.find("occurrence", detail_node, occurrenceType) return TrackingDetails( carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, tracking_number=pin.text, events=[ TrackingEvent( date=DF.fdate(event.event_date, "%Y-%m-%d"), time=DF.ftime(event.event_time, "%H:%M:%S"), code=event.event_identifier, location=SF.concat_str(event.event_site, event.event_province, join=True, separator=', '), description=event.event_description ) for event in events ], delivered=any(e.event_identifier in TRACKING_DELIVERED_EVENT_CODES for e in events) )
def parse_rate_response( response: Element, settings: Settings) -> Tuple[List[RateDetails], List[Message]]: quotes = XP.find("QtdShp", response, ResponseQtdShpType) rates: List[RateDetails] = [ _extract_quote(quote, settings) for quote in quotes if (quote.ShippingCharge is not None) or ( quote.ShippingCharge is not None) ] return rates, parse_error_response(response, settings)
def parse_pickup_response( response: Element, settings: Settings) -> Tuple[PickupDetails, List[Message]]: reply = XP.find("FreightPickupResponse", response, FreightPickupResponse, first=True) 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_response( response: Element, settings: Settings) -> Tuple[PickupDetails, List[Message]]: reply = XP.find("SchedulePickUpResponse", response, SchedulePickUpResponse, first=True) 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 _extract_shipment(shipment_node, settings: Settings) -> Optional[ShipmentDetails]: tracking_number = XP.find("AirwayBillNumber", shipment_node, first=True).text label_image = XP.find("LabelImage", shipment_node, LabelImage, first=True) multilabels: List[MultiLabelType] = XP.find("MultiLabel", shipment_node, MultiLabelType) invoice = next( (item for item in multilabels if item.DocName == "CustomInvoiceImage"), None) label = encodebytes(label_image.OutputImage).decode("utf-8") meta = (dict( custom_invoice=encodebytes(invoice.DocImageVal).decode("utf-8")) if invoice is not None else None) return ShipmentDetails(carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, tracking_number=tracking_number, shipment_identifier=tracking_number, label=label, meta=meta)