def get_rates(self, request: Serializable) -> Deserializable[str]: response = http( url=self.settings.server_url, data=bytearray(request.serialize(), "utf-8"), headers={"Content-Type": "application/xml"}, method="POST", ) return Deserializable(response, XP.to_xml)
def track_package_by_pin_request(payload: TrackingRequest, settings: Settings) -> Serializable[Envelope]: request = create_envelope( header_content=RequestContext( Version="1.2", Language=settings.language, GroupID="", RequestReference="", UserToken=settings.user_token, ), body_content=TrackPackagesByPinRequest(PINs=ArrayOfPIN( PIN=[PIN(Value=pin) for pin in payload.tracking_numbers])), ) return Serializable(request, _request_serializer)
def cancel_pickup_request(payload: PickupCancellationRequest, settings: Settings) -> Serializable[CancelPURequest]: request = CancelPURequest( Request=settings.Request( MetaData=MetaData(SoftwareName="XMLPI", SoftwareVersion=1.0)), schemaVersion=3.0, RegionCode=CountryRegion[payload.country_code].value if payload.country_code else "AM", ConfirmationNumber=payload.confirmation_number, RequestorName=payload.person_name, CountryCode=payload.country_code, Reason="006", PickupDate=payload.pickup_date, CancelTime=time.strftime("%H:%M:%S"), ) return Serializable(request, _request_serializer)
def cancel_shipment(self, request: Serializable) -> Deserializable: def _request(method: str, shipment_id: str, path: str = '', **kwargs): return http( url= f"{self.settings.server_url}/rs/{self.settings.customer_number}/{self.settings.customer_number}/shipment/{shipment_id}{path}", headers={ "Content-Type": "application/vnd.cpc.shipment-v8+xml", "Accept": "application/vnd.cpc.shipment-v8+xml", "Authorization": f"Basic {self.settings.authorization}", "Accept-language": f"{self.settings.language}-CA", }, method=method, **kwargs) def process(job: Job): if job.data is None: return job.fallback subprocess = { "info": lambda _: _request('GET', job.data.serialize()), "refund": lambda _: _request( 'POST', job.data['id'], '/refund', data=bytearray(job.data['payload'].serialize(), "utf-8")), "cancel": lambda _: _request('DELETE', job.data.serialize()), } if job.id not in subprocess: raise PurplShipError( f"Unknown shipment cancel request job id: {job.id}") return subprocess[job.id](job) pipeline: Pipeline = request.serialize() response = pipeline.apply(process) return Deserializable(XP.bundle_xml(response), XP.to_xml)
def create_shipping_request(payload: ShipmentRequest, settings: Settings, validate: bool = None) -> Serializable[Envelope]: RequestType: ShipmentRequestType = ValidateShipmentRequest if validate else CreateShipmentRequest packages = Packages(payload.parcels, PackagePresets, required=["weight"]) is_document = all([parcel.is_document for parcel in payload.parcels]) package_description = (packages[0].parcel.description if len(packages) == 1 else None) service = Product[payload.service].value is_international = payload.shipper.country_code != payload.recipient.country_code options = Options(payload.options) shipper_phone_number = Phone(payload.shipper.phone_number) recipient_phone_number = Phone(payload.recipient.phone_number) printing = PrinterType[options.printing or "regular"].value special_services = { Service[name].value: value for name, value in payload.options.items() if name in Service.__members__ } request = create_envelope( header_content=RequestContext( Version="2.1", Language=settings.language, GroupID="", RequestReference="", UserToken=settings.user_token, ), body_content=RequestType( Shipment=Shipment( SenderInformation=SenderInformation( Address=Address( Name=payload.shipper.person_name, Company=payload.shipper.company_name, Department=None, StreetNumber="", StreetSuffix=None, StreetName=concat_str(payload.shipper.address_line1, join=True), StreetType=None, StreetDirection=None, Suite=None, Floor=None, StreetAddress2=concat_str( payload.shipper.address_line2, join=True), StreetAddress3=None, City=payload.shipper.city, Province=payload.shipper.state_code, Country=payload.shipper.country_code, PostalCode=payload.shipper.postal_code, PhoneNumber=PhoneNumber( CountryCode=shipper_phone_number.country_code, AreaCode=shipper_phone_number.area_code, Phone=shipper_phone_number.phone, 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=concat_str(payload.recipient.address_line1, join=True), StreetType=None, StreetDirection=None, Suite=None, Floor=None, StreetAddress2=concat_str( payload.recipient.address_line2, join=True), StreetAddress3=None, City=payload.recipient.city, Province=payload.recipient.state_code, Country=payload.recipient.country_code, PostalCode=payload.recipient.postal_code, PhoneNumber=PhoneNumber( CountryCode=recipient_phone_number.country_code, AreaCode=recipient_phone_number.area_code, Phone=recipient_phone_number.phone, Extension=None), FaxNumber=None, ), TaxNumber=payload.recipient.federal_tax_id or payload.recipient.state_tax_id, ), FromOnLabelIndicator=None, FromOnLabelInformation=None, ShipmentDate=datetime.today().strftime("%Y-%m-%d"), PackageInformation=PackageInformation( ServiceID=service, Description=package_description, TotalWeight=TotalWeight( Value=packages.weight.value, WeightUnit=PurolatorWeightUnit.LB.value, ) if packages.weight.value else None, TotalPieces=1, PiecesInformation=ArrayOfPiece(Piece=[ Piece( Weight=PurolatorWeight( Value=package.weight.value, WeightUnit=PurolatorWeightUnit[ package.weight_unit.value].value, ) if package.weight.value else None, Length=PurolatorDimension( Value=package.length.value, DimensionUnit=PurolatorDimensionUnit[ package.dimension_unit.value].value, ) if package.length.value else None, Width=PurolatorDimension( Value=package.width.value, DimensionUnit=PurolatorDimensionUnit[ package.dimension_unit.value].value, ) if package.width.value else None, Height=PurolatorDimension( Value=package.height.value, DimensionUnit=PurolatorDimensionUnit[ package.dimension_unit.value].value, ) if package.height.value else None, Options=None, ) for package in packages ]), DangerousGoodsDeclarationDocumentIndicator=None, OptionsInformation=ArrayOfOptionIDValuePair( OptionIDValuePair=[ OptionIDValuePair(ID=key, Value=value) for key, value in special_services.items() ]) if len(special_services) > 0 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=CreditCardInformation( Type=payload.payment.credit_card.type, Number=payload.payment.credit_card.number, Name=payload.payment.credit_card.name, ExpiryMonth=payload.payment.credit_card.expiry_month, ExpiryYear=payload.payment.credit_card.expiry_year, CVV=payload.payment.credit_card.security_code, BillingPostalCode=payload.payment.credit_card. postal_code, ) if payload.payment.credit_card is not None else None, ) if payload.payment is not None else None, PickupInformation=PickupInformation( PickupType=PickupType.DROP_OFF.value), NotificationInformation=NotificationInformation( ConfirmationEmailAddress=options.notification.email or payload.shipper.email, AdvancedShippingNotificationMessage=None, ) if options.notification else None, TrackingReferenceInformation=TrackingReferenceInformation( Reference1=payload.reference), OtherInformation=None, ProactiveNotification=None, ), PrinterType=PurolatorPrinterType(printing).value, ), ) return Serializable(request, standard_request_serializer)
def process_shipment_request( payload: ShipmentRequest, settings: Settings) -> Serializable[ProcessShipmentRequest]: 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] package_type = (PackagingType[master_package.packaging_type or "your_packaging"].value if len(packages) == 1 else PackagingType.your_packaging.value) service = ServiceType[payload.service].value options = Options(payload.options) special_services = [ SpecialServiceType[name].value for name, value in payload.options.items() if name in SpecialServiceType.__members__ ] payment_type = PaymentType[payload.payment.paid_by or "sender"].value request = ProcessShipmentRequest( WebAuthenticationDetail=settings.webAuthenticationDetail, ClientDetail=settings.clientDetail, TransactionDetail=TransactionDetail( CustomerTransactionId="IE_v25_Ship"), Version=VersionId(ServiceId="ship", Major=25, Intermediate=0, Minor=0), RequestedShipment=RequestedShipment( ShipTimestamp=datetime.now(), DropoffType="REGULAR_PICKUP", ServiceType=service, PackagingType=package_type, ManifestDetail=None, TotalWeight=FedexWeight(Units=WeightUnits.LB.value, Value=packages.weight.LB), TotalInsuredValue=options.insurance.amount if options.insurance else None, PreferredCurrency=options.currency, ShipmentAuthorizationDetail=None, Shipper=Party( AccountNumber=settings.account_number, Tins=[ TaxpayerIdentification(TinType=None, Number=tax) for tax in [ payload.shipper.federal_tax_id, payload.shipper.state_tax_id, ] ] if any([ payload.shipper.federal_tax_id, payload.shipper.state_tax_id ]) else None, Contact=Contact( ContactId=None, PersonName=payload.shipper.person_name, Title=None, CompanyName=payload.shipper.company_name, PhoneNumber=payload.shipper.phone_number, PhoneExtension=None, TollFreePhoneNumber=None, PagerNumber=None, FaxNumber=None, EMailAddress=payload.shipper.email, ) if any(( payload.shipper.company_name, payload.shipper.phone_number, payload.shipper.person_name, payload.shipper.email, )) else None, Address=Address( StreetLines=concat_str(payload.shipper.address_line1, payload.shipper.address_line2), City=payload.shipper.city, StateOrProvinceCode=payload.shipper.state_code, PostalCode=payload.shipper.postal_code, UrbanizationCode=None, CountryCode=payload.shipper.country_code, CountryName=None, Residential=None, GeographicCoordinates=None, ), ), Recipient=Party( AccountNumber=None, Tins=[ TaxpayerIdentification(TinType=None, Number=tax) for tax in [ payload.recipient.federal_tax_id, payload.recipient.state_tax_id, ] ] if any([ payload.recipient.federal_tax_id, payload.recipient.state_tax_id ]) else None, Contact=Contact( ContactId=None, PersonName=payload.recipient.person_name, Title=None, CompanyName=payload.recipient.company_name, PhoneNumber=payload.recipient.phone_number, PhoneExtension=None, TollFreePhoneNumber=None, PagerNumber=None, FaxNumber=None, EMailAddress=payload.recipient.email, ) if any(( payload.recipient.company_name, payload.recipient.phone_number, payload.recipient.person_name, payload.recipient.email, )) else None, Address=Address( StreetLines=concat_str( payload.recipient.address_line1, payload.recipient.address_line2, ), City=payload.recipient.city, StateOrProvinceCode=payload.recipient.state_code, PostalCode=payload.recipient.postal_code, UrbanizationCode=None, CountryCode=payload.recipient.country_code, CountryName=None, Residential=None, GeographicCoordinates=None, ), ), RecipientLocationNumber=None, Origin=None, SoldTo=None, ShippingChargesPayment=Payment( PaymentType=payment_type, Payor=Payor(ResponsibleParty=Party( AccountNumber=payload.payment.account_number or settings.account_number, Tins=None, Contact=None, Address=None, )), ), SpecialServicesRequested=ShipmentSpecialServicesRequested( SpecialServiceTypes=special_services, CodDetail=CodDetail( CodCollectionAmount=Money( Currency=options.currency or "USD", Amount=options.cash_on_delivery.amount, ), AddTransportationChargesDetail=None, CollectionType=CodCollectionType.CASH, CodRecipient=None, FinancialInstitutionContactAndAddress=None, RemitToName=None, ReferenceIndicator=None, ReturnTrackingId=None, ) if options.cash_on_delivery else None, DeliveryOnInvoiceAcceptanceDetail=None, HoldAtLocationDetail=None, EventNotificationDetail=ShipmentEventNotificationDetail( AggregationType=None, PersonalMessage=None, EventNotifications=[ ShipmentEventNotificationSpecification( Role=None, Events=NOTIFICATION_EVENTS, NotificationDetail=NotificationDetail( NotificationType="EMAIL", EmailDetail=EMailDetail( EmailAddress=options.notification.email or payload.shipper.email, Name=payload.shipper.person_name, ), Localization=Localization(LanguageCode="EN", LocaleCode=None), ), FormatSpecification="TEXT", ) ], ) if options.notification else None, ReturnShipmentDetail=None, PendingShipmentDetail=None, InternationalControlledExportDetail=None, InternationalTrafficInArmsRegulationsDetail=None, ShipmentDryIceDetail=None, HomeDeliveryPremiumDetail=None, EtdDetail=None, CustomDeliveryWindowDetail=None, ) if options.has_content else None, ExpressFreightDetail=None, FreightShipmentDetail=None, DeliveryInstructions=None, VariableHandlingChargeDetail=None, CustomsClearanceDetail=None, PickupDetail=None, SmartPostDetail=None, BlockInsightVisibility=None, LabelSpecification=LabelSpecification( Dispositions=None, LabelFormatType=LabelFormatType.COMMON_2_D.value, ImageType=ShippingDocumentImageType.PDF.value, LabelStockType=LabelStockType.PAPER__7_X_4_75.value, LabelPrintingOrientation=LabelPrintingOrientationType. TOP_EDGE_OF_TEXT_FIRST.value, LabelOrder=None, 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, Value=master_package.weight.value, ) if master_package.weight.value else None, Dimensions=FedexDimensions( Length=master_package.length.value, Width=master_package.width.value, Height=master_package.height.value, Units=master_package.dimension_unit.value, ) if any([ master_package.length, master_package.width, master_package.height ]) else None, PhysicalPackaging=None, ItemDescription=master_package.parcel.description, ItemDescriptionForClearance=None, CustomerReferences=None, SpecialServicesRequested=None, ContentRecords=None, ) ]), ) return Serializable(request, _request_serializer)
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)
def freight_ship_request( payload: ShipmentRequest, settings: Settings ) -> Serializable[FreightShipRequest]: dimension_unit = DimensionUnit[payload.parcel.dimension_unit or "IN"] weight_unit = WeightUnit[payload.parcel.weight_unit or "LB"] options = Options(payload.options) service = ShippingServiceCode[payload.service].value freight_class = FreightClass[ payload.options.get("ups_freight_class", "ups_freight_class_50") ].value request = FreightShipRequest( Request=common.RequestType( RequestOption="1", SubVersion=None, TransactionReference=common.TransactionReferenceType( CustomerContext=payload.reference, TransactionIdentifier=None ), ), Shipment=ShipmentType( ShipFrom=ShipFromType( Name=payload.shipper.company_name, TaxIdentificationNumber=payload.shipper.federal_tax_id, TaxIDType=None, TariffPoint=None, Address=FreightShipAddressType( AddressLine=concat_str( payload.shipper.address_line1, payload.shipper.address_line2 ), City=payload.shipper.city, StateProvinceCode=payload.shipper.state_code, Town=None, PostalCode=payload.shipper.postal_code, CountryCode=payload.shipper.country_code, ), AttentionName=payload.shipper.person_name, Phone=FreightShipPhoneType( Number=payload.shipper.phone_number, Extension=None ) if payload.shipper.phone_number is not None else None, FaxNumber=None, EMailAddress=payload.shipper.email, ), ShipperNumber=settings.account_number, ShipTo=ShipToType( Name=payload.recipient.company_name, TaxIdentificationNumber=payload.recipient.federal_tax_id, Address=FreightShipAddressType( AddressLine=concat_str( payload.recipient.address_line1, payload.recipient.address_line2, ), City=payload.recipient.city, StateProvinceCode=payload.recipient.state_code, Town=None, PostalCode=payload.recipient.postal_code, CountryCode=payload.recipient.country_code, ), TariffPoint=None, AttentionName=payload.recipient.person_name, Phone=PhoneType(Number=payload.recipient.phone_number, Extension=None) if payload.recipient.phone_number is not None else None, FaxNumber=None, EMailAddress=payload.recipient.email, ), PaymentInformation=None, ManufactureInformation=None, Service=ShipCodeDescriptionType(Code=service) if service is not None else None, HandlingUnitOne=None, HandlingUnitTwo=None, ExistingShipmentID=None, HandlingInstructions=None, DeliveryInstructions=None, PickupInstructions=None, SpecialInstructions=None, ShipmentTotalWeight=None, Commodity=[ CommodityType( CommodityID=payload.parcel.id, Description=payload.parcel.description, Weight=WeightType( UnitOfMeasurement=FreightShipUnitOfMeasurementType( Code=UPSWeightUnit[weight_unit.name].value ), Value=Weight(payload.parcel.weight, weight_unit).value, ), Dimensions=DimensionsType( UnitOfMeasurement=FreightShipUnitOfMeasurementType( Code=dimension_unit.value ), Width=Dimension(payload.parcel.width, dimension_unit).value, Height=Dimension(payload.parcel.height, dimension_unit).value, Length=Dimension(payload.parcel.length, dimension_unit).value, ) if any( [ payload.parcel.width, payload.parcel.height, payload.parcel.length, ] ) else None, NumberOfPieces=None, PackagingType=None, DangerousGoodsIndicator=None, CommodityValue=None, FreightClass=freight_class, NMFCCommodityCode=None, NMFCCommodity=None, ) ], Reference=None, ShipmentServiceOptions=ShipmentServiceOptionsType( EMailInformation=[ EMailNotificationType( EMailAddress=options.notification.email or payload.shipper.email, EventType=NOTIFICATION_EVENT_TYPES, ) ] if options.notification else None, PickupOptions=None, DeliveryOptions=None, OverSeasLeg=None, COD=CODType( CODValue=CODValueType( CurrencyCode=options.currency or "USD", MonetaryValue=options.cash_on_delivery.amount, ), CODPaymentMethod=None, CODBillingOption=None, RemitTo=None, ) if options.cash_on_delivery else None, DangerousGoods=None, SortingAndSegregating=None, DeclaredValue=None, ExcessDeclaredValue=None, CustomsValue=None, DeliveryDutiesPaidIndicator=None, DeliveryDutiesUnpaidIndicator=None, HandlingCharge=None, CustomsClearanceIndicator=None, FreezableProtectionIndicator=None, ExtremeLengthIndicator=None, LinearFeet=None, ) if options.has_content else None, PickupRequest=None, Documents=None, ITNNumber=None, TaxID=None, MovementReferenceNumber=None, EICNumberAndStatement=None, TimeInTransitIndicator=None, HandlingUnits=None, DensityEligibleIndicator=None, ), ) return Serializable( create_envelope(header_content=settings.Security, body_content=request), _request_serializer, )
def 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 (("freight" in service) or ("ground" in service)) and ( packages.weight.value is None ): raise FieldError({"parcel.weight": FieldErrorCode.required}) 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 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=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=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=CreditCardType( Type=payment.credit_card.type, Number=payment.credit_card.number, ExpirationDate=( f"{payment.credit_card.expiry_year}{payment.credit_card.expiry_month}" ), SecurityCode=payment.credit_card.security_code, Address=CreditCardAddressType( AddressLine=concat_str( payload.shipper.address_line1, payload.shipper.address_line2, ), City=payload.shipper.city, StateProvinceCode=payload.shipper.state_code, PostalCode=payload.payment.credit_card.postal_code or payload.shipper.postal_code, CountryCode=payload.shipper.country_code, ), ) if payment.credit_card is not None else 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.amount, ), ) if options.cash_on_delivery else None, Notification=[ NotificationType( NotificationCode=event, EMail=EmailDetailsType( EMailAddress=[ options.notification.email or payload.shipper.email ], ), VoiceMessage=None, TextMessage=None, Locale=None, ) for event in [8] ] if options.notification else None, ) if any([options.cash_on_delivery, options.notification]) 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='GIF', Description=None ), HTTPUserAgent=None, LabelStockSize=None, Instruction=None, CharacterSet=None ), ReceiptSpecification=None, ) return Serializable( create_envelope(header_content=settings.Security, body_content=request), _request_serializer, )
def process_shipment_request( payload: ShipmentRequest, settings: Settings ) -> Serializable[ProcessShipmentRequest]: parcel_preset = ( PackagePresets[payload.parcel.package_preset].value if payload.parcel.package_preset else None ) package = Package(payload.parcel, parcel_preset) if package.weight.value is None: raise RequiredFieldError("parcel.weight") service = ServiceType[payload.service].value options = Options(payload.options) special_services = [ SpecialServiceType[name].value for name, value in payload.options.items() if name in SpecialServiceType.__members__ ] request = ProcessShipmentRequest( WebAuthenticationDetail=settings.webAuthenticationDetail, ClientDetail=settings.clientDetail, TransactionDetail=TransactionDetail(CustomerTransactionId="IE_v18_Ship"), Version=VersionId(ServiceId="ship", Major=25, Intermediate=0, Minor=0), RequestedShipment=RequestedShipment( ShipTimestamp=datetime.now(), DropoffType="REGULAR_PICKUP", ServiceType=service, PackagingType=PackagingType[ payload.parcel.packaging_type or "small_box" ].value, ManifestDetail=None, TotalWeight=FedexWeight( Units=package.weight_unit.value, Value=package.weight.value, ), TotalInsuredValue=options.insurance.amount if options.insurance else None, PreferredCurrency=options.currency, ShipmentAuthorizationDetail=None, Shipper=Party( AccountNumber=settings.account_number, Tins=[ TaxpayerIdentification(TinType=None, Number=tax) for tax in [ payload.shipper.federal_tax_id, payload.shipper.state_tax_id, ] ] if any([payload.shipper.federal_tax_id, payload.shipper.state_tax_id]) else None, Contact=Contact( ContactId=None, PersonName=payload.shipper.person_name, Title=None, CompanyName=payload.shipper.company_name, PhoneNumber=payload.shipper.phone_number, PhoneExtension=None, TollFreePhoneNumber=None, PagerNumber=None, FaxNumber=None, EMailAddress=payload.shipper.email, ) if any( ( payload.shipper.company_name, payload.shipper.phone_number, payload.shipper.person_name, payload.shipper.email, ) ) else None, Address=Address( StreetLines=concat_str( payload.shipper.address_line1, payload.shipper.address_line2 ), City=payload.shipper.city, StateOrProvinceCode=payload.shipper.state_code, PostalCode=payload.shipper.postal_code, UrbanizationCode=None, CountryCode=payload.shipper.country_code, CountryName=None, Residential=None, GeographicCoordinates=None, ), ), Recipient=Party( AccountNumber=None, Tins=[ TaxpayerIdentification(TinType=None, Number=tax) for tax in [ payload.recipient.federal_tax_id, payload.recipient.state_tax_id, ] ] if any( [payload.recipient.federal_tax_id, payload.recipient.state_tax_id] ) else None, Contact=Contact( ContactId=None, PersonName=payload.recipient.person_name, Title=None, CompanyName=payload.recipient.company_name, PhoneNumber=payload.recipient.phone_number, PhoneExtension=None, TollFreePhoneNumber=None, PagerNumber=None, FaxNumber=None, EMailAddress=payload.recipient.email, ) if any( ( payload.recipient.company_name, payload.recipient.phone_number, payload.recipient.person_name, payload.recipient.email, ) ) else None, Address=Address( StreetLines=concat_str( payload.recipient.address_line1, payload.recipient.address_line2, ), City=payload.recipient.city, StateOrProvinceCode=payload.recipient.state_code, PostalCode=payload.recipient.postal_code, UrbanizationCode=None, CountryCode=payload.recipient.country_code, CountryName=None, Residential=None, GeographicCoordinates=None, ), ), RecipientLocationNumber=None, Origin=None, SoldTo=None, ShippingChargesPayment=Payment( PaymentType=None, Payor=Payor( ResponsibleParty=Party( AccountNumber=payload.payment.account_number, Tins=None, Contact=None, Address=None, ) ), ), SpecialServicesRequested=ShipmentSpecialServicesRequested( SpecialServiceTypes=special_services, CodDetail=CodDetail( CodCollectionAmount=Money( Currency=options.currency or "USD", Amount=options.cash_on_delivery.amount, ), AddTransportationChargesDetail=None, CollectionType=CodCollectionType.CASH, CodRecipient=None, FinancialInstitutionContactAndAddress=None, RemitToName=None, ReferenceIndicator=None, ReturnTrackingId=None, ) if options.cash_on_delivery else None, DeliveryOnInvoiceAcceptanceDetail=None, HoldAtLocationDetail=None, EventNotificationDetail=ShipmentEventNotificationDetail( AggregationType=None, PersonalMessage=None, EventNotifications=[ ShipmentEventNotificationSpecification( Role=None, Events=NOTIFICATION_EVENTS, NotificationDetail=NotificationDetail( NotificationType="EMAIL", EmailDetail=EMailDetail( EmailAddress=options.notification.email or payload.shipper.email, Name=payload.shipper.person_name, ), Localization=Localization( LanguageCode="EN", LocaleCode=None ), ), FormatSpecification="TEXT", ) ], ) if options.notification else None, ReturnShipmentDetail=None, PendingShipmentDetail=None, InternationalControlledExportDetail=None, InternationalTrafficInArmsRegulationsDetail=None, ShipmentDryIceDetail=None, HomeDeliveryPremiumDetail=None, EtdDetail=None, CustomDeliveryWindowDetail=None, ) if options.has_content else None, ExpressFreightDetail=None, FreightShipmentDetail=None, DeliveryInstructions=None, VariableHandlingChargeDetail=None, CustomsClearanceDetail=None, PickupDetail=None, SmartPostDetail=None, BlockInsightVisibility=None, LabelSpecification=None, ShippingDocumentSpecification=None, RateRequestTypes=( ["LIST"] + ([] if options.currency is None else ["PREFERRED"]) ), EdtRequestType=None, MasterTrackingId=None, PackageCount=None, ConfigurationData=None, RequestedPackageLineItems=[ RequestedPackageLineItem( SequenceNumber=index, GroupNumber=None, GroupPackageCount=index, VariableHandlingChargeDetail=None, InsuredValue=None, Weight=FedexWeight( Units=package.weight_unit.value, Value=Weight(pkg.weight, package.weight_unit).value, ) if pkg.weight else None, Dimensions=FedexDimensions( Length=Dimension(pkg.length, package.dimension_unit).value, Width=Dimension(pkg.width, package.dimension_unit).value, Height=Dimension(pkg.height, package.dimension_unit).value, Units=package.dimension_unit.value, ) if any([pkg.length, pkg.width, pkg.height]) else None, PhysicalPackaging=None, ItemDescription=pkg.description, ItemDescriptionForClearance=None, CustomerReferences=None, SpecialServicesRequested=None, ContentRecords=None, ) for index, pkg in enumerate(payload.customs.commodities, 1) ] if payload.customs is not None else None, ), ) return Serializable(request, _request_serializer)