diff --git a/modules/connectors/easyship/karrio/providers/easyship/pickup/create.py b/modules/connectors/easyship/karrio/providers/easyship/pickup/create.py index 83c30b11d4..d96c1ec721 100644 --- a/modules/connectors/easyship/karrio/providers/easyship/pickup/create.py +++ b/modules/connectors/easyship/karrio/providers/easyship/pickup/create.py @@ -15,7 +15,7 @@ def parse_pickup_response( _response: lib.Deserializable[dict], settings: provider_utils.Settings, -) -> typing.Tuple[typing.List[models.RateDetails], typing.List[models.Message]]: +) -> typing.Tuple[typing.List[models.PickupDetails], typing.List[models.Message]]: response = _response.deserialize() messages = error.parse_error_response(response, settings) diff --git a/modules/connectors/easyship/karrio/providers/easyship/pickup/update.py b/modules/connectors/easyship/karrio/providers/easyship/pickup/update.py index edd5c2053e..41c0d29afb 100644 --- a/modules/connectors/easyship/karrio/providers/easyship/pickup/update.py +++ b/modules/connectors/easyship/karrio/providers/easyship/pickup/update.py @@ -15,7 +15,7 @@ def parse_pickup_update_response( _response: lib.Deserializable[dict], settings: provider_utils.Settings, -) -> typing.Tuple[typing.List[models.RateDetails], typing.List[models.Message]]: +) -> typing.Tuple[typing.List[models.PickupDetails], typing.List[models.Message]]: response = _response.deserialize() messages = error.parse_error_response(response, settings) diff --git a/modules/connectors/fedex/generate b/modules/connectors/fedex/generate index b65affdacd..eda13f6894 100755 --- a/modules/connectors/fedex/generate +++ b/modules/connectors/fedex/generate @@ -23,3 +23,7 @@ quicktype --src="${SCHEMAS}/tracking_request.json" --out="${LIB_MODULES}/trackin quicktype --src="${SCHEMAS}/tracking_response.json" --out="${LIB_MODULES}/tracking_response.py" quicktype --src="${SCHEMAS}/tracking_document_request.json" --out="${LIB_MODULES}/tracking_document_request.py" quicktype --src="${SCHEMAS}/tracking_document_response.json" --out="${LIB_MODULES}/tracking_document_response.py" +quicktype --src="${SCHEMAS}/pickup_request.json" --out="${LIB_MODULES}/pickup_request.py" +quicktype --src="${SCHEMAS}/pickup_response.json" --out="${LIB_MODULES}/pickup_response.py" +quicktype --src="${SCHEMAS}/cancel_pickup_request.json" --out="${LIB_MODULES}/cancel_pickup_request.py" +quicktype --src="${SCHEMAS}/cancel_pickup_response.json" --out="${LIB_MODULES}/cancel_pickup_response.py" diff --git a/modules/connectors/fedex/karrio/mappers/fedex/mapper.py b/modules/connectors/fedex/karrio/mappers/fedex/mapper.py index 3b95c86f21..dd82381338 100644 --- a/modules/connectors/fedex/karrio/mappers/fedex/mapper.py +++ b/modules/connectors/fedex/karrio/mappers/fedex/mapper.py @@ -34,6 +34,19 @@ def create_document_upload_request( ) -> lib.Serializable: return provider.document_upload_request(payload, self.settings) + def create_pickup_request(self, payload: models.PickupRequest) -> lib.Serializable: + return provider.pickup_request(payload, self.settings) + + def create_pickup_update_request( + self, payload: models.PickupUpdateRequest + ) -> lib.Serializable: + return provider.pickup_update_request(payload, self.settings) + + def create_cancel_pickup_request( + self, payload: models.PickupCancelRequest + ) -> lib.Serializable: + return provider.pickup_cancel_request(payload, self.settings) + def parse_cancel_shipment_response( self, response: lib.Deserializable ) -> typing.Tuple[models.ConfirmationDetails, typing.List[models.Message]]: @@ -59,3 +72,18 @@ def parse_document_upload_response( response: lib.Deserializable, ) -> typing.Tuple[models.DocumentUploadDetails, typing.List[models.Message]]: return provider.parse_document_upload_response(response, self.settings) + + def parse_cancel_pickup_response( + self, response: lib.Deserializable + ) -> typing.Tuple[models.ConfirmationDetails, typing.List[models.Message]]: + return provider.parse_pickup_cancel_response(response, self.settings) + + def parse_pickup_response( + self, response: lib.Deserializable + ) -> typing.Tuple[models.PickupDetails, typing.List[models.Message]]: + return provider.parse_pickup_response(response, self.settings) + + def parse_pickup_update_response( + self, response: lib.Deserializable + ) -> typing.Tuple[models.PickupDetails, typing.List[models.Message]]: + return provider.parse_pickup_update_response(response, self.settings) diff --git a/modules/connectors/fedex/karrio/mappers/fedex/proxy.py b/modules/connectors/fedex/karrio/mappers/fedex/proxy.py index e86a5c28db..3176806f32 100644 --- a/modules/connectors/fedex/karrio/mappers/fedex/proxy.py +++ b/modules/connectors/fedex/karrio/mappers/fedex/proxy.py @@ -99,3 +99,46 @@ def upload_document(self, requests: lib.Serializable) -> lib.Deserializable: response, lambda __: [lib.to_dict(_) for _ in __], ) + + def schedule_pickup(self, request: lib.Serializable) -> lib.Deserializable[str]: + response = lib.request( + url=f"{self.settings.server_url}/pickup/v1/pickups", + data=lib.to_json(request.serialize()), + trace=self.trace_as("json"), + method="POST", + headers={ + "x-locale": "en_US", + "content-type": "application/json", + "authorization": f"Bearer {self.settings.access_token}", + }, + decoder=provider_utils.parse_response, + on_error=lambda b: provider_utils.parse_response(b.read()), + ) + + return lib.Deserializable(response, lib.to_dict, request.ctx) + + def modify_pickup(self, request: lib.Serializable) -> lib.Deserializable[str]: + response = self.cancel_pickup(lib.Serializable(request.ctx["cancel"])) + confirmation = response.deserialize().get("output") or {} + + if confirmation.get("pickupConfirmationCode") is not None: + return self.schedule_pickup(request) + + return response + + def cancel_pickup(self, request: lib.Serializable) -> lib.Deserializable[str]: + response = lib.request( + url=f"{self.settings.server_url}/pickup/v1/pickups/cancel", + data=lib.to_json(request.serialize()), + trace=self.trace_as("json"), + method="PUT", + headers={ + "x-locale": "en_US", + "content-type": "application/json", + "authorization": f"Bearer {self.settings.access_token}", + }, + decoder=provider_utils.parse_response, + on_error=lambda b: provider_utils.parse_response(b.read()), + ) + + return lib.Deserializable(response, lib.to_dict, request.ctx) diff --git a/modules/connectors/fedex/karrio/providers/fedex/__init__.py b/modules/connectors/fedex/karrio/providers/fedex/__init__.py index b683b388e3..3ae45cade4 100644 --- a/modules/connectors/fedex/karrio/providers/fedex/__init__.py +++ b/modules/connectors/fedex/karrio/providers/fedex/__init__.py @@ -14,3 +14,11 @@ parse_document_upload_response, document_upload_request, ) +from karrio.providers.fedex.pickup import ( + parse_pickup_cancel_response, + parse_pickup_update_response, + parse_pickup_response, + pickup_cancel_request, + pickup_update_request, + pickup_request, +) diff --git a/modules/connectors/fedex/karrio/providers/fedex/error.py b/modules/connectors/fedex/karrio/providers/fedex/error.py index 21dcab74c1..05bf8585ef 100644 --- a/modules/connectors/fedex/karrio/providers/fedex/error.py +++ b/modules/connectors/fedex/karrio/providers/fedex/error.py @@ -16,13 +16,17 @@ def parse_error_response( *(result["errors"] if "errors" in result else []), *( result["output"]["alerts"] - if "alerts" in result.get("output", {}) + if "output" in result + and not isinstance(result["output"], str) + and "alerts" in result.get("output", {}) and not isinstance(result["output"]["alerts"], str) else [] ), *( [{"message": result["output"]["message"]}] - if "message" in result.get("output", {}) + if "output" in result + and not isinstance(result["output"], str) + and "message" in result.get("output", {}) and isinstance(result["output"]["message"], str) and not result["output"]["alertType"] != "NOTE" else [] diff --git a/modules/connectors/fedex/karrio/providers/fedex/pickup/__init__.py b/modules/connectors/fedex/karrio/providers/fedex/pickup/__init__.py new file mode 100644 index 0000000000..56d35585bc --- /dev/null +++ b/modules/connectors/fedex/karrio/providers/fedex/pickup/__init__.py @@ -0,0 +1,9 @@ +from karrio.providers.fedex.pickup.create import parse_pickup_response, pickup_request +from karrio.providers.fedex.pickup.update import ( + parse_pickup_update_response, + pickup_update_request, +) +from karrio.providers.fedex.pickup.cancel import ( + parse_pickup_cancel_response, + pickup_cancel_request, +) diff --git a/modules/connectors/fedex/karrio/providers/fedex/pickup/cancel.py b/modules/connectors/fedex/karrio/providers/fedex/pickup/cancel.py new file mode 100644 index 0000000000..297c45593d --- /dev/null +++ b/modules/connectors/fedex/karrio/providers/fedex/pickup/cancel.py @@ -0,0 +1,79 @@ +import karrio.schemas.fedex.cancel_pickup_request as fedex +import karrio.schemas.fedex.cancel_pickup_response as pickup + +import typing +import karrio.lib as lib +import karrio.core.units as units +import karrio.core.models as models +import karrio.providers.fedex.error as error +import karrio.providers.fedex.utils as provider_utils +import karrio.providers.fedex.units as provider_units + + +def parse_pickup_cancel_response( + _response: lib.Deserializable[dict], + settings: provider_utils.Settings, +) -> typing.Tuple[models.ConfirmationDetails, typing.List[models.Message]]: + response = _response.deserialize() + messages = error.parse_error_response(response, settings) + success = any(lib.failsafe(lambda: response["output"]["pickupConfirmationCode"])) + + confirmation = lib.identity( + models.ConfirmationDetails( + carrier_id=settings.carrier_id, + carrier_name=settings.carrier_name, + operation="Cancel Pickup", + success=success, + ) + if success + else None + ) + + return confirmation, messages + + +def pickup_cancel_request( + payload: models.PickupCancelRequest, + settings: provider_utils.Settings, +) -> lib.Serializable: + address = lib.to_address(payload.address) + options = lib.units.Options( + payload.options, + option_type=lib.units.create_enum( + "PickupOptions", + # fmt: off + { + "fedex_carrier_code": lib.OptionEnum("carrierCode"), + "fedex_pickup_location": lib.OptionEnum("location"), + }, + # fmt: on + ), + ) + + # map data to convert karrio model to fedex specific type + request = fedex.CancelPickupRequestType( + associatedAccountNumber=fedex.AssociatedAccountNumberType( + value=settings.account_number, + ), + pickupConfirmationCode=payload.confirmation_number, + remarks=payload.reason, + carrierCode=options.fedex_carrier_code.state, + accountAddressOfRecord=lib.identity( + fedex.AccountAddressOfRecordType( + streetLines=address.address_lines, + urbanizationCode=None, + city=address.city, + stateOrProvinceCode=provider_utils.state_code(address), + postalCode=address.postal_code, + countryCode=address.country_code, + residential=address.residential, + addressClassification=None, + ) + if payload.address + else None + ), + scheduledDate=lib.fdate(payload.pickup_date, "%Y-%m-%d"), + location=options.fedex_pickup_location.state, + ) + + return lib.Serializable(request, lib.to_dict) diff --git a/modules/connectors/fedex/karrio/providers/fedex/pickup/create.py b/modules/connectors/fedex/karrio/providers/fedex/pickup/create.py new file mode 100644 index 0000000000..3330820e51 --- /dev/null +++ b/modules/connectors/fedex/karrio/providers/fedex/pickup/create.py @@ -0,0 +1,148 @@ +import karrio.schemas.fedex.pickup_request as fedex +import karrio.schemas.fedex.pickup_response as pickup + +import typing +import karrio.lib as lib +import karrio.core.units as units +import karrio.core.models as models +import karrio.providers.fedex.error as error +import karrio.providers.fedex.utils as provider_utils +import karrio.providers.fedex.units as provider_units + + +def parse_pickup_response( + _response: lib.Deserializable[dict], + settings: provider_utils.Settings, +) -> typing.Tuple[typing.List[models.PickupDetails], typing.List[models.Message]]: + response = _response.deserialize() + + messages = error.parse_error_response(response, settings) + pickup = lib.identity( + _extract_details(response, settings, _response.ctx) + if (response.get("output") or {}).get("pickupConfirmationCode") + else None + ) + + return pickup, messages + + +def _extract_details( + data: dict, + settings: provider_utils.Settings, + ctx: dict, +) -> models.PickupDetails: + details = lib.to_object(pickup.PickupResponseType, data) + + return models.PickupDetails( + carrier_id=settings.carrier_id, + carrier_name=settings.carrier_name, + confirmation_number=details.output.pickupConfirmationCode, + pickup_date=lib.fdate(ctx["pickup_date"]), + ) + + +def pickup_request( + payload: models.PickupRequest, + settings: provider_utils.Settings, +) -> lib.Serializable: + address = lib.to_address(payload.address) + packages = lib.to_packages(payload.parcels) + options = lib.units.Options( + payload.options, + option_type=lib.units.create_enum( + "PickupOptions", + # fmt: off + { + "fedex_carrier_code": lib.OptionEnum("carrierCode"), + "fedex_pickup_location": lib.OptionEnum("location"), + "fedex_user_message": lib.OptionEnum("userMessage"), + "fedex_early_pickup": lib.OptionEnum("earlyPickup"), + "fedex_building_part": lib.OptionEnum("buildingPart"), + "fedex_pickup_date_type": lib.OptionEnum("pickupDateType"), + "fedex_supplies_requested": lib.OptionEnum("suppliesRequested"), + "fedex_pickup_address_type": lib.OptionEnum("pickupAddressType"), + "fedex_building_part_description": lib.OptionEnum("buildingPartDescription"), + "fedex_associated_account_number_type": lib.OptionEnum("associatedAccountNumberType"), + }, + # fmt: on + ), + ) + + # map data to convert karrio model to fedex specific type + request = fedex.PickupRequestType( + associatedAccountNumber=fedex.AccountNumberType( + value=settings.account_number, + ), + originDetail=fedex.OriginDetailType( + pickupAddressType=options.fedex_pickup_address_type.state, + pickupLocation=fedex.PickupLocationType( + contact=fedex.ContactType( + companyName=address.company_name, + personName=address.person_name, + phoneNumber=address.phone_number, + phoneExtension=None, + ), + address=fedex.AccountAddressOfRecordType( + streetLines=address.address_lines, + city=address.city, + stateOrProvinceCode=address.state_code, + postalCode=address.postal_code, + countryCode=address.country_code, + residential=address.residential, + addressClassification=None, + urbanizationCode=None, + ), + accountNumber=fedex.AccountNumberType( + value=settings.account_number, + ), + deliveryInstructions=options.instructions.state, + ), + readyDateTimestamp=f"{payload.pickup_date}T{payload.closing_time}:00Z", + customerCloseTime=f"{payload.closing_time}:00", + pickupDateType=options.fedex_pickup_date_type.state, + packageLocation=payload.package_location, + buildingPart=options.fedex_building_part.state, + buildingPartDescription=options.fedex_building_part_description.state, + earlyPickup=options.fedex_early_pickup.state, + suppliesRequested=options.fedex_supplies_requested.state, + geographicalPostalCode=options.geographical_postal_code.state, + ), + associatedAccountNumberType=options.fedex_associated_account_number_type.state, + totalWeight=fedex.TotalWeightType( + units=packages.weight_unit, + value=packages.weight.value, + ), + packageCount=len(packages), + carrierCode=options.fedex_carrier_code.state or "FDXE", + accountAddressOfRecord=None, + remarks=None, + countryRelationships=None, + pickupType=None, + trackingNumber=None, + commodityDescription=lib.text(packages.description, max=100), + expressFreightDetail=None, + oversizePackageCount=None, + pickupNotificationDetail=lib.identity( + fedex.PickupNotificationDetailType( + emailDetails=[ + fedex.EmailDetailType( + address=address.email, + locale="en_US", + ) + ], + format="TEXT", + userMessage=options.fedex_user_message.state, + ) + if address.email + else None + ), + ) + + return lib.Serializable( + request, + lib.to_dict, + dict( + pickup_date=payload.pickup_date, + address=payload.address, + ), + ) diff --git a/modules/connectors/fedex/karrio/providers/fedex/pickup/update.py b/modules/connectors/fedex/karrio/providers/fedex/pickup/update.py new file mode 100644 index 0000000000..a12df10e80 --- /dev/null +++ b/modules/connectors/fedex/karrio/providers/fedex/pickup/update.py @@ -0,0 +1,162 @@ +import karrio.schemas.fedex.pickup_request as fedex +import karrio.schemas.fedex.pickup_response as pickup + +import typing +import karrio.lib as lib +import karrio.core.units as units +import karrio.core.models as models +import karrio.providers.fedex.error as error +import karrio.providers.fedex.utils as provider_utils +import karrio.providers.fedex.units as provider_units +import karrio.providers.fedex.pickup.cancel as cancel + + +def parse_pickup_update_response( + _response: lib.Deserializable[dict], + settings: provider_utils.Settings, +) -> typing.Tuple[typing.List[models.PickupDetails], typing.List[models.Message]]: + response = _response.deserialize() + + messages = error.parse_error_response(response, settings) + pickup = lib.identity( + _extract_details(response, settings, _response.ctx) + if (response.get("output") or {}).get("pickupConfirmationCode") + else None + ) + + return pickup, messages + + +def _extract_details( + data: dict, + settings: provider_utils.Settings, + ctx: dict, +) -> models.PickupDetails: + details = lib.to_object(pickup.PickupResponseType, data) + + return models.PickupDetails( + carrier_id=settings.carrier_id, + carrier_name=settings.carrier_name, + confirmation_number=details.output.pickupConfirmationCode, + pickup_date=lib.fdate(ctx["pickup_date"]), + ) + + +def pickup_update_request( + payload: models.PickupUpdateRequest, + settings: provider_utils.Settings, +) -> lib.Serializable: + address = lib.to_address(payload.address) + packages = lib.to_packages(payload.parcels) + options = lib.units.Options( + payload.options, + option_type=lib.units.create_enum( + "PickupOptions", + # fmt: off + { + "fedex_carrier_code": lib.OptionEnum("carrierCode"), + "fedex_pickup_location": lib.OptionEnum("location"), + "fedex_user_message": lib.OptionEnum("userMessage"), + "fedex_early_pickup": lib.OptionEnum("earlyPickup"), + "fedex_building_part": lib.OptionEnum("buildingPart"), + "fedex_pickup_date_type": lib.OptionEnum("pickupDateType"), + "fedex_supplies_requested": lib.OptionEnum("suppliesRequested"), + "fedex_pickup_address_type": lib.OptionEnum("pickupAddressType"), + "fedex_building_part_description": lib.OptionEnum("buildingPartDescription"), + "fedex_associated_account_number_type": lib.OptionEnum("associatedAccountNumberType"), + }, + # fmt: on + ), + ) + + # map data to convert karrio model to fedex specific type + request = fedex.PickupRequestType( + associatedAccountNumber=fedex.AccountNumberType( + value=settings.account_number, + ), + originDetail=fedex.OriginDetailType( + pickupAddressType=options.fedex_pickup_address_type.state, + pickupLocation=fedex.PickupLocationType( + contact=fedex.ContactType( + companyName=address.company_name, + personName=address.person_name, + phoneNumber=address.phone_number, + phoneExtension=None, + ), + address=fedex.AccountAddressOfRecordType( + streetLines=address.address_lines, + city=address.city, + stateOrProvinceCode=address.state_code, + postalCode=address.postal_code, + countryCode=address.country_code, + residential=address.residential, + addressClassification=None, + urbanizationCode=None, + ), + accountNumber=fedex.AccountNumberType( + value=settings.account_number, + ), + deliveryInstructions=options.instructions.state, + ), + readyDateTimestamp=f"{payload.pickup_date}T{payload.closing_time}:00Z", + customerCloseTime=f"{payload.closing_time}:00", + pickupDateType=options.fedex_pickup_date_type.state, + packageLocation=payload.package_location, + buildingPart=options.fedex_building_part.state, + buildingPartDescription=options.fedex_building_part_description.state, + earlyPickup=options.fedex_early_pickup.state, + suppliesRequested=options.fedex_supplies_requested.state, + geographicalPostalCode=options.geographical_postal_code.state, + ), + associatedAccountNumberType=options.fedex_associated_account_number_type.state, + totalWeight=fedex.TotalWeightType( + units=packages.weight_unit, + value=packages.weight.value, + ), + packageCount=len(packages), + carrierCode=options.fedex_carrier_code.state or "FDXE", + accountAddressOfRecord=None, + remarks=None, + countryRelationships=None, + pickupType=None, + trackingNumber=None, + commodityDescription=lib.text(packages.description, max=100), + expressFreightDetail=None, + oversizePackageCount=None, + pickupNotificationDetail=lib.identity( + fedex.PickupNotificationDetailType( + emailDetails=[ + fedex.EmailDetailType( + address=address.email, + locale="en_US", + ) + ], + format="TEXT", + userMessage=options.fedex_user_message.state, + ) + if address.email + else None + ), + ) + + return lib.Serializable( + request, + lib.to_dict, + dict( + confirmation_number=payload.confirmation_number, + pickup_date=payload.pickup_date, + address=payload.address, + cancel=cancel.pickup_cancel_request( + lib.to_object( + models.PickupCancelRequest, + dict( + confirmation_number=payload.confirmation_number, + pickup_date=payload.pickup_date, + address=payload.address, + reason="update", + ), + ), + settings, + ), + ), + ) diff --git a/modules/connectors/fedex/karrio/providers/fedex/shipment/create.py b/modules/connectors/fedex/karrio/providers/fedex/shipment/create.py index 1c0887df5b..4822df5863 100644 --- a/modules/connectors/fedex/karrio/providers/fedex/shipment/create.py +++ b/modules/connectors/fedex/karrio/providers/fedex/shipment/create.py @@ -17,7 +17,7 @@ def parse_shipment_response( response = _response.deserialize() messages = provider_error.parse_error_response(response, settings) - shipment = ( + shipment = lib.identity( _extract_details( response["output"]["transactionShipments"][0], settings, @@ -82,6 +82,9 @@ def _extract_details( carrier_tracking_link=settings.tracking_url.format(tracking_number), trackingIdType=shipment.pieceResponses[0].trackingIdType, serviceCategory=shipment.pieceResponses[0].serviceCategory, + fedex_carrier_code=lib.failsafe( + lambda: shipment.completedShipmentDetail.carrierCode + ), ), ) diff --git a/modules/connectors/fedex/karrio/schemas/fedex/cancel_pickup_request.py b/modules/connectors/fedex/karrio/schemas/fedex/cancel_pickup_request.py new file mode 100644 index 0000000000..181063dccd --- /dev/null +++ b/modules/connectors/fedex/karrio/schemas/fedex/cancel_pickup_request.py @@ -0,0 +1,31 @@ +from attr import s +from typing import List, Optional +from jstruct import JStruct + + +@s(auto_attribs=True) +class AccountAddressOfRecordType: + streetLines: List[str] = [] + urbanizationCode: Optional[str] = None + city: Optional[str] = None + stateOrProvinceCode: Optional[str] = None + postalCode: Optional[int] = None + countryCode: Optional[str] = None + residential: Optional[bool] = None + addressClassification: Optional[str] = None + + +@s(auto_attribs=True) +class AssociatedAccountNumberType: + value: Optional[str] = None + + +@s(auto_attribs=True) +class CancelPickupRequestType: + associatedAccountNumber: Optional[AssociatedAccountNumberType] = JStruct[AssociatedAccountNumberType] + pickupConfirmationCode: Optional[int] = None + remarks: Optional[str] = None + carrierCode: Optional[str] = None + accountAddressOfRecord: Optional[AccountAddressOfRecordType] = JStruct[AccountAddressOfRecordType] + scheduledDate: Optional[str] = None + location: Optional[str] = None diff --git a/modules/connectors/fedex/karrio/schemas/fedex/cancel_pickup_response.py b/modules/connectors/fedex/karrio/schemas/fedex/cancel_pickup_response.py new file mode 100644 index 0000000000..4f2125efdf --- /dev/null +++ b/modules/connectors/fedex/karrio/schemas/fedex/cancel_pickup_response.py @@ -0,0 +1,24 @@ +from attr import s +from typing import Optional, List +from jstruct import JList, JStruct + + +@s(auto_attribs=True) +class AlertType: + code: Optional[str] = None + alertType: Optional[str] = None + message: Optional[str] = None + + +@s(auto_attribs=True) +class OutputType: + pickupConfirmationCode: Optional[str] = None + cancelConfirmationMessage: Optional[str] = None + alerts: List[AlertType] = JList[AlertType] + + +@s(auto_attribs=True) +class CancelPickupResponseType: + transactionId: Optional[str] = None + customerTransactionId: Optional[str] = None + output: Optional[OutputType] = JStruct[OutputType] diff --git a/modules/connectors/fedex/karrio/schemas/fedex/pickup_request.py b/modules/connectors/fedex/karrio/schemas/fedex/pickup_request.py new file mode 100644 index 0000000000..237a115994 --- /dev/null +++ b/modules/connectors/fedex/karrio/schemas/fedex/pickup_request.py @@ -0,0 +1,106 @@ +from attr import s +from typing import List, Optional +from jstruct import JStruct, JList + + +@s(auto_attribs=True) +class AccountAddressOfRecordType: + streetLines: List[str] = [] + city: Optional[str] = None + stateOrProvinceCode: Optional[str] = None + postalCode: Optional[int] = None + countryCode: Optional[str] = None + residential: Optional[bool] = None + addressClassification: Optional[str] = None + urbanizationCode: Optional[str] = None + + +@s(auto_attribs=True) +class AccountNumberType: + value: Optional[str] = None + + +@s(auto_attribs=True) +class DimensionsType: + length: Optional[int] = None + width: Optional[int] = None + height: Optional[int] = None + units: Optional[str] = None + + +@s(auto_attribs=True) +class ExpressFreightDetailType: + truckType: Optional[str] = None + service: Optional[str] = None + trailerLength: Optional[str] = None + bookingNumber: Optional[str] = None + dimensions: Optional[DimensionsType] = JStruct[DimensionsType] + + +@s(auto_attribs=True) +class ContactType: + companyName: Optional[str] = None + personName: Optional[str] = None + phoneNumber: Optional[str] = None + phoneExtension: Optional[str] = None + + +@s(auto_attribs=True) +class PickupLocationType: + contact: Optional[ContactType] = JStruct[ContactType] + address: Optional[AccountAddressOfRecordType] = JStruct[AccountAddressOfRecordType] + accountNumber: Optional[AccountNumberType] = JStruct[AccountNumberType] + deliveryInstructions: Optional[str] = None + + +@s(auto_attribs=True) +class OriginDetailType: + pickupAddressType: Optional[str] = None + pickupLocation: Optional[PickupLocationType] = JStruct[PickupLocationType] + readyDateTimestamp: Optional[str] = None + customerCloseTime: Optional[str] = None + pickupDateType: Optional[str] = None + packageLocation: Optional[str] = None + buildingPart: Optional[str] = None + buildingPartDescription: Optional[int] = None + earlyPickup: Optional[bool] = None + suppliesRequested: Optional[str] = None + geographicalPostalCode: Optional[str] = None + + +@s(auto_attribs=True) +class EmailDetailType: + address: Optional[str] = None + locale: Optional[str] = None + + +@s(auto_attribs=True) +class PickupNotificationDetailType: + emailDetails: List[EmailDetailType] = JList[EmailDetailType] + format: Optional[str] = None + userMessage: Optional[str] = None + + +@s(auto_attribs=True) +class TotalWeightType: + units: Optional[str] = None + value: Optional[int] = None + + +@s(auto_attribs=True) +class PickupRequestType: + associatedAccountNumber: Optional[AccountNumberType] = JStruct[AccountNumberType] + originDetail: Optional[OriginDetailType] = JStruct[OriginDetailType] + associatedAccountNumberType: Optional[str] = None + totalWeight: Optional[TotalWeightType] = JStruct[TotalWeightType] + packageCount: Optional[int] = None + carrierCode: Optional[str] = None + accountAddressOfRecord: Optional[AccountAddressOfRecordType] = JStruct[AccountAddressOfRecordType] + remarks: Optional[str] = None + countryRelationships: Optional[str] = None + pickupType: Optional[str] = None + trackingNumber: Optional[str] = None + commodityDescription: Optional[str] = None + expressFreightDetail: Optional[ExpressFreightDetailType] = JStruct[ExpressFreightDetailType] + oversizePackageCount: Optional[int] = None + pickupNotificationDetail: Optional[PickupNotificationDetailType] = JStruct[PickupNotificationDetailType] diff --git a/modules/connectors/fedex/karrio/schemas/fedex/pickup_response.py b/modules/connectors/fedex/karrio/schemas/fedex/pickup_response.py new file mode 100644 index 0000000000..9ddb4c3feb --- /dev/null +++ b/modules/connectors/fedex/karrio/schemas/fedex/pickup_response.py @@ -0,0 +1,25 @@ +from attr import s +from typing import Optional, List +from jstruct import JList, JStruct + + +@s(auto_attribs=True) +class AlertType: + code: Optional[str] = None + alertType: Optional[str] = None + message: Optional[str] = None + + +@s(auto_attribs=True) +class OutputType: + pickupConfirmationCode: Optional[int] = None + message: Optional[str] = None + location: Optional[str] = None + alerts: List[AlertType] = JList[AlertType] + + +@s(auto_attribs=True) +class PickupResponseType: + transactionId: Optional[str] = None + customerTransactionId: Optional[str] = None + output: Optional[OutputType] = JStruct[OutputType] diff --git a/modules/connectors/fedex/schemas/cancel_pickup_request.json b/modules/connectors/fedex/schemas/cancel_pickup_request.json new file mode 100644 index 0000000000..d5890502b9 --- /dev/null +++ b/modules/connectors/fedex/schemas/cancel_pickup_request.json @@ -0,0 +1,20 @@ +{ + "associatedAccountNumber": { + "value": "Your account number" + }, + "pickupConfirmationCode": "7", + "remarks": "Please ring bell at loading dock.", + "carrierCode": "FDXE", + "accountAddressOfRecord": { + "streetLines": ["123 Ship Street"], + "urbanizationCode": "URB FAIR OAKS", + "city": "Memphis", + "stateOrProvinceCode": "ON", + "postalCode": "38017", + "countryCode": "US", + "residential": false, + "addressClassification": "MIXED" + }, + "scheduledDate": "2019-10-15", + "location": "LOSA" +} diff --git a/modules/connectors/fedex/schemas/cancel_pickup_response.json b/modules/connectors/fedex/schemas/cancel_pickup_response.json new file mode 100644 index 0000000000..e57af4d6d9 --- /dev/null +++ b/modules/connectors/fedex/schemas/cancel_pickup_response.json @@ -0,0 +1,15 @@ +{ + "transactionId": "624deea6-b709-470c-8c39-4b5511281492", + "customerTransactionId": "AnyCo_order123456789", + "output": { + "pickupConfirmationCode": "NQAA97", + "cancelConfirmationMessage": "Requested pickup has been cancelled Successfully.", + "alerts": [ + { + "code": "SHIP.RECIPIENT.POSTALCITY.MISMATCH", + "alertType": "NOTE", + "message": "Recipient Postal-City Mismatch." + } + ] + } +} diff --git a/modules/connectors/fedex/schemas/pickup_request.json b/modules/connectors/fedex/schemas/pickup_request.json new file mode 100644 index 0000000000..4f58f85bd6 --- /dev/null +++ b/modules/connectors/fedex/schemas/pickup_request.json @@ -0,0 +1,83 @@ +{ + "associatedAccountNumber": { + "value": "Your account number" + }, + "originDetail": { + "pickupAddressType": "ACCOUNT", + "pickupLocation": { + "contact": { + "companyName": "Fedex", + "personName": "John Taylor", + "phoneNumber": "7194446666", + "phoneExtension": "phone extension" + }, + "address": { + "streetLines": ["123 Ship Street", "Suite 302"], + "urbanizationCode": "URB FAIR OAKS", + "city": "Memphis", + "stateOrProvinceCode": "TN", + "postalCode": "38017", + "countryCode": "US", + "residential": false, + "addressClassification": "MIXED" + }, + "accountNumber": { + "value": "XXX289837" + }, + "deliveryInstructions": "deliveryInstructions" + }, + "readyDateTimestamp": "2020-04-02T11:00:00Z", + "customerCloseTime": "18:00:00", + "pickupDateType": "SAME_DAY", + "packageLocation": "FRONT", + "buildingPart": "APARTMENT", + "buildingPartDescription": "111", + "earlyPickup": false, + "suppliesRequested": "Supplies requested by customer", + "geographicalPostalCode": "geographicalPostalCode" + }, + "associatedAccountNumberType": "FEDEX_GROUND", + "totalWeight": { + "units": "KG", + "value": 20 + }, + "packageCount": 5, + "carrierCode": "FDXE", + "accountAddressOfRecord": { + "streetLines": ["123 Ship Street"], + "city": "Memphis", + "stateOrProvinceCode": "TN", + "postalCode": "38017", + "countryCode": "US", + "residential": false, + "addressClassification": "MIXED" + }, + "remarks": "Please ring bell at loading dock.", + "countryRelationships": "DOMESTIC", + "pickupType": "ON_CALL, PACKAGE_RETURN_PROGRAM, REGULAR_STOP.", + "trackingNumber": "795803657326", + "commodityDescription": "This field contains CommodityDescription", + "expressFreightDetail": { + "truckType": "DROP_TRAILER_AGREEMENT", + "service": "FEDEX_1_DAY_FREIGHT", + "trailerLength": "TRAILER_28_FT", + "bookingNumber": "1234AGTT", + "dimensions": { + "length": 20, + "width": 15, + "height": 12, + "units": "CM" + } + }, + "oversizePackageCount": 2, + "pickupNotificationDetail": { + "emailDetails": [ + { + "address": "sample@gmail.com", + "locale": "en_US" + } + ], + "format": "HTML", + "userMessage": "This is the user message" + } +} diff --git a/modules/connectors/fedex/schemas/pickup_response.json b/modules/connectors/fedex/schemas/pickup_response.json new file mode 100644 index 0000000000..88cd685ffd --- /dev/null +++ b/modules/connectors/fedex/schemas/pickup_response.json @@ -0,0 +1,16 @@ +{ + "transactionId": "624deea6-b709-470c-8c39-4b5511281492", + "customerTransactionId": "AnyCo_order123456789", + "output": { + "pickupConfirmationCode": "3001", + "message": "Courier on the way", + "location": "COSA", + "alerts": [ + { + "code": "SHIP.RECIPIENT.POSTALCITY.MISMATCH", + "alertType": "NOTE", + "message": "Recipient Postal-City Mismatch." + } + ] + } +} diff --git a/modules/connectors/fedex/tests/__init__.py b/modules/connectors/fedex/tests/__init__.py index 6844a939cd..5825924524 100644 --- a/modules/connectors/fedex/tests/__init__.py +++ b/modules/connectors/fedex/tests/__init__.py @@ -1,4 +1,4 @@ - from tests.fedex.test_rate import * from tests.fedex.test_tracking import * -from tests.fedex.test_shipment import * \ No newline at end of file +from tests.fedex.test_shipment import * +from tests.fedex.test_pickup import * diff --git a/modules/connectors/fedex/tests/fedex/test_pickup.py b/modules/connectors/fedex/tests/fedex/test_pickup.py new file mode 100644 index 0000000000..3d1a0423f7 --- /dev/null +++ b/modules/connectors/fedex/tests/fedex/test_pickup.py @@ -0,0 +1,306 @@ +import unittest +from unittest.mock import patch, ANY + +from karrio.schemas.dpdhl.business_interface import CancelPickupResponse +from .fixture import gateway +from tests import logger + +import karrio +import karrio.lib as lib +import karrio.core.models as models + + +class TestFedExPickup(unittest.TestCase): + def setUp(self): + self.maxDiff = None + self.PickupRequest = models.PickupRequest(**PickupPayload) + self.PickupUpdateRequest = models.PickupUpdateRequest(**PickupUpdatePayload) + self.PickupCancelRequest = models.PickupCancelRequest(**PickupCancelPayload) + + def test_create_pickup_request(self): + request = gateway.mapper.create_pickup_request(self.PickupRequest) + + self.assertEqual(request.serialize(), PickupRequest) + + def test_create_update_pickup_request(self): + request = gateway.mapper.create_pickup_update_request(self.PickupUpdateRequest) + + self.assertEqual(request.serialize(), PickupUpdateRequest) + + def test_create_cancel_pickup_request(self): + request = gateway.mapper.create_cancel_pickup_request(self.PickupCancelRequest) + + self.assertEqual(request.serialize(), PickupCancelRequest) + + def test_create_pickup(self): + with patch("karrio.mappers.fedex.proxy.lib.request") as mock: + mock.return_value = "{}" + karrio.Pickup.schedule(self.PickupRequest).from_(gateway) + + self.assertEqual( + mock.call_args[1]["url"], + f"{gateway.settings.server_url}/pickup/v1/pickups", + ) + + def test_update_pickup(self): + with patch("karrio.mappers.fedex.proxy.lib.request") as mock: + mock.side_effect = ["{}", "{}"] + karrio.Pickup.update(self.PickupUpdateRequest).from_(gateway) + + self.assertEqual( + mock.call_args[1]["url"], + f"{gateway.settings.server_url}/pickup/v1/pickups/cancel", + ) + + def test_cancel_pickup(self): + with patch("karrio.mappers.fedex.proxy.lib.request") as mock: + mock.return_value = "{}" + karrio.Pickup.cancel(self.PickupCancelRequest).from_(gateway) + + self.assertEqual( + mock.call_args[1]["url"], + f"{gateway.settings.server_url}/pickup/v1/pickups/cancel", + ) + + def test_parse_pickup_response(self): + with patch("karrio.mappers.fedex.proxy.lib.request") as mock: + mock.side_effect = [PickupCancelResponse, PickupResponse] + parsed_response = ( + karrio.Pickup.schedule(self.PickupRequest).from_(gateway).parse() + ) + + self.assertListEqual(lib.to_dict(parsed_response), ParsedPickupResponse) + + def test_parse_cancel_pickup_response(self): + with patch("karrio.mappers.fedex.proxy.lib.request") as mock: + mock.return_value = PickupCancelResponse + parsed_response = ( + karrio.Pickup.cancel(self.PickupCancelRequest).from_(gateway).parse() + ) + + self.assertListEqual( + lib.to_dict(parsed_response), ParsedCancelPickupResponse + ) + + +if __name__ == "__main__": + unittest.main() + + +PickupPayload = { + "pickup_date": "2013-10-19", + "ready_time": "11:00", + "closing_time": "09:20", + "package_location": "behind the front desk", + "address": { + "company_name": "XYZ Inc.", + "address_line1": "456 Oak Avenue", + "address_line2": "Suite 789", + "city": "Springfield", + "postal_code": "62701", + "country_code": "US", + "person_name": "Jane Smith", + "phone_number": "2175551234", + "state_code": "IL", + "email": "jane.smith@xyz.com", + "residential": False, + }, + "parcels": [{"weight": 20, "weight_unit": "LB"}], + "options": { + "fedex_carrier_code": "FDXE", + "fedex_pickup_address_type": "BUSINESS", + }, +} + +PickupUpdatePayload = { + "confirmation_number": "XXX561073", + "pickup_date": "2013-10-19", + "ready_time": "11:00", + "closing_time": "09:20", + "package_location": "behind the front desk", + "address": { + "company_name": "XYZ Inc.", + "address_line1": "456 Oak Avenue", + "address_line2": "Suite 789", + "city": "Springfield", + "postal_code": "62701", + "country_code": "US", + "person_name": "Jane Smith", + "phone_number": "2175551234", + "state_code": "IL", + "email": "jane.smith@xyz.com", + "residential": False, + }, + "parcels": [{"weight": 20, "weight_unit": "LB"}], + "options": { + "fedex_carrier_code": "FDXE", + "fedex_pickup_address_type": "BUSINESS", + }, +} + +PickupCancelPayload = { + "confirmation_number": "XXX561073", + "pickup_date": "2020-07-03", + "options": { + "fedex_carrier_code": "FDXE", + "fedex_pickup_location": "NQAA", + }, +} + +ParsedPickupResponse = [ + { + "carrier_id": "fedex", + "carrier_name": "fedex", + "confirmation_number": "NQAA97", + "pickup_date": "2013-10-19", + }, + [ + { + "carrier_id": "fedex", + "carrier_name": "fedex", + "code": "SHIP.RECIPIENT.POSTALCITY.MISMATCH", + "details": {}, + "message": "Recipient Postal-City Mismatch.", + } + ], +] + +ParsedCancelPickupResponse = [ + { + "carrier_id": "fedex", + "carrier_name": "fedex", + "operation": "Cancel Pickup", + "success": True, + }, + [ + { + "carrier_id": "fedex", + "carrier_name": "fedex", + "code": "SHIP.RECIPIENT.POSTALCITY.MISMATCH", + "details": {}, + "message": "Recipient Postal-City Mismatch.", + } + ], +] + + +PickupRequest = { + "associatedAccountNumber": {"value": "2349857"}, + "carrierCode": "FDXE", + "originDetail": { + "customerCloseTime": "09:20:00", + "packageLocation": "behind the front desk", + "pickupAddressType": "BUSINESS", + "pickupLocation": { + "accountNumber": {"value": "2349857"}, + "address": { + "city": "Springfield", + "countryCode": "US", + "postalCode": "62701", + "residential": False, + "stateOrProvinceCode": "IL", + "streetLines": ["456 Oak Avenue", "Suite 789"], + }, + "contact": { + "companyName": "XYZ Inc.", + "personName": "Jane Smith", + "phoneNumber": "2175551234", + }, + }, + "readyDateTimestamp": "2013-10-19T09:20:00Z", + }, + "packageCount": 1, + "pickupNotificationDetail": { + "emailDetails": [{"address": "jane.smith@xyz.com", "locale": "en_US"}], + "format": "TEXT", + }, + "totalWeight": {"units": "LB", "value": 20.0}, +} + +PickupUpdateRequest = { + "associatedAccountNumber": {"value": "2349857"}, + "carrierCode": "FDXE", + "originDetail": { + "customerCloseTime": "09:20:00", + "packageLocation": "behind the front desk", + "pickupAddressType": "BUSINESS", + "pickupLocation": { + "accountNumber": {"value": "2349857"}, + "address": { + "city": "Springfield", + "countryCode": "US", + "postalCode": "62701", + "residential": False, + "stateOrProvinceCode": "IL", + "streetLines": ["456 Oak Avenue", "Suite 789"], + }, + "contact": { + "companyName": "XYZ Inc.", + "personName": "Jane Smith", + "phoneNumber": "2175551234", + }, + }, + "readyDateTimestamp": "2013-10-19T09:20:00Z", + }, + "packageCount": 1, + "pickupNotificationDetail": { + "emailDetails": [{"address": "jane.smith@xyz.com", "locale": "en_US"}], + "format": "TEXT", + }, + "totalWeight": {"units": "LB", "value": 20.0}, +} + +PickupCancelRequest = { + "associatedAccountNumber": {"value": "2349857"}, + "pickupConfirmationCode": "XXX561073", + "carrierCode": "FDXE", + "scheduledDate": "2020-07-03", + "location": "NQAA", +} + +PickupResponse = """{ + "transactionId": "624deea6-b709-470c-8c39-4b5511281492", + "customerTransactionId": "AnyCo_order123456789", + "output": { + "pickupConfirmationCode": "3001", + "message": "Courier on the way", + "location": "COSA", + "alerts": [ + { + "code": "SHIP.RECIPIENT.POSTALCITY.MISMATCH", + "alertType": "NOTE", + "message": "Recipient Postal-City Mismatch." + } + ] + } +} +""" + +PickupUpdateResponse = """{ + "transactionId": "624deea6-b709-470c-8c39-4b5511281492", + "customerTransactionId": "AnyCo_order123456789", + "output": { + "pickupConfirmationCode": "3001", + "message": "Courier on the way", + "location": "COSA", + "alerts": [] + } +} +""" + +PickupCancelResponse = """{ + "transactionId": "624deea6-b709-470c-8c39-4b5511281492", + "customerTransactionId": "AnyCo_order123456789", + "output": { + "pickupConfirmationCode": "NQAA97", + "cancelConfirmationMessage": "Requested pickup has been cancelled Successfully.", + "alerts": [ + { + "code": "SHIP.RECIPIENT.POSTALCITY.MISMATCH", + "alertType": "NOTE", + "message": "Recipient Postal-City Mismatch." + } + ] + } +} +""" diff --git a/modules/connectors/fedex/tests/fedex/test_shipment.py b/modules/connectors/fedex/tests/fedex/test_shipment.py index aadc6da29a..20ef910d29 100644 --- a/modules/connectors/fedex/tests/fedex/test_shipment.py +++ b/modules/connectors/fedex/tests/fedex/test_shipment.py @@ -187,6 +187,7 @@ def test_parse_cancel_shipment_response(self): "serviceCategory": "EXPRESS", "service_name": "fedex_standard_overnight", "trackingIdType": "FEDEX", + "fedex_carrier_code": "FDXE", }, "shipment_identifier": "794953535000", "tracking_number": "794953535000", @@ -211,6 +212,7 @@ def test_parse_cancel_shipment_response(self): "meta": { "carrier_tracking_link": "https://www.fedex.com/fedextrack/?trknbr=794791341818", "service_name": "fedex_international_priority_express", + "fedex_carrier_code": "FDXE", }, "shipment_identifier": "794791341818", "tracking_number": "794791341818", diff --git a/modules/connectors/mydhl/karrio/providers/mydhl/pickup/create.py b/modules/connectors/mydhl/karrio/providers/mydhl/pickup/create.py index 62f06c5718..4a49128d5a 100644 --- a/modules/connectors/mydhl/karrio/providers/mydhl/pickup/create.py +++ b/modules/connectors/mydhl/karrio/providers/mydhl/pickup/create.py @@ -1,4 +1,3 @@ - import typing import karrio.lib as lib import karrio.core.units as units @@ -11,7 +10,7 @@ def parse_pickup_response( _response: lib.Deserializable[dict], settings: provider_utils.Settings, -) -> typing.Tuple[typing.List[models.RateDetails], typing.List[models.Message]]: +) -> typing.Tuple[typing.List[models.PickupDetails], typing.List[models.Message]]: response = _response.deserialize() messages = error.parse_error_response(response, settings) @@ -34,13 +33,12 @@ def _extract_details( carrier_id=settings.carrier_id, carrier_name=settings.carrier_name, confirmation_number="", # extract confirmation number from pickup - pickup_date=lib.fdate(""), # extract tracking event date + pickup_date=lib.fdate(""), # extract tracking event date ) def pickup_request( - payload: models.PickupRequest, - settings: provider_utils.Settings + payload: models.PickupRequest, settings: provider_utils.Settings ) -> lib.Serializable: # map data to convert karrio model to mydhl specific type diff --git a/modules/connectors/mydhl/karrio/providers/mydhl/pickup/update.py b/modules/connectors/mydhl/karrio/providers/mydhl/pickup/update.py index 0e7aadef01..a66a4fa8ac 100644 --- a/modules/connectors/mydhl/karrio/providers/mydhl/pickup/update.py +++ b/modules/connectors/mydhl/karrio/providers/mydhl/pickup/update.py @@ -1,4 +1,3 @@ - import typing import karrio.lib as lib import karrio.core.units as units @@ -11,7 +10,7 @@ def parse_pickup_update_response( _response: lib.Deserializable[dict], settings: provider_utils.Settings, -) -> typing.Tuple[typing.List[models.RateDetails], typing.List[models.Message]]: +) -> typing.Tuple[typing.List[models.PickupDetails], typing.List[models.Message]]: response = _response.deserialize() messages = error.parse_error_response(response, settings) @@ -34,7 +33,7 @@ def _extract_details( carrier_id=settings.carrier_id, carrier_name=settings.carrier_name, confirmation_number="", # extract confirmation number from pickup - pickup_date=lib.fdate(""), # extract tracking event date + pickup_date=lib.fdate(""), # extract tracking event date ) diff --git a/modules/connectors/sapient/karrio/providers/sapient/pickup/create.py b/modules/connectors/sapient/karrio/providers/sapient/pickup/create.py index 6248d8ba9a..e35e61cdee 100644 --- a/modules/connectors/sapient/karrio/providers/sapient/pickup/create.py +++ b/modules/connectors/sapient/karrio/providers/sapient/pickup/create.py @@ -13,7 +13,7 @@ def parse_pickup_response( _response: lib.Deserializable[dict], settings: provider_utils.Settings, -) -> typing.Tuple[typing.List[models.RateDetails], typing.List[models.Message]]: +) -> typing.Tuple[typing.List[models.PickupDetails], typing.List[models.Message]]: response = _response.deserialize() messages = error.parse_error_response(response, settings) diff --git a/modules/connectors/sapient/karrio/providers/sapient/pickup/update.py b/modules/connectors/sapient/karrio/providers/sapient/pickup/update.py index bf9f93416b..2acae33b06 100644 --- a/modules/connectors/sapient/karrio/providers/sapient/pickup/update.py +++ b/modules/connectors/sapient/karrio/providers/sapient/pickup/update.py @@ -13,7 +13,7 @@ def parse_pickup_update_response( _response: lib.Deserializable[dict], settings: provider_utils.Settings, -) -> typing.Tuple[typing.List[models.RateDetails], typing.List[models.Message]]: +) -> typing.Tuple[typing.List[models.PickupDetails], typing.List[models.Message]]: response = _response.deserialize() messages = error.parse_error_response(response, settings, _response.ctx) diff --git a/modules/connectors/usps/karrio/providers/usps/pickup/create.py b/modules/connectors/usps/karrio/providers/usps/pickup/create.py index 2f87b81d7e..3291cc63df 100644 --- a/modules/connectors/usps/karrio/providers/usps/pickup/create.py +++ b/modules/connectors/usps/karrio/providers/usps/pickup/create.py @@ -15,7 +15,7 @@ def parse_pickup_response( _response: lib.Deserializable[dict], settings: provider_utils.Settings, -) -> typing.Tuple[typing.List[models.RateDetails], typing.List[models.Message]]: +) -> typing.Tuple[typing.List[models.PickupDetails], typing.List[models.Message]]: response = _response.deserialize() messages = error.parse_error_response(response, settings) diff --git a/modules/connectors/usps/karrio/providers/usps/pickup/update.py b/modules/connectors/usps/karrio/providers/usps/pickup/update.py index 5925a0a41c..cbb6df6b59 100644 --- a/modules/connectors/usps/karrio/providers/usps/pickup/update.py +++ b/modules/connectors/usps/karrio/providers/usps/pickup/update.py @@ -15,7 +15,7 @@ def parse_pickup_update_response( _response: lib.Deserializable[dict], settings: provider_utils.Settings, -) -> typing.Tuple[typing.List[models.RateDetails], typing.List[models.Message]]: +) -> typing.Tuple[typing.List[models.PickupDetails], typing.List[models.Message]]: response = _response.deserialize() messages = error.parse_error_response(response, settings) diff --git a/modules/connectors/usps_international/karrio/providers/usps_international/pickup/create.py b/modules/connectors/usps_international/karrio/providers/usps_international/pickup/create.py index 508fc58708..4d83e0d3d9 100644 --- a/modules/connectors/usps_international/karrio/providers/usps_international/pickup/create.py +++ b/modules/connectors/usps_international/karrio/providers/usps_international/pickup/create.py @@ -15,7 +15,7 @@ def parse_pickup_response( _response: lib.Deserializable[dict], settings: provider_utils.Settings, -) -> typing.Tuple[typing.List[models.RateDetails], typing.List[models.Message]]: +) -> typing.Tuple[typing.List[models.PickupDetails], typing.List[models.Message]]: response = _response.deserialize() messages = error.parse_error_response(response, settings) diff --git a/modules/connectors/usps_international/karrio/providers/usps_international/pickup/update.py b/modules/connectors/usps_international/karrio/providers/usps_international/pickup/update.py index bf14d0e0d7..ca24ec0e47 100644 --- a/modules/connectors/usps_international/karrio/providers/usps_international/pickup/update.py +++ b/modules/connectors/usps_international/karrio/providers/usps_international/pickup/update.py @@ -15,7 +15,7 @@ def parse_pickup_update_response( _response: lib.Deserializable[dict], settings: provider_utils.Settings, -) -> typing.Tuple[typing.List[models.RateDetails], typing.List[models.Message]]: +) -> typing.Tuple[typing.List[models.PickupDetails], typing.List[models.Message]]: response = _response.deserialize() messages = error.parse_error_response(response, settings)