Exemple #1
0
def parse_pickup_response(response: Element, settings: Settings) -> Tuple[PickupDetails, List[Message]]:
    pickup_node = next(iter(response.xpath(".//*[local-name() = $name]", name="pickup")), None)
    pickup = XP.build(PickupV2, pickup_node)
    details: PickupDetails = PickupDetails(
        carrier_id=settings.carrier_id,
        carrier_name=settings.carrier_name,
        confirmation_number=str(pickup.id),
        pickup_date=DF.fdatetime(pickup.pickup_date, '%Y-%m-%dT%H:%M:%S')
    )

    return details, parse_error_response(response, settings)
Exemple #2
0
def rate_request(payload: RateRequest,
                 settings: Settings) -> Serializable[priceRequest]:
    options = Options(payload.options, ShipmentOption)
    package = Packages(payload.parcels).single
    service = Services(payload.services, ShipmentService).first

    option_codes = [code for label, code in options if 'division' not in label]

    request = priceRequest(
        appId=settings.username,
        appVersion="3.0",
        priceCheck=priceCheck(
            rateId=None,
            sender=address(country=payload.shipper.country_code,
                           town=payload.shipper.city,
                           postcode=payload.shipper.postal_code),
            delivery=address(country=payload.recipient.country_code,
                             town=payload.recipient.city,
                             postcode=payload.recipient.postal_code),
            collectionDateTime=DF.fdatetime(options.shipment_date,
                                            output_format='%Y-%m-%dT%H:%M:%S'),
            product=product(
                id=getattr(service, 'value', None),
                division=next(
                    (code for label, code in options if 'division' in label),
                    None),
                productDesc=None,
                type_=('D' if package.parcel.is_document else 'N'),
                options=(optionsType(
                    option=[option(optionCode=code) for code in option_codes])
                         if any(option_codes) else None)),
            account=(account(
                accountNumber=settings.account_number,
                accountCountry=settings.account_country_code,
            ) if any([settings.account_number, settings.account_country_code])
                     else None),
            insurance=(insurance(insuranceValue=options.insurance,
                                 goodsValue=options.insurance)
                       if options.insurance is not None else None),
            termsOfPayment=PaymentType.sender.value,
            currency=options.currency,
            priceBreakDown=True,
            consignmentDetails=consignmentDetails(
                totalWeight=package.weight.KG,
                totalVolume=package.volume.value,
                totalNumberOfPieces=1,
            ),
            pieceLine=None),
    )

    return Serializable(request, XP.to_xml)
Exemple #3
0
def pickup_request(payload: PickupRequest, settings: Settings) -> Serializable[Envelope]:
    packages = Packages(payload.parcels)

    request = create_envelope(
        body_content=schedulePickupV2(
            request=SchedulePickupV2Rq(
                password=settings.password,
                pickup=PickupV2(
                    collect=None,
                    comments=payload.instruction,
                    created_by=payload.address.person_name,
                    pickup_address=Address(
                        address_line_1=payload.address.address_line1,
                        address_line_2=payload.address.address_line2,
                        address_line_3=None,
                        attention=payload.address.person_name,
                        city=payload.address.city,
                        country=payload.address.country_code,
                        email=payload.address.email,
                        extension=None,
                        name=payload.address.company_name,
                        phone=payload.address.phone_number,
                        postal_code=payload.address.postal_code,
                        province=payload.address.state_code,
                        residential=payload.address.residential,
                    ),
                    pickup_date=DF.fdatetime(
                        f"{payload.pickup_date} {payload.ready_time}", '%Y-%m-%d %H:%M', '%Y-%m-%dT%H:%M:%S'
                    ),
                    pickup_location=payload.package_location,
                    pickup_phone=payload.address.phone_number,
                    shipper_num=None,
                    unit_of_measure=WeightUnit.LB.value,
                    weight=packages.weight.LB
                ),
                user_id=settings.username
            )
        )
    )

    return Serializable(
        request, partial(
            settings.serialize,
            extra_namespace='xmlns:xsd1="http://dto.canshipws.canpar.com/xsd"',
            special_prefixes=dict(pickup_children='xsd1')
        )
    )
def shipment_request(
        payload: ShipmentRequest,
        settings: Settings) -> Serializable[eVSGXGGetLabelRequest]:
    package = Packages(payload.parcels,
                       max_weight=Weight(70, WeightUnit.LB)).single
    options = Options(payload.options, ShipmentOption)

    customs = payload.customs or Customs(commodities=[])
    incoterm = Incoterm[customs.incoterm or 'OTHER'].value
    insurance = getattr((options['usps_insurance_global_express_guaranteed']),
                        'value', options.insurance)

    request = eVSGXGGetLabelRequest(
        USERID=settings.username,
        PASSWORD=settings.password,
        Option=None,
        Revision=2,
        ImageParameters=None,
        FromFirstName=customs.signer or payload.shipper.person_name or "N/A",
        FromMiddleInitial=None,
        FromLastName=payload.shipper.person_name,
        FromFirm=payload.shipper.company_name or "N/A",
        FromAddress1=payload.shipper.address_line1,
        FromAddress2=payload.shipper.address_line2,
        FromUrbanization=None,
        FromCity=payload.shipper.city,
        FromState=Location(payload.shipper.state_code,
                           country='US').as_state_name,
        FromZIP5=Location(payload.shipper.postal_code).as_zip5,
        FromZIP4=Location(payload.shipper.postal_code).as_zip4,
        FromPhone=payload.shipper.phone_number,
        ShipFromZIP=None,
        ToFirstName=None,
        ToLastName=payload.recipient.person_name,
        ToFirm=payload.recipient.company_name or "N/A",
        ToAddress1=payload.recipient.address_line1,
        ToAddress2=payload.recipient.address_line2,
        ToAddress3=None,
        ToPostalCode=payload.recipient.postal_code,
        ToPhone=payload.recipient.phone_number,
        RecipientEMail=payload.recipient.email,
        ToDPID="000",  # supposedly required test and find a solution
        ToProvince=payload.recipient.state_code,
        ToTaxID=(payload.recipient.federal_tax_id
                 or payload.recipient.state_tax_id),
        Container=PackagingType[package.packaging_type or 'package'].value,
        ContentType=('DOCUMENTS' if package.parcel.is_document else 'NON-DOC'),
        ShippingContents=ShippingContentsType(ItemDetail=[
            ItemDetailType(
                Description=item.description,
                Commodity=item.description or "N/A",
                Quantity=item.quantity,
                UnitValue=item.value_amount,
                NetPounds=Weight(item.weight, WeightUnit[item.weight_unit
                                                         or 'LB']).LB,
                NetOunces=Weight(item.weight, WeightUnit[item.weight_unit
                                                         or 'LB']).OZ,
                UnitOfMeasure=None,
                HSTariffNumber=item.sku,
                CountryofManufacture=Location(
                    item.origin_country).as_country_name)
            for item in payload.customs.commodities
        ]),
        PurposeOfShipment=ContentType[customs.content_type or 'other'],
        PartiesToTransaction=None,
        Agreement=('N' if customs.certify else 'Y'),
        Postage=None,
        InsuredValue=insurance,
        GrossPounds=package.weight.LB,
        GrossOunces=package.weight.OZ,
        Length=package.length.IN,
        Width=package.weight.IN,
        Height=package.height.IN,
        Girth=(package.girth.value
               if package.packaging_type == "tube" else None),
        Shape=None,
        CIRequired=customs.commercial_invoice,
        InvoiceDate=None,
        InvoiceNumber=customs.invoice,
        CustomerOrderNumber=None,
        CustOrderNumber=None,
        TermsDelivery=incoterm,
        TermsDeliveryOther=((customs.incoterm or incoterm)
                            if incoterm == 'OTHER' else None),
        PackingCost=None,
        CountryUltDest=Location(
            payload.recipient.country_code).as_country_name,
        CIAgreement=customs.commercial_invoice,
        ImageType="PDF",
        ImageLayout=None,
        CustomerRefNo=None,
        CustomerRefNo2=None,
        ShipDate=DF.fdatetime((options.shipment_date or datetime.now()),
                              output_format="%m/%d/%Y"),
        HoldForManifest=None,
        PriceOptions=None,
        CommercialShipment=customs.commercial_invoice,
        BuyerRecipient=(
            customs.commercial_invoice
            or None),  # Consider recipient as buyer for commercial shipment
        TermsPayment=("Net 50" if customs.commercial_invoice else None),
        ActionCode=None,
        OptOutOfSPE=None,
        PermitNumber=None,
        AccountZipCode=None,
        Machinable=options['usps_option_machinable_item'],
        DestinationRateIndicator="I",
        MID=None,
        LogisticsManagerMID=None,
        CRID=None,
        VendorCode=None,
        VendorProductVersionNumber=None,
        OverrideMID=None,
        ChargebackCode=None,
    )

    return Serializable(request, XP.export)
Exemple #5
0
def rate_request(payload: RateRequest,
                 settings: Settings) -> Serializable[Envelope]:
    packages = Packages(payload.parcels)
    service_type = Services(payload.services, Service).first
    options = Options(payload.options, Option)

    shipment_date = DF.fdatetime(options.shipment_date
                                 or time.strftime('%Y-%m-%d'),
                                 current_format='%Y-%m-%d',
                                 output_format='%Y-%m-%dT%H:%M:%S')
    premium: Optional[bool] = next((True
                                    for option, _ in options if option in [
                                        Option.canpar_ten_am.name,
                                        Option.canpar_noon.name,
                                        Option.canpar_saturday.name,
                                    ]), None)
    nsr = next(
        (Option[o].value for o in
         ['canpar_no_signature_required', 'canpar_not_no_signature_required']
         if o in options), None)

    request = create_envelope(body_content=rateShipment(request=RateShipmentRq(
        apply_association_discount=False,
        apply_individual_discount=False,
        apply_invoice_discount=False,
        password=settings.password,
        shipment=Shipment(
            cod_type=options['canpar_cash_on_delivery'],
            delivery_address=Address(
                address_line_1=payload.recipient.address_line1,
                address_line_2=payload.recipient.address_line2,
                address_line_3=None,
                attention=payload.recipient.person_name,
                city=payload.recipient.city,
                country=payload.recipient.country_code,
                email=payload.recipient.email,
                extension=None,
                name=payload.recipient.company_name,
                phone=payload.recipient.phone_number,
                postal_code=payload.recipient.postal_code,
                province=payload.recipient.state_code,
                residential=payload.recipient.residential,
            ),
            description=None,
            dg=options['canpar_dangerous_goods'],
            dimention_unit=DimensionUnit.IN.value,
            handling=None,
            handling_type=None,
            instruction=None,
            nsr=nsr,
            packages=[
                Package(alternative_reference=None,
                        cod=None,
                        cost_centre=None,
                        declared_value=None,
                        height=pkg.height.CM,
                        length=pkg.length.CM,
                        lg=None,
                        reference=None,
                        reported_weight=pkg.weight.LB,
                        store_num=None,
                        width=pkg.width.CM,
                        xc=options['canpar_extra_care']) for pkg in packages
            ],
            pickup_address=Address(
                address_line_1=payload.shipper.address_line1,
                address_line_2=payload.shipper.address_line2,
                address_line_3=None,
                attention=payload.shipper.person_name,
                city=payload.shipper.city,
                country=payload.shipper.country_code,
                email=payload.shipper.email,
                extension=None,
                name=payload.shipper.company_name,
                phone=payload.shipper.phone_number,
                postal_code=payload.shipper.postal_code,
                province=payload.shipper.state_code,
                residential=payload.shipper.residential,
            ),
            premium=premium,
            proforma=None,
            reported_weight_unit=WeightUnit.LB.value,
            send_email_to_delivery=payload.recipient.email,
            send_email_to_pickup=payload.shipper.email,
            service_type=service_type.value,
            shipper_num=None,
            shipping_date=shipment_date,
            subtotal=None,
            subtotal_with_handling=None,
            total=None,
            total_with_handling=None,
            user_id=None,
        ),
        user_id=settings.username)))

    return Serializable(
        request,
        partial(
            settings.serialize,
            extra_namespace='xmlns:xsd1="http://dto.canshipws.canpar.com/xsd"',
            special_prefixes=dict(shipment_children='xsd1')))
def shipment_request(
        payload: ShipmentRequest,
        settings: Settings) -> Serializable[eVSPriorityMailIntlRequest]:
    package = Packages(payload.parcels,
                       max_weight=Weight(70, WeightUnit.LB)).single
    options = Options(payload.options, ShipmentOption)

    label_format = LabelFormat[payload.label_type or 'usps_6_x_4_label'].value
    extra_services = [
        getattr(option, 'value', option) for key, option in options
        if 'usps_option' not in key
    ]
    customs = payload.customs or Customs(commodities=[])
    insurance = getattr(
        (options['usps_insurance_priority_mail_international']), 'value',
        options.insurance)
    # Gets the first provided non delivery option or default to "RETURN"
    non_delivery = next(
        (option.value for name, option in options if 'non_delivery' in name),
        "RETURN")
    redirect_address = Address(
        **(options['usps_option_redirect_non_delivery'] or {}))

    request = eVSPriorityMailIntlRequest(
        USERID=settings.username,
        Option=None,
        Revision=2,
        ImageParameters=ImageParametersType(ImageParameter=label_format),
        FromFirstName=customs.signer or payload.shipper.person_name or "N/A",
        FromMiddleInitial=None,
        FromLastName=payload.shipper.person_name,
        FromFirm=payload.shipper.company_name or "N/A",
        FromAddress1=payload.shipper.address_line1,
        FromAddress2=payload.shipper.address_line2,
        FromUrbanization=None,
        FromCity=payload.shipper.city,
        FromState=Location(payload.shipper.state_code,
                           country='US').as_state_name,
        FromZip5=Location(payload.shipper.postal_code).as_zip5,
        FromZip4=Location(payload.shipper.postal_code).as_zip4,
        FromPhone=payload.shipper.phone_number,
        FromCustomsReference=None,
        ToName=None,
        ToFirstName=payload.recipient.person_name,
        ToLastName=None,
        ToFirm=payload.recipient.company_name or "N/A",
        ToAddress1=payload.recipient.address_line1,
        ToAddress2=payload.recipient.address_line2,
        ToAddress3=None,
        ToCity=payload.recipient.city,
        ToProvince=payload.recipient.state_code,
        ToCountry=Location(payload.recipient.country_code).as_country_name,
        ToPostalCode=payload.recipient.postal_code,
        ToPOBoxFlag=None,
        ToPhone=payload.recipient.phone_number,
        ToFax=None,
        ToEmail=payload.recipient.email,
        ImportersReferenceNumber=None,
        NonDeliveryOption=non_delivery,
        RedirectName=redirect_address.person_name,
        RedirectEmail=redirect_address.email,
        RedirectSMS=redirect_address.phone_number,
        RedirectAddress=SF.concat_str(redirect_address.address_line1,
                                      redirect_address.address_line2,
                                      join=True),
        RedirectCity=redirect_address.city,
        RedirectState=redirect_address.state_code,
        RedirectZipCode=redirect_address.postal_code,
        RedirectZip4=Location(redirect_address.postal_code).as_zip4,
        Container=None,
        ShippingContents=ShippingContentsType(ItemDetail=[
            ItemDetailType(
                Description=item.description,
                Quantity=item.quantity,
                Value=item.value_amount,
                NetPounds=Weight(item.weight, WeightUnit[item.weight_unit
                                                         or 'LB']).LB,
                NetOunces=Weight(item.weight, WeightUnit[item.weight_unit
                                                         or 'LB']).OZ,
                HSTariffNumber=item.sku,
                CountryOfOrigin=Location(item.origin_country).as_country_name)
            for item in payload.customs.commodities
        ]),
        Insured=('N' if insurance is None else 'Y'),
        InsuredAmount=insurance,
        GrossPounds=package.weight.LB,
        GrossOunces=package.weight.OZ,
        ContentType=ContentType[customs.content_type or "other"].value,
        ContentTypeOther=customs.content_description or "N/A",
        Agreement=('N' if customs.certify else 'Y'),
        Comments=customs.content_description,
        LicenseNumber=customs.license_number,
        CertificateNumber=customs.certificate_number,
        InvoiceNumber=customs.invoice,
        ImageType="PDF",
        ImageLayout="ALLINONEFILE",
        CustomerRefNo=None,
        CustomerRefNo2=None,
        POZipCode=None,
        LabelDate=DF.fdatetime(options.shipment_date,
                               output_format="%m/%d/%Y"),
        EMCAAccount=None,
        HoldForManifest=None,
        EELPFC=customs.eel_pfc,
        PriceOptions=None,
        Length=package.length.IN,
        Width=package.weight.IN,
        Height=package.height.IN,
        Girth=(package.girth.value
               if package.packaging_type == "tube" else None),
        ExtraServices=(ExtraServicesType(ExtraService=[
            getattr(option, 'value', option) for option in extra_services
        ]) if any(extra_services) else None),
        ActionCode=None,
        OptOutOfSPE=None,
        PermitNumber=None,
        AccountZipCode=None,
        ImportersReferenceType=None,
        ImportersTelephoneNumber=None,
        ImportersFaxNumber=None,
        ImportersEmail=None,
        Machinable=options["usps_option_machinable_item"],
        DestinationRateIndicator="I",
        MID=None,
        LogisticsManagerMID=None,
        CRID=None,
        VendorCode=None,
        VendorProductVersionNumber=None,
        ChargebackCode=None,
    )

    return Serializable(request, XP.export)
Exemple #7
0
def _process_shipment(payload: ShipmentRequest, settings: Settings) -> Job:
    packages = Packages(payload.parcels)
    options = Options(payload.options, Option)
    service_type: Optional[str] = (Service[payload.service] if payload.service
                                   in Service.__members__ else None)
    premium: Optional[bool] = next((True
                                    for option, _ in options if option in [
                                        Option.canpar_ten_am.value,
                                        Option.canpar_noon.value,
                                        Option.canpar_saturday.value,
                                    ]), None)
    shipping_date = DF.fdatetime(options.shipment_date
                                 or time.strftime('%Y-%m-%d'),
                                 current_format='%Y-%m-%d',
                                 output_format='%Y-%m-%dT%H:%M:%S')

    request = create_envelope(body_content=processShipment(
        request=ProcessShipmentRq(
            password=settings.password,
            shipment=Shipment(
                cod_type=options['canpar_cash_on_delivery'],
                delivery_address=Address(
                    address_line_1=payload.recipient.address_line1,
                    address_line_2=payload.recipient.address_line2,
                    address_line_3=None,
                    attention=payload.recipient.person_name,
                    city=payload.recipient.city,
                    country=payload.recipient.country_code,
                    email=payload.recipient.email,
                    extension=None,
                    name=payload.recipient.company_name,
                    phone=payload.recipient.phone_number,
                    postal_code=payload.recipient.postal_code,
                    province=payload.recipient.state_code,
                    residential=payload.recipient.residential,
                ),
                description=None,
                dg=options['canpar_dangerous_goods'],
                dimention_unit=DimensionUnit.IN.value,
                handling=None,
                handling_type=None,
                instruction=None,
                nsr=(options['canpar_no_signature_required']
                     or options['canpar_not_no_signature_required']),
                packages=[
                    Package(alternative_reference=None,
                            cod=None,
                            cost_centre=None,
                            declared_value=None,
                            height=pkg.height.CM,
                            length=pkg.length.CM,
                            lg=None,
                            reference=None,
                            reported_weight=pkg.weight.LB,
                            store_num=None,
                            width=pkg.width.CM,
                            xc=('canpar_extra_care' in options) or None)
                    for pkg in packages
                ],
                pickup_address=Address(
                    address_line_1=payload.shipper.address_line1,
                    address_line_2=payload.shipper.address_line2,
                    address_line_3=None,
                    attention=payload.shipper.person_name,
                    city=payload.shipper.city,
                    country=payload.shipper.country_code,
                    email=payload.shipper.email,
                    extension=None,
                    name=payload.shipper.company_name,
                    phone=payload.shipper.phone_number,
                    postal_code=payload.shipper.postal_code,
                    province=payload.shipper.state_code,
                    residential=payload.shipper.residential,
                ),
                premium=premium,
                proforma=None,
                reported_weight_unit=WeightUnit.LB.value,
                send_email_to_delivery=payload.recipient.email,
                send_email_to_pickup=payload.shipper.email,
                service_type=service_type,
                shipper_num=None,
                shipping_date=shipping_date,
                subtotal=None,
                subtotal_with_handling=None,
                total=None,
                total_with_handling=None,
                user_id=None,
            ),
            user_id=settings.username)))

    return Job(id="process",
               data=Serializable(request, default_request_serializer))
def rate_request(payload: RateRequest, settings: Settings) -> Serializable[IntlRateV2Request]:
    """Create the appropriate USPS International rate request depending on the destination

    :param payload: Purplship unified API rate request data
    :param settings: USPS International connection and auth settings
    :return: a domestic or international USPS International compatible request
    :raises:
        - OriginNotServicedError when origin country is not serviced by the carrier
        - DestinationNotServicedError when destination country is US
    """

    if payload.shipper.country_code is not None and payload.shipper.country_code != Country.US.name:
        raise OriginNotServicedError(payload.shipper.country_code)

    if payload.recipient.country_code == Country.US.name:
        raise DestinationNotServicedError(payload.recipient.country_code)

    package = Packages(payload.parcels, max_weight=Weight(70, WeightUnit.LB)).single
    recipient = CompleteAddress(payload.recipient)
    options = Options(payload.options, ShipmentOption)
    services = Services(payload.services, ShipmentService)

    extra_services = [getattr(option, 'value', option) for key, option in options if 'usps_option' not in key]
    commercial = next(("Y" for svc in services if "commercial" in svc.name), "N")
    commercial_plus = next(("Y" for svc in services if "plus" in svc.name), "N")

    request = IntlRateV2Request(
        USERID=settings.username,
        Revision="2",
        Package=[
            PackageType(
                ID=0,
                Pounds=package.weight.LB,
                Ounces=package.weight.OZ,
                Machinable=options.usps_option_machinable_item or False,
                MailType=PackagingType[package.packaging_type or "package"].value,
                GXG=(
                    GXGType(POBoxFlag='N', GiftFlag='N')
                    if any('global_express_guaranteed' in s.name for s in payload.services) else None
                ),
                ValueOfContents=(options.declared_value or ""),
                Country=recipient.country_name,
                Width=package.width.IN,
                Length=package.length.IN,
                Height=package.height.IN,
                Girth=(package.girth.value if package.packaging_type == "tube" else None),
                OriginZip=payload.shipper.postal_code,
                CommercialFlag=commercial,
                CommercialPlusFlag=commercial_plus,
                AcceptanceDateTime=DF.fdatetime(
                    (options.shipment_date or datetime.today()),
                    output_format="%Y-%m-%dT%H:%M:%S"
                ),
                DestinationPostalCode=recipient.postal_code,
                ExtraServices=(
                    ExtraServicesType(ExtraService=[s for s in extra_services])
                    if any(extra_services) else None
                ),
                Content=None,
            )
        ],
    )

    return Serializable(request, XP.export)
def shipment_request(payload: ShipmentRequest, settings: Settings) -> Serializable[eVSFirstClassMailIntlRequest]:
    package = Packages(payload.parcels, max_weight=Weight(70, WeightUnit.LB)).single
    options = Options(payload.options, ShipmentOption)

    label_format = LabelFormat[payload.label_type or 'usps_6_x_4_label'].value
    extra_services = [
        getattr(option, 'value', option) for key, option in options
        if key in ShipmentOption and 'usps_option' not in key
    ]
    customs = payload.customs or Customs(commodities=[])

    request = eVSFirstClassMailIntlRequest(
        USERID=settings.username,
        Option=None,
        Revision=2,
        ImageParameters=ImageParametersType(ImageParameter=label_format),
        FromFirstName=customs.signer or payload.shipper.person_name,
        FromLastName=payload.shipper.person_name,
        FromFirm=payload.shipper.company_name or "N/A",
        FromAddress1=payload.shipper.address_line2,
        FromAddress2=payload.shipper.address_line1,
        FromUrbanization=None,
        FromCity=payload.shipper.city,
        FromZip5=Location(payload.shipper.postal_code).as_zip5,
        FromZip4=Location(payload.shipper.postal_code).as_zip4 or "",
        FromPhone=payload.shipper.phone_number,
        ToName=None,
        ToFirstName=payload.recipient.person_name,
        ToLastName=payload.recipient.person_name,
        ToFirm=payload.recipient.company_name or "N/A",
        ToAddress1=payload.recipient.address_line2,
        ToAddress2=payload.recipient.address_line1,
        ToAddress3=None,
        ToCity=payload.recipient.city,
        ToProvince=Location(payload.recipient.state_code, country=payload.recipient.country_code).as_state_name,
        ToCountry=Location(payload.recipient.country_code).as_country_name,
        ToPostalCode=payload.recipient.postal_code,
        ToPOBoxFlag=None,
        ToPhone=payload.recipient.phone_number,
        ToFax=None,
        ToEmail=payload.recipient.email,
        FirstClassMailType=None,
        ShippingContents=ShippingContentsType(
            ItemDetail=[
                ItemDetailType(
                    Description=item.description,
                    Quantity=item.quantity,
                    Value=item.value_amount,
                    NetPounds=Weight(item.weight, WeightUnit[item.weight_unit or 'LB']).LB,
                    NetOunces=Weight(item.weight, WeightUnit[item.weight_unit or 'LB']).OZ,
                    HSTariffNumber=item.sku,
                    CountryOfOrigin=Location(item.origin_country).as_country_name
                )
                for item in payload.customs.commodities
            ]
        ),
        Postage=None,
        GrossPounds=package.weight.LB,
        GrossOunces=package.weight.OZ,
        ContentType=ContentType[customs.content_type or "other"].value,
        ContentTypeOther=customs.content_description or "N/A",
        Agreement=('N' if customs.certify else 'Y'),
        Comments=customs.content_description,
        LicenseNumber=customs.license_number,
        CertificateNumber=customs.certificate_number,
        InvoiceNumber=customs.invoice,
        ImageType="PDF",
        ImageLayout="ALLINONEFILE",
        CustomerRefNo=None,
        CustomerRefNo2=None,
        POZipCode=None,
        LabelDate=DF.fdatetime(
            (options.shipment_date or time.strftime('%Y-%m-%d')),
            current_format="%Y-%m-%d",
            output_format="%m/%d/%Y"
        ),
        HoldForManifest=None,
        EELPFC=customs.eel_pfc,
        Container=None,
        Length=package.length.IN,
        Width=package.width.IN,
        Height=package.height.IN,
        Girth=(package.girth.value if package.packaging_type == "tube" else None),
        ExtraServices=(
            ExtraServicesType(ExtraService=[s for s in extra_services])
            if any(extra_services) else None
        ),
        PriceOptions=None,
        ActionCode=None,
        OptOutOfSPE=None,
        PermitNumber=None,
        AccountZipCode=None,
        Machinable=(options.usps_option_machinable_item or False),
        DestinationRateIndicator="I",
        MID=settings.mailer_id,
        LogisticsManagerMID=settings.logistics_manager_mailer_id,
        CRID=settings.customer_registration_id,
        VendorCode=None,
        VendorProductVersionNumber=None,
        RemainingBarcodes=None,
        ChargebackCode=None,
    )

    return Serializable(request, XP.export)