예제 #1
0
def get_full_estimate_request(
    payload: RateRequest, settings: Settings
) -> Serializable[Envelope]:
    packages = Packages(payload.parcels, PackagePresets, required=["weight"])
    package_description = (packages[0].parcel.description if len(packages) == 1 else None)
    is_document = all([parcel.is_document for parcel in payload.parcels])
    options = Options(payload.options)
    shipper_phone_number = Phone(payload.shipper.phone_number)
    recipient_phone_number = Phone(payload.recipient.phone_number)
    is_international = payload.shipper.country_code != payload.recipient.country_code
    service = next((Product[s].value for s in payload.services if s in Product.__members__), None)
    default_service = (
        Product.purolator_express_international if is_international else Product.purolator_express
    ).value

    request = create_envelope(
        header_content=RequestContext(
            Version="2.1",
            Language=settings.language,
            GroupID="",
            RequestReference="",
            UserToken=settings.user_token,
        ),
        body_content=GetFullEstimateRequest(
            Shipment=Shipment(
                SenderInformation=SenderInformation(
                    Address=Address(
                        Name=payload.shipper.person_name or "",
                        Company=payload.shipper.company_name,
                        Department=None,
                        StreetNumber="",
                        StreetSuffix=None,
                        StreetName=concat_str(payload.shipper.address_line1, join=True),
                        StreetType=None,
                        StreetDirection=None,
                        Suite=None,
                        Floor=None,
                        StreetAddress2=concat_str(
                            payload.shipper.address_line2, join=True
                        ),
                        StreetAddress3=None,
                        City=payload.shipper.city,
                        Province=payload.shipper.state_code,
                        Country=payload.shipper.country_code,
                        PostalCode=payload.shipper.postal_code,
                        PhoneNumber=PhoneNumber(
                            CountryCode=shipper_phone_number.country_code or "0",
                            AreaCode=shipper_phone_number.area_code or "0",
                            Phone=shipper_phone_number.phone or "0",
                            Extension=None
                        ),
                        FaxNumber=None,
                    ),
                    TaxNumber=payload.shipper.federal_tax_id
                    or payload.shipper.state_tax_id,
                ),
                ReceiverInformation=ReceiverInformation(
                    Address=Address(
                        Name=payload.recipient.person_name or "",
                        Company=payload.recipient.company_name,
                        Department=None,
                        StreetNumber="",
                        StreetSuffix=None,
                        StreetName=concat_str(
                            payload.recipient.address_line1, join=True
                        ),
                        StreetType=None,
                        StreetDirection=None,
                        Suite=None,
                        Floor=None,
                        StreetAddress2=concat_str(
                            payload.recipient.address_line2, join=True
                        ),
                        StreetAddress3=None,
                        City=payload.recipient.city,
                        Province=payload.recipient.state_code,
                        Country=payload.recipient.country_code,
                        PostalCode=payload.recipient.postal_code,
                        PhoneNumber=PhoneNumber(
                            CountryCode=recipient_phone_number.country_code or "0",
                            AreaCode=recipient_phone_number.area_code or "0",
                            Phone=recipient_phone_number.phone or "0",
                            Extension=None
                        ),
                        FaxNumber=None,
                    ),
                    TaxNumber=payload.recipient.federal_tax_id
                    or payload.recipient.state_tax_id,
                ),
                FromOnLabelIndicator=None,
                FromOnLabelInformation=None,
                ShipmentDate=datetime.today().strftime("%Y-%m-%d"),
                PackageInformation=PackageInformation(
                    ServiceID=(service or default_service),
                    Description=package_description,
                    TotalWeight=TotalWeight(
                        Value=packages.weight.LB,
                        WeightUnit=PurolatorWeightUnit.LB.value,
                    )
                    if packages.weight.value is not None
                    else None,
                    TotalPieces=1,
                    PiecesInformation=ArrayOfPiece(
                        Piece=[
                            Piece(
                                Weight=PurolatorWeight(
                                    Value=package.weight.value,
                                    WeightUnit=PurolatorWeightUnit[
                                        package.weight_unit.value
                                    ].value,
                                )
                                if package.weight.value
                                else None,
                                Length=PurolatorDimension(
                                    Value=package.length.value,
                                    DimensionUnit=PurolatorDimensionUnit[
                                        package.dimension_unit.value
                                    ].value,
                                )
                                if package.length.value
                                else None,
                                Width=PurolatorDimension(
                                    Value=package.width.value,
                                    DimensionUnit=PurolatorDimensionUnit[
                                        package.dimension_unit.value
                                    ].value,
                                )
                                if package.width.value
                                else None,
                                Height=PurolatorDimension(
                                    Value=package.height.value,
                                    DimensionUnit=PurolatorDimensionUnit[
                                        package.dimension_unit.value
                                    ].value,
                                )
                                if package.height.value
                                else None,
                                Options=None,
                            )
                            for package in packages
                        ]
                    ),
                    DangerousGoodsDeclarationDocumentIndicator=None,
                    OptionsInformation=None,
                ),
                InternationalInformation=InternationalInformation(
                    DocumentsOnlyIndicator=is_document,
                    ContentDetails=None,
                    BuyerInformation=None,
                    PreferredCustomsBroker=None,
                    DutyInformation=DutyInformation(
                        BillDutiesToParty=DutyPaymentType.recipient.value,
                        BusinessRelationship=BusinessRelationship.NOT_RELATED.value,
                        Currency=options.currency,
                    ),
                    ImportExportType=None,
                    CustomsInvoiceDocumentIndicator=None
                ) if is_international else None,
                ReturnShipmentInformation=None,
                PaymentInformation=PaymentInformation(
                    PaymentType=PaymentType.SENDER.value,
                    RegisteredAccountNumber=settings.account_number,
                ),
                PickupInformation=PickupInformation(
                    PickupType=PickupType.DROP_OFF.value
                ),
                NotificationInformation=None,
                TrackingReferenceInformation=TrackingReferenceInformation(
                    Reference1=payload.reference,
                ) if payload.reference != "" else None,
                OtherInformation=None,
                ProactiveNotification=None,
            ),
            ShowAlternativeServicesIndicator=service is None,
        ),
    )
    return Serializable(request, standard_request_serializer)
예제 #2
0
def rate_request(
    payload: RateRequest, settings: Settings
) -> Serializable[UPSRateRequest]:
    packages = Packages(payload.parcels, PackagePresets)
    is_document = all([parcel.is_document for parcel in payload.parcels])
    service: str = next(
        (RatingServiceCode[s].value for s in payload.services if s in RatingServiceCode.__members__),
        None
    )

    if (service is not None) and (("freight" in service) or ("ground" in service)) and (
        packages.weight.value is None
    ):
        raise FieldError({"parcel.weight": FieldErrorCode.required})

    mps_packaging = RatingPackagingType.ups_unknown.value if len(packages) > 1 else None

    request = UPSRateRequest(
        Request=RequestType(
            RequestOption=["Shop", "Rate"],
            SubVersion=None,
            TransactionReference=TransactionReferenceType(
                CustomerContext=payload.reference, TransactionIdentifier=None
            ),
        ),
        PickupType=None,
        CustomerClassification=None,
        Shipment=ShipmentType(
            OriginRecordTransactionTimestamp=None,
            Shipper=ShipperType(
                Name=payload.shipper.company_name,
                ShipperNumber=settings.account_number,
                Address=ShipAddressType(
                    AddressLine=concat_str(
                        payload.recipient.address_line1,
                        payload.recipient.address_line2,
                    ),
                    City=payload.shipper.city,
                    StateProvinceCode=payload.shipper.state_code,
                    PostalCode=payload.shipper.postal_code,
                    CountryCode=payload.shipper.country_code,
                ),
            ),
            ShipTo=ShipToType(
                Name=payload.recipient.company_name,
                Address=ShipToAddressType(
                    AddressLine=concat_str(
                        payload.recipient.address_line1,
                        payload.recipient.address_line2,
                    ),
                    City=payload.recipient.city,
                    StateProvinceCode=payload.recipient.state_code,
                    PostalCode=payload.recipient.postal_code,
                    CountryCode=payload.recipient.country_code,
                    ResidentialAddressIndicator=None,
                ),
            ),
            ShipFrom=None,
            AlternateDeliveryAddress=None,
            ShipmentIndicationType=None,
            PaymentDetails=None,
            FRSPaymentInformation=None,
            FreightShipmentInformation=None,
            GoodsNotInFreeCirculationIndicator=None,
            Service=(
                UOMCodeDescriptionType(Code=service, Description=None) if service is not None else None
            ),
            NumOfPieces=None,  # Only required for Freight
            ShipmentTotalWeight=None,  # Only required for "timeintransit" requests
            DocumentsOnlyIndicator="" if is_document else None,
            Package=[
                PackageType(
                    PackagingType=UOMCodeDescriptionType(
                        Code=(
                            mps_packaging or RatingPackagingType[package.packaging_type or "small_box"].value
                        ),
                        Description=None,
                    ),
                    Dimensions=DimensionsType(
                        UnitOfMeasurement=UOMCodeDescriptionType(
                            Code=package.dimension_unit.value, Description=None
                        ),
                        Length=package.length.value,
                        Width=package.width.value,
                        Height=package.height.value,
                    )
                    if any(
                        [
                            package.length.value,
                            package.height.value,
                            package.width.value,
                        ]
                    )
                    else None,
                    DimWeight=None,
                    PackageWeight=PackageWeightType(
                        UnitOfMeasurement=UOMCodeDescriptionType(
                            Code=UPSWeightUnit[package.weight_unit.name].value,
                            Description=None,
                        ),
                        Weight=package.weight.value,
                    )
                    if package.weight.value
                    else None,
                    Commodity=None,
                    PackageServiceOptions=None,
                    AdditionalHandlingIndicator=None,
                )
                for package in packages
            ],
            ShipmentServiceOptions=None,
            ShipmentRatingOptions=ShipmentRatingOptionsType(
                NegotiatedRatesIndicator=""
            ),
            InvoiceLineTotal=None,
            RatingMethodRequestedIndicator=None,
            TaxInformationIndicator=None,
            PromotionalDiscountInformation=None,
            DeliveryTimeInformation=TimeInTransitRequestType(
                PackageBillType="02" if is_document else "03"
            ),
        ),
    )
    return Serializable(
        create_envelope(header_content=settings.Security, body_content=request),
        _request_serializer,
    )
예제 #3
0
def freight_rate_request(
        payload: RateRequest,
        settings: Settings) -> Serializable[FreightRateRequest]:
    packages = Packages(payload.parcels, PackagePresets)
    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=package.parcel.description or "...",
                Weight=WeightType(
                    UnitOfMeasurement=UnitOfMeasurementType(
                        Code=UPSWeightUnit[package.weight_unit].value),
                    Value=package.weight.value,
                ),
                Dimensions=DimensionsType(
                    UnitOfMeasurement=UnitOfMeasurementType(
                        Code=package.dimension_unit),
                    Width=package.width.value,
                    Height=package.height.value,
                    Length=package.length.value,
                ),
                NumberOfPieces=None,
                PackagingType=RateCodeDescriptionType(
                    Code=FreightPackagingType[package.packaging_type
                                              or "small_box"].value,
                    Description=None,
                ),
                FreightClass=50,
            ) for package in packages
        ],
    )
    return Serializable(
        create_envelope(header_content=settings.Security,
                        body_content=request),
        _request_serializer,
    )
def non_contract_shipment_request(
        payload: ShipmentRequest,
        settings: Settings) -> Serializable[NonContractShipmentType]:
    package = Packages(payload.parcels, PackagePresets).single

    if package.weight.value is None:
        raise FieldError({"parcel.weight": FieldErrorCode.required})

    service = ServiceType[payload.service].value
    options = Options(payload.options)

    def compute_amount(code: str, _: Any):
        if code == OptionCode.insurance.value:
            return options.insurance.amount
        if code == OptionCode.cash_on_delivery.value:
            return options.cash_on_delivery.amount
        return None

    special_services = {
        OptionCode[name].value: compute_amount(OptionCode[name].value, value)
        for name, value in payload.options.items()
        if name in OptionCode.__members__
    }

    request = NonContractShipmentType(
        requested_shipping_point=None,
        delivery_spec=DeliverySpecType(
            service_code=service,
            sender=SenderType(
                name=payload.shipper.person_name,
                company=payload.shipper.company_name,
                contact_phone=payload.shipper.phone_number,
                address_details=DomesticAddressDetailsType(
                    address_line_1=concat_str(payload.shipper.address_line1,
                                              join=True),
                    address_line_2=concat_str(payload.shipper.address_line2,
                                              join=True),
                    city=payload.shipper.city,
                    prov_state=payload.shipper.state_code,
                    postal_zip_code=payload.shipper.postal_code,
                ),
            ),
            destination=DestinationType(
                name=payload.recipient.person_name,
                company=payload.recipient.company_name,
                additional_address_info=None,
                client_voice_number=None,
                address_details=DestinationAddressDetailsType(
                    address_line_1=concat_str(payload.recipient.address_line1,
                                              join=True),
                    address_line_2=concat_str(payload.recipient.address_line2,
                                              join=True),
                    city=payload.recipient.city,
                    prov_state=payload.recipient.state_code,
                    country_code=payload.recipient.country_code,
                    postal_zip_code=payload.recipient.postal_code,
                ),
            ),
            options=optionsType(option=[
                OptionType(
                    option_code=code,
                    option_amount=amount,
                    option_qualifier_1=None,
                    option_qualifier_2=None,
                ) for code, amount in special_services.items()
            ]) if len(special_services) > 0 else None,
            parcel_characteristics=ParcelCharacteristicsType(
                weight=package.weight.KG,
                dimensions=dimensionsType(
                    length=package.length.CM,
                    width=package.width.CM,
                    height=package.height.CM,
                ),
                unpackaged=None,
                mailing_tube=None,
            ),
            notification=NotificationType(
                email=options.notification.email or payload.shipper.email,
                on_shipment=True,
                on_exception=True,
                on_delivery=True,
            ) if options.notification else None,
            preferences=PreferencesType(
                show_packing_instructions=True,
                show_postage_rate=True,
                show_insured_value=("insurance" in payload.options)),
            references=ReferencesType(
                cost_centre=None,
                customer_ref_1=payload.reference,
                customer_ref_2=None,
            ),
            customs=CustomsType(
                currency=Currency.AUD.value,
                conversion_from_cad=None,
                reason_for_export=payload.customs.terms_of_trade,
                other_reason=payload.customs.description,
                duties_and_taxes_prepaid=payload.customs.duty.account_number,
                certificate_number=None,
                licence_number=None,
                invoice_number=None,
                sku_list=sku_listType(item=[
                    SkuType(
                        customs_number_of_units=item.quantity,
                        customs_description=item.description,
                        sku=item.sku,
                        hs_tariff_code=None,
                        unit_weight=WeightUnit.KG.value,
                        customs_value_per_unit=item.value_amount,
                        customs_unit_of_measure=None,
                        country_of_origin=payload.shipper.country_code,
                        province_of_origin=None,
                    ) for item in payload.customs.commodities
                ]),
            ) if payload.customs is not None else None,
            settlement_info=None,
        ),
    )
    return Serializable(request, _request_serializer)
예제 #5
0
def rate_request(payload: RateRequest,
                 settings: Settings) -> Serializable[FedexRateRequest]:
    packages = Packages(payload.parcels, PackagePresets, required=["weight"])
    package_type = (PackagingType[packages[0].packaging_type
                                  or "your_packaging"].value
                    if len(packages) == 1 else None)
    service = next((ServiceType[s].value
                    for s in payload.services if s in ServiceType.__members__),
                   None)
    options = Options(payload.options)

    request = FedexRateRequest(
        WebAuthenticationDetail=settings.webAuthenticationDetail,
        ClientDetail=settings.clientDetail,
        TransactionDetail=TransactionDetail(CustomerTransactionId="FTC"),
        Version=VersionId(ServiceId="crs", Major=26, Intermediate=0, Minor=0),
        ReturnTransitAndCommit=True,
        CarrierCodes=None,
        VariableOptions=None,
        ConsolidationKey=None,
        RequestedShipment=RequestedShipment(
            ShipTimestamp=datetime.now(),
            DropoffType="REGULAR_PICKUP",
            ServiceType=service,
            PackagingType=package_type,
            VariationOptions=None,
            TotalWeight=FedexWeight(
                Units=WeightUnits.LB.value,
                Value=packages.weight.LB,
            ),
            TotalInsuredValue=None,
            PreferredCurrency=options.currency,
            ShipmentAuthorizationDetail=None,
            Shipper=Party(
                AccountNumber=settings.account_number,
                Tins=[
                    TaxpayerIdentification(TinType=None, Number=tax)
                    for tax in [
                        payload.shipper.federal_tax_id,
                        payload.shipper.state_tax_id,
                    ]
                ] if any([
                    payload.shipper.federal_tax_id,
                    payload.shipper.state_tax_id
                ]) else None,
                Contact=Contact(
                    ContactId=None,
                    PersonName=payload.shipper.person_name,
                    Title=None,
                    CompanyName=payload.shipper.company_name,
                    PhoneNumber=payload.shipper.phone_number,
                    PhoneExtension=None,
                    TollFreePhoneNumber=None,
                    PagerNumber=None,
                    FaxNumber=None,
                    EMailAddress=payload.shipper.email,
                ) if any((
                    payload.shipper.company_name,
                    payload.shipper.person_name,
                    payload.shipper.phone_number,
                    payload.shipper.email,
                )) else None,
                Address=Address(
                    StreetLines=concat_str(payload.shipper.address_line1,
                                           payload.shipper.address_line2),
                    City=payload.shipper.city,
                    StateOrProvinceCode=payload.shipper.state_code,
                    PostalCode=payload.shipper.postal_code,
                    UrbanizationCode=None,
                    CountryCode=payload.shipper.country_code,
                    CountryName=None,
                    Residential=None,
                    GeographicCoordinates=None,
                ),
            ),
            Recipient=Party(
                AccountNumber=None,
                Tins=[
                    TaxpayerIdentification(TinType=None, Number=tax)
                    for tax in [
                        payload.recipient.federal_tax_id,
                        payload.recipient.state_tax_id,
                    ]
                ] if any([
                    payload.recipient.federal_tax_id,
                    payload.recipient.state_tax_id
                ]) else None,
                Contact=Contact(
                    ContactId=None,
                    PersonName=payload.recipient.person_name,
                    Title=None,
                    CompanyName=payload.recipient.company_name,
                    PhoneNumber=payload.recipient.phone_number,
                    PhoneExtension=None,
                    TollFreePhoneNumber=None,
                    PagerNumber=None,
                    FaxNumber=None,
                    EMailAddress=payload.recipient.email,
                ) if any((
                    payload.recipient.company_name,
                    payload.recipient.person_name,
                    payload.recipient.phone_number,
                    payload.recipient.email,
                )) else None,
                Address=Address(
                    StreetLines=concat_str(
                        payload.recipient.address_line1,
                        payload.recipient.address_line2,
                    ),
                    City=payload.recipient.city,
                    StateOrProvinceCode=payload.recipient.state_code,
                    PostalCode=payload.recipient.postal_code,
                    UrbanizationCode=None,
                    CountryCode=payload.recipient.country_code,
                    CountryName=None,
                    Residential=None,
                    GeographicCoordinates=None,
                ),
            ),
            RecipientLocationNumber=None,
            Origin=None,
            SoldTo=None,
            ShippingChargesPayment=None,
            SpecialServicesRequested=None,
            ExpressFreightDetail=None,
            FreightShipmentDetail=None,
            DeliveryInstructions=None,
            VariableHandlingChargeDetail=None,
            CustomsClearanceDetail=None,
            PickupDetail=None,
            SmartPostDetail=None,
            BlockInsightVisibility=None,
            LabelSpecification=None,
            ShippingDocumentSpecification=None,
            RateRequestTypes=(
                ["LIST"] +
                ([] if "currency" not in payload.options else ["PREFERRED"])),
            EdtRequestType=None,
            PackageCount=len(packages),
            ShipmentOnlyFields=None,
            ConfigurationData=None,
            RequestedPackageLineItems=[
                RequestedPackageLineItem(
                    SequenceNumber=index,
                    GroupNumber=None,
                    GroupPackageCount=1,
                    VariableHandlingChargeDetail=None,
                    InsuredValue=None,
                    Weight=FedexWeight(
                        Units=package.weight_unit.value,
                        Value=package.weight.value,
                    ) if package.weight.value is not None else None,
                    Dimensions=Dimensions(
                        Length=package.length.value,
                        Width=package.width.value,
                        Height=package.height.value,
                        Units=package.dimension_unit.value,
                    ) if any([
                        package.length.value, package.width.value,
                        package.height.value
                    ]) else None,
                    PhysicalPackaging=None,
                    ItemDescription=package.parcel.description,
                    ItemDescriptionForClearance=None,
                    CustomerReferences=None,
                    SpecialServicesRequested=None,
                    ContentRecords=None,
                ) for index, package in enumerate(packages, 1)
            ],
        ),
    )
    return Serializable(request, _request_serializer)
예제 #6
0
def contract_shipment_request(
    payload: ShipmentRequest, settings: Settings
) -> Serializable[ShipmentType]:
    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)

    def compute_amount(code: str, _: Any):
        if code == OptionCode.insurance.value:
            return options.insurance.amount
        if code == OptionCode.cash_on_delivery.value:
            return options.cash_on_delivery.amount
        return None

    special_services = {
        OptionCode[name].value: compute_amount(OptionCode[name].value, value)
        for name, value in payload.options.items()
        if name in OptionCode.__members__
    }
    payment_type = (
        PaymentType[payload.payment.paid_by].value
        if payload.payment is not None
        else None
    )

    request = ShipmentType(
        customer_request_id=None,
        groupIdOrTransmitShipment=groupIdOrTransmitShipment(),
        quickship_label_requested=None,
        cpc_pickup_indicator=None,
        requested_shipping_point=payload.shipper.postal_code,
        shipping_point_id=None,
        expected_mailing_date=None,
        provide_pricing_info=True,
        provide_receipt_info=None,
        delivery_spec=DeliverySpecType(
            service_code=service,
            sender=SenderType(
                name=payload.shipper.person_name,
                company=payload.shipper.company_name,
                contact_phone=payload.shipper.phone_number,
                address_details=AddressDetailsType(
                    city=payload.shipper.city,
                    prov_state=payload.shipper.state_code,
                    country_code=payload.shipper.country_code,
                    postal_zip_code=payload.shipper.postal_code,
                    address_line_1=concat_str(payload.shipper.address_line1, join=True),
                    address_line_2=concat_str(payload.shipper.address_line2, join=True),
                ),
            ),
            destination=DestinationType(
                name=payload.recipient.person_name,
                company=payload.recipient.company_name,
                additional_address_info=None,
                client_voice_number=None,
                address_details=DestinationAddressDetailsType(
                    city=payload.recipient.city,
                    prov_state=payload.recipient.state_code,
                    country_code=payload.recipient.country_code,
                    postal_zip_code=payload.recipient.postal_code,
                    address_line_1=concat_str(
                        payload.recipient.address_line1, join=True
                    ),
                    address_line_2=concat_str(
                        payload.recipient.address_line2, join=True
                    ),
                ),
            ),
            parcel_characteristics=ParcelCharacteristicsType(
                weight=package.weight.KG,
                dimensions=dimensionsType(
                    length=package.length.CM,
                    width=package.width.CM,
                    height=package.height.CM,
                ),
                unpackaged=None,
                mailing_tube=None,
            ),
            options=optionsType(
                option=[
                    OptionType(
                        option_code=code,
                        option_amount=amount,
                        option_qualifier_1=None,
                        option_qualifier_2=None,
                    )
                    for code, amount in special_services.items()
                ]
            )
            if len(special_services) > 0
            else None,
            notification=NotificationType(
                email=options.notification.email or payload.shipper.email,
                on_shipment=True,
                on_exception=True,
                on_delivery=True,
            )
            if options.notification
            else None,
            print_preferences=PrintPreferencesType(
                output_format=PrinterType[options.printing or "regular"].value,
                encoding=None,
            ),
            preferences=PreferencesType(
                service_code=None,
                show_packing_instructions=True,
                show_postage_rate=True,
                show_insured_value=True,
            ),
            customs=CustomsType(
                currency=Currency.AUD.value,
                conversion_from_cad=None,
                reason_for_export=payload.customs.terms_of_trade,
                other_reason=payload.customs.description,
                duties_and_taxes_prepaid=payload.customs.duty.account_number,
                certificate_number=None,
                licence_number=None,
                invoice_number=None,
                sku_list=sku_listType(
                    item=[
                        SkuType(
                            customs_number_of_units=item.quantity,
                            customs_description=item.description,
                            sku=item.sku,
                            hs_tariff_code=None,
                            unit_weight=WeightUnit.KG.value,
                            customs_value_per_unit=item.value_amount,
                            customs_unit_of_measure=DimensionUnit.CM.value,
                            country_of_origin=payload.shipper.country_code,
                            province_of_origin=None,
                        )
                        for item in payload.customs.commodities
                    ]
                ),
            )
            if payload.customs is not None
            else None,
            references=ReferencesType(
                cost_centre=None,
                customer_ref_1=payload.reference,
                customer_ref_2=None,
            ),
            settlement_info=SettlementInfoType(
                paid_by_customer=(
                    payload.payment.account_number
                    if payload.payment is not None
                    else settings.customer_number
                ),
                contract_id=settings.contract_id,
                cif_shipment=None,
                intended_method_of_payment=payment_type,
                promo_code=None,
            ),
        ),
        return_spec=None,
        pre_authorized_payment=None,
    )
    return Serializable(request, _request_serializer)