365 lines
20 KiB
Python
365 lines
20 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from datetime import datetime, timedelta, date
|
|
|
|
from odoo import Command
|
|
from odoo.tests import freeze_time
|
|
from odoo.addons.web_gantt.models.models import Base
|
|
from .common import TestWebGantt
|
|
|
|
|
|
@freeze_time(datetime(2021, 1, 1))
|
|
class TestWebGanttReschedule(TestWebGantt):
|
|
def test_reschedule_cascading_forward(self):
|
|
""" This test purpose is to ensure that the forward rescheduling is properly working. """
|
|
# 1- consume buffer
|
|
res = self.gantt_reschedule_consume_buffer(self.pill_1, {
|
|
self.date_start_field_name: "2021-06-01 00:00:00",
|
|
self.date_stop_field_name: "2021-06-01 10:00:00",
|
|
})
|
|
moved_pills = self.pill_1 | self.pill_2 | self.pill_3 | self.pill_4
|
|
self.assert_old_pills_vals(res, 'success', 'Tasks rescheduled', moved_pills, self.initial_dates)
|
|
self.assertEqual(
|
|
self.pill_1[self.date_stop_field_name], self.pill_2[self.date_start_field_name],
|
|
'Pill 1 should move forward up to start of Pill 2.'
|
|
)
|
|
self.assertEqual(
|
|
self.pill_2[self.date_stop_field_name], self.pill_3[self.date_start_field_name],
|
|
'Pill 2 should move forward up to start of Pill 3.'
|
|
)
|
|
self.assertEqual(
|
|
self.pill_3[self.date_stop_field_name], self.pill_4[self.date_start_field_name],
|
|
'Pill 3 should move forward up to start of Pill 4.'
|
|
)
|
|
moved_pills.action_rollback_scheduling(res['old_vals_per_pill_id'])
|
|
self.assert_not_replanned(moved_pills, self.initial_dates)
|
|
|
|
# 2- maintain buffer
|
|
res = self.gantt_reschedule_maintain_buffer(self.pill_1, {
|
|
self.date_start_field_name: "2021-06-01 00:00:00",
|
|
self.date_stop_field_name: "2021-06-01 10:00:00",
|
|
})
|
|
self.assert_old_pills_vals(res, 'success', 'Tasks rescheduled', moved_pills, self.initial_dates)
|
|
self.assertEqual(
|
|
self.pill_1[self.date_stop_field_name] + timedelta(seconds=self.buffer12), self.pill_2[self.date_start_field_name],
|
|
'Pill 2 should start after buffer12 after the end of Pill 1.'
|
|
)
|
|
self.assertEqual(
|
|
self.pill_2[self.date_stop_field_name] + timedelta(seconds=self.buffer23), self.pill_3[self.date_start_field_name],
|
|
'Pill 3 should start after buffer12 after the end of Pill 2.'
|
|
)
|
|
self.assertEqual(
|
|
self.pill_3[self.date_stop_field_name] + timedelta(seconds=self.buffer34), self.pill_4[self.date_start_field_name],
|
|
'Pill 4 should start after buffer12 after the end of Pill 3.'
|
|
)
|
|
|
|
def test_reschedule_cascading_backward(self):
|
|
""" This test purpose is to ensure that the backward rescheduling is properly working. """
|
|
# 1- consume buffer
|
|
res = self.gantt_reschedule_consume_buffer(self.pill_4, {
|
|
self.date_start_field_name: "2021-03-01 00:00:00",
|
|
self.date_stop_field_name: "2021-03-01 10:00:00",
|
|
})
|
|
moved_pills = self.pill_1 | self.pill_2 | self.pill_3 | self.pill_4
|
|
self.assert_old_pills_vals(res, 'success', 'Tasks rescheduled', moved_pills, self.initial_dates)
|
|
self.assertEqual(
|
|
self.pill_1[self.date_stop_field_name], self.pill_2[self.date_start_field_name],
|
|
'Pill 1 should move backward up to start of Pill 2.'
|
|
)
|
|
self.assertEqual(
|
|
self.pill_2[self.date_stop_field_name], self.pill_3[self.date_start_field_name],
|
|
'Pill 2 should move backward up to start of Pill 3.'
|
|
)
|
|
self.assertEqual(
|
|
self.pill_3[self.date_stop_field_name], self.pill_4[self.date_start_field_name],
|
|
'Pill 3 should move backward up to start of Pill 4.'
|
|
)
|
|
moved_pills.action_rollback_scheduling(res['old_vals_per_pill_id'])
|
|
self.assert_not_replanned(moved_pills, self.initial_dates)
|
|
|
|
# 2- maintain buffer
|
|
res = self.gantt_reschedule_maintain_buffer(self.pill_4, {
|
|
self.date_start_field_name: "2021-03-01 00:00:00",
|
|
self.date_stop_field_name: "2021-03-01 10:00:00",
|
|
})
|
|
self.assert_old_pills_vals(res, 'success', 'Tasks rescheduled', moved_pills, self.initial_dates)
|
|
self.assertEqual(
|
|
self.pill_1[self.date_stop_field_name] + timedelta(seconds=self.buffer12), self.pill_2[self.date_start_field_name],
|
|
'Pill 2 should start after buffer12 after the end of Pill 1.'
|
|
)
|
|
self.assertEqual(
|
|
self.pill_2[self.date_stop_field_name] + timedelta(seconds=self.buffer23), self.pill_3[self.date_start_field_name],
|
|
'Pill 3 should start after buffer12 after the end of Pill 2.'
|
|
)
|
|
self.assertEqual(
|
|
self.pill_3[self.date_stop_field_name] + timedelta(seconds=self.buffer34), self.pill_4[self.date_start_field_name],
|
|
'Pill 4 should start after buffer12 after the end of Pill 3.'
|
|
)
|
|
|
|
def test_not_in_past(self):
|
|
""" This test purpose is to ensure that:
|
|
* Records are not rescheduled in the past.
|
|
* A notification is returned when trying to reschedule a record in the past.
|
|
"""
|
|
res = self.gantt_reschedule_consume_buffer(self.pill_4, {
|
|
self.date_start_field_name: "2021-01-01 00:00:00",
|
|
self.date_stop_field_name: "2021-01-01 10:00:00",
|
|
})
|
|
self.assert_old_pills_vals(res, 'warning', 'Pill 3 cannot be scheduled in the past', self.env['test.web.gantt.pill'], self.initial_dates)
|
|
|
|
def test_conflicting_cascade_forward(self):
|
|
"""
|
|
┌────────────────────────┐ ┌──────────────────────────────────┐
|
|
│pill_2_slave_in_conflict|<---------- -------------------------->| pill_2_slave_not_in_conflict |
|
|
└────────────────────────┘ | | └──────────────────────────────────┘
|
|
┌────────────────────────┐ ┌─────────┐ ┌─────────┐ ┌──────────────────────────────────┐
|
|
│ Pill 1 │ ---> │ Pill 2 │--> │ Pill 3 │ --> │ Pill 4 │
|
|
└────────────────────────┘ └─────────┘ └─────────┘ └──────────────────────────────────┘
|
|
┌────────────────────────┐ | | ┌──────────────────────────────────┐
|
|
│pill_3_slave_in_conflict│<--------------------------- --------->│ pill_3_slave_not_in_conflict │
|
|
└────────────────────────┘ └──────────────────────────────────┘
|
|
|
|
When moving forward without conflicts, we only move records in conflict.
|
|
When advancing pill 3 without creating conflicts with pill_3_slave_not_in_conflict and pill 4, they both should not move.
|
|
we only move pill_3_slave_in_conflict to fix the conflict
|
|
ancestors should not be impacted
|
|
"""
|
|
self.pill_2_slave_in_conflict = self.create_pill(
|
|
'Pill in conflict with Pill 2', self.pill_1_start_date, self.pill_1_stop_date, [self.pill_2.id]
|
|
)
|
|
self.pill_2_slave_not_in_conflict = self.create_pill(
|
|
'Pill not in conflict with Pill 2', self.pill_4_start_date, self.pill_4_stop_date, [self.pill_2.id]
|
|
)
|
|
self.pill_3_slave_in_conflict = self.create_pill(
|
|
'Pill in conflict with Pill 3', self.pill_1_start_date, self.pill_1_stop_date, [self.pill_3.id]
|
|
)
|
|
self.pill_3_slave_not_in_conflict = self.create_pill(
|
|
'Pill not in conflict with Pill 3', self.pill_4_start_date, self.pill_4_stop_date, [self.pill_3.id]
|
|
)
|
|
moved_pills = self.pill_3 | self.pill_3_slave_in_conflict
|
|
initial_dates_deep_copy = dict(self.initial_dates)
|
|
initial_dates_deep_copy[self.pill_3_slave_in_conflict.name] = (self.pill_3_slave_in_conflict.date_start, self.pill_3_slave_in_conflict.date_stop)
|
|
|
|
res = self.gantt_reschedule_consume_buffer(self.pill_3, {
|
|
self.date_start_field_name: "2021-03-04 00:00:00",
|
|
self.date_stop_field_name: "2021-03-04 08:00:00",
|
|
})
|
|
|
|
self.assert_old_pills_vals(res, 'success', 'Tasks rescheduled', moved_pills, initial_dates_deep_copy)
|
|
self.assertEqual(
|
|
self.pill_3[self.date_stop_field_name],
|
|
self.pill_4[self.date_start_field_name],
|
|
'pill_3 should have been rescheduled to the start of pill_4'
|
|
)
|
|
self.assertEqual(
|
|
self.pill_3_slave_in_conflict[self.date_start_field_name],
|
|
self.pill_3[self.date_stop_field_name],
|
|
'pill_3_slave_in_conflict should have been rescheduled once pill_3 had been rescheduled.'
|
|
)
|
|
self.assertEqual(
|
|
self.pill_3_slave_not_in_conflict[self.date_start_field_name],
|
|
self.pill_3[self.date_stop_field_name],
|
|
'pill_3_slave_not_in_conflict should not be rescheduled once as it is not in conflict with pill_3.'
|
|
)
|
|
self.assertEqual(
|
|
(self.pill_2[self.date_start_field_name], self.pill_2[self.date_stop_field_name]),
|
|
(self.pill_2_start_date, self.pill_2_stop_date),
|
|
'pill_2 should not be rescheduled.'
|
|
)
|
|
moved_pills.action_rollback_scheduling(res['old_vals_per_pill_id'])
|
|
self.assert_not_replanned(moved_pills, initial_dates_deep_copy)
|
|
|
|
def test_conflicting_cascade_backward(self):
|
|
"""
|
|
┌──────────────────────────────┐ ┌──────────────────────────────────┐
|
|
|pill_2_master_not_in_conflict |----------- ---------------------------| pill_2_master_in_conflict |
|
|
└──────────────────────────────┘ | | └──────────────────────────────────┘
|
|
v v
|
|
┌──────────────────────────────┐ ┌─────────┐ ┌─────────┐ ┌──────────────────────────────────┐
|
|
│ Pill 1 │ ---> │ Pill 2 │--> │ Pill 3 │ --> │ Pill 4 │
|
|
└──────────────────────────────┘ └─────────┘ └─────────┘ └──────────────────────────────────┘
|
|
^ ^
|
|
┌──────────────────────────────┐ | | ┌──────────────────────────────────┐
|
|
| pill_3_master_not_in_conflict|---------------------------- ----------| pill_3_master_in_conflict │
|
|
└──────────────────────────────┘ └──────────────────────────────────┘
|
|
|
|
When moving backward without conflicts, we only move records in conflict.
|
|
When moving pill 2 to the end of pill 1 and pill_2_master_not_in_conflict without creating conflicts, they both should not move.
|
|
we only move pill_2_master_in_conflict to fix the conflict
|
|
children should not be impacted
|
|
"""
|
|
self.pill_3_master_in_conflict = self.create_pill(
|
|
'Pill in conflict with Pill 3', self.pill_4_start_date, self.pill_4_stop_date
|
|
)
|
|
self.pill_3_master_not_in_conflict = self.create_pill(
|
|
'Pill not in conflict with Pill 3', self.pill_1_start_date, self.pill_1_stop_date
|
|
)
|
|
self.pill_3[self.dependency_field_name] = [
|
|
Command.link(self.pill_3_master_in_conflict.id),
|
|
Command.link(self.pill_3_master_not_in_conflict.id),
|
|
]
|
|
self.pill_2_master_in_conflict = self.create_pill(
|
|
'Pill in conflict with Pill 2', self.pill_4_start_date, self.pill_4_stop_date
|
|
)
|
|
self.pill_2_master_not_in_conflict = self.create_pill(
|
|
'Pill not in conflict with Pill 2', self.pill_1_start_date, self.pill_1_stop_date
|
|
)
|
|
self.pill_2[self.dependency_field_name] = [
|
|
Command.link(self.pill_2_master_in_conflict.id),
|
|
Command.link(self.pill_2_master_not_in_conflict.id),
|
|
]
|
|
moved_pills = self.pill_2 | self.pill_2_master_in_conflict
|
|
initial_dates_deep_copy = dict(self.initial_dates)
|
|
initial_dates_deep_copy[self.pill_2_master_in_conflict.name] = (self.pill_2_master_in_conflict.date_start, self.pill_2_master_in_conflict.date_stop)
|
|
res = self.gantt_reschedule_consume_buffer(self.pill_2, {
|
|
self.date_start_field_name: "2021-03-01 16:00:00",
|
|
self.date_stop_field_name: "2021-03-02 00:00:00",
|
|
})
|
|
self.assert_old_pills_vals(res, 'success', 'Tasks rescheduled', moved_pills, initial_dates_deep_copy)
|
|
self.assertEqual(self.pill_1[self.date_stop_field_name], self.pill_2[self.date_start_field_name])
|
|
self.assertEqual(
|
|
self.pill_2_master_in_conflict[self.date_stop_field_name],
|
|
self.pill_2[self.date_start_field_name],
|
|
'pill_2_master_in_conflict should have been rescheduled once pill_2 had been rescheduled.'
|
|
)
|
|
moved_pills.action_rollback_scheduling(res['old_vals_per_pill_id'])
|
|
self.assert_not_replanned(moved_pills, initial_dates_deep_copy)
|
|
|
|
def test_pills2_reschedule_cascading_forward(self):
|
|
"""
|
|
This test concerns pills2, when pill 0 is move ahead of task 8.
|
|
As pills 1, 2, 3 are children of 0, they should be done after it,
|
|
they should also be moved forward
|
|
All the other pills should not move.
|
|
"""
|
|
self.gantt_reschedule_consume_buffer(self.pills2_0, {
|
|
self.date_start_field_name: "2024-03-16 14:00:00",
|
|
self.date_stop_field_name: "2024-03-16 18:00:00",
|
|
})
|
|
self.assert_not_replanned(
|
|
self.pills2_4 | self.pills2_5 | self.pills2_6 | self.pills2_7 | self.pills2_8 | self.pills2_9 |
|
|
self.pills2_10 | self.pills2_11 | self.pills2_12 | self.pills2_13 | self.pills2_14,
|
|
self.initial_dates,
|
|
)
|
|
|
|
self.assertEqual(
|
|
self.pills2_0[self.date_start_field_name],
|
|
self.pills2_8[self.date_stop_field_name],
|
|
)
|
|
self.assertEqual(
|
|
self.pills2_1[self.date_start_field_name],
|
|
self.pills2_0[self.date_stop_field_name],
|
|
)
|
|
self.assertEqual(
|
|
self.pills2_2[self.date_start_field_name],
|
|
self.pills2_1[self.date_stop_field_name],
|
|
)
|
|
self.assertEqual(
|
|
self.pills2_2[self.date_start_field_name],
|
|
self.pills2_1[self.date_stop_field_name],
|
|
)
|
|
|
|
def test_pills2_reschedule_cascading_backward(self):
|
|
"""
|
|
This test concerns pills2, when the left arrow is clicked. pill 8 should be moved behind pill 0
|
|
As pills 4, 6, 5, 7 are ancestors for 8 and should be done before it, they should be moved backward.
|
|
9 and 10 should not be impacted as they are not ancestors of 8.
|
|
All the other pills should not move.
|
|
"""
|
|
self.gantt_reschedule_consume_buffer(self.pills2_8, {
|
|
self.date_start_field_name: "2024-03-01 02:00:00",
|
|
self.date_stop_field_name: "2024-03-01 08:00:00",
|
|
})
|
|
self.assert_not_replanned(
|
|
self.pills2_0 | self.pills2_1 | self.pills2_2 | self.pills2_3 | self.pills2_9 |
|
|
self.pills2_10 | self.pills2_11 | self.pills2_12 | self.pills2_13 | self.pills2_14,
|
|
self.initial_dates,
|
|
)
|
|
|
|
self.assertEqual(
|
|
self.pills2_0[self.date_start_field_name],
|
|
self.pills2_8[self.date_stop_field_name],
|
|
)
|
|
self.assertEqual(
|
|
self.pills2_8[self.date_start_field_name],
|
|
self.pills2_7[self.date_stop_field_name],
|
|
)
|
|
self.assertEqual(
|
|
self.pills2_7[self.date_start_field_name],
|
|
self.pills2_6[self.date_stop_field_name],
|
|
)
|
|
self.assertEqual(
|
|
self.pills2_7[self.date_start_field_name],
|
|
self.pills2_5[self.date_stop_field_name],
|
|
)
|
|
self.assertEqual(
|
|
self.pills2_6[self.date_start_field_name],
|
|
self.pills2_4[self.date_stop_field_name],
|
|
)
|
|
|
|
def test_dont_move_not_in_conflict(self):
|
|
"""
|
|
->[4]
|
|
|
|
|
---------<-------
|
|
[1]---------------------------->[2]->[3]--|
|
|
|
|
When moving 3 before 4, 2 should also move to avoid creating conflicts, but 1
|
|
should not be moved because with the new dates of 2 and 3, there is no
|
|
conflict created.
|
|
"""
|
|
self.pill_4.write({
|
|
self.date_start_field_name: datetime(2021, 4, 27, 8, 0),
|
|
self.date_stop_field_name: datetime(2021, 4, 27, 12, 0),
|
|
})
|
|
self.pill_2.write({
|
|
self.date_start_field_name: datetime(2021, 4, 27, 13, 0),
|
|
self.date_stop_field_name: datetime(2021, 4, 27, 17, 0),
|
|
})
|
|
self.pill_3.write({
|
|
self.date_start_field_name: datetime(2021, 4, 28, 13, 0),
|
|
self.date_stop_field_name: datetime(2021, 4, 28, 18, 0),
|
|
})
|
|
self.gantt_reschedule_consume_buffer(self.pill_3, {
|
|
self.date_start_field_name: "2021-04-27 03:00:00",
|
|
self.date_stop_field_name: "2021-04-27 08:00:00",
|
|
})
|
|
self.assertEqual(
|
|
self.pill_3[self.date_stop_field_name],
|
|
self.pill_4[self.date_start_field_name],
|
|
'3 moved before 4',
|
|
)
|
|
self.assertEqual(
|
|
self.pill_2[self.date_stop_field_name],
|
|
self.pill_3[self.date_start_field_name],
|
|
'2 moved before 3',
|
|
)
|
|
self.assert_not_replanned(self.pills2_1 | self.pills2_4, self.initial_dates)
|
|
|
|
def test_reschedule_dates(self):
|
|
pill = self.env["test.web.gantt.pill2"].create({
|
|
self.date_start_field_name: "2021-04-27",
|
|
self.date_stop_field_name: "2021-04-27",
|
|
})
|
|
|
|
self.env['test.web.gantt.pill2'].web_gantt_reschedule(
|
|
{
|
|
self.date_start_field_name: "2021-04-28",
|
|
self.date_stop_field_name: "2021-04-28",
|
|
},
|
|
Base._WEB_GANTT_RESCHEDULE_CONSUME_BUFFER,
|
|
pill.id,
|
|
self.dependency_field_name, self.dependency_inverted_field_name,
|
|
self.date_start_field_name, self.date_stop_field_name
|
|
)
|
|
|
|
self.assertEqual(
|
|
pill[self.date_stop_field_name],
|
|
date(2021, 4, 28),
|
|
)
|
|
self.assertEqual(
|
|
pill[self.date_start_field_name],
|
|
date(2021, 4, 28),
|
|
)
|