Example #1
0
 def parse_error_response(self,
                          response: etree.ElementBase) -> List[T.Error]:
     notifications = response.xpath(".//*[local-name() = $name]",
                                    name="Notifications") + response.xpath(
                                        ".//*[local-name() = $name]",
                                        name="Notification")
     return reduce(self._extract_error, notifications, [])
Example #2
0
    def _extract_package_rate(
        self, rates: List[T.QuoteDetails], detailNode: etree.ElementBase
    ) -> List[T.QuoteDetails]:
        rate = PRate.RatedShipmentType()
        rate.build(detailNode)

        if rate.NegotiatedRateCharges != 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 = PRate.PickupType()
        [
            arrival.build(arrival) for arrival in
            detailNode.xpath(".//*[local-name() = $name]", name="Arrival")
        ]
        currency_ = next(c.text for c in detailNode.xpath(
            ".//*[local-name() = $name]", name="CurrencyCode"
        ))

        return rates + [
            T.QuoteDetails(
                carrier=self.client.carrier_name,
                currency=currency_,
                service_name=str(ShippingServiceCode(rate.Service.Code).name),
                service_type=rate.Service.Code,
                base_charge=float(rate.TransportationCharges.MonetaryValue),
                total_charge=float(total_charges.MonetaryValue),
                duties_and_taxes=reduce(
                    lambda total, charge: total + float(charge.MonetaryValue),
                    taxes or [],
                    0.0,
                ),
                discount=None,
                extra_charges=reduce(
                    lambda total, charge: total
                    + [
                        T.ChargeDetails(
                            name=charge.Code,
                            amount=float(charge.MonetaryValue),
                            currency=charge.CurrencyCode,
                        )
                    ],
                    [charge for charge in extra_charges if charge != None],
                    [],
                ),
                delivery_date=str(arrival.Date)
            )
        ]
Example #3
0
 def parse_quote_response(
     self, response: etree.ElementBase
 ) -> Tuple[List[T.QuoteDetails], List[T.Error]]:
     details = response.xpath(
         ".//*[local-name() = $name]", name="FreightRateResponse"
     ) + response.xpath(".//*[local-name() = $name]", name="FreightRateResponse")
     if len(details) > 0:
         return self.parse_freight_rate_response(response)
     else:
         return self.parse_package_rate_response(response)
Example #4
0
 def _extract_quote(
     self, quotes: List[T.QuoteDetails], detailNode: etree.ElementBase
 ) -> List[T.QuoteDetails]:
     detail = RateReplyDetail()
     detail.build(detailNode)
     if not detail.RatedShipmentDetails:
         return quotes
     shipmentDetail: RatedShipmentDetail = detail.RatedShipmentDetails[0].ShipmentRateDetail
     delivery_ = reduce(lambda v, c: c.text, detailNode.xpath(
         ".//*[local-name() = $name]", name="DeliveryTimestamp"
     ), None)
     currency_ = reduce(lambda v, c: c.text, detailNode.xpath(
         ".//*[local-name() = $name]", name="Currency"
     ), None)
     Discounts_ = map(
         lambda d: T.ChargeDetails(
             name=d.RateDiscountType, amount=float(d.Amount.Amount), currency=currency_
         ),
         shipmentDetail.FreightDiscounts,
     )
     Surcharges_ = map(
         lambda s: T.ChargeDetails(
             name=s.SurchargeType, amount=float(s.Amount.Amount), currency=currency_
         ),
         shipmentDetail.Surcharges,
     )
     Taxes_ = map(
         lambda t: T.ChargeDetails(name=t.TaxType, amount=float(t.Amount.Amount), currency=currency_),
         shipmentDetail.Taxes,
     )
     return quotes + [
         T.QuoteDetails(
             carrier=self.client.carrier_name,
             service_name=detail.ServiceType,
             service_type=detail.ActualRateType,
             currency=currency_,
             delivery_date=datetime.strptime(
                 delivery_, "%Y-%m-%dT%H:%M:%S"
             ).strftime("%Y-%m-%d") if delivery_ else None,
             base_charge=float(shipmentDetail.TotalBaseCharge.Amount),
             total_charge=float(
                 shipmentDetail.TotalNetChargeWithDutiesAndTaxes.Amount
             ),
             duties_and_taxes=float(shipmentDetail.TotalTaxes.Amount),
             discount=float(shipmentDetail.TotalFreightDiscounts.Amount),
             extra_charges=list(Discounts_) + list(Surcharges_) + list(Taxes_),
         )
     ]
Example #5
0
    def _extract_quote(self, postage_node: etree.ElementBase) -> QuoteDetails:
        postage: RateRes.PostageType = RateRes.PostageType()
        postage.build(postage_node)
        currency = "USD"
        services: List[RateRes.SpecialServiceType] = [
            (lambda s: (s, s.build(svc)))(RateRes.SpecialServiceType())[0]
            for svc in postage_node.xpath(".//*[local-name() = $name]",
                                          name="SpecialService")
        ]

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

        return QuoteDetails(
            carrier=self.client.carrier_name,
            service_name=None,
            service_type=get("MailService"),
            base_charge=None,
            duties_and_taxes=None,
            total_charge=float(postage_node.find("Rate").text),
            currency=currency,
            delivery_date=postage.CommitmentDate,
            discount=None,
            extra_charges=[
                ChargeDetails(
                    name=SpecialService(str(svc.ServiceID)).name,
                    amount=svc.Price,
                    currency=currency,
                ) for svc in services
            ],
        )
Example #6
0
 def _extract_tracking(self,
                       tracking_node: etree.ElementBase) -> TrackingDetails:
     tracking: TrackInfoType = TrackInfoType()
     tracking.build(tracking_node)
     details: List[TrackDetailType] = [
         (lambda t: (t, t.build(detail)))(TrackDetailType())[0]
         for detail in tracking_node.xpath(".//*[local-name() = $name]",
                                           name="TrackDetail")
     ]
     return TrackingDetails(
         carrier=self.client.carrier_name,
         tracking_number=tracking.TrackInfoID,
         shipment_date=None,
         events=[
             TrackingEvent(
                 code=str(event.EventCode),
                 date=event.EventDate,
                 description=event.ActionCode,
                 location=", ".join([
                     location for location in [
                         event.EventCity,
                         event.EventState,
                         event.EventCountry,
                         str(event.EventZIPCode),
                     ] if location is not None
                 ]),
                 time=event.EventTime,
                 signatory=None,
             ) for event in details
         ],
     )
Example #7
0
 def parse_shipment_info(
     self, response: etree.ElementBase
 ) -> Tuple[T.ShipmentDetails, List[T.Error]]:
     shipment = (self._extract_shipment(response) if len(
         response.xpath(".//*[local-name() = $name]", name="shipment-id")) >
                 0 else None)
     return (shipment, self.parse_error_response(response))
Example #8
0
    def _extract_tracking(
            self, trackings: List[T.TrackingDetails],
            shipmentNode: etree.ElementBase) -> List[T.TrackingDetails]:
        trackDetail = Track.ShipmentType()
        trackDetail.build(shipmentNode)
        activityNodes = shipmentNode.xpath(".//*[local-name() = $name]",
                                           name="Activity")

        def buildActivity(node):
            activity = Track.ActivityType()
            activity.build(node)
            return activity

        activities = map(buildActivity, activityNodes)
        return trackings + [
            T.TrackingDetails(
                carrier=self.client.carrier_name,
                tracking_number=trackDetail.InquiryNumber.Value,
                events=list(
                    map(
                        lambda a: T.TrackingEvent(
                            date=str(a.Date),
                            time=str(a.Time),
                            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,
                    )),
            )
        ]
Example #9
0
 def _extract_intl_quote(self,
                         service_node: etree.ElementBase) -> QuoteDetails:
     service: IntlRateRes.ServiceType = IntlRateRes.ServiceType()
     service.build(service_node)
     currency = "USD"
     special_services: List[IntlRateRes.ExtraServiceType] = [
         (lambda s: (s, s.build(svc)))(IntlRateRes.ExtraServiceType())[0]
         for svc in service_node.xpath(".//*[local-name() = $name]",
                                       name="ExtraService")
     ]
     return QuoteDetails(
         carrier=self.client.carrier_name,
         service_name=None,
         service_type=service.MailType,
         base_charge=None,
         duties_and_taxes=None,
         total_charge=service.Postage,
         currency=currency,
         delivery_date=service.GuaranteeAvailability,
         discount=None,
         extra_charges=[
             ChargeDetails(
                 name=ExtraService(special.ServiceID).name,
                 amount=special.Price,
                 currency=currency,
             ) for special in special_services
         ],
     )
Example #10
0
 def parse_tracking_summary(
     self, response: etree.ElementBase
 ) -> Tuple[List[T.TrackingDetails], List[T.Error]]:
     pin_summaries = response.xpath(".//*[local-name() = $name]", name="pin-summary")
     trackings: List[T.TrackingDetails] = reduce(
         self._extract_tracking, pin_summaries, []
     )
     return (trackings, self.parse_error_response(response))
Example #11
0
 def parse_rate_reply(
     self, response: etree.ElementBase
 ) -> Tuple[List[T.QuoteDetails], List[T.Error]]:
     rate_replys = response.xpath(
         ".//*[local-name() = $name]", name="RateReplyDetails"
     )
     quotes: List[T.QuoteDetails] = reduce(self._extract_quote, rate_replys, [])
     return (quotes, self.parse_error_response(response))
 def parse_process_shipment_reply(
     self, response: etree.ElementBase
 ) -> Tuple[T.ShipmentDetails, List[T.Error]]:
     details = response.xpath(".//*[local-name() = $name]",
                              name="CompletedShipmentDetail")
     shipment: T.ShipmentDetails = self._extract_shipment(
         details[0]) if len(details) > 0 else None
     return (shipment, self.parse_error_response(response))
Example #13
0
 def parse_track_response(
     self, response: etree.ElementBase
 ) -> Tuple[List[T.TrackingDetails], List[T.Error]]:
     track_details = response.xpath(".//*[local-name() = $name]",
                                    name="Shipment")
     trackings: List[T.TrackingDetails] = reduce(self._extract_tracking,
                                                 track_details, [])
     return (trackings, self.parse_error_response(response))
Example #14
0
 def parse_price_quotes(
     self, response: etree.ElementBase
 ) -> Tuple[List[T.QuoteDetails], List[T.Error]]:
     price_quotes = response.xpath(".//*[local-name() = $name]",
                                   name="price-quote")
     quotes: List[T.QuoteDetails] = reduce(self._extract_quote,
                                           price_quotes, [])
     return quotes, self.parse_error_response(response)
Example #15
0
 def parse_dct_response(
     self, response: etree.ElementBase
 ) -> Tuple[List[T.QuoteDetails], List[T.Error]]:
     qtdshp_list = response.xpath(".//*[local-name() = $name]",
                                  name="QtdShp")
     quotes: List[T.QuoteDetails] = reduce(self._extract_quote, qtdshp_list,
                                           [])
     return (quotes, self.parse_error_response(response))
 def _xpath(node: etree.ElementBase, query: Text, *args,
            **kwargs) -> List[etree.ElementBase]:
     result = node.xpath(query, *args, **kwargs)
     if result is None:
         return []
     if isinstance(result, etree.ElementBase):
         return [result]
     return result
Example #17
0
 def parse_shipment_response(
     self, response: etree.ElementBase
 ) -> Tuple[T.ShipmentDetails, List[T.Error]]:
     details = response.xpath(
         ".//*[local-name() = $name]", name="FreightShipResponse"
     ) + response.xpath(".//*[local-name() = $name]", name="ShipmentResponse")
     if len(details) > 0:
         shipmentNode = details[0]
         is_freight = "FreightShipResponse" in shipmentNode.tag
         shipment = (
             self.parse_freight_shipment_response(shipmentNode)
             if is_freight
             else self.parse_package_shipment_response(shipmentNode)
         )
     return (
         shipment if len(details) > 0 else None,
         self.parse_error_response(response),
     )
Example #18
0
 def get_definition_name(res: etree.ElementBase) -> str:
     item_str = ''
     for elem in res.xpath('object/a'):
         for x in elem.iter():
             for item in [x.text, x.tail]:
                 if item is not None:
                     if item.strip() != '':
                         item_str += f' {item}'
     return item_str.strip()
Example #19
0
 def parse_track_response(
     self, response: etree.ElementBase
 ) -> Tuple[List[TrackingDetails], List[Error]]:
     return (
         [
             self._extract_tracking(node)
             for node in response.xpath(".//*[local-name() = $name]",
                                        name="TrackInfo")
         ],
         self.parse_error_response(response),
     )
Example #20
0
def read_xml(context: Context,
             prop: Property,
             *,
             source=str,
             value: etree.ElementBase):
    result = value.xpath(source)
    if len(result) == 1:
        return result[0]
    elif len(result) == 0:
        return None
    else:
        context.error(f"More than one value returned for {source}: {value}")
Example #21
0
def post_pr(xml: etree.ElementBase, url) -> (str, etree.ElementBase):
    parts = urlparse(url)

    for u in xml.xpath("//Request"):
        u.attrib['deploymentMode'] = 'test'
        pass

    for u in xml.xpath("//BrowserFormPost/URL"):
        u.text = "//%s/m2po/cxml/cartecho" % parts.netloc
        pass

    res = post(url, etree.tostring(xml, pretty_print=True))

    if not res.ok:
        raise Exception("failed with status %s" % res.status_code)

    res_xml: etree.ElementBase = etree.fromstring(res.content)

    punchout_url = str(res_xml.xpath('string(//URL)'))

    return punchout_url, res_xml
Example #22
0
 def parse_rate_response(
         self, response: etree.ElementBase
 ) -> Tuple[List[QuoteDetails], List[Error]]:
     is_intl = response.tag == "IntlRateV2Response"
     quotes: List[QuoteDetails] = [
         (self._extract_quote
          if not is_intl else self._extract_intl_quote)(package)
         for package in response.xpath(
             ".//*[local-name() = $name]",
             name="Postage" if not is_intl else "Service",
         )
     ]
     return quotes, self.parse_error_response(response)
Example #23
0
 def _extract_quote(self, quotes: List[T.QuoteDetails],
                    detailNode: etree.ElementBase) -> List[T.QuoteDetails]:
     detail = RateReplyDetail()
     detail.build(detailNode)
     if not detail.RatedShipmentDetails:
         return quotes
     shipmentDetail: RatedShipmentDetail = detail.RatedShipmentDetails[
         0].ShipmentRateDetail
     currency_ = next(c.text for c in detailNode.xpath(
         ".//*[local-name() = $name]", name="Currency"))
     Discounts_ = map(
         lambda d: T.ChargeDetails(name=d.RateDiscountType,
                                   amount=float(d.Amount.Amount),
                                   currency=currency_),
         shipmentDetail.FreightDiscounts,
     )
     Surcharges_ = map(
         lambda s: T.ChargeDetails(name=s.SurchargeType,
                                   amount=float(s.Amount.Amount),
                                   currency=currency_),
         shipmentDetail.Surcharges,
     )
     Taxes_ = map(
         lambda t: T.ChargeDetails(name=t.TaxType,
                                   amount=float(t.Amount.Amount),
                                   currency=currency_),
         shipmentDetail.Taxes,
     )
     return quotes + [
         T.QuoteDetails(
             carrier=self.client.carrier_name,
             service_name=detail.ServiceType,
             service_type=detail.ActualRateType,
             currency=currency_,
             base_charge=float(shipmentDetail.TotalBaseCharge.Amount),
             total_charge=float(
                 shipmentDetail.TotalNetChargeWithDutiesAndTaxes.Amount),
             duties_and_taxes=float(shipmentDetail.TotalTaxes.Amount),
             discount=float(shipmentDetail.TotalFreightDiscounts.Amount),
             extra_charges=list(Discounts_) + list(Surcharges_) +
             list(Taxes_),
         )
     ]
Example #24
0
    def _extract_freight_rate(
        self, rates: List[T.QuoteDetails], detailNode: etree.ElementBase
    ) -> List[T.QuoteDetails]:
        detail = Rate.FreightRateResponse()
        detail.build(detailNode)

        total_charge = [r for r in detail.Rate if r.Type.Code == "AFTR_DSCNT"][0]
        Discounts_ = [
            T.ChargeDetails(
                name=r.Type.Code,
                currency=r.Factor.UnitOfMeasurement.Code,
                amount=float(r.Factor.Value),
            )
            for r in detail.Rate
            if r.Type.Code == "DSCNT"
        ]
        Surcharges_ = [
            T.ChargeDetails(
                name=r.Type.Code,
                currency=r.Factor.UnitOfMeasurement.Code,
                amount=float(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 detailNode.xpath(
            ".//*[local-name() = $name]", name="CurrencyCode"
        ))
        return rates + [
            T.QuoteDetails(
                carrier=self.client.carrier_name,
                currency=currency_,
                service_name=detail.Service.Description,
                service_type=detail.Service.Code,
                base_charge=float(detail.TotalShipmentCharge.MonetaryValue),
                total_charge=float(total_charge.Factor.Value or 0.0),
                duties_and_taxes=reduce(lambda r, c: r + c.amount, Surcharges_, 0.0),
                discount=reduce(lambda r, c: r + c.amount, Discounts_, 0.0),
                extra_charges=extra_charges,
            )
        ]
Example #25
0
def text(element: etree.ElementBase,
         name: str,
         is_attribute: bool = False,
         nullable: bool = False) -> Optional[str]:
    if is_attribute:
        if nullable:
            return element.attrib.get(name)
        else:
            return element.attrib[name]

    value = element.xpath(name)

    if (not value) and nullable:
        return None

    if len(value) != 1:
        raise ValueError(
            f"Only one '{name}' tag per tree is supported, {len(value)}  found"
        )
    return value[0].text
 def _xpath_one(node: etree.ElementBase, query: Text, *args,
                **kwargs) -> etree.ElementBase:
     result = node.xpath(query, *args, **kwargs)
     if not result:
         raise ValueError(f'Query {query} has no result.')
     return result[0]
Example #27
0
def tei_xpath(parent: etree.ElementBase, xpath: str) -> List[etree.ElementBase]:
    return parent.xpath(xpath, namespaces=TEI_NS_MAP)
Example #28
0
    def _extract_shipment(self,
                          response: etree.ElementBase) -> T.ShipmentDetails:
        is_non_contract = (len(
            response.xpath(".//*[local-name() = $name]",
                           name="non-contract-shipment-info")) > 0)
        info = (NCShipment.NonContractShipmentInfoType()
                if is_non_contract else Shipment.ShipmentInfoType())
        data = (NCShipment.NonContractShipmentReceiptType()
                if is_non_contract else Shipment.ShipmentPriceType())

        info.build(
            response.xpath(
                ".//*[local-name() = $name]",
                name=("non-contract-shipment-info"
                      if is_non_contract else "shipment-info"),
            )[0])
        data.build(
            response.xpath(
                ".//*[local-name() = $name]",
                name=("non-contract-shipment-receipt"
                      if is_non_contract else "shipment-price"),
            )[0])
        currency_ = data.cc_receipt_details.currency if is_non_contract else "CAD"

        return T.ShipmentDetails(
            carrier=self.client.carrier_name,
            tracking_numbers=[info.tracking_pin],
            total_charge=T.ChargeDetails(
                name="Shipment charge",
                amount=data.cc_receipt_details.charge_amount
                if is_non_contract else data.due_amount,
                currency=currency_,
            ),
            charges=([
                T.ChargeDetails(name="base-amount",
                                amount=data.base_amount,
                                currency=currency_),
                T.ChargeDetails(name="gst-amount",
                                amount=data.gst_amount,
                                currency=currency_),
                T.ChargeDetails(name="pst-amount",
                                amount=data.pst_amount,
                                currency=currency_),
                T.ChargeDetails(name="hst-amount",
                                amount=data.hst_amount,
                                currency=currency_),
            ] + [
                T.ChargeDetails(
                    name=adjustment.adjustment_code,
                    amount=adjustment.adjustment_amount,
                    currency=currency_,
                ) for adjustment in data.adjustments.get_adjustment()
            ] + [
                T.ChargeDetails(
                    name=option.option_code,
                    amount=option.option_price,
                    currency=currency_,
                ) for option in data.priced_options.get_priced_option()
            ]),
            shipment_date=data.service_standard.expected_delivery_date,
            services=([data.service_code] + [
                option.option_code
                for option in data.priced_options.get_priced_option()
            ]),
            documents=[
                link.get("href")
                for link in response.xpath(".//*[local-name() = $name]",
                                           name="link")
                if link.get("rel") == "label"
            ],
            reference=T.ReferenceDetails(value=info.shipment_id,
                                         type="Shipment Id"),
        )
Example #29
0
 def parse_error_response(self,
                          response: etree.ElementBase) -> List[T.Error]:
     messages = response.xpath(".//*[local-name() = $name]", name="message")
     return reduce(self._extract_error, messages, [])
Example #30
0
def alto_xpath(parent: etree.ElementBase,
               xpath: str) -> List[etree.ElementBase]:
    return parent.xpath(xpath, namespaces=ALTO_NS_MAP)