diff --git a/payments/paypal/__init__.py b/payments/paypal/__init__.py index 58caac6b4..35f9ee4f7 100644 --- a/payments/paypal/__init__.py +++ b/payments/paypal/__init__.py @@ -413,15 +413,16 @@ def release(self, payment): self.post(payment, url) def refund(self, payment, amount=None): - if amount is None: - amount = payment.captured_amount - amount_data = self.get_amount_data(payment, amount) - refund_data = {"amount": amount_data} + refund_data = {} + if amount is not None: + refund_data["amount"] = self.get_amount_data(payment, amount) links = self._get_links(payment) url = links["refund"]["href"] - self.post(payment, url, data=refund_data) + response = self.post(payment, url, data=refund_data) payment.change_status(PaymentStatus.REFUNDED) - return amount + if response["amount"]["currency"] != payment.currency: + raise NotImplementedError(f"refund's currency other than {payment.currency} not supported yet: {response['amount']['currency']}") + return Decimal(response["amount"]["total"]) class PaypalCardProvider(PaypalProvider): diff --git a/payments/paypal/test_paypal.py b/payments/paypal/test_paypal.py index 312083218..c0a7710b1 100644 --- a/payments/paypal/test_paypal.py +++ b/payments/paypal/test_paypal.py @@ -126,17 +126,39 @@ def test_provider_handles_captured_payment(self, mocked_post): self.assertEqual(self.payment.status, PaymentStatus.CONFIRMED) @patch("requests.post") - def test_provider_refunds_payment(self, mocked_post): + def test_provider_refunds_payment_fully(self, mocked_post): data = MagicMock() - data.return_value = { - "token_type": "test_token_type", - "access_token": "test_access_token", - } + data.side_effect = [ + { + "token_type": "test_token_type", + "access_token": "test_access_token", + }, + {"amount": {"total": "220.00", "currency": "USD"}}, + ] post = MagicMock() post.json = data post.status_code = 200 mocked_post.return_value = post self.provider.refund(self.payment) + mocked_post.assert_called_with("http://refund.com", headers={"Content-Type": "application/json", "Authorization": "test_token_type test_access_token"}, data="{}") + self.assertEqual(self.payment.status, PaymentStatus.REFUNDED) + + @patch("requests.post") + def test_provider_refunds_payment_partially(self, mocked_post): + data = MagicMock() + data.side_effect = [ + { + "token_type": "test_token_type", + "access_token": "test_access_token", + }, + {"amount": {"total": "1.00", "currency": "USD"}}, + ] + post = MagicMock() + post.json = data + post.status_code = 200 + mocked_post.return_value = post + self.provider.refund(self.payment, amount=Decimal(1)) + mocked_post.assert_called_with("http://refund.com", headers={"Content-Type": "application/json", "Authorization": "test_token_type test_access_token"}, data='{"amount": {"currency": "USD", "total": "1.00"}}') self.assertEqual(self.payment.status, PaymentStatus.REFUNDED) @patch("requests.post")