From 15842b370d320abf9eed3c17e0ec0db780ea46d1 Mon Sep 17 00:00:00 2001 From: Emmanuel Cazenave Date: Fri, 5 Oct 2018 18:36:45 +0200 Subject: [PATCH] lingo: allow arbitrary date for deferred payment (#27045) --- .../0032_basketitem_capture_date.py | 20 +++++++ combo/apps/lingo/models.py | 1 + combo/apps/lingo/views.py | 24 ++++++-- tests/test_lingo_payment.py | 55 +++++++++++++++++++ 4 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 combo/apps/lingo/migrations/0032_basketitem_capture_date.py diff --git a/combo/apps/lingo/migrations/0032_basketitem_capture_date.py b/combo/apps/lingo/migrations/0032_basketitem_capture_date.py new file mode 100644 index 0000000..285f8f7 --- /dev/null +++ b/combo/apps/lingo/migrations/0032_basketitem_capture_date.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.15 on 2018-10-05 15:33 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('lingo', '0031_basketitem_waiting_date'), + ] + + operations = [ + migrations.AddField( + model_name='basketitem', + name='capture_date', + field=models.DateField(null=True), + ), + ] diff --git a/combo/apps/lingo/models.py b/combo/apps/lingo/models.py index f93bf06..5cdf143 100644 --- a/combo/apps/lingo/models.py +++ b/combo/apps/lingo/models.py @@ -327,6 +327,7 @@ class BasketItem(models.Model): waiting_date = models.DateTimeField(null=True) payment_date = models.DateTimeField(null=True) notification_date = models.DateTimeField(null=True) + capture_date = models.DateField(null=True) class Meta: ordering = ['regie', 'extra_fee', 'subject'] diff --git a/combo/apps/lingo/views.py b/combo/apps/lingo/views.py index 7c4492a..0f7fafd 100644 --- a/combo/apps/lingo/views.py +++ b/combo/apps/lingo/views.py @@ -26,7 +26,7 @@ from django.core.urlresolvers import reverse from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest from django.http import HttpResponseForbidden, Http404, JsonResponse from django.template.response import TemplateResponse -from django.utils import timezone +from django.utils import timezone, dateparse from django.utils.encoding import force_text from django.views.decorators.csrf import csrf_exempt from django.views.generic import View, DetailView, ListView, TemplateView @@ -160,6 +160,9 @@ class AddBasketItemApiView(View): item.subject = request_body.get('display_name') item.source_url = request_body.get('url') or '' + capture_date = request_body.get('capture_date') + if capture_date: + item.capture_date = dateparse.parse_date(capture_date) item.save() item.regie.compute_extra_fees(user=item.user) @@ -328,10 +331,14 @@ class PayMixin(object): transaction.amount = total_amount payment = get_eopayment_object(request, regie) - - (order_id, kind, data) = payment.request(total_amount, email=email, - first_name=firstname, - last_name=lastname) + kwargs = { + 'email': email, 'first_name': firstname, 'last_name': lastname + } + if items: + capture_date = items[0].capture_date + if capture_date: + kwargs['capture_date'] = capture_date.isoformat() + (order_id, kind, data) = payment.request(total_amount, **kwargs) 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)}) @@ -382,6 +389,13 @@ class PayView(PayMixin, View): regie.compute_extra_fees(user=user) items = BasketItem.get_items_to_be_paid(user=user).filter(regie=regie) + if items: + capture_date = items[0].capture_date + for item in items: + if item.capture_date != capture_date: + messages.error(request, _(u'Invalid grouping for basket items.')) + 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')) diff --git a/tests/test_lingo_payment.py b/tests/test_lingo_payment.py index 45a25c5..49a867d 100644 --- a/tests/test_lingo_payment.py +++ b/tests/test_lingo_payment.py @@ -233,6 +233,61 @@ def test_add_amount_to_basket(app, key, regie, user): resp = app.post_json(url, params=data, status=400) assert resp.text == 'Unknown regie' + +def test_basket_item_with_capture_date(app, user, regie, basket_page, monkeypatch): + User.objects.get_or_create(email=user.email) + url = '%s?email=%s' % (reverse('api-add-basket-item'), user.email) + capture_date = timezone.now().date() + data = { + 'amount': 10, 'capture_date': capture_date.isoformat(), + 'display_name': 'test item' + } + url = sign_url(url, settings.LINGO_API_SIGN_KEY) + resp = app.post_json(url, params=data) + assert resp.status_code == 200 + assert BasketItem.objects.all()[0].capture_date == capture_date + + resp = login(app).get('/test_basket_cell/') + import eopayment + eopayment_mock = mock.Mock( + return_value=('orderid', eopayment.URL, 'http://dummy-payment.demo.entrouvert.com/')) + monkeypatch.setattr(eopayment.Payment, 'request', eopayment_mock) + resp = resp.form.submit() + assert resp.status_code == 302 + location = urlparse.urlparse(resp.location) + assert location.path == '/' + assert location.hostname == 'dummy-payment.demo.entrouvert.com' + eopayment_mock.assert_called_once_with( + Decimal(10), email=user.email, first_name=user.first_name, last_name=user.last_name, + capture_date=capture_date.isoformat()) + + +def test_cant_pay_if_different_capture_date(app, basket_page, regie, user): + capture1 = (timezone.now() + timedelta(days=1)).date() + capture2 = (timezone.now() + timedelta(days=2)).date() + items = { + 'item1': { + 'amount': '10.5', 'capture_date': capture1.isoformat(), + 'source_url': 'http://example.org/item/1' + }, + 'item2': { + 'amount': '42', 'capture_date': capture2.isoformat(), + 'source_url': 'http://example.org/item/2'}, + } + b_items = [] + for subject, details in items.items(): + b_item = BasketItem.objects.create( + user=user, regie=regie, subject=subject, **details) + b_items.append(b_item.pk) + + resp = login(app).get('/test_basket_cell/') + resp = resp.form.submit() + assert resp.status_code == 302 + assert urlparse.urlparse(resp.location).path == '/test_basket_cell/' + resp = resp.follow() + assert "Invalid grouping for basket items." in resp.content + + def test_pay_single_basket_item(app, key, regie, user, john_doe): page = Page(title='xxx', slug='index', template_name='standard') page.save() -- 2.19.0