192 lines
11 KiB
Python
192 lines
11 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from datetime import datetime
|
|
from dateutil.relativedelta import relativedelta
|
|
from freezegun import freeze_time
|
|
|
|
from odoo import fields
|
|
from odoo.tests import tagged
|
|
|
|
from odoo.addons.hr_timesheet.tests.test_timesheet import TestCommonTimesheet
|
|
|
|
|
|
@tagged('-at_install', 'post_install')
|
|
class TestTimesheetTimer(TestCommonTimesheet):
|
|
def test_start_timer_in_timesheet(self):
|
|
timesheet_without_task, timesheet = self.env['account.analytic.line'].with_user(self.user_employee).create([
|
|
{'name': '/', 'project_id': self.project_customer.id, 'employee_id': self.empl_employee.id},
|
|
{'name': '/', 'project_id': self.project_customer.id, 'task_id': self.task1.id, 'employee_id': self.empl_employee.id},
|
|
])
|
|
timesheet_without_task.action_timer_start()
|
|
timer = timesheet_without_task.user_timer_id
|
|
self.assertTrue(timer, 'A timer should created for this timesheet.')
|
|
self.assertEqual(timer.res_id, timesheet_without_task.id, 'The document linked to this timer should be the timesheet in which the user starts the timer.')
|
|
self.assertEqual(timer.res_model, timesheet_without_task._name, 'The document model should be the one of the timesheet in which the timer is launched.')
|
|
self.assertFalse(timer.parent_res_model, 'No Parent Document Model should be found since no task is linked to the timesheet in which the timer is launched.')
|
|
self.assertFalse(timer.parent_res_id, 'No Parent Document should be found since no task is linked to the timesheet in which the timer is launched.')
|
|
|
|
timesheet.action_timer_start()
|
|
self.assertFalse(timesheet_without_task.user_timer_id, 'The previous timer should be stopped and removed since another timer will be created and launched.')
|
|
timer = timesheet.user_timer_id
|
|
self.assertTrue(timer, 'A timer should created for this timesheet.')
|
|
self.assertEqual(timer.res_id, timesheet.id, 'The document linked to this timer should be the timesheet in which the user starts the timer.')
|
|
self.assertEqual(timer.res_model, timesheet._name, 'The document model should be the one of the timesheet in which the timer is launched.')
|
|
self.assertEqual(timer.parent_res_model, 'project.task', 'The parent document model should be the `project.task` model.')
|
|
self.assertEqual(timer.parent_res_id, self.task1.id, 'The parent document should be the task linked to the timesheet in which the timer is launched.')
|
|
|
|
def test_timer_in_task(self):
|
|
""" Test the timer on a task """
|
|
task = self.task1.with_user(self.user_employee)
|
|
self.assertTrue(task.display_timesheet_timer, 'The timer should be available in that task.')
|
|
task.action_timer_start()
|
|
self.assertTrue(task.is_timer_running, 'The timer should be running and so the stop button appears on the task')
|
|
action = task.action_timer_stop()
|
|
self.assertEqual(action['res_model'], 'hr.timesheet.stop.timer.confirmation.wizard')
|
|
wizard = self.env['hr.timesheet.stop.timer.confirmation.wizard'] \
|
|
.with_context(action['context']) \
|
|
.with_user(self.user_employee) \
|
|
.new({})
|
|
wizard.action_save_timesheet()
|
|
self.assertFalse(task.timer_start, 'The stop button on the task is invisible')
|
|
self.assertFalse(task.is_timer_running, 'The timer should be removed and so it is obviously no longer running.')
|
|
|
|
def test_timer_sync_timesheet_to_task(self):
|
|
""" Test sync between timesheet and task """
|
|
timesheet = self.env['account.analytic.line'].with_user(self.user_employee).create({
|
|
'name': "my timesheet 1",
|
|
'project_id': self.project_customer.id,
|
|
'task_id': self.task1.id,
|
|
'date': fields.Date.today(),
|
|
'unit_amount': 2.0,
|
|
'employee_id': self.empl_employee.id,
|
|
})
|
|
|
|
# Start the timer on timesheet
|
|
timesheet.action_timer_start()
|
|
self.assertTrue(timesheet.is_timer_running, 'Timer should be started on timesheet')
|
|
|
|
# Stop the timer from the task through the wizard
|
|
task = self.task1.with_user(self.user_employee)
|
|
self.assertTrue(task.user_timer_id, 'The timer in the task should be the one of the timesheet.')
|
|
action = task.action_timer_stop()
|
|
self.assertEqual(action['res_model'], 'hr.timesheet.stop.timer.confirmation.wizard')
|
|
wizard = self.env['hr.timesheet.stop.timer.confirmation.wizard'] \
|
|
.with_context(action['context']) \
|
|
.with_user(self.user_employee) \
|
|
.new({})
|
|
wizard.action_save_timesheet()
|
|
self.assertFalse(timesheet.is_timer_running, 'Timer should be stoped on Timesheet')
|
|
|
|
def test_timer_sync_task_to_timesheet(self):
|
|
""" Start the timer from the task and stop the timer from the timesheet """
|
|
# start timer from the task
|
|
task = self.task1.with_user(self.user_employee)
|
|
with freeze_time(datetime.now() - relativedelta(minutes=1)):
|
|
task.action_timer_start()
|
|
self.assertTrue(bool(task.user_timer_id), 'A timer should be generated in the task.')
|
|
timesheet = task.user_timer_id._get_related_document()
|
|
self.assertIn(timesheet, task.timesheet_ids, 'A timesheet should be generated in the task in which the timer is started.')
|
|
|
|
# stop timer from the timesheet
|
|
timesheet.with_user(self.user_employee).action_timer_stop(True)
|
|
self.assertFalse(task.user_timer_id, 'Timer should be stopped on ticket')
|
|
self.assertGreater(timesheet.unit_amount, 0.0, 'unit_amount should be greated than his last value')
|
|
|
|
def test_switch_timer_task(self):
|
|
"""
|
|
Stop the running timer and log the timesheet entry on task when same user start the timer on another task
|
|
"""
|
|
task1 = self.task1.copy()
|
|
task2 = self.task1.copy()
|
|
|
|
# Start the timer on task1
|
|
with freeze_time(datetime.now() - relativedelta(minutes=1)):
|
|
task1.with_user(self.user_employee).action_timer_start()
|
|
|
|
# Start the timer on task2
|
|
task2.with_user(self.user_employee).action_timer_start()
|
|
self.assertFalse(task1.timer_start, 'Timer should be stoped on task1')
|
|
self.assertEqual(len(task1.timesheet_ids), 1, 'Timesheet entry should be logged to the task1')
|
|
self.assertEqual(len(task2.timesheet_ids), 1, 'Timesheet entry should be logged to the task2')
|
|
|
|
def test_update_timesheet(self):
|
|
""" Test if when the task is updated on the timesheet, the timer is also updated """
|
|
timesheet = self.env['account.analytic.line'].with_user(self.user_employee).create({'name': '/', 'project_id': self.project_customer.id})
|
|
timesheet.action_timer_start()
|
|
timer = timesheet.user_timer_id
|
|
self.assertTrue(bool(timer))
|
|
self.assertFalse(timer.parent_res_model)
|
|
self.assertFalse(timer.parent_res_id)
|
|
|
|
timesheet.write({'task_id': self.task1.id})
|
|
self.assertEqual(timer.parent_res_model, 'project.task')
|
|
self.assertEqual(timer.parent_res_id, self.task1.id)
|
|
|
|
def test_update_project_on_task_linked_to_timesheet_with_timer_running(self):
|
|
""" Test if when the project is updated on the task linked to the timesheet with timer running, the timer is also updated """
|
|
timesheet = self.env['account.analytic.line'] \
|
|
.with_user(self.user_employee) \
|
|
.create({
|
|
'name': '/',
|
|
'project_id': self.project_customer.id,
|
|
'task_id': self.task1.id,
|
|
})
|
|
timesheet.action_timer_start()
|
|
timer = timesheet.user_timer_id
|
|
self.assertTrue(bool(timer))
|
|
self.assertEqual(timer.res_id, timesheet.id)
|
|
self.assertEqual(timer.res_model, timesheet._name)
|
|
self.assertEqual(timer.parent_res_model, 'project.task')
|
|
self.assertEqual(timer.parent_res_id, self.task1.id)
|
|
|
|
timesheet_project, non_timesheetable_project = self.env['project.project'].create([
|
|
{'name': 'Timesheet Project', 'allow_timesheets': True},
|
|
{'name': 'Non Timesheet Project', 'allow_timesheets': False},
|
|
])
|
|
self.task1.write({'project_id': timesheet_project.id})
|
|
self.assertTrue(self.task1.with_user(self.user_employee).is_timer_running)
|
|
self.assertEqual(timer.parent_res_model, 'project.task')
|
|
self.assertEqual(timer.parent_res_id, self.task1.id)
|
|
|
|
self.task1.write({'project_id': non_timesheetable_project.id})
|
|
self.task1.invalidate_recordset()
|
|
self.assertFalse(self.task1.with_user(self.user_employee).is_timer_running)
|
|
self.assertFalse(timesheet.exists(), 'The timesheet should be removed since the timesheet has unit amount equals to 0.')
|
|
|
|
def test_multi_company_start_timer(self):
|
|
company = self.env['res.company'].create({'name': 'Company Test'})
|
|
project = self.env['project.project'].create({
|
|
'name': 'Test Project in Company Test',
|
|
'allow_timesheets': True,
|
|
})
|
|
task = self.env['project.task'].create({
|
|
'name': 'Test Task in Company Test',
|
|
'project_id': project.id,
|
|
'company_id': company.id,
|
|
}).with_user(self.user_employee)
|
|
self.assertFalse(self.task1.timesheet_ids)
|
|
task1 = self.task1.with_user(self.user_employee)
|
|
task1.action_timer_start()
|
|
timer = task1.user_timer_id
|
|
self.assertTrue(bool(timer))
|
|
self.assertEqual(timer.parent_res_model, 'project.task')
|
|
self.assertEqual(timer.parent_res_id, task1.id)
|
|
timesheet_with_timer_running = self.env[timer.res_model].browse(timer.res_id)
|
|
self.assertTrue(timesheet_with_timer_running, 'A timer should generate a timesheet')
|
|
self.assertEqual(timesheet_with_timer_running.task_id, task1, 'The timesheet generated by the timer should be linked to the task1.')
|
|
|
|
self.user_employee.company_ids += company
|
|
self.env['hr.employee'].create({
|
|
'name': 'Employee Test Company',
|
|
'user_id': self.user_employee.id,
|
|
'company_id': company.id,
|
|
})
|
|
task.with_company(company).action_timer_start()
|
|
timer = task.user_timer_id
|
|
self.assertTrue(bool(timer))
|
|
self.assertEqual(timer.parent_res_model, 'project.task')
|
|
self.assertEqual(timer.parent_res_id, task.id)
|
|
self.assertFalse(task1.user_timer_id, 'The previous timer should be stopped since another timer is started.')
|
|
self.assertTrue(timesheet_with_timer_running, 'A timesheet should still be there even if the timer is stopped.')
|
|
self.assertFalse(timesheet_with_timer_running.with_user(self.user_employee).user_timer_id)
|