def shipment_request(payload: ShipmentRequest, settings: Settings) -> Serializable[Envelope]: packages = Packages(payload.parcels) options = Options(payload.options, Option) product = Service.map(payload.service).value_or_key request = create_envelope( body_content=CreateShipment( AuthenicateAccount=Authenticate( AccountID=settings.account_id, Password=settings.password, ), ConsigneeInfo=AddressInfo( ID=payload.recipient.id, Name=payload.recipient.company_name, Address1=payload.recipient.address_line1, Address2=payload.recipient.address_line2, City=payload.recipient.city, Province=payload.recipient.state_code, Postcode=payload.recipient.postal_code, Contact=payload.recipient.person_name, Phone=payload.recipient.phone_number, ), PackageInfo=PackageInfo( Product=product, Pieces=ArrayOfPieceInfo( PieceInfo=[ PieceInfo( Weight=piece.weight.value, WeightUnit=piece.weight.unit, Length=piece.length.value, Width=piece.width.value, Height=piece.height.value, DeclaredValue=None, ) for piece in packages ] ), Contact=payload.shipper.person_name, Phone=payload.shipper.phone_number, CostCenter=options.ics_courier_cost_center, Refereces=( ArrayOfString(string=[payload.reference]) if payload.reference is not None else payload.reference ), NotificationEmail=( options.email_notification_to or payload.recipient.email_address if options.email_notification and any( [options.email_notification_to or payload.recipient.email_address] ) else None ), SpecialInstruction=options.ics_courier_special_instruction, NoSignatureRequired=options.ics_courier_no_signature_required, ShipDate=options.ship_date, ) ), ) return Serializable(request)
def rate_request(payload: RateRequest, settings: Settings) -> Serializable[mailing_scenario]: """Create the appropriate Canada Post rate request depending on the destination :param settings: Purplship carrier connection settings :param payload: Purplship unified API rate request data :return: a domestic or international Canada post compatible request :raises: an OriginNotServicedError when origin country is not serviced by the carrier """ if payload.shipper.country_code and payload.shipper.country_code != Country.CA.name: raise OriginNotServicedError(payload.shipper.country_code) package = Packages(payload.parcels, PackagePresets, required=["weight"]).single services = Services(payload.services, ServiceType) options = Options(payload.options, OptionCode) request = mailing_scenario( customer_number=settings.customer_number, contract_id=None, promo_code=None, quote_type=None, expected_mailing_date=options.shipment_date, options=(optionsType(option=[ optionType(option_code=getattr(option, 'key', option), option_amount=getattr(option, 'value', None)) for code, option in options if code in OptionCode ]) if any([c in OptionCode for c, _ in options]) else None), parcel_characteristics=parcel_characteristicsType( weight=package.weight.map(MeasurementOptions).KG, dimensions=dimensionsType( length=package.length.map(MeasurementOptions).CM, width=package.width.map(MeasurementOptions).CM, height=package.height.map(MeasurementOptions).CM, ), unpackaged=None, mailing_tube=None, oversized=None, ), services=(servicesType( service_code=[svc.value for svc in services]) if any(services) else None), origin_postal_code=payload.shipper.postal_code, destination=destinationType( domestic=( domesticType(postal_code=payload.recipient.postal_code) if (payload.recipient.country_code == Country.CA.name) else None), united_states=( united_statesType(zip_code=payload.recipient.postal_code) if (payload.recipient.country_code == Country.US.name) else None), international=(internationalType( country_code=payload.recipient.postal_code) if (payload.recipient.country_code not in [ Country.US.name, Country.CA.name ]) else None), ), ) return Serializable(request, _request_serializer)
def rate_request(payload: RateRequest, settings: Settings) -> Serializable[DicomRateRequest]: packages = Packages(payload.parcels) service = (Services(payload.services, Service).first or Service.dicom_ground_delivery).value options = Options(payload.options, Option) request = DicomRateRequest( category="Parcel", paymentType=PaymentType.prepaid.value, deliveryType=service, unitOfMeasurement=UnitOfMeasurement.KC.value, sender=Address(postalCode=payload.shipper.postal_code, provinceCode=payload.shipper.state_code, countryCode=payload.shipper.country_code, name=(payload.shipper.company_name or payload.shipper.person_name)), consignee=Address(postalCode=payload.recipient.postal_code, provinceCode=payload.recipient.state_code, countryCode=payload.recipient.country_code, name=(payload.recipient.company_name or payload.recipient.person_name)), parcels=[ Parcel( quantity=1, parcelType=ParcelType[package.packaging_type or "dicom_box"].value, id=None, weight=package.weight.KG, length=package.height.CM, depth=package.length.CM, width=package.width.CM, note=None, status=None, FCA_Class=None, hazmat=None, requestReturnLabel=None, returnWaybill=None, ) for package in packages ], billing=settings.billing_account, promoCodes=None, surcharges=[ Surcharge(type=getattr(option, 'key', option), value=getattr(option, 'value', None)) for _, option in options ], appointment=None, ) return Serializable(request, DP.to_dict)
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 rate_request(payload: RateRequest, settings: Settings) -> Serializable[RateV4Request]: package = Packages(payload.parcels).single options = Options(payload.options) service = Services(payload.services, RateService).first or RateService.usps_all special_services = Services(payload.options.keys(), SpecialService) request = RateV4Request( USERID=settings.username, Revision="2", Package=[ PackageType( ID=0, Service=service.value, FirstClassMailType=FirstClassMailType[ package.packaging_type or "your_packaging"].value, ZipOrigination=payload.shipper.postal_code, ZipDestination=payload.recipient.postal_code, Pounds=package.weight.LB, Ounces=package.weight.OZ, Container=Container[package.packaging_type or "your_packaging"].value, Width=package.width.IN, Length=package.length.IN, Height=package.height.IN, Girth=package.girth.value, Value=None, AmountToCollect=options.cash_on_delivery, SpecialServices=SpecialServicesType( SpecialService=[s.value for s in special_services]), Content=None, GroundOnly=None, SortBy=None, Machinable=("usps_machinable" in options), ReturnLocations=None, ReturnServiceInfo=None, DropOffTime=None, ShipDate=ShipDateType( valueOf_=str(datetime.today().strftime("%Y-%m-%d"))), ) ], ) return Serializable(request, XP.export)
def shipment_request(payload: ShipmentRequest, _) -> Serializable[NonContractShipmentType]: package = Packages(payload.parcels, PackagePresets, required=["weight"]).single service = ServiceType[payload.service].value options = Options(payload.options, OptionCode) is_intl = (payload.recipient.country_code is not None and payload.recipient.country_code != 'CA') all_options = ([*options] + [(OptionCode.canadapost_return_to_sender.name, OptionCode.canadapost_return_to_sender.value.apply(True))] if is_intl and not any(key in options for key in INTERNATIONAL_NON_DELIVERY_OPTION) else [*options]) request = NonContractShipmentType( requested_shipping_point=None, delivery_spec=DeliverySpecType( service_code=service, sender=SenderType( name=payload.shipper.person_name, company=payload.shipper.company_name, contact_phone=payload.shipper.phone_number, address_details=DomesticAddressDetailsType( address_line_1=SF.concat_str(payload.shipper.address_line1, join=True), address_line_2=SF.concat_str(payload.shipper.address_line2, join=True), city=payload.shipper.city, prov_state=payload.shipper.state_code, postal_zip_code=payload.shipper.postal_code, ), ), destination=DestinationType( name=payload.recipient.person_name, company=payload.recipient.company_name, additional_address_info=None, client_voice_number=payload.recipient.phone_number, address_details=DestinationAddressDetailsType( address_line_1=SF.concat_str( payload.recipient.address_line1, join=True), address_line_2=SF.concat_str( payload.recipient.address_line2, join=True), city=payload.recipient.city, prov_state=payload.recipient.state_code, country_code=payload.recipient.country_code, postal_zip_code=payload.recipient.postal_code, ), ), options=(optionsType(option=[ OptionType( option_code=getattr(option, 'key', option), option_amount=getattr(option, 'value', None), option_qualifier_1=None, option_qualifier_2=None, ) for code, option in all_options if code in OptionCode ]) if any(options) else None), parcel_characteristics=ParcelCharacteristicsType( weight=NF.decimal(package.weight.KG, .1), dimensions=dimensionsType( length=NF.decimal(package.length.CM, .1), width=NF.decimal(package.width.CM, .1), height=NF.decimal(package.height.CM, .1), ), unpackaged=None, mailing_tube=None, ), notification=(NotificationType( email=options.notification_email or payload.recipient.email, on_shipment=True, on_exception=True, on_delivery=True, ) if options.notification_email is not None else None), preferences=PreferencesType( show_packing_instructions=False, show_postage_rate=True, show_insured_value=("insurance" in payload.options), ), references=ReferencesType( cost_centre=None, customer_ref_1=payload.reference, customer_ref_2=None, ), customs=(CustomsType( currency=Currency.AUD.value, conversion_from_cad=None, reason_for_export=payload.customs.incoterm, other_reason=payload.customs.content_description, duties_and_taxes_prepaid=payload.customs.duty.account_number, certificate_number=None, licence_number=None, invoice_number=None, sku_list=sku_listType(item=[ SkuType( customs_number_of_units=item.quantity, customs_description=item.description, sku=item.sku, hs_tariff_code=None, unit_weight=WeightUnit.KG.value, customs_value_per_unit=item.value_amount, customs_unit_of_measure=None, country_of_origin=payload.shipper.country_code, province_of_origin=None, ) for item in payload.customs.commodities ]), ) if payload.customs is not None else None), settlement_info=None, ), ) return Serializable(request, _request_serializer)
def shipment_request(payload: ShipmentRequest, settings: Settings) -> Serializable[DHLShipmentRequest]: packages = Packages(payload.parcels, PackagePresets, required=["weight"]) options = Options(payload.options, SpecialServiceCode) product = ProductCode[payload.service].value insurance = options[ 'dhl_shipment_insurance'].value if 'dhl_shipment_insurance' in options else None package_type = (PackageType[packages[0].packaging_type or "your_packaging"].value if len(packages) == 1 else None) delivery_type = next( (d for d in DeliveryType if d.name in payload.options.keys()), None) has_payment_config = payload.payment is not None has_customs_config = payload.customs is not None label_format, label_template = LabelType[payload.label_type or 'PDF_6x4'].value request = DHLShipmentRequest( schemaVersion=6.2, Request=settings.Request( MetaData=MetaData(SoftwareName="3PV", SoftwareVersion=6.2)), RegionCode=CountryRegion[payload.shipper.country_code].value, RequestedPickupTime="Y", LanguageCode="en", PiecesEnabled="Y", LatinResponseInd=None, Billing=Billing( ShipperAccountNumber=settings.account_number, BillingAccountNumber=payload.payment.account_number if has_payment_config else None, ShippingPaymentType=PaymentType[payload.payment.paid_by].value if has_payment_config else None, DutyAccountNumber=payload.customs.duty.account_number if has_customs_config else None, DutyPaymentType=PaymentType[payload.customs.duty.paid_by].value if has_customs_config else None, ), Consignee=Consignee( CompanyName=payload.recipient.company_name or " ", SuiteDepartmentName=None, AddressLine=SF.concat_str(payload.recipient.address_line1, payload.recipient.address_line2), City=payload.recipient.city, Division=None, DivisionCode=payload.recipient.state_code, PostalCode=payload.recipient.postal_code, CountryCode=payload.recipient.country_code, CountryName=Country[payload.recipient.country_code].value, FederalTaxId=payload.shipper.federal_tax_id, StateTaxId=payload.shipper.state_tax_id, Contact=(Contact( PersonName=payload.recipient.person_name, PhoneNumber=payload.recipient.phone_number or "0000", Email=payload.recipient.email, )), Suburb=None, ), Commodity=[ Commodity(CommodityCode=c.sku, CommodityName=c.description) for c in payload.customs.commodities ] if payload.customs is not None else None, NewShipper=None, Shipper=Shipper( ShipperID=settings.account_number or " ", RegisteredAccount=settings.account_number, AddressLine=SF.concat_str(payload.shipper.address_line1, payload.shipper.address_line2), CompanyName=payload.shipper.company_name or " ", PostalCode=payload.shipper.postal_code, CountryCode=payload.shipper.country_code, City=payload.shipper.city, CountryName=Country[payload.shipper.country_code].value, Division=None, DivisionCode=payload.shipper.state_code, Contact=(Contact( PersonName=payload.shipper.person_name, PhoneNumber=payload.shipper.phone_number or "0000", Email=payload.shipper.email, )), ), ShipmentDetails=DHLShipmentDetails( NumberOfPieces=len(packages), Pieces=Pieces(Piece=[ Piece( PieceID=payload.parcels[index].id, PackageType=(package_type or PackageType[ package.packaging_type or "your_packaging"].value), Depth=package.length.IN, Width=package.width.IN, Height=package.height.IN, Weight=package.weight.LB, DimWeight=None, PieceContents=payload.parcels[index].description, ) for index, package in enumerate(packages) ]), Weight=packages.weight.LB, CurrencyCode=options.currency or "USD", WeightUnit=WeightUnit.L.value, DimensionUnit=DimensionUnit.I.value, Date=(options.shipment_date or time.strftime("%Y-%m-%d")), PackageType=package_type, IsDutiable=("Y" if payload.customs is not None else "N"), InsuredAmount=insurance, ShipmentCharges=(options.cash_on_delivery if options.cash_on_delivery else None), DoorTo=delivery_type, GlobalProductCode=product, LocalProductCode=product, Contents=" ", ), EProcShip=None, Dutiable=Dutiable( DeclaredCurrency=payload.customs.duty.currency or "USD", DeclaredValue=payload.customs.duty.amount, TermsOfTrade=payload.customs.incoterm, ) if payload.customs is not None and payload.customs.duty is not None else None, ExportDeclaration=None, Reference=[Reference(ReferenceID=payload.reference)], SpecialService=[ SpecialService( SpecialServiceType=SpecialServiceCode[key].value.key) for key, svc in options if key in SpecialServiceCode ], Notification=(Notification( EmailAddress=options.notification_email or payload.recipient.email) if options.notification_email is None else None), DocImages=None, RequestArchiveDoc=None, NumberOfArchiveDoc=None, LabelImageFormat=label_format, Label=Label(LabelTemplate=label_template), ODDLinkReq=None, DGs=None, ) return Serializable(request, _request_serializer)
def shipment_request( payload: ShipmentRequest, settings: Settings) -> Serializable[ProcessShipmentRequest]: packages = Packages(payload.parcels, PackagePresets, required=["weight"]) # Only the master package is selected here because even for MPS only one package is accepted for a master tracking. master_package = packages[0] package_type = (PackagingType[master_package.packaging_type or "your_packaging"].value if len(packages) == 1 else PackagingType.your_packaging.value) service = ServiceType[payload.service].value options = Options(payload.options) special_services = [ SpecialServiceType[name].value for name, value in payload.options.items() if name in SpecialServiceType.__members__ ] payment_type = PaymentType[payload.payment.paid_by or "sender"].value shipment_date = (DF.date(options.shipment_date) if 'shipment_date' in options else datetime.now()) label_type, label_format = LabelType[payload.label_type or 'PDF_4x6'].value request = ProcessShipmentRequest( WebAuthenticationDetail=settings.webAuthenticationDetail, ClientDetail=settings.clientDetail, TransactionDetail=TransactionDetail( CustomerTransactionId="IE_v25_Ship"), Version=VersionId(ServiceId="ship", Major=25, Intermediate=0, Minor=0), RequestedShipment=RequestedShipment( ShipTimestamp=shipment_date, DropoffType="REGULAR_PICKUP", ServiceType=service, PackagingType=package_type, ManifestDetail=None, TotalWeight=FedexWeight(Units=WeightUnit.LB.value, Value=packages.weight.LB), TotalInsuredValue=options.insurance, PreferredCurrency=options.currency, ShipmentAuthorizationDetail=None, Shipper=Party( AccountNumber=settings.account_number, Tins=[ TaxpayerIdentification(TinType=None, Number=tax) for tax in [ payload.shipper.federal_tax_id, payload.shipper.state_tax_id, ] ] if any([ payload.shipper.federal_tax_id, payload.shipper.state_tax_id ]) else None, Contact=Contact( ContactId=None, PersonName=payload.shipper.person_name, Title=None, CompanyName=payload.shipper.company_name, PhoneNumber=payload.shipper.phone_number, PhoneExtension=None, TollFreePhoneNumber=None, PagerNumber=None, FaxNumber=None, EMailAddress=payload.shipper.email, ) if any(( payload.shipper.company_name, payload.shipper.phone_number, payload.shipper.person_name, payload.shipper.email, )) else None, Address=Address( StreetLines=SF.concat_str(payload.shipper.address_line1, payload.shipper.address_line2), City=payload.shipper.city, StateOrProvinceCode=payload.shipper.state_code, PostalCode=payload.shipper.postal_code, UrbanizationCode=None, CountryCode=payload.shipper.country_code, CountryName=None, Residential=None, GeographicCoordinates=None, ), ), Recipient=Party( AccountNumber=None, Tins=[ TaxpayerIdentification(TinType=None, Number=tax) for tax in [ payload.recipient.federal_tax_id, payload.recipient.state_tax_id, ] ] if any([ payload.recipient.federal_tax_id, payload.recipient.state_tax_id ]) else None, Contact=Contact( ContactId=None, PersonName=payload.recipient.person_name, Title=None, CompanyName=payload.recipient.company_name, PhoneNumber=payload.recipient.phone_number, PhoneExtension=None, TollFreePhoneNumber=None, PagerNumber=None, FaxNumber=None, EMailAddress=payload.recipient.email, ) if any(( payload.recipient.company_name, payload.recipient.phone_number, payload.recipient.person_name, payload.recipient.email, )) else None, Address=Address( StreetLines=SF.concat_str( payload.recipient.address_line1, payload.recipient.address_line2, ), City=payload.recipient.city, StateOrProvinceCode=payload.recipient.state_code, PostalCode=payload.recipient.postal_code, UrbanizationCode=None, CountryCode=payload.recipient.country_code, CountryName=None, Residential=None, GeographicCoordinates=None, ), ), RecipientLocationNumber=None, Origin=None, SoldTo=None, ShippingChargesPayment=Payment( PaymentType=payment_type, Payor=Payor(ResponsibleParty=Party( AccountNumber=(payload.payment.account_number or settings.account_number), Tins=None, Contact=None, Address=None, )), ), SpecialServicesRequested=ShipmentSpecialServicesRequested( SpecialServiceTypes=special_services, CodDetail=(CodDetail( CodCollectionAmount=Money( Currency=options.currency or "USD", Amount=options.cash_on_delivery, ), AddTransportationChargesDetail=None, CollectionType=CodCollectionType.CASH, CodRecipient=None, FinancialInstitutionContactAndAddress=None, RemitToName=None, ReferenceIndicator=None, ReturnTrackingId=None, ) if options.cash_on_delivery else None), DeliveryOnInvoiceAcceptanceDetail=None, HoldAtLocationDetail=None, EventNotificationDetail=(ShipmentEventNotificationDetail( AggregationType=None, PersonalMessage=None, EventNotifications=[ ShipmentEventNotificationSpecification( Role=None, Events=NOTIFICATION_EVENTS, NotificationDetail=NotificationDetail( NotificationType="EMAIL", EmailDetail=EMailDetail( EmailAddress=options.notification_email or payload.recipient.email, Name=payload.recipient.person_name or payload.recipient.company_name, ), Localization=Localization(LanguageCode="EN", LocaleCode=None), ), FormatSpecification= ShipmentNotificationFormatSpecification( Type="TEXT"), ) ], ) if options.notification_email is None else None), ReturnShipmentDetail=None, PendingShipmentDetail=None, InternationalControlledExportDetail=None, InternationalTrafficInArmsRegulationsDetail=None, ShipmentDryIceDetail=None, HomeDeliveryPremiumDetail=None, EtdDetail=None, CustomDeliveryWindowDetail=None, ) if options.has_content else None, ExpressFreightDetail=None, FreightShipmentDetail=None, DeliveryInstructions=None, VariableHandlingChargeDetail=None, CustomsClearanceDetail=None, PickupDetail=None, SmartPostDetail=None, BlockInsightVisibility=None, LabelSpecification=LabelSpecification( Dispositions=None, LabelFormatType=LabelFormatType.COMMON_2_D.value, ImageType=label_type, LabelStockType=label_format, LabelPrintingOrientation=LabelPrintingOrientationType. TOP_EDGE_OF_TEXT_FIRST.value, LabelOrder=LabelOrderType.SHIPPING_LABEL_FIRST.value, PrintedLabelOrigin=None, CustomerSpecifiedDetail=None, ), ShippingDocumentSpecification=None, RateRequestTypes=None, EdtRequestType=None, MasterTrackingId=None, PackageCount=len(packages), ConfigurationData=None, RequestedPackageLineItems=[ RequestedPackageLineItem( SequenceNumber=1, GroupNumber=None, GroupPackageCount=None, VariableHandlingChargeDetail=None, InsuredValue=None, Weight=FedexWeight( Units=master_package.weight_unit.value, Value=master_package.weight.value, ) if master_package.weight.value else None, Dimensions=FedexDimensions( Length=master_package.length.value, Width=master_package.width.value, Height=master_package.height.value, Units=master_package.dimension_unit.value, ) if any([ master_package.length, master_package.width, master_package.height, ]) else None, PhysicalPackaging=None, ItemDescription=master_package.parcel.description, ItemDescriptionForClearance=None, CustomerReferences=None, SpecialServicesRequested=None, ContentRecords=None, ) ], ), ) return Serializable(request, _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 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 rate_request(payload: RateRequest, settings: Settings) -> Serializable[FedexRateRequest]: packages = Packages(payload.parcels, PackagePresets, required=["weight"]) service = Services(payload.services, ServiceType).first options = Options(payload.options) package_type = (PackagingType[packages[0].packaging_type or "your_packaging"].value if len(packages) == 1 else None) request_types = ["LIST" ] + ([] if "currency" not in options else ["PREFERRED"]) request = FedexRateRequest( WebAuthenticationDetail=settings.webAuthenticationDetail, ClientDetail=settings.clientDetail, TransactionDetail=TransactionDetail(CustomerTransactionId="FTC"), Version=VersionId(ServiceId="crs", Major=26, Intermediate=0, Minor=0), ReturnTransitAndCommit=True, CarrierCodes=None, VariableOptions=None, ConsolidationKey=None, RequestedShipment=RequestedShipment( ShipTimestamp=DF.date(options.shipment_date or datetime.now()), DropoffType="REGULAR_PICKUP", ServiceType=(service.value if service is not None else None), PackagingType=package_type, VariationOptions=None, TotalWeight=FedexWeight( Units=WeightUnit.LB.value, Value=packages.weight.LB, ), TotalInsuredValue=None, PreferredCurrency=options.currency, ShipmentAuthorizationDetail=None, Shipper=Party( AccountNumber=settings.account_number, Tins=([ TaxpayerIdentification(TinType=None, Number=tax) for tax in [ payload.shipper.federal_tax_id, payload.shipper.state_tax_id, ] ] if any([ payload.shipper.federal_tax_id, payload.shipper.state_tax_id ]) else None), Contact=Contact( ContactId=None, PersonName=payload.shipper.person_name, Title=None, CompanyName=payload.shipper.company_name, PhoneNumber=payload.shipper.phone_number, PhoneExtension=None, TollFreePhoneNumber=None, PagerNumber=None, FaxNumber=None, EMailAddress=payload.shipper.email, ) if any(( payload.shipper.company_name, payload.shipper.person_name, payload.shipper.phone_number, payload.shipper.email, )) else None, Address=Address( StreetLines=SF.concat_str(payload.shipper.address_line1, payload.shipper.address_line2), City=payload.shipper.city, StateOrProvinceCode=payload.shipper.state_code, PostalCode=payload.shipper.postal_code, UrbanizationCode=None, CountryCode=payload.shipper.country_code, CountryName=None, Residential=None, GeographicCoordinates=None, ), ), Recipient=Party( AccountNumber=None, Tins=[ TaxpayerIdentification(TinType=None, Number=tax) for tax in [ payload.recipient.federal_tax_id, payload.recipient.state_tax_id, ] ] if any([ payload.recipient.federal_tax_id, payload.recipient.state_tax_id ]) else None, Contact=Contact( ContactId=None, PersonName=payload.recipient.person_name, Title=None, CompanyName=payload.recipient.company_name, PhoneNumber=payload.recipient.phone_number, PhoneExtension=None, TollFreePhoneNumber=None, PagerNumber=None, FaxNumber=None, EMailAddress=payload.recipient.email, ) if any(( payload.recipient.company_name, payload.recipient.person_name, payload.recipient.phone_number, payload.recipient.email, )) else None, Address=Address( StreetLines=SF.concat_str( payload.recipient.address_line1, payload.recipient.address_line2, ), City=payload.recipient.city, StateOrProvinceCode=payload.recipient.state_code, PostalCode=payload.recipient.postal_code, UrbanizationCode=None, CountryCode=payload.recipient.country_code, CountryName=None, Residential=None, GeographicCoordinates=None, ), ), RecipientLocationNumber=None, Origin=None, SoldTo=None, ShippingChargesPayment=None, SpecialServicesRequested=None, ExpressFreightDetail=None, FreightShipmentDetail=None, DeliveryInstructions=None, VariableHandlingChargeDetail=None, CustomsClearanceDetail=None, PickupDetail=None, SmartPostDetail=None, BlockInsightVisibility=None, LabelSpecification=None, ShippingDocumentSpecification=None, RateRequestTypes=request_types, EdtRequestType=None, PackageCount=len(packages), ShipmentOnlyFields=None, ConfigurationData=None, RequestedPackageLineItems=[ RequestedPackageLineItem( SequenceNumber=index, GroupNumber=None, GroupPackageCount=1, VariableHandlingChargeDetail=None, InsuredValue=None, Weight=FedexWeight( Units=package.weight_unit.value, Value=package.weight.value, ) if package.weight.value is not None else None, Dimensions=Dimensions( Length=package.length.value, Width=package.width.value, Height=package.height.value, Units=package.dimension_unit.value, ) if any([ package.length.value, package.width.value, package.height.value, ]) else None, PhysicalPackaging=None, ItemDescription=package.parcel.description, ItemDescriptionForClearance=None, CustomerReferences=None, SpecialServicesRequested=None, ContentRecords=None, ) for index, package in enumerate(packages, 1) ], ), ) return Serializable(request, _request_serializer)
def shipment_request(payload: ShipmentRequest, settings: Settings) -> Serializable[DHLShipmentRequest]: parcel_preset = (PackagePresets[payload.parcel.package_preset].value if payload.parcel.package_preset else None) package = Package(payload.parcel, parcel_preset) if package.weight.value is None: raise RequiredFieldError("parcel.weight") is_international = payload.shipper.country_code == payload.recipient.country_code options = Options(payload.options) product = ProductCode[payload.service].value delivery_type = next( (d for d in DeliveryType if d.name in payload.options.keys()), None) special_services = [ SpecialServiceCode[s].value for s in payload.options.keys() if s in SpecialServiceCode.__members__ ] if is_international and payload.doc_images is not None: special_services.append(SpecialServiceCode.dhl_paperless_trade.value) has_payment_config = payload.payment is not None has_customs_config = payload.customs is not None request = DHLShipmentRequest( schemaVersion=6.2, Request=settings.Request( MetaData=MetaData(SoftwareName="3PV", SoftwareVersion=6.2)), RegionCode=CountryRegion[payload.shipper.country_code].value, RequestedPickupTime="Y", LanguageCode="en", PiecesEnabled="Y", LatinResponseInd=None, Billing=Billing( ShipperAccountNumber=settings.account_number, BillingAccountNumber=payload.payment.account_number if has_payment_config else None, ShippingPaymentType=PaymentType[payload.payment.paid_by].value if has_payment_config else None, DutyAccountNumber=payload.customs.duty.account_number if has_customs_config else None, DutyPaymentType=PaymentType[payload.customs.duty.paid_by].value if has_customs_config else None, ), Consignee=Consignee( CompanyName=payload.recipient.company_name or " ", SuiteDepartmentName=None, AddressLine=concat_str(payload.recipient.address_line1, payload.recipient.address_line2), City=payload.recipient.city, Division=None, DivisionCode=payload.recipient.state_code, PostalCode=payload.recipient.postal_code, CountryCode=payload.recipient.country_code, CountryName=Country[payload.recipient.country_code].value, FederalTaxId=payload.shipper.federal_tax_id, StateTaxId=payload.shipper.state_tax_id, Contact=(Contact( PersonName=payload.recipient.person_name, PhoneNumber=payload.recipient.phone_number, Email=payload.recipient.email, )), Suburb=None, ), Commodity=[ Commodity(CommodityCode=c.sku, CommodityName=c.description) for c in payload.customs.commodities ] if payload.customs is not None else None, NewShipper=None, Shipper=Shipper( ShipperID=settings.account_number or " ", RegisteredAccount=settings.account_number, AddressLine=concat_str(payload.shipper.address_line1, payload.shipper.address_line2), CompanyName=payload.shipper.company_name or " ", PostalCode=payload.shipper.postal_code, CountryCode=payload.shipper.country_code, City=payload.shipper.city, CountryName=Country[payload.shipper.country_code].value, Division=None, DivisionCode=payload.shipper.state_code, Contact=(Contact( PersonName=payload.shipper.person_name, PhoneNumber=payload.shipper.phone_number, Email=payload.shipper.email, )), ), ShipmentDetails=DHLShipmentDetails( NumberOfPieces=1, Pieces=Pieces(Piece=[ Piece( PieceID=payload.parcel.id, PackageType=PackageType[package.packaging_type or "your_packaging"].value, Depth=package.length.value, Width=package.width.value, Height=package.height.value, Weight=package.weight.value, DimWeight=None, PieceContents=payload.parcel.description, ) ]), Weight=package.weight.value, CurrencyCode=options.currency or "USD", WeightUnit=DHLWeightUnit[package.weight_unit.name].value, DimensionUnit=DHLDimensionUnit[package.dimension_unit.name].value, Date=time.strftime("%Y-%m-%d"), PackageType=PackageType[package.packaging_type].value, IsDutiable="Y" if payload.customs is not None else "N", InsuredAmount=options.insurance.amount if options.insurance else None, ShipmentCharges=options.cash_on_delivery.amount if options.cash_on_delivery else None, DoorTo=delivery_type, GlobalProductCode=product, LocalProductCode=product, Contents=" ", ), EProcShip=None, Dutiable=Dutiable( DeclaredCurrency=payload.customs.duty.currency or "USD", DeclaredValue=payload.customs.duty.amount, TermsOfTrade=payload.customs.terms_of_trade, ) if payload.customs is not None and payload.customs.duty is not None else None, ExportDeclaration=None, Reference=[Reference(ReferenceID=payload.reference)], SpecialService=[ SpecialService(SpecialServiceType=service) for service in special_services ], Notification=Notification(EmailAddress=options.notification.email or payload.shipper.email, ) if options.notification else None, LabelImageFormat="PDF", DocImages=DocImages(DocImage=[ DocImage( Type=doc.type, ImageFormat=doc.format, Image=b64decode(doc.image + "=" * (-len(doc.image) % 4)), ) for doc in payload.doc_images ]) if len(payload.doc_images) > 0 else None, RequestArchiveDoc=None, NumberOfArchiveDoc=None, Label=None, ODDLinkReq=None, DGs=None, ) return Serializable(request, _request_serializer)
def dct_request(payload: RateRequest, settings: Settings) -> Serializable[DCTRequest]: parcel_preset = (PackagePresets[payload.parcel.package_preset].value if payload.parcel.package_preset else None) package = Package(payload.parcel, parcel_preset) if package.weight.value is None: raise RequiredFieldError("parcel.weight") options = Options(payload.options) is_international = payload.shipper.country_code != payload.recipient.country_code is_dutiable = not payload.parcel.is_document products = [ ProductCode[svc].value for svc in payload.services if svc in ProductCode.__members__ ] special_services = [ SpecialServiceCode[s].value for s in payload.options.keys() if s in SpecialServiceCode.__members__ ] if is_international and is_dutiable: special_services.append(SpecialServiceCode.dhl_paperless_trade.value) if len(products) == 0: if is_international: products = [(ProductCode.dhl_express_worldwide_doc if payload.parcel.is_document else ProductCode.dhl_express_worldwide_nondoc).value] else: products = [ (ProductCode.dhl_express_easy_doc if payload.parcel.is_document else ProductCode.dhl_express_easy_nondoc).value ] 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=package.weight_unit.value, DimensionUnit=package.dimension_unit.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=payload.parcel.id or "1", PackageTypeCode=DCTPackageType[package.packaging_type or "your_packaging"].value, Depth=package.length.value, Width=package.width.value, Height=package.height.value, Weight=package.weight.value, ) ]), NumberOfPieces=1, ShipmentWeight=package.weight.value, Volume=None, PaymentAccountNumber=settings.account_number, InsuredCurrency=options.currency if options.insurance is not None else None, InsuredValue=options.insurance.amount if options.insurance is not None else None, PaymentType=None, AcctPickupCloseTime=None, QtdShp=[ QtdShpType( GlobalProductCode=product, LocalProductCode=product, QtdShpExChrg=[ QtdShpExChrgType(SpecialServiceType=service) for service in special_services ], ) for product in products ], ), Dutiable=DCTDutiable( DeclaredValue=payload.options.get('value', 1.0), DeclaredCurrency=options.currency, ) if is_international and is_dutiable else None, ), ) return Serializable(request, _request_serializer)
def _shipment_request(payload: ShipmentRequest, settings: Settings) -> Serializable[Envelope]: packages = Packages(payload.parcels, PackagePresets, required=["weight"]) service = Product.map(payload.service).value_or_key options = Options(payload.options, Service) is_document = all([parcel.is_document for parcel in payload.parcels]) package_description = packages[0].parcel.description if len( packages) == 1 else None is_international = (payload.shipper.country_code != payload.recipient.country_code) shipper_phone_number = Phone(payload.shipper.phone_number, payload.shipper.country_code) recipient_phone_number = Phone(payload.recipient.phone_number, payload.recipient.country_code) printing = PrintType.map(payload.label_type or "PDF").value option_ids = [(key, value) for key, value in options if key in Service and key not in NON_OFFICIAL_SERVICES] request = create_envelope( header_content=RequestContext( Version="2.1", Language=settings.language, GroupID="", RequestReference=(getattr(payload, 'id', None) or ""), UserToken=settings.user_token, ), body_content=CreateShipmentRequest( Shipment=Shipment( SenderInformation=SenderInformation( Address=Address( Name=payload.shipper.person_name, Company=payload.shipper.company_name, Department=None, StreetNumber="", StreetSuffix=None, StreetName=SF.concat_str(payload.shipper.address_line1, join=True), StreetType=None, StreetDirection=None, Suite=None, Floor=None, StreetAddress2=SF.concat_str( payload.shipper.address_line2, join=True), StreetAddress3=None, City=payload.shipper.city or "", Province=payload.shipper.state_code or "", Country=payload.shipper.country_code or "", PostalCode=payload.shipper.postal_code or "", PhoneNumber=PhoneNumber( CountryCode=shipper_phone_number.country_code or "0", AreaCode=shipper_phone_number.area_code or "0", Phone=shipper_phone_number.phone or "0", Extension=None, ), FaxNumber=None, ), TaxNumber=(payload.shipper.federal_tax_id or payload.shipper.state_tax_id), ), ReceiverInformation=ReceiverInformation( Address=Address( Name=payload.recipient.person_name, Company=payload.recipient.company_name, Department=None, StreetNumber="", StreetSuffix=None, StreetName=SF.concat_str( payload.recipient.address_line1, join=True), StreetType=None, StreetDirection=None, Suite=None, Floor=None, StreetAddress2=SF.concat_str( payload.recipient.address_line2, join=True), StreetAddress3=None, City=payload.recipient.city or "", Province=payload.recipient.state_code or "", Country=payload.recipient.country_code or "", PostalCode=payload.recipient.postal_code or "", PhoneNumber=PhoneNumber( CountryCode=recipient_phone_number.country_code or "0", AreaCode=recipient_phone_number.area_code or "0", Phone=recipient_phone_number.phone or "0", Extension=None, ), FaxNumber=None, ), TaxNumber=(payload.recipient.federal_tax_id or payload.recipient.state_tax_id), ), FromOnLabelIndicator=None, FromOnLabelInformation=None, ShipmentDate=options.shipment_date, PackageInformation=PackageInformation( ServiceID=service, Description=package_description, TotalWeight=(TotalWeight( Value=packages.weight.map(MeasurementOptions).LB, WeightUnit=PurolatorWeightUnit.LB.value, ) if packages.weight.value else None), TotalPieces=1, PiecesInformation=ArrayOfPiece(Piece=[ Piece( Weight=(PurolatorWeight( Value=package.weight.map(MeasurementOptions). value, WeightUnit=PurolatorWeightUnit[ package.weight_unit.value].value, ) if package.weight.value else None), Length=(PurolatorDimension( Value=package.length.map(MeasurementOptions). value, DimensionUnit=PurolatorDimensionUnit[ package.dimension_unit.value].value, ) if package.length.value else None), Width=(PurolatorDimension( Value=package.width.map(MeasurementOptions). value, DimensionUnit=PurolatorDimensionUnit[ package.dimension_unit.value].value, ) if package.width.value else None), Height=(PurolatorDimension( Value=package.height.map(MeasurementOptions). value, DimensionUnit=PurolatorDimensionUnit[ package.dimension_unit.value].value, ) if package.height.value else None), Options=None, ) for package in packages ]), DangerousGoodsDeclarationDocumentIndicator=None, OptionsInformation=(ArrayOfOptionIDValuePair( OptionIDValuePair=[ OptionIDValuePair(ID=key, Value=value) for key, value in option_ids ]) if any(option_ids) else None), ), InternationalInformation=(InternationalInformation( DocumentsOnlyIndicator=is_document, ContentDetails=(ArrayOfContentDetail(ContentDetail=[ ContentDetail( Description=c.description, HarmonizedCode=None, CountryOfManufacture=c.origin_country, ProductCode=c.sku, UnitValue=c.value_amount, Quantity=c.quantity, NAFTADocumentIndicator=None, FDADocumentIndicator=None, FCCDocumentIndicator=None, SenderIsProducerIndicator=None, TextileIndicator=None, TextileManufacturer=None, ) for c in payload.customs.commodities ]) if not is_document else None), BuyerInformation=None, PreferredCustomsBroker=None, DutyInformation=(DutyInformation( BillDutiesToParty=DutyPaymentType[ payload.customs.duty.paid_by].value, BusinessRelationship=BusinessRelationship.NOT_RELATED. value, Currency=payload.customs.duty.currency, ) if payload.customs is not None else None), ImportExportType=None, CustomsInvoiceDocumentIndicator=None, ) if is_international else None), ReturnShipmentInformation=None, PaymentInformation=(PaymentInformation( PaymentType=PaymentType[payload.payment.paid_by].value, RegisteredAccountNumber=(payload.payment.account_number or settings.account_number), BillingAccountNumber=(payload.payment.account_number or settings.account_number), CreditCardInformation=None, ) if payload.payment is not None else None), PickupInformation=PickupInformation( PickupType=PickupType.DROP_OFF.value), NotificationInformation=( NotificationInformation( ConfirmationEmailAddress=(options.email_notification_to or payload.recipient.email)) if options.email_notification and any([ options.email_notification_to, payload.recipient.email ]) else None), TrackingReferenceInformation=(TrackingReferenceInformation( Reference1=payload.reference) if any(payload.reference or "") else None), OtherInformation=None, ProactiveNotification=None, ), PrinterType=PrinterType(printing).value, ), ) return Serializable(request, standard_request_serializer)
def freight_ship_request( payload: ShipmentRequest, settings: Settings ) -> Serializable[FreightShipRequest]: dimension_unit = DimensionUnit[payload.parcel.dimension_unit or "IN"] weight_unit = WeightUnit[payload.parcel.weight_unit or "LB"] options = Options(payload.options) service = ShippingServiceCode[payload.service].value freight_class = FreightClass[ payload.options.get("ups_freight_class", "ups_freight_class_50") ].value request = FreightShipRequest( Request=common.RequestType( RequestOption="1", SubVersion=None, TransactionReference=common.TransactionReferenceType( CustomerContext=payload.reference, TransactionIdentifier=None ), ), Shipment=ShipmentType( ShipFrom=ShipFromType( Name=payload.shipper.company_name, TaxIdentificationNumber=payload.shipper.federal_tax_id, TaxIDType=None, TariffPoint=None, Address=FreightShipAddressType( AddressLine=concat_str( payload.shipper.address_line1, payload.shipper.address_line2 ), City=payload.shipper.city, StateProvinceCode=payload.shipper.state_code, Town=None, PostalCode=payload.shipper.postal_code, CountryCode=payload.shipper.country_code, ), AttentionName=payload.shipper.person_name, Phone=FreightShipPhoneType( Number=payload.shipper.phone_number, Extension=None ) if payload.shipper.phone_number is not None else None, FaxNumber=None, EMailAddress=payload.shipper.email, ), ShipperNumber=settings.account_number, ShipTo=ShipToType( Name=payload.recipient.company_name, TaxIdentificationNumber=payload.recipient.federal_tax_id, Address=FreightShipAddressType( AddressLine=concat_str( payload.recipient.address_line1, payload.recipient.address_line2, ), City=payload.recipient.city, StateProvinceCode=payload.recipient.state_code, Town=None, PostalCode=payload.recipient.postal_code, CountryCode=payload.recipient.country_code, ), TariffPoint=None, AttentionName=payload.recipient.person_name, Phone=PhoneType(Number=payload.recipient.phone_number, Extension=None) if payload.recipient.phone_number is not None else None, FaxNumber=None, EMailAddress=payload.recipient.email, ), PaymentInformation=None, ManufactureInformation=None, Service=ShipCodeDescriptionType(Code=service) if service is not None else None, HandlingUnitOne=None, HandlingUnitTwo=None, ExistingShipmentID=None, HandlingInstructions=None, DeliveryInstructions=None, PickupInstructions=None, SpecialInstructions=None, ShipmentTotalWeight=None, Commodity=[ CommodityType( CommodityID=payload.parcel.id, Description=payload.parcel.description, Weight=WeightType( UnitOfMeasurement=FreightShipUnitOfMeasurementType( Code=UPSWeightUnit[weight_unit.name].value ), Value=Weight(payload.parcel.weight, weight_unit).value, ), Dimensions=DimensionsType( UnitOfMeasurement=FreightShipUnitOfMeasurementType( Code=dimension_unit.value ), Width=Dimension(payload.parcel.width, dimension_unit).value, Height=Dimension(payload.parcel.height, dimension_unit).value, Length=Dimension(payload.parcel.length, dimension_unit).value, ) if any( [ payload.parcel.width, payload.parcel.height, payload.parcel.length, ] ) else None, NumberOfPieces=None, PackagingType=None, DangerousGoodsIndicator=None, CommodityValue=None, FreightClass=freight_class, NMFCCommodityCode=None, NMFCCommodity=None, ) ], Reference=None, ShipmentServiceOptions=ShipmentServiceOptionsType( EMailInformation=[ EMailNotificationType( EMailAddress=options.notification.email or payload.shipper.email, EventType=NOTIFICATION_EVENT_TYPES, ) ] if options.notification else None, PickupOptions=None, DeliveryOptions=None, OverSeasLeg=None, COD=CODType( CODValue=CODValueType( CurrencyCode=options.currency or "USD", MonetaryValue=options.cash_on_delivery.amount, ), CODPaymentMethod=None, CODBillingOption=None, RemitTo=None, ) if options.cash_on_delivery else None, DangerousGoods=None, SortingAndSegregating=None, DeclaredValue=None, ExcessDeclaredValue=None, CustomsValue=None, DeliveryDutiesPaidIndicator=None, DeliveryDutiesUnpaidIndicator=None, HandlingCharge=None, CustomsClearanceIndicator=None, FreezableProtectionIndicator=None, ExtremeLengthIndicator=None, LinearFeet=None, ) if options.has_content else None, PickupRequest=None, Documents=None, ITNNumber=None, TaxID=None, MovementReferenceNumber=None, EICNumberAndStatement=None, TimeInTransitIndicator=None, HandlingUnits=None, DensityEligibleIndicator=None, ), ) return Serializable( create_envelope(header_content=settings.Security, body_content=request), _request_serializer, )
def shipment_request(payload: ShipmentRequest, settings: Settings) -> Serializable[UPSShipmentRequest]: packages = Packages(payload.parcels, PackagePresets) is_document = all([parcel.is_document for parcel in payload.parcels]) package_description = packages[0].parcel.description if len( packages) == 1 else None options = Options(payload.options) service = ShippingServiceCode[payload.service].value if any(key in service for key in ["freight", "ground"]): packages.validate(required=["weight"]) charges: Dict[str, Payment] = { "01": payload.payment, "02": payload.customs.duty if payload.customs is not None else None, } mps_packaging = (ShippingPackagingType.your_packaging.value if len(packages) > 1 else None) label_format, label_height, label_width = LabelType[payload.label_type or 'PDF_6x4'].value request = UPSShipmentRequest( Request=common.RequestType( RequestOption=["validate"], SubVersion=None, TransactionReference=common.TransactionReferenceType( CustomerContext=payload.reference, TransactionIdentifier=None), ), Shipment=ShipmentType( Description=package_description, DocumentsOnlyIndicator="" if is_document else None, Shipper=ShipperType( Name=payload.shipper.company_name, AttentionName=payload.shipper.person_name, CompanyDisplayableName=None, TaxIdentificationNumber=payload.shipper.federal_tax_id, TaxIDType=None, Phone=(ShipPhoneType(Number=payload.shipper.phone_number, Extension=None) if payload.shipper.phone_number is not None else None), ShipperNumber=settings.account_number, FaxNumber=None, EMailAddress=payload.shipper.email, Address=ShipAddressType( AddressLine=SF.concat_str(payload.shipper.address_line1, payload.shipper.address_line2), City=payload.shipper.city, StateProvinceCode=payload.shipper.state_code, PostalCode=payload.shipper.postal_code, CountryCode=payload.shipper.country_code, ), ), ShipTo=ShipToType( Name=payload.recipient.company_name, AttentionName=payload.recipient.person_name, CompanyDisplayableName=None, TaxIdentificationNumber=payload.recipient.federal_tax_id, TaxIDType=None, Phone=(ShipPhoneType(Number=payload.recipient.phone_number, Extension=None) if payload.recipient.phone_number is not None else None), FaxNumber=None, EMailAddress=payload.recipient.email, Address=ShipAddressType( AddressLine=SF.concat_str( payload.recipient.address_line1, payload.recipient.address_line2, ), City=payload.recipient.city, StateProvinceCode=payload.recipient.state_code, PostalCode=payload.recipient.postal_code, CountryCode=payload.recipient.country_code, ), ), PaymentInformation=PaymentInfoType( ShipmentCharge=[ ShipmentChargeType( Type=charge_type, BillShipper=BillShipperType( AccountNumber=settings.account_number, CreditCard=None, AlternatePaymentMethod=None, ) if payment.paid_by == PaymentType.sender.name else None, BillReceiver=BillReceiverType( AccountNumber=payment.account_number, Address=BillReceiverAddressType( PostalCode=payload.recipient.postal_code), ) if payment.paid_by == PaymentType.recipient.name else None, BillThirdParty=BillThirdPartyChargeType( AccountNumber=payment.account_number, ) if payment. paid_by == PaymentType.third_party.name else None, ConsigneeBilledIndicator=None, ) for charge_type, payment in charges.items() if payment is not None ], SplitDutyVATIndicator=None, ) if any(charges.values()) else None, Service=(ServiceType( Code=service) if service is not None else None), ShipmentServiceOptions=(ShipmentServiceOptionsType( COD=(CODType( CODFundsCode=None, CODAmount=CurrencyMonetaryType( CurrencyCode=options.currency or "USD", MonetaryValue=options.cash_on_delivery, ), ) if options.cash_on_delivery else None), Notification=([ NotificationType( NotificationCode=event, EMail=EmailDetailsType(EMailAddress=[ options.notification_email or payload.recipient.email ]), VoiceMessage=None, TextMessage=None, Locale=None, ) for event in [8] ] if options.notification_email is not None else None), ) if any([options.cash_on_delivery, options.notification_email]) else None), Package=[ PackageType( Description=package.parcel.description, Packaging=PackagingType( Code=mps_packaging or ShippingPackagingType[ package.packaging_type or "your_packaging"].value), Dimensions=DimensionsType( UnitOfMeasurement=ShipUnitOfMeasurementType( Code=package.dimension_unit.value, ), Length=package.length.value, Width=package.width.value, Height=package.height.value, ), PackageWeight=PackageWeightType( UnitOfMeasurement=ShipUnitOfMeasurementType( Code=UPSWeightUnit[ package.weight_unit.name].value, ), Weight=package.weight.value, ), ) for package in packages ], ), LabelSpecification=LabelSpecificationType( LabelImageFormat=LabelImageFormatType(Code=label_format, Description=None), HTTPUserAgent=None, LabelStockSize=LabelStockSizeType(Height=label_height, Width=label_width), Instruction=None, CharacterSet=None, ), ReceiptSpecification=None, ) return Serializable( create_envelope(header_content=settings.Security, body_content=request), _request_serializer, )
def non_contract_shipment_request( payload: ShipmentRequest, settings: Settings) -> Serializable[NonContractShipmentType]: package = Packages(payload.parcels, PackagePresets).single if package.weight.value is None: raise FieldError({"parcel.weight": FieldErrorCode.required}) service = ServiceType[payload.service].value options = Options(payload.options) def compute_amount(code: str, _: Any): if code == OptionCode.insurance.value: return options.insurance.amount if code == OptionCode.cash_on_delivery.value: return options.cash_on_delivery.amount return None special_services = { OptionCode[name].value: compute_amount(OptionCode[name].value, value) for name, value in payload.options.items() if name in OptionCode.__members__ } request = NonContractShipmentType( requested_shipping_point=None, delivery_spec=DeliverySpecType( service_code=service, sender=SenderType( name=payload.shipper.person_name, company=payload.shipper.company_name, contact_phone=payload.shipper.phone_number, address_details=DomesticAddressDetailsType( address_line_1=concat_str(payload.shipper.address_line1, join=True), address_line_2=concat_str(payload.shipper.address_line2, join=True), city=payload.shipper.city, prov_state=payload.shipper.state_code, postal_zip_code=payload.shipper.postal_code, ), ), destination=DestinationType( name=payload.recipient.person_name, company=payload.recipient.company_name, additional_address_info=None, client_voice_number=None, address_details=DestinationAddressDetailsType( address_line_1=concat_str(payload.recipient.address_line1, join=True), address_line_2=concat_str(payload.recipient.address_line2, join=True), city=payload.recipient.city, prov_state=payload.recipient.state_code, country_code=payload.recipient.country_code, postal_zip_code=payload.recipient.postal_code, ), ), options=optionsType(option=[ OptionType( option_code=code, option_amount=amount, option_qualifier_1=None, option_qualifier_2=None, ) for code, amount in special_services.items() ]) if len(special_services) > 0 else None, parcel_characteristics=ParcelCharacteristicsType( weight=package.weight.KG, dimensions=dimensionsType( length=package.length.CM, width=package.width.CM, height=package.height.CM, ), unpackaged=None, mailing_tube=None, ), notification=NotificationType( email=options.notification.email or payload.shipper.email, on_shipment=True, on_exception=True, on_delivery=True, ) if options.notification else None, preferences=PreferencesType( show_packing_instructions=True, show_postage_rate=True, show_insured_value=("insurance" in payload.options)), references=ReferencesType( cost_centre=None, customer_ref_1=payload.reference, customer_ref_2=None, ), customs=CustomsType( currency=Currency.AUD.value, conversion_from_cad=None, reason_for_export=payload.customs.terms_of_trade, other_reason=payload.customs.description, duties_and_taxes_prepaid=payload.customs.duty.account_number, certificate_number=None, licence_number=None, invoice_number=None, sku_list=sku_listType(item=[ SkuType( customs_number_of_units=item.quantity, customs_description=item.description, sku=item.sku, hs_tariff_code=None, unit_weight=WeightUnit.KG.value, customs_value_per_unit=item.value_amount, customs_unit_of_measure=None, country_of_origin=payload.shipper.country_code, province_of_origin=None, ) for item in payload.customs.commodities ]), ) if payload.customs is not None else None, settlement_info=None, ), ) return Serializable(request, _request_serializer)
def shipment_request( payload: ShipmentRequest, settings: Settings ) -> Serializable[Envelope]: packages = Packages(payload.parcels, PackagePresets) packages.validate(required=["weight"]) options = Options(payload.options, ServiceOption) service = ServiceCode.map(payload.service).value_or_key ship_from = CompleteAddress.map(payload.shipper) ship_to = CompleteAddress.map(payload.shipper) payment_account_number = getattr( payload.payment, "account_number", settings.account_number ) payment_address = getattr(payload.payment, "address", None) mps_packaging = PackagingType.your_packaging.value if len(packages) > 1 else None payer = dict( sender=payment_address or ship_from, recipient=payment_address or ship_to, third_party=payment_address, )[getattr(payload.payment, "paid_by", "sender")] label_format, label_height, label_width = LabelType[ payload.label_type or "PDF_6x4" ].value request = create_envelope( header_content=settings.Security, body_content=FreightShipRequest( Request=RequestType( RequestOption=1, SubVersion=1607, TransactionReference=TransactionReferenceType( CustomerContext=payload.reference, TransactionIdentifier=getattr(payload, "id", None), ), ), Shipment=ShipmentType( ShipFrom=ShipFromType( Name=ship_from.company_name, Address=AddressType( AddressLine=ship_from.address_line, City=ship_from.city, StateProvinceCode=ship_from.state_code, Town=None, PostalCode=ship_from.postal_code, CountryCode=ship_from.country_code, ResidentialAddressIndicator=( "" if ship_from.residential else None ), ), TariffPoint=None, AttentionName=ship_from.person_name, Phone=PhoneType(Number=ship_from.phone_number), FaxNumber=None, EMailAddress=ship_from.email, ), ShipTo=ShipToType( Name=ship_to.company_name, TaxIdentificationNumber=None, Address=AddressType( AddressLine=ship_to.address_line, City=ship_to.city, StateProvinceCode=ship_to.state_code, Town=None, PostalCode=ship_to.postal_code, CountryCode=ship_to.country_code, ResidentialAddressIndicator=( "" if ship_to.residential else None ), ), TariffPoint=None, AttentionName=ship_to.person_name, Phone=PhoneType(Number=ship_to.phone_number), FaxNumber=None, EMailAddress=ship_to.email, ), PaymentInformation=PaymentInformationType( Payer=PayerType( Name=payer.company_name, Address=AddressType( AddressLine=payer.address_line, City=payer.city, StateProvinceCode=payer.state_code, Town=None, CountryCode=payer.country_code, PostalCode=payer.postal_code, ResidentialAddressIndicator=( "" if payer.residential else None ), ), ShipperNumber=payment_account_number, AttentionName=payer.person_name, Phone=PhoneType(Number=payer.phone_number), FaxNumber=None, EMailAddress=payer.email, ), ShipmentBillingOption=ShipCodeDescriptionType( Code=40, Description="Freight Collect" ), ), ManufactureInformation=None, Service=( ShipCodeDescriptionType(Code=service, Description=None) if service is not None else None ), HandlingUnitOne=None, HandlingUnitTwo=None, ExistingShipmentID=None, HandlingInstructions=None, DeliveryInstructions=None, PickupInstructions=None, SpecialInstructions=None, ShipmentTotalWeight=ShipmentTotalWeightType( Value=packages.weight.value, UnitOfMeasurement=UPSWeightUnit[packages.weight.unit].value, ), Commodity=[ CommodityType( CommodityID=getattr(commodity, "id", None), Description=commodity.parcel.description, Weight=WeightType( Value=commodity.weight.value, UnitOfMeasurement=UnitOfMeasurementType( Code=UPSWeightUnit[commodity.weight_unit.name].value, ), ), AdjustedWeight=None, Dimensions=( DimensionsType( UnitOfMeasurement=UnitOfMeasurementType( Code=commodity.dimension_unit.value, Description=None, ), Length=commodity.length.value, Width=commodity.width.value, Height=commodity.height.value, ) if commodity.has_dimensions else None ), NumberOfPieces=1, PackagingType=ShipCodeDescriptionType( Code=( mps_packaging or PackagingType[ commodity.packaging_type or "your_packaging" ].value ), ), DangerousGoodsIndicator=( "" if options.dangerous_good else None ), CommodityValue=None, FreightClass=FreightClass.map( options.freight_class or 50 ).value, NMFCCommodity=None, NMFCCommodityCode=None, ) for commodity in packages ], Reference=( [ ReferenceType( Number=ReferenceNumberType( Code="OTHER", Value=payload.reference ) ) ] if any(payload.reference or "") else None ), ShipmentServiceOptions=( ShipmentServiceOptionsType( EMailInformation=( [ EMailInformationType( EMailType=f"000{email_type}", EMail=options.email_notification_to or payload.recipient.email, ) for email_type in [1, 2, 3, 4] ] if any( [options.email_notification_to, payload.recipient.email] ) else None ), COD=( CODType( CODValue=CODValueType( CurrencyCode=options.currency or "USD", MonetaryValue=options.cash_on_delivery, ), CODPaymentMethod=ShipCodeDescriptionType(Code="M"), CODBillingOption=ShipCodeDescriptionType(Code="02"), RemitTo=RemitToType( Name=payer.company_name, Address=FreightShipAddressType( AddressLine=payer.address_line, City=payer.city, StateProvinceCode=payer.state_code, Town=payer.city, PostalCode=payer.postal_code, CountryCode=payer.country_code, ResidentialAddressIndicator=( "" if payer.residential else None ), ), AttentionName=payer.person_name, Phone=( FreightShipPhoneType(Number=payer.phone_number) if payer.phone_number else None ), FaxNumber=None, EMailAddress=payer.email, ), ) if options.cash_on_delivery else None ), DangerousGoods=( DangerousGoodsType( Name=(ship_from.company_name or ship_from.person_name), Phone=( FreightShipPhoneType(Number=payer.phone_number) if payer.phone_number else None ), ) if options.dangerous_good else None ), DeclaredValue=( DeclaredValueType( CurrencyCode=options.currency or "USD", MonetaryValue=options.declared_value, ) if options.declared_value else None ), ) if any( [ options.cash_on_delivery, options.email_notification, options.dangerous_good, options.declared_value, ] ) else None ), PickupRequest=None, Documents=DocumentsType( Image=ImageType( Type=ShipCodeDescriptionType(Code="30"), LabelsPerPage=1, Format=ShipCodeDescriptionType(Code="01"), PrintFormat=ShipCodeDescriptionType( Code="02" if "ZPL" in label_format else "01" ), PrintSize=PrintSizeType(Length=label_height, Width=label_width), ) ), ITNNumber=None, TaxID=None, MovementReferenceNumber=None, EICNumberAndStatement=None, TimeInTransitIndicator=None, HandlingUnits=None, DensityEligibleIndicator=None, ), ), ) return Serializable(request, _request_serializer)
def shipment_request(payload: ShipmentRequest, settings: Settings) -> Serializable[ESHIPPER]: ref = f"ref_{uuid4()}" options = Options(payload.options, ShipmentOption) package = Packages(payload.parcels).single service = ShipmentService.map(payload.service).value_or_key payment = payload.payment or Payment(paid_by='sender') insurance = getattr(options.tnt_insurance, 'value', None) request = ESHIPPER( LOGIN=LOGIN( COMPANY=settings.username, PASSWORD=settings.password, APPID='EC', APPVERSION=3.1, ), CONSIGNMENTBATCH=CONSIGNMENTBATCH( GROUPCODE=None, SENDER=SENDER( COMPANYNAME=payload.shipper.company_name, STREETADDRESS1=payload.shipper.address_line1, STREETADDRESS2=payload.shipper.address_line2, STREETADDRESS3=None, CITY=payload.shipper.city, PROVINCE=payload.shipper.state_code, POSTCODE=payload.shipper.postal_code, COUNTRY=payload.shipper.country_code, ACCOUNT=settings.account_number, VAT=(payload.shipper.state_tax_id or payload.shipper.federal_tax_id), CONTACTNAME=payload.shipper.person_name, CONTACTDIALCODE=None, CONTACTTELEPHONE=payload.shipper.phone_number, CONTACTEMAIL=payload.shipper.email, COLLECTION=None, ), CONSIGNMENT=CONSIGNMENT( CONREF=ref, DETAILS=DETAILS( RECEIVER=RECEIVER( COMPANYNAME=payload.recipient.company_name, STREETADDRESS1=payload.recipient.address_line1, STREETADDRESS2=payload.recipient.address_line2, STREETADDRESS3=None, CITY=payload.recipient.city, PROVINCE=payload.recipient.state_code, POSTCODE=payload.recipient.postal_code, COUNTRY=payload.recipient.country_code, VAT=(payload.recipient.state_tax_id or payload.recipient.federal_tax_id), CONTACTNAME=payload.recipient.person_name, CONTACTDIALCODE=None, CONTACTTELEPHONE=payload.recipient.phone_number, CONTACTEMAIL=payload.recipient.email, ACCOUNT=None, ACCOUNTCOUNTRY=None, ), DELIVERY=None, CONNUMBER=None, CUSTOMERREF=payload.reference, CONTYPE=('D' if package.parcel.is_document else 'N'), PAYMENTIND=PaymentType[payment.paid_by or 'sender'].value, ITEMS=1, TOTALWEIGHT=package.weight.KG, TOTALVOLUME=package.volume, CURRENCY=options.currency, GOODSVALUE=insurance, INSURANCEVALUE=insurance, INSURANCECURRENCY=options.currency, DIVISION=None, SERVICE=service, OPTION=[ getattr(option, 'key', option) for _, option in options ], DESCRIPTION=package.parcel.content, DELIVERYINST=None, CUSTOMCONTROLIN=None, HAZARDOUS=None, UNNUMBER=None, PACKINGGROUP=None, PACKAGE=PACKAGE( ITEMS=1, DESCRIPTION=package.parcel.description, LENGTH=package.length.M, HEIGHT=package.height.M, WIDTH=package.width.M, WEIGHT=package.weight.KG, ARTICLE=([ ARTICLE(ITEMS=article.quantity, DESCRIPTION=article.description, WEIGHT=Weight( article.weight, WeightUnit[article.weight_unit]).KG, INVOICEVALUE=article.value_amount, INVOICEDESC=None, HTS=article.sku, COUNTRY=article.origin_country) for article in payload.customs.commodities ] if payload.customs is not None and any(payload.customs.commodities) else None)), ), CONNUMBER=None, )), ACTIVITY=ACTIVITY(CREATE=CREATE(CONREF=ref), RATE=RATE(CONREF=ref), BOOK=BOOK(CONREF=ref), SHIP=SHIP(CONREF=ref), PRINT=PRINT( REQUIRED=REQUIRED(CONREF=ref), CONNOTE=CONNOTE(CONREF=ref), LABEL=LABEL(CONREF=ref), MANIFEST=MANIFEST(CONREF=ref), INVOICE=INVOICE(CONREF=ref), EMAILTO=payload.recipient.email, EMAILFROM=payload.shipper.email, ), SHOW_GROUPCODE=None)) return Serializable(request, XP.to_xml)
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)
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[ShippingRequest]: package = Packages(payload.parcels).single options = Options(payload.options, Option) product_code = Service.map(payload.service).value_or_key unique_id = getattr(payload, 'id', uuid4().hex) customs = payload.customs or Customs(commodities=[]) request = ShippingRequest( accountNumber=settings.account_number, subAccountNumber=options.asendia_sub_account_number, processingLocation=ProcessingLocation.map( options.asendia_processing_location or "SFO").name, includeRate=True, labelType=LabelType.map(payload.label_type or "PDF").name_or_key, orderNumber=unique_id, dispatchNumber=unique_id, packageID=unique_id, recipientTaxID=payload.recipient.state_tax_id, returnFirstName=payload.shipper.person_name, returnLastName=payload.shipper.person_name, returnCompanyName=payload.shipper.company_name, returnAddressLine1=payload.shipper.address_line1, returnAddressLine2=payload.shipper.address_line2, returnAddressLine3=None, returnProvince=payload.shipper.state_code, returnPostalCode=payload.shipper.postal_code, returnCountryCode=payload.shipper.country_code, returnPhone=payload.shipper.phone_number, returnEmail=payload.shipper.email, recipientFirstName=payload.recipient.person_name, recipientLastName=payload.recipient.person_name, recipientBusinessName=payload.recipient.company_name, recipientAddressLine1=payload.recipient.address_line1, recipientAddressLine2=payload.recipient.address_line2, recipientAddressLine3=None, recipientCity=payload.recipient.city, recipientProvince=payload.recipient.state_code, recipientPostalCode=payload.recipient.postal_code, recipientPhone=payload.recipient.phone_number, recipientEmail=payload.recipient.email, totalPackageWeight=package.weight.value, weightUnit=package.weight_unit.value.lower(), dimLength=package.length.value, dimWidth=package.width.value, dimHeight=package.height.value, dimUnit=package.dimension_unit.value, totalPackageValue=options.declared_value, currencyType=options.currency, productCode=product_code, customerReferenceNumber1=payload.reference, customerReferenceNumber2=None, customerReferenceNumber3=None, contentType=("D" if package.parcel.is_document else "M"), packageContentDescription=package.parcel.description, vatNumber=None, sellerName=payload.shipper.person_name, sellerAddressLine1=payload.shipper.address_line1, sellerAddressLine2=payload.shipper.address_line2, sellerAddressLine3=None, sellerProvince=payload.shipper.state_code, sellerPostalCode=payload.shipper.postal_code, sellerPhone=payload.shipper.phone_number, sellerEmail=payload.shipper.email, items=[ Item(sku=item.sku, itemDescription=item.description, unitPrice=item.value_amount, quantity=item.quantity, unitWeight=Weight(item.weight, package.weight_unit).value, countryOfOrigin=item.origin_country, htsNumber=None) for item in customs.commodities ]) return Serializable(request)
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 _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[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[Envelope]: packages = Packages(payload.parcels, PackagePresets, required=["weight"]) service = Services(payload.services, Product).first options = Options(payload.options, Service) package_description = packages[0].parcel.description if len( packages) == 1 else None is_document = all([parcel.is_document for parcel in payload.parcels]) shipper_phone = Phone(payload.shipper.phone_number, payload.shipper.country_code or 'CA') recipient_phone = Phone(payload.recipient.phone_number, payload.recipient.country_code) is_international = payload.shipper.country_code != payload.recipient.country_code option_ids = [(key, value) for key, value in options if key in Service and key not in NON_OFFICIAL_SERVICES] # When no specific service is requested, set a default one. if service is None: show_alternate_services = options[ 'purolator_show_alternative_services'] is not False service = Product['purolator_express_international' if is_international else 'purolator_express'] else: show_alternate_services = options[ 'purolator_show_alternative_services'] is True request = create_envelope( header_content=RequestContext( Version="2.1", Language=settings.language, GroupID="", RequestReference=getattr(payload, 'id', ""), UserToken=settings.user_token, ), body_content=GetFullEstimateRequest( Shipment=Shipment( SenderInformation=SenderInformation( Address=Address( Name=payload.shipper.person_name or "", Company=payload.shipper.company_name, Department=None, StreetNumber="", StreetSuffix=None, StreetName=SF.concat_str(payload.shipper.address_line1, join=True), StreetType=None, StreetDirection=None, Suite=None, Floor=None, StreetAddress2=SF.concat_str( payload.shipper.address_line2, join=True), StreetAddress3=None, City=payload.shipper.city or "", Province=payload.shipper.state_code or "", Country=payload.shipper.country_code or "", PostalCode=payload.shipper.postal_code or "", PhoneNumber=PhoneNumber( CountryCode=shipper_phone.country_code or "0", AreaCode=shipper_phone.area_code or "0", Phone=shipper_phone.phone or "0", Extension=None, ), FaxNumber=None, ), TaxNumber=(payload.shipper.federal_tax_id or payload.shipper.state_tax_id), ), ReceiverInformation=ReceiverInformation( Address=Address( Name=payload.recipient.person_name or "", Company=payload.recipient.company_name, Department=None, StreetNumber="", StreetSuffix=None, StreetName=SF.concat_str( payload.recipient.address_line1, join=True), StreetType=None, StreetDirection=None, Suite=None, Floor=None, StreetAddress2=SF.concat_str( payload.recipient.address_line2, join=True), StreetAddress3=None, City=payload.recipient.city or "", Province=payload.recipient.state_code or "", Country=payload.recipient.country_code or "", PostalCode=payload.recipient.postal_code or "", PhoneNumber=PhoneNumber( CountryCode=recipient_phone.country_code or "0", AreaCode=recipient_phone.area_code or "0", Phone=recipient_phone.phone or "0", Extension=None, ), FaxNumber=None, ), TaxNumber=(payload.recipient.federal_tax_id or payload.recipient.state_tax_id), ), FromOnLabelIndicator=None, FromOnLabelInformation=None, ShipmentDate=options.shipment_date, PackageInformation=PackageInformation( ServiceID=service.value, Description=package_description, TotalWeight=(TotalWeight( Value=packages.weight.map(MeasurementOptions).LB, WeightUnit=PurolatorWeightUnit.LB.value, ) if packages.weight.value is not None else None), TotalPieces=1, PiecesInformation=ArrayOfPiece(Piece=[ Piece( Weight=(PurolatorWeight( Value=package.weight.map(MeasurementOptions). value, WeightUnit=PurolatorWeightUnit[ package.weight_unit.value].value, ) if package.weight.value else None), Length=(PurolatorDimension( Value=package.length.value, DimensionUnit=PurolatorDimensionUnit[ package.dimension_unit.value].value, ) if package.length.value else None), Width=(PurolatorDimension( Value=package.width.value, DimensionUnit=PurolatorDimensionUnit[ package.dimension_unit.value].value, ) if package.width.value else None), Height=(PurolatorDimension( Value=package.height.value, DimensionUnit=PurolatorDimensionUnit[ package.dimension_unit.value].value, ) if package.height.value else None), Options=ArrayOfOptionIDValuePair( OptionIDValuePair=[ OptionIDValuePair(ID=key, Value=value) for key, value in option_ids ]) if any(option_ids) else None, ) for package in packages ]), DangerousGoodsDeclarationDocumentIndicator=None, OptionsInformation=None, ), InternationalInformation=(InternationalInformation( DocumentsOnlyIndicator=is_document, ContentDetails=None, BuyerInformation=None, PreferredCustomsBroker=None, DutyInformation=DutyInformation( BillDutiesToParty=DutyPaymentType.recipient.value, BusinessRelationship=BusinessRelationship.NOT_RELATED. value, Currency=options.currency, ), ImportExportType=None, CustomsInvoiceDocumentIndicator=None, ) if is_international else None), ReturnShipmentInformation=None, PaymentInformation=PaymentInformation( PaymentType=PaymentType.SENDER.value, RegisteredAccountNumber=settings.account_number, ), PickupInformation=PickupInformation( PickupType=PickupType.DROP_OFF.value), NotificationInformation=None, TrackingReferenceInformation=(TrackingReferenceInformation( Reference1=payload.reference) if payload.reference != "" else None), OtherInformation=None, ProactiveNotification=None, ), ShowAlternativeServicesIndicator=show_alternate_services, ), ) return Serializable(request, standard_request_serializer)
def create_shipping_request(payload: ShipmentRequest, settings: Settings, validate: bool = None) -> Serializable[Envelope]: RequestType: ShipmentRequestType = ValidateShipmentRequest if validate else CreateShipmentRequest packages = Packages(payload.parcels, PackagePresets, required=["weight"]) is_document = all([parcel.is_document for parcel in payload.parcels]) package_description = (packages[0].parcel.description if len(packages) == 1 else None) service = Product[payload.service].value is_international = payload.shipper.country_code != payload.recipient.country_code options = Options(payload.options) shipper_phone_number = Phone(payload.shipper.phone_number) recipient_phone_number = Phone(payload.recipient.phone_number) printing = PrinterType[options.printing or "regular"].value special_services = { Service[name].value: value for name, value in payload.options.items() if name in Service.__members__ } request = create_envelope( header_content=RequestContext( Version="2.1", Language=settings.language, GroupID="", RequestReference="", UserToken=settings.user_token, ), body_content=RequestType( Shipment=Shipment( SenderInformation=SenderInformation( Address=Address( Name=payload.shipper.person_name, Company=payload.shipper.company_name, Department=None, StreetNumber="", StreetSuffix=None, StreetName=concat_str(payload.shipper.address_line1, join=True), StreetType=None, StreetDirection=None, Suite=None, Floor=None, StreetAddress2=concat_str( payload.shipper.address_line2, join=True), StreetAddress3=None, City=payload.shipper.city, Province=payload.shipper.state_code, Country=payload.shipper.country_code, PostalCode=payload.shipper.postal_code, PhoneNumber=PhoneNumber( CountryCode=shipper_phone_number.country_code, AreaCode=shipper_phone_number.area_code, Phone=shipper_phone_number.phone, Extension=None), FaxNumber=None, ), TaxNumber=payload.shipper.federal_tax_id or payload.shipper.state_tax_id, ), ReceiverInformation=ReceiverInformation( Address=Address( Name=payload.recipient.person_name, Company=payload.recipient.company_name, Department=None, StreetNumber="", StreetSuffix=None, StreetName=concat_str(payload.recipient.address_line1, join=True), StreetType=None, StreetDirection=None, Suite=None, Floor=None, StreetAddress2=concat_str( payload.recipient.address_line2, join=True), StreetAddress3=None, City=payload.recipient.city, Province=payload.recipient.state_code, Country=payload.recipient.country_code, PostalCode=payload.recipient.postal_code, PhoneNumber=PhoneNumber( CountryCode=recipient_phone_number.country_code, AreaCode=recipient_phone_number.area_code, Phone=recipient_phone_number.phone, Extension=None), FaxNumber=None, ), TaxNumber=payload.recipient.federal_tax_id or payload.recipient.state_tax_id, ), FromOnLabelIndicator=None, FromOnLabelInformation=None, ShipmentDate=datetime.today().strftime("%Y-%m-%d"), PackageInformation=PackageInformation( ServiceID=service, Description=package_description, TotalWeight=TotalWeight( Value=packages.weight.value, WeightUnit=PurolatorWeightUnit.LB.value, ) if packages.weight.value else None, TotalPieces=1, PiecesInformation=ArrayOfPiece(Piece=[ Piece( Weight=PurolatorWeight( Value=package.weight.value, WeightUnit=PurolatorWeightUnit[ package.weight_unit.value].value, ) if package.weight.value else None, Length=PurolatorDimension( Value=package.length.value, DimensionUnit=PurolatorDimensionUnit[ package.dimension_unit.value].value, ) if package.length.value else None, Width=PurolatorDimension( Value=package.width.value, DimensionUnit=PurolatorDimensionUnit[ package.dimension_unit.value].value, ) if package.width.value else None, Height=PurolatorDimension( Value=package.height.value, DimensionUnit=PurolatorDimensionUnit[ package.dimension_unit.value].value, ) if package.height.value else None, Options=None, ) for package in packages ]), DangerousGoodsDeclarationDocumentIndicator=None, OptionsInformation=ArrayOfOptionIDValuePair( OptionIDValuePair=[ OptionIDValuePair(ID=key, Value=value) for key, value in special_services.items() ]) if len(special_services) > 0 else None, ), InternationalInformation=InternationalInformation( DocumentsOnlyIndicator=is_document, ContentDetails=ArrayOfContentDetail(ContentDetail=[ ContentDetail(Description=c.description, HarmonizedCode=None, CountryOfManufacture=c.origin_country, ProductCode=c.sku, UnitValue=c.value_amount, Quantity=c.quantity, NAFTADocumentIndicator=None, FDADocumentIndicator=None, FCCDocumentIndicator=None, SenderIsProducerIndicator=None, TextileIndicator=None, TextileManufacturer=None) for c in payload.customs.commodities ]) if not is_document else None, BuyerInformation=None, PreferredCustomsBroker=None, DutyInformation=DutyInformation( BillDutiesToParty=DutyPaymentType[ payload.customs.duty.paid_by].value, BusinessRelationship=BusinessRelationship.NOT_RELATED. value, Currency=payload.customs.duty.currency, ) if payload.customs is not None else None, ImportExportType=None, CustomsInvoiceDocumentIndicator=None, ) if is_international else None, ReturnShipmentInformation=None, PaymentInformation=PaymentInformation( PaymentType=PaymentType[payload.payment.paid_by].value, RegisteredAccountNumber=payload.payment.account_number or settings.account_number, BillingAccountNumber=payload.payment.account_number or settings.account_number, CreditCardInformation=CreditCardInformation( Type=payload.payment.credit_card.type, Number=payload.payment.credit_card.number, Name=payload.payment.credit_card.name, ExpiryMonth=payload.payment.credit_card.expiry_month, ExpiryYear=payload.payment.credit_card.expiry_year, CVV=payload.payment.credit_card.security_code, BillingPostalCode=payload.payment.credit_card. postal_code, ) if payload.payment.credit_card is not None else None, ) if payload.payment is not None else None, PickupInformation=PickupInformation( PickupType=PickupType.DROP_OFF.value), NotificationInformation=NotificationInformation( ConfirmationEmailAddress=options.notification.email or payload.shipper.email, AdvancedShippingNotificationMessage=None, ) if options.notification else None, TrackingReferenceInformation=TrackingReferenceInformation( Reference1=payload.reference), OtherInformation=None, ProactiveNotification=None, ), PrinterType=PurolatorPrinterType(printing).value, ), ) return Serializable(request, standard_request_serializer)
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 get_full_estimate_request( payload: RateRequest, settings: Settings ) -> Serializable[Envelope]: packages = Packages(payload.parcels, PackagePresets, required=["weight"]) package_description = (packages[0].parcel.description if len(packages) == 1 else None) is_document = all([parcel.is_document for parcel in payload.parcels]) options = Options(payload.options) shipper_phone_number = Phone(payload.shipper.phone_number) recipient_phone_number = Phone(payload.recipient.phone_number) is_international = payload.shipper.country_code != payload.recipient.country_code service = next((Product[s].value for s in payload.services if s in Product.__members__), None) default_service = ( Product.purolator_express_international if is_international else Product.purolator_express ).value request = create_envelope( header_content=RequestContext( Version="2.1", Language=settings.language, GroupID="", RequestReference="", UserToken=settings.user_token, ), body_content=GetFullEstimateRequest( Shipment=Shipment( SenderInformation=SenderInformation( Address=Address( Name=payload.shipper.person_name or "", Company=payload.shipper.company_name, Department=None, StreetNumber="", StreetSuffix=None, StreetName=concat_str(payload.shipper.address_line1, join=True), StreetType=None, StreetDirection=None, Suite=None, Floor=None, StreetAddress2=concat_str( payload.shipper.address_line2, join=True ), StreetAddress3=None, City=payload.shipper.city, Province=payload.shipper.state_code, Country=payload.shipper.country_code, PostalCode=payload.shipper.postal_code, PhoneNumber=PhoneNumber( CountryCode=shipper_phone_number.country_code or "0", AreaCode=shipper_phone_number.area_code or "0", Phone=shipper_phone_number.phone or "0", Extension=None ), FaxNumber=None, ), TaxNumber=payload.shipper.federal_tax_id or payload.shipper.state_tax_id, ), ReceiverInformation=ReceiverInformation( Address=Address( Name=payload.recipient.person_name or "", Company=payload.recipient.company_name, Department=None, StreetNumber="", StreetSuffix=None, StreetName=concat_str( payload.recipient.address_line1, join=True ), StreetType=None, StreetDirection=None, Suite=None, Floor=None, StreetAddress2=concat_str( payload.recipient.address_line2, join=True ), StreetAddress3=None, City=payload.recipient.city, Province=payload.recipient.state_code, Country=payload.recipient.country_code, PostalCode=payload.recipient.postal_code, PhoneNumber=PhoneNumber( CountryCode=recipient_phone_number.country_code or "0", AreaCode=recipient_phone_number.area_code or "0", Phone=recipient_phone_number.phone or "0", Extension=None ), FaxNumber=None, ), TaxNumber=payload.recipient.federal_tax_id or payload.recipient.state_tax_id, ), FromOnLabelIndicator=None, FromOnLabelInformation=None, ShipmentDate=datetime.today().strftime("%Y-%m-%d"), PackageInformation=PackageInformation( ServiceID=(service or default_service), Description=package_description, TotalWeight=TotalWeight( Value=packages.weight.LB, WeightUnit=PurolatorWeightUnit.LB.value, ) if packages.weight.value is not None else None, TotalPieces=1, PiecesInformation=ArrayOfPiece( Piece=[ Piece( Weight=PurolatorWeight( Value=package.weight.value, WeightUnit=PurolatorWeightUnit[ package.weight_unit.value ].value, ) if package.weight.value else None, Length=PurolatorDimension( Value=package.length.value, DimensionUnit=PurolatorDimensionUnit[ package.dimension_unit.value ].value, ) if package.length.value else None, Width=PurolatorDimension( Value=package.width.value, DimensionUnit=PurolatorDimensionUnit[ package.dimension_unit.value ].value, ) if package.width.value else None, Height=PurolatorDimension( Value=package.height.value, DimensionUnit=PurolatorDimensionUnit[ package.dimension_unit.value ].value, ) if package.height.value else None, Options=None, ) for package in packages ] ), DangerousGoodsDeclarationDocumentIndicator=None, OptionsInformation=None, ), InternationalInformation=InternationalInformation( DocumentsOnlyIndicator=is_document, ContentDetails=None, BuyerInformation=None, PreferredCustomsBroker=None, DutyInformation=DutyInformation( BillDutiesToParty=DutyPaymentType.recipient.value, BusinessRelationship=BusinessRelationship.NOT_RELATED.value, Currency=options.currency, ), ImportExportType=None, CustomsInvoiceDocumentIndicator=None ) if is_international else None, ReturnShipmentInformation=None, PaymentInformation=PaymentInformation( PaymentType=PaymentType.SENDER.value, RegisteredAccountNumber=settings.account_number, ), PickupInformation=PickupInformation( PickupType=PickupType.DROP_OFF.value ), NotificationInformation=None, TrackingReferenceInformation=TrackingReferenceInformation( Reference1=payload.reference, ) if payload.reference != "" else None, OtherInformation=None, ProactiveNotification=None, ), ShowAlternativeServicesIndicator=service is None, ), ) return Serializable(request, standard_request_serializer)
def shipment_request(payload: ShipmentRequest, settings: Settings) -> Serializable[DHLShipmentRequest]: if any(settings.account_country_code or "") and ( payload.shipper.country_code != settings.account_country_code): raise OriginNotServicedError(payload.shipper.country_code) packages = Packages.map(payload.parcels, PackagePresets, required=["weight"]) options = Options(payload.options, SpecialServiceCode) product = ProductCode.map(payload.service).value_or_key shipper = CompleteAddress.map(payload.shipper) recipient = CompleteAddress.map(payload.recipient) weight_unit, dim_unit = (COUNTRY_PREFERED_UNITS.get( payload.shipper.country_code) or packages.compatible_units) is_document = all(p.parcel.is_document for p in packages) package_type = PackageType[packages.package_type].value label_format, label_template = LabelType[payload.label_type or 'PDF_6x4'].value payment = (payload.payment or Payment(paid_by="sender", account_number=settings.account_number)) customs = (payload.customs or Customs(commodities=[])) is_dutiable = (is_document is False and customs.duty is not None) paperless_supported = (is_dutiable and payload.shipper.country_code not in UNSUPPORTED_PAPERLESS_COUNTRIES) duty = (customs.duty or Duty(paid_by="sender")) bill_to = CompleteAddress.map(duty.bill_to) content = (packages[0].parcel.content or customs.content_description or "N/A") reference = (payload.reference or getattr(payload, 'id', None)) request = DHLShipmentRequest( schemaVersion='10.0', Request=settings.Request( MetaData=MetaData(SoftwareName="3PV", SoftwareVersion='10.0')), RegionCode=CountryRegion[shipper.country_code].value, LanguageCode="en", LatinResponseInd=None, Billing=Billing( ShipperAccountNumber=settings.account_number, ShippingPaymentType=PaymentType[payment.paid_by].value, BillingAccountNumber=payment.account_number, DutyAccountNumber=duty.account_number, ), Consignee=Consignee( CompanyName=recipient.company_name or "N/A", SuiteDepartmentName=recipient.suite, AddressLine1=recipient.address_line1 or recipient.address_line, AddressLine2=SF.concat_str(recipient.address_line2, join=True), AddressLine3=None, City=recipient.city, Division=None, DivisionCode=recipient.state_code, PostalCode=recipient.postal_code, CountryCode=recipient.country_code, CountryName=recipient.country_name, Contact=Contact( PersonName=recipient.person_name, PhoneNumber=recipient.phone_number or "0000", Email=recipient.email, ), Suburb=recipient.suburb, StreetName=recipient.street_name, BuildingName=None, StreetNumber=recipient.street_number, RegistrationNumbers=None, BusinessPartyTypeCode=None, ), Commodity=([ Commodity(CommodityCode=c.sku, CommodityName=c.description) for c in payload.customs.commodities ] if any(customs.commodities) else None), Dutiable=(Dutiable( DeclaredValue=duty.declared_value or options.declared_value or 1.0, DeclaredCurrency=duty.currency or options.currency or "USD", ScheduleB=None, ExportLicense=customs.license_number, ShipperEIN=None, ShipperIDType=None, TermsOfTrade=customs.incoterm, CommerceLicensed=None, Filing=None) if is_dutiable else None), UseDHLInvoice=("Y" if is_dutiable else None), DHLInvoiceLanguageCode=("en" if is_dutiable else None), DHLInvoiceType=(("CMI" if customs.commercial_invoice else "PFI") if is_dutiable else None), ExportDeclaration=(ExportDeclaration( InterConsignee=None, IsPartiesRelation=None, ECCN=None, SignatureName=customs.signer, SignatureTitle=None, ExportReason=customs.content_type, ExportReasonCode=ExportReasonCode[customs.content_type or 'other'].value, SedNumber=None, SedNumberType=None, MxStateCode=None, InvoiceNumber=(customs.invoice or "N/A"), InvoiceDate=(customs.invoice_date or time.strftime("%Y-%m-%d")), BillToCompanyName=bill_to.company_name, BillToContactName=bill_to.person_name, BillToAddressLine=bill_to.address_line, BillToCity=bill_to.city, BillToPostcode=bill_to.postal_code, BillToSuburb=bill_to.extra, BillToCountryName=bill_to.country_name, BillToPhoneNumber=bill_to.phone_number, BillToPhoneNumberExtn=None, BillToFaxNumber=None, BillToFederalTaxID=bill_to.federal_tax_id, Remarks=customs.content_description, DestinationPort=None, TermsOfPayment=None, PayerGSTVAT=bill_to.state_tax_id, SignatureImage=None, ReceiverReference=None, ExporterId=None, ExporterCode=None, ExportLineItem=[ ExportLineItem( LineNumber=index, Quantity=item.quantity, QuantityUnit='PCS', Description=item.description or 'N/A', Value=((item.quantity or 1) * (item.value_amount or 0.0)), IsDomestic=None, CommodityCode=item.sku, ScheduleB=None, ECCN=None, Weight=WeightType( Weight=Weight(item.weight, WeightUnit[item.weight_unit or 'KG'])[weight_unit.name], WeightUnit=DHLWeightUnit[weight_unit.name].value), GrossWeight=WeightType( Weight=Weight(item.weight, WeightUnit[item.weight_unit or 'KG'])[weight_unit.name], WeightUnit=DHLWeightUnit[weight_unit.name].value), License=None, LicenseSymbol=None, ManufactureCountryCode=item.origin_country, ManufactureCountryName=Location( item.origin_country).as_country_name, ImportTaxManagedOutsideDhlExpress=None, AdditionalInformation=None, ImportCommodityCode=None, ItemReferences=None, CustomsPaperworks=None, ) for (index, item) in enumerate(customs.commodities, start=1) ], ShipmentDocument=None, InvoiceInstructions=None, CustomerDataTextEntries=None, PlaceOfIncoterm="N/A", ShipmentPurpose=( "COMMERCIAL" if customs.commercial_invoice else "PERSONAL"), DocumentFunction=None, CustomsDocuments=None, InvoiceTotalNetWeight=None, InvoiceTotalGrossWeight=None, InvoiceReferences=None, ) if is_dutiable else None), Reference=([Reference( ReferenceID=reference)] if any([reference]) else None), ShipmentDetails=DHLShipmentDetails( Pieces=Pieces(Piece=[ Piece( PieceID=index, PackageType=(package_type or PackageType[package.packaging_type or "your_packaging"].value), Depth=package.length.map(MeasurementOptions)[ dim_unit.name], Width=package.width.map(MeasurementOptions)[dim_unit.name], Height=package.height.map(MeasurementOptions)[ dim_unit.name], Weight=package.weight[weight_unit.name], PieceContents=( package.parcel.content or package.parcel.description), PieceReference=([Reference( ReferenceID=package.parcel.id)] if package.parcel. id is not None else None), AdditionalInformation=(AdditionalInformation( CustomerDescription=package.parcel.description ) if package.parcel.description is not None else None)) for (index, package) in enumerate(packages, start=1) ]), WeightUnit=DHLWeightUnit[weight_unit.name].value, GlobalProductCode=product, LocalProductCode=product, Date=(options.shipment_date or time.strftime("%Y-%m-%d")), Contents=content, DimensionUnit=DimensionUnit[dim_unit.name].value, PackageType=package_type, IsDutiable=("Y" if is_dutiable else "N"), CurrencyCode=options.currency or "USD", CustData=getattr(payload, 'id', None), ShipmentCharges=(options.cash_on_delivery if options.cash_on_delivery else None), ParentShipmentIdentificationNumber=None, ParentShipmentGlobalProductCode=None, ParentShipmentPackagesCount=None, ), Shipper=Shipper( ShipperID=settings.account_number or "N/A", CompanyName=shipper.company_name or "N/A", SuiteDepartmentName=shipper.suite, RegisteredAccount=settings.account_number, AddressLine1=shipper.address_line1 or shipper.address_line, AddressLine2=SF.concat_str(shipper.address_line2, join=True), AddressLine3=None, City=shipper.city, Division=None, DivisionCode=shipper.state_code, PostalCode=shipper.postal_code, OriginServiceAreaCode=None, OriginFacilityCode=None, CountryCode=shipper.country_code, CountryName=shipper.country_name, Contact=Contact( PersonName=shipper.person_name, PhoneNumber=shipper.phone_number or "0000", Email=shipper.email, ), Suburb=shipper.suburb, StreetName=shipper.street_name, BuildingName=None, StreetNumber=shipper.street_number, RegistrationNumbers=None, BusinessPartyTypeCode=None, ), SpecialService=([ SpecialService( SpecialServiceType=SpecialServiceCode[key].value.key, ChargeValue=getattr(svc, 'value', None), CurrencyCode=(options.currency or "USD" if hasattr( svc, 'value') else None)) for key, svc in options if key in SpecialServiceCode ] + ( # Add paperless trade if dutiable [SpecialService(SpecialServiceType="WY")] if paperless_supported and 'dhl_paperless_trade' not in options else [])), Notification=(Notification( EmailAddress=options.email_notification_to or recipient.email) if options.email_notification and any([options.email_notification_to, recipient.email]) else None), Place=None, EProcShip=None, Airwaybill=None, DocImages=None, LabelImageFormat=label_format, RequestArchiveDoc=None, NumberOfArchiveDoc=None, RequestQRCode='N', RequestTransportLabel=None, Label=Label(LabelTemplate=label_template), ODDLinkReq=None, DGs=None, GetPriceEstimate='Y', SinglePieceImage='N', ShipmentIdentificationNumber=None, UseOwnShipmentIdentificationNumber='N', Importer=None, ) return Serializable(request, _request_serializer)