예제 #1
0
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)
예제 #2
0
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)
예제 #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,
    )
예제 #4
0
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)
예제 #5
0
파일: create.py 프로젝트: iliaaz/purplship
def shipment_request(payload: ShipmentRequest,
                     settings: Settings) -> Serializable[UPSShipmentRequest]:
    packages = Packages(payload.parcels, PackagePresets)
    is_document = all([parcel.is_document for parcel in payload.parcels])
    package_description = packages[0].parcel.description if len(
        packages) == 1 else None
    options = Options(payload.options)
    service = ShippingServiceCode[payload.service].value

    if any(key in service for key in ["freight", "ground"]):
        packages.validate(required=["weight"])

    charges: Dict[str, Payment] = {
        "01": payload.payment,
        "02": payload.customs.duty if payload.customs is not None else None,
    }
    mps_packaging = (ShippingPackagingType.your_packaging.value
                     if len(packages) > 1 else None)
    label_format, label_height, label_width = LabelType[payload.label_type
                                                        or 'PDF_6x4'].value

    request = UPSShipmentRequest(
        Request=common.RequestType(
            RequestOption=["validate"],
            SubVersion=None,
            TransactionReference=common.TransactionReferenceType(
                CustomerContext=payload.reference, TransactionIdentifier=None),
        ),
        Shipment=ShipmentType(
            Description=package_description,
            DocumentsOnlyIndicator="" if is_document else None,
            Shipper=ShipperType(
                Name=payload.shipper.company_name,
                AttentionName=payload.shipper.person_name,
                CompanyDisplayableName=None,
                TaxIdentificationNumber=payload.shipper.federal_tax_id,
                TaxIDType=None,
                Phone=(ShipPhoneType(Number=payload.shipper.phone_number,
                                     Extension=None)
                       if payload.shipper.phone_number is not None else None),
                ShipperNumber=settings.account_number,
                FaxNumber=None,
                EMailAddress=payload.shipper.email,
                Address=ShipAddressType(
                    AddressLine=SF.concat_str(payload.shipper.address_line1,
                                              payload.shipper.address_line2),
                    City=payload.shipper.city,
                    StateProvinceCode=payload.shipper.state_code,
                    PostalCode=payload.shipper.postal_code,
                    CountryCode=payload.shipper.country_code,
                ),
            ),
            ShipTo=ShipToType(
                Name=payload.recipient.company_name,
                AttentionName=payload.recipient.person_name,
                CompanyDisplayableName=None,
                TaxIdentificationNumber=payload.recipient.federal_tax_id,
                TaxIDType=None,
                Phone=(ShipPhoneType(Number=payload.recipient.phone_number,
                                     Extension=None) if
                       payload.recipient.phone_number is not None else None),
                FaxNumber=None,
                EMailAddress=payload.recipient.email,
                Address=ShipAddressType(
                    AddressLine=SF.concat_str(
                        payload.recipient.address_line1,
                        payload.recipient.address_line2,
                    ),
                    City=payload.recipient.city,
                    StateProvinceCode=payload.recipient.state_code,
                    PostalCode=payload.recipient.postal_code,
                    CountryCode=payload.recipient.country_code,
                ),
            ),
            PaymentInformation=PaymentInfoType(
                ShipmentCharge=[
                    ShipmentChargeType(
                        Type=charge_type,
                        BillShipper=BillShipperType(
                            AccountNumber=settings.account_number,
                            CreditCard=None,
                            AlternatePaymentMethod=None,
                        ) if payment.paid_by == PaymentType.sender.name else
                        None,
                        BillReceiver=BillReceiverType(
                            AccountNumber=payment.account_number,
                            Address=BillReceiverAddressType(
                                PostalCode=payload.recipient.postal_code),
                        ) if payment.paid_by == PaymentType.recipient.name else
                        None,
                        BillThirdParty=BillThirdPartyChargeType(
                            AccountNumber=payment.account_number, ) if payment.
                        paid_by == PaymentType.third_party.name else None,
                        ConsigneeBilledIndicator=None,
                    ) for charge_type, payment in charges.items()
                    if payment is not None
                ],
                SplitDutyVATIndicator=None,
            ) if any(charges.values()) else None,
            Service=(ServiceType(
                Code=service) if service is not None else None),
            ShipmentServiceOptions=(ShipmentServiceOptionsType(
                COD=(CODType(
                    CODFundsCode=None,
                    CODAmount=CurrencyMonetaryType(
                        CurrencyCode=options.currency or "USD",
                        MonetaryValue=options.cash_on_delivery,
                    ),
                ) if options.cash_on_delivery else None),
                Notification=([
                    NotificationType(
                        NotificationCode=event,
                        EMail=EmailDetailsType(EMailAddress=[
                            options.notification_email
                            or payload.recipient.email
                        ]),
                        VoiceMessage=None,
                        TextMessage=None,
                        Locale=None,
                    ) for event in [8]
                ] if options.notification_email is not None else None),
            ) if any([options.cash_on_delivery, options.notification_email])
                                    else None),
            Package=[
                PackageType(
                    Description=package.parcel.description,
                    Packaging=PackagingType(
                        Code=mps_packaging or ShippingPackagingType[
                            package.packaging_type or "your_packaging"].value),
                    Dimensions=DimensionsType(
                        UnitOfMeasurement=ShipUnitOfMeasurementType(
                            Code=package.dimension_unit.value, ),
                        Length=package.length.value,
                        Width=package.width.value,
                        Height=package.height.value,
                    ),
                    PackageWeight=PackageWeightType(
                        UnitOfMeasurement=ShipUnitOfMeasurementType(
                            Code=UPSWeightUnit[
                                package.weight_unit.name].value, ),
                        Weight=package.weight.value,
                    ),
                ) for package in packages
            ],
        ),
        LabelSpecification=LabelSpecificationType(
            LabelImageFormat=LabelImageFormatType(Code=label_format,
                                                  Description=None),
            HTTPUserAgent=None,
            LabelStockSize=LabelStockSizeType(Height=label_height,
                                              Width=label_width),
            Instruction=None,
            CharacterSet=None,
        ),
        ReceiptSpecification=None,
    )
    return Serializable(
        create_envelope(header_content=settings.Security,
                        body_content=request),
        _request_serializer,
    )
예제 #6
0
def _pickup_request(payload: PickupRequest,
                    settings: Settings) -> Serializable[CreatePickupRequest]:
    same_day = DF.date(payload.pickup_date).date() == datetime.today().date()
    packages = Packages(payload.parcels, PackagePresets, required=["weight"])

    request = CreatePickupRequest(
        WebAuthenticationDetail=settings.webAuthenticationDetail,
        ClientDetail=settings.clientDetail,
        TransactionDetail=TransactionDetail(CustomerTransactionId="FTC"),
        Version=VersionId(ServiceId="disp", Major=22, Intermediate=0, Minor=0),
        AssociatedAccountNumber=AssociatedAccount(
            Type=AssociatedAccountNumberType.FEDEX_EXPRESS.value,
            AccountNumber=settings.account_number,
        ),
        TrackingNumber=None,
        OriginDetail=PickupOriginDetail(
            UseAccountAddress=None,
            PickupLocation=ContactAndAddress(
                Contact=Contact(
                    ContactId=None,
                    PersonName=payload.address.person_name,
                    CompanyName=payload.address.company_name,
                    PhoneNumber=payload.address.phone_number,
                    EMailAddress=payload.address.email,
                ),
                Address=Address(
                    StreetLines=SF.concat_str(payload.address.address_line1,
                                              payload.address.address_line2),
                    City=payload.address.city,
                    StateOrProvinceCode=payload.address.state_code,
                    PostalCode=payload.address.postal_code,
                    CountryCode=payload.address.country_code,
                    Residential=payload.address.residential,
                ),
            ),
            PackageLocation=payload.package_location,
            ReadyTimestamp=f"{payload.pickup_date}T{payload.ready_time}:00",
            CompanyCloseTime=f"{payload.closing_time}:00",
            PickupDateType=(PickupRequestType.SAME_DAY if same_day else
                            PickupRequestType.FUTURE_DAY).value,
            LastAccessTime=None,
            GeographicalPostalCode=None,
            Location=payload.package_location,
            DeleteLastUsed=None,
            SuppliesRequested=None,
            EarlyPickup=None,
        ),
        PickupServiceCategory=None,
        FreightPickupDetail=None,
        ExpressFreightDetail=None,
        PackageCount=len(packages) or 1,
        TotalWeight=Weight(Units=WeightUnits.LB.name, Value=packages.weight.LB)
        if len(packages) > 0 else None,
        CarrierCode=CarrierCodeType.FDXE.value,
        OversizePackageCount=None,
        Remarks=payload.instruction,
        CommodityDescription=None,
        CountryRelationship=None,
    )

    return Serializable(request, _request_serializer)
예제 #7
0
파일: create.py 프로젝트: iliaaz/purplship
def shipment_request(payload: ShipmentRequest, settings: Settings) -> Serializable[DicomShipmentRequest]:
    packages = Packages(payload.parcels)
    is_international = payload.shipper.country_code != payload.recipient.country_code
    broker_info = payload.options.get('dicom_broker_info', {})
    importer_info = (
        Address(**payload.options.get('importer_info'))
        if 'importer_info' in payload.options else None
    )
    delivery_type = Service[payload.service].value
    options = {
        key: (value if Option[key].value in ['DCV', 'COD'] else None)
        for key, value in payload.options
        if key in Option.__members__
    }

    request = DicomShipmentRequest(
        paymentType=PaymentType[payload.payment.paid_by or "prepaid"].value,
        billingAccount=settings.billing_account,
        sender=DicomAddress(
            city=payload.shipper.city,
            provinceCode=payload.shipper.state_code,
            postalCode=payload.shipper.postal_code,
            countryCode=payload.shipper.country_code,
            customerName=payload.shipper.company_name,
            addressLine1=payload.shipper.address_line1,
            addressLine2=payload.shipper.address_line2,
            contact=Contact(
                fullName=payload.shipper.person_name,
                email=payload.shipper.email,
                telephone=payload.shipper.phone_number
            )
        ),
        consignee=DicomAddress(
            city=payload.recipient.city,
            provinceCode=payload.recipient.state_code,
            postalCode=payload.recipient.postal_code,
            countryCode=payload.recipient.country_code,
            customerName=payload.recipient.company_name,
            addressLine1=payload.recipient.address_line1,
            addressLine2=payload.recipient.address_line2,
            contact=Contact(
                fullName=payload.recipient.person_name,
                email=payload.recipient.email,
                telephone=payload.recipient.phone_number
            )
        ),
        parcels=[
            Parcel(
                quantity=1,
                parcelType=ParcelType[package.packaging_type or "dicom_box"].value,
                weight=package.weight.KG,
                length=package.height.CM,
                depth=package.length.CM,
                width=package.width.CM,
                note=None,
                status=None,
                FCAClass=None,
                hazmat=None,
                requestReturnLabel=None,
                returnWaybill=None,
            )
            for package in packages
        ],
        note=None,
        category="Parcel",
        pickupDate=None,
        deliveryType=delivery_type,
        trackingNumber=None,
        unitOfMeasurement=UnitOfMeasurement.KC.value,
        surcharges=[
            Surcharge(type=key, value=value) for key, value in options.items()
        ],
        promoCodes=None,
        references=None,
        returnAddress=None,
        appointment=None,
        internationalDetails=(InternationalDetails(
            isDicomBroker=(broker_info is not None),
            descriptionOfGoods=payload.customs.content_description,
            dutyBilling=payload.customs.duty.paid_by,
            importerOfRecord=(DicomAddress(
                city=importer_info.city,
                provinceCode=importer_info.state_code,
                postalCode=importer_info.postal_code,
                countryCode=importer_info.country_code,
                customerName=importer_info.company_name,
                addressLine1=importer_info.address_line1,
                addressLine2=importer_info.address_line2,
                contact=Contact(
                    fullName=importer_info.person_name,
                    email=importer_info.email,
                    telephone=importer_info.phone_number
                )
            ) if importer_info is not None else None),
            broker=(Broker(
                id=broker_info.get("id"),
                CSA_BusinessNumber=broker_info.get("CSA_BusinessNumber"),
                otherBroker=broker_info.get("otherBroker")
            ) if broker_info is not None else None),
            purpose=(
                Purpose[payload.customs.content_type].value
                if payload.customs.content_type is not None else
                None
            ),
            products=[
                Product(id=index, Quantity=product.quantity)
                for index, product in enumerate(payload.customs.commodities, 1)
            ]
        ) if is_international and payload.customs is not None else None),
    )

    return Serializable(request)
예제 #8
0
def shipment_request(
    payload: ShipmentRequest, settings: Settings
) -> Serializable[DHLShipmentRequest]:
    packages = Packages(payload.parcels, PackagePresets, required=["weight"])
    options = Options(payload.options, SpecialServiceCode)
    product = next(
        (p.value for p in ProductCode if payload.service == p.name),
        payload.service
    )

    insurance = options['dhl_shipment_insurance'].value if 'dhl_shipment_insurance' in options else None
    package_type = (
        PackageType[packages[0].packaging_type or "your_packaging"].value
        if len(packages) == 1 else None
    )
    delivery_type = next(
        (d for d in DeliveryType if d.name in payload.options.keys()), None
    )
    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())
    content = (packages[0].parcel.content or "N/A")

    request = DHLShipmentRequest(
        schemaVersion=6.2,
        Request=settings.Request(
            MetaData=MetaData(SoftwareName="3PV", SoftwareVersion=6.2)
        ),
        RegionCode=CountryRegion[payload.shipper.country_code].value,
        RequestedPickupTime="Y",
        LanguageCode="en",
        PiecesEnabled="Y",
        LatinResponseInd=None,
        Billing=Billing(
            ShipperAccountNumber=settings.account_number,
            BillingAccountNumber=payment.account_number,
            ShippingPaymentType=PaymentType[payment.paid_by].value,
            DutyAccountNumber=(customs.duty.account_number if customs.duty is not None else None),
            DutyPaymentType=(PaymentType[customs.duty.paid_by].value if customs.duty is not None else None),
        ),
        Consignee=Consignee(
            CompanyName=payload.recipient.company_name or "N/A",
            SuiteDepartmentName=None,
            AddressLine=SF.concat_str(
                payload.recipient.address_line1, payload.recipient.address_line2
            ),
            City=payload.recipient.city,
            Division=None,
            DivisionCode=payload.recipient.state_code,
            PostalCode=payload.recipient.postal_code,
            CountryCode=payload.recipient.country_code,
            CountryName=Country[payload.recipient.country_code].value,
            FederalTaxId=payload.shipper.federal_tax_id,
            StateTaxId=payload.shipper.state_tax_id,
            Contact=(
                Contact(
                    PersonName=payload.recipient.person_name,
                    PhoneNumber=payload.recipient.phone_number or "0000",
                    Email=payload.recipient.email,
                )
            ),
            Suburb=None,
        ),
        Commodity=(
            [
                Commodity(CommodityCode=c.sku, CommodityName=c.description)
                for c in payload.customs.commodities
            ]
            if any(customs.commodities) else None
        ),
        NewShipper=None,
        Shipper=Shipper(
            ShipperID=settings.account_number or "N/A",
            RegisteredAccount=settings.account_number,
            AddressLine=SF.concat_str(
                payload.shipper.address_line1, payload.shipper.address_line2
            ),
            CompanyName=payload.shipper.company_name or "N/A",
            PostalCode=payload.shipper.postal_code,
            CountryCode=payload.shipper.country_code,
            City=payload.shipper.city,
            CountryName=Country[payload.shipper.country_code].value,
            Division=None,
            DivisionCode=payload.shipper.state_code,
            Contact=(
                Contact(
                    PersonName=payload.shipper.person_name,
                    PhoneNumber=payload.shipper.phone_number or "0000",
                    Email=payload.shipper.email,
                )
            ),
        ),
        ShipmentDetails=DHLShipmentDetails(
            NumberOfPieces=len(packages),
            Pieces=Pieces(
                Piece=[
                    Piece(
                        PieceID=package.parcel.id,
                        PackageType=(
                            package_type
                            or PackageType[
                                package.packaging_type or "your_packaging"
                            ].value
                        ),
                        Depth=package.length.IN,
                        Width=package.width.IN,
                        Height=package.height.IN,
                        Weight=package.weight.LB,
                        DimWeight=None,
                        PieceContents=(
                            package.parcel.content or package.parcel.description
                        ),
                    )
                    for package in packages
                ]
            ),
            Weight=packages.weight.LB,
            CurrencyCode=options.currency or "USD",
            WeightUnit=WeightUnit.L.value,
            DimensionUnit=DimensionUnit.I.value,
            Date=(options.shipment_date or time.strftime("%Y-%m-%d")),
            PackageType=package_type,
            IsDutiable=("Y" if payload.customs is not None else "N"),
            InsuredAmount=insurance,
            ShipmentCharges=(options.cash_on_delivery if options.cash_on_delivery else None),
            DoorTo=delivery_type,
            GlobalProductCode=product,
            LocalProductCode=product,
            Contents=content,
        ),
        EProcShip=None,
        Dutiable=(
            Dutiable(
                DeclaredCurrency=customs.duty.currency or "USD",
                DeclaredValue=insurance or 1.0,
                TermsOfTrade=customs.incoterm,
            )
            if customs.duty is not None else None
        ),
        ExportDeclaration=None,
        Reference=[Reference(ReferenceID=payload.reference)],
        SpecialService=[
            SpecialService(SpecialServiceType=SpecialServiceCode[key].value.key)
            for key, svc in options if key in SpecialServiceCode
        ],
        Notification=(
            Notification(
                EmailAddress=options.notification_email or payload.recipient.email
            )
            if options.notification_email is None else None
        ),
        DocImages=None,
        RequestArchiveDoc=None,
        NumberOfArchiveDoc=None,
        LabelImageFormat=label_format,
        Label=Label(LabelTemplate=label_template),
        ODDLinkReq=None,
        DGs=None,
    )
    return Serializable(request, _request_serializer)
예제 #9
0
def shipment_request(payload: ShipmentRequest,
                     settings: Settings) -> Serializable[ShipmentType]:
    package = Packages(payload.parcels, PackagePresets,
                       required=['weight']).single
    service = ServiceType[payload.service].value
    options = Options(payload.options, OptionCode)

    is_intl = (payload.recipient.country_code is not None
               and payload.recipient.country_code != 'CA')
    payment_type = (PaymentType[payload.payment.paid_by].value
                    if payload.payment is not None else None)
    all_options = ([
        *options,
        (OptionCode.canadapost_return_to_sender.name,
         OptionCode.canadapost_return_to_sender.value.apply(True))
    ] if is_intl and not any(key in options
                             for key in INTERNATIONAL_NON_DELIVERY_OPTION) else
                   [*options])

    label_encoding, label_format = LabelType[payload.label_type
                                             or 'PDF_4x6'].value

    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=options.shipment_date,
        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 or "Not Applicable",
                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=SF.concat_str(payload.shipper.address_line1,
                                                 join=True),
                    address_line_2=SF.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=payload.recipient.phone_number,
                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=SF.concat_str(
                        payload.recipient.address_line1, join=True),
                    address_line_2=SF.concat_str(
                        payload.recipient.address_line2, join=True),
                ),
            ),
            parcel_characteristics=ParcelCharacteristicsType(
                weight=package.weight.map(MeasurementOptions).KG,
                dimensions=dimensionsType(
                    length=package.length.map(MeasurementOptions).CM,
                    width=package.width.map(MeasurementOptions).CM,
                    height=package.height.map(MeasurementOptions).CM,
                ),
                unpackaged=None,
                mailing_tube=None,
            ),
            options=(optionsType(option=[
                OptionType(
                    option_code=getattr(option, 'key', option),
                    option_amount=getattr(option, 'value', None),
                    option_qualifier_1=None,
                    option_qualifier_2=None,
                ) for code, option in all_options if code in OptionCode
            ]) if any(all_options) else None),
            notification=(NotificationType(
                email=options.notification_email or payload.recipient.email,
                on_shipment=True,
                on_exception=True,
                on_delivery=True,
            ) if options.notification_email else None),
            print_preferences=PrintPreferencesType(
                output_format=label_format,
                encoding=label_encoding,
            ),
            preferences=PreferencesType(
                service_code=None,
                show_packing_instructions=False,
                show_postage_rate=True,
                show_insured_value=True,
            ),
            customs=(CustomsType(
                currency=options.currency or Currency.CAD.value,
                conversion_from_cad=None,
                reason_for_export=payload.customs.content_type,
                other_reason=payload.customs.content_description,
                duties_and_taxes_prepaid=payload.customs.duty.account_number,
                certificate_number=payload.customs.certificate_number,
                licence_number=None,
                invoice_number=payload.customs.invoice,
                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),
            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,
    )
    request.groupIdOrTransmitShipment.original_tagname_ = "transmit-shipment"

    return Serializable(request, _request_serializer)
예제 #10
0
def rate_request(payload: RateRequest, settings: Settings) -> Serializable[RateV4Request]:
    """Create the appropriate USPS rate request depending on the destination

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

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

    if payload.recipient.country_code is not None and payload.recipient.country_code == Country.US.name:
        raise DestinationNotServicedError(payload.recipient.country_code)

    package = Packages(payload.parcels).single
    options = Options(payload.options, ShipmentOption)
    service = (Services(payload.services, ShipmentService).first or ShipmentService.usps_all).value
    special_services = [getattr(option, 'value', option) for key, option in options if 'usps_option' not in key]
    insurance = next(
        (option.value for key, option in options if 'usps_insurance' in key),
        options.insurance
    )

    container = PackagingType[package.packaging_type or "your_packaging"]
    sort_level = SortLevelType[container.name]
    mail_type = (FirstClassMailType[container.name].value if 'first_class' in service else None)

    request = RateV4Request(
        USERID=settings.username,
        Revision="2",
        Package=[
            PackageType(
                ID=0,
                Service=(service or ShipmentService.usps_all).value,
                FirstClassMailType=mail_type,
                ZipOrigination=payload.shipper.postal_code,
                ZipDestination=payload.recipient.postal_code,
                Pounds=package.weight.LB,
                Ounces=package.weight.OZ,
                Container=container.value,
                Width=package.width.IN,
                Length=package.length.IN,
                Height=package.height.IN,
                Girth=package.girth.value,
                Value=insurance,
                AmountToCollect=options.cash_on_delivery,
                SpecialServices=(
                    SpecialServicesType(SpecialService=[s.value for s in special_services])
                    if any(special_services) else None
                ),
                Content=None,
                GroundOnly=options["usps_option_ground_only"],
                SortBy=sort_level.value,
                Machinable=options["usps_option_machinable_item"],
                ReturnLocations=options["usps_option_return_service_info"],
                ReturnServiceInfo=options["usps_option_return_service_info"],
                DropOffTime=('13:30' if options.shipment_date is not None else None),
                ShipDate=ShipDateType(valueOf_=DF.fdate(options.shipment_date)),
            )
        ],
    )

    return Serializable(request, XP.export)
예제 #11
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, default_request_serializer)
예제 #12
0
def dct_request(payload: RateRequest,
                settings: Settings) -> Serializable[DCTRequest]:
    packages = Packages(payload.parcels, PackagePresets, required=["weight"])
    options = Options(payload.options)
    is_international = payload.shipper.country_code != payload.recipient.country_code
    is_document = all([parcel.is_document for parcel in payload.parcels])
    is_dutiable = not is_document
    products = [
        ProductCode[svc].value for svc in payload.services
        if svc in ProductCode.__members__
    ]
    special_services = [
        SpecialServiceCode[s].value for s in payload.options.keys()
        if s in SpecialServiceCode.__members__
    ]
    if is_international and is_dutiable:
        special_services.append(SpecialServiceCode.dhl_paperless_trade.value)
    if len(products) == 0:
        if is_international:
            products = [(ProductCode.dhl_express_worldwide_doc if is_document
                         else ProductCode.dhl_express_worldwide_nondoc).value]
        else:
            products = [(ProductCode.dhl_express_easy_doc if is_document else
                         ProductCode.dhl_express_easy_nondoc).value]

    request = DCTRequest(GetQuote=GetQuoteType(
        Request=settings.Request(
            MetaData=MetaData(SoftwareName="3PV", SoftwareVersion=1.0)),
        From=DCTFrom(
            CountryCode=payload.shipper.country_code,
            Postalcode=payload.shipper.postal_code,
            City=payload.shipper.city,
            Suburb=payload.shipper.state_code,
        ),
        To=DCTTo(
            CountryCode=payload.recipient.country_code,
            Postalcode=payload.recipient.postal_code,
            City=payload.recipient.city,
            Suburb=payload.recipient.state_code,
        ),
        BkgDetails=BkgDetailsType(
            PaymentCountryCode=payload.shipper.country_code,
            NetworkTypeCode=NetworkType.both_time_and_day_definite.value,
            WeightUnit=WeightUnit.LB.value,
            DimensionUnit=DimensionUnit.IN.value,
            ReadyTime=time.strftime("PT%HH%MM"),
            Date=time.strftime("%Y-%m-%d"),
            IsDutiable=("Y" if is_dutiable else "N"),
            Pieces=PiecesType(Piece=[
                PieceType(
                    PieceID=package.parcel.id or f"{index}",
                    PackageTypeCode=DCTPackageType[package.packaging_type
                                                   or "your_packaging"].value,
                    Depth=package.length.IN,
                    Width=package.width.IN,
                    Height=package.height.IN,
                    Weight=package.weight.LB,
                ) for index, package in enumerate(
                    cast(Iterable[Package], packages), 1)
            ]),
            NumberOfPieces=len(packages),
            ShipmentWeight=packages.weight.LB,
            Volume=None,
            PaymentAccountNumber=settings.account_number,
            InsuredCurrency=options.currency
            if options.insurance is not None else None,
            InsuredValue=options.insurance.amount
            if options.insurance is not None else None,
            PaymentType=None,
            AcctPickupCloseTime=None,
            QtdShp=[
                QtdShpType(
                    GlobalProductCode=product,
                    LocalProductCode=product,
                    QtdShpExChrg=[
                        QtdShpExChrgType(SpecialServiceType=service)
                        for service in special_services
                    ],
                ) for product in products
            ],
        ),
        Dutiable=DCTDutiable(
            DeclaredValue=payload.options.get('value', 1.0),
            DeclaredCurrency=options.currency,
        ) if is_international and is_dutiable else None,
    ), )
    return Serializable(request, _request_serializer)
예제 #13
0
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)
예제 #14
0
def shipping_request(
        payload: ShipmentRequest, settings: Settings
) -> Serializable[EShipper]:
    packages = Packages(payload.parcels, required=["weight", "height", "width", "length"])
    options = Options(payload.options, Option)

    service = Service.map(payload.service).value_or_key
    packaging_type = PackagingType[packages.package_type or "eshipper_boxes"].value
    packaging = ("Pallet" if packaging_type in [PackagingType.pallet.value] else "Package")
    freight_class = (
        FreightClass[payload.options["freight_class"]].value
        if payload.options.get("freight_class") in FreightClass
        else None
    )
    payment_type = (
        PaymentType[payload.payment.paid_by].value if payload.payment else None
    )
    item = next(
        iter(payload.customs.commodities if payload.customs is not None else []), None
    )
    payer: Address = {
        PaymentType.sender: payload.shipper,
        PaymentType.recipient: payload.recipient,
        PaymentType.third_party: payload.recipient,
    }.get(PaymentType[payload.payment.paid_by]) if payload.payment else None

    request = EShipper(
        username=settings.username,
        password=settings.password,
        version="3.0.0",
        ShippingRequest=ShippingRequestType(
            saturdayPickupRequired=options.eshipper_saturday_pickup_required,
            homelandSecurity=options.eshipper_homeland_security,
            pierCharge=None,
            exhibitionConventionSite=options.eshipper_exhibition_convention_site,
            militaryBaseDelivery=options.eshipper_military_base_delivery,
            customsIn_bondFreight=options.eshipper_customs_in_bond_freight,
            limitedAccess=options.eshipper_limited_access,
            excessLength=options.eshipper_excess_length,
            tailgatePickup=options.eshipper_tailgate_pickup,
            residentialPickup=options.eshipper_residential_pickup,
            crossBorderFee=None,
            notifyRecipient=options.eshipper_notify_recipient,
            singleShipment=options.eshipper_single_shipment,
            tailgateDelivery=options.eshipper_tailgate_delivery,
            residentialDelivery=options.eshipper_residential_delivery,
            insuranceType=options.insurance is not None,
            scheduledShipDate=None,
            insideDelivery=options.eshipper_inside_delivery,
            isSaturdayService=options.eshipper_is_saturday_service,
            dangerousGoodsType=options.eshipper_dangerous_goods_type,
            serviceId=service,
            stackable=options.eshipper_stackable,
            From=FromType(
                id=payload.shipper.id,
                company=payload.shipper.company_name,
                instructions=None,
                email=payload.shipper.email,
                attention=payload.shipper.person_name,
                phone=payload.shipper.phone_number,
                tailgateRequired=None,
                residential=payload.shipper.residential,
                address1=SF.concat_str(payload.shipper.address_line1, join=True),
                address2=SF.concat_str(payload.shipper.address_line2, join=True),
                city=payload.shipper.city,
                state=payload.shipper.state_code,
                zip=payload.shipper.postal_code,
                country=payload.shipper.country_code,
            ),
            To=ToType(
                id=payload.recipient.id,
                company=payload.recipient.company_name,
                notifyRecipient=None,
                instructions=None,
                email=payload.recipient.email,
                attention=payload.recipient.person_name,
                phone=payload.recipient.phone_number,
                tailgateRequired=None,
                residential=payload.recipient.residential,
                address1=SF.concat_str(payload.recipient.address_line1, join=True),
                address2=SF.concat_str(payload.recipient.address_line2, join=True),
                city=payload.recipient.city,
                state=payload.recipient.state_code,
                zip=payload.recipient.postal_code,
                country=payload.recipient.country_code,
            ),
            COD=(
                CODType(
                    paymentType=PaymentType.recipient.value,
                    CODReturnAddress=CODReturnAddressType(
                        codCompany=payload.recipient.company_name,
                        codName=payload.recipient.person_name,
                        codAddress1=SF.concat_str(payload.recipient.address_line1, join=True),
                        codCity=payload.recipient.city,
                        codStateCode=payload.recipient.state_code,
                        codZip=payload.recipient.postal_code,
                        codCountry=payload.recipient.country_code,
                    ),
                )
                if options.cash_on_delivery is not None else None
            ),
            Packages=PackagesType(
                Package=[
                    PackageType(
                        length=ceil(package.length.IN),
                        width=ceil(package.width.IN),
                        height=ceil(package.height.IN),
                        weight=ceil(package.weight.LB),
                        type_=packaging_type,
                        freightClass=freight_class,
                        nmfcCode=None,
                        insuranceAmount=None,
                        codAmount=None,
                        description=package.parcel.description,
                    )
                    for package in packages
                ],
                type_=packaging,
            ),
            Payment=(
                RequestPaymentType(type_=payment_type)
                if payload.payment is not None else None
            ),
            Reference=(
                [ReferenceType(name="REF", code=payload.reference)]
                if payload.reference != "" else None
            ),
            CustomsInvoice=(
                CustomsInvoiceType(
                    BillTo=BillToType(
                        company=payer.company_name,
                        name=payer.person_name,
                        address1=SF.concat_str(payer.address_line1, join=True),
                        city=payer.city,
                        state=payer.state_code,
                        zip=payer.postal_code,
                        country=payer.country_code,
                    ),
                    Contact=ContactType(name=payer.person_name, phone=payer.phone_number),
                    Item=ItemType(
                        code=item.sku,
                        description=item.description,
                        originCountry=item.origin_country,
                        quantity=item.quantity,
                        unitPrice=item.value_amount,
                    ),
                )
                if all([payload.customs, payer]) else None
            ),
        ),
    )

    return Serializable(request, standard_request_serializer)
예제 #15
0
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 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 customs.commodities
        ]),
        PurposeOfShipment=ContentType[customs.content_type or 'other'].value,
        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.width.IN,
        Height=package.height.IN,
        Girth=(package.girth.value
               if package.packaging_type == "tube" else None),
        Shape=None,
        CIRequired=customs.commercial_invoice,
        InvoiceDate=DF.fdatetime(customs.invoice_date,
                                 output_format="%m/%d/%Y"),
        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 time.strftime('%Y-%m-%d')),
            current_format="%Y-%m-%d",
            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 or False),
        DestinationRateIndicator="I",
        MID=settings.mailer_id,
        LogisticsManagerMID=settings.logistics_manager_mailer_id,
        CRID=settings.customer_registration_id,
        VendorCode=None,
        VendorProductVersionNumber=None,
        OverrideMID=None,
        ChargebackCode=None,
    )

    return Serializable(request, XP.export)
예제 #17
0
def shipment_request(
    payload: ShipmentRequest, settings: Settings
) -> Serializable[DHLShipmentRequest]:
    packages = Packages(payload.parcels, PackagePresets, required=["weight"])
    is_international = payload.shipper.country_code == payload.recipient.country_code
    options = Options(payload.options)
    product = ProductCode[payload.service].value
    package_type = (
        PackageType[packages[0].packaging_type or "your_packaging"].value
        if len(packages) == 1 else None
    )
    delivery_type = next(
        (d for d in DeliveryType if d.name in payload.options.keys()), None
    )
    special_services = [
        SpecialServiceCode[s].value
        for s in payload.options.keys()
        if s in SpecialServiceCode.__members__
    ]
    if is_international and payload.doc_images is not None:
        special_services.append(SpecialServiceCode.dhl_paperless_trade.value)
    has_payment_config = payload.payment is not None
    has_customs_config = payload.customs is not None

    request = DHLShipmentRequest(
        schemaVersion=6.2,
        Request=settings.Request(
            MetaData=MetaData(SoftwareName="3PV", SoftwareVersion=6.2)
        ),
        RegionCode=CountryRegion[payload.shipper.country_code].value,
        RequestedPickupTime="Y",
        LanguageCode="en",
        PiecesEnabled="Y",
        LatinResponseInd=None,
        Billing=Billing(
            ShipperAccountNumber=settings.account_number,
            BillingAccountNumber=payload.payment.account_number
            if has_payment_config
            else None,
            ShippingPaymentType=PaymentType[payload.payment.paid_by].value
            if has_payment_config
            else None,
            DutyAccountNumber=payload.customs.duty.account_number
            if has_customs_config
            else None,
            DutyPaymentType=PaymentType[payload.customs.duty.paid_by].value
            if has_customs_config
            else None,
        ),
        Consignee=Consignee(
            CompanyName=payload.recipient.company_name or "  ",
            SuiteDepartmentName=None,
            AddressLine=concat_str(
                payload.recipient.address_line1, payload.recipient.address_line2
            ),
            City=payload.recipient.city,
            Division=None,
            DivisionCode=payload.recipient.state_code,
            PostalCode=payload.recipient.postal_code,
            CountryCode=payload.recipient.country_code,
            CountryName=Country[payload.recipient.country_code].value,
            FederalTaxId=payload.shipper.federal_tax_id,
            StateTaxId=payload.shipper.state_tax_id,
            Contact=(
                Contact(
                    PersonName=payload.recipient.person_name,
                    PhoneNumber=payload.recipient.phone_number or "0000",
                    Email=payload.recipient.email,
                )
            ),
            Suburb=None,
        ),
        Commodity=[
            Commodity(CommodityCode=c.sku, CommodityName=c.description)
            for c in payload.customs.commodities
        ] if payload.customs is not None else None,
        NewShipper=None,
        Shipper=Shipper(
            ShipperID=settings.account_number or "  ",
            RegisteredAccount=settings.account_number,
            AddressLine=concat_str(
                payload.shipper.address_line1, payload.shipper.address_line2
            ),
            CompanyName=payload.shipper.company_name or "  ",
            PostalCode=payload.shipper.postal_code,
            CountryCode=payload.shipper.country_code,
            City=payload.shipper.city,
            CountryName=Country[payload.shipper.country_code].value,
            Division=None,
            DivisionCode=payload.shipper.state_code,
            Contact=(
                Contact(
                    PersonName=payload.shipper.person_name,
                    PhoneNumber=payload.shipper.phone_number or "0000",
                    Email=payload.shipper.email,
                )
            ),
        ),
        ShipmentDetails=DHLShipmentDetails(
            NumberOfPieces=len(packages),
            Pieces=Pieces(
                Piece=[
                    Piece(
                        PieceID=payload.parcels[index].id,
                        PackageType=(
                            package_type or PackageType[package.packaging_type or "your_packaging"].value
                        ),
                        Depth=package.length.IN,
                        Width=package.width.IN,
                        Height=package.height.IN,
                        Weight=package.weight.LB,
                        DimWeight=None,
                        PieceContents=payload.parcels[index].description,
                    )
                    for index, package in enumerate(packages)
                ]
            ),
            Weight=packages.weight.LB,
            CurrencyCode=options.currency or "USD",
            WeightUnit=WeightUnit.L.value,
            DimensionUnit=DimensionUnit.I.value,
            Date=time.strftime("%Y-%m-%d"),
            PackageType=package_type,
            IsDutiable="Y" if payload.customs is not None else "N",
            InsuredAmount=options.insurance.amount if options.insurance else None,
            ShipmentCharges=options.cash_on_delivery.amount
            if options.cash_on_delivery
            else None,
            DoorTo=delivery_type,
            GlobalProductCode=product,
            LocalProductCode=product,
            Contents="  ",
        ),
        EProcShip=None,
        Dutiable=Dutiable(
            DeclaredCurrency=payload.customs.duty.currency or "USD",
            DeclaredValue=payload.customs.duty.amount,
            TermsOfTrade=payload.customs.terms_of_trade,
        )
        if payload.customs is not None and payload.customs.duty is not None
        else None,
        ExportDeclaration=None,
        Reference=[Reference(ReferenceID=payload.reference)],
        SpecialService=[
            SpecialService(SpecialServiceType=service) for service in special_services
        ],
        Notification=Notification(
            EmailAddress=options.notification.email or payload.shipper.email,
        )
        if options.notification
        else None,
        LabelImageFormat="PDF",
        DocImages=DocImages(
            DocImage=[
                DocImage(
                    Type=doc.type,
                    ImageFormat=doc.format,
                    Image=b64decode(doc.image + "=" * (-len(doc.image) % 4)),
                )
                for doc in payload.doc_images
            ]
        )
        if len(payload.doc_images) > 0
        else None,
        RequestArchiveDoc=None,
        NumberOfArchiveDoc=None,
        Label=None,
        ODDLinkReq=None,
        DGs=None,
    )
    return Serializable(request, _request_serializer)
예제 #18
0
def shipment_request(payload: ShipmentRequest,
                     _) -> Serializable[NonContractShipmentType]:
    package = Packages(payload.parcels, PackagePresets,
                       required=["weight"]).single
    service = ServiceType[payload.service].value
    options = Options(payload.options, OptionCode)

    is_intl = (payload.recipient.country_code is not None
               and payload.recipient.country_code != 'CA')
    all_options = ([*options] +
                   [(OptionCode.canadapost_return_to_sender.name,
                     OptionCode.canadapost_return_to_sender.value.apply(True))]
                   if is_intl
                   and not any(key in options
                               for key in INTERNATIONAL_NON_DELIVERY_OPTION)
                   else [*options])

    request = NonContractShipmentType(
        requested_shipping_point=None,
        delivery_spec=DeliverySpecType(
            service_code=service,
            sender=SenderType(
                name=payload.shipper.person_name,
                company=payload.shipper.company_name,
                contact_phone=payload.shipper.phone_number,
                address_details=DomesticAddressDetailsType(
                    address_line_1=SF.concat_str(payload.shipper.address_line1,
                                                 join=True),
                    address_line_2=SF.concat_str(payload.shipper.address_line2,
                                                 join=True),
                    city=payload.shipper.city,
                    prov_state=payload.shipper.state_code,
                    postal_zip_code=payload.shipper.postal_code,
                ),
            ),
            destination=DestinationType(
                name=payload.recipient.person_name,
                company=payload.recipient.company_name,
                additional_address_info=None,
                client_voice_number=payload.recipient.phone_number,
                address_details=DestinationAddressDetailsType(
                    address_line_1=SF.concat_str(
                        payload.recipient.address_line1, join=True),
                    address_line_2=SF.concat_str(
                        payload.recipient.address_line2, join=True),
                    city=payload.recipient.city,
                    prov_state=payload.recipient.state_code,
                    country_code=payload.recipient.country_code,
                    postal_zip_code=payload.recipient.postal_code,
                ),
            ),
            options=(optionsType(option=[
                OptionType(
                    option_code=getattr(option, 'key', option),
                    option_amount=getattr(option, 'value', None),
                    option_qualifier_1=None,
                    option_qualifier_2=None,
                ) for code, option in all_options if code in OptionCode
            ]) if any(options) else None),
            parcel_characteristics=ParcelCharacteristicsType(
                weight=NF.decimal(package.weight.KG, .1),
                dimensions=dimensionsType(
                    length=NF.decimal(package.length.CM, .1),
                    width=NF.decimal(package.width.CM, .1),
                    height=NF.decimal(package.height.CM, .1),
                ),
                unpackaged=None,
                mailing_tube=None,
            ),
            notification=(NotificationType(
                email=options.notification_email or payload.recipient.email,
                on_shipment=True,
                on_exception=True,
                on_delivery=True,
            ) if options.notification_email is not None else None),
            preferences=PreferencesType(
                show_packing_instructions=False,
                show_postage_rate=True,
                show_insured_value=("insurance" in payload.options),
            ),
            references=ReferencesType(
                cost_centre=None,
                customer_ref_1=payload.reference,
                customer_ref_2=None,
            ),
            customs=(CustomsType(
                currency=Currency.AUD.value,
                conversion_from_cad=None,
                reason_for_export=payload.customs.incoterm,
                other_reason=payload.customs.content_description,
                duties_and_taxes_prepaid=payload.customs.duty.account_number,
                certificate_number=None,
                licence_number=None,
                invoice_number=None,
                sku_list=sku_listType(item=[
                    SkuType(
                        customs_number_of_units=item.quantity,
                        customs_description=item.description,
                        sku=item.sku,
                        hs_tariff_code=None,
                        unit_weight=WeightUnit.KG.value,
                        customs_value_per_unit=item.value_amount,
                        customs_unit_of_measure=None,
                        country_of_origin=payload.shipper.country_code,
                        province_of_origin=None,
                    ) for item in payload.customs.commodities
                ]),
            ) if payload.customs is not None else None),
            settlement_info=None,
        ),
    )
    return Serializable(request, _request_serializer)
예제 #19
0
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)
예제 #20
0
def freight_ship_request(
        payload: ShipmentRequest,
        settings: Settings) -> Serializable[FreightShipRequest]:
    packages = Packages(payload.parcels, PackagePresets)
    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=package.parcel.id,
                    Description=package.parcel.description,
                    Weight=WeightType(
                        UnitOfMeasurement=FreightShipUnitOfMeasurementType(
                            Code=WeightUnit[package.weight_unit].value),
                        Value=package.weight.value,
                    ),
                    Dimensions=DimensionsType(
                        UnitOfMeasurement=FreightShipUnitOfMeasurementType(
                            Code=package.dimension_unit),
                        Width=package.width.value,
                        Height=package.height.value,
                        Length=package.length.value,
                    ) if any([
                        package.width.value,
                        package.height.value,
                        package.length.value,
                    ]) else None,
                    NumberOfPieces=None,
                    PackagingType=None,
                    DangerousGoodsIndicator=None,
                    CommodityValue=None,
                    FreightClass=freight_class,
                    NMFCCommodityCode=None,
                    NMFCCommodity=None,
                ) for package in packages
            ],
            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,
    )
예제 #21
0
def rate_request(payload: RateRequest,
                 settings: Settings) -> Serializable[Envelope]:
    packages = Packages(payload.parcels, PackagePresets, required=["weight"])
    service = Services(payload.services, Product).first
    options = Options(payload.options, Service)

    package_description = packages[0].parcel.description if len(
        packages) == 1 else None
    is_document = all([parcel.is_document for parcel in payload.parcels])
    shipper_phone = Phone(payload.shipper.phone_number,
                          payload.shipper.country_code or 'CA')
    recipient_phone = Phone(payload.recipient.phone_number,
                            payload.recipient.country_code)
    is_international = payload.shipper.country_code != payload.recipient.country_code
    option_ids = [(key, value) for key, value in options
                  if key in Service and key not in NON_OFFICIAL_SERVICES]

    # When no specific service is requested, set a default one.
    if service is None:
        show_alternate_services = options[
            'purolator_show_alternative_services'] is not False
        service = Product['purolator_express_international'
                          if is_international else 'purolator_express']
    else:
        show_alternate_services = options[
            'purolator_show_alternative_services'] is True

    request = create_envelope(
        header_content=RequestContext(
            Version="2.1",
            Language=settings.language,
            GroupID="",
            RequestReference=getattr(payload, 'id', ""),
            UserToken=settings.user_token,
        ),
        body_content=GetFullEstimateRequest(
            Shipment=Shipment(
                SenderInformation=SenderInformation(
                    Address=Address(
                        Name=payload.shipper.person_name or "",
                        Company=payload.shipper.company_name,
                        Department=None,
                        StreetNumber="",
                        StreetSuffix=None,
                        StreetName=SF.concat_str(payload.shipper.address_line1,
                                                 join=True),
                        StreetType=None,
                        StreetDirection=None,
                        Suite=None,
                        Floor=None,
                        StreetAddress2=SF.concat_str(
                            payload.shipper.address_line2, join=True),
                        StreetAddress3=None,
                        City=payload.shipper.city or "",
                        Province=payload.shipper.state_code or "",
                        Country=payload.shipper.country_code or "",
                        PostalCode=payload.shipper.postal_code or "",
                        PhoneNumber=PhoneNumber(
                            CountryCode=shipper_phone.country_code or "0",
                            AreaCode=shipper_phone.area_code or "0",
                            Phone=shipper_phone.phone or "0",
                            Extension=None,
                        ),
                        FaxNumber=None,
                    ),
                    TaxNumber=(payload.shipper.federal_tax_id
                               or payload.shipper.state_tax_id),
                ),
                ReceiverInformation=ReceiverInformation(
                    Address=Address(
                        Name=payload.recipient.person_name or "",
                        Company=payload.recipient.company_name,
                        Department=None,
                        StreetNumber="",
                        StreetSuffix=None,
                        StreetName=SF.concat_str(
                            payload.recipient.address_line1, join=True),
                        StreetType=None,
                        StreetDirection=None,
                        Suite=None,
                        Floor=None,
                        StreetAddress2=SF.concat_str(
                            payload.recipient.address_line2, join=True),
                        StreetAddress3=None,
                        City=payload.recipient.city or "",
                        Province=payload.recipient.state_code or "",
                        Country=payload.recipient.country_code or "",
                        PostalCode=payload.recipient.postal_code or "",
                        PhoneNumber=PhoneNumber(
                            CountryCode=recipient_phone.country_code or "0",
                            AreaCode=recipient_phone.area_code or "0",
                            Phone=recipient_phone.phone or "0",
                            Extension=None,
                        ),
                        FaxNumber=None,
                    ),
                    TaxNumber=(payload.recipient.federal_tax_id
                               or payload.recipient.state_tax_id),
                ),
                FromOnLabelIndicator=None,
                FromOnLabelInformation=None,
                ShipmentDate=options.shipment_date,
                PackageInformation=PackageInformation(
                    ServiceID=service.value,
                    Description=package_description,
                    TotalWeight=(TotalWeight(
                        Value=packages.weight.map(MeasurementOptions).LB,
                        WeightUnit=PurolatorWeightUnit.LB.value,
                    ) if packages.weight.value is not None else None),
                    TotalPieces=1,
                    PiecesInformation=ArrayOfPiece(Piece=[
                        Piece(
                            Weight=(PurolatorWeight(
                                Value=package.weight.map(MeasurementOptions).
                                value,
                                WeightUnit=PurolatorWeightUnit[
                                    package.weight_unit.value].value,
                            ) if package.weight.value else None),
                            Length=(PurolatorDimension(
                                Value=package.length.value,
                                DimensionUnit=PurolatorDimensionUnit[
                                    package.dimension_unit.value].value,
                            ) if package.length.value else None),
                            Width=(PurolatorDimension(
                                Value=package.width.value,
                                DimensionUnit=PurolatorDimensionUnit[
                                    package.dimension_unit.value].value,
                            ) if package.width.value else None),
                            Height=(PurolatorDimension(
                                Value=package.height.value,
                                DimensionUnit=PurolatorDimensionUnit[
                                    package.dimension_unit.value].value,
                            ) if package.height.value else None),
                            Options=ArrayOfOptionIDValuePair(
                                OptionIDValuePair=[
                                    OptionIDValuePair(ID=key, Value=value)
                                    for key, value in option_ids
                                ]) if any(option_ids) else None,
                        ) for package in packages
                    ]),
                    DangerousGoodsDeclarationDocumentIndicator=None,
                    OptionsInformation=None,
                ),
                InternationalInformation=(InternationalInformation(
                    DocumentsOnlyIndicator=is_document,
                    ContentDetails=None,
                    BuyerInformation=None,
                    PreferredCustomsBroker=None,
                    DutyInformation=DutyInformation(
                        BillDutiesToParty=DutyPaymentType.recipient.value,
                        BusinessRelationship=BusinessRelationship.NOT_RELATED.
                        value,
                        Currency=options.currency,
                    ),
                    ImportExportType=None,
                    CustomsInvoiceDocumentIndicator=None,
                ) if is_international else None),
                ReturnShipmentInformation=None,
                PaymentInformation=PaymentInformation(
                    PaymentType=PaymentType.SENDER.value,
                    RegisteredAccountNumber=settings.account_number,
                ),
                PickupInformation=PickupInformation(
                    PickupType=PickupType.DROP_OFF.value),
                NotificationInformation=None,
                TrackingReferenceInformation=(TrackingReferenceInformation(
                    Reference1=payload.reference) if payload.reference != ""
                                              else None),
                OtherInformation=None,
                ProactiveNotification=None,
            ),
            ShowAlternativeServicesIndicator=show_alternate_services,
        ),
    )
    return Serializable(request, standard_request_serializer)
예제 #22
0
def _schedule_pickup_request(payload: Union[PickupRequest,
                                            PickupUpdateRequest],
                             settings: Settings) -> Serializable[Envelope]:
    """
    Create a serializable typed Envelope containing a SchedulePickUpRequest

    Options:
        - LoadingDockAvailable
        - TrailerAccessible

    :param payload: PickupRequest
    :param settings: Settings
    :return: Serializable[PickupRequest]
    """
    packages = Packages(payload.parcels, PackagePresets, required=["weight"])
    phone = Phone(payload.address.phone_number, payload.address.country_code
                  or 'CA')
    request = create_envelope(
        header_content=RequestContext(
            Version="1.2",
            Language=settings.language,
            GroupID="",
            RequestReference="",
            UserToken=settings.user_token,
        ),
        body_content=SchedulePickUpRequest(
            BillingAccountNumber=settings.account_number,
            PartnerID=None,
            PickupInstruction=PickupInstruction(
                Date=payload.pickup_date,
                AnyTimeAfter="".join(payload.ready_time.split(":")),
                UntilTime="".join(payload.closing_time.split(":")),
                TotalWeight=Weight(Value=packages.weight.LB,
                                   WeightUnit=WeightUnit.LB.value),
                TotalPieces=len(packages) or 1,
                BoxesIndicator=None,
                PickUpLocation=payload.package_location,
                AdditionalInstructions=payload.instruction,
                SupplyRequestCodes=None,
                TrailerAccessible=payload.options.get("TrailerAccessible"),
                LoadingDockAvailable=payload.options.get(
                    "LoadingDockAvailable"),
                ShipmentOnSkids=None,
                NumberOfSkids=None,
            ),
            Address=Address(
                Name=payload.address.person_name or "",
                Company=payload.address.company_name,
                Department=None,
                StreetNumber="",
                StreetSuffix=None,
                StreetName=SF.concat_str(payload.address.address_line1,
                                         join=True),
                StreetType=None,
                StreetDirection=None,
                Suite=None,
                Floor=None,
                StreetAddress2=SF.concat_str(payload.address.address_line2,
                                             join=True),
                StreetAddress3=None,
                City=payload.address.city,
                Province=payload.address.state_code,
                Country=payload.address.country_code,
                PostalCode=payload.address.postal_code,
                PhoneNumber=PhoneNumber(
                    CountryCode=phone.country_code or "0",
                    AreaCode=phone.area_code or "0",
                    Phone=phone.phone or "0",
                    Extension=None,
                ),
                FaxNumber=None,
            ),
            ShipmentSummary=None,
            NotificationEmails=NotificationEmails(
                NotificationEmail=[payload.address.email]),
        ),
    )

    return Serializable(request,
                        partial(standard_request_serializer, version="v1"))
예제 #23
0
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)
예제 #24
0
def _shipment_request(payload: ShipmentRequest,
                      settings: Settings) -> Serializable[Envelope]:
    packages = Packages(payload.parcels, PackagePresets, required=["weight"])
    service = Product.map(payload.service).value_or_key
    options = Options(payload.options, Service)

    is_document = all([parcel.is_document for parcel in payload.parcels])
    package_description = packages[0].parcel.description if len(
        packages) == 1 else None
    is_international = (payload.shipper.country_code !=
                        payload.recipient.country_code)
    shipper_phone_number = Phone(payload.shipper.phone_number,
                                 payload.shipper.country_code)
    recipient_phone_number = Phone(payload.recipient.phone_number,
                                   payload.recipient.country_code)
    printing = PrintType.map(payload.label_type or "PDF").value
    option_ids = [(key, value) for key, value in options
                  if key in Service and key not in NON_OFFICIAL_SERVICES]

    request = create_envelope(
        header_content=RequestContext(
            Version="2.1",
            Language=settings.language,
            GroupID="",
            RequestReference=(getattr(payload, 'id', None) or ""),
            UserToken=settings.user_token,
        ),
        body_content=CreateShipmentRequest(
            Shipment=Shipment(
                SenderInformation=SenderInformation(
                    Address=Address(
                        Name=payload.shipper.person_name,
                        Company=payload.shipper.company_name,
                        Department=None,
                        StreetNumber="",
                        StreetSuffix=None,
                        StreetName=SF.concat_str(payload.shipper.address_line1,
                                                 join=True),
                        StreetType=None,
                        StreetDirection=None,
                        Suite=None,
                        Floor=None,
                        StreetAddress2=SF.concat_str(
                            payload.shipper.address_line2, join=True),
                        StreetAddress3=None,
                        City=payload.shipper.city or "",
                        Province=payload.shipper.state_code or "",
                        Country=payload.shipper.country_code or "",
                        PostalCode=payload.shipper.postal_code or "",
                        PhoneNumber=PhoneNumber(
                            CountryCode=shipper_phone_number.country_code
                            or "0",
                            AreaCode=shipper_phone_number.area_code or "0",
                            Phone=shipper_phone_number.phone or "0",
                            Extension=None,
                        ),
                        FaxNumber=None,
                    ),
                    TaxNumber=(payload.shipper.federal_tax_id
                               or payload.shipper.state_tax_id),
                ),
                ReceiverInformation=ReceiverInformation(
                    Address=Address(
                        Name=payload.recipient.person_name,
                        Company=payload.recipient.company_name,
                        Department=None,
                        StreetNumber="",
                        StreetSuffix=None,
                        StreetName=SF.concat_str(
                            payload.recipient.address_line1, join=True),
                        StreetType=None,
                        StreetDirection=None,
                        Suite=None,
                        Floor=None,
                        StreetAddress2=SF.concat_str(
                            payload.recipient.address_line2, join=True),
                        StreetAddress3=None,
                        City=payload.recipient.city or "",
                        Province=payload.recipient.state_code or "",
                        Country=payload.recipient.country_code or "",
                        PostalCode=payload.recipient.postal_code or "",
                        PhoneNumber=PhoneNumber(
                            CountryCode=recipient_phone_number.country_code
                            or "0",
                            AreaCode=recipient_phone_number.area_code or "0",
                            Phone=recipient_phone_number.phone or "0",
                            Extension=None,
                        ),
                        FaxNumber=None,
                    ),
                    TaxNumber=(payload.recipient.federal_tax_id
                               or payload.recipient.state_tax_id),
                ),
                FromOnLabelIndicator=None,
                FromOnLabelInformation=None,
                ShipmentDate=options.shipment_date,
                PackageInformation=PackageInformation(
                    ServiceID=service,
                    Description=package_description,
                    TotalWeight=(TotalWeight(
                        Value=packages.weight.map(MeasurementOptions).LB,
                        WeightUnit=PurolatorWeightUnit.LB.value,
                    ) if packages.weight.value else None),
                    TotalPieces=1,
                    PiecesInformation=ArrayOfPiece(Piece=[
                        Piece(
                            Weight=(PurolatorWeight(
                                Value=package.weight.map(MeasurementOptions).
                                value,
                                WeightUnit=PurolatorWeightUnit[
                                    package.weight_unit.value].value,
                            ) if package.weight.value else None),
                            Length=(PurolatorDimension(
                                Value=package.length.map(MeasurementOptions).
                                value,
                                DimensionUnit=PurolatorDimensionUnit[
                                    package.dimension_unit.value].value,
                            ) if package.length.value else None),
                            Width=(PurolatorDimension(
                                Value=package.width.map(MeasurementOptions).
                                value,
                                DimensionUnit=PurolatorDimensionUnit[
                                    package.dimension_unit.value].value,
                            ) if package.width.value else None),
                            Height=(PurolatorDimension(
                                Value=package.height.map(MeasurementOptions).
                                value,
                                DimensionUnit=PurolatorDimensionUnit[
                                    package.dimension_unit.value].value,
                            ) if package.height.value else None),
                            Options=None,
                        ) for package in packages
                    ]),
                    DangerousGoodsDeclarationDocumentIndicator=None,
                    OptionsInformation=(ArrayOfOptionIDValuePair(
                        OptionIDValuePair=[
                            OptionIDValuePair(ID=key, Value=value)
                            for key, value in option_ids
                        ]) if any(option_ids) else None),
                ),
                InternationalInformation=(InternationalInformation(
                    DocumentsOnlyIndicator=is_document,
                    ContentDetails=(ArrayOfContentDetail(ContentDetail=[
                        ContentDetail(
                            Description=c.description,
                            HarmonizedCode=None,
                            CountryOfManufacture=c.origin_country,
                            ProductCode=c.sku,
                            UnitValue=c.value_amount,
                            Quantity=c.quantity,
                            NAFTADocumentIndicator=None,
                            FDADocumentIndicator=None,
                            FCCDocumentIndicator=None,
                            SenderIsProducerIndicator=None,
                            TextileIndicator=None,
                            TextileManufacturer=None,
                        ) for c in payload.customs.commodities
                    ]) if not is_document else None),
                    BuyerInformation=None,
                    PreferredCustomsBroker=None,
                    DutyInformation=(DutyInformation(
                        BillDutiesToParty=DutyPaymentType[
                            payload.customs.duty.paid_by].value,
                        BusinessRelationship=BusinessRelationship.NOT_RELATED.
                        value,
                        Currency=payload.customs.duty.currency,
                    ) if payload.customs is not None else None),
                    ImportExportType=None,
                    CustomsInvoiceDocumentIndicator=None,
                ) if is_international else None),
                ReturnShipmentInformation=None,
                PaymentInformation=(PaymentInformation(
                    PaymentType=PaymentType[payload.payment.paid_by].value,
                    RegisteredAccountNumber=(payload.payment.account_number
                                             or settings.account_number),
                    BillingAccountNumber=(payload.payment.account_number
                                          or settings.account_number),
                    CreditCardInformation=None,
                ) if payload.payment is not None else None),
                PickupInformation=PickupInformation(
                    PickupType=PickupType.DROP_OFF.value),
                NotificationInformation=(
                    NotificationInformation(
                        ConfirmationEmailAddress=(options.email_notification_to
                                                  or payload.recipient.email))
                    if options.email_notification and any([
                        options.email_notification_to, payload.recipient.email
                    ]) else None),
                TrackingReferenceInformation=(TrackingReferenceInformation(
                    Reference1=payload.reference) if any(payload.reference
                                                         or "") else None),
                OtherInformation=None,
                ProactiveNotification=None,
            ),
            PrinterType=PrinterType(printing).value,
        ),
    )
    return Serializable(request, standard_request_serializer)
def 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)
예제 #26
0
def rate_request(payload: RateRequest,
                 settings: Settings) -> Serializable[FedexRateRequest]:
    packages = Packages(payload.parcels, PackagePresets, required=["weight"])
    service = Services(payload.services, ServiceType).first
    options = Options(payload.options)

    package_type = (PackagingType[packages[0].packaging_type
                                  or "your_packaging"].value
                    if len(packages) == 1 else None)
    request_types = ["LIST"
                     ] + ([] if "currency" not in options else ["PREFERRED"])

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

    request = create_envelope(
        header_content=settings.Security,
        body_content=PickupCreationRequest(
            Request=RequestType(),
            RatePickupIndicator="N",
            TaxInformationIndicator=None,
            UserLevelDiscountIndicator=None,
            Shipper=ShipperType(
                Account=AccountType(
                    AccountNumber=settings.account_number,
                    AccountCountryCode=payload.address.country_code or "",
                ),
                ChargeCard=None,
                TaxInformation=None,
            ),
            PickupDateInfo=PickupDateInfoType(
                CloseTime=DF.ftime(payload.closing_time, "%H:%M", "%H%M"),
                ReadyTime=DF.ftime(payload.ready_time, "%H:%M", "%H%M"),
                PickupDate=DF.date(payload.pickup_date).strftime("%Y%m%d"),
            ),
            PickupAddress=PickupAddressType(
                CompanyName=payload.address.company_name,
                ContactName=payload.address.person_name,
                AddressLine=SF.concat_str(
                    payload.address.address_line1, payload.address.address_line2
                ),
                Room=None,
                Floor=None,
                City=payload.address.city,
                StateProvince=payload.address.state_code,
                Urbanization=None,
                PostalCode=payload.address.postal_code,
                CountryCode=payload.address.country_code,
                ResidentialIndicator=("Y" if payload.address.residential else "N"),
                PickupPoint=payload.package_location,
                Phone=PhoneType(Number=payload.address.phone_number, Extension=None)
                if payload.address.phone_number is not None
                else None,
            ),
            AlternateAddressIndicator="Y",
            PickupPiece=None,
            TotalWeight=WeightType(
                Weight=packages.weight.LB, UnitOfMeasurement=WeightUnit.LB.value
            ),
            OverweightIndicator=("Y" if has_overweight else "N"),
            TrackingData=None,
            TrackingDataWithReferenceNumber=None,
            PaymentMethod="01",
            SpecialInstruction=payload.instruction,
            ReferenceNumber=None,
            FreightOptions=None,
            ServiceCategory=None,
            CashType=None,
            ShippingLabelsAvailable="Y",
        ),
    )

    return Serializable(
        request,
        default_request_serializer(
            "v11", 'xmlns:v11="http://www.ups.com/XMLSchema/XOLTWS/Pickup/v1.1"'
        ),
    )
예제 #28
0
def shipment_request(
    payload: ShipmentRequest, settings: Settings
) -> Serializable[Envelope]:
    packages = Packages(payload.parcels, PackagePresets)
    packages.validate(required=["weight"])
    options = Options(payload.options, ServiceOption)
    service = ServiceCode.map(payload.service).value_or_key
    ship_from = CompleteAddress.map(payload.shipper)
    ship_to = CompleteAddress.map(payload.shipper)

    payment_account_number = getattr(
        payload.payment, "account_number", settings.account_number
    )
    payment_address = getattr(payload.payment, "address", None)
    mps_packaging = PackagingType.your_packaging.value if len(packages) > 1 else None
    payer = dict(
        sender=payment_address or ship_from,
        recipient=payment_address or ship_to,
        third_party=payment_address,
    )[getattr(payload.payment, "paid_by", "sender")]
    label_format, label_height, label_width = LabelType[
        payload.label_type or "PDF_6x4"
    ].value

    request = create_envelope(
        header_content=settings.Security,
        body_content=FreightShipRequest(
            Request=RequestType(
                RequestOption=1,
                SubVersion=1607,
                TransactionReference=TransactionReferenceType(
                    CustomerContext=payload.reference,
                    TransactionIdentifier=getattr(payload, "id", None),
                ),
            ),
            Shipment=ShipmentType(
                ShipFrom=ShipFromType(
                    Name=ship_from.company_name,
                    Address=AddressType(
                        AddressLine=ship_from.address_line,
                        City=ship_from.city,
                        StateProvinceCode=ship_from.state_code,
                        Town=None,
                        PostalCode=ship_from.postal_code,
                        CountryCode=ship_from.country_code,
                        ResidentialAddressIndicator=(
                            "" if ship_from.residential else None
                        ),
                    ),
                    TariffPoint=None,
                    AttentionName=ship_from.person_name,
                    Phone=PhoneType(Number=ship_from.phone_number),
                    FaxNumber=None,
                    EMailAddress=ship_from.email,
                ),
                ShipTo=ShipToType(
                    Name=ship_to.company_name,
                    TaxIdentificationNumber=None,
                    Address=AddressType(
                        AddressLine=ship_to.address_line,
                        City=ship_to.city,
                        StateProvinceCode=ship_to.state_code,
                        Town=None,
                        PostalCode=ship_to.postal_code,
                        CountryCode=ship_to.country_code,
                        ResidentialAddressIndicator=(
                            "" if ship_to.residential else None
                        ),
                    ),
                    TariffPoint=None,
                    AttentionName=ship_to.person_name,
                    Phone=PhoneType(Number=ship_to.phone_number),
                    FaxNumber=None,
                    EMailAddress=ship_to.email,
                ),
                PaymentInformation=PaymentInformationType(
                    Payer=PayerType(
                        Name=payer.company_name,
                        Address=AddressType(
                            AddressLine=payer.address_line,
                            City=payer.city,
                            StateProvinceCode=payer.state_code,
                            Town=None,
                            CountryCode=payer.country_code,
                            PostalCode=payer.postal_code,
                            ResidentialAddressIndicator=(
                                "" if payer.residential else None
                            ),
                        ),
                        ShipperNumber=payment_account_number,
                        AttentionName=payer.person_name,
                        Phone=PhoneType(Number=payer.phone_number),
                        FaxNumber=None,
                        EMailAddress=payer.email,
                    ),
                    ShipmentBillingOption=ShipCodeDescriptionType(
                        Code=40, Description="Freight Collect"
                    ),
                ),
                ManufactureInformation=None,
                Service=(
                    ShipCodeDescriptionType(Code=service, Description=None)
                    if service is not None
                    else None
                ),
                HandlingUnitOne=None,
                HandlingUnitTwo=None,
                ExistingShipmentID=None,
                HandlingInstructions=None,
                DeliveryInstructions=None,
                PickupInstructions=None,
                SpecialInstructions=None,
                ShipmentTotalWeight=ShipmentTotalWeightType(
                    Value=packages.weight.value,
                    UnitOfMeasurement=UPSWeightUnit[packages.weight.unit].value,
                ),
                Commodity=[
                    CommodityType(
                        CommodityID=getattr(commodity, "id", None),
                        Description=commodity.parcel.description,
                        Weight=WeightType(
                            Value=commodity.weight.value,
                            UnitOfMeasurement=UnitOfMeasurementType(
                                Code=UPSWeightUnit[commodity.weight_unit.name].value,
                            ),
                        ),
                        AdjustedWeight=None,
                        Dimensions=(
                            DimensionsType(
                                UnitOfMeasurement=UnitOfMeasurementType(
                                    Code=commodity.dimension_unit.value,
                                    Description=None,
                                ),
                                Length=commodity.length.value,
                                Width=commodity.width.value,
                                Height=commodity.height.value,
                            )
                            if commodity.has_dimensions
                            else None
                        ),
                        NumberOfPieces=1,
                        PackagingType=ShipCodeDescriptionType(
                            Code=(
                                mps_packaging
                                or PackagingType[
                                    commodity.packaging_type or "your_packaging"
                                ].value
                            ),
                        ),
                        DangerousGoodsIndicator=(
                            "" if options.dangerous_good else None
                        ),
                        CommodityValue=None,
                        FreightClass=FreightClass.map(
                            options.freight_class or 50
                        ).value,
                        NMFCCommodity=None,
                        NMFCCommodityCode=None,
                    )
                    for commodity in packages
                ],
                Reference=(
                    [
                        ReferenceType(
                            Number=ReferenceNumberType(
                                Code="OTHER", Value=payload.reference
                            )
                        )
                    ]
                    if any(payload.reference or "")
                    else None
                ),
                ShipmentServiceOptions=(
                    ShipmentServiceOptionsType(
                        EMailInformation=(
                            [
                                EMailInformationType(
                                    EMailType=f"000{email_type}",
                                    EMail=options.email_notification_to
                                    or payload.recipient.email,
                                )
                                for email_type in [1, 2, 3, 4]
                            ]
                            if any(
                                [options.email_notification_to, payload.recipient.email]
                            )
                            else None
                        ),
                        COD=(
                            CODType(
                                CODValue=CODValueType(
                                    CurrencyCode=options.currency or "USD",
                                    MonetaryValue=options.cash_on_delivery,
                                ),
                                CODPaymentMethod=ShipCodeDescriptionType(Code="M"),
                                CODBillingOption=ShipCodeDescriptionType(Code="02"),
                                RemitTo=RemitToType(
                                    Name=payer.company_name,
                                    Address=FreightShipAddressType(
                                        AddressLine=payer.address_line,
                                        City=payer.city,
                                        StateProvinceCode=payer.state_code,
                                        Town=payer.city,
                                        PostalCode=payer.postal_code,
                                        CountryCode=payer.country_code,
                                        ResidentialAddressIndicator=(
                                            "" if payer.residential else None
                                        ),
                                    ),
                                    AttentionName=payer.person_name,
                                    Phone=(
                                        FreightShipPhoneType(Number=payer.phone_number)
                                        if payer.phone_number
                                        else None
                                    ),
                                    FaxNumber=None,
                                    EMailAddress=payer.email,
                                ),
                            )
                            if options.cash_on_delivery
                            else None
                        ),
                        DangerousGoods=(
                            DangerousGoodsType(
                                Name=(ship_from.company_name or ship_from.person_name),
                                Phone=(
                                    FreightShipPhoneType(Number=payer.phone_number)
                                    if payer.phone_number
                                    else None
                                ),
                            )
                            if options.dangerous_good
                            else None
                        ),
                        DeclaredValue=(
                            DeclaredValueType(
                                CurrencyCode=options.currency or "USD",
                                MonetaryValue=options.declared_value,
                            )
                            if options.declared_value
                            else None
                        ),
                    )
                    if any(
                        [
                            options.cash_on_delivery,
                            options.email_notification,
                            options.dangerous_good,
                            options.declared_value,
                        ]
                    )
                    else None
                ),
                PickupRequest=None,
                Documents=DocumentsType(
                    Image=ImageType(
                        Type=ShipCodeDescriptionType(Code="30"),
                        LabelsPerPage=1,
                        Format=ShipCodeDescriptionType(Code="01"),
                        PrintFormat=ShipCodeDescriptionType(
                            Code="02" if "ZPL" in label_format else "01"
                        ),
                        PrintSize=PrintSizeType(Length=label_height, Width=label_width),
                    )
                ),
                ITNNumber=None,
                TaxID=None,
                MovementReferenceNumber=None,
                EICNumberAndStatement=None,
                TimeInTransitIndicator=None,
                HandlingUnits=None,
                DensityEligibleIndicator=None,
            ),
        ),
    )

    return Serializable(request, _request_serializer)
예제 #29
0
def _process_shipment(payload: ShipmentRequest, settings: Settings) -> Job:
    packages = Packages(payload.parcels)
    options = Options(payload.options, Option)
    service_type = Service.map(payload.service).value_or_key

    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
            )
        )
    )

    data = Serializable(
        request, partial(
            settings.serialize,
            extra_namespace='xmlns:xsd1="http://dto.canshipws.canpar.com/xsd"',
            special_prefixes=dict(shipment_children='xsd1')
        )
    )
    return Job(id="process", data=data)
예제 #30
0
def rate_request(
        payload: RateRequest, settings: Settings
) -> Serializable[mailing_scenario]:
    """Create the appropriate Canada Post rate request depending on the destination

    :param settings: Purplship carrier connection settings
    :param payload: Purplship unified API rate request data
    :return: a domestic or international Canada post compatible request
    :raises: an OriginNotServicedError when origin country is not serviced by the carrier
    """
    if payload.shipper.country_code and payload.shipper.country_code != Country.CA.name:
        raise OriginNotServicedError(payload.shipper.country_code)

    package = Packages(payload.parcels, PackagePresets, required=["weight"]).single
    services = Services(payload.services, ServiceType)
    options = Options(payload.options, OptionCode)
    recipient_postal_code = (payload.recipient.postal_code or "").replace(" ", "").upper()
    shipper_postal_code = (payload.shipper.postal_code or "").replace(" ", "").upper()

    request = mailing_scenario(
        customer_number=settings.customer_number,
        contract_id=settings.contract_id,
        promo_code=None,
        quote_type=None,
        expected_mailing_date=options.shipment_date,
        options=(
            optionsType(
                option=[
                    optionType(
                        option_code=getattr(option, 'key', option),
                        option_amount=getattr(option, 'value', None)
                    )
                    for code, option in options if code in OptionCode
                ]
            )
            if any([c in OptionCode for c, _ in options]) else None
        ),
        parcel_characteristics=parcel_characteristicsType(
            weight=package.weight.map(MeasurementOptions).KG,
            dimensions=dimensionsType(
                length=package.length.map(MeasurementOptions).CM,
                width=package.width.map(MeasurementOptions).CM,
                height=package.height.map(MeasurementOptions).CM,
            ),
            unpackaged=None,
            mailing_tube=None,
            oversized=None,
        ),
        services=(
            servicesType(
                service_code=[svc.value for svc in services]
            )
            if any(services) else None
        ),
        origin_postal_code=shipper_postal_code,
        destination=destinationType(
            domestic=(
                domesticType(postal_code=recipient_postal_code)
                if (payload.recipient.country_code == Country.CA.name)
                else None
            ),
            united_states=(
                united_statesType(zip_code=recipient_postal_code)
                if (payload.recipient.country_code == Country.US.name)
                else None
            ),
            international=(
                internationalType(country_code=recipient_postal_code)
                if (
                        payload.recipient.country_code
                        not in [Country.US.name, Country.CA.name]
                )
                else None
            ),
        ),
    )

    return Serializable(request, _request_serializer)