agendas: add shared custody holiday rules (#62801)
This commit is contained in:
parent
dcec0f2d3f
commit
7d0511aa78
|
@ -0,0 +1,80 @@
|
|||
# Generated by Django 2.2.19 on 2022-03-24 16:02
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('agendas', '0113_auto_20220323_1708'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='SharedCustodyHolidayRule',
|
||||
fields=[
|
||||
(
|
||||
'id',
|
||||
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||
),
|
||||
(
|
||||
'years',
|
||||
models.CharField(
|
||||
blank=True,
|
||||
choices=[('', 'All'), ('even', 'Even'), ('odd', 'Odd')],
|
||||
max_length=16,
|
||||
verbose_name='Years',
|
||||
),
|
||||
),
|
||||
(
|
||||
'periodicity',
|
||||
models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
('first-half', 'First half'),
|
||||
('second-half', 'Second half'),
|
||||
('first-and-third-quarters', 'First and third quarters'),
|
||||
('second-and-fourth-quarters', 'Second and fourth quarters'),
|
||||
],
|
||||
max_length=32,
|
||||
verbose_name='Periodicity',
|
||||
),
|
||||
),
|
||||
(
|
||||
'agenda',
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name='holiday_rules',
|
||||
to='agendas.SharedCustodyAgenda',
|
||||
),
|
||||
),
|
||||
(
|
||||
'guardian',
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to='agendas.Person',
|
||||
verbose_name='Guardian',
|
||||
),
|
||||
),
|
||||
(
|
||||
'holiday',
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to='agendas.TimePeriodExceptionGroup',
|
||||
verbose_name='Holiday',
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'ordering': ['holiday__label', 'guardian', 'years', 'periodicity'],
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='sharedcustodyperiod',
|
||||
name='holiday_rule',
|
||||
field=models.ForeignKey(
|
||||
null=True, on_delete=django.db.models.deletion.CASCADE, to='agendas.SharedCustodyHolidayRule'
|
||||
),
|
||||
),
|
||||
]
|
|
@ -27,6 +27,7 @@ from dataclasses import dataclass, field
|
|||
|
||||
import requests
|
||||
import vobject
|
||||
from dateutil.relativedelta import SU, relativedelta
|
||||
from dateutil.rrule import DAILY, WEEKLY, rrule, rruleset
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import Group
|
||||
|
@ -3149,8 +3150,27 @@ class SharedCustodyAgenda(models.Model):
|
|||
qs = qs.filter(days__overlap=days)
|
||||
return qs.exists()
|
||||
|
||||
def holiday_rule_overlaps(self, holiday, years, periodicity, instance=None):
|
||||
qs = self.holiday_rules.filter(holiday=holiday)
|
||||
if hasattr(instance, 'pk'):
|
||||
qs = qs.exclude(pk=instance.pk)
|
||||
|
||||
if years:
|
||||
qs = qs.filter(Q(years='') | Q(years=years))
|
||||
|
||||
if periodicity == 'first-half':
|
||||
qs = qs.exclude(periodicity='second-half')
|
||||
elif periodicity == 'second-half':
|
||||
qs = qs.exclude(periodicity='first-half')
|
||||
elif periodicity == 'first-and-third-quarters':
|
||||
qs = qs.exclude(periodicity='second-and-fourth-quarters')
|
||||
elif periodicity == 'second-and-fourth-quarters':
|
||||
qs = qs.exclude(periodicity='first-and-third-quarters')
|
||||
|
||||
return qs.exists()
|
||||
|
||||
def period_overlaps(self, date_start, date_end, instance=None):
|
||||
qs = self.periods
|
||||
qs = self.periods.filter(holiday_rule__isnull=True)
|
||||
if hasattr(instance, 'pk'):
|
||||
qs = qs.exclude(pk=instance.pk)
|
||||
|
||||
|
@ -3218,9 +3238,124 @@ class SharedCustodyRule(models.Model):
|
|||
ordering = ['days__0', 'weeks']
|
||||
|
||||
|
||||
class SharedCustodyHolidayRule(models.Model):
|
||||
YEAR_CHOICES = [
|
||||
('', pgettext_lazy('years', 'All')),
|
||||
('even', pgettext_lazy('years', 'Even')),
|
||||
('odd', pgettext_lazy('years', 'Odd')),
|
||||
]
|
||||
|
||||
PERIODICITY_CHOICES = [
|
||||
('first-half', _('First half')),
|
||||
('second-half', _('Second half')),
|
||||
('first-and-third-quarters', _('First and third quarters')),
|
||||
('second-and-fourth-quarters', _('Second and fourth quarters')),
|
||||
]
|
||||
|
||||
agenda = models.ForeignKey(SharedCustodyAgenda, on_delete=models.CASCADE, related_name='holiday_rules')
|
||||
holiday = models.ForeignKey(TimePeriodExceptionGroup, verbose_name=_('Holiday'), on_delete=models.CASCADE)
|
||||
years = models.CharField(_('Years'), choices=YEAR_CHOICES, blank=True, max_length=16)
|
||||
periodicity = models.CharField(_('Periodicity'), choices=PERIODICITY_CHOICES, blank=True, max_length=32)
|
||||
guardian = models.ForeignKey(Person, verbose_name=_('Guardian'), on_delete=models.CASCADE)
|
||||
|
||||
def update_or_create_periods(self):
|
||||
shared_custody_periods = []
|
||||
for exception in self.holiday.exceptions.all():
|
||||
date_start = localtime(exception.start_datetime).date()
|
||||
|
||||
if self.years == 'even' and date_start.year % 2:
|
||||
continue
|
||||
if self.years == 'odd' and not date_start.year % 2:
|
||||
continue
|
||||
|
||||
date_start_sunday = date_start + relativedelta(weekday=SU)
|
||||
date_end = localtime(exception.end_datetime).date()
|
||||
|
||||
number_of_weeks = (date_end - date_start_sunday).days // 7
|
||||
|
||||
periods = []
|
||||
if self.periodicity == 'first-half':
|
||||
date_end = date_start_sunday + datetime.timedelta(days=7 * (number_of_weeks // 2))
|
||||
periods = [(date_start, date_end)]
|
||||
elif self.periodicity == 'second-half':
|
||||
date_start = date_start_sunday + datetime.timedelta(days=7 * (number_of_weeks // 2))
|
||||
periods = [(date_start, date_end)]
|
||||
elif self.periodicity == 'first-and-third-quarters' and number_of_weeks >= 4:
|
||||
weeks_in_quarters = round(number_of_weeks / 4)
|
||||
first_quarters_date_end = date_start_sunday + datetime.timedelta(days=7 * weeks_in_quarters)
|
||||
third_quarters_date_start = date_start_sunday + datetime.timedelta(
|
||||
days=7 * weeks_in_quarters * 2
|
||||
)
|
||||
third_quarters_date_end = date_start_sunday + datetime.timedelta(
|
||||
days=7 * weeks_in_quarters * 3
|
||||
)
|
||||
periods = [
|
||||
(date_start, first_quarters_date_end),
|
||||
(third_quarters_date_start, third_quarters_date_end),
|
||||
]
|
||||
elif self.periodicity == 'second-and-fourth-quarters' and number_of_weeks >= 4:
|
||||
weeks_in_quarters = round(number_of_weeks / 4)
|
||||
second_quarters_date_start = date_start_sunday + datetime.timedelta(
|
||||
days=7 * weeks_in_quarters
|
||||
)
|
||||
second_quarters_date_end = date_start_sunday + datetime.timedelta(
|
||||
days=7 * weeks_in_quarters * 2
|
||||
)
|
||||
fourth_quarters_date_start = date_start_sunday + datetime.timedelta(
|
||||
days=7 * weeks_in_quarters * 3
|
||||
)
|
||||
periods = [
|
||||
(second_quarters_date_start, second_quarters_date_end),
|
||||
(fourth_quarters_date_start, date_end),
|
||||
]
|
||||
elif not self.periodicity:
|
||||
periods = [(date_start, date_end)]
|
||||
|
||||
for date_start, date_end in periods:
|
||||
shared_custody_periods.append(
|
||||
SharedCustodyPeriod(
|
||||
guardian=self.guardian,
|
||||
agenda=self.agenda,
|
||||
holiday_rule=self,
|
||||
date_start=date_start,
|
||||
date_end=date_end,
|
||||
)
|
||||
)
|
||||
|
||||
with transaction.atomic():
|
||||
SharedCustodyPeriod.objects.filter(
|
||||
guardian=self.guardian, agenda=self.agenda, holiday_rule=self
|
||||
).delete()
|
||||
SharedCustodyPeriod.objects.bulk_create(shared_custody_periods)
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
label = self.holiday.label
|
||||
|
||||
if self.periodicity == 'first-half':
|
||||
label = '%s, %s' % (label, _('the first half'))
|
||||
elif self.periodicity == 'second-half':
|
||||
label = '%s, %s' % (label, _('the second half'))
|
||||
elif self.periodicity == 'first-and-third-quarters':
|
||||
label = '%s, %s' % (label, _('the first and third quarters'))
|
||||
elif self.periodicity == 'second-and-fourth-quarters':
|
||||
label = '%s, %s' % (label, _('the second and fourth quarters'))
|
||||
|
||||
if self.years == 'odd':
|
||||
label = '%s, %s' % (label, _('on odd years'))
|
||||
elif self.years == 'even':
|
||||
label = '%s, %s' % (label, _('on even years'))
|
||||
|
||||
return label
|
||||
|
||||
class Meta:
|
||||
ordering = ['holiday__label', 'guardian', 'years', 'periodicity']
|
||||
|
||||
|
||||
class SharedCustodyPeriod(models.Model):
|
||||
agenda = models.ForeignKey(SharedCustodyAgenda, on_delete=models.CASCADE, related_name='periods')
|
||||
guardian = models.ForeignKey(Person, on_delete=models.CASCADE, related_name='+')
|
||||
holiday_rule = models.ForeignKey(SharedCustodyHolidayRule, null=True, on_delete=models.CASCADE)
|
||||
date_start = models.DateField(_('Start'))
|
||||
date_end = models.DateField(_('End'))
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ from django.conf import settings
|
|||
from django.contrib.auth.models import Group
|
||||
from django.core.exceptions import FieldDoesNotExist
|
||||
from django.db import transaction
|
||||
from django.db.models import DurationField, ExpressionWrapper, F
|
||||
from django.forms import ValidationError
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.formats import date_format
|
||||
|
@ -50,11 +51,13 @@ from chrono.agendas.models import (
|
|||
MeetingType,
|
||||
Person,
|
||||
Resource,
|
||||
SharedCustodyHolidayRule,
|
||||
SharedCustodyPeriod,
|
||||
SharedCustodyRule,
|
||||
Subscription,
|
||||
TimePeriod,
|
||||
TimePeriodException,
|
||||
TimePeriodExceptionGroup,
|
||||
TimePeriodExceptionSource,
|
||||
UnavailabilityCalendar,
|
||||
VirtualMember,
|
||||
|
@ -1339,6 +1342,49 @@ class SharedCustodyRuleForm(forms.ModelForm):
|
|||
return cleaned_data
|
||||
|
||||
|
||||
class SharedCustodyHolidayRuleForm(forms.ModelForm):
|
||||
guardian = forms.ModelChoiceField(label=_('Guardian'), queryset=Person.objects.none())
|
||||
|
||||
class Meta:
|
||||
model = SharedCustodyHolidayRule
|
||||
fields = ['guardian', 'holiday', 'years', 'periodicity']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['guardian'].empty_label = None
|
||||
self.fields['guardian'].queryset = Person.objects.filter(
|
||||
pk__in=[self.instance.agenda.first_guardian_id, self.instance.agenda.second_guardian_id]
|
||||
)
|
||||
self.fields['holiday'].queryset = TimePeriodExceptionGroup.objects.filter(
|
||||
unavailability_calendar__slug='chrono-holidays',
|
||||
exceptions__isnull=False,
|
||||
).distinct()
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
|
||||
holidays = cleaned_data['holiday'].exceptions.annotate(
|
||||
delta=ExpressionWrapper(F('end_datetime') - F('start_datetime'), output_field=DurationField())
|
||||
)
|
||||
is_short_holiday = holidays.filter(delta__lt=datetime.timedelta(days=28)).exists()
|
||||
if 'quarters' in cleaned_data['periodicity'] and is_short_holiday:
|
||||
raise ValidationError(_('Short holidays cannot be cut into quarters.'))
|
||||
|
||||
if self.instance.agenda.holiday_rule_overlaps(
|
||||
cleaned_data['holiday'], cleaned_data['years'], cleaned_data['periodicity'], self.instance
|
||||
):
|
||||
raise ValidationError(_('Rule overlaps existing rules.'))
|
||||
|
||||
return cleaned_data
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
with transaction.atomic():
|
||||
super().save()
|
||||
self.instance.update_or_create_periods()
|
||||
|
||||
return self.instance
|
||||
|
||||
|
||||
class SharedCustodyPeriodForm(forms.ModelForm):
|
||||
guardian = forms.ModelChoiceField(label=_('Guardian'), queryset=Person.objects.none())
|
||||
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
<h2>{% trans "Settings" %}</h2>
|
||||
<span class="actions">
|
||||
<a rel="popup" href="{% url 'chrono-manager-shared-custody-agenda-add-period' pk=object.id %}">{% trans 'Add custody period' %}</a>
|
||||
{% if has_holidays %}
|
||||
<a rel="popup" href="{% url 'chrono-manager-shared-custody-agenda-add-holiday-rule' pk=object.id %}">{% trans 'Add custody rule during holidays' %}</a>
|
||||
{% endif %}
|
||||
<a rel="popup" href="{% url 'chrono-manager-shared-custody-agenda-add-rule' pk=object.id %}">{% trans 'Add custody rule' %}</a>
|
||||
</span>
|
||||
{% endblock %}
|
||||
|
@ -45,12 +48,39 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{% if has_holidays %}
|
||||
<div class="section">
|
||||
<h3>{% trans "Custody rules during holidays" %}</h3>
|
||||
<div>
|
||||
{% if agenda.holiday_rules.all %}
|
||||
<ul class="objects-list single-links">
|
||||
{% for rule in agenda.holiday_rules.all %}
|
||||
<li><a rel="popup" href="{% url 'chrono-manager-shared-custody-agenda-edit-holiday-rule' pk=agenda.pk rule_pk=rule.pk %}">
|
||||
<span class="rule-info">
|
||||
{{ rule.guardian.name }}, {{ rule.label }}
|
||||
</span>
|
||||
</a>
|
||||
<a rel="popup" class="delete" href="{% url 'chrono-manager-shared-custody-agenda-delete-holiday-rule' pk=agenda.pk rule_pk=rule.pk %}?next=settings">{% trans "remove" %}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<div class="big-msg-info">
|
||||
{% blocktrans trimmed %}
|
||||
This agenda doesn't specify any custody rules during holidays. It means normal rules will be applied.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="section">
|
||||
<h3>{% trans "Exceptional custody periods" %}</h3>
|
||||
<div>
|
||||
{% if agenda.periods.all %}
|
||||
{% if exceptional_periods %}
|
||||
<ul class="objects-list single-links">
|
||||
{% for period in agenda.periods.all %}
|
||||
{% for period in exceptional_periods %}
|
||||
<li>
|
||||
<a rel="popup" href="{% url 'chrono-manager-shared-custody-agenda-edit-period' pk=agenda.pk period_pk=period.pk %}">
|
||||
{{ period }}
|
||||
|
|
|
@ -411,6 +411,21 @@ urlpatterns = [
|
|||
views.shared_custody_agenda_delete_rule,
|
||||
name='chrono-manager-shared-custody-agenda-delete-rule',
|
||||
),
|
||||
url(
|
||||
r'^shared-custody/(?P<pk>\d+)/add-holiday-rule$',
|
||||
views.shared_custody_agenda_add_holiday_rule,
|
||||
name='chrono-manager-shared-custody-agenda-add-holiday-rule',
|
||||
),
|
||||
url(
|
||||
r'^shared-custody/(?P<pk>\d+)/holiday-rules/(?P<rule_pk>\d+)/edit$',
|
||||
views.shared_custody_agenda_edit_holiday_rule,
|
||||
name='chrono-manager-shared-custody-agenda-edit-holiday-rule',
|
||||
),
|
||||
url(
|
||||
r'^shared-custody/(?P<pk>\d+)/holiday-rules/(?P<rule_pk>\d+)/delete$',
|
||||
views.shared_custody_agenda_delete_holiday_rule,
|
||||
name='chrono-manager-shared-custody-agenda-delete-holiday-rule',
|
||||
),
|
||||
url(
|
||||
r'^shared-custody/(?P<pk>\d+)/add-period$',
|
||||
views.shared_custody_agenda_add_period,
|
||||
|
|
|
@ -76,6 +76,7 @@ from chrono.agendas.models import (
|
|||
MeetingType,
|
||||
Resource,
|
||||
SharedCustodyAgenda,
|
||||
SharedCustodyHolidayRule,
|
||||
SharedCustodyPeriod,
|
||||
SharedCustodyRule,
|
||||
TimePeriod,
|
||||
|
@ -114,6 +115,7 @@ from .forms import (
|
|||
NewEventForm,
|
||||
NewMeetingTypeForm,
|
||||
NewTimePeriodExceptionForm,
|
||||
SharedCustodyHolidayRuleForm,
|
||||
SharedCustodyPeriodForm,
|
||||
SharedCustodyRuleForm,
|
||||
SubscriptionCheckFilterSet,
|
||||
|
@ -3458,6 +3460,12 @@ class SharedCustodyAgendaSettings(SharedCustodyAgendaMixin, DetailView):
|
|||
template_name = 'chrono/manager_shared_custody_agenda_settings.html'
|
||||
model = SharedCustodyAgenda
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['has_holidays'] = UnavailabilityCalendar.objects.filter(slug='chrono-holidays').exists()
|
||||
context['exceptional_periods'] = SharedCustodyPeriod.objects.filter(holiday_rule__isnull=True)
|
||||
return context
|
||||
|
||||
|
||||
shared_custody_agenda_settings = SharedCustodyAgendaSettings.as_view()
|
||||
|
||||
|
@ -3492,6 +3500,36 @@ class SharedCustodyAgendaDeleteRuleView(SharedCustodyAgendaMixin, DeleteView):
|
|||
shared_custody_agenda_delete_rule = SharedCustodyAgendaDeleteRuleView.as_view()
|
||||
|
||||
|
||||
class SharedCustodyAgendaAddHolidayRuleView(SharedCustodyAgendaMixin, CreateView):
|
||||
title = _('Add custody rule during holidays')
|
||||
template_name = 'chrono/manager_agenda_form.html'
|
||||
form_class = SharedCustodyHolidayRuleForm
|
||||
model = SharedCustodyHolidayRule
|
||||
|
||||
|
||||
shared_custody_agenda_add_holiday_rule = SharedCustodyAgendaAddHolidayRuleView.as_view()
|
||||
|
||||
|
||||
class SharedCustodyAgendaEditHolidayRuleView(SharedCustodyAgendaMixin, UpdateView):
|
||||
title = _('Edit custody rule during holidays')
|
||||
template_name = 'chrono/manager_agenda_form.html'
|
||||
form_class = SharedCustodyHolidayRuleForm
|
||||
model = SharedCustodyHolidayRule
|
||||
pk_url_kwarg = 'rule_pk'
|
||||
|
||||
|
||||
shared_custody_agenda_edit_holiday_rule = SharedCustodyAgendaEditHolidayRuleView.as_view()
|
||||
|
||||
|
||||
class SharedCustodyAgendaDeleteHolidayRuleView(SharedCustodyAgendaMixin, DeleteView):
|
||||
template_name = 'chrono/manager_confirm_delete.html'
|
||||
model = SharedCustodyHolidayRule
|
||||
pk_url_kwarg = 'rule_pk'
|
||||
|
||||
|
||||
shared_custody_agenda_delete_holiday_rule = SharedCustodyAgendaDeleteHolidayRuleView.as_view()
|
||||
|
||||
|
||||
class SharedCustodyAgendaAddPeriodView(SharedCustodyAgendaMixin, CreateView):
|
||||
title = _('Add custody period')
|
||||
template_name = 'chrono/manager_agenda_form.html'
|
||||
|
|
|
@ -15,10 +15,13 @@ from chrono.agendas.models import (
|
|||
Event,
|
||||
Person,
|
||||
SharedCustodyAgenda,
|
||||
SharedCustodyHolidayRule,
|
||||
SharedCustodyPeriod,
|
||||
SharedCustodyRule,
|
||||
Subscription,
|
||||
TimePeriodException,
|
||||
TimePeriodExceptionGroup,
|
||||
UnavailabilityCalendar,
|
||||
)
|
||||
from tests.utils import login
|
||||
|
||||
|
@ -2657,3 +2660,69 @@ def test_datetimes_multiple_agendas_shared_custody_recurring_event(app):
|
|||
assert [d['id'] for d in resp.json['data']] == [
|
||||
'first-agenda@event-wednesday--2022-03-09-1400',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-12-13 14:00') # Monday of 50th week
|
||||
def test_datetimes_multiple_agendas_shared_custody_holiday_rules(app):
|
||||
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=2021, month=12, day=25, 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', name='John Doe')
|
||||
mother = Person.objects.create(user_external_id='mother_id', name='Jane Doe')
|
||||
child = Person.objects.create(user_external_id='child_id', name='James Doe')
|
||||
agenda = SharedCustodyAgenda.objects.create(first_guardian=father, second_guardian=mother)
|
||||
agenda.children.add(child)
|
||||
|
||||
SharedCustodyRule.objects.create(agenda=agenda, days=list(range(7)), weeks='even', guardian=father)
|
||||
SharedCustodyRule.objects.create(agenda=agenda, days=list(range(7)), weeks='odd', guardian=mother)
|
||||
|
||||
resp = app.get(
|
||||
'/api/agendas/datetimes/',
|
||||
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
|
||||
)
|
||||
assert len(resp.json['data']) == 0
|
||||
|
||||
resp = app.get(
|
||||
'/api/agendas/datetimes/',
|
||||
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'mother_id'},
|
||||
)
|
||||
assert len(resp.json['data']) == 1
|
||||
|
||||
# add father custody during holidays
|
||||
calendar = UnavailabilityCalendar.objects.create(label='Calendar')
|
||||
christmas_holiday = TimePeriodExceptionGroup.objects.create(
|
||||
unavailability_calendar=calendar, label='Christmas', slug='christmas'
|
||||
)
|
||||
TimePeriodException.objects.create(
|
||||
unavailability_calendar=calendar,
|
||||
start_datetime=make_aware(datetime.datetime(year=2021, month=12, day=18, hour=0, minute=0)),
|
||||
end_datetime=make_aware(datetime.datetime(year=2022, month=1, day=3, hour=0, minute=0)),
|
||||
group=christmas_holiday,
|
||||
)
|
||||
|
||||
rule = SharedCustodyHolidayRule.objects.create(agenda=agenda, guardian=father, holiday=christmas_holiday)
|
||||
rule.update_or_create_periods()
|
||||
|
||||
resp = app.get(
|
||||
'/api/agendas/datetimes/',
|
||||
params={'subscribed': 'all', 'user_external_id': 'child_id', 'guardian_external_id': 'father_id'},
|
||||
)
|
||||
assert len(resp.json['data']) == 1
|
||||
|
||||
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
|
||||
|
|
|
@ -1,13 +1,26 @@
|
|||
import datetime
|
||||
|
||||
import pytest
|
||||
from django.core.files.base import ContentFile
|
||||
|
||||
from chrono.agendas.models import Person, SharedCustodyAgenda, SharedCustodyPeriod, SharedCustodyRule
|
||||
from chrono.agendas.models import (
|
||||
Person,
|
||||
SharedCustodyAgenda,
|
||||
SharedCustodyHolidayRule,
|
||||
SharedCustodyPeriod,
|
||||
SharedCustodyRule,
|
||||
TimePeriodExceptionGroup,
|
||||
UnavailabilityCalendar,
|
||||
)
|
||||
from tests.utils import login
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
with open('tests/data/holidays.ics') as f:
|
||||
ICS_HOLIDAYS = f.read()
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2022-02-22 14:00') # Tuesday
|
||||
def test_shared_custody_agenda_settings_rules(app, admin_user):
|
||||
father = Person.objects.create(user_external_id='father_id', name='John Doe')
|
||||
|
@ -153,3 +166,78 @@ def test_shared_custody_agenda_month_view(app, admin_user):
|
|||
assert resp.text == old_resp.text
|
||||
|
||||
app.get('/manage/shared-custody/%s/42/42/' % agenda.pk, status=404)
|
||||
|
||||
|
||||
def test_shared_custody_agenda_holiday_rules(app, admin_user):
|
||||
father = Person.objects.create(user_external_id='father_id', name='John Doe')
|
||||
mother = Person.objects.create(user_external_id='mother_id', name='Jane Doe')
|
||||
agenda = SharedCustodyAgenda.objects.create(first_guardian=father, second_guardian=mother)
|
||||
|
||||
app = login(app)
|
||||
resp = app.get('/manage/shared-custody/%s/settings/' % agenda.pk)
|
||||
assert 'Add custody rule during holidays' not in resp.text
|
||||
assert 'Custody rules during holidays' not in resp.text
|
||||
|
||||
# configure holidays
|
||||
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar', slug='chrono-holidays')
|
||||
source = unavailability_calendar.timeperiodexceptionsource_set.create(
|
||||
ics_filename='holidays.ics', ics_file=ContentFile(ICS_HOLIDAYS, name='holidays.ics')
|
||||
)
|
||||
source.refresh_timeperiod_exceptions_from_ics()
|
||||
|
||||
resp = app.get('/manage/shared-custody/%s/settings/' % agenda.pk)
|
||||
resp = resp.click('Add custody rule during holidays')
|
||||
resp.form['guardian'] = father.pk
|
||||
resp.form['holiday'].select(text='Vacances de Noël')
|
||||
resp.form['years'] = 'odd'
|
||||
resp.form['periodicity'] = 'first-half'
|
||||
resp = resp.form.submit().follow()
|
||||
assert SharedCustodyHolidayRule.objects.count() == 1
|
||||
assert SharedCustodyPeriod.objects.count() == 3
|
||||
assert 'This agenda doesn\'t have any custody period.' in resp.text
|
||||
|
||||
resp = resp.click('John Doe, Vacances de Noël, the first half, on odd years')
|
||||
resp.form['years'] = ''
|
||||
resp = resp.form.submit().follow()
|
||||
assert 'John Doe, Vacances de Noël, the first half' in resp.text
|
||||
assert SharedCustodyHolidayRule.objects.count() == 1
|
||||
assert SharedCustodyPeriod.objects.count() == 6
|
||||
|
||||
resp = resp.click('Add custody rule during holidays')
|
||||
resp.form['guardian'] = mother.pk
|
||||
resp.form['holiday'].select(text='Vacances de Noël')
|
||||
resp.form['periodicity'] = 'first-half'
|
||||
resp = resp.form.submit()
|
||||
assert 'Rule overlaps existing rules.' in resp.text
|
||||
|
||||
resp.form['periodicity'] = 'second-half'
|
||||
resp = resp.form.submit().follow()
|
||||
assert 'Jane Doe, Vacances de Noël, the second half' in resp.text
|
||||
|
||||
assert SharedCustodyHolidayRule.objects.count() == 2
|
||||
assert SharedCustodyPeriod.objects.count() == 12
|
||||
|
||||
resp = resp.click('remove', index=1)
|
||||
resp = resp.form.submit().follow()
|
||||
assert SharedCustodyHolidayRule.objects.count() == 1
|
||||
assert SharedCustodyPeriod.objects.count() == 6
|
||||
|
||||
resp = resp.click('Add custody rule during holidays')
|
||||
resp.form['guardian'] = father.pk
|
||||
resp.form['holiday'].select(text='Vacances de Noël')
|
||||
resp.form['periodicity'] = 'first-and-third-quarters'
|
||||
resp = resp.form.submit()
|
||||
assert 'Short holidays cannot be cut into quarters.' in resp.text
|
||||
|
||||
resp.form['holiday'].select(text='Vacances d’Été')
|
||||
resp = resp.form.submit().follow()
|
||||
assert 'John Doe, Vacances d’Été, the first and third quarters' in resp.text
|
||||
|
||||
# if dates get deleted, rules still exist but holiday is not shown anymore
|
||||
summer_holidays = TimePeriodExceptionGroup.objects.get(slug='summer_holidays')
|
||||
summer_holidays.exceptions.all().delete()
|
||||
|
||||
assert SharedCustodyHolidayRule.objects.filter(holiday=summer_holidays).exists()
|
||||
|
||||
resp = resp.click('Add custody rule during holidays')
|
||||
assert [x[2] for x in resp.form['holiday'].options] == ['---------', 'Vacances de Noël']
|
||||
|
|
|
@ -27,6 +27,7 @@ from chrono.agendas.models import (
|
|||
Person,
|
||||
Resource,
|
||||
SharedCustodyAgenda,
|
||||
SharedCustodyHolidayRule,
|
||||
SharedCustodyPeriod,
|
||||
SharedCustodyRule,
|
||||
TimePeriod,
|
||||
|
@ -2913,6 +2914,64 @@ def test_shared_custody_agenda_rule_overlaps(rules, days, weeks, overlaps):
|
|||
assert agenda.rule_overlaps(days, weeks) is overlaps
|
||||
|
||||
|
||||
def test_shared_custody_agenda_holiday_rule_overlaps():
|
||||
calendar = UnavailabilityCalendar.objects.create(label='Calendar')
|
||||
|
||||
father = Person.objects.create(user_external_id='father_id', name='John Doe')
|
||||
mother = Person.objects.create(user_external_id='mother_id', name='Jane Doe')
|
||||
agenda = SharedCustodyAgenda.objects.create(first_guardian=father, second_guardian=mother)
|
||||
|
||||
summer_holiday = TimePeriodExceptionGroup.objects.create(
|
||||
unavailability_calendar=calendar, label='Summer', slug='summer'
|
||||
)
|
||||
winter_holiday = TimePeriodExceptionGroup.objects.create(
|
||||
unavailability_calendar=calendar, label='Winter', slug='winter'
|
||||
)
|
||||
|
||||
rule = SharedCustodyHolidayRule.objects.create(agenda=agenda, guardian=father, holiday=summer_holiday)
|
||||
assert agenda.holiday_rule_overlaps(summer_holiday, years='', periodicity='') is True
|
||||
assert agenda.holiday_rule_overlaps(summer_holiday, years='', periodicity='', instance=rule) is False
|
||||
assert agenda.holiday_rule_overlaps(winter_holiday, years='', periodicity='') is False
|
||||
assert agenda.holiday_rule_overlaps(summer_holiday, years='odd', periodicity='') is True
|
||||
assert agenda.holiday_rule_overlaps(summer_holiday, years='', periodicity='first-half') is True
|
||||
|
||||
rule.years = 'odd'
|
||||
rule.save()
|
||||
assert agenda.holiday_rule_overlaps(summer_holiday, years='', periodicity='') is True
|
||||
assert agenda.holiday_rule_overlaps(summer_holiday, years='odd', periodicity='') is True
|
||||
assert agenda.holiday_rule_overlaps(summer_holiday, years='even', periodicity='') is False
|
||||
|
||||
rule.periodicity = 'first-half'
|
||||
rule.save()
|
||||
assert agenda.holiday_rule_overlaps(summer_holiday, years='', periodicity='') is True
|
||||
assert agenda.holiday_rule_overlaps(summer_holiday, years='odd', periodicity='first-half') is True
|
||||
assert agenda.holiday_rule_overlaps(summer_holiday, years='odd', periodicity='second-half') is False
|
||||
assert (
|
||||
agenda.holiday_rule_overlaps(summer_holiday, years='odd', periodicity='first-and-third-quarters')
|
||||
is True
|
||||
)
|
||||
assert (
|
||||
agenda.holiday_rule_overlaps(summer_holiday, years='odd', periodicity='second-and-fourth-quarters')
|
||||
is True
|
||||
)
|
||||
assert agenda.holiday_rule_overlaps(summer_holiday, years='even', periodicity='first-half') is False
|
||||
|
||||
rule.periodicity = 'second-and-fourth-quarters'
|
||||
rule.save()
|
||||
assert agenda.holiday_rule_overlaps(summer_holiday, years='', periodicity='') is True
|
||||
assert agenda.holiday_rule_overlaps(summer_holiday, years='odd', periodicity='first-half') is True
|
||||
assert agenda.holiday_rule_overlaps(summer_holiday, years='odd', periodicity='second-half') is True
|
||||
assert (
|
||||
agenda.holiday_rule_overlaps(summer_holiday, years='odd', periodicity='first-and-third-quarters')
|
||||
is False
|
||||
)
|
||||
assert (
|
||||
agenda.holiday_rule_overlaps(summer_holiday, years='odd', periodicity='second-and-fourth-quarters')
|
||||
is True
|
||||
)
|
||||
assert agenda.holiday_rule_overlaps(summer_holiday, years='even', periodicity='first-half') is False
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'periods,date_start,date_end,overlaps',
|
||||
(
|
||||
|
@ -2941,6 +3000,25 @@ def test_shared_custody_agenda_period_overlaps(periods, date_start, date_end, ov
|
|||
assert agenda.period_overlaps(date_start, date_end) is overlaps
|
||||
|
||||
|
||||
def test_shared_custody_agenda_period_holiday_rule_no_overlaps():
|
||||
calendar = UnavailabilityCalendar.objects.create(label='Calendar')
|
||||
|
||||
father = Person.objects.create(user_external_id='father_id', name='John Doe')
|
||||
mother = Person.objects.create(user_external_id='mother_id', name='Jane Doe')
|
||||
agenda = SharedCustodyAgenda.objects.create(first_guardian=father, second_guardian=mother)
|
||||
|
||||
summer_holiday = TimePeriodExceptionGroup.objects.create(
|
||||
unavailability_calendar=calendar, label='Summer', slug='summer'
|
||||
)
|
||||
|
||||
rule = SharedCustodyHolidayRule.objects.create(agenda=agenda, guardian=father, holiday=summer_holiday)
|
||||
SharedCustodyPeriod.objects.create(
|
||||
holiday_rule=rule, agenda=agenda, guardian=father, date_start='2022-02-03', date_end='2022-02-05'
|
||||
)
|
||||
|
||||
assert agenda.period_overlaps('2022-02-03', '2022-02-05') is False
|
||||
|
||||
|
||||
def test_shared_custody_agenda_rule_label():
|
||||
father = Person.objects.create(user_external_id='father_id', name='John Doe')
|
||||
mother = Person.objects.create(user_external_id='mother_id', name='Jane Doe')
|
||||
|
@ -2971,6 +3049,46 @@ def test_shared_custody_agenda_rule_label():
|
|||
assert rule.label == 'on Mondays, on odd weeks'
|
||||
|
||||
|
||||
def test_shared_custody_agenda_holiday_rule_label():
|
||||
calendar = UnavailabilityCalendar.objects.create(label='Calendar')
|
||||
|
||||
father = Person.objects.create(user_external_id='father_id', name='John Doe')
|
||||
mother = Person.objects.create(user_external_id='mother_id', name='Jane Doe')
|
||||
agenda = SharedCustodyAgenda.objects.create(first_guardian=father, second_guardian=mother)
|
||||
|
||||
summer_holiday = TimePeriodExceptionGroup.objects.create(
|
||||
unavailability_calendar=calendar, label='Summer Holidays', slug='summer'
|
||||
)
|
||||
|
||||
rule = SharedCustodyHolidayRule.objects.create(agenda=agenda, guardian=father, holiday=summer_holiday)
|
||||
assert rule.label == 'Summer Holidays'
|
||||
|
||||
rule.years = 'even'
|
||||
rule.save()
|
||||
assert rule.label == 'Summer Holidays, on even years'
|
||||
|
||||
rule.years = 'odd'
|
||||
rule.save()
|
||||
assert rule.label == 'Summer Holidays, on odd years'
|
||||
|
||||
rule.periodicity = 'first-half'
|
||||
rule.save()
|
||||
assert rule.label == 'Summer Holidays, the first half, on odd years'
|
||||
|
||||
rule.years = ''
|
||||
rule.periodicity = 'second-half'
|
||||
rule.save()
|
||||
assert rule.label == 'Summer Holidays, the second half'
|
||||
|
||||
rule.periodicity = 'first-and-third-quarters'
|
||||
rule.save()
|
||||
assert rule.label == 'Summer Holidays, the first and third quarters'
|
||||
|
||||
rule.periodicity = 'second-and-fourth-quarters'
|
||||
rule.save()
|
||||
assert rule.label == 'Summer Holidays, the second and fourth quarters'
|
||||
|
||||
|
||||
def test_shared_custody_agenda_period_label(freezer):
|
||||
father = Person.objects.create(user_external_id='father_id', name='John Doe')
|
||||
mother = Person.objects.create(user_external_id='mother_id', name='Jane Doe')
|
||||
|
@ -2987,3 +3105,197 @@ def test_shared_custody_agenda_period_label(freezer):
|
|||
period.date_end = datetime.date(2021, 7, 13)
|
||||
period.save()
|
||||
assert str(period) == 'John Doe, 07/10/2021 → 07/13/2021'
|
||||
|
||||
|
||||
def test_shared_custody_agenda_holiday_rule_create_periods():
|
||||
calendar = UnavailabilityCalendar.objects.create(label='Calendar')
|
||||
|
||||
father = Person.objects.create(user_external_id='father_id', name='John Doe')
|
||||
mother = Person.objects.create(user_external_id='mother_id', name='Jane Doe')
|
||||
agenda = SharedCustodyAgenda.objects.create(first_guardian=father, second_guardian=mother)
|
||||
|
||||
summer_holiday = TimePeriodExceptionGroup.objects.create(
|
||||
unavailability_calendar=calendar, label='Summer', slug='summer'
|
||||
)
|
||||
TimePeriodException.objects.create(
|
||||
unavailability_calendar=calendar,
|
||||
start_datetime=make_aware(datetime.datetime(year=2021, month=7, day=6, hour=0, minute=0)),
|
||||
end_datetime=make_aware(datetime.datetime(year=2021, month=9, day=2, hour=0, minute=0)),
|
||||
group=summer_holiday,
|
||||
)
|
||||
TimePeriodException.objects.create(
|
||||
unavailability_calendar=calendar,
|
||||
start_datetime=make_aware(datetime.datetime(year=2022, month=7, day=7, hour=0, minute=0)),
|
||||
end_datetime=make_aware(datetime.datetime(year=2022, month=9, day=1, hour=0, minute=0)),
|
||||
group=summer_holiday,
|
||||
)
|
||||
|
||||
rule = SharedCustodyHolidayRule.objects.create(agenda=agenda, guardian=father, holiday=summer_holiday)
|
||||
rule.update_or_create_periods()
|
||||
period1, period2 = SharedCustodyPeriod.objects.all()
|
||||
assert period1.holiday_rule == rule
|
||||
assert period1.guardian == father
|
||||
assert period1.agenda == agenda
|
||||
assert period1.date_start == datetime.date(year=2021, month=7, day=6)
|
||||
assert period1.date_end == datetime.date(year=2021, month=9, day=2)
|
||||
assert period2.holiday_rule == rule
|
||||
assert period2.guardian == father
|
||||
assert period2.agenda == agenda
|
||||
assert period2.date_start == datetime.date(year=2022, month=7, day=7)
|
||||
assert period2.date_end == datetime.date(year=2022, month=9, day=1)
|
||||
|
||||
rule.years = 'odd'
|
||||
rule.update_or_create_periods()
|
||||
period = SharedCustodyPeriod.objects.get()
|
||||
assert period.date_start == datetime.date(year=2021, month=7, day=6)
|
||||
assert period.date_end == datetime.date(year=2021, month=9, day=2)
|
||||
|
||||
rule.years = 'even'
|
||||
rule.update_or_create_periods()
|
||||
period = SharedCustodyPeriod.objects.get()
|
||||
assert period.date_start == datetime.date(year=2022, month=7, day=7)
|
||||
assert period.date_end == datetime.date(year=2022, month=9, day=1)
|
||||
|
||||
rule.years = ''
|
||||
rule.periodicity = 'first-half'
|
||||
rule.update_or_create_periods()
|
||||
period1, period2 = SharedCustodyPeriod.objects.all()
|
||||
assert period1.date_start == datetime.date(year=2021, month=7, day=6)
|
||||
assert period1.date_end == datetime.date(year=2021, month=8, day=1)
|
||||
assert period1.date_end.weekday() == 6
|
||||
assert period2.date_start == datetime.date(year=2022, month=7, day=7)
|
||||
assert period2.date_end == datetime.date(year=2022, month=7, day=31)
|
||||
assert period2.date_end.weekday() == 6
|
||||
|
||||
rule.periodicity = 'second-half'
|
||||
rule.update_or_create_periods()
|
||||
period1, period2 = SharedCustodyPeriod.objects.all()
|
||||
assert period1.date_start == datetime.date(year=2021, month=8, day=1)
|
||||
assert period1.date_start.weekday() == 6
|
||||
assert period1.date_end == datetime.date(year=2021, month=9, day=2)
|
||||
assert period2.date_start == datetime.date(year=2022, month=7, day=31)
|
||||
assert period2.date_start.weekday() == 6
|
||||
assert period2.date_end == datetime.date(year=2022, month=9, day=1)
|
||||
|
||||
rule.periodicity = 'first-and-third-quarters'
|
||||
rule.update_or_create_periods()
|
||||
period1, period2, period3, period4 = SharedCustodyPeriod.objects.all()
|
||||
assert period1.date_start == datetime.date(year=2021, month=7, day=6)
|
||||
assert period1.date_end == datetime.date(year=2021, month=7, day=25)
|
||||
assert period1.date_end.weekday() == 6
|
||||
assert period2.date_start == datetime.date(year=2021, month=8, day=8)
|
||||
assert period2.date_end == datetime.date(year=2021, month=8, day=22)
|
||||
assert period2.date_end.weekday() == 6
|
||||
assert period3.date_start == datetime.date(year=2022, month=7, day=7)
|
||||
assert period3.date_end == datetime.date(year=2022, month=7, day=24)
|
||||
assert period3.date_end.weekday() == 6
|
||||
assert period4.date_start == datetime.date(year=2022, month=8, day=7)
|
||||
assert period4.date_end == datetime.date(year=2022, month=8, day=21)
|
||||
assert period4.date_end.weekday() == 6
|
||||
|
||||
rule.periodicity = 'second-and-fourth-quarters'
|
||||
rule.update_or_create_periods()
|
||||
period1, period2, period3, period4 = SharedCustodyPeriod.objects.all()
|
||||
assert period1.date_start == datetime.date(year=2021, month=7, day=25)
|
||||
assert period1.date_start.weekday() == 6
|
||||
assert period1.date_end == datetime.date(year=2021, month=8, day=8)
|
||||
assert period2.date_start == datetime.date(year=2021, month=8, day=22)
|
||||
assert period2.date_start.weekday() == 6
|
||||
assert period2.date_end == datetime.date(year=2021, month=9, day=2)
|
||||
assert period3.date_start == datetime.date(year=2022, month=7, day=24)
|
||||
assert period3.date_start.weekday() == 6
|
||||
assert period3.date_end == datetime.date(year=2022, month=8, day=7)
|
||||
assert period4.date_start == datetime.date(year=2022, month=8, day=21)
|
||||
assert period4.date_start.weekday() == 6
|
||||
assert period4.date_end == datetime.date(year=2022, month=9, day=1)
|
||||
|
||||
|
||||
def test_shared_custody_agenda_holiday_rule_create_periods_christmas_holidays():
|
||||
calendar = UnavailabilityCalendar.objects.create(label='Calendar')
|
||||
|
||||
father = Person.objects.create(user_external_id='father_id', name='John Doe')
|
||||
mother = Person.objects.create(user_external_id='mother_id', name='Jane Doe')
|
||||
agenda = SharedCustodyAgenda.objects.create(first_guardian=father, second_guardian=mother)
|
||||
|
||||
christmas_holiday = TimePeriodExceptionGroup.objects.create(
|
||||
unavailability_calendar=calendar, label='Christmas', slug='christmas'
|
||||
)
|
||||
TimePeriodException.objects.create(
|
||||
unavailability_calendar=calendar,
|
||||
start_datetime=make_aware(datetime.datetime(year=2021, month=12, day=18, hour=0, minute=0)),
|
||||
end_datetime=make_aware(datetime.datetime(year=2022, month=1, day=3, hour=0, minute=0)),
|
||||
group=christmas_holiday,
|
||||
)
|
||||
TimePeriodException.objects.create(
|
||||
unavailability_calendar=calendar,
|
||||
start_datetime=make_aware(datetime.datetime(year=2022, month=12, day=17, hour=0, minute=0)),
|
||||
end_datetime=make_aware(datetime.datetime(year=2023, month=1, day=3, hour=0, minute=0)),
|
||||
group=christmas_holiday,
|
||||
)
|
||||
|
||||
rule = SharedCustodyHolidayRule.objects.create(agenda=agenda, guardian=father, holiday=christmas_holiday)
|
||||
rule.update_or_create_periods()
|
||||
period1, period2 = SharedCustodyPeriod.objects.all()
|
||||
assert period1.date_start == datetime.date(year=2021, month=12, day=18)
|
||||
assert period1.date_end == datetime.date(year=2022, month=1, day=3)
|
||||
assert period2.date_start == datetime.date(year=2022, month=12, day=17)
|
||||
assert period2.date_end == datetime.date(year=2023, month=1, day=3)
|
||||
|
||||
rule.periodicity = 'first-half'
|
||||
rule.update_or_create_periods()
|
||||
period1, period2 = SharedCustodyPeriod.objects.all()
|
||||
assert period1.date_start == datetime.date(year=2021, month=12, day=18)
|
||||
assert period1.date_end == datetime.date(year=2021, month=12, day=26)
|
||||
assert period1.date_end.weekday() == 6
|
||||
assert period2.date_start == datetime.date(year=2022, month=12, day=17)
|
||||
assert period2.date_end == datetime.date(year=2022, month=12, day=25)
|
||||
assert period2.date_end.weekday() == 6
|
||||
|
||||
rule.periodicity = 'second-half'
|
||||
rule.update_or_create_periods()
|
||||
period1, period2 = SharedCustodyPeriod.objects.all()
|
||||
assert period1.date_start == datetime.date(year=2021, month=12, day=26)
|
||||
assert period1.date_start.weekday() == 6
|
||||
assert period1.date_end == datetime.date(year=2022, month=1, day=3)
|
||||
assert period2.date_start == datetime.date(year=2022, month=12, day=25)
|
||||
assert period2.date_start.weekday() == 6
|
||||
assert period2.date_end == datetime.date(year=2023, month=1, day=3)
|
||||
|
||||
rule.periodicity = 'first-and-third-quarters'
|
||||
rule.update_or_create_periods()
|
||||
assert not SharedCustodyPeriod.objects.exists()
|
||||
|
||||
rule.periodicity = 'second-and-fourth-quarters'
|
||||
rule.update_or_create_periods()
|
||||
assert not SharedCustodyPeriod.objects.exists()
|
||||
|
||||
|
||||
def test_shared_custody_agenda_holiday_rules_application():
|
||||
calendar = UnavailabilityCalendar.objects.create(label='Calendar')
|
||||
|
||||
father = Person.objects.create(user_external_id='father_id', name='John Doe')
|
||||
mother = Person.objects.create(user_external_id='mother_id', name='Jane Doe')
|
||||
agenda = SharedCustodyAgenda.objects.create(first_guardian=father, second_guardian=mother)
|
||||
|
||||
christmas_holiday = TimePeriodExceptionGroup.objects.create(
|
||||
unavailability_calendar=calendar, label='Christmas', slug='christmas'
|
||||
)
|
||||
TimePeriodException.objects.create(
|
||||
unavailability_calendar=calendar,
|
||||
start_datetime=make_aware(datetime.datetime(year=2021, month=12, day=18, hour=0, minute=0)),
|
||||
end_datetime=make_aware(datetime.datetime(year=2022, month=1, day=3, hour=0, minute=0)),
|
||||
group=christmas_holiday,
|
||||
)
|
||||
|
||||
SharedCustodyRule.objects.create(agenda=agenda, days=list(range(7)), weeks='even', guardian=father)
|
||||
SharedCustodyRule.objects.create(agenda=agenda, days=list(range(7)), weeks='odd', guardian=mother)
|
||||
|
||||
rule = SharedCustodyHolidayRule.objects.create(agenda=agenda, guardian=father, holiday=christmas_holiday)
|
||||
rule.update_or_create_periods()
|
||||
|
||||
date_start = datetime.date(year=2021, month=12, day=13) # Monday, even week
|
||||
slots = agenda.get_custody_slots(date_start, date_start + datetime.timedelta(days=30))
|
||||
guardians = [x.guardian.name for x in slots]
|
||||
assert all(name == 'John Doe' for name in guardians[:21])
|
||||
assert all(name == 'Jane Doe' for name in guardians[21:28])
|
||||
assert all(name == 'John Doe' for name in guardians[28:])
|
||||
|
|
Loading…
Reference in New Issue