Projet

Général

Profil

0002-api-cancel-booking-in-events-fillslots-instead-of-de.patch

Lauréline Guérin, 07 février 2022 17:35

Télécharger (8,27 ko)

Voir les différences:

Subject: [PATCH 2/3] api: cancel booking in events fillslots - instead of
 delete (#61066)

 chrono/api/views.py        | 39 ++++++++++++++++-----
 tests/api/test_fillslot.py | 69 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 97 insertions(+), 11 deletions(-)
chrono/api/views.py
1779 1779
        if end_datetime:
1780 1780
            already_booked_events = already_booked_events.filter(start_datetime__lt=end_datetime)
1781 1781
        agendas_by_ids = self.get_agendas_by_ids()
1782
        events_to_unbook_ids = []
1782
        events_to_unbook = []
1783 1783
        events_in_request_ids = [e.pk for e in events]
1784 1784
        for event in already_booked_events:
1785 1785
            if event.pk in events_in_request_ids:
......
1793 1793
                continue
1794 1794
            if agenda.max_booking_datetime and event.start_datetime > agenda.max_booking_datetime:
1795 1795
                continue
1796
            events_to_unbook_ids.append(event.pk)
1796
            events_to_unbook.append(event)
1797 1797

  
1798
        events = events.exclude(booking__user_external_id=user_external_id)
1798
        # outdated bookings to remove (cancelled bookings to replace by an active booking)
1799
        events_cancelled_to_delete = events.filter(
1800
            booking__user_external_id=user_external_id,
1801
            booking__cancellation_datetime__isnull=False,
1802
        )
1803
        # book only events without active booking for the user
1804
        events = events.exclude(
1805
            pk__in=Booking.objects.filter(
1806
                event__in=events, user_external_id=user_external_id, cancellation_datetime__isnull=True
1807
            ).values('event')
1808
        )
1799 1809

  
1800 1810
        full_events = [str(event) for event in events.filter(full=True)]
1801 1811
        if full_events:
......
1814 1824
        extra_data = {k: v for k, v in request.data.items() if k not in payload}
1815 1825
        bookings = [make_booking(event, payload, extra_data) for event in events]
1816 1826

  
1827
        bookings_to_cancel = Booking.objects.filter(
1828
            user_external_id=user_external_id, event__in=events_to_unbook, cancellation_datetime__isnull=True
1829
        )
1830

  
1817 1831
        with transaction.atomic():
1818
            deleted_count = Booking.objects.filter(
1819
                user_external_id=user_external_id, event__in=events_to_unbook_ids
1820
            ).delete()[0]
1832
            # cancel existing bookings
1833
            cancelled_count = 0
1834
            for booking in bookings_to_cancel:
1835
                booking.cancel()
1836
                cancelled_count += 1
1837
            # and delete outdated cancelled bookings
1838
            Booking.objects.filter(
1839
                user_external_id=user_external_id, event__in=events_cancelled_to_delete
1840
            ).delete()
1841
            # create missing bookings
1821 1842
            Booking.objects.bulk_create(bookings)
1822 1843

  
1823 1844
        response = {
......
1830 1851
                get_event_detail(request, x, multiple_agendas=self.multiple_agendas)
1831 1852
                for x in waiting_list_events
1832 1853
            ],
1833
            'cancelled_booking_count': deleted_count,
1854
            'cancelled_booking_count': cancelled_count,
1834 1855
        }
1835 1856
        return Response(response)
1836 1857

  
......
1838 1859
        return get_events_from_slots(payload['slots'], request, self.agenda, payload)
1839 1860

  
1840 1861
    def get_already_booked_events(self, user_external_id):
1841
        return self.agenda.event_set.filter(booking__user_external_id=user_external_id)
1862
        return self.agenda.event_set.filter(
1863
            booking__user_external_id=user_external_id, booking__cancellation_datetime__isnull=True
1864
        )
1842 1865

  
1843 1866
    def get_agendas_by_ids(self):
1844 1867
        return {self.agenda.pk: self.agenda}
tests/api/test_fillslot.py
3341 3341
    assert resp.json['booking_count'] == 1
3342 3342
    assert resp.json['cancelled_booking_count'] == 1
3343 3343

  
3344
    user_bookings = Booking.objects.filter(user_external_id='user_id')
3344
    user_bookings = Booking.objects.filter(user_external_id='user_id', cancellation_datetime__isnull=True)
3345 3345
    assert {b.event.slug for b in user_bookings} == {'event-2', 'event-3'}
3346
    assert event.booking_set.count() == 2
3346
    assert event.booking_set.filter(cancellation_datetime__isnull=True).count() == 2
3347 3347
    assert second_event.booking_set.count() == 2
3348 3348
    assert third_event.booking_set.count() == 1
3349 3349

  
......
3370 3370
    params['slots'] = ''
3371 3371
    resp = app.post_json(fillslots_url, params=params)
3372 3372
    assert resp.json['cancelled_booking_count'] == 3
3373
    assert Booking.objects.filter(user_external_id='user_id').count() == 0
3373
    assert Booking.objects.filter(user_external_id='user_id', cancellation_datetime__isnull=True).count() == 0
3374 3374

  
3375 3375
    resp = app.post('/api/agenda/foobar/events/fillslots/', status=404)
3376 3376
    resp = app.post('/api/agenda/0/events/fillslots/', status=404)
3377 3377

  
3378 3378

  
3379
@pytest.mark.freeze_time('2021-09-06 12:00')
3380
def test_api_events_fillslots_with_cancelled(app, user):
3381
    agenda = Agenda.objects.create(label='Foo bar', kind='events')
3382
    event_1 = Event.objects.create(
3383
        label='Event 1',
3384
        start_datetime=now() + datetime.timedelta(days=1),
3385
        places=2,
3386
        agenda=agenda,
3387
    )
3388
    event_2 = Event.objects.create(
3389
        label='Event 2',
3390
        start_datetime=now() + datetime.timedelta(days=2),
3391
        places=2,
3392
        agenda=agenda,
3393
    )
3394
    Event.objects.create(
3395
        label='Event 3',
3396
        start_datetime=now() + datetime.timedelta(days=3),
3397
        places=2,
3398
        agenda=agenda,
3399
    )
3400

  
3401
    # create cancelled booking for the user
3402
    booking_1 = Booking.objects.create(event=event_1, user_external_id='user_id')
3403
    booking_1.cancel()
3404
    assert booking_1.cancellation_datetime is not None
3405
    # and non cancelled booking for the user
3406
    booking_2 = Booking.objects.create(event=event_2, user_external_id='user_id')
3407
    assert booking_2.cancellation_datetime is None
3408
    # and bookings for another user
3409
    Booking.objects.create(event=event_1, user_external_id='user_id_foobar')
3410
    other_booking = Booking.objects.create(event=event_2, user_external_id='user_id_foobar')
3411
    other_booking.cancel()
3412

  
3413
    app.authorization = ('Basic', ('john.doe', 'password'))
3414
    fillslots_url = '/api/agenda/%s/events/fillslots/' % agenda.slug
3415

  
3416
    params = {'user_external_id': 'user_id', 'slots': 'event-1,event-2,event-3'}
3417
    resp = app.post_json(fillslots_url, params=params)
3418
    assert resp.json['booking_count'] == 2
3419
    assert len(resp.json['booked_events']) == 2
3420
    assert resp.json['cancelled_booking_count'] == 0
3421
    assert resp.json['booked_events'][0]['id'] == 'event-1'
3422
    assert resp.json['booked_events'][1]['id'] == 'event-3'
3423
    assert Booking.objects.filter(user_external_id='user_id').count() == 3
3424
    assert Booking.objects.filter(user_external_id='user_id', cancellation_datetime__isnull=True).count() == 3
3425

  
3426
    assert Booking.objects.filter(pk=booking_1.pk).exists() is False  # cancelled booking deleted
3427
    booking_2.refresh_from_db()
3428
    assert booking_2.cancellation_datetime is None
3429

  
3430
    params = {'user_external_id': 'user_id', 'slots': 'event-3'}
3431
    resp = app.post_json(fillslots_url, params=params)
3432
    assert resp.json['booking_count'] == 0
3433
    assert resp.json['cancelled_booking_count'] == 2
3434
    assert Booking.objects.filter(user_external_id='user_id').count() == 3
3435
    assert Booking.objects.filter(user_external_id='user_id', cancellation_datetime__isnull=True).count() == 1
3436

  
3437
    assert Booking.objects.filter(pk=booking_1.pk).exists() is False  # cancelled booking deleted
3438
    booking_2.refresh_from_db()
3439
    assert booking_2.cancellation_datetime is not None
3440

  
3441

  
3379 3442
def test_api_events_fillslots_check_delays(app, user):
3380 3443
    agenda = Agenda.objects.create(
3381 3444
        label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=7
3382
-