Projet

Général

Profil

0002-api-remove-user-bookings-on-subscription-date-change.patch

Lauréline Guérin, 03 février 2022 16:55

Télécharger (16,6 ko)

Voir les différences:

Subject: [PATCH 2/3] api: remove user bookings on subscription date changes
 (#61065)

 chrono/api/views.py            |  58 ++++--
 tests/api/test_subscription.py | 323 +++++++++++++++++++++++++++++++++
 2 files changed, 362 insertions(+), 19 deletions(-)
chrono/api/views.py
1953 1953
        response.update({'err': 0})
1954 1954
        return Response(response)
1955 1955

  
1956
    def patch(self, request, *args, **kwargs):
1957
        serializer = self.serializer_class(self.subscription, data=request.data, partial=True)
1958

  
1959
        if not serializer.is_valid():
1960
            raise APIErrorBadRequest(N_('invalid payload'), errors=serializer.errors, err=4)
1961

  
1962
        serializer.save()
1963
        extra_data = {k: v for k, v in request.data.items() if k not in serializer.validated_data}
1964
        if extra_data:
1965
            self.subscription.extra_data = self.subscription.extra_data or {}
1966
            self.subscription.extra_data.update(extra_data)
1967
            self.subscription.save()
1968

  
1969
        return self.get(request, *args, **kwargs)
1970

  
1971
    def delete(self, request, *args, **kwargs):
1956
    def delete_out_of_period_bookings(self, date_start, date_end):
1972 1957
        other_user_subscription_qs = Subscription.objects.filter(
1973 1958
            agenda=self.subscription.agenda,
1974 1959
            user_external_id=self.subscription.user_external_id,
......
1977 1962
            # remove user bookings for this agenda
1978 1963
            event__agenda=self.subscription.agenda,
1979 1964
            user_external_id=self.subscription.user_external_id,
1980
            # in the period of the deleted subscription
1981
            event__start_datetime__gt=self.subscription.date_start,
1982
            event__start_datetime__lt=self.subscription.date_end + datetime.timedelta(days=1),
1965
            # in the requested period
1966
            event__start_datetime__gt=date_start,
1967
            event__start_datetime__lt=date_end + datetime.timedelta(days=1),
1983 1968
        ).filter(
1984 1969
            # but only in the future
1985 1970
            event__start_datetime__gt=now(),
......
1991 1976
                event__start_datetime__lt=subscription.date_end + datetime.timedelta(days=1),
1992 1977
            )
1993 1978
        booking_qs.delete()
1979

  
1980
    def patch(self, request, *args, **kwargs):
1981
        serializer = self.serializer_class(self.subscription, data=request.data, partial=True)
1982
        old_date_start = self.subscription.date_start
1983
        old_date_end = self.subscription.date_end
1984

  
1985
        if not serializer.is_valid():
1986
            raise APIErrorBadRequest(N_('invalid payload'), errors=serializer.errors, err=4)
1987

  
1988
        serializer.save()
1989
        extra_data = {k: v for k, v in request.data.items() if k not in serializer.validated_data}
1990
        if extra_data:
1991
            self.subscription.extra_data = self.subscription.extra_data or {}
1992
            self.subscription.extra_data.update(extra_data)
1993
            self.subscription.save()
1994

  
1995
        if old_date_start > self.subscription.date_end or old_date_end < self.subscription.date_start:
1996
            # new period does not overlaps the old one, delete all bookings in the old period
1997
            self.delete_out_of_period_bookings(old_date_start, old_date_end)
1998
        else:
1999
            if old_date_start < self.subscription.date_start:
2000
                # date start has been postponed, remove all bookings from old start to new start
2001
                self.delete_out_of_period_bookings(
2002
                    old_date_start, self.subscription.date_start - datetime.timedelta(days=1)
2003
                )
2004
            if old_date_end > self.subscription.date_end:
2005
                # date end has been brought forward, remove all bookings from new end to old end
2006
                self.delete_out_of_period_bookings(
2007
                    self.subscription.date_end + datetime.timedelta(days=1), old_date_end
2008
                )
2009

  
2010
        return self.get(request, *args, **kwargs)
2011

  
2012
    def delete(self, request, *args, **kwargs):
2013
        self.delete_out_of_period_bookings(self.subscription.date_start, self.subscription.date_end)
1994 2014
        self.subscription.delete()
1995 2015
        response = {'err': 0}
1996 2016
        return Response(response)
tests/api/test_subscription.py
547 547
        agenda.kind = kind
548 548
        agenda.save()
549 549
        app.patch('/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk), status=404)
550

  
551

  
552
@pytest.mark.parametrize(
553
    'date_now, event_date, user_id, in_waiting_list, cancelled, deleted',
554
    [
555
        # event in the future, but no booking for the user
556
        ('2021-09-04 09:59', (2021, 9, 4, 12, 0), 'yyy', False, False, False),
557
        # event in the future
558
        ('2021-09-04 09:59', (2021, 9, 4, 12, 0), 'xxx', False, False, True),
559
        ('2021-09-04 09:59', (2021, 9, 4, 12, 0), 'xxx', True, False, True),
560
        ('2021-09-04 09:59', (2021, 9, 4, 12, 0), 'xxx', False, True, True),
561
        # event in the past
562
        ('2021-09-04 10:00', (2021, 9, 4, 12, 0), 'xxx', False, False, False),
563
        # event in the future and not covered by another subscription
564
        ('2021-08-01 10:00', (2021, 9, 4, 12, 0), 'xxx', False, False, True),
565
        ('2021-08-01 10:00', (2021, 9, 27, 12, 0), 'xxx', False, False, True),
566
        # event in the future but covered by another subscription
567
        ('2021-08-01 10:00', (2021, 9, 1, 12, 0), 'xxx', False, False, False),
568
        ('2021-08-01 10:00', (2021, 9, 3, 12, 0), 'xxx', False, False, False),
569
        ('2021-08-01 10:00', (2021, 9, 28, 12, 0), 'xxx', False, False, False),
570
        ('2021-08-01 10:00', (2021, 9, 30, 12, 0), 'xxx', False, False, False),
571
        # event in the future, before the period
572
        ('2021-08-01 10:00', (2021, 8, 14, 12, 0), 'xxx', False, False, False),
573
        ('2021-08-01 10:00', (2021, 8, 31, 12, 0), 'xxx', False, False, False),
574
        # event in the future, after the period
575
        ('2021-08-01 10:00', (2021, 10, 1, 12, 0), 'xxx', False, False, False),
576
        ('2021-08-01 10:00', (2021, 10, 16, 12, 0), 'xxx', False, False, False),
577
    ],
578
)
579
def test_api_patch_subscription_date_changes_delete_bookings(
580
    app, user, freezer, date_now, event_date, user_id, in_waiting_list, cancelled, deleted
581
):
582
    agenda = Agenda.objects.create(label='Foo bar', kind='events')
583
    subscription = Subscription.objects.create(
584
        agenda=agenda,
585
        user_external_id='xxx',
586
        date_start=datetime.date(year=2021, month=9, day=1),
587
        date_end=datetime.date(year=2021, month=9, day=30),
588
    )
589
    Subscription.objects.create(
590
        agenda=agenda,
591
        user_external_id='xxx',
592
        date_start=datetime.date(year=2021, month=8, day=15),
593
        date_end=datetime.date(year=2021, month=9, day=3),  # overlaps
594
    )
595
    Subscription.objects.create(
596
        agenda=agenda,
597
        user_external_id='xxx',
598
        date_start=datetime.date(year=2021, month=9, day=28),  # overlaps
599
        date_end=datetime.date(year=2021, month=10, day=15),
600
    )
601
    Subscription.objects.create(
602
        agenda=agenda,
603
        user_external_id='zzz',  # another user
604
        date_start=datetime.date(year=2021, month=9, day=1),
605
        date_end=datetime.date(year=2021, month=9, day=30),
606
    )
607

  
608
    other_agenda = Agenda.objects.create(label='Foo bar', kind='events')
609
    Subscription.objects.create(
610
        agenda=other_agenda,
611
        user_external_id='xxx',
612
        date_start=datetime.date(year=2021, month=9, day=1),
613
        date_end=datetime.date(year=2021, month=10, day=1),
614
    )
615

  
616
    app.authorization = ('Basic', ('john.doe', 'password'))
617

  
618
    freezer.move_to(date_now)
619
    event = Event.objects.create(
620
        agenda=agenda, start_datetime=make_aware(datetime.datetime(*event_date)), places=10
621
    )
622
    booking = Booking.objects.create(
623
        event=event,
624
        user_external_id=user_id,
625
        in_waiting_list=in_waiting_list,
626
        cancellation_datetime=(now() if cancelled else None),
627
    )
628

  
629
    # date_start is postponed, date_end is brought forward
630
    params = {
631
        'date_start': '2021-09-05',
632
        'date_end': '2021-09-25',
633
    }
634
    resp = app.patch('/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk), params=params)
635
    assert resp.json['err'] == 0
636
    assert Booking.objects.filter(pk=booking.pk).exists() is not deleted
637

  
638

  
639
@pytest.mark.parametrize(
640
    'event_date, deleted',
641
    [
642
        # just before old first day
643
        ((2021, 8, 31, 12, 00), False),
644
        # old first day
645
        ((2021, 9, 1, 12, 00), True),
646
        # old last day
647
        ((2021, 9, 30, 12, 00), True),
648
        # just after old last day
649
        ((2021, 10, 1, 12, 00), False),
650
    ],
651
)
652
def test_api_patch_subscription_date_changes_delete_bookings_forwards_no_overlaps(
653
    app, user, freezer, event_date, deleted
654
):
655
    agenda = Agenda.objects.create(label='Foo bar', kind='events')
656
    subscription = Subscription.objects.create(
657
        agenda=agenda,
658
        user_external_id='xxx',
659
        date_start=datetime.date(year=2021, month=9, day=1),
660
        date_end=datetime.date(year=2021, month=9, day=30),
661
    )
662

  
663
    app.authorization = ('Basic', ('john.doe', 'password'))
664

  
665
    freezer.move_to('2021-08-01 10:00')
666
    event = Event.objects.create(
667
        agenda=agenda, start_datetime=make_aware(datetime.datetime(*event_date)), places=10
668
    )
669
    booking = Booking.objects.create(
670
        event=event,
671
        user_external_id='xxx',
672
    )
673
    # subscription moved forwards, no overlaps
674
    params = {
675
        'date_start': '2021-11-01',
676
        'date_end': '2021-11-30',
677
    }
678
    resp = app.patch('/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk), params=params)
679
    assert resp.json['err'] == 0
680
    assert Booking.objects.filter(pk=booking.pk).exists() is not deleted
681

  
682

  
683
@pytest.mark.parametrize(
684
    'event_date, deleted',
685
    [
686
        # just before old first day
687
        ((2021, 8, 31, 12, 00), False),
688
        # old first day
689
        ((2021, 9, 1, 12, 00), True),
690
        # old last day
691
        ((2021, 9, 30, 12, 00), True),
692
        # just after old last day
693
        ((2021, 10, 1, 12, 00), False),
694
    ],
695
)
696
def test_api_patch_subscription_date_changes_delete_bookings_backwards_no_overlaps(
697
    app, user, freezer, event_date, deleted
698
):
699
    agenda = Agenda.objects.create(label='Foo bar', kind='events')
700
    subscription = Subscription.objects.create(
701
        agenda=agenda,
702
        user_external_id='xxx',
703
        date_start=datetime.date(year=2021, month=9, day=1),
704
        date_end=datetime.date(year=2021, month=9, day=30),
705
    )
706

  
707
    app.authorization = ('Basic', ('john.doe', 'password'))
708

  
709
    freezer.move_to('2021-06-01 10:00')
710
    event = Event.objects.create(
711
        agenda=agenda, start_datetime=make_aware(datetime.datetime(*event_date)), places=10
712
    )
713
    booking = Booking.objects.create(
714
        event=event,
715
        user_external_id='xxx',
716
    )
717
    # subscription moved backwards, no overlaps
718
    params = {
719
        'date_start': '2021-07-01',
720
        'date_end': '2021-07-31',
721
    }
722
    resp = app.patch('/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk), params=params)
723
    assert resp.json['err'] == 0
724
    assert Booking.objects.filter(pk=booking.pk).exists() is not deleted
725

  
726

  
727
@pytest.mark.parametrize(
728
    'event_date, deleted',
729
    [
730
        # just before old first day
731
        ((2021, 8, 31, 12, 00), False),
732
        # old first day
733
        ((2021, 9, 1, 12, 00), True),
734
        # just before new first day
735
        ((2021, 9, 4, 12, 00), True),
736
        # new first day
737
        ((2021, 9, 5, 12, 00), False),
738
        # new last day
739
        ((2021, 9, 25, 12, 00), False),
740
        # just after new last day
741
        ((2021, 9, 26, 12, 00), True),
742
        # old last day
743
        ((2021, 9, 30, 12, 00), True),
744
        # just after old last day
745
        ((2021, 10, 1, 12, 00), False),
746
    ],
747
)
748
def test_api_patch_subscription_date_changes_delete_bookings_shorter_period(
749
    app, user, freezer, event_date, deleted
750
):
751
    agenda = Agenda.objects.create(label='Foo bar', kind='events')
752
    subscription = Subscription.objects.create(
753
        agenda=agenda,
754
        user_external_id='xxx',
755
        date_start=datetime.date(year=2021, month=9, day=1),
756
        date_end=datetime.date(year=2021, month=9, day=30),
757
    )
758

  
759
    app.authorization = ('Basic', ('john.doe', 'password'))
760

  
761
    freezer.move_to('2021-08-01 10:00')
762
    event = Event.objects.create(
763
        agenda=agenda, start_datetime=make_aware(datetime.datetime(*event_date)), places=10
764
    )
765
    booking = Booking.objects.create(
766
        event=event,
767
        user_external_id='xxx',
768
    )
769
    # date_start is postponed, date_end is brought forward
770
    params = {
771
        'date_start': '2021-09-05',
772
        'date_end': '2021-09-25',
773
    }
774
    resp = app.patch('/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk), params=params)
775
    assert resp.json['err'] == 0
776
    assert Booking.objects.filter(pk=booking.pk).exists() is not deleted
777

  
778

  
779
@pytest.mark.parametrize(
780
    'event_date, deleted',
781
    [
782
        # just before old first day
783
        ((2021, 8, 31, 12, 00), False),
784
        # old first day
785
        ((2021, 9, 1, 12, 00), True),
786
        # just before new first day
787
        ((2021, 9, 14, 12, 00), True),
788
        # new first day
789
        ((2021, 9, 15, 12, 00), False),
790
        # old last day
791
        ((2021, 9, 30, 12, 00), False),
792
        # just after old last day
793
        ((2021, 10, 1, 12, 00), False),
794
    ],
795
)
796
def test_api_patch_subscription_date_changes_delete_bookings_forwards_with_overlaps(
797
    app, user, freezer, event_date, deleted
798
):
799
    agenda = Agenda.objects.create(label='Foo bar', kind='events')
800
    subscription = Subscription.objects.create(
801
        agenda=agenda,
802
        user_external_id='xxx',
803
        date_start=datetime.date(year=2021, month=9, day=1),
804
        date_end=datetime.date(year=2021, month=9, day=30),
805
    )
806

  
807
    app.authorization = ('Basic', ('john.doe', 'password'))
808

  
809
    freezer.move_to('2021-08-01 10:00')
810
    event = Event.objects.create(
811
        agenda=agenda, start_datetime=make_aware(datetime.datetime(*event_date)), places=10
812
    )
813
    booking = Booking.objects.create(
814
        event=event,
815
        user_external_id='xxx',
816
    )
817
    # subscription moved forwards, with overlaps
818
    params = {
819
        'date_start': '2021-09-15',
820
        'date_end': '2021-10-15',
821
    }
822
    resp = app.patch('/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk), params=params)
823
    assert resp.json['err'] == 0
824
    assert Booking.objects.filter(pk=booking.pk).exists() is not deleted
825

  
826

  
827
@pytest.mark.parametrize(
828
    'event_date, deleted',
829
    [
830
        # just before old first day
831
        ((2021, 8, 31, 12, 00), False),
832
        # old first day
833
        ((2021, 9, 1, 12, 00), False),
834
        # new last day
835
        ((2021, 9, 15, 12, 00), False),
836
        # just after new last day
837
        ((2021, 9, 16, 12, 00), True),
838
        # old last day
839
        ((2021, 9, 30, 12, 00), True),
840
        # just after old last day
841
        ((2021, 10, 1, 12, 00), False),
842
    ],
843
)
844
def test_api_patch_subscription_date_changes_delete_bookings_backwards_with_overlaps(
845
    app, user, freezer, event_date, deleted
846
):
847
    agenda = Agenda.objects.create(label='Foo bar', kind='events')
848
    subscription = Subscription.objects.create(
849
        agenda=agenda,
850
        user_external_id='xxx',
851
        date_start=datetime.date(year=2021, month=9, day=1),
852
        date_end=datetime.date(year=2021, month=9, day=30),
853
    )
854

  
855
    app.authorization = ('Basic', ('john.doe', 'password'))
856

  
857
    freezer.move_to('2021-08-01 10:00')
858
    event = Event.objects.create(
859
        agenda=agenda, start_datetime=make_aware(datetime.datetime(*event_date)), places=10
860
    )
861
    booking = Booking.objects.create(
862
        event=event,
863
        user_external_id='xxx',
864
    )
865
    # subscription moved backwards, with overlaps
866
    params = {
867
        'date_start': '2021-08-15',
868
        'date_end': '2021-09-15',
869
    }
870
    resp = app.patch('/api/agenda/%s/subscription/%s/' % (agenda.slug, subscription.pk), params=params)
871
    assert resp.json['err'] == 0
872
    assert Booking.objects.filter(pk=booking.pk).exists() is not deleted
550
-