Beispiel #1
0
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)))
Beispiel #2
0
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)
Beispiel #3
0
    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))
        ]
Beispiel #4
0
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)
Beispiel #5
0
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,
    )
Beispiel #6
0
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),
    )
Beispiel #7
0
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,
    )
Beispiel #8
0
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 != ""
        ]
    ]
Beispiel #9
0
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)
Beispiel #10
0
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],
    ]
Beispiel #11
0
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)
Beispiel #12
0
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),
        ),
    )
Beispiel #13
0
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)
Beispiel #14
0
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)
Beispiel #15
0
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)
Beispiel #16
0
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)
Beispiel #17
0
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)
Beispiel #18
0
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)
Beispiel #19
0
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)
Beispiel #20
0
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)
Beispiel #21
0
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)
Beispiel #22
0
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),
    )
Beispiel #23
0
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),
    )
Beispiel #25
0
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="")
Beispiel #26
0
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)
    )
Beispiel #27
0
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)
Beispiel #28
0
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)
Beispiel #29
0
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)