Skip to content

Commit

Permalink
fix: Update default payment method on subscription for user (#630)
Browse files Browse the repository at this point in the history
  • Loading branch information
ajay-sentry committed Jun 21, 2024
1 parent 555a041 commit c3824bd
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
interactions:
- request:
body: default_payment_method=pm_123
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
Content-Length:
- '29'
Content-Type:
- application/x-www-form-urlencoded
Idempotency-Key:
- 7c40f9e9-3a01-4109-87bf-3218dfbcf27f
Stripe-Version:
- '2024-04-10'
User-Agent:
- Stripe/v1 PythonBindings/9.6.0
X-Stripe-Client-User-Agent:
- '{"bindings_version": "9.6.0", "lang": "python", "publisher": "stripe", "httplib":
"requests", "lang_version": "3.12.4", "platform": "Linux-6.6.31-linuxkit-aarch64-with-glibc2.36",
"uname": "Linux 2b87f96d1995 6.6.31-linuxkit #1 SMP Thu May 23 08:36:57 UTC
2024 aarch64 "}'
method: POST
uri: https://api.stripe.com/v1/subscriptions/djfos
response:
body:
string: "{\n \"error\": {\n \"code\": \"resource_missing\",\n \"doc_url\":
\"https://stripe.com/docs/error-codes/resource-missing\",\n \"message\":
\"No such PaymentMethod: 'pm_123'\",\n \"param\": \"default_payment_method\",\n
\ \"request_log_url\": \"https://dashboard.stripe.com/test/logs/req_xT5h1VWY7P75Lu?t=1719007484\",\n
\ \"type\": \"invalid_request_error\"\n }\n}\n"
headers:
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET,HEAD,PUT,PATCH,POST,DELETE
Access-Control-Allow-Origin:
- '*'
Access-Control-Expose-Headers:
- Request-Id, Stripe-Manage-Version, Stripe-Should-Retry, X-Stripe-External-Auth-Required,
X-Stripe-Privileged-Session-Required
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Connection:
- keep-alive
Content-Length:
- '346'
Content-Security-Policy:
- report-uri https://q.stripe.com/csp-report?p=v1%2Fsubscriptions%2F%3Asubscription_exposed_id;
block-all-mixed-content; default-src 'none'; base-uri 'none'; form-action
'none'; frame-ancestors 'none'; img-src 'self'; script-src 'self' 'report-sample';
style-src 'self'
Content-Type:
- application/json
Cross-Origin-Opener-Policy-Report-Only:
- same-origin; report-to="coop"
Date:
- Fri, 21 Jun 2024 22:04:44 GMT
Idempotency-Key:
- 7c40f9e9-3a01-4109-87bf-3218dfbcf27f
Original-Request:
- req_xT5h1VWY7P75Lu
Report-To:
- '{"group":"coop","max_age":8640,"endpoints":[{"url":"https://q.stripe.com/coop-report?s=billing-api-srv"}],"include_subdomains":true}'
Reporting-Endpoints:
- coop="https://q.stripe.com/coop-report?s=billing-api-srv"
Request-Id:
- req_xT5h1VWY7P75Lu
Server:
- nginx
Strict-Transport-Security:
- max-age=63072000; includeSubDomains; preload
Stripe-Version:
- '2024-04-10'
Vary:
- Origin
X-Content-Type-Options:
- nosniff
X-Stripe-Priority-Routing-Enabled:
- 'true'
X-Stripe-Routing-Context-Priority-Tier:
- api-testmode
status:
code: 400
message: Bad Request
version: 1
12 changes: 11 additions & 1 deletion api/internal/tests/views/test_account_viewset.py
Original file line number Diff line number Diff line change
Expand Up @@ -961,8 +961,13 @@ def test_update_payment_method_without_body(self):
@patch("services.billing.stripe.Subscription.retrieve")
@patch("services.billing.stripe.PaymentMethod.attach")
@patch("services.billing.stripe.Customer.modify")
@patch("services.billing.stripe.Subscription.modify")
def test_update_payment_method(
self, modify_customer_mock, attach_payment_mock, retrieve_subscription_mock
self,
modify_subscription_mock,
modify_customer_mock,
attach_payment_mock,
retrieve_subscription_mock,
):
self.current_owner.stripe_customer_id = "flsoe"
self.current_owner.stripe_subscription_id = "djfos"
Expand Down Expand Up @@ -1008,6 +1013,11 @@ def test_update_payment_method(
invoice_settings={"default_payment_method": payment_method_id},
)

modify_subscription_mock.assert_called_once_with(
self.current_owner.stripe_subscription_id,
default_payment_method=payment_method_id,
)

@patch("services.billing.StripeService.update_payment_method")
def test_update_payment_method_handles_stripe_error(self, upm_mock):
code, message = 402, "Oops, nope"
Expand Down
34 changes: 28 additions & 6 deletions services/billing.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,11 +397,24 @@ def create_checkout_session(self, owner: Owner, desired_plan):
return session["id"]

@_log_stripe_error
def update_payment_method(self, owner, payment_method):
log.info(f"Stripe update payment method for owner {owner.ownerid}")
if owner.stripe_subscription_id is None:
log.info(
f"stripe_subscription_id is None, no updating card for owner {owner.ownerid}"
def update_payment_method(self, owner: Owner, payment_method):
log.info(
"Stripe update payment method for owner",
extra=dict(
owner_id=owner.ownerid,
user_id=self.requesting_user.ownerid,
subscription_id=owner.stripe_subscription_id,
customer_id=owner.stripe_customer_id,
),
)
if owner.stripe_subscription_id is None or owner.stripe_customer_id is None:
log.warn(
"Missing subscription or customer id, returning early",
extra=dict(
owner_id=owner.ownerid,
subscription_id=owner.stripe_subscription_id,
customer_id=owner.stripe_customer_id,
),
)
return None
# attach the payment method + set as default on the invoice and subscription
Expand All @@ -410,8 +423,17 @@ def update_payment_method(self, owner, payment_method):
owner.stripe_customer_id,
invoice_settings={"default_payment_method": payment_method},
)
stripe.Subscription.modify(
owner.stripe_subscription_id, default_payment_method=payment_method
)
log.info(
f"Stripe success update payment method for owner {owner.ownerid} by user #{self.requesting_user.ownerid}"
"Successfully updated payment method for owner {owner.ownerid} by user #{self.requesting_user.ownerid}",
extra=dict(
owner_id=owner.ownerid,
user_id=self.requesting_user.ownerid,
subscription_id=owner.stripe_subscription_id,
customer_id=owner.stripe_customer_id,
),
)

@_log_stripe_error
Expand Down
9 changes: 8 additions & 1 deletion services/tests/test_billing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1106,7 +1106,10 @@ def test_update_payment_method_when_no_subscription(self):

@patch("services.billing.stripe.PaymentMethod.attach")
@patch("services.billing.stripe.Customer.modify")
def test_update_payment_method(self, modify_customer_mock, attach_payment_mock):
@patch("services.billing.stripe.Subscription.modify")
def test_update_payment_method(
self, modify_sub_mock, modify_customer_mock, attach_payment_mock
):
payment_method_id = "pm_1234567"
subscription_id = "sub_abc"
customer_id = "cus_abc"
Expand All @@ -1121,6 +1124,10 @@ def test_update_payment_method(self, modify_customer_mock, attach_payment_mock):
customer_id, invoice_settings={"default_payment_method": payment_method_id}
)

modify_sub_mock.assert_called_once_with(
subscription_id, default_payment_method=payment_method_id
)

def test_update_email_address_with_invalid_email(self):
owner = OwnerFactory(stripe_subscription_id=None)
assert self.stripe.update_email_address(owner, "not-an-email") is None
Expand Down

0 comments on commit c3824bd

Please sign in to comment.