Projet

Général

Profil

0001-lingo-allow-arbitrary-date-for-deferred-payment-2704.patch

Emmanuel Cazenave, 10 octobre 2018 15:22

Télécharger (8,92 ko)

Voir les différences:

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                     | 36 ++++++++--
 tests/test_lingo_payment.py                   | 65 +++++++++++++++++++
 4 files changed, 116 insertions(+), 6 deletions(-)
 create mode 100644 combo/apps/lingo/migrations/0032_basketitem_capture_date.py
combo/apps/lingo/migrations/0032_basketitem_capture_date.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.15 on 2018-10-05 15:33
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations, models
6

  
7

  
8
class Migration(migrations.Migration):
9

  
10
    dependencies = [
11
        ('lingo', '0031_basketitem_waiting_date'),
12
    ]
13

  
14
    operations = [
15
        migrations.AddField(
16
            model_name='basketitem',
17
            name='capture_date',
18
            field=models.DateField(null=True),
19
        ),
20
    ]
combo/apps/lingo/models.py
327 327
    waiting_date = models.DateTimeField(null=True)
328 328
    payment_date = models.DateTimeField(null=True)
329 329
    notification_date = models.DateTimeField(null=True)
330
    capture_date = models.DateField(null=True)
330 331

  
331 332
    class Meta:
332 333
        ordering = ['regie', 'extra_fee', 'subject']
combo/apps/lingo/views.py
26 26
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest
27 27
from django.http import HttpResponseForbidden, Http404, JsonResponse
28 28
from django.template.response import TemplateResponse
29
from django.utils import timezone
29
from django.utils import timezone, dateparse
30 30
from django.utils.encoding import force_text
31 31
from django.views.decorators.csrf import csrf_exempt
32 32
from django.views.generic import View, DetailView, ListView, TemplateView
......
161 161
        item.subject = request_body.get('display_name')
162 162
        item.source_url = request_body.get('url') or ''
163 163

  
164
        if 'capture_date' in request_body:
165
            try:
166
                # parse_date returns None when the string format is invalid
167
                capture_date_err = False
168
                item.capture_date = dateparse.parse_date(request_body['capture_date'])
169
            except TypeError:
170
                capture_date_err = True
171
            finally:
172
                if item.capture_date is None or capture_date_err:
173
                    return HttpResponseBadRequest(
174
                        _(u'Bad format for capture date, it should be yyyy-mm-dd.'))
175

  
164 176
        item.save()
165 177
        item.regie.compute_extra_fees(user=item.user)
166 178

  
......
328 340
        transaction.amount = total_amount
329 341

  
330 342
        payment = get_eopayment_object(request, regie)
331

  
332
        (order_id, kind, data) = payment.request(total_amount, email=email,
333
                                            first_name=firstname,
334
                                            last_name=lastname)
343
        kwargs = {
344
            'email': email, 'first_name': firstname, 'last_name': lastname
345
        }
346
        if items:
347
            capture_date = items[0].capture_date
348
            if capture_date:
349
                kwargs['capture_date'] = capture_date.isoformat()
350
        (order_id, kind, data) = payment.request(total_amount, **kwargs)
335 351
        logger = logging.getLogger(__name__)
336 352
        logger.info(u'emitted payment request with id %s', smart_text(order_id), extra={
337 353
            'eopayment_order_id': smart_text(order_id), 'eopayment_data': repr(data)})
......
359 375
        user = request.user if request.user.is_authenticated() else None
360 376
        remote_items = []
361 377
        items = []
378
        invalid_grouping_msg = _(u'Invalid grouping for basket items.')
362 379
        if regie_id and Regie.objects.get(pk=regie_id).is_remote():
363 380
            regie = Regie.objects.get(pk=regie_id)
364 381
            # get all items data from regie webservice
......
375 392
                regie_id = items[0].regie_id
376 393
                for item in items:
377 394
                    if item.regie_id != regie_id:
378
                        messages.error(request, _(u'Invalid grouping for basket items.'))
395
                        messages.error(request, invalid_grouping_msg)
379 396
                        return HttpResponseRedirect(next_url)
380 397

  
381 398
            regie = Regie.objects.get(id=regie_id)
382 399
            regie.compute_extra_fees(user=user)
383 400
            items = BasketItem.get_items_to_be_paid(user=user).filter(regie=regie)
384 401

  
402
        if items:
403
            capture_date = items[0].capture_date
404
            for item in items:
405
                if item.capture_date != capture_date:
406
                    messages.error(request, invalid_grouping_msg)
407
                    return HttpResponseRedirect(next_url)
408

  
385 409
        if not user and not request.POST.get('email'):
386 410
            messages.warning(request, _(u'You must give an email address.'))
387 411
            return HttpResponseRedirect(request.POST.get('item_url'))
tests/test_lingo_payment.py
233 233
    resp = app.post_json(url, params=data, status=400)
234 234
    assert resp.text == 'Unknown regie'
235 235

  
236

  
237
def test_basket_item_with_capture_date(app, user, regie, basket_page, monkeypatch):
238
    User.objects.get_or_create(email=user.email)
239
    url = '%s?email=%s' % (reverse('api-add-basket-item'), user.email)
240
    capture_date = timezone.now().date()
241
    data = {
242
        'amount': 10, 'capture_date': capture_date.isoformat(),
243
        'display_name': 'test item'
244
    }
245
    url = sign_url(url, settings.LINGO_API_SIGN_KEY)
246
    resp = app.post_json(url, params=data)
247
    assert resp.status_code == 200
248
    assert BasketItem.objects.all()[0].capture_date == capture_date
249

  
250
    resp = login(app).get('/test_basket_cell/')
251
    import eopayment
252
    eopayment_mock = mock.Mock(
253
        return_value=('orderid', eopayment.URL, 'http://dummy-payment.demo.entrouvert.com/'))
254
    monkeypatch.setattr(eopayment.Payment, 'request', eopayment_mock)
255
    resp = resp.form.submit()
256
    assert resp.status_code == 302
257
    location = urlparse.urlparse(resp.location)
258
    assert location.path == '/'
259
    assert location.hostname == 'dummy-payment.demo.entrouvert.com'
260
    eopayment_mock.assert_called_once_with(
261
        Decimal(10), email=user.email, first_name=user.first_name, last_name=user.last_name,
262
        capture_date=capture_date.isoformat())
263

  
264

  
265
@pytest.mark.parametrize("invalid_capture_date", [8, '', 'not-a-date'])
266
def test_add_basket_capture_date_format(app, user, regie, invalid_capture_date):
267
    url = '%s?email=%s' % (reverse('api-add-basket-item'), user.email)
268
    data = {'amount': 10, 'display_name': 'test item'}
269
    data['capture_date'] = invalid_capture_date
270
    url = sign_url(url, settings.LINGO_API_SIGN_KEY)
271
    resp = app.post_json(url, params=data, status=400)
272
    assert 'Bad format for capture date, it should be yyyy-mm-dd.' in resp.content
273

  
274

  
275
def test_cant_pay_if_different_capture_date(app, basket_page, regie, user):
276
    capture1 = (timezone.now() + timedelta(days=1)).date()
277
    capture2 = (timezone.now() + timedelta(days=2)).date()
278
    items = {
279
        'item1': {
280
            'amount': '10.5', 'capture_date': capture1.isoformat(),
281
            'source_url': 'http://example.org/item/1'
282
        },
283
        'item2': {
284
            'amount': '42', 'capture_date': capture2.isoformat(),
285
            'source_url': 'http://example.org/item/2'},
286
    }
287
    b_items = []
288
    for subject, details in items.items():
289
        b_item = BasketItem.objects.create(
290
            user=user, regie=regie, subject=subject, **details)
291
        b_items.append(b_item.pk)
292

  
293
    resp = login(app).get('/test_basket_cell/')
294
    resp = resp.form.submit()
295
    assert resp.status_code == 302
296
    assert urlparse.urlparse(resp.location).path == '/test_basket_cell/'
297
    resp = resp.follow()
298
    assert "Invalid grouping for basket items." in resp.content
299

  
300

  
236 301
def test_pay_single_basket_item(app, key, regie, user, john_doe):
237 302
    page = Page(title='xxx', slug='index', template_name='standard')
238 303
    page.save()
239
-