lingo: move email extraction to payment views (#47513)
There is too much non-linear logic around emails in handle_payment(), it's better to locate this logic in the calling views where situations are more constrained.
This commit is contained in:
parent
4b88540880
commit
902a52278e
|
@ -382,7 +382,6 @@ class PayMixin(object):
|
|||
transaction = Transaction()
|
||||
if user:
|
||||
transaction.user = user
|
||||
email = user.email
|
||||
firstname = user.first_name
|
||||
lastname = user.last_name
|
||||
else:
|
||||
|
@ -407,8 +406,7 @@ class PayMixin(object):
|
|||
'amount': item.amount,
|
||||
'reference_id': item.reference_id,
|
||||
})
|
||||
if not email and item.email:
|
||||
kwargs['email'] = item.email
|
||||
|
||||
if items:
|
||||
capture_date = items[0].capture_date
|
||||
if capture_date:
|
||||
|
@ -504,10 +502,15 @@ class PayView(PayMixin, View):
|
|||
_(u'Invalid grouping for basket items: different capture dates.'))
|
||||
return HttpResponseRedirect(next_url)
|
||||
|
||||
if not user and not request.POST.get('email'):
|
||||
messages.warning(request, _(u'You must give an email address.'))
|
||||
return HttpResponseRedirect(request.POST.get('item_url'))
|
||||
email = request.POST.get('email')
|
||||
if user:
|
||||
email = user.email
|
||||
else:
|
||||
# user is not authenticated, it comes from ItemCell where an email
|
||||
# can be given in the payment form.
|
||||
if not request.POST.get('email'):
|
||||
messages.warning(request, _(u'You must give an email address.'))
|
||||
return HttpResponseRedirect(request.POST.get('item_url'))
|
||||
email = request.POST.get('email')
|
||||
|
||||
# XXX: mark basket items as being processed (?)
|
||||
return self.handle_payment(request, regie, items, remote_items, next_url, email)
|
||||
|
@ -527,7 +530,6 @@ class BasketItemPayView(PayMixin, View):
|
|||
|
||||
def get(self, request, *args, **kwargs):
|
||||
next_url = request.GET.get('next_url')
|
||||
email = request.GET.get('email', '')
|
||||
firstname = request.GET.get('firstname', '')
|
||||
lastname = request.GET.get('lastname', '')
|
||||
|
||||
|
@ -542,6 +544,16 @@ class BasketItemPayView(PayMixin, View):
|
|||
if regie.extra_fees_ws_url:
|
||||
return HttpResponseForbidden(_('No item payment allowed as extra fees set.'))
|
||||
|
||||
# Get an email from request or the item
|
||||
if request.user.is_authenticated:
|
||||
email = request.user.email
|
||||
elif request.GET.get('email'):
|
||||
email = request.GET.get('email', '')
|
||||
elif item.user and item.user.email:
|
||||
email = item.user.email
|
||||
else:
|
||||
email = item.email
|
||||
|
||||
if not next_url:
|
||||
next_url = item.source_url
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ from mellon.models import UserSAMLIdentifier
|
|||
|
||||
from django.apps import apps
|
||||
from django.contrib.auth.models import User
|
||||
from django.http.request import QueryDict
|
||||
from django.urls import reverse
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
from django.conf import settings
|
||||
|
@ -30,6 +31,8 @@ from combo.apps.lingo.models import (
|
|||
from combo.utils import aes_hex_decrypt, sign_url
|
||||
from combo.apps.lingo.views import signing_loads, signing_dumps
|
||||
|
||||
import httmock
|
||||
|
||||
from .test_manager import login
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
@ -1648,3 +1651,203 @@ def test_payfip_ws_kwargs_can_pay_only_one_basket_item(payment_request, app, bas
|
|||
assert resp.location == 'https://payfip/'
|
||||
assert payment_request.call_args[1]['refdet'] == 'F20201030'
|
||||
assert payment_request.call_args[1]['exer'] == '2020'
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def remote_invoices_httmock():
|
||||
invoices = []
|
||||
invoice = {}
|
||||
|
||||
netloc = 'remote.regie.example.com'
|
||||
|
||||
@httmock.urlmatch(netloc=netloc, path='^/invoice/')
|
||||
def invoice_mock(url, request):
|
||||
return json.dumps({'err': 0, 'data': invoice})
|
||||
|
||||
@httmock.urlmatch(netloc=netloc, path='^/invoices/')
|
||||
def invoices_mock(url, request):
|
||||
return json.dumps({'err': 0, 'data': invoices})
|
||||
|
||||
context_manager = httmock.HTTMock(invoices_mock, invoice_mock)
|
||||
context_manager.url = 'https://%s/' % netloc
|
||||
context_manager.invoices = invoices
|
||||
context_manager.invoice = invoice
|
||||
return context_manager
|
||||
|
||||
|
||||
def test_email_from_basket(app, regie, remote_invoices_httmock):
|
||||
def parse_qs(url):
|
||||
return QueryDict(urlparse.urlparse(url).query)
|
||||
|
||||
user1 = User.objects.create(username='user1', email='user1@example.com')
|
||||
user2 = User.objects.create(username='user2', email='user2@example.com')
|
||||
|
||||
item1 = BasketItem.objects.create(user=user1, regie=regie, amount=42, subject='foo item')
|
||||
item12 = BasketItem.objects.create(user=user1, regie=regie, amount=42, subject='bar item')
|
||||
item2 = BasketItem.objects.create(user=user2, regie=regie, amount=42, subject='foo item')
|
||||
item3 = BasketItem.objects.create(regie=regie, amount=42, subject='foo item', email='no-user@example.com')
|
||||
item4 = BasketItem.objects.create(regie=regie, amount=42, subject='foo item')
|
||||
|
||||
# **Behaviours of BasketItemPayView**
|
||||
# not authenticated, email is from the basket item
|
||||
response = app.get(item1.payment_url)
|
||||
qs = parse_qs(response.location)
|
||||
assert qs['email'] == user1.email
|
||||
|
||||
response = app.get(item12.payment_url)
|
||||
qs = parse_qs(response.location)
|
||||
assert qs['email'] == user1.email
|
||||
|
||||
response = app.get(item2.payment_url)
|
||||
qs = parse_qs(response.location)
|
||||
assert qs['email'] == user2.email
|
||||
|
||||
response = app.get(item3.payment_url)
|
||||
qs = parse_qs(response.location)
|
||||
assert qs['email'] == 'no-user@example.com'
|
||||
|
||||
# FIXME: if required, there should be an email requested (PayFiP, Paybox, etc..)
|
||||
response = app.get(item4.payment_url)
|
||||
qs = parse_qs(response.location)
|
||||
assert 'email' not in qs
|
||||
|
||||
# not authenticated, email in the query-string is ALWAYS used
|
||||
response = app.get(item1.payment_url + '?email=user3@example.com')
|
||||
qs = parse_qs(response.location)
|
||||
assert qs['email'] == 'user3@example.com'
|
||||
|
||||
response = app.get(item12.payment_url + '?email=user3@example.com')
|
||||
qs = parse_qs(response.location)
|
||||
assert qs['email'] == 'user3@example.com'
|
||||
|
||||
response = app.get(item2.payment_url + '?email=user3@example.com')
|
||||
qs = parse_qs(response.location)
|
||||
assert qs['email'] == 'user3@example.com'
|
||||
|
||||
response = app.get(item3.payment_url + '?email=user3@example.com')
|
||||
qs = parse_qs(response.location)
|
||||
assert qs['email'] == 'user3@example.com'
|
||||
|
||||
response = app.get(item4.payment_url + '?email=user3@example.com')
|
||||
qs = parse_qs(response.location)
|
||||
assert qs['email'] == 'user3@example.com'
|
||||
|
||||
# authenticated, the email from the authenticated user is ALWAYS used, event
|
||||
# if another email is given in the URL.
|
||||
app.set_user(user1)
|
||||
response = app.get(item1.payment_url + '?email=user3@example.com')
|
||||
qs = parse_qs(response.location)
|
||||
assert qs['email'] == user1.email
|
||||
|
||||
response = app.get(item12.payment_url + '?email=user3@example.com')
|
||||
qs = parse_qs(response.location)
|
||||
assert qs['email'] == user1.email
|
||||
|
||||
response = app.get(item2.payment_url + '?email=user3@example.com')
|
||||
qs = parse_qs(response.location)
|
||||
assert qs['email'] == user1.email
|
||||
|
||||
response = app.get(item3.payment_url + '?email=user3@example.com')
|
||||
qs = parse_qs(response.location)
|
||||
assert qs['email'] == user1.email
|
||||
|
||||
response = app.get(item4.payment_url + '?email=user3@example.com')
|
||||
qs = parse_qs(response.location)
|
||||
assert qs['email'] == user1.email
|
||||
|
||||
# **Behaviours of PayView**
|
||||
# Logout
|
||||
app.set_user()
|
||||
app.session.flush()
|
||||
|
||||
# email is mandatory for paying a remote invoice without being authenticated
|
||||
response = app.get('/')
|
||||
csrf_token = response.context['csrf_token']
|
||||
response = app.post('/lingo/pay', params={
|
||||
'regie': regie.id,
|
||||
'csrfmiddlewaretoken': csrf_token,
|
||||
'item': ['1'],
|
||||
'item_url': '/item-url/',
|
||||
})
|
||||
assert response.location == '/'
|
||||
assert 'Payment requires to be logged in.' in app.session['_messages']
|
||||
|
||||
app.set_user(user1)
|
||||
response = app.get('/')
|
||||
csrf_token = response.context['csrf_token']
|
||||
|
||||
# Paying the basket always use the logged user email
|
||||
response = app.post('/lingo/pay', params={
|
||||
'regie': regie.id,
|
||||
'csrfmiddlewaretoken': csrf_token,
|
||||
'item': ['1'],
|
||||
'item_url': '/item-url/',
|
||||
'email': 'no-user@example.com'
|
||||
})
|
||||
assert response.location.startswith('http://dummy-payment.demo.entrouvert.com/')
|
||||
qs = parse_qs(response.location)
|
||||
assert qs['email'] == 'user1@example.com'
|
||||
|
||||
# Now try with a remote regie
|
||||
regie.webservice_url = remote_invoices_httmock.url
|
||||
regie.save()
|
||||
|
||||
# Logout
|
||||
app.set_user()
|
||||
app.session.flush()
|
||||
|
||||
# Get a response to extract csrf_token
|
||||
response = app.get('/')
|
||||
csrf_token = response.context['csrf_token']
|
||||
with remote_invoices_httmock:
|
||||
remote_invoices_httmock.invoice.update({
|
||||
'id': 'F201601',
|
||||
'display_id': 'F-2016-One',
|
||||
'label': 'invoice-one',
|
||||
'regie': 'remote',
|
||||
'created': '2016-02-02',
|
||||
'pay_limit_date': '2999-12-31',
|
||||
'total_amount': '123.45',
|
||||
'amount': '123.45',
|
||||
'has_pdf': True,
|
||||
'online_payment': True,
|
||||
'paid': False,
|
||||
'payment_date': '1970-01-01',
|
||||
'no_online_payment_reason': '',
|
||||
})
|
||||
|
||||
# email is mandatory for paying a remote invoice without being authenticated
|
||||
response = app.post('/lingo/pay', params={
|
||||
'regie': regie.id,
|
||||
'csrfmiddlewaretoken': csrf_token,
|
||||
'item': ['1'],
|
||||
'item_url': '/item-url/',
|
||||
})
|
||||
assert response.location == '/item-url/'
|
||||
assert 'You must give an email address.' in app.session['_messages']
|
||||
response = app.post('/lingo/pay', params={
|
||||
'regie': regie.id,
|
||||
'csrfmiddlewaretoken': csrf_token,
|
||||
'item': ['1'],
|
||||
'item_url': '/item-url/',
|
||||
'email': 'no-user@example.com',
|
||||
})
|
||||
assert response.location.startswith('http://dummy-payment.demo.entrouvert.com/')
|
||||
qs = parse_qs(response.location)
|
||||
assert qs['email'] == 'no-user@example.com'
|
||||
|
||||
app.set_user(user1)
|
||||
response = app.get('/')
|
||||
csrf_token = response.context['csrf_token']
|
||||
|
||||
# authenticated, always use the authenticated user's email
|
||||
response = app.post('/lingo/pay', params={
|
||||
'regie': regie.id,
|
||||
'csrfmiddlewaretoken': csrf_token,
|
||||
'item': ['1'],
|
||||
'item_url': '/item-url/',
|
||||
'email': 'no-user@example.com',
|
||||
})
|
||||
assert response.location.startswith('http://dummy-payment.demo.entrouvert.com/')
|
||||
qs = parse_qs(response.location)
|
||||
assert qs['email'] == 'user1@example.com'
|
||||
|
|
Loading…
Reference in New Issue