lingo: allow invoices anonymous payment (#12637)
This commit is contained in:
parent
e6aded4460
commit
9779837cb4
|
@ -172,7 +172,10 @@ class Regie(models.Model):
|
|||
item = requests.get(self.signed_url(request, url,
|
||||
NameID=mellon['name_id_content'])).json()
|
||||
return build_remote_item(item.get('data'), self)
|
||||
return {}
|
||||
else:
|
||||
url = self.webservice_url + '/invoice/%s/' % item
|
||||
item = requests.get(self.signed_url(request, url)).json()
|
||||
return build_remote_item(item.get('data'), self)
|
||||
|
||||
def pay_item(self, request, item_id, transaction_id, transaction_date):
|
||||
url = self.webservice_url + '/invoice/%s/pay/' % item_id
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
{% load i18n %}<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% blocktrans %}Invoice number {{ number }}{% endblocktrans %}</title>
|
||||
</head>
|
||||
<body class="invoice_fullpage">
|
||||
|
||||
{% if messages %}
|
||||
<ul class="messages">
|
||||
{% for message in messages %}
|
||||
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
<div class="invoice">
|
||||
{% include 'lingo/combo/item.html' %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -34,8 +34,18 @@
|
|||
{% endif %}
|
||||
{% if item.online_payment and item.amount >= regie.payment_min_amount %}
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="regie" value="{{ regie.pk }}" />
|
||||
<input type="hidden" name="item" value="{{ item.id }}" />
|
||||
{% if not user.is_authenticated %}
|
||||
<div class="email">
|
||||
<label for="email">{% trans 'Email:' %}</label>
|
||||
<input type="email" id="email" name="email" required/>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<input type="hidden" name="regie" value="{{ regie.pk }}"/>
|
||||
<input type="hidden" name="item" value="{{ item.id }}"/>
|
||||
{% if item_url %}
|
||||
<input type="hidden" name="item_url" value="{{ item_url }}"/>
|
||||
{% endif %}
|
||||
<div class="buttons">
|
||||
<button>{% trans "Pay" %}</button>
|
||||
</div>
|
||||
|
|
|
@ -308,8 +308,18 @@ class PayView(View):
|
|||
transaction = Transaction()
|
||||
if request.user.is_authenticated():
|
||||
transaction.user = request.user
|
||||
email = request.user.email
|
||||
firstname = request.user.first_name
|
||||
lastname = request.user.last_name
|
||||
else:
|
||||
transaction.user = None
|
||||
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')
|
||||
firstname = ''
|
||||
lastname = ''
|
||||
|
||||
transaction.save()
|
||||
transaction.regie = regie
|
||||
transaction.items = items
|
||||
|
@ -328,9 +338,10 @@ class PayView(View):
|
|||
return HttpResponseRedirect(next_url)
|
||||
|
||||
payment = get_eopayment_object(request, regie)
|
||||
(order_id, kind, data) = payment.request(total_amount, email=request.user.email,
|
||||
first_name=request.user.first_name,
|
||||
last_name=request.user.last_name)
|
||||
|
||||
(order_id, kind, data) = payment.request(total_amount, email=email,
|
||||
first_name=firstname,
|
||||
last_name=lastname)
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.info(u'emitted payment request with id %s', smart_text(order_id), extra={
|
||||
'eopayment_order_id': smart_text(order_id), 'eopayment_data': repr(data)})
|
||||
|
@ -489,6 +500,8 @@ class ItemDownloadView(View):
|
|||
data = regie.download_item(request, item_id)
|
||||
except PermissionDenied:
|
||||
return HttpResponseForbidden()
|
||||
except DecryptionError as e:
|
||||
return Http404(str(e))
|
||||
|
||||
if data.status_code != 200:
|
||||
logging.error('failed to retrieve invoice (%r)', data.status_code)
|
||||
|
@ -504,21 +517,30 @@ class ItemDownloadView(View):
|
|||
|
||||
class ItemView(TemplateView):
|
||||
http_method_names = [u'get']
|
||||
template_name = 'lingo/combo/item.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ret = {'item_url': self.request.get_full_path()}
|
||||
|
||||
try:
|
||||
regie = Regie.objects.get(pk=kwargs['regie_id'])
|
||||
except Regie.DoesNotExist:
|
||||
raise Http404()
|
||||
|
||||
try:
|
||||
item_id = aes_hex_decrypt(settings.SECRET_KEY, kwargs['item_crypto_id'])
|
||||
except DecryptionError:
|
||||
raise Http404()
|
||||
|
||||
item = regie.get_item(self.request, item_id)
|
||||
if not item:
|
||||
raise Http404(_('No item was found.'))
|
||||
return {'item': item, 'regie': regie}
|
||||
ret.update({'item': item, 'regie': regie})
|
||||
return ret
|
||||
|
||||
def get_template_names(self):
|
||||
if self.request.is_ajax:
|
||||
return ['lingo/combo/item.html']
|
||||
return ['lingo/combo/invoice_fullpage.html']
|
||||
|
||||
|
||||
class CancelItemView(DetailView):
|
||||
|
|
|
@ -6,13 +6,13 @@ from decimal import Decimal
|
|||
from django.contrib.auth.models import User
|
||||
from django.test.client import RequestFactory
|
||||
from django.template import Context
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
|
||||
from combo.utils import check_query
|
||||
from combo.utils import check_query, aes_hex_encrypt
|
||||
from combo.data.models import Page
|
||||
from combo.apps.lingo.models import Regie, BasketItem, Transaction
|
||||
from combo.apps.lingo.models import ActiveItems
|
||||
|
||||
from combo.apps.lingo.models import Regie, ActiveItems
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
@ -100,3 +100,69 @@ def test_remote_regie_cell(mock_get, remote_regie, user):
|
|||
mock_json.json.return_value = {'err': 0, 'data': []}
|
||||
content = cell.render(context)
|
||||
assert 'No items yet' in content
|
||||
|
||||
@mock.patch('combo.apps.lingo.models.Regie.pay_item')
|
||||
@mock.patch('combo.apps.lingo.models.requests.get')
|
||||
def test_anonymous_successful_item_payment(mock_get, mock_pay_item, app, remote_regie):
|
||||
assert remote_regie.is_remote() == True
|
||||
encrypt_id = aes_hex_encrypt(settings.SECRET_KEY, 'F201601')
|
||||
mock_json = mock.Mock()
|
||||
mock_json.json.return_value = {'err': 0, 'data': INVOICES[0]}
|
||||
mock_get.return_value = mock_json
|
||||
mock_pay_item.return_value = mock.Mock(status_code=200)
|
||||
resp = app.get('/lingo/item/%s/%s/' % (remote_regie.id, encrypt_id))
|
||||
form = resp.form
|
||||
|
||||
assert 'email' in form.fields
|
||||
assert form['email'].value == ''
|
||||
assert 'item_url' in form.fields
|
||||
assert form['item_url'].value == '/lingo/item/%s/%s/' % (remote_regie.id, encrypt_id)
|
||||
assert 'item' in form.fields
|
||||
assert form['item'].value == 'F201601'
|
||||
assert 'regie' in form.fields
|
||||
assert form['regie'].value == unicode(remote_regie.pk)
|
||||
|
||||
form['email'] = 'ghost@buster.com'
|
||||
resp = form.submit()
|
||||
|
||||
assert resp.status_code == 302
|
||||
location = resp.location
|
||||
assert 'dummy-payment' in location
|
||||
parsed = urlparse.urlparse(location)
|
||||
# get return_url and transaction id from location
|
||||
qs = urlparse.parse_qs(parsed.query)
|
||||
args = {'transaction_id': qs['transaction_id'][0], 'signed': True,
|
||||
'ok': True, 'reason': 'Paid'}
|
||||
# make sure return url is the user return URL
|
||||
assert urlparse.urlparse(qs['return_url'][0]).path.startswith(
|
||||
reverse('lingo-return', kwargs={'regie_pk': remote_regie.id}))
|
||||
# simulate successful return URL
|
||||
resp = app.get(qs['return_url'][0], args)
|
||||
assert resp.status_code == 302
|
||||
assert urlparse.urlparse(resp.url).path == '/'
|
||||
# simulate successful call to callback URL
|
||||
resp = app.get(reverse('lingo-callback', kwargs={'regie_pk': remote_regie.id}), args)
|
||||
assert resp.status_code == 200
|
||||
|
||||
@mock.patch('combo.apps.lingo.models.requests.get')
|
||||
def test_anonymous_item_payment_email_error(mock_get, app, remote_regie):
|
||||
assert remote_regie.is_remote() == True
|
||||
encrypt_id = aes_hex_encrypt(settings.SECRET_KEY, 'F201601')
|
||||
mock_json = mock.Mock()
|
||||
mock_json.json.return_value = {'err': 0, 'data': INVOICES[0]}
|
||||
mock_get.return_value = mock_json
|
||||
resp = app.get('/lingo/item/%s/%s/' % (remote_regie.id, encrypt_id))
|
||||
form = resp.form
|
||||
resp = form.submit()
|
||||
|
||||
assert resp.status_code == 302
|
||||
path = urlparse.urlparse(resp.location).path
|
||||
assert path == '/lingo/item/%s/%s/' % (remote_regie.id, encrypt_id)
|
||||
|
||||
@mock.patch('combo.apps.lingo.models.requests.get')
|
||||
def test_wrong_crypted_item(mock_get, remote_regie, app):
|
||||
assert remote_regie.is_remote() == True
|
||||
mock_json = mock.Mock()
|
||||
mock_json.json.return_value = {'err': 0, 'data': INVOICES[0]}
|
||||
mock_get.return_value = mock_json
|
||||
resp = app.get('/lingo/item/%s/%s/' % (remote_regie.id, 'zrzer854sfaear45e6rzerzerzef'), status=404)
|
||||
|
|
Loading…
Reference in New Issue