Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions payments/stripe/providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,14 @@ def create_session(self, payment):
else:
raise PaymentError("This payment has already been processed.")

def cancel(self, payment):
if payment.transaction_id:
stripe.api_key = self.api_key
try:
stripe.checkout.Session.expire(payment.transaction_id)
except stripe.StripeError as e:
raise PaymentError(e) from e

def refund(self, payment, amount=None):
if payment.status == PaymentStatus.CONFIRMED:
to_refund = amount or payment.total
Expand Down Expand Up @@ -253,8 +261,8 @@ def process_data(self, payment, request):
) from e

if session_info["status"] == "expired":
# Expired Order
payment.change_status(PaymentStatus.REJECTED)
if payment.status != PaymentStatus.CANCELLED:
payment.change_status(PaymentStatus.REJECTED)

elif session_info["payment_status"] == "paid":
# Paid Order
Expand Down
46 changes: 46 additions & 0 deletions payments/stripe/test_stripev3.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,37 @@ def test_provider_refund_zero_decimal_currency_returns_currency_units():
assert result == 3000


def test_cancel_with_transaction_id():
payment = Payment()
payment.transaction_id = "cs_test_..."
provider = StripeProviderV3(api_key=API_KEY)

with patch("stripe.checkout.Session.expire") as mock_expire:
provider.cancel(payment)
mock_expire.assert_called_once_with("cs_test_...")


def test_cancel_without_transaction_id():
payment = Payment()
payment.transaction_id = None
provider = StripeProviderV3(api_key=API_KEY)

with patch("stripe.checkout.Session.expire") as mock_expire:
provider.cancel(payment)
mock_expire.assert_not_called()


def test_cancel_stripe_error():
payment = Payment()
payment.transaction_id = "cs_test_..."
provider = StripeProviderV3(api_key=API_KEY)

with patch("stripe.checkout.Session.expire") as mock_expire:
mock_expire.side_effect = PaymentError("Stripe error")
with pytest.raises(PaymentError):
provider.cancel(payment)


def _make_webhook_request(event_type, session_status, payment_status):
body = json.dumps(
{
Expand Down Expand Up @@ -316,3 +347,18 @@ def test_process_data_does_not_set_captured_amount_on_expiry():

assert payment.status == PaymentStatus.REJECTED
assert payment.captured_amount == 0


def test_process_data_does_not_overwrite_cancelled_on_expiry():
payment = Payment()
payment.status = PaymentStatus.CANCELLED
provider = StripeProviderV3(api_key=API_KEY, secure_endpoint=False)
request = _make_webhook_request(
event_type="checkout.session.expired",
session_status="expired",
payment_status="unpaid",
)

provider.process_data(payment, request)

assert payment.status == PaymentStatus.CANCELLED
Loading