corporate: Update create_stripe_customer to not attach payment method.

According to stripe's documentation for attaching payment methods to
customers (see https://stripe.com/docs/api/payment_methods/attach),
payment methods should be attached to customers through a SetupIntent
or PaymentIntent, which is what we do as we process new customers
and accounts.

Updates create_stripe_customer so that it is clear that the payment
method should not be added when we directly create a new  stripe
customer.
This commit is contained in:
Lauryn Menard 2023-11-09 14:46:39 +01:00 committed by Tim Abbott
parent 4dd6f105a0
commit 1f28837bd7
2 changed files with 13 additions and 24 deletions

View File

@ -402,22 +402,16 @@ class BillingSession(ABC):
pass pass
@catch_stripe_errors @catch_stripe_errors
def create_stripe_customer(self, payment_method: Optional[str] = None) -> Customer: def create_stripe_customer(self) -> Customer:
stripe_customer_data = self.get_data_for_stripe_customer() stripe_customer_data = self.get_data_for_stripe_customer()
stripe_customer = stripe.Customer.create( stripe_customer = stripe.Customer.create(
description=stripe_customer_data.description, description=stripe_customer_data.description,
email=stripe_customer_data.email, email=stripe_customer_data.email,
metadata=stripe_customer_data.metadata, metadata=stripe_customer_data.metadata,
payment_method=payment_method,
)
stripe.Customer.modify(
stripe_customer.id, invoice_settings={"default_payment_method": payment_method}
) )
event_time = timestamp_to_datetime(stripe_customer.created) event_time = timestamp_to_datetime(stripe_customer.created)
with transaction.atomic(): with transaction.atomic():
self.write_to_audit_log(AuditLogEventType.STRIPE_CUSTOMER_CREATED, event_time) self.write_to_audit_log(AuditLogEventType.STRIPE_CUSTOMER_CREATED, event_time)
if payment_method is not None:
self.write_to_audit_log(AuditLogEventType.STRIPE_CARD_CHANGED, event_time)
customer = self.update_or_create_customer(stripe_customer.id) customer = self.update_or_create_customer(stripe_customer.id)
return customer return customer
@ -448,11 +442,15 @@ class BillingSession(ABC):
def update_or_create_stripe_customer(self, payment_method: Optional[str] = None) -> Customer: def update_or_create_stripe_customer(self, payment_method: Optional[str] = None) -> Customer:
customer = self.get_customer() customer = self.get_customer()
if customer is None or customer.stripe_customer_id is None: if customer is None or customer.stripe_customer_id is None:
# A stripe.PaymentMethod should be attached to a stripe.Customer via
# a stripe.SetupIntent or stripe.PaymentIntent. Here we just want to
# create a new stripe.Customer.
assert payment_method is None
# We could do a better job of handling race conditions here, but if two # We could do a better job of handling race conditions here, but if two
# people try to upgrade at exactly the same time, the main bad thing that # people try to upgrade at exactly the same time, the main bad thing that
# will happen is that we will create an extra stripe customer that we can # will happen is that we will create an extra stripe.Customer that we can
# delete or ignore. # delete or ignore.
return self.create_stripe_customer(payment_method=payment_method) return self.create_stripe_customer()
if payment_method is not None: if payment_method is not None:
self.replace_payment_method(customer.stripe_customer_id, payment_method, True) self.replace_payment_method(customer.stripe_customer_id, payment_method, True)
return customer return customer

View File

@ -3849,16 +3849,11 @@ class StripeTest(StripeTestCase):
self.assertFalse(customer_has_credit_card_as_default_payment_method(customer)) self.assertFalse(customer_has_credit_card_as_default_payment_method(customer))
billing_session = RealmBillingSession(iago) billing_session = RealmBillingSession(iago)
customer = billing_session.create_stripe_customer() customer = billing_session.update_or_create_stripe_customer()
self.assertFalse(customer_has_credit_card_as_default_payment_method(customer)) self.assertFalse(customer_has_credit_card_as_default_payment_method(customer))
customer = billing_session.create_stripe_customer( self.login_user(iago)
payment_method=create_payment_method( self.upgrade()
self.get_test_card_number(
attaches_to_customer=True, charge_succeeds=True, card_provider="visa"
)
).id,
)
self.assertTrue(customer_has_credit_card_as_default_payment_method(customer)) self.assertTrue(customer_has_credit_card_as_default_payment_method(customer))
@ -4317,9 +4312,7 @@ class BillingHelpersTest(ZulipTestCase):
"corporate.lib.stripe.BillingSession.create_stripe_customer", return_value="returned" "corporate.lib.stripe.BillingSession.create_stripe_customer", return_value="returned"
) as mocked1: ) as mocked1:
billing_session = RealmBillingSession(user) billing_session = RealmBillingSession(user)
returned = billing_session.update_or_create_stripe_customer( returned = billing_session.update_or_create_stripe_customer()
payment_method="payment_method_id"
)
mocked1.assert_called_once() mocked1.assert_called_once()
self.assertEqual(returned, "returned") self.assertEqual(returned, "returned")
@ -4329,9 +4322,7 @@ class BillingHelpersTest(ZulipTestCase):
"corporate.lib.stripe.BillingSession.create_stripe_customer", return_value="returned" "corporate.lib.stripe.BillingSession.create_stripe_customer", return_value="returned"
) as mocked2: ) as mocked2:
billing_session = RealmBillingSession(user) billing_session = RealmBillingSession(user)
returned = billing_session.update_or_create_stripe_customer( returned = billing_session.update_or_create_stripe_customer()
payment_method="payment_method_id"
)
mocked2.assert_called_once() mocked2.assert_called_once()
self.assertEqual(returned, "returned") self.assertEqual(returned, "returned")
@ -4340,7 +4331,7 @@ class BillingHelpersTest(ZulipTestCase):
# Customer exists, replace payment source # Customer exists, replace payment source
with patch("corporate.lib.stripe.BillingSession.replace_payment_method") as mocked3: with patch("corporate.lib.stripe.BillingSession.replace_payment_method") as mocked3:
billing_session = RealmBillingSession(user) billing_session = RealmBillingSession(user)
returned_customer = billing_session.update_or_create_stripe_customer("token") returned_customer = billing_session.update_or_create_stripe_customer("pm_card_visa")
mocked3.assert_called_once() mocked3.assert_called_once()
self.assertEqual(returned_customer, customer) self.assertEqual(returned_customer, customer)