def book_pickup_request( payload: PickupRequest, settings: Settings ) -> Serializable[BookPURequest]: weight_unit = DHLWeightUnit.LB weight = sum( [ Weight(parcel.weight, WeightUnit[weight_unit.name]).LB for parcel in payload.parcels ] ) request = BookPURequest( Request=settings.Request( MetaData=MetaData(SoftwareName="XMLPI", SoftwareVersion=3.0) ), schemaVersion=3.0, RegionCode=CountryRegion[payload.address.country_code].value if payload.address.country_code else "AM", Requestor=Requestor( AccountNumber=settings.account_number, AccountType="D", RequestorContact=RequestorContact( PersonName=payload.address.person_name, Phone=payload.address.phone_number, PhoneExtension=None, ), CompanyName=payload.address.company_name, ), Place=Place( City=payload.address.city, StateCode=payload.address.state_code, PostalCode=payload.address.postal_code, CompanyName=payload.address.company_name, CountryCode=payload.address.country_code, PackageLocation=payload.package_location, LocationType="R" if payload.address.residential else "B", Address1=payload.address.address_line1, Address2=payload.address.address_line2, ), PickupContact=RequestorContact( PersonName=payload.address.person_name, Phone=payload.address.phone_number ), Pickup=Pickup( Pieces=len(payload.parcels), PickupDate=payload.date, ReadyByTime=f'{payload.ready_time}:00', CloseTime=f'{payload.closing_time}:00', SpecialInstructions=[payload.instruction], RemotePickupFlag="Y", weight=WeightSeg(Weight=weight, WeightUnit=weight_unit.value), ), ShipmentDetails=None, ConsigneeDetails=None, ) return Serializable(request, _request_serializer)
def intl_rate_request(payload: RateRequest, settings: Settings) -> Serializable[IntlRateV2Request]: weight_unit = WeightUnit[payload.parcel.weight_unit or "LB"] dimension_unit = DimensionUnit[payload.parcel.dimension_unit or "IN"] request = IntlRateV2Request( USERID=settings.username, Revision="2", Package=[ PackageType( ID=payload.parcel.id or 1, Pounds=Weight(payload.parcel.weight, weight_unit).LB, Ounces=Weight(payload.parcel.weight, weight_unit).OZ, Machinable=None, MailType=IntlMailType[payload.parcel.packaging_type].value, GXG=None, ValueOfContents=None, Country=(Country[payload.recipient.country_code].value if payload.recipient.country_code else None), Container=(IntlContainer[payload.parcel.packaging_type].value if payload.parcel.packaging_type else None), Size="LARGE" if any(dim for dim in [ Dimension(payload.parcel.width, dimension_unit).IN, Dimension(payload.parcel.length, dimension_unit).IN, Dimension(payload.parcel.height, dimension_unit).IN, ] if dim > 12) else "REGULAR", Width=Dimension(payload.parcel.width, dimension_unit).IN, Length=Dimension(payload.parcel.length, dimension_unit).IN, Height=Dimension(payload.parcel.height, dimension_unit).IN, Girth=None, OriginZip=payload.shipper.postal_code, CommercialFlag=None, CommercialPlusFlag=None, AcceptanceDateTime=datetime.today().strftime( "%Y-%m-%dT%H:%M:%S"), DestinationPostalCode=payload.recipient.postal_code, ExtraServices=None, Content=None, ) ], ) return Serializable(request, _request_serializer)
def rate_request(payload: RateRequest, settings: Settings) -> Serializable[IntlRateV2Request]: package = Packages(payload.parcels, max_weight=Weight(70, WeightUnit.LB)).single services = Services(payload.options.keys(), RateService) extra_services = Services(payload.services, ExtraService) commercial = "Y" if "commercial" in services else "N" commercial_plus = "Y" if "plus" in services else "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=("usps_machinable" in payload.options), MailType=IntlPackageType[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=[s.value for s in extra_services]), Content=None, ) ], ) return Serializable(request, XP.export)
def rate_request(payload: RateRequest, settings: Settings) -> Serializable[IntlRateV2Request]: """Create the appropriate USPS International rate request depending on the destination :param payload: Purplship unified API rate request data :param settings: USPS International connection and auth settings :return: a domestic or international USPS International compatible request :raises: - OriginNotServicedError when origin country is not serviced by the carrier - DestinationNotServicedError when destination country is US """ if payload.shipper.country_code is not None and payload.shipper.country_code != Country.US.name: raise OriginNotServicedError(payload.shipper.country_code) if payload.recipient.country_code == Country.US.name: raise DestinationNotServicedError(payload.recipient.country_code) package = Packages(payload.parcels, max_weight=Weight(70, WeightUnit.LB)).single options = Options(payload.options, ShipmentOption) services = Services(payload.services, ShipmentService) extra_services = [getattr(option, 'value', option) for key, option in options if 'usps_option' not in key] commercial = next(("Y" for svc in services if "commercial" in svc.name), "N") commercial_plus = next(("Y" for svc in services if "plus" in svc.name), "N") country = ( Country[payload.recipient.country_code].value if payload.recipient.country_code else None ) request = IntlRateV2Request( USERID=settings.username, Revision="2", Package=[ PackageType( ID=0, Pounds=package.weight.LB, Ounces=package.weight.OZ, Machinable=options["usps_option_machinable_item"], MailType=PackagingType[package.packaging_type or "package"].value, GXG=None, ValueOfContents=None, Country=country, Width=package.width.IN, Length=package.length.IN, Height=package.height.IN, Girth=(package.girth.value if package.packaging_type == "tube" else None), OriginZip=payload.shipper.postal_code, CommercialFlag=commercial, CommercialPlusFlag=commercial_plus, AcceptanceDateTime=datetime.today().strftime("%Y-%m-%dT%H:%M:%S"), DestinationPostalCode=payload.recipient.postal_code, ExtraServices=( ExtraServicesType( ExtraService=[ getattr(option, 'value', option) for option in extra_services ] ) if any(extra_services) else None ), Content=None, ) ], ) return Serializable(request, XP.export)
def 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 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[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[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 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[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 freight_rate_request( payload: RateRequest, settings: Settings) -> Serializable[FreightRateRequest]: dimension_unit = DimensionUnit[payload.parcel.dimension_unit or "IN"] weight_unit = WeightUnit[payload.parcel.weight_unit or "LB"] service = ([ RatingServiceCode[svc] for svc in payload.services if svc in RatingServiceCode.__members__ ] + [RatingServiceCode.ups_freight_ltl_guaranteed])[0] request = FreightRateRequest( Request=common.RequestType( TransactionReference=common.TransactionReferenceType( TransactionIdentifier="TransactionIdentifier"), RequestOption=[1], ), ShipFrom=ShipFromType( Name=payload.shipper.company_name, Address=AddressType( AddressLine=concat_str(payload.shipper.address_line1, payload.shipper.address_line2), City=payload.shipper.city, PostalCode=payload.shipper.postal_code, CountryCode=payload.shipper.country_code, StateProvinceCode=payload.shipper.state_code, ), AttentionName=payload.shipper.person_name, ), ShipTo=ShipToType( Name=payload.recipient.company_name, Address=AddressType( AddressLine=concat_str(payload.recipient.address_line1, payload.recipient.address_line2), City=payload.recipient.city, PostalCode=payload.recipient.postal_code, CountryCode=payload.recipient.country_code, StateProvinceCode=payload.recipient.state_code, ), AttentionName=payload.recipient.person_name, ), PaymentInformation=None, Service=RateCodeDescriptionType(Code=service.value, Description=None), HandlingUnitOne=HandlingUnitType( Quantity=1, Type=RateCodeDescriptionType(Code="SKD")), ShipmentServiceOptions=ShipmentServiceOptionsType( PickupOptions=PickupOptionsType(WeekendPickupIndicator="")), DensityEligibleIndicator="", AdjustedWeightIndicator="", HandlingUnitWeight=None, PickupRequest=None, GFPOptions=None, TimeInTransitIndicator="", Commodity=[ CommodityType( Description=payload.parcel.description or "...", Weight=WeightType( UnitOfMeasurement=UnitOfMeasurementType( Code=UPSWeightUnit[weight_unit.name].value), Value=Weight(payload.parcel.weight, weight_unit).value, ), Dimensions=DimensionsType( UnitOfMeasurement=UnitOfMeasurementType( 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, ), NumberOfPieces=None, PackagingType=RateCodeDescriptionType( Code=FreightPackagingType[payload.parcel.packaging_type or "small_box"].value, Description=None, ), FreightClass=50, ) ], ) return Serializable( create_envelope(header_content=settings.Security, body_content=request), _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 process_shipment_request( payload: ShipmentRequest, settings: Settings ) -> Serializable[ProcessShipmentRequest]: 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") 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__ ] request = ProcessShipmentRequest( WebAuthenticationDetail=settings.webAuthenticationDetail, ClientDetail=settings.clientDetail, TransactionDetail=TransactionDetail(CustomerTransactionId="IE_v18_Ship"), Version=VersionId(ServiceId="ship", Major=25, Intermediate=0, Minor=0), RequestedShipment=RequestedShipment( ShipTimestamp=datetime.now(), DropoffType="REGULAR_PICKUP", ServiceType=service, PackagingType=PackagingType[ payload.parcel.packaging_type or "small_box" ].value, ManifestDetail=None, TotalWeight=FedexWeight( Units=package.weight_unit.value, Value=package.weight.value, ), TotalInsuredValue=options.insurance.amount if options.insurance else 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.phone_number, payload.shipper.person_name, payload.shipper.email, ) ) else None, Address=Address( StreetLines=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=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=None, Payor=Payor( ResponsibleParty=Party( AccountNumber=payload.payment.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.amount, ), 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.shipper.email, Name=payload.shipper.person_name, ), Localization=Localization( LanguageCode="EN", LocaleCode=None ), ), FormatSpecification="TEXT", ) ], ) if options.notification 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=None, ShippingDocumentSpecification=None, RateRequestTypes=( ["LIST"] + ([] if options.currency is None else ["PREFERRED"]) ), EdtRequestType=None, MasterTrackingId=None, PackageCount=None, ConfigurationData=None, RequestedPackageLineItems=[ RequestedPackageLineItem( SequenceNumber=index, GroupNumber=None, GroupPackageCount=index, VariableHandlingChargeDetail=None, InsuredValue=None, Weight=FedexWeight( Units=package.weight_unit.value, Value=Weight(pkg.weight, package.weight_unit).value, ) if pkg.weight else None, Dimensions=FedexDimensions( Length=Dimension(pkg.length, package.dimension_unit).value, Width=Dimension(pkg.width, package.dimension_unit).value, Height=Dimension(pkg.height, package.dimension_unit).value, Units=package.dimension_unit.value, ) if any([pkg.length, pkg.width, pkg.height]) else None, PhysicalPackaging=None, ItemDescription=pkg.description, ItemDescriptionForClearance=None, CustomerReferences=None, SpecialServicesRequested=None, ContentRecords=None, ) for index, pkg in enumerate(payload.customs.commodities, 1) ] if payload.customs is not None else 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 shipment_request(payload: ShipmentRequest, settings: Settings) -> Serializable[eVSFirstClassMailIntlRequest]: package = Packages(payload.parcels, max_weight=Weight(70, WeightUnit.LB)).single options = Options(payload.options, ShipmentOption) label_format = LabelFormat[payload.label_type or 'usps_6_x_4_label'].value extra_services = [ getattr(option, 'value', option) for key, option in options if key in ShipmentOption and 'usps_option' not in key ] customs = payload.customs or Customs(commodities=[]) request = eVSFirstClassMailIntlRequest( USERID=settings.username, Option=None, Revision=2, ImageParameters=ImageParametersType(ImageParameter=label_format), FromFirstName=customs.signer or payload.shipper.person_name, FromLastName=payload.shipper.person_name, FromFirm=payload.shipper.company_name or "N/A", FromAddress1=payload.shipper.address_line2, FromAddress2=payload.shipper.address_line1, FromUrbanization=None, FromCity=payload.shipper.city, FromZip5=Location(payload.shipper.postal_code).as_zip5, FromZip4=Location(payload.shipper.postal_code).as_zip4 or "", FromPhone=payload.shipper.phone_number, ToName=None, ToFirstName=payload.recipient.person_name, ToLastName=payload.recipient.person_name, ToFirm=payload.recipient.company_name or "N/A", ToAddress1=payload.recipient.address_line2, ToAddress2=payload.recipient.address_line1, ToAddress3=None, ToCity=payload.recipient.city, ToProvince=Location(payload.recipient.state_code, country=payload.recipient.country_code).as_state_name, ToCountry=Location(payload.recipient.country_code).as_country_name, ToPostalCode=payload.recipient.postal_code, ToPOBoxFlag=None, ToPhone=payload.recipient.phone_number, ToFax=None, ToEmail=payload.recipient.email, FirstClassMailType=None, ShippingContents=ShippingContentsType( ItemDetail=[ ItemDetailType( Description=item.description, Quantity=item.quantity, Value=item.value_amount, NetPounds=Weight(item.weight, WeightUnit[item.weight_unit or 'LB']).LB, NetOunces=Weight(item.weight, WeightUnit[item.weight_unit or 'LB']).OZ, HSTariffNumber=item.sku, CountryOfOrigin=Location(item.origin_country).as_country_name ) for item in payload.customs.commodities ] ), Postage=None, GrossPounds=package.weight.LB, GrossOunces=package.weight.OZ, ContentType=ContentType[customs.content_type or "other"].value, ContentTypeOther=customs.content_description or "N/A", Agreement=('N' if customs.certify else 'Y'), Comments=customs.content_description, LicenseNumber=customs.license_number, CertificateNumber=customs.certificate_number, InvoiceNumber=customs.invoice, ImageType="PDF", ImageLayout="ALLINONEFILE", CustomerRefNo=None, CustomerRefNo2=None, POZipCode=None, LabelDate=DF.fdatetime( (options.shipment_date or time.strftime('%Y-%m-%d')), current_format="%Y-%m-%d", output_format="%m/%d/%Y" ), HoldForManifest=None, EELPFC=customs.eel_pfc, Container=None, Length=package.length.IN, Width=package.width.IN, Height=package.height.IN, Girth=(package.girth.value if package.packaging_type == "tube" else None), ExtraServices=( ExtraServicesType(ExtraService=[s for s in extra_services]) if any(extra_services) else None ), PriceOptions=None, ActionCode=None, OptOutOfSPE=None, PermitNumber=None, AccountZipCode=None, Machinable=(options.usps_option_machinable_item or False), DestinationRateIndicator="I", MID=settings.mailer_id, LogisticsManagerMID=settings.logistics_manager_mailer_id, CRID=settings.customer_registration_id, VendorCode=None, VendorProductVersionNumber=None, RemainingBarcodes=None, ChargebackCode=None, ) return Serializable(request, XP.export)