forked from Mapan/odoo17e
375 lines
21 KiB
Python
375 lines
21 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from datetime import datetime, timedelta
|
|
from dateutil.relativedelta import relativedelta
|
|
from freezegun import freeze_time
|
|
|
|
from odoo.fields import Command
|
|
from odoo.tests.common import users, tagged
|
|
from .gantt_reschedule_dates_common import ProjectEnterpriseGanttRescheduleCommon, fake_now
|
|
|
|
|
|
@tagged('gantt_reschedule')
|
|
@freeze_time(fake_now)
|
|
class TestGanttRescheduleOnTasks(ProjectEnterpriseGanttRescheduleCommon):
|
|
|
|
def test_gantt_reschedule_date_not_active(self):
|
|
""" This test purpose is to ensure that auto shift date feature is not active when it shouldn't:
|
|
* When the task has no project (either the moved task or the linked one (depend_on_ids or dependent_ids).
|
|
* When the calculated planned_start_date is prior to now.
|
|
"""
|
|
|
|
def test_task_3_dates_unchanged(task_1_new_planned_dates, failed_message, domain_force=False, **context):
|
|
task_1 = self.task_1.with_context(context) if domain_force else self.task_1.with_context(**context)
|
|
task_1.write(task_1_new_planned_dates)
|
|
self.gantt_reschedule_backward(self.task_1, self.task_3)
|
|
self.assertEqual(self.task_3_planned_date_begin, self.task_3.planned_date_begin, failed_message)
|
|
self.assertEqual(self.task_3_date_deadline, self.task_3.date_deadline, failed_message)
|
|
task_1.write({
|
|
'planned_date_begin': self.task_1_planned_date_begin,
|
|
'date_deadline': self.task_1_date_deadline,
|
|
})
|
|
|
|
self.task_4.depend_on_ids = [Command.clear()]
|
|
|
|
# Checks that no date shift is made when the moved task has no project_id
|
|
failed_message = "The auto shift date feature should not be triggered after having moved a task that " \
|
|
"does not have a project_id."
|
|
project_id = self.task_1.project_id
|
|
self.task_1.write({
|
|
'project_id': False
|
|
})
|
|
test_task_3_dates_unchanged(self.task_1_date_gantt_reschedule_trigger, failed_message)
|
|
self.task_1.write({
|
|
'project_id': project_id.id
|
|
})
|
|
|
|
# Checks that no date shift is made when the linked task has no project_id
|
|
failed_message = "The auto shift date feature should not be triggered on tasks (depend_on_ids/dependent_ids) " \
|
|
"that do have a project_id."
|
|
project_id = self.task_3.project_id
|
|
self.task_3.write({
|
|
'project_id': False
|
|
})
|
|
test_task_3_dates_unchanged(self.task_1_date_gantt_reschedule_trigger, failed_message)
|
|
self.task_3.write({
|
|
'project_id': project_id.id
|
|
})
|
|
|
|
# Checks that no date shift is made when the new planned_date is prior to the current datetime.
|
|
with freeze_time(self.task_1_no_date_gantt_reschedule_trigger['planned_date_begin'] + relativedelta(weeks=1)):
|
|
failed_message = "The auto shift date feature should not trigger any changes when the new planned_date " \
|
|
"is prior to the current datetime."
|
|
test_task_3_dates_unchanged(self.task_1_date_gantt_reschedule_trigger, failed_message)
|
|
|
|
def test_gantt_reschedule_dependent_task(self):
|
|
""" This test purpose is to ensure that a task B that depends on a task A is shifted forward, up to after
|
|
A date_deadline field value.
|
|
"""
|
|
|
|
self.task_1.write(self.task_1_date_gantt_reschedule_trigger)
|
|
self.gantt_reschedule_forward(self.task_1, self.task_3)
|
|
failed_message = "The auto shift date feature should move forward a dependent tasks."
|
|
self.assertTrue(self.task_1.date_deadline <= self.task_3.planned_date_begin, failed_message)
|
|
|
|
def test_gantt_reschedule_depend_on_task(self):
|
|
""" This test purpose is to ensure that a task A that depends on a task B is shifted backward, up to before
|
|
B planned_date_start field value.
|
|
"""
|
|
self.task_3.write(self.task_3_date_gantt_reschedule_trigger)
|
|
self.gantt_reschedule_backward(self.task_1, self.task_3)
|
|
failed_message = "The auto shift date feature should move backward a task the moved task depends on."
|
|
self.assertTrue(self.task_3.planned_date_begin >= self.task_1.date_deadline, failed_message)
|
|
|
|
@users('admin')
|
|
# @warmup
|
|
def test_gantt_reschedule_on_dependent_task_with_allocated_hours(self):
|
|
""" This test purpose is to ensure that the task planned_date_fields (begin/end) are calculated accordingly to
|
|
the allocated_hours if any. So if a dependent task has to be move forward up to before an unavailable period
|
|
of time and that its allocated_hours is such that the date_deadline would fall into that unavailable
|
|
period, then the date_deadline will be push forward after the unavailable period so that the
|
|
allocated_hours constraint is met.
|
|
"""
|
|
self.task_1.write({
|
|
'planned_date_begin': self.task_3_planned_date_begin,
|
|
'date_deadline': self.task_3_planned_date_begin + (self.task_1_date_deadline - self.task_1_planned_date_begin),
|
|
})
|
|
# FIXME as indeterminately fails. Suspected indeterminate cache invalidation.
|
|
# with self.assertQueryCount(20):
|
|
# self.env.invalidate_all()
|
|
self.gantt_reschedule_forward(self.task_1, self.task_3)
|
|
failed_message = ("The auto shift date feature should take the allocated_hours into account and update the"
|
|
"date_deadline accordingly when moving a task forward.")
|
|
self.assertEqual(
|
|
self.task_3.date_deadline, self.task_3_date_deadline + relativedelta(days=1, hour=9),
|
|
failed_message
|
|
)
|
|
|
|
@users('admin')
|
|
# @warmup
|
|
def test_gantt_reschedule_on_task_depending_on_with_allocated_hours(self):
|
|
""" This test purpose is to ensure that the task planned_date_fields (planned_date_begin/date_deadline) are calculated accordingly to
|
|
the allocated_hours if any. So if a task, that the current task depends on, has to be move backward up to
|
|
after an unavailable period of time and that its allocated_hours is such that the date_deadline would fall
|
|
into that unavailable period, then the planned_date_begin will be push backward before the unavailable
|
|
period so that the allocated_hours constraint is met.
|
|
"""
|
|
new_task_3_begin_date = self.task_1_date_deadline - timedelta(hours=2)
|
|
self.task_3.write({
|
|
'planned_date_begin': new_task_3_begin_date,
|
|
'date_deadline': new_task_3_begin_date + (self.task_3_date_deadline - self.task_3_planned_date_begin),
|
|
})
|
|
# FIXME as indeterminately fails. Suspected indeterminate cache invalidation.
|
|
# with self.assertQueryCount(38):
|
|
# self.env.invalidate_all()
|
|
self.gantt_reschedule_backward(self.task_1, self.task_3)
|
|
failed_message = ("The auto shift date feature should take the allocated_hours into account and update the"
|
|
"planned_date_begin accordingly when moving a task backward.")
|
|
self.assertEqual(self.task_1.planned_date_begin,
|
|
self.task_1_planned_date_begin + relativedelta(days=-1, hour=16), failed_message)
|
|
|
|
@users('admin')
|
|
# @warmup
|
|
def test_gantt_reschedule_on_dependent_task_without_allocated_hours(self):
|
|
""" This test purpose is to ensure that the interval made by the task planned_date_fields (begin/end) is
|
|
preserved when no allocated_hours is set.
|
|
"""
|
|
self.task_3.write({
|
|
'allocated_hours': 0,
|
|
})
|
|
self.task_1.write({
|
|
'planned_date_begin': self.task_3_planned_date_begin,
|
|
'date_deadline': self.task_3_planned_date_begin + (
|
|
self.task_1_date_deadline - self.task_1_planned_date_begin),
|
|
})
|
|
# FIXME as indeterminately fails. Suspected indeterminate cache invalidation.
|
|
# with self.assertQueryCount(38):
|
|
# self.env.invalidate_all()
|
|
self.gantt_reschedule_backward(self.task_1, self.task_3)
|
|
failed_message = "When allocated_hours=0, the auto shift date feature should preserve the time interval between" \
|
|
"planned_date_begin and date_deadline when moving a task forward."
|
|
self.assertEqual(self.task_3.date_deadline - self.task_3.planned_date_begin,
|
|
self.task_3_date_deadline - self.task_3_planned_date_begin, failed_message)
|
|
|
|
@users('admin')
|
|
# @warmup
|
|
def test_gantt_reschedule_on_task_depending_on_without_allocated_hours(self):
|
|
""" This test purpose is to ensure that the interval made by the task planned_date_fields (begin/end) is
|
|
preserved when no allocated_hours is set.
|
|
"""
|
|
new_task_3_begin_date = self.task_1_date_deadline - timedelta(hours=2)
|
|
self.task_1.write({
|
|
'allocated_hours': 0,
|
|
})
|
|
self.task_3.write({
|
|
'planned_date_begin': new_task_3_begin_date,
|
|
'date_deadline': new_task_3_begin_date + (self.task_3_date_deadline - self.task_3_planned_date_begin),
|
|
})
|
|
# FIXME as indeterminately fails. Suspected indeterminate cache invalidation.
|
|
# with self.assertQueryCount(20):
|
|
# self.env.invalidate_all()
|
|
self.gantt_reschedule_forward(self.task_1, self.task_3)
|
|
failed_message = "The auto shift date feature should take the allocated_hours into account and update the" \
|
|
"planned_date_begin accordingly when moving a task backward."
|
|
self.assertEqual(self.task_1.date_deadline - self.task_1.planned_date_begin,
|
|
self.task_1_date_deadline - self.task_1_planned_date_begin, failed_message)
|
|
|
|
@users('admin')
|
|
# @warmup
|
|
def test_gantt_reschedule_next_work_time_with_allocated_hours(self):
|
|
""" This test purpose is to ensure that computed dates are in accordance with the user resource_calendar
|
|
if any is set, or with the user company resource_calendar if not.
|
|
"""
|
|
new_task_1_planned_date_begin = self.task_3_planned_date_begin + timedelta(hours=1)
|
|
self.task_1.write({
|
|
'planned_date_begin': new_task_1_planned_date_begin,
|
|
'date_deadline': new_task_1_planned_date_begin + (
|
|
self.task_1_date_deadline - self.task_1_planned_date_begin),
|
|
})
|
|
# FIXME as indeterminately fails. Suspected indeterminate cache invalidation.
|
|
# with self.assertQueryCount(20):
|
|
# self.env.invalidate_all()
|
|
self.gantt_reschedule_forward(self.task_1, self.task_3)
|
|
failed_message = "The auto shift date feature should take the user company resource_calendar into account."
|
|
self.assertEqual(self.task_3.planned_date_begin,
|
|
self.task_3_planned_date_begin + relativedelta(days=1, hour=8), failed_message)
|
|
|
|
@users('admin')
|
|
# @warmup
|
|
def test_gantt_reschedule_previous_work_time_with_allocated_hours(self):
|
|
""" This test purpose is to ensure that computed dates are in accordance with the user resource_calendar
|
|
if any is set, or with the user company resource_calendar if not.
|
|
"""
|
|
new_task_3_begin_date = self.task_1_planned_date_begin - timedelta(hours=1)
|
|
self.task_3.write({
|
|
'planned_date_begin': new_task_3_begin_date,
|
|
'date_deadline': new_task_3_begin_date + (self.task_3_date_deadline - self.task_3_planned_date_begin),
|
|
})
|
|
# FIXME as indeterminately fails. Suspected indeterminate cache invalidation.
|
|
# with self.assertQueryCount(38):
|
|
# self.env.invalidate_all()
|
|
self.gantt_reschedule_backward(self.task_1, self.task_3)
|
|
failed_message = "The auto shift date feature should take the user company resource_calendar into account."
|
|
self.assertEqual(self.task_1.date_deadline,
|
|
self.task_1_date_deadline + relativedelta(days=-1, hour=17), failed_message)
|
|
|
|
@users('admin')
|
|
# @warmup
|
|
def test_gantt_reschedule_next_work_time_without_allocated_hours(self):
|
|
""" This test purpose is to ensure that computed dates are in accordance with the user resource_calendar
|
|
if any is set, or with the user company resource_calendar if not.
|
|
"""
|
|
new_task_1_planned_date_begin = self.task_3_planned_date_begin + timedelta(hours=1)
|
|
self.task_3.write({
|
|
'allocated_hours': 0,
|
|
})
|
|
self.task_1.write({
|
|
'planned_date_begin': new_task_1_planned_date_begin,
|
|
'date_deadline': new_task_1_planned_date_begin + (self.task_1_date_deadline - self.task_1_planned_date_begin),
|
|
})
|
|
# FIXME as indeterminately fails. Suspected indeterminate cache invalidation.
|
|
# with self.assertQueryCount(20):
|
|
# self.env.invalidate_all()
|
|
self.gantt_reschedule_forward(self.task_1, self.task_3)
|
|
failed_message = "The auto shift date feature should take the user company resource_calendar into account."
|
|
self.assertEqual(self.task_3.planned_date_begin,
|
|
self.task_3_planned_date_begin + relativedelta(days=1, hour=8), failed_message)
|
|
|
|
@users('admin')
|
|
# @warmup
|
|
def test_gantt_reschedule_previous_work_time_without_allocated_hours(self):
|
|
""" This test purpose is to ensure that computed dates are in accordance with the user resource_calendar
|
|
if any is set, or with the user company resource_calendar if not.
|
|
"""
|
|
new_task_3_begin_date = self.task_1_planned_date_begin - timedelta(hours=1)
|
|
self.task_1.write({
|
|
'allocated_hours': 0,
|
|
})
|
|
self.task_3.write({
|
|
'planned_date_begin': new_task_3_begin_date,
|
|
'date_deadline': new_task_3_begin_date + (self.task_3_date_deadline - self.task_3_planned_date_begin),
|
|
})
|
|
# FIXME as indeterminately fails. Suspected indeterminate cache invalidation.
|
|
# with self.assertQueryCount(38):
|
|
# self.env.invalidate_all()
|
|
self.gantt_reschedule_backward(self.task_1, self.task_3)
|
|
failed_message = "The auto shift date feature should take the user company resource_calendar into account."
|
|
self.assertEqual(self.task_1.date_deadline,
|
|
self.task_1_date_deadline + relativedelta(days=-1, hour=17), failed_message)
|
|
|
|
@users('admin')
|
|
# @warmup
|
|
def test_gantt_reschedule_next_work_time_long_leaves(self):
|
|
""" This test purpose is to ensure that computed dates are in accordance with the user resource_calendar
|
|
if any is set, or with the user company resource_calendar if not. This test is made on a long leave period
|
|
to ensure that it works when the new dates are further than the default fetched data. This test focuses on
|
|
ensuring that a task is pushed forward up to after the holiday leave period when a task that it depends on
|
|
is moved so that it creates an overlap between, the tasks.
|
|
"""
|
|
self.task_3.write({
|
|
'planned_date_begin': self.task_4_planned_date_begin,
|
|
'date_deadline': self.task_4_planned_date_begin + (self.task_3_date_deadline - self.task_3_planned_date_begin),
|
|
})
|
|
# FIXME as indeterminately fails. Suspected indeterminate cache invalidation.
|
|
# with self.assertQueryCount(37):
|
|
# self.env.invalidate_all()
|
|
self.gantt_reschedule_forward(self.task_3, self.task_4)
|
|
failed_message = "The auto shift date feature should take the user company resource_calendar into account and" \
|
|
"works also for long periods (requiring extending the search interval period)."
|
|
self.assertEqual(self.task_4.planned_date_begin,
|
|
self.task_4_planned_date_begin + relativedelta(month=8, day=2, hour=8), failed_message)
|
|
|
|
@users('admin')
|
|
# @warmup
|
|
def test_gantt_reschedule_previous_work_time_long_leaves(self):
|
|
""" This test purpose is to ensure that computed dates are in accordance with the user resource_calendar
|
|
if any is set, or with the user company resource_calendar if not. This test is made on a long leave period
|
|
to ensure that it works when the new dates are further than the default fetched data. This test focuses on
|
|
ensuring that a task is pushed backward up to before the holiday leave period when a dependent task is moved
|
|
so that it creates an overlap between the tasks.
|
|
"""
|
|
self.task_6.write({
|
|
'planned_date_begin': self.task_5_planned_date_begin,
|
|
'date_deadline': self.task_5_planned_date_begin + (
|
|
self.task_6_date_deadline - self.task_6_planned_date_begin),
|
|
})
|
|
# FIXME as indeterminately fails. Suspected indeterminate cache invalidation.
|
|
# with self.assertQueryCount(31):
|
|
# self.env.invalidate_all()
|
|
self.gantt_reschedule_backward(self.task_5, self.task_6)
|
|
failed_message = "The auto shift date feature should take the user company resource_calendar into account and" \
|
|
"works also for long periods (requiring extending the search interval period)."
|
|
self.assertEqual(self.task_5.date_deadline,
|
|
self.task_5_date_deadline + relativedelta(month=6, day=30, hour=17), failed_message)
|
|
|
|
@users('admin')
|
|
# @warmup
|
|
def test_gantt_reschedule_cascading_forward(self):
|
|
""" This test purpose is to ensure that the cascade is well supported on dependent tasks
|
|
(task A move impacts B that moves forwards and then impacts C that is moved forward).
|
|
"""
|
|
new_task_3_planned_date_begin = self.task_4_planned_date_begin - timedelta(hours=1)
|
|
self.task_3.write({
|
|
'planned_date_begin': new_task_3_planned_date_begin,
|
|
'date_deadline': new_task_3_planned_date_begin + (self.task_3_date_deadline - self.task_3_planned_date_begin),
|
|
})
|
|
# FIXME as indeterminately fails. Suspected indeterminate cache invalidation.
|
|
# with self.assertQueryCount(43):
|
|
# self.env.invalidate_all()
|
|
self.gantt_reschedule_forward(self.task_3, self.task_4)
|
|
failed_message = "The auto shift date feature should handle correctly dependencies cascades."
|
|
self.assertEqual(self.task_4.planned_date_begin,
|
|
self.task_3.date_deadline, failed_message)
|
|
self.assertEqual(self.task_4.date_deadline,
|
|
self.task_4_planned_date_begin + relativedelta(month=8, day=2, hour=9), failed_message)
|
|
self.assertEqual(self.task_5.planned_date_begin,
|
|
self.task_4.date_deadline, failed_message)
|
|
self.assertEqual(self.task_5.date_deadline,
|
|
self.task_5_date_deadline + relativedelta(days=1, hour=9), failed_message)
|
|
|
|
@users('admin')
|
|
# @warmup
|
|
def test_gantt_reschedule_cascading_backward(self):
|
|
""" This test purpose is to ensure that the cascade is well supported on tasks that the current task depends on
|
|
(task A move impacts B that moves backward and then impacts C that is moved backward).
|
|
"""
|
|
new_task_6_planned_date_begin = self.task_5_planned_date_begin + timedelta(hours=1)
|
|
self.task_6.write({
|
|
'planned_date_begin': new_task_6_planned_date_begin,
|
|
'date_deadline': new_task_6_planned_date_begin + (self.task_6_date_deadline - self.task_6_planned_date_begin),
|
|
})
|
|
# FIXME as indeterminately fails. Suspected indeterminate cache invalidation.
|
|
# with self.assertQueryCount(35):
|
|
# self.env.invalidate_all()
|
|
self.gantt_reschedule_backward(self.task_5, self.task_6)
|
|
failed_message = "The auto shift date feature should handle correctly dependencies cascades."
|
|
self.assertEqual(self.task_5.date_deadline,
|
|
new_task_6_planned_date_begin, failed_message)
|
|
self.assertEqual(self.task_5.planned_date_begin,
|
|
datetime(year=2021, month=6, day=29, hour=9), failed_message)
|
|
self.assertEqual(self.task_4.date_deadline,
|
|
self.task_5.planned_date_begin, failed_message)
|
|
self.assertEqual(self.task_4.planned_date_begin,
|
|
datetime(year=2021, month=6, day=28, hour=16), failed_message)
|
|
|
|
def test_gantt_reschedule_project_user(self):
|
|
""" This test purpose is to ensure that the project user has the sufficient rights to trigger a gantt
|
|
reschedule.
|
|
"""
|
|
new_task_6_planned_date_begin = self.task_5_planned_date_begin + timedelta(hours=1)
|
|
self.task_6.with_user(self.user_projectuser).write({
|
|
'planned_date_begin': new_task_6_planned_date_begin,
|
|
'date_deadline': new_task_6_planned_date_begin + (self.task_6_date_deadline - self.task_6_planned_date_begin),
|
|
})
|
|
self.gantt_reschedule_backward(self.task_5, self.task_6)
|
|
failed_message = "The auto shift date feature should handle correctly dependencies cascades."
|
|
self.assertEqual(self.task_5.date_deadline,
|
|
new_task_6_planned_date_begin, failed_message)
|
|
self.assertEqual(self.task_5.planned_date_begin,
|
|
datetime(year=2021, month=6, day=29, hour=9), failed_message)
|
|
self.assertEqual(self.task_4.date_deadline,
|
|
self.task_5.planned_date_begin, failed_message)
|
|
self.assertEqual(self.task_4.planned_date_begin,
|
|
datetime(year=2021, month=6, day=28, hour=16), failed_message)
|