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[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)
def shipment_request( payload: ShipmentRequest, settings: Settings ) -> Serializable[ProcessShipmentRequest]: shipper = CompleteAddress.map(payload.shipper) recipient = CompleteAddress.map(payload.recipient) 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] service = ServiceType.map(payload.service).value_or_key options = Options(payload.options, SpecialServiceType) special_services = [getattr(v, 'value', v) for k, v in options if k in SpecialServiceType] label_type, label_format = LabelType[payload.label_type or 'PDF_4x6'].value customs = payload.customs duty = customs.duty if customs is not None else None bill_to = CompleteAddress(getattr(duty, 'bill_to', None)) request = ProcessShipmentRequest( WebAuthenticationDetail=settings.webAuthenticationDetail, ClientDetail=settings.clientDetail, TransactionDetail=TransactionDetail(CustomerTransactionId="IE_v26_Ship"), Version=VersionId(ServiceId="ship", Major=26, Intermediate=0, Minor=0), RequestedShipment=RequestedShipment( ShipTimestamp=DF.date(options.shipment_date or datetime.now()), DropoffType="REGULAR_PICKUP", ServiceType=service, PackagingType=PackagingType[packages.package_type or 'your_packaging'].value, ManifestDetail=None, VariationOptions=None, TotalWeight=FedexWeight( Units=packages.weight.unit, Value=packages.weight.value ), TotalInsuredValue=options.insurance, PreferredCurrency=options.currency, ShipmentAuthorizationDetail=None, Shipper=Party( AccountNumber=settings.account_number, Tins=( [TaxpayerIdentification(Number=tax) for tax in shipper.taxes] if shipper.has_tax_info else None ), Contact=( Contact( ContactId=None, PersonName=shipper.person_name, Title=None, CompanyName=shipper.company_name, PhoneNumber=shipper.phone_number, PhoneExtension=None, TollFreePhoneNumber=None, PagerNumber=None, FaxNumber=None, EMailAddress=shipper.email, ) if shipper.has_contact_info else None ), Address=Address( StreetLines=shipper.address_lines, City=shipper.city, StateOrProvinceCode=shipper.state_code, PostalCode=shipper.postal_code, UrbanizationCode=None, CountryCode=shipper.country_code, CountryName=shipper.country_name, Residential=shipper.residential, GeographicCoordinates=None, ), ), Recipient=Party( AccountNumber=None, Tins=( [TaxpayerIdentification(Number=tax) for tax in recipient.taxes] if recipient.has_tax_info else None ), Contact=( Contact( ContactId=None, PersonName=recipient.person_name, Title=None, CompanyName=recipient.company_name, PhoneNumber=recipient.phone_number, PhoneExtension=None, TollFreePhoneNumber=None, PagerNumber=None, FaxNumber=None, EMailAddress=recipient.email, ) if recipient.has_contact_info else None ), Address=Address( StreetLines=recipient.address_lines, City=recipient.city, StateOrProvinceCode=recipient.state_code, PostalCode=recipient.postal_code, UrbanizationCode=None, CountryCode=recipient.country_code, CountryName=recipient.country_name, Residential=recipient.residential, GeographicCoordinates=None, ), ), RecipientLocationNumber=None, Origin=None, SoldTo=None, ShippingChargesPayment=Payment( PaymentType=PaymentType[payload.payment.paid_by or "sender"].value, Payor=Payor( ResponsibleParty=Party( AccountNumber=(payload.payment.account_number or settings.account_number), ) ), ), 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.email_notification_to or recipient.email), Name=recipient.person_name or recipient.company_name, ), Localization=Localization(LanguageCode="EN"), ), FormatSpecification=ShipmentNotificationFormatSpecification( Type="TEXT" ), ) ], ) if options.email_notification and any([options.email_notification_to, recipient.email]) else None ), ReturnShipmentDetail=None, PendingShipmentDetail=None, InternationalControlledExportDetail=None, InternationalTrafficInArmsRegulationsDetail=None, ShipmentDryIceDetail=None, HomeDeliveryPremiumDetail=None, EtdDetail=None, ) if options.has_content else None ), ExpressFreightDetail=None, FreightShipmentDetail=None, DeliveryInstructions=None, VariableHandlingChargeDetail=None, CustomsClearanceDetail=( CustomsClearanceDetail( Brokers=None, ClearanceBrokerage=None, CustomsOptions=None, ImporterOfRecord=None, RecipientCustomsId=None, DutiesPayment=( Payment( PaymentType=PaymentType[duty.paid_by or "sender"].value, Payor=( Payor( ResponsibleParty=Party( AccountNumber=duty.account_number, Tins=bill_to.taxes ) ) if any([duty.account_number, bill_to.taxes]) else None ) ) if duty is not None else None ), DocumentContent=None, CustomsValue=Money( Currency=(duty.currency or options.currency), Amount=(duty.declared_value or options.declared_value) ), FreightOnValue=None, InsuranceCharges=None, PartiesToTransactionAreRelated=None, CommercialInvoice=( CommercialInvoice( Comments=None, FreightCharge=None, TaxesOrMiscellaneousChargeType=None, PackingCosts=None, HandlingCosts=None, SpecialInstructions=None, DeclarationStatement=None, PaymentTerms=None, Purpose=PurposeType[customs.content_type or 'other'].value, PurposeOfShipmentDescription=None, CustomerReferences=None, OriginatorName=(shipper.company_name or shipper.person_name), TermsOfSale=Incoterm[customs.incoterm or "DDU"].value ) if customs.commercial_invoice else None ), Commodities=[ Commodity( Name=None, NumberOfPieces=item.quantity, Description=item.description or "N/A", Purpose=None, CountryOfManufacture=item.origin_country, HarmonizedCode=None, Weight=FedexWeight( Units=master_package.weight_unit.value, Value=Weight(item.weight, item.weight_unit)[master_package.weight_unit.value] ), Quantity=item.quantity, QuantityUnits='EA', AdditionalMeasures=None, UnitPrice=Money( Currency=(options.currency or duty.currency), Amount=item.value_amount, ), CustomsValue=None, ExciseConditions=None, ExportLicenseNumber=None, ExportLicenseExpirationDate=None, CIMarksAndNumbers=None, PartNumber=item.sku, NaftaDetail=None, ) for item in customs.commodities ], ExportDetail=None, RegulatoryControls=None, DeclarationStatementDetail=None ) if payload.customs is not None else 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=master_package.weight.value, ) if master_package.weight.value else None ), Dimensions=( FedexDimensions( Length=master_package.length.map(MeasurementOptions).value, Width=master_package.width.map(MeasurementOptions).value, Height=master_package.height.map(MeasurementOptions).value, Units=master_package.dimension_unit.value, ) if master_package.has_dimensions else None ), PhysicalPackaging=None, ItemDescription=master_package.parcel.description, ItemDescriptionForClearance=None, CustomerReferences=( [ CustomerReference( CustomerReferenceType=CustomerReferenceType.CUSTOMER_REFERENCE, Value=payload.reference ) ] if any(payload.reference or "") else 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 recipient = CompleteAddress(payload.recipient) options = Options(payload.options, ShipmentOption) services = Services(payload.services, ShipmentService) extra_services = [getattr(option, 'value', option) for key, option in options if 'usps_option' not in key] commercial = next(("Y" for svc in services if "commercial" in svc.name), "N") commercial_plus = next(("Y" for svc in services if "plus" in svc.name), "N") request = IntlRateV2Request( USERID=settings.username, Revision="2", Package=[ PackageType( ID=0, Pounds=package.weight.LB, Ounces=package.weight.OZ, Machinable=options.usps_option_machinable_item or False, MailType=PackagingType[package.packaging_type or "package"].value, GXG=( GXGType(POBoxFlag='N', GiftFlag='N') if any('global_express_guaranteed' in s.name for s in payload.services) else None ), ValueOfContents=(options.declared_value or ""), Country=recipient.country_name, Width=package.width.IN, Length=package.length.IN, Height=package.height.IN, Girth=(package.girth.value if package.packaging_type == "tube" else None), OriginZip=payload.shipper.postal_code, CommercialFlag=commercial, CommercialPlusFlag=commercial_plus, AcceptanceDateTime=DF.fdatetime( (options.shipment_date or datetime.today()), output_format="%Y-%m-%dT%H:%M:%S" ), DestinationPostalCode=recipient.postal_code, ExtraServices=( ExtraServicesType(ExtraService=[s for s in extra_services]) if any(extra_services) else None ), Content=None, ) ], ) return Serializable(request, XP.export)
def rate_request( payload: RateRequest, settings: Settings ) -> Serializable[FedexRateRequest]: shipper = CompleteAddress.map(payload.shipper) recipient = CompleteAddress.map(payload.recipient) packages = Packages(payload.parcels, PackagePresets, required=["weight"]) service = Services(payload.services, ServiceType).first options = Options(payload.options) 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=28, 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=PackagingType[packages.package_type or 'your_packaging'].value, VariationOptions=None, TotalWeight=FedexWeight( Units=packages.weight.unit, Value=packages.weight.LB, ), TotalInsuredValue=None, PreferredCurrency=options.currency, ShipmentAuthorizationDetail=None, Shipper=Party( AccountNumber=settings.account_number, Tins=( [TaxpayerIdentification(Number=tax) for tax in shipper.taxes] if shipper.has_tax_info else None ), Contact=( Contact( ContactId=None, PersonName=shipper.person_name, Title=None, CompanyName=shipper.company_name, PhoneNumber=shipper.phone_number, PhoneExtension=None, TollFreePhoneNumber=None, PagerNumber=None, FaxNumber=None, EMailAddress=shipper.email, ) if shipper.has_contact_info else None ), Address=Address( StreetLines=shipper.address_lines, City=shipper.city, StateOrProvinceCode=shipper.state_code, PostalCode=shipper.postal_code, UrbanizationCode=None, CountryCode=shipper.country_code, CountryName=shipper.country_name, Residential=shipper.residential, GeographicCoordinates=None, ), ), Recipient=Party( AccountNumber=None, Tins=( [TaxpayerIdentification(Number=tax) for tax in recipient.taxes] if recipient.has_tax_info else None ), Contact=( Contact( ContactId=None, PersonName=recipient.person_name, Title=None, CompanyName=recipient.company_name, PhoneNumber=recipient.phone_number, PhoneExtension=None, TollFreePhoneNumber=None, PagerNumber=None, FaxNumber=None, EMailAddress=recipient.email, ) if recipient.has_contact_info else None ), Address=Address( StreetLines=recipient.address_lines, City=recipient.city, StateOrProvinceCode=recipient.state_code, PostalCode=recipient.postal_code, UrbanizationCode=None, CountryCode=recipient.country_code, CountryName=recipient.country_name, Residential=recipient.residential, 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=package.weight.value, ) if package.weight.value else None ), Dimensions=( Dimensions( Length=package.length.map(MeasurementOptions).value, Width=package.width.map(MeasurementOptions).value, Height=package.height.map(MeasurementOptions).value, Units=package.dimension_unit.value, ) if package.has_dimensions else None ), PhysicalPackaging=None, ItemDescription=package.parcel.description, ItemDescriptionForClearance=None, CustomerReferences=( [ CustomerReference( CustomerReferenceType=CustomerReferenceType.CUSTOMER_REFERENCE, Value=payload.reference ) ] if any(payload.reference or "") else None ), SpecialServicesRequested=None, ContentRecords=None, ) for index, package in enumerate(packages, 1) ], ), ) return Serializable(request, _request_serializer)
def rate_request(payload: RateRequest, settings: Settings) -> Serializable[Envelope]: packages = Packages(payload.parcels, PackagePresets) packages.validate(required=["weight"]) options = Options(payload.options, ServiceOption) service = Services(payload.services, ServiceCode).first ship_from = CompleteAddress.map(payload.shipper) ship_to = CompleteAddress.map(payload.shipper) mps_packaging = PackagingType.ups_freight_other.value if len( packages) > 1 else None request = create_envelope( header_content=settings.Security, body_content=FreightRateRequest( Request=RequestType( RequestOption=[1], SubVersion=1707, TransactionReference=TransactionReferenceType( CustomerContext=payload.reference, TransactionIdentifier=getattr(payload, "id", None), ), ), 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, CountryCode=ship_from.country_code, ResidentialAddressIndicator=("" if ship_from.residential else None), ), AttentionName=ship_from.person_name, TariffPoint=None, ), ShipTo=ShipToType( Name=ship_to.company_name, Address=AddressType( AddressLine=[ship_to.address_line], City=ship_to.city, StateProvinceCode=ship_to.state_code, Town=None, CountryCode=ship_to.country_code, ResidentialAddressIndicator=("" if ship_to.residential else None), ), AttentionName=ship_to.person_name, TariffPoint=None, ), PaymentInformation=PaymentInformationType( Payer=PayerType( Name=ship_from.company_name, Address=AddressType( AddressLine=[ship_from.address_line], City=ship_from.city, StateProvinceCode=ship_from.state_code, Town=None, CountryCode=ship_from.country_code, ResidentialAddressIndicator=( "" if ship_from.residential else None), ), AttentionName=ship_from.person_name, ShipperNumber=settings.account_number, ), ShipmentBillingOption=RateCodeDescriptionType( Code=40, Description="Freight Collect"), ), Service=(RateCodeDescriptionType(Code=service, Description=None) if service is not None else None), HandlingUnitOne=None, HandlingUnitTwo=None, 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=RateCodeDescriptionType( Code=(mps_packaging or PackagingType[ commodity.packaging_type or "small_box"].value, )), DangerousGoodsIndicator=None, CommodityValue=None, FreightClass=None, NMFCCommodity=None, NMFCCommodityCode=None, ) for commodity in packages ], ShipmentServiceOptions=(ShipmentServiceOptionsType( PickupOptions=None, DeliveryOptions=None, OverSeasLeg=None, COD=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, AdjustedHeight=None, ) if any([ options.cash_on_delivery, options.email_notification, options.dangerous_good, options.declared_value, ]) else None), PickupRequest=None, AlternateRateOptions=RateCodeDescriptionType(Code=3), GFPOptions=None, AccountType=None, ShipmentTotalWeight=ShipmentTotalWeightType( Value=packages.weight.value, UnitOfMeasurement=UnitOfMeasurementType( Code=UPSWeightUnit[packages.weight.unit].value, ), ), HandlingUnitWeight=None, AdjustedWeightIndicator=None, TimeInTransitIndicator="", HandlingUnits=None, AdjustedHeightIndicator=None, DensityEligibleIndicator=None, QuoteNumberIndicator="", ), ) return Serializable(request, _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 key in ShipmentOption and '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 = CompleteAddress.map( 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_line2, FromAddress2=payload.shipper.address_line1, 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 or "", 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_line2, ToAddress2=payload.recipient.address_line1, ToAddress3=None, ToCity=payload.recipient.city, ToProvince=Location( payload.recipient.state_code, country=payload.recipient.country_code).as_state_name, ToCountry=Location(payload.recipient.country_code).as_country_name, ToPostalCode=payload.recipient.postal_code, ToPOBoxFlag=None, ToPhone=payload.recipient.phone_number, ToFax=None, ToEmail=payload.recipient.email, ImportersReferenceNumber=None, NonDeliveryOption=non_delivery, RedirectName=redirect_address.person_name, RedirectEmail=redirect_address.email, RedirectSMS=redirect_address.phone_number, RedirectAddress=redirect_address.address_line, RedirectCity=redirect_address.city, RedirectState=redirect_address.state_code, RedirectZipCode=redirect_address.postal_code, RedirectZip4=Location(redirect_address.postal_code).as_zip4 or "", 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 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 or time.strftime('%Y-%m-%d')), current_format="%Y-%m-%d", output_format="%m/%d/%Y"), EMCAAccount=None, HoldForManifest=None, EELPFC=customs.eel_pfc, PriceOptions=None, Length=package.length.IN, Width=package.width.IN, Height=package.height.IN, Girth=(package.girth.value if package.packaging_type == "tube" else None), ExtraServices=(ExtraServicesType( ExtraService=[s for s in extra_services]) if any(extra_services) else None), ActionCode=None, OptOutOfSPE=None, PermitNumber=None, AccountZipCode=None, ImportersReferenceType=None, ImportersTelephoneNumber=None, ImportersFaxNumber=None, ImportersEmail=None, Machinable=(options.usps_option_machinable_item or False), DestinationRateIndicator="I", MID=settings.mailer_id, LogisticsManagerMID=settings.logistics_manager_mailer_id, CRID=settings.customer_registration_id, VendorCode=None, VendorProductVersionNumber=None, ChargebackCode=None, ) return Serializable(request, XP.export)