Skip to content

Commit f1333c5

Browse files
committed
Task chunk series: Update task chunk durations
1 parent 1717a6e commit f1333c5

File tree

3 files changed

+139
-3
lines changed

3 files changed

+139
-3
lines changed

task/models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,13 +231,13 @@ def clean_scheduled(self) -> List[int]:
231231
if self.end:
232232
chunks |= self.chunks.filter(day__gt=self.end)
233233
ids = [chunk.id for chunk in chunks]
234-
total_duration = sum(chunk.duration for chunk in chunks)
234+
cleaned_duration = sum(chunk.duration for chunk in chunks)
235235
chunks.delete()
236236

237237
self.last_scheduled_day = self.chunks.aggregate(Max('day'))['day__max']
238238
self.save(update_fields=('last_scheduled_day',))
239239

240-
self.task.duration = F('duration') - total_duration
240+
self.task.duration = F('duration') - cleaned_duration
241241
self.task.save(update_fields=('duration',))
242242
# refresh the task from the db to get the actual duration value
243243
self.task.refresh_from_db()

task/serializers.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from django.core.exceptions import ObjectDoesNotExist
77
from django.db import transaction
8+
from django.db.models import F
89
from rest_framework import serializers
910
from rest_framework.exceptions import ErrorDetail, ValidationError
1011

@@ -289,6 +290,20 @@ def validate(self, data):
289290

290291
return data
291292

293+
@transaction.atomic
294+
def update(self, instance, validated_data):
295+
if validated_data['duration'] != instance.duration:
296+
# duration changed, update chunks duration
297+
updated = instance.chunks.filter(duration=instance.duration).update(
298+
duration=validated_data['duration'])
299+
additional_duration = updated * (validated_data['duration'] - instance.duration)
300+
instance.task.duration = F('duration') + additional_duration
301+
instance.task.save(update_fields=('duration',))
302+
# refresh the task from the db to get the actual duration value
303+
instance.task.refresh_from_db()
304+
305+
return super().update(instance, validated_data)
306+
292307
def _update_errors(
293308
self, data: dict, errors: DefaultDict[str, List],
294309
required: List[str], disallowed: List[str]):

task/tests.py

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3522,6 +3522,7 @@ def test_update_interval(self):
35223522

35233523
serializer = TaskChunkSeriesSerializer(instance=instance, data={
35243524
'task_id': self.task.pk,
3525+
'duration': 1,
35253526
'start': '2010-02-24',
35263527
'rule': 'interval',
35273528
'interval_days': 7,
@@ -3624,6 +3625,7 @@ def test_validation_update_change_end(self):
36243625

36253626
serializer = TaskChunkSeriesSerializer(instance=instance, data={
36263627
'task_id': self.task.pk,
3628+
'duration': 1,
36273629
'start': '2010-02-24',
36283630
'end': '2010-05-01',
36293631
'rule': 'interval',
@@ -3881,7 +3883,7 @@ def test_update_cleaning(self):
38813883

38823884
resp = self.client.put('/task/chunk/series/{}/'.format(series.pk), {
38833885
'task_id': self.task.pk,
3884-
'duration': '2',
3886+
'duration': '1',
38853887
'start': '2010-05-03',
38863888
'end': '2010-05-10',
38873889
'rule': 'interval',
@@ -3912,6 +3914,125 @@ def test_update_cleaning(self):
39123914
self.task.duration,
39133915
initial_task_duration - 2)
39143916

3917+
@freeze_time('2010-05-03')
3918+
def test_update_duration(self):
3919+
"""
3920+
Test updating the duration of a task chunk series.
3921+
"""
3922+
series = TaskChunkSeries.objects.create(
3923+
task=self.task,
3924+
start=date(2010, 5, 3),
3925+
end=date(2010, 5, 24),
3926+
rule='interval',
3927+
interval_days=7)
3928+
series.schedule()
3929+
3930+
self.assertEqual(
3931+
TaskChunkSeries.objects.count(),
3932+
1)
3933+
self.assertEqual(
3934+
TaskChunk.objects.count(),
3935+
4)
3936+
3937+
resp = self.client.put('/task/chunk/series/{}/'.format(series.pk), {
3938+
'task_id': self.task.pk,
3939+
'duration': 5,
3940+
'start': '2010-05-03',
3941+
'end': '2010-05-24',
3942+
'rule': 'interval',
3943+
'interval_days': 7,
3944+
})
3945+
self.assertEqual(
3946+
resp.status_code,
3947+
status.HTTP_200_OK)
3948+
3949+
self.assertSetEqual(
3950+
set(resp.data.keys()),
3951+
{'series', 'cleaned', 'scheduled', 'task'})
3952+
3953+
self.assertEqual(
3954+
len(resp.data['cleaned']),
3955+
0)
3956+
self.assertEqual(
3957+
len(resp.data['scheduled']),
3958+
0)
3959+
3960+
self.assertEqual(
3961+
TaskChunk.objects.count(),
3962+
4)
3963+
3964+
# each chunk is increased to the new duration of 5
3965+
initial_task_duration = self.task.duration
3966+
self.task.refresh_from_db()
3967+
self.assertEqual(
3968+
self.task.duration,
3969+
initial_task_duration + 4 * (5 - 1))
3970+
self.assertEqual(
3971+
Decimal(resp.data['task']['duration']),
3972+
initial_task_duration + 4 * (5 - 1))
3973+
3974+
@freeze_time('2010-05-03')
3975+
def test_update_duration_modified(self):
3976+
"""
3977+
Test updating the duration of a task chunk series when the duration
3978+
of a task chunk was already modified.
3979+
"""
3980+
series = TaskChunkSeries.objects.create(
3981+
task=self.task,
3982+
start=date(2010, 5, 3),
3983+
end=date(2010, 5, 24),
3984+
rule='interval',
3985+
interval_days=7)
3986+
series.schedule()
3987+
3988+
self.assertEqual(
3989+
TaskChunkSeries.objects.count(),
3990+
1)
3991+
self.assertEqual(
3992+
TaskChunk.objects.count(),
3993+
4)
3994+
3995+
chunk = TaskChunk.objects.last()
3996+
chunk.duration = 3
3997+
chunk.save()
3998+
3999+
resp = self.client.put('/task/chunk/series/{}/'.format(series.pk), {
4000+
'task_id': self.task.pk,
4001+
'duration': 5,
4002+
'start': '2010-05-03',
4003+
'end': '2010-05-24',
4004+
'rule': 'interval',
4005+
'interval_days': 7,
4006+
})
4007+
self.assertEqual(
4008+
resp.status_code,
4009+
status.HTTP_200_OK)
4010+
4011+
self.assertSetEqual(
4012+
set(resp.data.keys()),
4013+
{'series', 'cleaned', 'scheduled', 'task'})
4014+
4015+
self.assertEqual(
4016+
len(resp.data['cleaned']),
4017+
0)
4018+
self.assertEqual(
4019+
len(resp.data['scheduled']),
4020+
0)
4021+
4022+
self.assertEqual(
4023+
TaskChunk.objects.count(),
4024+
4)
4025+
4026+
# each chunk except for the modified one is increased to the new duration of 5
4027+
initial_task_duration = self.task.duration
4028+
self.task.refresh_from_db()
4029+
self.assertEqual(
4030+
self.task.duration,
4031+
initial_task_duration + 3 * (5 - 1))
4032+
self.assertEqual(
4033+
Decimal(resp.data['task']['duration']),
4034+
initial_task_duration + 3 * (5 - 1))
4035+
39154036
@freeze_time('2010-05-03')
39164037
def test_update_scheduling(self):
39174038
"""

0 commit comments

Comments
 (0)