Commit db3cfb2d by Bill DeRusha

Catch valid use case exceptions and log info message

parent d4cb4fc8
...@@ -6,7 +6,7 @@ from factory.django import mute_signals ...@@ -6,7 +6,7 @@ from factory.django import mute_signals
import httpretty import httpretty
import mock import mock
from oscar.apps.order.exceptions import UnableToPlaceOrder from oscar.apps.order.exceptions import UnableToPlaceOrder
from oscar.apps.payment.exceptions import PaymentError from oscar.apps.payment.exceptions import PaymentError, UserCancelled, TransactionDeclined
from oscar.core.loading import get_class, get_model from oscar.core.loading import get_class, get_model
from oscar.test import factories from oscar.test import factories
from oscar.test.contextmanagers import mock_signal_receiver from oscar.test.contextmanagers import mock_signal_receiver
...@@ -63,7 +63,7 @@ class CybersourceNotifyViewTests(CybersourceMixin, PaymentEventsMixin, TestCase) ...@@ -63,7 +63,7 @@ class CybersourceNotifyViewTests(CybersourceMixin, PaymentEventsMixin, TestCase)
paid_type = PaymentEventType.objects.get(code='paid') paid_type = PaymentEventType.objects.get(code='paid')
self.assert_payment_event_exists(self.basket, paid_type, reference, self.processor_name) self.assert_payment_event_exists(self.basket, paid_type, reference, self.processor_name)
def _assert_processing_failure(self, notification, status_code, error_message): def _assert_processing_failure(self, notification, status_code, error_message, log_level='ERROR'):
"""Verify that payment processing operations fail gracefully.""" """Verify that payment processing operations fail gracefully."""
logger_name = 'ecommerce.extensions.payment.views' logger_name = 'ecommerce.extensions.payment.views'
with LogCapture(logger_name) as l: with LogCapture(logger_name) as l:
...@@ -88,7 +88,7 @@ class CybersourceNotifyViewTests(CybersourceMixin, PaymentEventsMixin, TestCase) ...@@ -88,7 +88,7 @@ class CybersourceNotifyViewTests(CybersourceMixin, PaymentEventsMixin, TestCase)
basket_id=self.basket.id basket_id=self.basket.id
) )
), ),
(logger_name, 'ERROR', error_message) (logger_name, log_level, error_message)
) )
# Disable the normal signal receivers so that we can verify the state of the created order. # Disable the normal signal receivers so that we can verify the state of the created order.
...@@ -158,7 +158,18 @@ class CybersourceNotifyViewTests(CybersourceMixin, PaymentEventsMixin, TestCase) ...@@ -158,7 +158,18 @@ class CybersourceNotifyViewTests(CybersourceMixin, PaymentEventsMixin, TestCase)
self.assert_processor_response_recorded(self.processor_name, notification[u'transaction_id'], notification, self.assert_processor_response_recorded(self.processor_name, notification[u'transaction_id'], notification,
basket=self.basket) basket=self.basket)
def test_payment_handling_error(self): @ddt.data(
(PaymentError, 200, 'ERROR', 'CyberSource payment failed for basket [{basket_id}]. '
'The payment response was recorded in entry [{response_id}].'),
(UserCancelled, 200, 'INFO', 'CyberSource payment did not complete for basket [{basket_id}] because '
'[UserCancelled]. The payment response was recorded in entry [{response_id}].'),
(TransactionDeclined, 200, 'INFO', 'CyberSource payment did not complete for basket [{basket_id}] because '
'[TransactionDeclined]. The payment response was recorded in entry '
'[{response_id}].'),
(KeyError, 500, 'ERROR', 'Attempts to handle payment for basket [{basket_id}] failed.')
)
@ddt.unpack
def test_payment_handling_error(self, error_class, status_code, log_level, error_message):
""" """
Verify that CyberSource's merchant notification is saved to the database despite an error handling payment. Verify that CyberSource's merchant notification is saved to the database despite an error handling payment.
""" """
...@@ -167,21 +178,17 @@ class CybersourceNotifyViewTests(CybersourceMixin, PaymentEventsMixin, TestCase) ...@@ -167,21 +178,17 @@ class CybersourceNotifyViewTests(CybersourceMixin, PaymentEventsMixin, TestCase)
self.basket, self.basket,
billing_address=self.billing_address, billing_address=self.billing_address,
) )
with mock.patch.object(
with mock.patch.object(CybersourceNotifyView, 'handle_payment', CybersourceNotifyView,
side_effect=PaymentError) as fake_handle_payment: 'handle_payment',
error_message = 'CyberSource payment failed for basket [{basket_id}]. ' \ side_effect=error_class
'The payment response was recorded in entry [{response_id}].'.\ ) as fake_handle_payment:
format(basket_id=self.basket.id, response_id=1) self._assert_processing_failure(
self._assert_processing_failure(notification, 200, error_message) notification,
self.assertTrue(fake_handle_payment.called) status_code,
error_message.format(basket_id=self.basket.id, response_id=1),
with mock.patch.object(CybersourceNotifyView, 'handle_payment', log_level
side_effect=KeyError) as fake_handle_payment:
error_message = 'Attempts to handle payment for basket [{basket_id}] failed.'.format(
basket_id=self.basket.id
) )
self._assert_processing_failure(notification, 500, error_message)
self.assertTrue(fake_handle_payment.called) self.assertTrue(fake_handle_payment.called)
def test_unable_to_place_order(self): def test_unable_to_place_order(self):
......
...@@ -12,7 +12,7 @@ from django.utils.decorators import method_decorator ...@@ -12,7 +12,7 @@ from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.views.generic import View from django.views.generic import View
from oscar.apps.partner import strategy from oscar.apps.partner import strategy
from oscar.apps.payment.exceptions import PaymentError from oscar.apps.payment.exceptions import PaymentError, UserCancelled, TransactionDeclined
from oscar.core.loading import get_class, get_model from oscar.core.loading import get_class, get_model
from ecommerce.extensions.checkout.mixins import EdxOrderPlacementMixin from ecommerce.extensions.checkout.mixins import EdxOrderPlacementMixin
...@@ -112,6 +112,15 @@ class CybersourceNotifyView(EdxOrderPlacementMixin, View): ...@@ -112,6 +112,15 @@ class CybersourceNotifyView(EdxOrderPlacementMixin, View):
ppr.id ppr.id
) )
return HttpResponse(status=400) return HttpResponse(status=400)
except (UserCancelled, TransactionDeclined) as exception:
logger.info(
'CyberSource payment did not complete for basket [%d] because [%s]. '
'The payment response was recorded in entry [%d].',
basket.id,
exception.__class__.__name__,
ppr.id
)
return HttpResponse()
except PaymentError: except PaymentError:
logger.exception( logger.exception(
'CyberSource payment failed for basket [%d]. The payment response was recorded in entry [%d].', 'CyberSource payment failed for basket [%d]. The payment response was recorded in entry [%d].',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment