From 770d5888f4859a5548a1abdfe58d3759fe794b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20Hol=C3=BD?= Date: Thu, 2 May 2024 16:11:09 +0200 Subject: [PATCH 1/2] fix multiple deduction of the refund amount from payment.captured_amount --- HISTORY.rst | 4 ++++ payments_payu/provider.py | 15 +++++++++++++-- tests/test_payu.py | 16 ++++++++-------- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index f406589..57b4ebe 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -3,6 +3,10 @@ History ------- +Unreleased +********** +* fix multiple deduction of the refund amount from `payment.captured_amount` + 1.4.0 (2024-04-12) ****************** * fix backward compatibility by making PayuProvider's get_refund_description argument optional diff --git a/payments_payu/provider.py b/payments_payu/provider.py index d2a3f9b..05f1f81 100644 --- a/payments_payu/provider.py +++ b/payments_payu/provider.py @@ -689,7 +689,11 @@ def refund(self, payment, amount=None): ) if refund_status == "CANCELED": raise ValueError(f"refund {refund_id} of payment {payment.id} canceled") - elif refund_status not in {"PENDING", "FINALIZED"}: + elif refund_status == "FINALIZED": + raise NotImplementedError( + f"refund {refund_id} of payment {payment.id} being FINALIZED already is not supported yet" + ) + elif refund_status not in {"PENDING"}: raise PayuApiError( f"invalid status of refund {refund_id} of payment {payment.id}" ) @@ -698,7 +702,14 @@ def refund(self, payment, amount=None): f"refund {refund_id} of payment {payment.id} in different currency not supported yet: " f"{refund_currency}" ) - return refund_amount + if amount is not None and refund_amount != amount: + raise NotImplementedError( + f"refund {refund_id} of payment {payment.id} having a different amount than requested not supported " + f"yet: {refund_amount}" + ) + # Return 0 in order not to change captured_amount yet. If we returned the amount, captured_amount would change + # twice (now and once we get a notification from PayU). + return Decimal(0) class PaymentProcessor(object): diff --git a/tests/test_payu.py b/tests/test_payu.py index d291b6c..86e5c28 100644 --- a/tests/test_payu.py +++ b/tests/test_payu.py @@ -1207,7 +1207,7 @@ def test_refund(self): "refund_responses" ] self.assertEqual(refund_request_mock.call_count, 1) - self.assertEqual(amount, Decimal(110)) + self.assertEqual(amount, Decimal(0)) self.assertEqual(self.payment.total, Decimal(220)) self.assertEqual(self.payment.captured_amount, Decimal(210)) self.assertEqual(self.payment.status, PaymentStatus.CONFIRMED) @@ -1265,7 +1265,7 @@ def test_refund_no_amount(self): "refund_responses" ] self.assertEqual(refund_request_mock.call_count, 1) - self.assertEqual(amount, Decimal(220)) + self.assertEqual(amount, Decimal(0)) self.assertEqual(self.payment.total, Decimal(220)) self.assertEqual(self.payment.captured_amount, Decimal(220)) self.assertEqual(self.payment.status, PaymentStatus.CONFIRMED) @@ -1324,7 +1324,7 @@ def test_refund_no_get_refund_ext_id(self): "refund_responses" ] self.assertEqual(refund_request_mock.call_count, 1) - self.assertEqual(amount, Decimal(110)) + self.assertEqual(amount, Decimal(0)) self.assertEqual(self.payment.total, Decimal(220)) self.assertEqual(self.payment.captured_amount, Decimal(220)) self.assertEqual(self.payment.status, PaymentStatus.CONFIRMED) @@ -1380,7 +1380,7 @@ def test_refund_no_ext_id(self): "refund_responses" ] self.assertEqual(refund_request_mock.call_count, 1) - self.assertEqual(amount, Decimal(110)) + self.assertEqual(amount, Decimal(0)) self.assertEqual(self.payment.total, Decimal(220)) self.assertEqual(self.payment.captured_amount, Decimal(220)) self.assertEqual(self.payment.status, PaymentStatus.CONFIRMED) @@ -1438,7 +1438,7 @@ def test_refund_no_ext_id_twice(self): ] self.assertEqual(refund_request_mock.call_count, 2) self.assertEqual(amount2, amount1) - self.assertEqual(amount2, Decimal(200)) + self.assertEqual(amount2, Decimal(0)) self.assertEqual(self.payment.total, Decimal(220)) self.assertEqual(self.payment.captured_amount, Decimal(220)) self.assertEqual(self.payment.status, PaymentStatus.CONFIRMED) @@ -1448,7 +1448,7 @@ def test_refund_no_ext_id_twice(self): ) self.assertFalse(caught_warnings) - def test_refund_finalized(self): + def test_refund_pending(self): with warnings.catch_warnings(record=True) as caught_warnings: warnings.simplefilter("always") self.set_up_provider( @@ -1470,7 +1470,7 @@ def test_refund_finalized(self): "currencyCode": "USD", "description": "desc 1234 110", "creationDateTime": "2020-07-02T09:19:03.896+02:00", - "status": "FINALIZED", + "status": "PENDING", "statusDateTime": "2020-07-02T09:19:04.013+02:00", }, "status": { @@ -1496,7 +1496,7 @@ def test_refund_finalized(self): "refund_responses" ] self.assertEqual(refund_request_mock.call_count, 1) - self.assertEqual(amount, Decimal(110)) + self.assertEqual(amount, Decimal(0)) self.assertEqual(self.payment.total, Decimal(220)) self.assertEqual(self.payment.captured_amount, Decimal(220)) self.assertEqual(self.payment.status, PaymentStatus.CONFIRMED) From a7a1e60a3bec53a453309bd26e3592e628513c3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20Hol=C3=BD?= Date: Thu, 2 May 2024 16:31:31 +0200 Subject: [PATCH 2/2] change statuses of payments refunded with an amount greater than captured_amount to REFUNDED instead of just deducing captured_amount --- HISTORY.rst | 1 + payments_payu/provider.py | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index 57b4ebe..91eb209 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -6,6 +6,7 @@ History Unreleased ********** * fix multiple deduction of the refund amount from `payment.captured_amount` +* change statuses of payments refunded with an amount greater than `payment.captured_amount` to `REFUNDED` instead of just deducing `captured_amount` 1.4.0 (2024-04-12) ****************** diff --git a/payments_payu/provider.py b/payments_payu/provider.py index 05f1f81..912628d 100644 --- a/payments_payu/provider.py +++ b/payments_payu/provider.py @@ -564,7 +564,16 @@ def process_notification(self, payment, request): print(refunded_price, payment.total) if data["refund"]["status"] == "FINALIZED": payment.message += data["refund"]["reasonDescription"] - if refunded_price == payment.captured_amount: + if refunded_price >= payment.captured_amount: + if refunded_price > payment.captured_amount: + logger.error( + "refund %s of payment %s has amount greater than the payment's captured_amount: " + "%f > %f", + data["refund"].get("refundId", "???"), + payment.id, + refunded_price, + payment.captured_amount, + ) payment.change_status(PaymentStatus.REFUNDED) else: payment.captured_amount -= refunded_price