Projet

Général

Profil

0001-api-allow-changing-recurrence-bookings-54746.patch

Valentin Deniaud, 05 août 2021 14:22

Télécharger (8,08 ko)

Voir les différences:

Subject: [PATCH] api: allow changing recurrence bookings (#54746)

 chrono/api/views.py        | 23 ++++++++++---
 tests/api/test_fillslot.py | 70 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 89 insertions(+), 4 deletions(-)
chrono/api/views.py
1571 1571
                http_status=status.HTTP_400_BAD_REQUEST,
1572 1572
            )
1573 1573
        payload = serializer.validated_data
1574
        user_external_id = payload['user_external_id']
1574 1575

  
1575 1576
        open_event_slugs = set(agenda.get_open_recurring_events().values_list('slug', flat=True))
1576 1577
        slots = collections.defaultdict(list)
......
1600 1601

  
1601 1602
        events_to_book = Event.objects.filter(event_filter)
1602 1603
        events_to_book = events_to_book.filter(start_datetime__gte=start_datetime, cancelled=False)
1604
        if end_datetime:
1605
            events_to_book = events_to_book.filter(start_datetime__lte=end_datetime)
1606

  
1607
        events_to_unbook = list(
1608
            agenda.event_set.filter(booking__user_external_id=user_external_id, primary_event__isnull=False)
1609
            .exclude(pk__in=events_to_book)
1610
            .values_list('pk', flat=True)
1611
        )
1612
        events_to_book = events_to_book.exclude(booking__user_external_id=user_external_id)
1603 1613

  
1604 1614
        full_events = list(events_to_book.filter(full=True))
1605 1615
        events_to_book = events_to_book.filter(full=False)
1606
        if end_datetime:
1607
            events_to_book = events_to_book.filter(start_datetime__lte=end_datetime)
1608
        if not events_to_book.exists():
1616
        if not events_to_book.exists() and not events_to_unbook:
1609 1617
            if full_events:
1610 1618
                raise APIError(_('all events are all full'), err_class='all events are all full')
1611 1619
            raise APIError(_('no event recurrences to book'), err_class='no event recurrences to book')
......
1621 1629
        extra_data = {k: v for k, v in request.data.items() if k not in payload}
1622 1630
        bookings = [make_booking(event, payload, extra_data) for event in events_to_book]
1623 1631

  
1632
        events_to_update = Event.annotate_queryset(
1633
            agenda.event_set.filter(pk__in=events_to_unbook + [event.pk for event in events_to_book])
1634
        )
1624 1635
        with transaction.atomic():
1636
            deleted_count = Booking.objects.filter(
1637
                user_external_id=user_external_id, event__in=events_to_unbook
1638
            ).delete()[0]
1625 1639
            Booking.objects.bulk_create(bookings)
1626
            events_to_book.update(
1640
            events_to_update.update(
1627 1641
                full=Q(booked_places_count__gte=F('places'), waiting_list_places=0)
1628 1642
                | Q(waiting_list_places__gt=0, waiting_list_count__gte=F('waiting_list_places')),
1629 1643
                almost_full=Q(booked_places_count__gte=0.9 * F('places')),
......
1632 1646
        response = {
1633 1647
            'err': 0,
1634 1648
            'booking_count': len(bookings),
1649
            'cancelled_booking_count': deleted_count,
1635 1650
            'full_events': [get_event_detail(request, x, agenda=agenda) for x in full_events],
1636 1651
        }
1637 1652
        return Response(response)
tests/api/test_fillslot.py
2168 2168
    assert resp.json['booking_count'] == 155
2169 2169
    assert len(resp.json['full_events']) == 1
2170 2170
    assert resp.json['full_events'][0]['slug'] == event.slug
2171
    resp = app.post_json(fillslots_url, params=params)
2171 2172

  
2172 2173
    params['user_external_id'] = 'user_id_4'
2173 2174
    resp = app.post_json(fillslots_url, params=params)
......
2179 2180
    assert resp.json['booking_count'] == 4
2180 2181
    assert Booking.objects.filter(user_external_id='user_id_4').count() == 4
2181 2182

  
2183
    params['user_external_id'] = 'user_id_5'
2182 2184
    resp = app.post_json(fillslots_url + '?date_start=2020-10-06&date_end=2020-11-06', params=params)
2183 2185
    assert resp.json['err'] == 1
2184 2186
    assert resp.json['err_desc'] == 'no event recurrences to book'
......
2226 2228
    assert events.filter(waiting_list_count=2).count() == 5
2227 2229

  
2228 2230

  
2231
def test_recurring_events_api_fillslots_change_bookings(app, user, freezer):
2232
    freezer.move_to('2021-09-06 12:00')
2233
    agenda = Agenda.objects.create(label='Foo bar', kind='events')
2234
    event = Event.objects.create(
2235
        label='Event',
2236
        start_datetime=now(),
2237
        recurrence_days=[0, 1, 3, 4],  # Monday, Tuesday, Thursday, Friday
2238
        places=1,
2239
        waiting_list_places=1,
2240
        agenda=agenda,
2241
        recurrence_end_date=now() + datetime.timedelta(days=364),
2242
    )
2243
    event.create_all_recurrences()
2244

  
2245
    app.authorization = ('Basic', ('john.doe', 'password'))
2246
    fillslots_url = '/api/agenda/%s/recurring-events/fillslots/' % agenda.slug
2247
    params = {'user_external_id': 'user_id'}
2248
    # Book Monday and Thursday
2249
    params['slots'] = 'event:0,event:3'
2250
    resp = app.post_json(fillslots_url, params=params)
2251
    assert resp.json['booking_count'] == 104
2252
    assert resp.json['cancelled_booking_count'] == 0
2253
    assert Booking.objects.count() == 104
2254
    assert Booking.objects.filter(event__start_datetime__week_day=2).count() == 52
2255
    assert Booking.objects.filter(event__start_datetime__week_day=5).count() == 52
2256

  
2257
    # Change booking to Monday and Tuesday
2258
    params['slots'] = 'event:0,event:1'
2259
    resp = app.post_json(fillslots_url, params=params)
2260
    assert resp.json['booking_count'] == 52
2261
    assert resp.json['cancelled_booking_count'] == 52
2262
    assert Booking.objects.count() == 104
2263
    assert Booking.objects.filter(event__start_datetime__week_day=2).count() == 52
2264
    assert Booking.objects.filter(event__start_datetime__week_day=3).count() == 52
2265

  
2266
    params = {'user_external_id': 'user_id_2'}
2267
    params['slots'] = 'event:0,event:3'
2268
    resp = app.post_json(fillslots_url, params=params)
2269
    assert resp.json['booking_count'] == 104
2270
    assert resp.json['cancelled_booking_count'] == 0
2271
    assert Booking.objects.count() == 208
2272
    assert Booking.objects.filter(event__start_datetime__week_day=2).count() == 104
2273
    assert Booking.objects.filter(event__start_datetime__week_day=5).count() == 52
2274
    events = Event.annotate_queryset(Event.objects.filter(primary_event__isnull=False))
2275
    assert events.filter(booked_places_count=1).count() == 156
2276
    assert events.filter(waiting_list_count=1).count() == 52
2277

  
2278
    params['slots'] = 'event:1,event:4'
2279
    resp = app.post_json(fillslots_url, params=params)
2280
    assert resp.json['booking_count'] == 104
2281
    assert resp.json['cancelled_booking_count'] == 104
2282
    assert Booking.objects.count() == 208
2283
    assert Booking.objects.filter(event__start_datetime__week_day=3).count() == 104
2284
    assert Booking.objects.filter(event__start_datetime__week_day=6).count() == 52
2285
    events = Event.annotate_queryset(Event.objects.filter(primary_event__isnull=False))
2286
    assert events.filter(booked_places_count=1).count() == 156
2287
    assert events.filter(waiting_list_count=1).count() == 52
2288

  
2289
    # only recurring events are impacted
2290
    normal_event = Event.objects.create(
2291
        start_datetime=now() + datetime.timedelta(days=1), places=2, agenda=agenda
2292
    )
2293
    Booking.objects.create(event=normal_event, user_external_id='user_id')
2294
    resp = app.post_json(fillslots_url, params={'user_external_id': 'user_id', 'slots': 'event:0'})
2295
    assert resp.json['cancelled_booking_count'] == 52
2296
    assert Booking.objects.filter(user_external_id='user_id', event=normal_event).count() == 1
2297

  
2298

  
2229 2299
@pytest.mark.freeze_time('2021-09-06 12:00')
2230 2300
def test_api_events_fillslots(app, user):
2231 2301
    agenda = Agenda.objects.create(label='Foo bar', kind='events')
2232
-