Merge remote-tracking branch 'origin/matiasb-combine-same-shift-events' into new-schedules

This commit is contained in:
Maxim 2022-08-15 16:58:48 +03:00
commit a01a39875d
3 changed files with 120 additions and 7 deletions

View file

@ -557,9 +557,9 @@ def test_filter_events_range_calendar(
"schedule": schedule,
}
on_call_shift = make_on_call_shift(
organization=organization, shift_type=CustomOnCallShift.TYPE_RECURRENT_EVENT, **data
organization=organization, shift_type=CustomOnCallShift.TYPE_ROLLING_USERS_EVENT, **data
)
on_call_shift.users.add(user)
on_call_shift.add_rolling_users([[user]])
# add override shift
override_start = request_date + timezone.timedelta(seconds=3600)
@ -640,9 +640,9 @@ def test_filter_events_overrides(
"schedule": schedule,
}
on_call_shift = make_on_call_shift(
organization=organization, shift_type=CustomOnCallShift.TYPE_RECURRENT_EVENT, **data
organization=organization, shift_type=CustomOnCallShift.TYPE_ROLLING_USERS_EVENT, **data
)
on_call_shift.users.add(user)
on_call_shift.add_rolling_users([[user]])
# add override shift
override_start = request_date + timezone.timedelta(seconds=3600)
@ -735,9 +735,9 @@ def test_filter_events_final_schedule(
"schedule": schedule,
}
on_call_shift = make_on_call_shift(
organization=organization, shift_type=CustomOnCallShift.TYPE_RECURRENT_EVENT, **data
organization=organization, shift_type=CustomOnCallShift.TYPE_ROLLING_USERS_EVENT, **data
)
on_call_shift.users.add(user)
on_call_shift.add_rolling_users([[user]])
# override: 22-23 / E
override_data = {
@ -868,6 +868,97 @@ def test_next_shifts_per_user(
assert returned_data == expected
@pytest.mark.django_db
def test_merging_same_shift_events(
make_organization_and_user_with_plugin_token,
make_user_for_organization,
make_user_auth_headers,
make_schedule,
make_on_call_shift,
):
organization, user, token = make_organization_and_user_with_plugin_token()
client = APIClient()
schedule = make_schedule(
organization,
schedule_class=OnCallScheduleWeb,
name="test_web_schedule",
)
now = timezone.now().replace(hour=0, minute=0, second=0, microsecond=0)
start_date = now - timezone.timedelta(days=7)
request_date = start_date
user_a = make_user_for_organization(organization)
user_b = make_user_for_organization(organization)
user_c = make_user_for_organization(organization, role=Role.VIEWER)
data = {
"start": start_date + timezone.timedelta(hours=10),
"rotation_start": start_date,
"duration": timezone.timedelta(hours=2),
"priority_level": 1,
"frequency": CustomOnCallShift.FREQUENCY_DAILY,
"schedule": schedule,
}
on_call_shift = make_on_call_shift(
organization=organization, shift_type=CustomOnCallShift.TYPE_ROLLING_USERS_EVENT, **data
)
on_call_shift.add_rolling_users([[user_a, user_c, user_b]])
expected_events = [
{
"calendar_type": 0,
"end": start_date + timezone.timedelta(hours=12),
"is_gap": False,
"priority_level": 1,
"start": start_date + timezone.timedelta(hours=10),
"users": [user_a.username, user_b.username],
"missing_users": [user_c.username],
}
]
# final schedule
url = reverse("api-internal:schedule-filter-events", kwargs={"pk": schedule.public_primary_key})
url += "?date={}&days=1".format(request_date.strftime("%Y-%m-%d"))
response = client.get(url, format="json", **make_user_auth_headers(user, token))
assert response.status_code == status.HTTP_200_OK
returned_events = [
{
"calendar_type": e["calendar_type"],
"end": e["end"],
"is_gap": e["is_gap"],
"priority_level": e["priority_level"],
"start": e["start"],
"users": [u["display_name"] for u in e["users"]] if e["users"] else None,
"missing_users": e["missing_users"],
}
for e in response.data["events"]
if not e["is_gap"]
]
assert returned_events == expected_events
# rotations
url = reverse("api-internal:schedule-filter-events", kwargs={"pk": schedule.public_primary_key})
url += "?date={}&days=1&type=rotation".format(request_date.strftime("%Y-%m-%d"))
response = client.get(url, format="json", **make_user_auth_headers(user, token))
assert response.status_code == status.HTTP_200_OK
returned_events = [
{
"calendar_type": e["calendar_type"],
"end": e["end"],
"is_gap": e["is_gap"],
"priority_level": e["priority_level"],
"start": e["start"],
"users": [u["display_name"] for u in e["users"]] if e["users"] else None,
"missing_users": e["missing_users"],
}
for e in response.data["events"]
if not e["is_gap"]
]
assert returned_events == expected_events
@pytest.mark.django_db
def test_filter_events_invalid_type(
make_organization_and_user_with_plugin_token,

View file

@ -240,6 +240,9 @@ class ScheduleView(
else: # return final schedule
events = schedule.final_events(user_tz, starting_date, days)
# combine multiple-users same-shift events into one
events = self._merge_events(events)
result = {
"id": schedule.public_primary_key,
"name": schedule.name,
@ -248,6 +251,25 @@ class ScheduleView(
}
return Response(result, status=status.HTTP_200_OK)
def _merge_events(self, events):
"""Merge user groups same-shift events."""
if events:
merged = [events[0]]
current = merged[0]
for next_event in events[1:]:
if (
current["start"] == next_event["start"]
and current["shift"]["pk"] is not None
and current["shift"]["pk"] == next_event["shift"]["pk"]
):
current["users"] += next_event["users"]
current["missing_users"] += next_event["missing_users"]
else:
merged.append(next_event)
current = next_event
events = merged
return events
@action(detail=True, methods=["get"])
def next_shifts_per_user(self, request, pk):
"""Return next shift for users in schedule."""

View file

@ -365,7 +365,7 @@ class OnCallSchedule(PolymorphicModel):
# event starts after the current interval, move to next interval and go through it
current_interval_idx += 1
resolved.sort(key=lambda e: e["start"])
resolved.sort(key=lambda e: (e["start"], e["shift"]["pk"]))
return resolved