def shipment_request(payload: ShipmentRequest, settings: Settings) -> Serializable: 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) service = ServiceType[payload.service] # Create a First Class Mail Shipment Request if service == ServiceType.usps_first_class_mail_international: return first_class_mail.shipment_request(payload, settings) # Create a GXG Shipment Request elif service == ServiceType.usps_global_express_guaranteed: return global_express_guaranteed.shipment_request(payload, settings) # Create a Priority Mail Shipment Request elif service == ServiceType.usps_priority_mail_international: return priority_mail.shipment_request(payload, settings) # Fallback to creating a Priority Express Mail Shipment Request else: return priority_express.shipment_request(payload, settings)
def rate_request(payload: RateRequest, settings: Settings) -> Serializable[RateV4Request]: """Create the appropriate USPS rate request depending on the destination :param payload: Purplship unified API rate request data :param settings: USPS connection and auth settings :return: a domestic or international USPS compatible request :raises: an OriginNotServicedError when origin country is not serviced by the carrier """ 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 is not None and payload.recipient.country_code == Country.US.name: raise DestinationNotServicedError(payload.recipient.country_code) package = Packages(payload.parcels).single options = Options(payload.options, ShipmentOption) service = (Services(payload.services, ShipmentService).first or ShipmentService.usps_all) special_services = [ getattr(option, 'value', option) for key, option in options if 'usps_option' not in key ] insurance = next( (option.value for key, option in options if 'usps_insurance' in key), options.insurance) container = PackagingType[package.packaging_type or "your_packaging"] sort_level = (SortLevelType[container.name].value if service.value in ["All", "Online"] else None) mail_type = (FirstClassMailType[container.name].value if 'first_class' in service.value else None) request = RateV4Request( USERID=settings.username, Revision="2", Package=[ PackageType( ID=0, Service=service.value, FirstClassMailType=mail_type, ZipOrigination=payload.shipper.postal_code, ZipDestination=payload.recipient.postal_code, Pounds=package.weight.LB, Ounces=package.weight.OZ, Container=container.value, Width=package.width.IN, Length=package.length.IN, Height=package.height.IN, Girth=package.girth.value, Value=insurance, AmountToCollect=options.cash_on_delivery, SpecialServices=(SpecialServicesType( SpecialService=[s for s in special_services]) if any(special_services) else None), Content=None, GroundOnly=options.usps_option_ground_only, SortBy=sort_level, Machinable=(options.usps_option_machinable_item or False), ReturnLocations=options.usps_option_return_service_info, ReturnServiceInfo=options.usps_option_return_service_info, DropOffTime=('13:30' if options.shipment_date is not None else None), ShipDate=(ShipDateType( valueOf_=DF.fdate(options.shipment_date)) if options.shipment_date is not None else None), ) ], ) return Serializable(request, XP.export)
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 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") country = ( Country[payload.recipient.country_code].value if payload.recipient.country_code else None ) 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"], MailType=PackagingType[package.packaging_type or "package"].value, GXG=None, ValueOfContents=None, Country=country, 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=datetime.today().strftime("%Y-%m-%dT%H:%M:%S"), DestinationPostalCode=payload.recipient.postal_code, ExtraServices=( ExtraServicesType( ExtraService=[ getattr(option, 'value', option) for option in extra_services ] ) if any(extra_services) else None ), Content=None, ) ], ) return Serializable(request, XP.export)
def rate_request(payload: RateRequest, settings: Settings) -> Serializable[DCTRequest]: packages = Packages(payload.parcels, PackagePresets, required=["weight"]) products = [*Services(payload.services, ProductCode)] options = Options(payload.options, SpecialServiceCode) is_international = payload.shipper.country_code != payload.recipient.country_code is_document = all([parcel.is_document for parcel in payload.parcels]) is_dutiable = not is_document if not is_international and payload.shipper.country_code in ["CA"]: raise DestinationNotServicedError(payload.shipper.country_code) paperless = (SpecialServiceCode.dhl_paperless_trade if (is_international and is_dutiable) else None) special_services = [ *options, *([(paperless.name, None)] if paperless is not None else []) ] insurance = options[ 'dhl_shipment_insurance'].value if 'dhl_shipment_insurance' in options else None if len(products) == 0: if is_international and is_document: product = 'dhl_express_worldwide_doc' elif is_international: product = 'dhl_express_worldwide_nondoc' elif is_document: product = 'dhl_express_worldwide_doc' else: product = 'dhl_express_easy_nondoc' products = [ProductCode[product]] request = DCTRequest(GetQuote=GetQuoteType( Request=settings.Request( MetaData=MetaData(SoftwareName="3PV", SoftwareVersion=1.0)), From=DCTFrom( CountryCode=payload.shipper.country_code, Postalcode=payload.shipper.postal_code, City=payload.shipper.city, Suburb=payload.shipper.state_code, ), To=DCTTo( CountryCode=payload.recipient.country_code, Postalcode=payload.recipient.postal_code, City=payload.recipient.city, Suburb=payload.recipient.state_code, ), BkgDetails=BkgDetailsType( PaymentCountryCode=payload.shipper.country_code, NetworkTypeCode=NetworkType.both_time_and_day_definite.value, WeightUnit=WeightUnit.LB.value, DimensionUnit=DimensionUnit.IN.value, ReadyTime=time.strftime("PT%HH%MM"), Date=time.strftime("%Y-%m-%d"), IsDutiable=("Y" if is_dutiable else "N"), Pieces=PiecesType(Piece=[ PieceType( PieceID=package.parcel.id or f"{index}", PackageTypeCode=DCTPackageType[package.packaging_type or "your_packaging"].value, Depth=package.length.IN, Width=package.width.IN, Height=package.height.IN, Weight=package.weight.LB, ) for index, package in enumerate( cast(Iterable[Package], packages), 1) ]), NumberOfPieces=len(packages), ShipmentWeight=packages.weight.LB, Volume=None, PaymentAccountNumber=settings.account_number, InsuredCurrency=(options.currency if insurance is not None else None), InsuredValue=insurance, PaymentType=None, AcctPickupCloseTime=None, QtdShp=[ QtdShpType( GlobalProductCode=product.value, LocalProductCode=product.value, QtdShpExChrg=[ QtdShpExChrgType( SpecialServiceType=SpecialServiceCode[key].value. key) for key, _ in special_services if key in SpecialServiceCode ], ) for product in products ], ), Dutiable=(DCTDutiable( DeclaredValue=insurance or 1.0, DeclaredCurrency=options.currency or CountryCurrency[payload.shipper.country_code].value) if is_international and is_dutiable else None), ), ) return Serializable(request, _request_serializer)
def shipment_request(payload: ShipmentRequest, settings: Settings) -> Serializable[eVSRequest]: 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 is not None and payload.recipient.country_code != Country.US.name: raise DestinationNotServicedError(payload.recipient.country_code) service = ServiceType[payload.service].value package = Packages(payload.parcels).single options = Options(payload.options, ShipmentOption) customs = payload.customs or Customs(commodities=[]) extra_services = [ getattr(option, 'value', option) for key, option in options if 'usps_option' not in key ] label_format = LabelFormat[payload.label_type or 'usps_6_x_4_label'].value insurance = next( (option.value for key, option in options if 'usps_insurance' in key), 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 = eVSRequest( USERID=settings.username, Option=None, Revision="1", ImageParameters=ImageParametersType(ImageParameter=label_format, LabelSequence=LabelSequenceType( PackageNumber=1, TotalPackages=1)), FromName=payload.shipper.person_name, FromFirm=payload.shipper.company_name or "N/A", FromAddress1=payload.shipper.address_line1, FromAddress2=payload.shipper.address_line2, FromCity=payload.shipper.city, FromState=payload.shipper.state_code, FromZip5=Location(payload.shipper.postal_code).as_zip5, FromZip4=Location(payload.shipper.postal_code).as_zip4, FromPhone=payload.shipper.phone_number, POZipCode=None, AllowNonCleansedOriginAddr=False, ToName=payload.recipient.person_name, ToFirm=payload.recipient.company_name or "N/A", ToAddress1=payload.recipient.address_line1, ToAddress2=payload.recipient.address_line2, ToCity=payload.recipient.city, ToState=payload.recipient.state_code, ToZip5=Location(payload.recipient.postal_code).as_zip5, ToZip4=Location(payload.recipient.postal_code).as_zip4, ToPhone=payload.recipient.phone_number, POBox=None, ToContactPreference=None, ToContactMessaging=payload.recipient.email, ToContactEmail=payload.recipient.email, AllowNonCleansedDestAddr=False, WeightInOunces=package.weight.OZ, ServiceType=service, Container=PackagingType[package.packaging_type or 'variable'].value, Width=package.width.IN, Length=package.length.IN, Height=package.height.IN, Girth=(package.girth.value if package.packaging_type == "tube" else None), Machinable=options["usps_option_machinable_item"], ProcessingCategory=None, PriceOptions=None, InsuredAmount=insurance, AddressServiceRequested=None, ExpressMailOptions=None, ShipDate=options.shipment_date, CustomerRefNo=None, ExtraServices=(ExtraServicesType(ExtraService=[ getattr(option, 'value', option) for option in extra_services ]) if any(extra_services) else None), CRID=None, MID=None, LogisticsManagerMID=None, VendorCode=None, VendorProductVersionNumber=None, SenderName=(payload.shipper.person_name or payload.shipper.company_name), SenderEMail=payload.shipper.email, RecipientName=(payload.recipient.person_name or payload.recipient.company_name), RecipientEMail=payload.recipient.email, ReceiptOption="SEPARATE PAGE", ImageType="PDF", HoldForManifest=None, NineDigitRoutingZip=None, ShipInfo=options["usps_option_ship_info"], CarrierRelease=None, DropOffTime=None, ReturnCommitments=None, PrintCustomerRefNo=None, Content=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 customs.commodities ]) if payload.customs is not None else None), CustomsContentType=ContentType[customs.content_type or "other"].value, ContentComments=None, RestrictionType=None, RestrictionComments=None, AESITN=customs.aes, ImportersReference=None, ImportersContact=None, ExportersReference=None, ExportersContact=None, InvoiceNumber=customs.invoice, LicenseNumber=customs.license_number, CertificateNumber=customs.certificate_number, NonDeliveryOption=non_delivery, AltReturnAddress1=redirect_address.address_line1, AltReturnAddress2=redirect_address.address_line2, AltReturnAddress3=None, AltReturnAddress4=None, AltReturnAddress5=None, AltReturnAddress6=None, AltReturnCountry=None, LabelImportType=None, ChargebackCode=None, TrackingRetentionPeriod=None, ) return Serializable(request)