def parse_error_response(response: Element, settings: Settings) -> List[Message]: notifications = ( response.xpath(".//*[local-name() = $name]", name="Notifications") + response.xpath(".//*[local-name() = $name]", name="Notification") ) return reduce( _extract_error(settings), notifications, extract_fault(response, settings) )
def parse_shipment_response( response: Element, settings: Settings ) -> Tuple[ShipmentDetails, List[Message]]: details = next( iter(response.xpath(".//*[local-name() = $name]", name="ShipmentResults")), None ) shipment = _extract_shipment(details, settings) if details is not None else None return shipment, parse_error_response(response, settings)
def parse_freight_ship_response( response: Element, settings: Settings) -> Tuple[ShipmentDetails, List[Message]]: details = response.xpath(".//*[local-name() = $name]", name="FreightShipResponse") shipment = _extract_shipment(details[0], settings) if len(details) > 0 else None return shipment, parse_error_response(response, settings)
def parse_freight_rate_response( response: Element, settings: Settings) -> Tuple[List[RateDetails], List[Message]]: rate_reply = response.xpath(".//*[local-name() = $name]", name="FreightRateResponse") rates: List[RateDetails] = [ _extract_freight_rate(detail_node, settings) for detail_node in rate_reply ] return rates, parse_error_response(response, settings)
def extract_fault(response: Element, settings: Type[Settings]) -> Message: faults = [build(Fault, node) for node in response.xpath(".//*[local-name() = $name]", name="Fault")] return [ Message( code=fault.faultcode, message=fault.faultstring, carrier_name=settings.carrier_name, carrier_id=settings.carrier_id ) for fault in faults ]
def parse_shipment_response( response: Element, settings: Settings ) -> Tuple[ShipmentDetails, List[Message]]: air_way_bill = next( iter(response.xpath(".//*[local-name() = $name]", name="AirwayBillNumber")), None, ) return ( _extract_shipment(response, settings) if air_way_bill is not None else None, parse_error_response(response, settings), )
def parse_rate_response( response: Element, settings: Settings) -> Tuple[List[RateDetails], List[Message]]: rate_reply = response.xpath(".//*[local-name() = $name]", name="RateReplyDetails") rate_details: List[RateDetails] = [ _extract_rate(detail_node, settings) for detail_node in rate_reply ] return ( [details for details in rate_details if details is not None], parse_error_response(response, settings), )
def extract_fault(response: Element, settings: Settings) -> List[Message]: faults = [ XMLPARSER.build(Fault, node) for node in response.xpath(".//*[local-name() = $name]", name="Fault") ] return [ Message( code=fault.faultcode, message=fault.faultstring, carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, ) for fault in faults ]
def parse_error_response(response: Element, settings: Settings) -> List[Message]: error_nodes: List[Error] = [ (lambda error: (error, error.build(node)))(Error())[0] for node in ( [response] if response.tag == "Error" else response.xpath(".//*[local-name() = $name]", name="Error") ) ] return [ Message( carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, code=str(error.Number), message=error.Description, ) for error in error_nodes ]
def _extract_freight_rate(detail_node: Element, settings: Settings) -> RateDetails: detail = FreightRateResponse() detail.build(detail_node) total_charge = [r for r in detail.Rate if r.Type.Code == "AFTR_DSCNT"][0] Discounts_ = [ ChargeDetails( name=r.Type.Code, currency=r.Factor.UnitOfMeasurement.Code, amount=decimal(r.Factor.Value), ) for r in detail.Rate if r.Type.Code == "DSCNT" ] Surcharges_ = [ ChargeDetails( name=r.Type.Code, currency=r.Factor.UnitOfMeasurement.Code, amount=decimal(r.Factor.Value), ) for r in detail.Rate if r.Type.Code not in ["DSCNT", "AFTR_DSCNT", "DSCNT_RATE", "LND_GROSS"] ] extra_charges = Discounts_ + Surcharges_ currency_ = next(c.text for c in detail_node.xpath(".//*[local-name() = $name]", name="CurrencyCode")) return RateDetails( carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, currency=currency_, service=detail.Service.Description, base_charge=decimal(detail.TotalShipmentCharge.MonetaryValue), total_charge=decimal(total_charge.Factor.Value or 0.0), duties_and_taxes=decimal( reduce(lambda r, c: r + c.amount, Surcharges_, 0.0)), discount=decimal(reduce(lambda r, c: r + c.amount, Discounts_, 0.0)), extra_charges=extra_charges, )
def parse_error_response(response: Element, settings: Settings) -> List[Message]: notifications = response.xpath(".//*[local-name() = $name]", name="PrimaryErrorCode") return [_extract_error(node, settings) for node in notifications]
def parse_error_response(response: Element, settings: Settings) -> List[Message]: errors = response.xpath(".//*[local-name() = $name]", name="Error") return [_extract_error(node, settings) for node in errors] + extract_fault(response, settings)
def parse_error_response(response: Element, settings: Settings) -> List[Message]: messages = response.xpath(".//*[local-name() = $name]", name="message") return reduce(_extract_error(settings), messages, [])
def extract(rates: List[RateDetails], detail_node: Element) -> List[RateDetails]: rate = RatedShipmentType() rate.build(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] arrival = PickupType() [ arrival.build(arrival) for arrival in detail_node.xpath( ".//*[local-name() = $name]", name="Arrival" ) ] currency_ = next( c.text for c in detail_node.xpath( ".//*[local-name() = $name]", name="CurrencyCode" ) ) service = ShippingServiceCode(rate.Service.Code).name return rates + [ RateDetails( carrier_name=settings.carrier_name, carrier_id=settings.carrier_id, currency=currency_, service=service, base_charge=decimal(rate.TransportationCharges.MonetaryValue), total_charge=decimal(total_charges.MonetaryValue), duties_and_taxes=reduce( lambda total, charge: total + decimal(charge.MonetaryValue), taxes or [], 0.0, ), extra_charges=reduce( lambda total, charge: ( total + [ ChargeDetails( name=charge.Code, amount=decimal(charge.MonetaryValue), currency=charge.CurrencyCode, ) ] ), [charge for charge in extra_charges if charge is not None], [], ), estimated_delivery=format_date(arrival.Date), ) ]
def parse_rate_response( response: Element, settings: Settings ) -> Tuple[List[RateDetails], List[Message]]: rate_reply = response.xpath(".//*[local-name() = $name]", name="RatedShipment") rates: List[RateDetails] = reduce(_extract_package_rate(settings), rate_reply, []) return rates, parse_error_response(response, settings)