Skip to content
This repository has been archived by the owner on Nov 4, 2024. It is now read-only.

Commit

Permalink
fix: Capture-context modification for existing Payment Intents (#4154)
Browse files Browse the repository at this point in the history
REV-3821
  • Loading branch information
julianajlk authored Apr 22, 2024
1 parent 5482fe2 commit e63fbfa
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/migrations-mysql8.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ jobs:
pip uninstall -y mysqlclient
pip install --no-binary mysqlclient mysqlclient
pip uninstall -y xmlsec
pip install --no-binary xmlsec xmlsec
pip install --no-binary xmlsec xmlsec==1.3.13
- name: Initiate Services
run: |
Expand Down
11 changes: 10 additions & 1 deletion ecommerce/extensions/payment/processors/stripe.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,16 @@ def get_capture_context(self, request):
if payment_intent_id:
stripe_response = stripe.PaymentIntent.retrieve(id=payment_intent_id)
status = stripe_response['status']
if status != 'requires_payment_method' or status != 'requires_confirmation':
logger.info(
'Stripe capture-context called for basket [%d] and order number [%s] with '
'existing Payment Intent [%s] with status [%s]',
basket.id,
basket.order_number,
payment_intent_id,
status,
)
confirmable_statuses = ['requires_payment_method', 'requires_confirmation']
if status not in confirmable_statuses:
# Payment Intent is in a non-confirmable status, must create a new one
stripe_response = self.cancel_and_create_new_payment_intent_for_basket(basket, payment_intent_id)
# If a Payment Intent exists in a confirmable status, it will skip the below else statement,
Expand Down
33 changes: 33 additions & 0 deletions ecommerce/extensions/payment/tests/views/test_stripe.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,39 @@ def test_capture_context_large_characters_basket(self):
# The metadata must be less than 500 characters
assert len(mock_create.call_args.kwargs['metadata']['courses']) < 500

@file_data('fixtures/test_stripe_test_payment_flow.json')
def test_capture_context_confirmable_status(
self,
confirm_resp, # pylint: disable=unused-argument
confirm_resp_in_progress, # pylint: disable=unused-argument
create_resp, # pylint: disable=unused-argument
modify_resp, # pylint: disable=unused-argument
cancel_resp, # pylint: disable=unused-argument
refund_resp, # pylint: disable=unused-argument
retrieve_addr_resp,
retrieve_resp_in_progress): # pylint: disable=unused-argument
"""
Verify that hitting capture-context with a Payment Intent that already exists and it's in a status that
can be confirmed, that a new Payment Intent is not created for this basket.
"""
basket = self.create_basket(product_class=SEAT_PRODUCT_CLASS_NAME)
payment_intent_id = retrieve_addr_resp['id']
basket_add_payment_intent_id_attribute(basket, payment_intent_id)

with mock.patch('stripe.PaymentIntent.retrieve') as mock_retrieve:
mock_retrieve.return_value = retrieve_addr_resp
# If Payment Intent already exists for this basket, and it's in a usable status that
# can later be confirmed, make sure we do not cancel and create a new Payment Intent.
with mock.patch('stripe.PaymentIntent.cancel') as mock_cancel:
self.client.get(self.capture_context_url)
mock_cancel.assert_not_called()
payment_intent_id = BasketAttribute.objects.get(
basket=basket,
attribute_type__name=PAYMENT_INTENT_ID_ATTRIBUTE
).value_text
assert payment_intent_id == mock_retrieve.return_value['id']
assert retrieve_addr_resp['status'] == 'requires_confirmation'

@file_data('fixtures/test_stripe_test_payment_flow.json')
def test_capture_context_in_progress_payment(
self,
Expand Down

0 comments on commit e63fbfa

Please sign in to comment.