0003-lingo-handle-empty-payload-in-ReturnView-42581.patch
combo/apps/lingo/views.py | ||
---|---|---|
554 | 554 |
payment = get_eopayment_object(request, payment_backend) |
555 | 555 |
logger = logging.getLogger(__name__) |
556 | 556 |
logger.info(u'received payment response: %r', backend_response) |
557 |
extra_info = kwargs.pop('payment_extra_info', {}) |
|
557 | 558 |
try: |
558 |
payment_response = payment.response(backend_response) |
|
559 |
payment_response = payment.response(backend_response, **extra_info)
|
|
559 | 560 |
except eopayment.PaymentException as e: |
560 | 561 |
logger.error(u'failed to process payment response: %s', e, |
561 | 562 |
extra={'eopayment_raw_response': repr(backend_response)}) |
... | ... | |
678 | 679 |
return super(ReturnView, self).dispatch(*args, **kwargs) |
679 | 680 | |
680 | 681 |
def get(self, request, *args, **kwargs): |
681 |
if not request.environ['QUERY_STRING']: |
|
682 |
return HttpResponseBadRequest('Missing query string') |
|
683 | 682 |
return self.handle_return(request, request.environ['QUERY_STRING'], **kwargs) |
684 | 683 | |
685 | 684 |
def post(self, request, *args, **kwargs): |
686 | 685 |
return self.handle_return(request, force_text(request.body) or request.environ['QUERY_STRING'], **kwargs) |
687 | 686 | |
688 | 687 |
def handle_return(self, request, backend_response, **kwargs): |
688 |
payment_extra_info = {'redirect': True} |
|
689 | ||
689 | 690 |
transaction = None |
690 | 691 |
transaction_id = kwargs.get('transaction_signature') |
691 | 692 |
if transaction_id: |
692 | 693 |
try: |
693 | 694 |
transaction_id = signing_loads(transaction_id) |
694 | 695 |
except signing.BadSignature: |
696 |
transaction_id = None |
|
697 | ||
698 |
if transaction_id: |
|
699 |
# retrieve info about previously known state |
|
700 |
try: |
|
701 |
current_transaction = Transaction.objects.get(pk=transaction_id) |
|
702 |
except Transaction.DoesNotExist: |
|
695 | 703 |
pass |
704 |
else: |
|
705 |
payment_extra_info['order_id_hint'] = current_transaction.order_id |
|
706 |
payment_extra_info['order_status_hint'] = current_transaction.status |
|
707 | ||
696 | 708 |
try: |
697 |
transaction = self.handle_response(request, backend_response, **kwargs) |
|
709 |
transaction = self.handle_response( |
|
710 |
request, backend_response, payment_extra_info=payment_extra_info, **kwargs |
|
711 |
) |
|
698 | 712 |
except UnsignedPaymentException as e: |
699 | 713 |
# some payment backends do not sign return URLs, don't mark this as |
700 | 714 |
# an error, they will provide a notification to the callback |
... | ... | |
702 | 716 |
if transaction_id: |
703 | 717 |
return HttpResponseRedirect(get_payment_status_view(transaction_id)) |
704 | 718 |
return HttpResponseRedirect(get_basket_url()) |
705 | ||
706 | 719 |
except PaymentException as e: |
707 | 720 |
messages.error(request, _('We are sorry but the payment service ' |
708 | 721 |
'failed to provide a correct answer.')) |
tests/test_lingo_payment.py | ||
---|---|---|
766 | 766 |
assert data['amount'] == '11.50' |
767 | 767 | |
768 | 768 | |
769 |
@pytest.mark.parametrize('with_payment_backend', [False, True]) |
|
770 |
def test_payment_return_without_query_string(app, basket_page, regie, user, with_payment_backend): |
|
771 |
page = Page(title='xxx', slug='index', template_name='standard') |
|
772 |
page.save() |
|
773 |
item = BasketItem.objects.create(user=user, regie=regie, |
|
774 |
subject='test_item', amount='10.5', |
|
775 |
source_url='http://example.org/testitem/') |
|
776 |
resp = login(app).get(basket_page.get_online_url()) |
|
777 |
resp = resp.form.submit() |
|
778 |
assert resp.status_code == 302 |
|
779 |
location = resp.location |
|
780 |
parsed = urlparse.urlparse(location) |
|
781 |
qs = urlparse.parse_qs(parsed.query) |
|
782 |
return_url = qs['return_url'][0] |
|
783 |
transaction_id = qs['transaction_id'][0] |
|
784 |
data = {'transaction_id': transaction_id, 'signed': True, |
|
785 |
'amount': qs['amount'][0], 'ok': True} |
|
786 | ||
787 |
# payment status is obtained through callback |
|
788 |
callback_url = get_url(with_payment_backend, 'lingo-callback', regie) |
|
789 |
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as request: |
|
790 |
get_resp = app.get(callback_url, params=data) |
|
791 |
transaction = Transaction.objects.get(order_id=transaction_id) |
|
792 |
assert transaction.status == 3 |
|
793 | ||
794 |
# then return view is called without any data, which should be expected by the backend |
|
795 |
with mock.patch.object(eopayment.dummy.Payment, 'response', autospec=True) as mock_response: |
|
796 |
mock_response.return_value = eopayment.common.PaymentResponse(result=transaction.status, |
|
797 |
order_id=transaction.order_id) |
|
798 |
get_resp = app.get(return_url) |
|
799 |
mock_response.assert_called_once_with( |
|
800 |
mock.ANY, '', redirect=True, order_id_hint=transaction.order_id, |
|
801 |
order_status_hint=transaction.status |
|
802 |
) |
|
803 |
assert get_resp.status_code == 302 |
|
804 |
resp = app.get(get_resp['Location']) |
|
805 |
assert 'Your payment has been succesfully registered.' in resp.text |
|
806 | ||
807 | ||
769 | 808 |
@pytest.mark.parametrize('with_payment_backend', [False, True]) |
770 | 809 |
def test_nonexisting_transaction(app, regie, user, with_payment_backend): |
771 | 810 |
app = login(app) |
772 |
- |