Skip to content

Commit 77012f5

Browse files
committed
feat: add new create_ups and update_ups functions
1 parent 0b650b6 commit 77012f5

7 files changed

Lines changed: 228 additions & 24 deletions

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# CHANGELOG
22

3+
## Next Release
4+
5+
- Adds new `create_ups` and `update_ups` functions under `carrier_account`
6+
- Starting `2024-08-05`, UPS accounts can no longer be created or updated through the normal create and update functions and must use these UPS specific functions
7+
38
## v9.2.0 (2024-04-10)
49

510
- Fix payment method funding and deletion failures due to undetermined payment method type

easypost/constant.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,5 @@
3535
_CARRIER_ACCOUNT_TYPES_WITH_CUSTOM_WORKFLOWS = [
3636
"FedexAccount",
3737
"FedexSmartpostAccount",
38-
"UpsAccount",
3938
]
4039
_FILTERS_KEY = "filters"

easypost/services/carrier_account_service.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,23 @@ def types(self) -> List[Dict[str, Any]]:
6060

6161
return convert_to_easypost_object(response=response)
6262

63+
def create_ups(self, **params) -> CarrierAccount:
64+
"""Create a UPS CarrierAccount which has its own custom workflow."""
65+
url = "/ups_oauth_registrations"
66+
wrapped_params = {"ups_oauth_registrations": params}
67+
68+
response = Requestor(self._client).request(
69+
method=RequestMethod.POST,
70+
url=url,
71+
params=wrapped_params,
72+
)
73+
74+
return convert_to_easypost_object(response=response)
75+
76+
def update_ups(self, id: str, **params) -> CarrierAccount:
77+
"""Update a UPS CarrierAccount which has its own custom workflow."""
78+
return self._update_resource("UpsOauthRegistrations", id, **params)
79+
6380
def _select_carrier_account_creation_endpoint(self, carrier_account_type: Optional[Any]) -> str:
6481
"""Determines which API endpoint to use for the creation call."""
6582
if carrier_account_type in _CARRIER_ACCOUNT_TYPES_WITH_CUSTOM_WORKFLOWS:

tests/cassettes/test_carrier_account_create_ups.yaml

Lines changed: 69 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/cassettes/test_carrier_account_create_with_custom_workflow.yaml

Lines changed: 27 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/cassettes/test_carrier_account_update_ups.yaml

Lines changed: 70 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/test_carrier_account.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,13 @@ def test_carrier_account_type(prod_client):
7575

7676
@pytest.mark.vcr()
7777
def test_carrier_account_create_with_custom_workflow(prod_client):
78-
"""Test register a Carrier Account with custom registration such as FedEx or UPS.
78+
"""Test registering a Carrier Account with custom workflow.
7979
8080
We purposefully don't pass data here because real data is required for this endpoint
8181
which we don't have in a test context, simply assert the error matches when no data is passed.
8282
"""
8383
carrier_account = {
84-
"type": "UpsAccount",
84+
"type": "FedexAccount",
8585
"registration_data": {},
8686
}
8787

@@ -93,3 +93,41 @@ def test_carrier_account_create_with_custom_workflow(prod_client):
9393
[error["field"] == "account_number" and error["message"] == "must be present and a string"]
9494
for error in error.errors
9595
)
96+
97+
98+
@pytest.mark.vcr()
99+
def test_carrier_account_create_ups(prod_client):
100+
"""Test registering a UPS Carrier Account.
101+
102+
We purposefully don't pass data here because real data is required for this endpoint
103+
which we don't have in a test context, simply assert the error matches when no data is passed.
104+
"""
105+
carrier_account = {
106+
"type": "UpsAccount",
107+
}
108+
109+
try:
110+
prod_client.carrier_account.create_ups(**carrier_account)
111+
except ApiError as error:
112+
assert error.http_status == 422
113+
assert any(
114+
[error["field"] == "account_number" and error["message"] == "must be present and a string"]
115+
for error in error.errors
116+
)
117+
118+
119+
@pytest.mark.vcr()
120+
def test_carrier_account_update_ups(prod_client):
121+
"""Test updating a UPS Carrier Account.
122+
123+
We purposefully don't pass data here because real data is required for this endpoint
124+
which we don't have in a test context, simply assert that we routed the request correctly.
125+
"""
126+
carrier_account = {
127+
"type": "UpsAccount",
128+
}
129+
130+
try:
131+
prod_client.carrier_account.update_ups("ca_123", **carrier_account)
132+
except ApiError as error:
133+
assert error.http_status == 404

0 commit comments

Comments
 (0)