Skip to content

Commit cb9765d

Browse files
committed
feat: handle payment error on trial
1 parent 4745854 commit cb9765d

File tree

7 files changed

+795
-339
lines changed

7 files changed

+795
-339
lines changed

enterprise_access/apps/api_client/license_manager_client.py

Lines changed: 65 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,71 @@ class LicenseManagerApiClient(BaseOAuthClient):
2828
subscription_provisioning_endpoint = api_base_url + 'provisioning-admins/subscriptions/'
2929
subscription_plan_renewal_provisioning_endpoint = api_base_url + 'provisioning-admins/subscription-plan-renewals/'
3030

31+
def list_subscriptions(self, enterprise_customer_uuid):
32+
"""
33+
List subscription plans for an enterprise.
34+
35+
Returns a paginated DRF list response: { count, next, previous, results: [...] }
36+
"""
37+
try:
38+
params = {
39+
'enterprise_customer_uuid': enterprise_customer_uuid,
40+
}
41+
42+
response = self.client.get(
43+
self.subscriptions_endpoint,
44+
params=params,
45+
timeout=settings.LICENSE_MANAGER_CLIENT_TIMEOUT,
46+
)
47+
response.raise_for_status()
48+
return response.json()
49+
except requests.exceptions.HTTPError as exc:
50+
logger.exception(
51+
'Failed to list subscriptions for enterprise %s, response: %s, exc: %s',
52+
enterprise_customer_uuid, safe_error_response_content(exc), exc,
53+
)
54+
raise
55+
56+
def update_subscription_plan(self, subscription_uuid, salesforce_opportunity_line_item=None, **kwargs):
57+
"""
58+
Partially update a SubscriptionPlan via the provisioning-admins endpoint.
59+
60+
Accepts any fields supported by license-manager for SubscriptionPlan patching, including:
61+
- is_active (bool)
62+
- change_reason (str)
63+
- salesforce_opportunity_line_item (str)
64+
65+
Args:
66+
subscription_uuid (str): Subscription plan UUID.
67+
salesforce_opportunity_line_item (str|None): Optional Salesforce OLI to associate.
68+
**kwargs: Additional JSON fields to patch.
69+
70+
Returns:
71+
dict: JSON response from license-manager.
72+
"""
73+
payload = {**kwargs}
74+
if salesforce_opportunity_line_item:
75+
payload['salesforce_opportunity_line_item'] = salesforce_opportunity_line_item
76+
77+
if not payload:
78+
raise ValueError('Must supply payload to update subscription plan')
79+
80+
endpoint = f"{self.subscription_provisioning_endpoint}{subscription_uuid}/"
81+
try:
82+
response = self.client.patch(
83+
endpoint,
84+
json=payload,
85+
timeout=settings.LICENSE_MANAGER_CLIENT_TIMEOUT,
86+
)
87+
response.raise_for_status()
88+
return response.json()
89+
except requests.exceptions.HTTPError as exc:
90+
logger.exception(
91+
'Failed to update subscription %s, payload=%s, response: %s, exc: %s',
92+
subscription_uuid, payload, safe_error_response_content(exc), exc,
93+
)
94+
raise
95+
3196
def get_subscription_overview(self, subscription_uuid):
3297
"""
3398
Call license-manager API for data about a SubscriptionPlan.
@@ -212,46 +277,6 @@ def create_subscription_plan(
212277
exc,
213278
) from exc
214279

215-
def update_subscription_plan(self, subscription_uuid, salesforce_opportunity_line_item):
216-
"""
217-
Update a SubscriptionPlan's Salesforce Opportunity Line Item.
218-
219-
Arguments:
220-
subscription_uuid (str): UUID of the SubscriptionPlan to update
221-
salesforce_opportunity_line_item (str): Salesforce OLI to associate with the plan
222-
223-
Returns:
224-
dict: Updated subscription plan data from the API
225-
226-
Raises:
227-
APIClientException: If the API call fails
228-
"""
229-
endpoint = f"{self.api_base_url}subscription-plans/{subscription_uuid}/"
230-
payload = {
231-
'salesforce_opportunity_line_item': salesforce_opportunity_line_item
232-
}
233-
234-
try:
235-
response = self.client.patch(
236-
endpoint,
237-
json=payload,
238-
timeout=settings.LICENSE_MANAGER_CLIENT_TIMEOUT
239-
)
240-
response.raise_for_status()
241-
return response.json()
242-
except requests.exceptions.HTTPError as exc:
243-
logger.exception(
244-
'Failed to update subscription plan %s with OLI %s, response %s, exception: %s',
245-
subscription_uuid,
246-
salesforce_opportunity_line_item,
247-
safe_error_response_content(exc),
248-
exc,
249-
)
250-
raise APIClientException(
251-
f'Could not update subscription plan {subscription_uuid}',
252-
exc,
253-
) from exc
254-
255280
def create_subscription_plan_renewal(
256281
self,
257282
prior_subscription_plan_uuid: str,

enterprise_access/apps/api_client/tests/test_license_manager_client.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,49 @@ def test_create_customer_agreement(self, mock_oauth_client):
8888
json=expected_payload,
8989
)
9090

91+
@mock.patch('enterprise_access.apps.api_client.base_oauth.OAuthAPIClient', autospec=True)
92+
def test_list_subscriptions_params(self, mock_oauth_client):
93+
mock_get = mock_oauth_client.return_value.get
94+
mock_get.return_value.json.return_value = {'results': []}
95+
96+
lm_client = LicenseManagerApiClient()
97+
enterprise_uuid = 'ec-uuid-123'
98+
99+
# Should only set enterprise_customer_uuid parameter
100+
result = lm_client.list_subscriptions(enterprise_uuid)
101+
self.assertEqual(result, {'results': []})
102+
103+
# Verify URL and params
104+
expected_url = (
105+
'http://license-manager.example.com'
106+
'/api/v1/subscriptions/'
107+
)
108+
mock_get.assert_called_with(
109+
expected_url,
110+
params={'enterprise_customer_uuid': enterprise_uuid},
111+
timeout=settings.LICENSE_MANAGER_CLIENT_TIMEOUT,
112+
)
113+
114+
@mock.patch('enterprise_access.apps.api_client.base_oauth.OAuthAPIClient', autospec=True)
115+
def test_update_subscription_plan_patch(self, mock_oauth_client):
116+
mock_patch = mock_oauth_client.return_value.patch
117+
mock_patch.return_value.json.return_value = {'uuid': 'plan-uuid', 'is_active': False}
118+
119+
lm_client = LicenseManagerApiClient()
120+
payload = {'is_active': False, 'change_reason': 'delayed_payment'}
121+
result = lm_client.update_subscription_plan('plan-uuid', **payload)
122+
123+
self.assertEqual(result, mock_patch.return_value.json.return_value)
124+
expected_url = (
125+
'http://license-manager.example.com'
126+
'/api/v1/provisioning-admins/subscriptions/plan-uuid/'
127+
)
128+
mock_patch.assert_called_once_with(
129+
expected_url,
130+
json=payload,
131+
timeout=settings.LICENSE_MANAGER_CLIENT_TIMEOUT,
132+
)
133+
91134
@mock.patch('enterprise_access.apps.api_client.base_oauth.OAuthAPIClient', autospec=True)
92135
def test_create_subscription_plan(self, mock_oauth_client):
93136
mock_post = mock_oauth_client.return_value.post

0 commit comments

Comments
 (0)