コード例 #1
0
ファイル: create.py プロジェクト: iliaaz/purplship
def _extract_pickup_details(response: Element,
                            settings: Settings) -> PickupDetails:
    header = next((XP.build(PickupRequestHeaderType, elt)
                   for elt in response.xpath(".//*[local-name() = $name]",
                                             name="pickup-request-header")))
    price = next((XP.build(PickupRequestPriceType, elt)
                  for elt in response.xpath(".//*[local-name() = $name]",
                                            name="pickup-request-price")),
                 None)

    price_amount = sum(
        [
            NF.decimal(price.hst_amount or 0.0),
            NF.decimal(price.gst_amount or 0.0),
            NF.decimal(price.due_amount or 0.0),
        ],
        0.0,
    ) if price is not None else None

    return PickupDetails(
        carrier_id=settings.carrier_id,
        carrier_name=settings.carrier_name,
        confirmation_number=header.request_id,
        pickup_date=DF.fdate(header.next_pickup_date),
        pickup_charge=ChargeDetails(name="Pickup fees",
                                    amount=NF.decimal(price_amount),
                                    currency="CAD")
        if price is not None else None,
    )
コード例 #2
0
def _extract_shipment(response: Element,
                      settings: Settings) -> ShipmentDetails:
    shipment = CreateShipmentResponse()
    document = DocumentDetail()
    shipment_nodes = response.xpath(".//*[local-name() = $name]",
                                    name="CreateShipmentResponse")
    document_nodes = response.xpath(".//*[local-name() = $name]",
                                    name="DocumentDetail")

    next((shipment.build(node) for node in shipment_nodes), None)
    next((document.build(node) for node in document_nodes), None)

    label = next(
        (content
         for content in [document.Data, document.URL] if content is not None),
        "No label returned",
    )
    pin = cast(PIN, shipment.ShipmentPIN).Value

    return ShipmentDetails(
        carrier_name=settings.carrier_name,
        carrier_id=settings.carrier_id,
        tracking_number=pin,
        shipment_identifier=pin,
        label=label,
    )
コード例 #3
0
def _extract_details(postage_node: Element, settings: Settings) -> RateDetails:
    postage: PostageType = PostageType()
    postage.build(postage_node)
    currency = Currency.USD.name
    services: List[SpecialServiceType] = [
        XP.build(SpecialServiceType, svc)
        for svc in postage_node.xpath(".//*[local-name() = $name]",
                                      name="SpecialService")
    ]
    estimated_date = DF.date(postage.CommitmentDate)
    transit = ((estimated_date -
                datetime.now()).days if estimated_date is not None else None)
    postage_rate = postage_node.find("Rate").text

    def get(key: str) -> Any:
        return reduce(lambda r, v: v.text, postage_node.findall(key), None)

    return RateDetails(
        carrier_name=settings.carrier_name,
        carrier_id=settings.carrier_id,
        service=Service.find(get("MailService")).name,
        total_charge=NF.decimal(postage_rate),
        currency=currency,
        transit_days=transit,
        extra_charges=[
            ChargeDetails(
                name=SpecialService(str(svc.ServiceID)).name,
                amount=NF.decimal(svc.Price),
                currency=currency,
            ) for svc in services
        ],
    )
コード例 #4
0
ファイル: error.py プロジェクト: iliaaz/purplship
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")
    errors = [_extract_error(node, settings)
              for node in notifications] + extract_fault(response, settings)
    return [error for error in errors if error is not None]
コード例 #5
0
ファイル: rate.py プロジェクト: iliaaz/purplship
    def extract(rates: List[RateDetails],
                detail_node: Element) -> List[RateDetails]:
        rate = XP.build(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 = next(
            (XP.build(EstimatedArrivalType, n)
             for n in detail_node.xpath(".//*[local-name() = $name]",
                                        name="EstimatedArrival")),
            EstimatedArrivalType(),
        )
        transit_days = (rate.GuaranteedDelivery.BusinessDaysInTransit
                        if rate.GuaranteedDelivery is not None else
                        estimated_arrival.BusinessDaysInTransit)
        currency_ = next(
            str(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=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],
                    [],
                ),
                transit_days=NF.integer(transit_days),
            )
        ]
コード例 #6
0
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.to_object(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),
    )
コード例 #7
0
def _extract_shipment(response: Element, settings: Settings) -> ShipmentDetails:
    info_node = next(
        iter(response.xpath(".//*[local-name() = $name]", name="shipment-info"))
    )
    label = next(iter(response.xpath(".//*[local-name() = $name]", name="label")))
    errors = parse_error_response(label, settings)
    info: ShipmentInfoType = ShipmentInfoType()
    info.build(info_node)

    return ShipmentDetails(
        carrier_name=settings.carrier_name,
        carrier_id=settings.carrier_id,
        tracking_number=info.tracking_pin,
        label=label.text if len(errors) == 0 else None,
    )
コード例 #8
0
ファイル: track.py プロジェクト: gitter-badger/purplship
def _extract_tracking(shipment_node: Element,
                      settings: Settings) -> TrackingDetails:
    track_detail = ShipmentType()
    track_detail.build(shipment_node)
    activity_nodes = shipment_node.xpath(".//*[local-name() = $name]",
                                         name="Activity")

    def build_activity(node) -> ActivityType:
        activity = ActivityType()
        activity.build(node)
        return activity

    activities: List[ActivityType] = list(map(build_activity, activity_nodes))
    return TrackingDetails(
        carrier_name=settings.carrier_name,
        carrier_id=settings.carrier_id,
        tracking_number=track_detail.InquiryNumber.Value,
        events=list(
            map(
                lambda a: TrackingEvent(
                    date=format_date(a.Date, "%Y%m%d"),
                    time=format_time(a.Time, "%H%M%S"),
                    code=a.Status.Code if a.Status else None,
                    location=(a.ActivityLocation.Address.City
                              if a.ActivityLocation and a.ActivityLocation.
                              Address else None),
                    description=a.Status.Description if a.Status else None,
                ),
                activities,
            )),
    )
コード例 #9
0
def parse_address_validation_response(
        response: Element,
        settings: Settings) -> Tuple[AddressValidationDetails, List[Message]]:
    errors = parse_error_response(response, settings)
    reply = XP.to_object(
        ValidateCityPostalCodeZipResponse,
        next(
            iter(
                response.xpath(".//*[local-name() = $name]",
                               name="ValidateCityPostalCodeZipResponse")),
            None))
    address: ShortAddress = next(
        (result.Address
         for result in reply.SuggestedAddresses.SuggestedAddress), None)
    success = len(errors) == 0
    validation_details = AddressValidationDetails(
        carrier_id=settings.carrier_id,
        carrier_name=settings.carrier_name,
        success=success,
        complete_address=Address(city=address.City,
                                 state_code=address.Province,
                                 country_code=address.Country,
                                 postal_code=address.PostalCode)
        if address is not None else None) if success else None

    return validation_details, errors
コード例 #10
0
def _extract_tracking(tracking_node: Element, settings) -> TrackingDetails:
    tracking: TrackInfoType = TrackInfoType()
    tracking.build(tracking_node)
    track_detail_nodes = tracking_node.xpath(".//*[local-name() = $name]",
                                             name="TrackDetail")
    details: List[TrackDetailType] = [
        (lambda t: (t, t.build(detail)))(TrackDetailType())[0]
        for detail in track_detail_nodes
    ]
    return TrackingDetails(
        carrier_name=settings.carrier_name,
        carrier_id=settings.carrier_id,
        tracking_number=tracking.TrackInfoID,
        events=[
            TrackingEvent(
                code=str(event.EventCode),
                date=format_date(event.EventDate, "%B %d, %Y"),
                time=format_time(event.EventTime, "%H:%M %p"),
                description=event.ActionCode,
                location=", ".join([
                    location for location in [
                        event.EventCity,
                        event.EventState,
                        event.EventCountry,
                        str(event.EventZIPCode),
                    ] if location is not None
                ]),
            ) for event in details
        ],
    )
コード例 #11
0
ファイル: address.py プロジェクト: iliaaz/purplship
def parse_address_validation_response(
        response: Element,
        settings: Settings) -> Tuple[AddressValidationDetails, List[Message]]:
    reply = XP.build(
        AddressValidationReply,
        next(
            iter(
                response.xpath(".//*[local-name() = $name]",
                               name="AddressValidationReply")), None))
    address: FedexAddress = next(
        (result.EffectiveAddress for result in reply.AddressResults), None)
    success = reply.HighestSeverity == NotificationSeverityType.SUCCESS.value
    _, lines = (address.StreetLines if address is not None
                and len(address.StreetLines) > 1 else ["", ""])
    validation_details = AddressValidationDetails(
        carrier_id=settings.carrier_id,
        carrier_name=settings.carrier_name,
        success=success,
        complete_address=Address(city=address.City,
                                 state_code=address.StateOrProvinceCode,
                                 country_code=address.CountryCode,
                                 residential=address.Residential,
                                 address_line1=next(iter(address.StreetLines),
                                                    None),
                                 address_line2=SF.concat_str(lines, join=True))
        if address is not None else None) if success else None

    return validation_details, parse_error_response(response, settings)
コード例 #12
0
ファイル: tracking.py プロジェクト: derekcao0226/purplship
def _extract_details(shipment_node: Element,
                     settings: Settings) -> TrackingDetails:
    track_detail = XP.build(ShipmentType, shipment_node)
    activities = [
        XP.build(ActivityType, node)
        for node in shipment_node.xpath(".//*[local-name() = $name]",
                                        name="Activity")
    ]
    delivered = any(a.Status.Type == 'D' for a in activities)

    return TrackingDetails(
        carrier_name=settings.carrier_name,
        carrier_id=settings.carrier_id,
        tracking_number=track_detail.InquiryNumber.Value,
        events=list(
            map(
                lambda a: TrackingEvent(
                    date=DF.fdate(a.Date, "%Y%m%d"),
                    description=a.Status.Description if a.Status else None,
                    location=(_format_location(a.ActivityLocation.Address)
                              if a.ActivityLocation is not None and a.
                              ActivityLocation.Address is not None else None),
                    time=DF.ftime(a.Time, "%H%M%S"),
                    code=a.Status.Code if a.Status else None,
                ),
                activities,
            )),
        delivered=delivered)
コード例 #13
0
def parse_address_validation_response(
        response: Element,
        settings: Settings) -> Tuple[AddressValidationDetails, List[Message]]:
    errors = parse_error_response(response, settings)
    address_node = next(
        iter(response.xpath(".//*[local-name() = $name]", name="address")),
        None)
    address = XP.to_object(CanparAddress, address_node)
    success = len(errors) == 0
    validation_details = AddressValidationDetails(
        carrier_id=settings.carrier_id,
        carrier_name=settings.carrier_name,
        success=success,
        complete_address=Address(postal_code=address.postal_code,
                                 city=address.city,
                                 company_name=address.name,
                                 country_code=address.country,
                                 email=address.email,
                                 state_code=address.province,
                                 residential=address.residential,
                                 address_line1=address.address_line_1,
                                 address_line2=SF.concat_str(
                                     address.address_line_2,
                                     address.address_line_3,
                                     join=True))) if success else None

    return validation_details, errors
コード例 #14
0
def _extract_intl_rates(service_node: Element,
                        settings: Settings) -> RateDetails:
    service: ServiceType = ServiceType()
    service.build(service_node)
    currency = "USD"
    special_services: List[ExtraServiceType] = [
        (lambda s: (s, s.build(svc)))(ExtraServiceType())[0]
        for svc in service_node.xpath(".//*[local-name() = $name]",
                                      name="ExtraService")
    ]
    delivery_date = (format_date(service.GuaranteeAvailability, "%m/%d/%Y")
                     if service.GuaranteeAvailability is not None else None)

    return RateDetails(
        carrier_name=settings.carrier_name,
        carrier_id=settings.carrier_id,
        service=service.SvcDescription,
        base_charge=decimal(service.Postage),
        total_charge=decimal(service.Postage),
        currency=currency,
        estimated_delivery=delivery_date,
        extra_charges=[
            ChargeDetails(
                name=ExtraService(special.ServiceID).name,
                amount=decimal(special.Price),
                currency=currency,
            ) for special in special_services
        ],
    )
コード例 #15
0
ファイル: intl.py プロジェクト: iliaaz/purplship
def _extract_details(service_node: Element, settings: Settings) -> RateDetails:
    service: ServiceType = ServiceType()
    service.build(service_node)
    currency = "USD"
    special_services: List[ExtraServiceType] = [
        XP.build(ExtraServiceType, svc)
        for svc in service_node.xpath(".//*[local-name() = $name]",
                                      name="ExtraService")
    ]
    delivery_date = DF.date(service.GuaranteeAvailability, "%m/%d/%Y")
    transit = ((delivery_date -
                datetime.now()).days if delivery_date is not None else None)
    rate_service: Service = Service.find(service.SvcDescription)

    return RateDetails(
        carrier_name=settings.carrier_name,
        carrier_id=settings.carrier_id,
        service=rate_service.value,
        base_charge=NF.decimal(service.Postage),
        total_charge=NF.decimal(service.Postage),
        currency=currency,
        transit_days=transit,
        extra_charges=[
            ChargeDetails(
                name=ExtraService(special.ServiceID).name,
                amount=NF.decimal(special.Price),
                currency=currency,
            ) for special in special_services
        ],
    )
コード例 #16
0
ファイル: create.py プロジェクト: iliaaz/purplship
def parse_pickup_response(
        response: Element,
        settings: Settings) -> Tuple[PickupDetails, List[Message]]:
    pickup = (_extract_pickup_details(response, settings) if len(
        response.xpath(".//*[local-name() = $name]",
                       name="pickup-request-header")) > 0 else None)
    return pickup, parse_error_response(response, settings)
コード例 #17
0
def parse_non_contract_shipment_response(
        response: Element,
        settings: Settings) -> Tuple[ShipmentDetails, List[Message]]:
    shipment = (_extract_shipment(response, settings) if len(
        response.xpath(".//*[local-name() = $name]", name="shipment-id")) > 0
                else None)
    return shipment, parse_error_response(response, settings)
コード例 #18
0
ファイル: rate.py プロジェクト: iliaaz/purplship
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)
コード例 #19
0
def parse_shipment_response(response: Element, settings: Settings) -> Tuple[ShipmentDetails, List[Message]]:
    shipment = XP.to_object(
        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)
コード例 #20
0
def parse_full_estimate_response(
    response: Element, settings: Settings
) -> Tuple[List[RateDetails], List[Message]]:
    estimates = response.xpath(".//*[local-name() = $name]", name="ShipmentEstimate")
    return (
        [_extract_rate(node, settings) for node in estimates],
        parse_error_response(response, settings),
    )
コード例 #21
0
ファイル: track.py プロジェクト: QwadwoNyamekye/purplship
def parse_tracking_summary(
    response: Element, settings: Settings
) -> Tuple[List[TrackingDetails], List[Message]]:
    pin_summaries = response.xpath(".//*[local-name() = $name]", name="pin-summary")
    tracking: List[TrackingDetails] = [
        _extract_tracking(pin, settings) for pin in pin_summaries
    ]
    return tracking, parse_error_response(response, settings)
コード例 #22
0
def parse_price_quotes(
    response: Element, settings: Settings
) -> Tuple[List[RateDetails], List[Message]]:
    price_quotes = response.xpath(".//*[local-name() = $name]", name="price-quote")
    quotes: List[RateDetails] = [
        _extract_quote(price_quote_node, settings) for price_quote_node in price_quotes
    ]
    return quotes, parse_error_response(response, settings)
コード例 #23
0
ファイル: tracking.py プロジェクト: derekcao0226/purplship
def parse_tracking_response(
        response: Element,
        settings: Settings) -> Tuple[List[TrackingDetails], List[Message]]:
    track_details = response.xpath(".//*[local-name() = $name]",
                                   name="Shipment")
    tracking: List[TrackingDetails] = [
        _extract_details(node, settings) for node in track_details
    ]
    return tracking, parse_error_response(response, settings)
コード例 #24
0
ファイル: dct_quote.py プロジェクト: gitter-badger/purplship
def parse_dct_response(
        response: Element,
        settings: Settings) -> Tuple[List[RateDetails], List[Message]]:
    qtdshp_list = response.xpath(".//*[local-name() = $name]", name="QtdShp")
    quotes: List[RateDetails] = [
        _extract_quote(qtdshp_node, settings) for qtdshp_node in qtdshp_list
    ]
    return ([quote for quote in quotes
             if quote is not None], parse_error_response(response, settings))
コード例 #25
0
def parse_tracking_response(
        response: Element,
        settings: Settings) -> Tuple[List[TrackingDetails], List[Message]]:
    results = response.xpath(".//*[local-name() = $name]", name="result")
    details: List[TrackingDetails] = [
        _extract_tracking_details(result, settings) for result in results
    ]

    return details, parse_error_response(response, settings)
コード例 #26
0
def parse_track_package_response(
        response: Element,
        settings: Settings) -> Tuple[List[TrackingDetails], List[Message]]:
    track_infos = response.xpath(".//*[local-name() = $name]",
                                 name="TrackingInformation")
    return (
        [_extract_tracking(node, settings) for node in track_infos],
        parse_error_response(response, settings),
    )
コード例 #27
0
def parse_intl_rate_response(
        response: Element,
        settings: Settings) -> Tuple[List[RateDetails], List[Message]]:
    quotes: List[RateDetails] = [
        _extract_intl_rates(package, settings)
        for package in response.xpath(".//*[local-name() = $name]",
                                      name="Service")
    ]
    return quotes, parse_error_response(response, settings)
コード例 #28
0
ファイル: rate.py プロジェクト: derekcao0226/purplship
def parse_rate_response(
        response: Element,
        settings: Settings) -> Tuple[List[RateDetails], List[Message]]:
    shipment_nodes = response.xpath(".//*[local-name() = $name]",
                                    name="shipment")
    rates: List[RateDetails] = [
        _extract_rate_details(node, settings) for node in shipment_nodes
    ]
    return rates, parse_error_response(response, settings)
コード例 #29
0
ファイル: create.py プロジェクト: iliaaz/purplship
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)
コード例 #30
0
ファイル: create.py プロジェクト: derekcao0226/purplship
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)