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)
def rate_request(payload: RateRequest, settings: Settings) -> Serializable[priceRequest]: options = Options(payload.options, ShipmentOption) package = Packages(payload.parcels).single service = Services(payload.services, ShipmentService).first option_codes = [code for label, code in options if 'division' not in label] request = priceRequest( appId=settings.username, appVersion="3.0", priceCheck=priceCheck( rateId=None, sender=address(country=payload.shipper.country_code, town=payload.shipper.city, postcode=payload.shipper.postal_code), delivery=address(country=payload.recipient.country_code, town=payload.recipient.city, postcode=payload.recipient.postal_code), collectionDateTime=DF.fdatetime(options.shipment_date, output_format='%Y-%m-%dT%H:%M:%S'), product=product( id=getattr(service, 'value', None), division=next( (code for label, code in options if 'division' in label), None), productDesc=None, type_=('D' if package.parcel.is_document else 'N'), options=(optionsType( option=[option(optionCode=code) for code in option_codes]) if any(option_codes) else None)), account=(account( accountNumber=settings.account_number, accountCountry=settings.account_country_code, ) if any([settings.account_number, settings.account_country_code]) else None), insurance=(insurance(insuranceValue=options.insurance, goodsValue=options.insurance) if options.insurance is not None else None), termsOfPayment=PaymentType.sender.value, currency=options.currency, priceBreakDown=True, consignmentDetails=consignmentDetails( totalWeight=package.weight.KG, totalVolume=package.volume.value, totalNumberOfPieces=1, ), pieceLine=None), ) return Serializable(request, XP.to_xml)
def pickup_request(payload: PickupRequest, settings: Settings) -> Serializable[Envelope]: packages = Packages(payload.parcels) request = create_envelope( body_content=schedulePickupV2( request=SchedulePickupV2Rq( password=settings.password, pickup=PickupV2( collect=None, comments=payload.instruction, created_by=payload.address.person_name, pickup_address=Address( address_line_1=payload.address.address_line1, address_line_2=payload.address.address_line2, address_line_3=None, attention=payload.address.person_name, city=payload.address.city, country=payload.address.country_code, email=payload.address.email, extension=None, name=payload.address.company_name, phone=payload.address.phone_number, postal_code=payload.address.postal_code, province=payload.address.state_code, residential=payload.address.residential, ), pickup_date=DF.fdatetime( f"{payload.pickup_date} {payload.ready_time}", '%Y-%m-%d %H:%M', '%Y-%m-%dT%H:%M:%S' ), pickup_location=payload.package_location, pickup_phone=payload.address.phone_number, shipper_num=None, unit_of_measure=WeightUnit.LB.value, weight=packages.weight.LB ), user_id=settings.username ) ) ) return Serializable( request, partial( settings.serialize, extra_namespace='xmlns:xsd1="http://dto.canshipws.canpar.com/xsd"', special_prefixes=dict(pickup_children='xsd1') ) )
def shipment_request( payload: ShipmentRequest, settings: Settings) -> Serializable[eVSGXGGetLabelRequest]: package = Packages(payload.parcels, max_weight=Weight(70, WeightUnit.LB)).single options = Options(payload.options, ShipmentOption) customs = payload.customs or Customs(commodities=[]) incoterm = Incoterm[customs.incoterm or 'OTHER'].value insurance = getattr((options['usps_insurance_global_express_guaranteed']), 'value', options.insurance) request = eVSGXGGetLabelRequest( USERID=settings.username, PASSWORD=settings.password, Option=None, Revision=2, ImageParameters=None, FromFirstName=customs.signer or payload.shipper.person_name or "N/A", FromMiddleInitial=None, FromLastName=payload.shipper.person_name, FromFirm=payload.shipper.company_name or "N/A", FromAddress1=payload.shipper.address_line1, FromAddress2=payload.shipper.address_line2, FromUrbanization=None, FromCity=payload.shipper.city, FromState=Location(payload.shipper.state_code, country='US').as_state_name, FromZIP5=Location(payload.shipper.postal_code).as_zip5, FromZIP4=Location(payload.shipper.postal_code).as_zip4, FromPhone=payload.shipper.phone_number, ShipFromZIP=None, ToFirstName=None, ToLastName=payload.recipient.person_name, ToFirm=payload.recipient.company_name or "N/A", ToAddress1=payload.recipient.address_line1, ToAddress2=payload.recipient.address_line2, ToAddress3=None, ToPostalCode=payload.recipient.postal_code, ToPhone=payload.recipient.phone_number, RecipientEMail=payload.recipient.email, ToDPID="000", # supposedly required test and find a solution ToProvince=payload.recipient.state_code, ToTaxID=(payload.recipient.federal_tax_id or payload.recipient.state_tax_id), Container=PackagingType[package.packaging_type or 'package'].value, ContentType=('DOCUMENTS' if package.parcel.is_document else 'NON-DOC'), ShippingContents=ShippingContentsType(ItemDetail=[ ItemDetailType( Description=item.description, Commodity=item.description or "N/A", Quantity=item.quantity, UnitValue=item.value_amount, NetPounds=Weight(item.weight, WeightUnit[item.weight_unit or 'LB']).LB, NetOunces=Weight(item.weight, WeightUnit[item.weight_unit or 'LB']).OZ, UnitOfMeasure=None, HSTariffNumber=item.sku, CountryofManufacture=Location( item.origin_country).as_country_name) for item in payload.customs.commodities ]), PurposeOfShipment=ContentType[customs.content_type or 'other'], PartiesToTransaction=None, Agreement=('N' if customs.certify else 'Y'), Postage=None, InsuredValue=insurance, GrossPounds=package.weight.LB, GrossOunces=package.weight.OZ, Length=package.length.IN, Width=package.weight.IN, Height=package.height.IN, Girth=(package.girth.value if package.packaging_type == "tube" else None), Shape=None, CIRequired=customs.commercial_invoice, InvoiceDate=None, InvoiceNumber=customs.invoice, CustomerOrderNumber=None, CustOrderNumber=None, TermsDelivery=incoterm, TermsDeliveryOther=((customs.incoterm or incoterm) if incoterm == 'OTHER' else None), PackingCost=None, CountryUltDest=Location( payload.recipient.country_code).as_country_name, CIAgreement=customs.commercial_invoice, ImageType="PDF", ImageLayout=None, CustomerRefNo=None, CustomerRefNo2=None, ShipDate=DF.fdatetime((options.shipment_date or datetime.now()), output_format="%m/%d/%Y"), HoldForManifest=None, PriceOptions=None, CommercialShipment=customs.commercial_invoice, BuyerRecipient=( customs.commercial_invoice or None), # Consider recipient as buyer for commercial shipment TermsPayment=("Net 50" if customs.commercial_invoice else None), ActionCode=None, OptOutOfSPE=None, PermitNumber=None, AccountZipCode=None, Machinable=options['usps_option_machinable_item'], DestinationRateIndicator="I", MID=None, LogisticsManagerMID=None, CRID=None, VendorCode=None, VendorProductVersionNumber=None, OverrideMID=None, ChargebackCode=None, ) return Serializable(request, XP.export)
def rate_request(payload: RateRequest, settings: Settings) -> Serializable[Envelope]: packages = Packages(payload.parcels) service_type = Services(payload.services, Service).first options = Options(payload.options, Option) shipment_date = DF.fdatetime(options.shipment_date or time.strftime('%Y-%m-%d'), current_format='%Y-%m-%d', output_format='%Y-%m-%dT%H:%M:%S') premium: Optional[bool] = next((True for option, _ in options if option in [ Option.canpar_ten_am.name, Option.canpar_noon.name, Option.canpar_saturday.name, ]), None) nsr = next( (Option[o].value for o in ['canpar_no_signature_required', 'canpar_not_no_signature_required'] if o in options), None) request = create_envelope(body_content=rateShipment(request=RateShipmentRq( apply_association_discount=False, apply_individual_discount=False, apply_invoice_discount=False, password=settings.password, shipment=Shipment( cod_type=options['canpar_cash_on_delivery'], delivery_address=Address( address_line_1=payload.recipient.address_line1, address_line_2=payload.recipient.address_line2, address_line_3=None, attention=payload.recipient.person_name, city=payload.recipient.city, country=payload.recipient.country_code, email=payload.recipient.email, extension=None, name=payload.recipient.company_name, phone=payload.recipient.phone_number, postal_code=payload.recipient.postal_code, province=payload.recipient.state_code, residential=payload.recipient.residential, ), description=None, dg=options['canpar_dangerous_goods'], dimention_unit=DimensionUnit.IN.value, handling=None, handling_type=None, instruction=None, nsr=nsr, packages=[ Package(alternative_reference=None, cod=None, cost_centre=None, declared_value=None, height=pkg.height.CM, length=pkg.length.CM, lg=None, reference=None, reported_weight=pkg.weight.LB, store_num=None, width=pkg.width.CM, xc=options['canpar_extra_care']) for pkg in packages ], pickup_address=Address( address_line_1=payload.shipper.address_line1, address_line_2=payload.shipper.address_line2, address_line_3=None, attention=payload.shipper.person_name, city=payload.shipper.city, country=payload.shipper.country_code, email=payload.shipper.email, extension=None, name=payload.shipper.company_name, phone=payload.shipper.phone_number, postal_code=payload.shipper.postal_code, province=payload.shipper.state_code, residential=payload.shipper.residential, ), premium=premium, proforma=None, reported_weight_unit=WeightUnit.LB.value, send_email_to_delivery=payload.recipient.email, send_email_to_pickup=payload.shipper.email, service_type=service_type.value, shipper_num=None, shipping_date=shipment_date, subtotal=None, subtotal_with_handling=None, total=None, total_with_handling=None, user_id=None, ), user_id=settings.username))) return Serializable( request, partial( settings.serialize, extra_namespace='xmlns:xsd1="http://dto.canshipws.canpar.com/xsd"', special_prefixes=dict(shipment_children='xsd1')))
def shipment_request( payload: ShipmentRequest, settings: Settings) -> Serializable[eVSPriorityMailIntlRequest]: package = Packages(payload.parcels, max_weight=Weight(70, WeightUnit.LB)).single options = Options(payload.options, ShipmentOption) label_format = LabelFormat[payload.label_type or 'usps_6_x_4_label'].value extra_services = [ getattr(option, 'value', option) for key, option in options if 'usps_option' not in key ] customs = payload.customs or Customs(commodities=[]) insurance = getattr( (options['usps_insurance_priority_mail_international']), 'value', options.insurance) # Gets the first provided non delivery option or default to "RETURN" non_delivery = next( (option.value for name, option in options if 'non_delivery' in name), "RETURN") redirect_address = Address( **(options['usps_option_redirect_non_delivery'] or {})) request = eVSPriorityMailIntlRequest( USERID=settings.username, Option=None, Revision=2, ImageParameters=ImageParametersType(ImageParameter=label_format), FromFirstName=customs.signer or payload.shipper.person_name or "N/A", FromMiddleInitial=None, FromLastName=payload.shipper.person_name, FromFirm=payload.shipper.company_name or "N/A", FromAddress1=payload.shipper.address_line1, FromAddress2=payload.shipper.address_line2, FromUrbanization=None, FromCity=payload.shipper.city, FromState=Location(payload.shipper.state_code, country='US').as_state_name, FromZip5=Location(payload.shipper.postal_code).as_zip5, FromZip4=Location(payload.shipper.postal_code).as_zip4, FromPhone=payload.shipper.phone_number, FromCustomsReference=None, ToName=None, ToFirstName=payload.recipient.person_name, ToLastName=None, ToFirm=payload.recipient.company_name or "N/A", ToAddress1=payload.recipient.address_line1, ToAddress2=payload.recipient.address_line2, ToAddress3=None, ToCity=payload.recipient.city, ToProvince=payload.recipient.state_code, ToCountry=Location(payload.recipient.country_code).as_country_name, ToPostalCode=payload.recipient.postal_code, ToPOBoxFlag=None, ToPhone=payload.recipient.phone_number, ToFax=None, ToEmail=payload.recipient.email, ImportersReferenceNumber=None, NonDeliveryOption=non_delivery, RedirectName=redirect_address.person_name, RedirectEmail=redirect_address.email, RedirectSMS=redirect_address.phone_number, RedirectAddress=SF.concat_str(redirect_address.address_line1, redirect_address.address_line2, join=True), RedirectCity=redirect_address.city, RedirectState=redirect_address.state_code, RedirectZipCode=redirect_address.postal_code, RedirectZip4=Location(redirect_address.postal_code).as_zip4, Container=None, ShippingContents=ShippingContentsType(ItemDetail=[ ItemDetailType( Description=item.description, Quantity=item.quantity, Value=item.value_amount, NetPounds=Weight(item.weight, WeightUnit[item.weight_unit or 'LB']).LB, NetOunces=Weight(item.weight, WeightUnit[item.weight_unit or 'LB']).OZ, HSTariffNumber=item.sku, CountryOfOrigin=Location(item.origin_country).as_country_name) for item in payload.customs.commodities ]), Insured=('N' if insurance is None else 'Y'), InsuredAmount=insurance, GrossPounds=package.weight.LB, GrossOunces=package.weight.OZ, ContentType=ContentType[customs.content_type or "other"].value, ContentTypeOther=customs.content_description or "N/A", Agreement=('N' if customs.certify else 'Y'), Comments=customs.content_description, LicenseNumber=customs.license_number, CertificateNumber=customs.certificate_number, InvoiceNumber=customs.invoice, ImageType="PDF", ImageLayout="ALLINONEFILE", CustomerRefNo=None, CustomerRefNo2=None, POZipCode=None, LabelDate=DF.fdatetime(options.shipment_date, output_format="%m/%d/%Y"), EMCAAccount=None, HoldForManifest=None, EELPFC=customs.eel_pfc, PriceOptions=None, Length=package.length.IN, Width=package.weight.IN, Height=package.height.IN, Girth=(package.girth.value if package.packaging_type == "tube" else None), ExtraServices=(ExtraServicesType(ExtraService=[ getattr(option, 'value', option) for option in extra_services ]) if any(extra_services) else None), ActionCode=None, OptOutOfSPE=None, PermitNumber=None, AccountZipCode=None, ImportersReferenceType=None, ImportersTelephoneNumber=None, ImportersFaxNumber=None, ImportersEmail=None, Machinable=options["usps_option_machinable_item"], DestinationRateIndicator="I", MID=None, LogisticsManagerMID=None, CRID=None, VendorCode=None, VendorProductVersionNumber=None, ChargebackCode=None, ) return Serializable(request, XP.export)
def _process_shipment(payload: ShipmentRequest, settings: Settings) -> Job: packages = Packages(payload.parcels) options = Options(payload.options, Option) service_type: Optional[str] = (Service[payload.service] if payload.service in Service.__members__ else None) premium: Optional[bool] = next((True for option, _ in options if option in [ Option.canpar_ten_am.value, Option.canpar_noon.value, Option.canpar_saturday.value, ]), None) shipping_date = DF.fdatetime(options.shipment_date or time.strftime('%Y-%m-%d'), current_format='%Y-%m-%d', output_format='%Y-%m-%dT%H:%M:%S') request = create_envelope(body_content=processShipment( request=ProcessShipmentRq( password=settings.password, shipment=Shipment( cod_type=options['canpar_cash_on_delivery'], delivery_address=Address( address_line_1=payload.recipient.address_line1, address_line_2=payload.recipient.address_line2, address_line_3=None, attention=payload.recipient.person_name, city=payload.recipient.city, country=payload.recipient.country_code, email=payload.recipient.email, extension=None, name=payload.recipient.company_name, phone=payload.recipient.phone_number, postal_code=payload.recipient.postal_code, province=payload.recipient.state_code, residential=payload.recipient.residential, ), description=None, dg=options['canpar_dangerous_goods'], dimention_unit=DimensionUnit.IN.value, handling=None, handling_type=None, instruction=None, nsr=(options['canpar_no_signature_required'] or options['canpar_not_no_signature_required']), packages=[ Package(alternative_reference=None, cod=None, cost_centre=None, declared_value=None, height=pkg.height.CM, length=pkg.length.CM, lg=None, reference=None, reported_weight=pkg.weight.LB, store_num=None, width=pkg.width.CM, xc=('canpar_extra_care' in options) or None) for pkg in packages ], pickup_address=Address( address_line_1=payload.shipper.address_line1, address_line_2=payload.shipper.address_line2, address_line_3=None, attention=payload.shipper.person_name, city=payload.shipper.city, country=payload.shipper.country_code, email=payload.shipper.email, extension=None, name=payload.shipper.company_name, phone=payload.shipper.phone_number, postal_code=payload.shipper.postal_code, province=payload.shipper.state_code, residential=payload.shipper.residential, ), premium=premium, proforma=None, reported_weight_unit=WeightUnit.LB.value, send_email_to_delivery=payload.recipient.email, send_email_to_pickup=payload.shipper.email, service_type=service_type, shipper_num=None, shipping_date=shipping_date, subtotal=None, subtotal_with_handling=None, total=None, total_with_handling=None, user_id=None, ), user_id=settings.username))) return Job(id="process", data=Serializable(request, default_request_serializer))
def rate_request(payload: RateRequest, settings: Settings) -> Serializable[IntlRateV2Request]: """Create the appropriate USPS International rate request depending on the destination :param payload: Purplship unified API rate request data :param settings: USPS International connection and auth settings :return: a domestic or international USPS International compatible request :raises: - OriginNotServicedError when origin country is not serviced by the carrier - DestinationNotServicedError when destination country is US """ if payload.shipper.country_code is not None and payload.shipper.country_code != Country.US.name: raise OriginNotServicedError(payload.shipper.country_code) if payload.recipient.country_code == Country.US.name: raise DestinationNotServicedError(payload.recipient.country_code) package = Packages(payload.parcels, max_weight=Weight(70, WeightUnit.LB)).single recipient = CompleteAddress(payload.recipient) options = Options(payload.options, ShipmentOption) services = Services(payload.services, ShipmentService) extra_services = [getattr(option, 'value', option) for key, option in options if 'usps_option' not in key] commercial = next(("Y" for svc in services if "commercial" in svc.name), "N") commercial_plus = next(("Y" for svc in services if "plus" in svc.name), "N") request = IntlRateV2Request( USERID=settings.username, Revision="2", Package=[ PackageType( ID=0, Pounds=package.weight.LB, Ounces=package.weight.OZ, Machinable=options.usps_option_machinable_item or False, MailType=PackagingType[package.packaging_type or "package"].value, GXG=( GXGType(POBoxFlag='N', GiftFlag='N') if any('global_express_guaranteed' in s.name for s in payload.services) else None ), ValueOfContents=(options.declared_value or ""), Country=recipient.country_name, Width=package.width.IN, Length=package.length.IN, Height=package.height.IN, Girth=(package.girth.value if package.packaging_type == "tube" else None), OriginZip=payload.shipper.postal_code, CommercialFlag=commercial, CommercialPlusFlag=commercial_plus, AcceptanceDateTime=DF.fdatetime( (options.shipment_date or datetime.today()), output_format="%Y-%m-%dT%H:%M:%S" ), DestinationPostalCode=recipient.postal_code, ExtraServices=( ExtraServicesType(ExtraService=[s for s in extra_services]) if any(extra_services) else None ), Content=None, ) ], ) return Serializable(request, XP.export)
def shipment_request(payload: ShipmentRequest, settings: Settings) -> Serializable[eVSFirstClassMailIntlRequest]: package = Packages(payload.parcels, max_weight=Weight(70, WeightUnit.LB)).single options = Options(payload.options, ShipmentOption) label_format = LabelFormat[payload.label_type or 'usps_6_x_4_label'].value extra_services = [ getattr(option, 'value', option) for key, option in options if key in ShipmentOption and 'usps_option' not in key ] customs = payload.customs or Customs(commodities=[]) request = eVSFirstClassMailIntlRequest( USERID=settings.username, Option=None, Revision=2, ImageParameters=ImageParametersType(ImageParameter=label_format), FromFirstName=customs.signer or payload.shipper.person_name, FromLastName=payload.shipper.person_name, FromFirm=payload.shipper.company_name or "N/A", FromAddress1=payload.shipper.address_line2, FromAddress2=payload.shipper.address_line1, FromUrbanization=None, FromCity=payload.shipper.city, FromZip5=Location(payload.shipper.postal_code).as_zip5, FromZip4=Location(payload.shipper.postal_code).as_zip4 or "", FromPhone=payload.shipper.phone_number, ToName=None, ToFirstName=payload.recipient.person_name, ToLastName=payload.recipient.person_name, ToFirm=payload.recipient.company_name or "N/A", ToAddress1=payload.recipient.address_line2, ToAddress2=payload.recipient.address_line1, ToAddress3=None, ToCity=payload.recipient.city, ToProvince=Location(payload.recipient.state_code, country=payload.recipient.country_code).as_state_name, ToCountry=Location(payload.recipient.country_code).as_country_name, ToPostalCode=payload.recipient.postal_code, ToPOBoxFlag=None, ToPhone=payload.recipient.phone_number, ToFax=None, ToEmail=payload.recipient.email, FirstClassMailType=None, ShippingContents=ShippingContentsType( ItemDetail=[ ItemDetailType( Description=item.description, Quantity=item.quantity, Value=item.value_amount, NetPounds=Weight(item.weight, WeightUnit[item.weight_unit or 'LB']).LB, NetOunces=Weight(item.weight, WeightUnit[item.weight_unit or 'LB']).OZ, HSTariffNumber=item.sku, CountryOfOrigin=Location(item.origin_country).as_country_name ) for item in payload.customs.commodities ] ), Postage=None, GrossPounds=package.weight.LB, GrossOunces=package.weight.OZ, ContentType=ContentType[customs.content_type or "other"].value, ContentTypeOther=customs.content_description or "N/A", Agreement=('N' if customs.certify else 'Y'), Comments=customs.content_description, LicenseNumber=customs.license_number, CertificateNumber=customs.certificate_number, InvoiceNumber=customs.invoice, ImageType="PDF", ImageLayout="ALLINONEFILE", CustomerRefNo=None, CustomerRefNo2=None, POZipCode=None, LabelDate=DF.fdatetime( (options.shipment_date or time.strftime('%Y-%m-%d')), current_format="%Y-%m-%d", output_format="%m/%d/%Y" ), HoldForManifest=None, EELPFC=customs.eel_pfc, Container=None, Length=package.length.IN, Width=package.width.IN, Height=package.height.IN, Girth=(package.girth.value if package.packaging_type == "tube" else None), ExtraServices=( ExtraServicesType(ExtraService=[s for s in extra_services]) if any(extra_services) else None ), PriceOptions=None, ActionCode=None, OptOutOfSPE=None, PermitNumber=None, AccountZipCode=None, Machinable=(options.usps_option_machinable_item or False), DestinationRateIndicator="I", MID=settings.mailer_id, LogisticsManagerMID=settings.logistics_manager_mailer_id, CRID=settings.customer_registration_id, VendorCode=None, VendorProductVersionNumber=None, RemainingBarcodes=None, ChargebackCode=None, ) return Serializable(request, XP.export)