api: use custody agendas date start (#66330)
This commit is contained in:
parent
bf9463e678
commit
ebe1884e17
|
@ -824,15 +824,29 @@ class Agenda(models.Model):
|
|||
|
||||
@staticmethod
|
||||
def filter_for_guardian(qs, guardian_external_id, child_external_id):
|
||||
agendas = SharedCustodyAgenda.objects.filter(children__user_external_id=child_external_id)
|
||||
qs = (
|
||||
qs.annotate(week=ExtractWeek('start_datetime'))
|
||||
.annotate(week_number=Cast('week', models.IntegerField()))
|
||||
.annotate(odd_week=F('week_number') % 2)
|
||||
)
|
||||
|
||||
previous_date_start = None
|
||||
filtered_qs = Event.objects.none()
|
||||
for agenda in agendas.order_by('-date_start'):
|
||||
filtered_qs |= Agenda.filter_for_custody_agenda(
|
||||
qs, agenda, guardian_external_id, date_end=previous_date_start
|
||||
)
|
||||
previous_date_start = agenda.date_start
|
||||
|
||||
return filtered_qs
|
||||
|
||||
@staticmethod
|
||||
def filter_for_custody_agenda(qs, agenda, guardian_external_id, date_end=None):
|
||||
rules = (
|
||||
SharedCustodyRule.objects.filter(
|
||||
guardian__user_external_id=guardian_external_id,
|
||||
agenda__children__user_external_id=child_external_id,
|
||||
agenda=agenda,
|
||||
)
|
||||
.annotate(day=Func(F('days'), function='unnest'))
|
||||
.annotate(week_day=(F('day') + 1) % 7 + 1) # convert ISO day number to db lookup day number
|
||||
|
@ -846,7 +860,7 @@ class Agenda(models.Model):
|
|||
)
|
||||
|
||||
all_periods = SharedCustodyPeriod.objects.filter(
|
||||
agenda__children__user_external_id=child_external_id,
|
||||
agenda=agenda,
|
||||
date_start__lte=OuterRef('start_datetime'),
|
||||
date_end__gt=OuterRef('start_datetime'),
|
||||
)
|
||||
|
@ -866,9 +880,14 @@ class Agenda(models.Model):
|
|||
)
|
||||
|
||||
rules_lookup = (rules_lookup | Q(in_holiday_period=True)) & Q(in_excluded_holiday_period=False)
|
||||
return qs.filter(
|
||||
(rules_lookup | Q(in_exceptional_period=True)) & Q(in_excluded_exceptional_period=False)
|
||||
qs = qs.filter(
|
||||
(rules_lookup | Q(in_exceptional_period=True)) & Q(in_excluded_exceptional_period=False),
|
||||
start_datetime__gte=agenda.date_start,
|
||||
)
|
||||
if date_end:
|
||||
qs = qs.filter(start_datetime__lt=date_end)
|
||||
|
||||
return qs
|
||||
|
||||
@staticmethod
|
||||
def prefetch_recurring_events(qs, with_overlaps=False):
|
||||
|
|
|
@ -418,13 +418,14 @@ def test_datetimes_multiple_agendas_queries(app):
|
|||
father = Person.objects.create(user_external_id='father_id', first_name='John', last_name='Doe')
|
||||
mother = Person.objects.create(user_external_id='mother_id', first_name='Jane', last_name='Doe')
|
||||
child = Person.objects.create(user_external_id='xxx', first_name='James', last_name='Doe')
|
||||
agenda = SharedCustodyAgenda.objects.create(
|
||||
first_guardian=father, second_guardian=mother, date_start=now() - datetime.timedelta(days=5)
|
||||
)
|
||||
agenda.children.add(child)
|
||||
for i in range(5):
|
||||
agenda = SharedCustodyAgenda.objects.create(
|
||||
first_guardian=father, second_guardian=mother, date_start=now() - datetime.timedelta(days=5 + i)
|
||||
)
|
||||
agenda.children.add(child)
|
||||
|
||||
SharedCustodyRule.objects.create(agenda=agenda, guardian=father, days=list(range(7)), weeks='even')
|
||||
SharedCustodyRule.objects.create(agenda=agenda, guardian=mother, days=list(range(7)), weeks='odd')
|
||||
SharedCustodyRule.objects.create(agenda=agenda, guardian=father, days=list(range(7)), weeks='even')
|
||||
SharedCustodyRule.objects.create(agenda=agenda, guardian=mother, days=list(range(7)), weeks='odd')
|
||||
|
||||
with CaptureQueriesContext(connection) as ctx:
|
||||
resp = app.get(
|
||||
|
@ -438,7 +439,7 @@ def test_datetimes_multiple_agendas_queries(app):
|
|||
},
|
||||
)
|
||||
assert len(resp.json['data']) == 30
|
||||
assert len(ctx.captured_queries) == 2
|
||||
assert len(ctx.captured_queries) == 3
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-05-06 14:00')
|
||||
|
@ -1214,6 +1215,138 @@ def test_datetimes_multiple_agendas_shared_custody_holiday_rules(app):
|
|||
assert len(resp.json['data']) == 1
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2022-03-07 14:00') # Monday of 10th week
|
||||
def test_datetimes_multiple_agendas_shared_custody_date_start(app):
|
||||
agenda = Agenda.objects.create(label='First agenda', kind='events')
|
||||
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
||||
start_datetime = make_aware(datetime.datetime(year=2022, month=3, day=9, hour=14, minute=0))
|
||||
wednesday_event = Event.objects.create(
|
||||
slug='event-wednesday',
|
||||
start_datetime=start_datetime,
|
||||
recurrence_days=[2],
|
||||
recurrence_end_date=start_datetime + datetime.timedelta(days=30),
|
||||
places=5,
|
||||
agenda=agenda,
|
||||
)
|
||||
wednesday_event.create_all_recurrences()
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='child_id',
|
||||
date_start=now(),
|
||||
date_end=now() + datetime.timedelta(days=30),
|
||||
)
|
||||
|
||||
father = Person.objects.create(user_external_id='father_id', first_name='John', last_name='Doe')
|
||||
mother = Person.objects.create(user_external_id='mother_id', first_name='Jane', last_name='Doe')
|
||||
child = Person.objects.create(user_external_id='child_id', first_name='James', last_name='Doe')
|
||||
agenda = SharedCustodyAgenda.objects.create(
|
||||
first_guardian=father, second_guardian=mother, date_start=now()
|
||||
)
|
||||
agenda.children.add(child)
|
||||
SharedCustodyRule.objects.create(agenda=agenda, guardian=father, days=list(range(7)))
|
||||
|
||||
resp = app.get(
|
||||
'/api/agendas/datetimes/',
|
||||
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
|
||||
)
|
||||
assert [d['id'] for d in resp.json['data']] == [
|
||||
'first-agenda@event-wednesday--2022-03-09-1400',
|
||||
'first-agenda@event-wednesday--2022-03-16-1400',
|
||||
'first-agenda@event-wednesday--2022-03-23-1400',
|
||||
'first-agenda@event-wednesday--2022-03-30-1400',
|
||||
]
|
||||
|
||||
resp = app.get(
|
||||
'/api/agendas/datetimes/',
|
||||
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
|
||||
)
|
||||
assert len(resp.json['data']) == 0
|
||||
|
||||
agenda = SharedCustodyAgenda.objects.create(
|
||||
first_guardian=father, second_guardian=mother, date_start=datetime.date(year=2022, month=3, day=10)
|
||||
)
|
||||
agenda.children.add(child)
|
||||
SharedCustodyRule.objects.create(agenda=agenda, guardian=mother, days=list(range(7)))
|
||||
|
||||
resp = app.get(
|
||||
'/api/agendas/datetimes/',
|
||||
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
|
||||
)
|
||||
assert [d['id'] for d in resp.json['data']] == [
|
||||
'first-agenda@event-wednesday--2022-03-09-1400',
|
||||
]
|
||||
|
||||
resp = app.get(
|
||||
'/api/agendas/datetimes/',
|
||||
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
|
||||
)
|
||||
assert [d['id'] for d in resp.json['data']] == [
|
||||
'first-agenda@event-wednesday--2022-03-16-1400',
|
||||
'first-agenda@event-wednesday--2022-03-23-1400',
|
||||
'first-agenda@event-wednesday--2022-03-30-1400',
|
||||
]
|
||||
|
||||
agenda = SharedCustodyAgenda.objects.create(
|
||||
first_guardian=father, second_guardian=mother, date_start=datetime.date(year=2022, month=3, day=17)
|
||||
)
|
||||
agenda.children.add(child)
|
||||
SharedCustodyRule.objects.create(agenda=agenda, guardian=father, days=list(range(7)), weeks='odd')
|
||||
SharedCustodyRule.objects.create(agenda=agenda, guardian=mother, days=list(range(7)), weeks='even')
|
||||
|
||||
resp = app.get(
|
||||
'/api/agendas/datetimes/',
|
||||
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
|
||||
)
|
||||
assert [d['id'] for d in resp.json['data']] == [
|
||||
'first-agenda@event-wednesday--2022-03-09-1400',
|
||||
'first-agenda@event-wednesday--2022-03-30-1400',
|
||||
]
|
||||
|
||||
resp = app.get(
|
||||
'/api/agendas/datetimes/',
|
||||
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
|
||||
)
|
||||
assert [d['id'] for d in resp.json['data']] == [
|
||||
'first-agenda@event-wednesday--2022-03-16-1400',
|
||||
'first-agenda@event-wednesday--2022-03-23-1400',
|
||||
]
|
||||
|
||||
other_person = Person.objects.create(user_external_id='other_person', first_name='O', last_name='P')
|
||||
agenda = SharedCustodyAgenda.objects.create(
|
||||
first_guardian=other_person,
|
||||
second_guardian=mother,
|
||||
date_start=datetime.date(year=2022, month=3, day=22),
|
||||
)
|
||||
agenda.children.add(child)
|
||||
SharedCustodyRule.objects.create(agenda=agenda, guardian=other_person, days=list(range(7)), weeks='odd')
|
||||
SharedCustodyRule.objects.create(agenda=agenda, guardian=mother, days=list(range(7)), weeks='even')
|
||||
|
||||
resp = app.get(
|
||||
'/api/agendas/datetimes/',
|
||||
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
|
||||
)
|
||||
assert [d['id'] for d in resp.json['data']] == [
|
||||
'first-agenda@event-wednesday--2022-03-09-1400',
|
||||
]
|
||||
|
||||
resp = app.get(
|
||||
'/api/agendas/datetimes/',
|
||||
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'other_person'},
|
||||
)
|
||||
assert [d['id'] for d in resp.json['data']] == [
|
||||
'first-agenda@event-wednesday--2022-03-30-1400',
|
||||
]
|
||||
|
||||
resp = app.get(
|
||||
'/api/agendas/datetimes/',
|
||||
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
|
||||
)
|
||||
assert [d['id'] for d in resp.json['data']] == [
|
||||
'first-agenda@event-wednesday--2022-03-16-1400',
|
||||
'first-agenda@event-wednesday--2022-03-23-1400',
|
||||
]
|
||||
|
||||
|
||||
def test_datetimes_multiple_agendas_with_status(app):
|
||||
agenda = Agenda.objects.create(label='agenda', kind='events')
|
||||
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
||||
|
|
|
@ -253,6 +253,57 @@ def test_recurring_events_api_list_shared_custody(app):
|
|||
assert [x['id'] for x in resp.json['data']] == ['foo-bar@event:0', 'foo-bar@event:1', 'foo-bar@event:2']
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-12-13 14:00') # Monday of 50th week
|
||||
def test_recurring_events_api_list_shared_custody_start_date(app):
|
||||
agenda = Agenda.objects.create(
|
||||
label='Foo bar', kind='events', minimal_booking_delay=1, maximal_booking_delay=30
|
||||
)
|
||||
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
||||
event = Event.objects.create(
|
||||
slug='event',
|
||||
start_datetime=now(),
|
||||
recurrence_days=[0, 1, 2],
|
||||
recurrence_end_date=now() + datetime.timedelta(days=30),
|
||||
places=5,
|
||||
agenda=agenda,
|
||||
)
|
||||
event.create_all_recurrences()
|
||||
|
||||
resp = app.get('/api/agendas/recurring-events/', params={'agendas': agenda.slug})
|
||||
assert [x['id'] for x in resp.json['data']] == ['foo-bar@event:0', 'foo-bar@event:1', 'foo-bar@event:2']
|
||||
|
||||
# add shared two custody agendas
|
||||
father = Person.objects.create(user_external_id='father_id', first_name='John', last_name='Doe')
|
||||
mother = Person.objects.create(user_external_id='mother_id', first_name='Jane', last_name='Doe')
|
||||
child = Person.objects.create(user_external_id='child_id', first_name='James', last_name='Doe')
|
||||
|
||||
custody_agenda = SharedCustodyAgenda.objects.create(
|
||||
first_guardian=father, second_guardian=mother, date_start=now()
|
||||
)
|
||||
custody_agenda.children.add(child)
|
||||
SharedCustodyRule.objects.create(agenda=custody_agenda, guardian=father, days=[0], weeks='even')
|
||||
SharedCustodyRule.objects.create(agenda=custody_agenda, guardian=mother, days=[1, 2], weeks='odd')
|
||||
|
||||
custody_agenda2 = SharedCustodyAgenda.objects.create(
|
||||
first_guardian=father, second_guardian=mother, date_start=now() + datetime.timedelta(days=15)
|
||||
)
|
||||
custody_agenda2.children.add(child)
|
||||
SharedCustodyRule.objects.create(agenda=custody_agenda2, guardian=father, days=[1], weeks='even')
|
||||
SharedCustodyRule.objects.create(agenda=custody_agenda2, guardian=mother, days=[0, 2], weeks='odd')
|
||||
|
||||
resp = app.get(
|
||||
'/api/agendas/recurring-events/',
|
||||
params={'agendas': agenda.slug, 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
|
||||
)
|
||||
assert [x['id'] for x in resp.json['data']] == ['foo-bar@event:0', 'foo-bar@event:1']
|
||||
|
||||
resp = app.get(
|
||||
'/api/agendas/recurring-events/',
|
||||
params={'agendas': agenda.slug, 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
|
||||
)
|
||||
assert [x['id'] for x in resp.json['data']] == ['foo-bar@event:0', 'foo-bar@event:1', 'foo-bar@event:2']
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-09-06 12:00')
|
||||
def test_recurring_events_api_list_multiple_agendas(app):
|
||||
agenda = Agenda.objects.create(label='First Agenda', kind='events')
|
||||
|
@ -345,7 +396,7 @@ def test_recurring_events_api_list_multiple_agendas_queries(app):
|
|||
'/api/agendas/recurring-events/?subscribed=category-a&user_external_id=xxx&guardian_external_id=father_id'
|
||||
)
|
||||
assert len(resp.json['data']) == 40
|
||||
assert len(ctx.captured_queries) == 4
|
||||
assert len(ctx.captured_queries) == 5
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-09-06 12:00')
|
||||
|
|
|
@ -652,6 +652,76 @@ def test_api_events_fillslots_multiple_agendas_shared_custody(app, user):
|
|||
assert resp.json['err_desc'] == 'Some events are outside guardian custody: first-agenda@event-thursday'
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2022-03-07 14:00') # Monday of 10th week
|
||||
def test_api_events_fillslots_multiple_agendas_shared_custody_date_start(app, user):
|
||||
agenda = Agenda.objects.create(label='First agenda', kind='events')
|
||||
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
||||
Event.objects.create(
|
||||
slug='event-wednesday',
|
||||
start_datetime=make_aware(datetime.datetime(year=2022, month=3, day=9, hour=14, minute=0)),
|
||||
places=5,
|
||||
agenda=agenda,
|
||||
)
|
||||
Event.objects.create(
|
||||
slug='event-thursday',
|
||||
start_datetime=make_aware(datetime.datetime(year=2022, month=3, day=10, hour=14, minute=0)),
|
||||
places=5,
|
||||
agenda=agenda,
|
||||
)
|
||||
Subscription.objects.create(
|
||||
agenda=agenda,
|
||||
user_external_id='child_id',
|
||||
date_start=now(),
|
||||
date_end=now() + datetime.timedelta(days=14),
|
||||
)
|
||||
|
||||
father = Person.objects.create(user_external_id='father_id', first_name='John', last_name='Doe')
|
||||
mother = Person.objects.create(user_external_id='mother_id', first_name='Jane', last_name='Doe')
|
||||
child = Person.objects.create(user_external_id='child_id', first_name='James', last_name='Doe')
|
||||
|
||||
agenda = SharedCustodyAgenda.objects.create(
|
||||
first_guardian=father, second_guardian=mother, date_start=now()
|
||||
)
|
||||
agenda.children.add(child)
|
||||
SharedCustodyRule.objects.create(agenda=agenda, guardian=father, days=list(range(7)))
|
||||
|
||||
agenda2 = SharedCustodyAgenda.objects.create(
|
||||
first_guardian=father, second_guardian=mother, date_start=datetime.date(year=2022, month=3, day=10)
|
||||
)
|
||||
agenda2.children.add(child)
|
||||
SharedCustodyRule.objects.create(agenda=agenda2, guardian=mother, days=list(range(7)))
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
params = {'user_external_id': 'child_id', 'slots': 'first-agenda@event-wednesday'}
|
||||
resp = app.post_json(
|
||||
'/api/agendas/events/fillslots/?subscribed=all&guardian_external_id=father_id', params=params
|
||||
)
|
||||
assert resp.json['booking_count'] == 1
|
||||
|
||||
resp = app.post_json(
|
||||
'/api/agendas/events/fillslots/?subscribed=all&guardian_external_id=mother_id',
|
||||
params=params,
|
||||
status=400,
|
||||
)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_desc'] == 'Some events are outside guardian custody: first-agenda@event-wednesday'
|
||||
|
||||
params['slots'] = 'first-agenda@event-thursday'
|
||||
resp = app.post_json(
|
||||
'/api/agendas/events/fillslots/?subscribed=all&guardian_external_id=mother_id', params=params
|
||||
)
|
||||
assert resp.json['booking_count'] == 1
|
||||
|
||||
params['slots'] = 'first-agenda@event-thursday'
|
||||
resp = app.post_json(
|
||||
'/api/agendas/events/fillslots/?subscribed=all&guardian_external_id=father_id',
|
||||
params=params,
|
||||
status=400,
|
||||
)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_desc'] == 'Some events are outside guardian custody: first-agenda@event-thursday'
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-09-06 12:00')
|
||||
def test_api_events_fillslots_multiple_agendas_overlapping_events(app, user, freezer):
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
|
|
|
@ -1312,7 +1312,7 @@ def test_recurring_events_api_fillslots_multiple_agendas_queries(app, user):
|
|||
params={'slots': events_to_book, 'user_external_id': 'xxx'},
|
||||
)
|
||||
assert resp.json['booking_count'] == 100
|
||||
assert len(ctx.captured_queries) == 13
|
||||
assert len(ctx.captured_queries) == 14
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2022-03-07 14:00') # Monday of 10th week
|
||||
|
@ -1377,6 +1377,37 @@ def test_recurring_events_api_fillslots_shared_custody(app, user, freezer):
|
|||
'2022-03-20',
|
||||
]
|
||||
|
||||
# give father full custody from 14/03/2022
|
||||
agenda2 = SharedCustodyAgenda.objects.create(
|
||||
first_guardian=father, second_guardian=mother, date_start=datetime.date(year=2022, month=3, day=14)
|
||||
)
|
||||
agenda2.children.add(child)
|
||||
|
||||
SharedCustodyRule.objects.create(agenda=agenda2, guardian=father, days=list(range(7)))
|
||||
Booking.objects.all().delete()
|
||||
|
||||
resp = app.post_json(fillslots_url % 'father_id', params=params)
|
||||
assert [x['date'] for x in resp.json['booked_events']] == [
|
||||
'2022-03-10',
|
||||
'2022-03-11',
|
||||
'2022-03-12',
|
||||
'2022-03-14',
|
||||
'2022-03-15',
|
||||
'2022-03-16',
|
||||
'2022-03-17',
|
||||
'2022-03-18',
|
||||
'2022-03-19',
|
||||
'2022-03-20',
|
||||
]
|
||||
|
||||
resp = app.post_json(fillslots_url % 'mother_id', params=params)
|
||||
assert [x['date'] for x in resp.json['booked_events']] == [
|
||||
'2022-03-07',
|
||||
'2022-03-08',
|
||||
'2022-03-09',
|
||||
'2022-03-13', # last date before new agenda rules apply
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-09-06 12:00')
|
||||
def test_recurring_events_api_fillslots_overlapping_events(app, user):
|
||||
|
|
Loading…
Reference in New Issue