Skip to content

Commit 543a98e

Browse files
committed
Fix not refunding the total amount by default
Fixes #401
1 parent cdb7281 commit 543a98e

File tree

3 files changed

+30
-18
lines changed

3 files changed

+30
-18
lines changed

CHANGELOG.rst

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ v3.0.0
1414
- Stripe backends now supports webhooks
1515
- New :ref:`webhook settings <webhooks>`
1616
- Fixed PayPal backends not saving captured_amount when processing data.
17+
- Fixed ``base_payment.refund()`` not making any refund
1718

1819
v2.0.0
1920
------

payments/models.py

+20-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import json
4+
import logging
45
from typing import Iterable
56
from uuid import uuid4
67

@@ -14,6 +15,8 @@
1415
from . import PurchasedItem
1516
from .core import provider_factory
1617

18+
logger = logging.getLogger(__name__)
19+
1720

1821
class PaymentAttributeProxy:
1922
def __init__(self, payment):
@@ -212,15 +215,23 @@ def release(self):
212215
def refund(self, amount=None):
213216
if self.status != PaymentStatus.CONFIRMED:
214217
raise ValueError("Only charged payments can be refunded.")
215-
if amount:
216-
if amount > self.captured_amount:
217-
raise ValueError(
218-
"Refund amount can not be greater then captured amount"
219-
)
220-
provider = provider_factory(self.variant, self)
221-
amount = provider.refund(self, amount)
222-
self.captured_amount -= amount
223-
if self.captured_amount == 0 and self.status != PaymentStatus.REFUNDED:
218+
if amount and amount > self.captured_amount:
219+
raise ValueError("Refund amount can not be greater then captured amount")
220+
provider = provider_factory(self.variant, self)
221+
amount = provider.refund(self, amount)
222+
# If the initial amount is None, the code above has no chance to check whether
223+
# the actual amount is greater than the captured amount before actually
224+
# performing the refund. But since the refund has been performed already,
225+
# raising an exception would just cause inconsistencies. Thus, logging an error.
226+
if amount > self.captured_amount:
227+
logger.error(
228+
"Refund amount of payment %s greater than captured amount: %f > %f",
229+
self.id,
230+
amount,
231+
self.captured_amount,
232+
)
233+
self.captured_amount -= amount
234+
if self.captured_amount <= 0 and self.status != PaymentStatus.REFUNDED:
224235
self.change_status(PaymentStatus.REFUNDED)
225236
self.save()
226237

payments/test_core.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -113,20 +113,20 @@ def test_refund_too_high_amount(self):
113113

114114
@patch("payments.dummy.DummyProvider.refund")
115115
def test_refund_without_amount(self, mocked_refund_method):
116-
refund_amount = None
116+
captured_amount = Decimal("200")
117117
with patch.object(BasePayment, "save") as mocked_save_method:
118118
mocked_save_method.return_value = None
119-
mocked_refund_method.return_value = refund_amount
119+
mocked_refund_method.return_value = captured_amount
120120

121-
captured_amount = Decimal("200")
122-
status = PaymentStatus.CONFIRMED
123121
payment = Payment(
124-
variant="default", status=status, captured_amount=captured_amount
122+
variant="default",
123+
status=PaymentStatus.CONFIRMED,
124+
captured_amount=captured_amount,
125125
)
126-
payment.refund(refund_amount)
127-
self.assertEqual(payment.status, status)
128-
self.assertEqual(payment.captured_amount, captured_amount)
129-
self.assertEqual(mocked_refund_method.call_count, 0)
126+
payment.refund()
127+
self.assertEqual(payment.status, PaymentStatus.REFUNDED)
128+
self.assertEqual(payment.captured_amount, Decimal(0))
129+
self.assertEqual(mocked_refund_method.call_count, 1)
130130

131131
@patch("payments.dummy.DummyProvider.refund")
132132
def test_refund_partial_success(self, mocked_refund_method):

0 commit comments

Comments
 (0)