karrio-fedex 2025.5rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- karrio/mappers/fedex/__init__.py +3 -0
- karrio/mappers/fedex/mapper.py +89 -0
- karrio/mappers/fedex/proxy.py +144 -0
- karrio/mappers/fedex/settings.py +24 -0
- karrio/plugins/fedex/__init__.py +23 -0
- karrio/providers/fedex/__init__.py +24 -0
- karrio/providers/fedex/document.py +88 -0
- karrio/providers/fedex/error.py +66 -0
- karrio/providers/fedex/pickup/__init__.py +9 -0
- karrio/providers/fedex/pickup/cancel.py +79 -0
- karrio/providers/fedex/pickup/create.py +148 -0
- karrio/providers/fedex/pickup/update.py +162 -0
- karrio/providers/fedex/rate.py +357 -0
- karrio/providers/fedex/shipment/__init__.py +9 -0
- karrio/providers/fedex/shipment/cancel.py +46 -0
- karrio/providers/fedex/shipment/create.py +748 -0
- karrio/providers/fedex/tracking.py +154 -0
- karrio/providers/fedex/units.py +501 -0
- karrio/providers/fedex/utils.py +199 -0
- karrio/schemas/fedex/__init__.py +0 -0
- karrio/schemas/fedex/cancel_pickup_request.py +31 -0
- karrio/schemas/fedex/cancel_pickup_response.py +24 -0
- karrio/schemas/fedex/cancel_request.py +17 -0
- karrio/schemas/fedex/cancel_response.py +25 -0
- karrio/schemas/fedex/error_response.py +16 -0
- karrio/schemas/fedex/paperless_request.py +30 -0
- karrio/schemas/fedex/paperless_response.py +21 -0
- karrio/schemas/fedex/pickup_request.py +106 -0
- karrio/schemas/fedex/pickup_response.py +25 -0
- karrio/schemas/fedex/rating_request.py +478 -0
- karrio/schemas/fedex/rating_responses.py +208 -0
- karrio/schemas/fedex/shipping_request.py +731 -0
- karrio/schemas/fedex/shipping_responses.py +584 -0
- karrio/schemas/fedex/tracking_document_request.py +30 -0
- karrio/schemas/fedex/tracking_document_response.py +30 -0
- karrio/schemas/fedex/tracking_request.py +23 -0
- karrio/schemas/fedex/tracking_response.py +350 -0
- karrio_fedex-2025.5rc1.dist-info/METADATA +45 -0
- karrio_fedex-2025.5rc1.dist-info/RECORD +42 -0
- karrio_fedex-2025.5rc1.dist-info/WHEEL +5 -0
- karrio_fedex-2025.5rc1.dist-info/entry_points.txt +2 -0
- karrio_fedex-2025.5rc1.dist-info/top_level.txt +3 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
"""Karrio FedEx client mapper."""
|
2
|
+
|
3
|
+
import typing
|
4
|
+
import karrio.lib as lib
|
5
|
+
import karrio.api.mapper as mapper
|
6
|
+
import karrio.core.models as models
|
7
|
+
import karrio.providers.fedex as provider
|
8
|
+
import karrio.mappers.fedex.settings as provider_settings
|
9
|
+
|
10
|
+
|
11
|
+
class Mapper(mapper.Mapper):
|
12
|
+
settings: provider_settings.Settings
|
13
|
+
|
14
|
+
def create_rate_request(self, payload: models.RateRequest) -> lib.Serializable:
|
15
|
+
return provider.rate_request(payload, self.settings)
|
16
|
+
|
17
|
+
def create_tracking_request(
|
18
|
+
self, payload: models.TrackingRequest
|
19
|
+
) -> lib.Serializable:
|
20
|
+
return provider.tracking_request(payload, self.settings)
|
21
|
+
|
22
|
+
def create_shipment_request(
|
23
|
+
self, payload: models.ShipmentRequest
|
24
|
+
) -> lib.Serializable:
|
25
|
+
return provider.shipment_request(payload, self.settings)
|
26
|
+
|
27
|
+
def create_cancel_shipment_request(
|
28
|
+
self, payload: models.ShipmentCancelRequest
|
29
|
+
) -> lib.Serializable:
|
30
|
+
return provider.shipment_cancel_request(payload, self.settings)
|
31
|
+
|
32
|
+
def create_document_upload_request(
|
33
|
+
self, payload: models.DocumentUploadRequest
|
34
|
+
) -> lib.Serializable:
|
35
|
+
return provider.document_upload_request(payload, self.settings)
|
36
|
+
|
37
|
+
def create_pickup_request(self, payload: models.PickupRequest) -> lib.Serializable:
|
38
|
+
return provider.pickup_request(payload, self.settings)
|
39
|
+
|
40
|
+
def create_pickup_update_request(
|
41
|
+
self, payload: models.PickupUpdateRequest
|
42
|
+
) -> lib.Serializable:
|
43
|
+
return provider.pickup_update_request(payload, self.settings)
|
44
|
+
|
45
|
+
def create_cancel_pickup_request(
|
46
|
+
self, payload: models.PickupCancelRequest
|
47
|
+
) -> lib.Serializable:
|
48
|
+
return provider.pickup_cancel_request(payload, self.settings)
|
49
|
+
|
50
|
+
def parse_cancel_shipment_response(
|
51
|
+
self, response: lib.Deserializable
|
52
|
+
) -> typing.Tuple[models.ConfirmationDetails, typing.List[models.Message]]:
|
53
|
+
return provider.parse_shipment_cancel_response(response, self.settings)
|
54
|
+
|
55
|
+
def parse_rate_response(
|
56
|
+
self, response: lib.Deserializable
|
57
|
+
) -> typing.Tuple[typing.List[models.RateDetails], typing.List[models.Message]]:
|
58
|
+
return provider.parse_rate_response(response, self.settings)
|
59
|
+
|
60
|
+
def parse_shipment_response(
|
61
|
+
self, response: lib.Deserializable
|
62
|
+
) -> typing.Tuple[models.ShipmentDetails, typing.List[models.Message]]:
|
63
|
+
return provider.parse_shipment_response(response, self.settings)
|
64
|
+
|
65
|
+
def parse_tracking_response(
|
66
|
+
self, response: lib.Deserializable
|
67
|
+
) -> typing.Tuple[typing.List[models.TrackingDetails], typing.List[models.Message]]:
|
68
|
+
return provider.parse_tracking_response(response, self.settings)
|
69
|
+
|
70
|
+
def parse_document_upload_response(
|
71
|
+
self,
|
72
|
+
response: lib.Deserializable,
|
73
|
+
) -> typing.Tuple[models.DocumentUploadDetails, typing.List[models.Message]]:
|
74
|
+
return provider.parse_document_upload_response(response, self.settings)
|
75
|
+
|
76
|
+
def parse_cancel_pickup_response(
|
77
|
+
self, response: lib.Deserializable
|
78
|
+
) -> typing.Tuple[models.ConfirmationDetails, typing.List[models.Message]]:
|
79
|
+
return provider.parse_pickup_cancel_response(response, self.settings)
|
80
|
+
|
81
|
+
def parse_pickup_response(
|
82
|
+
self, response: lib.Deserializable
|
83
|
+
) -> typing.Tuple[models.PickupDetails, typing.List[models.Message]]:
|
84
|
+
return provider.parse_pickup_response(response, self.settings)
|
85
|
+
|
86
|
+
def parse_pickup_update_response(
|
87
|
+
self, response: lib.Deserializable
|
88
|
+
) -> typing.Tuple[models.PickupDetails, typing.List[models.Message]]:
|
89
|
+
return provider.parse_pickup_update_response(response, self.settings)
|
@@ -0,0 +1,144 @@
|
|
1
|
+
import urllib.parse
|
2
|
+
import karrio.lib as lib
|
3
|
+
import karrio.api.proxy as proxy
|
4
|
+
import karrio.providers.fedex.utils as provider_utils
|
5
|
+
import karrio.mappers.fedex.settings as provider_settings
|
6
|
+
|
7
|
+
|
8
|
+
class Proxy(proxy.Proxy):
|
9
|
+
settings: provider_settings.Settings
|
10
|
+
|
11
|
+
def get_rates(self, request: lib.Serializable) -> lib.Deserializable:
|
12
|
+
response = lib.request(
|
13
|
+
url=f"{self.settings.server_url}/rate/v1/rates/quotes",
|
14
|
+
data=lib.to_json(request.serialize()),
|
15
|
+
trace=self.trace_as("json"),
|
16
|
+
method="POST",
|
17
|
+
headers={
|
18
|
+
"x-locale": "en_US",
|
19
|
+
"content-type": "application/json",
|
20
|
+
"authorization": f"Bearer {self.settings.access_token}",
|
21
|
+
},
|
22
|
+
decoder=provider_utils.parse_response,
|
23
|
+
on_error=lambda b: provider_utils.parse_response(b.read()),
|
24
|
+
)
|
25
|
+
|
26
|
+
return lib.Deserializable(response, lib.to_dict, request.ctx)
|
27
|
+
|
28
|
+
def get_tracking(self, request: lib.Serializable) -> lib.Deserializable:
|
29
|
+
response = lib.request(
|
30
|
+
url=f"{self.settings.server_url}/track/v1/trackingnumbers",
|
31
|
+
data=lib.to_json(request.serialize()),
|
32
|
+
trace=self.trace_as("json"),
|
33
|
+
method="POST",
|
34
|
+
headers={
|
35
|
+
"x-locale": "en_US",
|
36
|
+
"content-type": "application/json",
|
37
|
+
"authorization": f"Bearer {self.settings.track_access_token}",
|
38
|
+
},
|
39
|
+
decoder=provider_utils.parse_response,
|
40
|
+
on_error=lambda b: provider_utils.parse_response(b.read()),
|
41
|
+
)
|
42
|
+
|
43
|
+
return lib.Deserializable(response, lib.to_dict)
|
44
|
+
|
45
|
+
def create_shipment(self, request: lib.Serializable) -> lib.Deserializable:
|
46
|
+
responses = lib.request(
|
47
|
+
url=f"{self.settings.server_url}/ship/v1/shipments",
|
48
|
+
data=lib.to_json(request.serialize()),
|
49
|
+
trace=self.trace_as("json"),
|
50
|
+
method="POST",
|
51
|
+
headers={
|
52
|
+
"x-locale": "en_US",
|
53
|
+
"content-type": "application/json",
|
54
|
+
"authorization": f"Bearer {self.settings.access_token}",
|
55
|
+
},
|
56
|
+
decoder=provider_utils.parse_response,
|
57
|
+
on_error=lambda b: provider_utils.parse_response(b.read()),
|
58
|
+
)
|
59
|
+
|
60
|
+
return lib.Deserializable(responses, lib.to_dict)
|
61
|
+
|
62
|
+
def cancel_shipment(self, request: lib.Serializable) -> lib.Deserializable:
|
63
|
+
response = lib.request(
|
64
|
+
url=f"{self.settings.server_url}/ship/v1/shipments/cancel",
|
65
|
+
data=lib.to_json(request.serialize()),
|
66
|
+
trace=self.trace_as("json"),
|
67
|
+
method="PUT",
|
68
|
+
headers={
|
69
|
+
"x-locale": "en_US",
|
70
|
+
"content-type": "application/json",
|
71
|
+
"authorization": f"Bearer {self.settings.access_token}",
|
72
|
+
},
|
73
|
+
decoder=provider_utils.parse_response,
|
74
|
+
on_error=lambda b: provider_utils.parse_response(b.read()),
|
75
|
+
)
|
76
|
+
|
77
|
+
return lib.Deserializable(response, lib.to_dict)
|
78
|
+
|
79
|
+
def upload_document(self, requests: lib.Serializable) -> lib.Deserializable:
|
80
|
+
response = lib.run_asynchronously(
|
81
|
+
lambda _: lib.request(
|
82
|
+
url=(
|
83
|
+
"https://documentapitest.prod.fedex.com/sandbox/documents/v1/etds/upload"
|
84
|
+
if self.settings.test_mode
|
85
|
+
else "https://documentapi.prod.fedex.com/documents/v1/etds/upload"
|
86
|
+
),
|
87
|
+
data=urllib.parse.urlencode(_),
|
88
|
+
trace=self.trace_as("json"),
|
89
|
+
method="POST",
|
90
|
+
headers={
|
91
|
+
"content-Type": "multipart/form-data",
|
92
|
+
"authorization": f"Bearer {self.settings.access_token}",
|
93
|
+
},
|
94
|
+
),
|
95
|
+
requests.serialize(),
|
96
|
+
)
|
97
|
+
|
98
|
+
return lib.Deserializable(
|
99
|
+
response,
|
100
|
+
lambda __: [lib.to_dict(_) for _ in __],
|
101
|
+
)
|
102
|
+
|
103
|
+
def schedule_pickup(self, request: lib.Serializable) -> lib.Deserializable[str]:
|
104
|
+
response = lib.request(
|
105
|
+
url=f"{self.settings.server_url}/pickup/v1/pickups",
|
106
|
+
data=lib.to_json(request.serialize()),
|
107
|
+
trace=self.trace_as("json"),
|
108
|
+
method="POST",
|
109
|
+
headers={
|
110
|
+
"x-locale": "en_US",
|
111
|
+
"content-type": "application/json",
|
112
|
+
"authorization": f"Bearer {self.settings.access_token}",
|
113
|
+
},
|
114
|
+
decoder=provider_utils.parse_response,
|
115
|
+
on_error=lambda b: provider_utils.parse_response(b.read()),
|
116
|
+
)
|
117
|
+
|
118
|
+
return lib.Deserializable(response, lib.to_dict, request.ctx)
|
119
|
+
|
120
|
+
def modify_pickup(self, request: lib.Serializable) -> lib.Deserializable[str]:
|
121
|
+
response = self.cancel_pickup(lib.Serializable(request.ctx["cancel"]))
|
122
|
+
confirmation = response.deserialize().get("output") or {}
|
123
|
+
|
124
|
+
if confirmation.get("pickupConfirmationCode") is not None:
|
125
|
+
return self.schedule_pickup(request)
|
126
|
+
|
127
|
+
return response
|
128
|
+
|
129
|
+
def cancel_pickup(self, request: lib.Serializable) -> lib.Deserializable[str]:
|
130
|
+
response = lib.request(
|
131
|
+
url=f"{self.settings.server_url}/pickup/v1/pickups/cancel",
|
132
|
+
data=lib.to_json(request.serialize()),
|
133
|
+
trace=self.trace_as("json"),
|
134
|
+
method="PUT",
|
135
|
+
headers={
|
136
|
+
"x-locale": "en_US",
|
137
|
+
"content-type": "application/json",
|
138
|
+
"authorization": f"Bearer {self.settings.access_token}",
|
139
|
+
},
|
140
|
+
decoder=provider_utils.parse_response,
|
141
|
+
on_error=lambda b: provider_utils.parse_response(b.read()),
|
142
|
+
)
|
143
|
+
|
144
|
+
return lib.Deserializable(response, lib.to_dict, request.ctx)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
"""Karrio FedEx client settings."""
|
2
|
+
|
3
|
+
import attr
|
4
|
+
import jstruct
|
5
|
+
import karrio.lib as lib
|
6
|
+
import karrio.providers.fedex.utils as provider_utils
|
7
|
+
|
8
|
+
|
9
|
+
@attr.s(auto_attribs=True)
|
10
|
+
class Settings(provider_utils.Settings):
|
11
|
+
"""FedEx connection settings."""
|
12
|
+
|
13
|
+
api_key: str = None
|
14
|
+
secret_key: str = None
|
15
|
+
account_number: str = None
|
16
|
+
track_api_key: str = None
|
17
|
+
track_secret_key: str = None
|
18
|
+
|
19
|
+
account_country_code: str = None
|
20
|
+
carrier_id: str = "fedex"
|
21
|
+
test_mode: bool = False
|
22
|
+
metadata: dict = {}
|
23
|
+
config: dict = {}
|
24
|
+
id: str = None
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import karrio.core.metadata as metadata
|
2
|
+
import karrio.mappers.fedex as mappers
|
3
|
+
import karrio.providers.fedex.units as units
|
4
|
+
|
5
|
+
|
6
|
+
METADATA = metadata.PluginMetadata(
|
7
|
+
status="production-ready",
|
8
|
+
id="fedex",
|
9
|
+
label="FedEx",
|
10
|
+
# Integrations
|
11
|
+
Mapper=mappers.Mapper,
|
12
|
+
Proxy=mappers.Proxy,
|
13
|
+
Settings=mappers.Settings,
|
14
|
+
# Data Units
|
15
|
+
is_hub=False,
|
16
|
+
services=units.ShippingService,
|
17
|
+
options=units.ShippingOption,
|
18
|
+
connection_configs=units.ConnectionConfig,
|
19
|
+
has_intl_accounts=True,
|
20
|
+
# New fields
|
21
|
+
website="https://www.fedex.com",
|
22
|
+
description="FedEx Corporation is an American multinational conglomerate holding company which focuses on transportation, e-commerce and business services.",
|
23
|
+
)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
from karrio.providers.fedex.utils import Settings
|
2
|
+
from karrio.providers.fedex.tracking import (
|
3
|
+
parse_tracking_response,
|
4
|
+
tracking_request,
|
5
|
+
)
|
6
|
+
from karrio.providers.fedex.rate import rate_request, parse_rate_response
|
7
|
+
from karrio.providers.fedex.shipment import (
|
8
|
+
parse_shipment_cancel_response,
|
9
|
+
parse_shipment_response,
|
10
|
+
shipment_cancel_request,
|
11
|
+
shipment_request,
|
12
|
+
)
|
13
|
+
from karrio.providers.fedex.document import (
|
14
|
+
parse_document_upload_response,
|
15
|
+
document_upload_request,
|
16
|
+
)
|
17
|
+
from karrio.providers.fedex.pickup import (
|
18
|
+
parse_pickup_cancel_response,
|
19
|
+
parse_pickup_update_response,
|
20
|
+
parse_pickup_response,
|
21
|
+
pickup_cancel_request,
|
22
|
+
pickup_update_request,
|
23
|
+
pickup_request,
|
24
|
+
)
|
@@ -0,0 +1,88 @@
|
|
1
|
+
import karrio.schemas.fedex.paperless_request as fedex
|
2
|
+
import time
|
3
|
+
import typing
|
4
|
+
import karrio.lib as lib
|
5
|
+
import karrio.core.models as models
|
6
|
+
import karrio.providers.fedex.error as provider_error
|
7
|
+
import karrio.providers.fedex.units as provider_units
|
8
|
+
import karrio.providers.fedex.utils as provider_utils
|
9
|
+
|
10
|
+
|
11
|
+
def parse_document_upload_response(
|
12
|
+
_response: lib.Deserializable[typing.List[dict]],
|
13
|
+
settings: provider_utils.Settings,
|
14
|
+
) -> typing.Tuple[models.DocumentUploadDetails, typing.List[models.Message]]:
|
15
|
+
responses = _response.deserialize()
|
16
|
+
|
17
|
+
metas = [_["output"]["meta"] for _ in responses if _.get("output", {}).get("meta")]
|
18
|
+
details = _extract_details(metas, settings) if len(metas) > 0 else None
|
19
|
+
errors = provider_error.parse_error_response([_ for _ in responses], settings)
|
20
|
+
|
21
|
+
return details, errors
|
22
|
+
|
23
|
+
|
24
|
+
def _extract_details(
|
25
|
+
metas: typing.List[dict],
|
26
|
+
settings: provider_utils.Settings,
|
27
|
+
) -> models.DocumentUploadDetails:
|
28
|
+
return models.DocumentUploadDetails(
|
29
|
+
carrier_id=settings.carrier_id,
|
30
|
+
carrier_name=settings.carrier_id,
|
31
|
+
documents=[
|
32
|
+
models.DocumentDetails(
|
33
|
+
doc_id=meta["docId"],
|
34
|
+
file_name=meta["docId"],
|
35
|
+
)
|
36
|
+
for meta in metas
|
37
|
+
],
|
38
|
+
meta=dict(),
|
39
|
+
)
|
40
|
+
|
41
|
+
|
42
|
+
def document_upload_request(
|
43
|
+
payload: models.DocumentUploadRequest,
|
44
|
+
settings: provider_utils.Settings,
|
45
|
+
) -> lib.Serializable:
|
46
|
+
document_files = lib.to_document_files(payload.document_files)
|
47
|
+
options = lib.to_upload_options(
|
48
|
+
payload.options,
|
49
|
+
provider_units.DocumentUploadOption,
|
50
|
+
)
|
51
|
+
shipment_date = lib.fdatetime(
|
52
|
+
payload.shipment_date or time.strftime("%Y-%m-%d"),
|
53
|
+
current_format="%Y-%m-%d",
|
54
|
+
output_format="%Y%m%dT%H%M%S",
|
55
|
+
)
|
56
|
+
|
57
|
+
request = [
|
58
|
+
fedex.PaperlessRequestType(
|
59
|
+
document=fedex.DocumentType(
|
60
|
+
workflowName=(
|
61
|
+
"ETDPreshipment"
|
62
|
+
if options.pre_shipment.state
|
63
|
+
else "ETDPostshipment"
|
64
|
+
),
|
65
|
+
carrierCode=options.fedex_carrier_code.state,
|
66
|
+
name=document.doc_name,
|
67
|
+
contentType=document.doc_format,
|
68
|
+
meta=fedex.MetaType(
|
69
|
+
shipDocumentType=(
|
70
|
+
provider_units.UploadDocumentType.map(document.doc_type).value
|
71
|
+
or provider_units.UploadDocumentType.other.value
|
72
|
+
),
|
73
|
+
formCode=None,
|
74
|
+
trackingNumber=payload.tracking_number,
|
75
|
+
shipmentDate=shipment_date,
|
76
|
+
originCountryCode=options.origin_country_code.state,
|
77
|
+
destinationCountryCode=options.destination_country_code.state,
|
78
|
+
),
|
79
|
+
),
|
80
|
+
attachment=document.doc_file,
|
81
|
+
)
|
82
|
+
for document in document_files
|
83
|
+
]
|
84
|
+
|
85
|
+
return lib.Serializable(
|
86
|
+
request,
|
87
|
+
lambda __: [lib.to_dict(_) for _ in __],
|
88
|
+
)
|
@@ -0,0 +1,66 @@
|
|
1
|
+
import typing
|
2
|
+
import karrio.lib as lib
|
3
|
+
import karrio.core.models as models
|
4
|
+
from karrio.providers.fedex.utils import Settings
|
5
|
+
|
6
|
+
|
7
|
+
def parse_error_response(
|
8
|
+
response: typing.Union[typing.List[dict], dict],
|
9
|
+
settings: Settings,
|
10
|
+
**details,
|
11
|
+
) -> typing.List[models.Message]:
|
12
|
+
responses = response if isinstance(response, list) else [response]
|
13
|
+
errors: typing.List[dict] = sum(
|
14
|
+
[
|
15
|
+
[
|
16
|
+
*(result["errors"] if "errors" in result else []),
|
17
|
+
*(
|
18
|
+
result["output"]["alerts"]
|
19
|
+
if "output" in result
|
20
|
+
and not isinstance(result["output"], str)
|
21
|
+
and "alerts" in result.get("output", {})
|
22
|
+
and not isinstance(result["output"]["alerts"], str)
|
23
|
+
else []
|
24
|
+
),
|
25
|
+
*(
|
26
|
+
[{"message": result["output"]["message"]}]
|
27
|
+
if "output" in result
|
28
|
+
and not isinstance(result["output"], str)
|
29
|
+
and "message" in result.get("output", {})
|
30
|
+
and isinstance(result["output"]["message"], str)
|
31
|
+
and not result["output"].get("alertType") != "NOTE"
|
32
|
+
else []
|
33
|
+
),
|
34
|
+
*(
|
35
|
+
[
|
36
|
+
{
|
37
|
+
**result["error"],
|
38
|
+
"tracking_number": result.get("trackingNumberInfo", {}).get(
|
39
|
+
"trackingNumber"
|
40
|
+
),
|
41
|
+
}
|
42
|
+
]
|
43
|
+
if "error" in result
|
44
|
+
else []
|
45
|
+
),
|
46
|
+
]
|
47
|
+
for result in responses
|
48
|
+
],
|
49
|
+
[],
|
50
|
+
)
|
51
|
+
|
52
|
+
return [
|
53
|
+
models.Message(
|
54
|
+
carrier_name=settings.carrier_name,
|
55
|
+
carrier_id=settings.carrier_id,
|
56
|
+
code=error.get("code"),
|
57
|
+
message=error.get("message"),
|
58
|
+
details=lib.to_dict(
|
59
|
+
{
|
60
|
+
**details,
|
61
|
+
"tracking_number": error.get("tracking_number"),
|
62
|
+
}
|
63
|
+
),
|
64
|
+
)
|
65
|
+
for error in errors
|
66
|
+
]
|
@@ -0,0 +1,9 @@
|
|
1
|
+
from karrio.providers.fedex.pickup.create import parse_pickup_response, pickup_request
|
2
|
+
from karrio.providers.fedex.pickup.update import (
|
3
|
+
parse_pickup_update_response,
|
4
|
+
pickup_update_request,
|
5
|
+
)
|
6
|
+
from karrio.providers.fedex.pickup.cancel import (
|
7
|
+
parse_pickup_cancel_response,
|
8
|
+
pickup_cancel_request,
|
9
|
+
)
|
@@ -0,0 +1,79 @@
|
|
1
|
+
import karrio.schemas.fedex.cancel_pickup_request as fedex
|
2
|
+
import karrio.schemas.fedex.cancel_pickup_response as pickup
|
3
|
+
|
4
|
+
import typing
|
5
|
+
import karrio.lib as lib
|
6
|
+
import karrio.core.units as units
|
7
|
+
import karrio.core.models as models
|
8
|
+
import karrio.providers.fedex.error as error
|
9
|
+
import karrio.providers.fedex.utils as provider_utils
|
10
|
+
import karrio.providers.fedex.units as provider_units
|
11
|
+
|
12
|
+
|
13
|
+
def parse_pickup_cancel_response(
|
14
|
+
_response: lib.Deserializable[dict],
|
15
|
+
settings: provider_utils.Settings,
|
16
|
+
) -> typing.Tuple[models.ConfirmationDetails, typing.List[models.Message]]:
|
17
|
+
response = _response.deserialize()
|
18
|
+
messages = error.parse_error_response(response, settings)
|
19
|
+
success = any(lib.failsafe(lambda: response["output"]["pickupConfirmationCode"]))
|
20
|
+
|
21
|
+
confirmation = lib.identity(
|
22
|
+
models.ConfirmationDetails(
|
23
|
+
carrier_id=settings.carrier_id,
|
24
|
+
carrier_name=settings.carrier_name,
|
25
|
+
operation="Cancel Pickup",
|
26
|
+
success=success,
|
27
|
+
)
|
28
|
+
if success
|
29
|
+
else None
|
30
|
+
)
|
31
|
+
|
32
|
+
return confirmation, messages
|
33
|
+
|
34
|
+
|
35
|
+
def pickup_cancel_request(
|
36
|
+
payload: models.PickupCancelRequest,
|
37
|
+
settings: provider_utils.Settings,
|
38
|
+
) -> lib.Serializable:
|
39
|
+
address = lib.to_address(payload.address)
|
40
|
+
options = lib.units.Options(
|
41
|
+
payload.options,
|
42
|
+
option_type=lib.units.create_enum(
|
43
|
+
"PickupOptions",
|
44
|
+
# fmt: off
|
45
|
+
{
|
46
|
+
"fedex_carrier_code": lib.OptionEnum("carrierCode"),
|
47
|
+
"fedex_pickup_location": lib.OptionEnum("location"),
|
48
|
+
},
|
49
|
+
# fmt: on
|
50
|
+
),
|
51
|
+
)
|
52
|
+
|
53
|
+
# map data to convert karrio model to fedex specific type
|
54
|
+
request = fedex.CancelPickupRequestType(
|
55
|
+
associatedAccountNumber=fedex.AssociatedAccountNumberType(
|
56
|
+
value=settings.account_number,
|
57
|
+
),
|
58
|
+
pickupConfirmationCode=payload.confirmation_number,
|
59
|
+
remarks=payload.reason,
|
60
|
+
carrierCode=options.fedex_carrier_code.state,
|
61
|
+
accountAddressOfRecord=lib.identity(
|
62
|
+
fedex.AccountAddressOfRecordType(
|
63
|
+
streetLines=address.address_lines,
|
64
|
+
urbanizationCode=None,
|
65
|
+
city=address.city,
|
66
|
+
stateOrProvinceCode=provider_utils.state_code(address),
|
67
|
+
postalCode=address.postal_code,
|
68
|
+
countryCode=address.country_code,
|
69
|
+
residential=address.residential,
|
70
|
+
addressClassification=None,
|
71
|
+
)
|
72
|
+
if payload.address
|
73
|
+
else None
|
74
|
+
),
|
75
|
+
scheduledDate=lib.fdate(payload.pickup_date, "%Y-%m-%d"),
|
76
|
+
location=options.fedex_pickup_location.state,
|
77
|
+
)
|
78
|
+
|
79
|
+
return lib.Serializable(request, lib.to_dict)
|