Projet

Général

Profil

0004-api-add-support-for-subscriptions-in-recurring-fills.patch

Valentin Deniaud, 02 décembre 2021 15:28

Télécharger (9,12 ko)

Voir les différences:

Subject: [PATCH 4/4] api: add support for subscriptions in recurring fillslots
 (#58446)

 chrono/api/views.py        |  42 +++++++++------
 tests/api/test_fillslot.py | 103 +++++++++++++++++++++++++++++++++++++
 2 files changed, 128 insertions(+), 17 deletions(-)
chrono/api/views.py
674 674
    return serializer.validated_data.get('date_start'), serializer.validated_data.get('date_end')
675 675

  
676 676

  
677
def get_agendas_from_request(request):
678
    serializer = serializers.AgendaSlugsSerializer(data=request.query_params)
679
    if not serializer.is_valid():
680
        raise APIErrorBadRequest(N_('invalid payload'), errors=serializer.errors)
681

  
682
    return serializer.validated_data.get('agendas')
683

  
684

  
685 677
def make_booking(event, payload, extra_data, primary_booking=None, in_waiting_list=False, color=None):
686 678
    return Booking(
687 679
        event_id=event.pk,
......
1558 1550
        if not start_datetime or start_datetime < now():
1559 1551
            start_datetime = now()
1560 1552

  
1561
        agenda_slugs = get_agendas_from_request(request)
1562
        agendas = get_objects_from_slugs(agenda_slugs, qs=Agenda.objects.filter(kind='events'))
1553
        serializer = serializers.AgendaOrSubscribedSlugsSerializer(
1554
            data=request.query_params, context={'user_external_id': request.data.get('user_external_id')}
1555
        )
1556
        if not serializer.is_valid():
1557
            raise APIErrorBadRequest(N_('invalid payload'), errors=serializer.errors)
1558
        data = serializer.validated_data
1563 1559

  
1564
        context = {'allowed_agenda_slugs': agenda_slugs, 'agendas': Agenda.prefetch_recurring_events(agendas)}
1560
        context = {
1561
            'allowed_agenda_slugs': data['agenda_slugs'],
1562
            'agendas': Agenda.prefetch_recurring_events(data['agendas']),
1563
        }
1565 1564
        serializer = self.serializer_class(data=request.data, partial=True, context=context)
1566 1565
        if not serializer.is_valid():
1567 1566
            raise APIErrorBadRequest(N_('invalid payload'), errors=serializer.errors)
1568 1567
        payload = serializer.validated_data
1569 1568
        user_external_id = payload['user_external_id']
1570
        agendas = Agenda.prefetch_events_and_exceptions(agendas, user_external_id=user_external_id)
1569
        agendas = Agenda.prefetch_events_and_exceptions(data['agendas'], user_external_id=user_external_id)
1571 1570

  
1572 1571
        event_filter = Q()
1573 1572
        for agenda_slug, days_by_event in payload['slots'].items():
1574 1573
            for event_slug, days in days_by_event.items():
1575
                event_filter |= Q(
1576
                    agenda__slug=agenda_slug,
1577
                    primary_event__slug=event_slug,
1578
                    start_datetime__week_day__in=days,
1579
                )
1574
                lookups = {
1575
                    'agenda__slug': agenda_slug,
1576
                    'primary_event__slug': event_slug,
1577
                    'start_datetime__week_day__in': days,
1578
                }
1579
                if 'subscribed' in request.query_params:
1580
                    lookups.update(
1581
                        {
1582
                            'agenda__subscriptions__user_external_id': user_external_id,
1583
                            'agenda__subscriptions__date_start__lt': F('start_datetime'),
1584
                            'agenda__subscriptions__date_end__gt': F('start_datetime'),
1585
                        }
1586
                    )
1587
                event_filter |= Q(**lookups)
1580 1588

  
1581 1589
        events_to_book = Event.objects.filter(event_filter) if event_filter else Event.objects.none()
1582 1590
        events_to_book = events_to_book.filter(start_datetime__gte=start_datetime, cancelled=False)
tests/api/test_fillslot.py
2360 2360
    assert Booking.objects.filter(user_external_id='user_id', event=normal_event).count() == 1
2361 2361

  
2362 2362

  
2363
@pytest.mark.freeze_time('2021-09-06 12:00')
2364
def test_recurring_events_api_fillslots_subscribed(app, user):
2365
    category = Category.objects.create(label='Category A')
2366
    first_agenda = Agenda.objects.create(label='First agenda', kind='events', category=category)
2367
    Desk.objects.create(agenda=first_agenda, slug='_exceptions_holder')
2368
    category = Category.objects.create(label='Category B')
2369
    second_agenda = Agenda.objects.create(label='Second agenda', kind='events', category=category)
2370
    Desk.objects.create(agenda=second_agenda, slug='_exceptions_holder')
2371
    event = Event.objects.create(
2372
        slug='event',
2373
        start_datetime=now(),
2374
        recurrence_days=[0, 1, 3, 4],  # Monday, Tuesday, Thursday, Friday
2375
        places=2,
2376
        waiting_list_places=1,
2377
        agenda=first_agenda,
2378
        recurrence_end_date=now() + datetime.timedelta(days=364),
2379
    )
2380
    event.create_all_recurrences()
2381
    sunday_event = Event.objects.create(
2382
        slug='sunday-event',
2383
        start_datetime=now(),
2384
        recurrence_days=[6],
2385
        places=2,
2386
        waiting_list_places=1,
2387
        agenda=second_agenda,
2388
        recurrence_end_date=now() + datetime.timedelta(days=364),
2389
    )
2390
    sunday_event.create_all_recurrences()
2391

  
2392
    Subscription.objects.create(
2393
        agenda=first_agenda,
2394
        user_external_id='xxx',
2395
        date_start=now() + datetime.timedelta(days=16),  # Wednesday 22/09
2396
        date_end=now() + datetime.timedelta(days=44),  # Wednesday 20/10
2397
    )
2398

  
2399
    app.authorization = ('Basic', ('john.doe', 'password'))
2400
    params = {'user_external_id': 'xxx'}
2401
    # book Monday and Thursday of first event, in subscription range
2402
    params['slots'] = 'first-agenda@event:0,first-agenda@event:3'
2403
    resp = app.post_json('/api/agendas/recurring-events/fillslots/?subscribed=category-a', params=params)
2404
    assert resp.json['booking_count'] == 8
2405
    assert Booking.objects.count() == 8
2406
    assert Booking.objects.filter(event__primary_event=event).count() == 8
2407
    assert Booking.objects.first().event.start_datetime.strftime('%d/%m') == '23/09'
2408
    assert Booking.objects.last().event.start_datetime.strftime('%d/%m') == '18/10'
2409

  
2410
    # wrong category
2411
    resp = app.post_json(
2412
        '/api/agendas/recurring-events/fillslots/?subscribed=category-b', params=params, status=400
2413
    )
2414

  
2415
    # not subscribed category
2416
    params['slots'] = 'second-agenda@sunday-event:6'
2417
    resp = app.post_json(
2418
        '/api/agendas/recurring-events/fillslots/?subscribed=category-b', params=params, status=400
2419
    )
2420

  
2421
    # update bookings
2422
    Subscription.objects.create(
2423
        agenda=second_agenda,
2424
        user_external_id='xxx',
2425
        date_start=now() + datetime.timedelta(days=100),  # Wednesday 15/12
2426
        date_end=now() + datetime.timedelta(days=150),  # Thursday 03/02
2427
    )
2428
    params['slots'] = 'first-agenda@event:1,second-agenda@sunday-event:6'
2429
    resp = app.post_json('/api/agendas/recurring-events/fillslots/?subscribed=all', params=params)
2430
    assert resp.json['booking_count'] == 11
2431
    assert resp.json['cancelled_booking_count'] == 8
2432
    assert Booking.objects.count() == 11
2433
    booked_events_first_agenda = Event.objects.filter(primary_event=event, booking__isnull=False)
2434
    assert [
2435
        x.strftime('%d/%m/%Y') for x in booked_events_first_agenda.values_list('start_datetime', flat=True)
2436
    ] == ['28/09/2021', '05/10/2021', '12/10/2021', '19/10/2021']
2437
    booked_events_second_agenda = Event.objects.filter(primary_event=sunday_event, booking__isnull=False)
2438
    assert [
2439
        x.strftime('%d/%m/%Y') for x in booked_events_second_agenda.values_list('start_datetime', flat=True)
2440
    ] == ['19/12/2021', '26/12/2021', '02/01/2022', '09/01/2022', '16/01/2022', '23/01/2022', '30/01/2022']
2441

  
2442
    # other user
2443
    Subscription.objects.create(
2444
        agenda=second_agenda,
2445
        user_external_id='yyy',
2446
        date_start=now(),
2447
        date_end=now() + datetime.timedelta(days=10),
2448
    )
2449
    # disjoint subscription
2450
    Subscription.objects.create(
2451
        agenda=second_agenda,
2452
        user_external_id='yyy',
2453
        date_start=now() + datetime.timedelta(days=60),
2454
        date_end=now() + datetime.timedelta(days=70),
2455
    )
2456
    params = {'user_external_id': 'yyy', 'slots': 'second-agenda@sunday-event:6'}
2457
    resp = app.post_json('/api/agendas/recurring-events/fillslots/?subscribed=category-b', params=params)
2458
    assert resp.json['booking_count'] == 3
2459
    assert Booking.objects.count() == 14
2460
    booked_events_user_yyy = Event.objects.filter(primary_event=sunday_event, booking__user_external_id='yyy')
2461
    assert [
2462
        x.strftime('%d/%m/%Y') for x in booked_events_user_yyy.values_list('start_datetime', flat=True)
2463
    ] == ['12/09/2021', '07/11/2021', '14/11/2021']
2464

  
2465

  
2363 2466
@pytest.mark.freeze_time('2021-09-06 12:00')
2364 2467
def test_recurring_events_api_fillslots_multiple_agendas(app, user):
2365 2468
    agenda = Agenda.objects.create(label='First Agenda', kind='events')
2366
-