diff options
| author | jbm-odoo <jbm@odoo.com> | 2020-06-05 17:13:53 +0200 |
|---|---|---|
| committer | jbm-odoo <jbm@odoo.com> | 2020-06-15 15:51:20 +0200 |
| commit | d6a23144d5c5b85c2a02097bcbb3e006a9c2c52a (patch) | |
| tree | 2eb930372884160d675497ce415279374d21b48a /addons | |
| parent | e7dda3fab002f5db930b4af340787177d597d59e (diff) | |
[MOV] timer: Move to Enterprise
taskId: 2217930
Diffstat (limited to 'addons')
36 files changed, 40 insertions, 1199 deletions
diff --git a/addons/hr_timesheet/__init__.py b/addons/hr_timesheet/__init__.py index 67486585c98..6aab6c417a5 100644 --- a/addons/hr_timesheet/__init__.py +++ b/addons/hr_timesheet/__init__.py @@ -11,37 +11,28 @@ from odoo import api, fields, SUPERUSER_ID, _ def create_internal_project(cr, registry): env = api.Environment(cr, SUPERUSER_ID, {}) - companies_with_internal = env['project.project'].read_group([ - ('name', '=', _('Internal')), ('allow_timesheets', '=', True) - ], ['company_id'], ['company_id']) - company_ids_with_internal = [c['company_id'][0] for c in companies_with_internal] - for company in env['res.company'].search([('id', 'not in', company_ids_with_internal)]): + admin = env.ref('base.user_admin', raise_if_not_found=False) + if not admin: + return + project_vals = [] + for company in env['res.company'].search([]): company = company.with_company(company) - internal_project = company.env['project.project'].create({ + project_vals += [{ 'name': _('Internal'), 'allow_timesheets': True, 'company_id': company.id, - }) - admin = env.ref('base.user_admin', raise_if_not_found=False) - if not admin: - continue - tasks = company.env['project.task'].create([{ - 'name': _('Training'), - 'project_id': internal_project.id, - 'company_id': company.id, - }, { - 'name': _('Meeting'), - 'project_id': internal_project.id, - 'company_id': company.id, - }]) + 'task_ids': [(0, 0, { + 'name': name, + 'company_id': company.id, + }) for name in [_('Training'), _('Meeting')]] + }] + project_ids = env['project.project'].create(project_vals) - if not admin.employee_ids.filtered(lambda e: e.company_id == company): - continue - company.env['account.analytic.line'].create([{ - 'name': _("Analysis"), - 'user_id': admin.id, - 'date': fields.datetime.today(), - 'unit_amount': 0, - 'project_id': internal_project.id, - 'task_id': task.id, - } for task in tasks]) + env['account.analytic.line'].create([{ + 'name': _("Analysis"), + 'user_id': admin.id, + 'date': fields.datetime.today(), + 'unit_amount': 0, + 'project_id': task.project_id.id, + 'task_id': task.id, + } for task in project_ids.task_ids.filtered(lambda t: t.company_id in admin.employee_ids.company_id)]) diff --git a/addons/hr_timesheet/__manifest__.py b/addons/hr_timesheet/__manifest__.py index e529653a5e6..841971e8836 100644 --- a/addons/hr_timesheet/__manifest__.py +++ b/addons/hr_timesheet/__manifest__.py @@ -20,7 +20,7 @@ It is completely integrated with the cost accounting module. It allows you to se up a management by affair. """, 'website': 'https://www.odoo.com/page/timesheet-mobile-app', - 'depends': ['hr', 'analytic', 'project', 'uom', 'timer'], + 'depends': ['hr', 'analytic', 'project', 'uom'], 'data': [ 'security/hr_timesheet_security.xml', 'security/ir.model.access.csv', diff --git a/addons/hr_timesheet/models/hr_timesheet.py b/addons/hr_timesheet/models/hr_timesheet.py index 820d7a694ce..dc41a4e5963 100644 --- a/addons/hr_timesheet/models/hr_timesheet.py +++ b/addons/hr_timesheet/models/hr_timesheet.py @@ -9,8 +9,7 @@ from odoo.exceptions import UserError, AccessError from odoo.osv import expression class AccountAnalyticLine(models.Model): - _name = 'account.analytic.line' - _inherit = ['account.analytic.line', 'timer.mixin'] + _inherit = 'account.analytic.line' @api.model def default_get(self, field_list): @@ -48,9 +47,6 @@ class AccountAnalyticLine(models.Model): employee_id = fields.Many2one('hr.employee', "Employee", check_company=True, domain=_domain_employee_id) department_id = fields.Many2one('hr.department', "Department", compute='_compute_department_id', store=True, compute_sudo=True) encoding_uom_id = fields.Many2one('uom.uom', compute='_compute_encoding_uom_id') - display_timer = fields.Boolean( - compute='_compute_display_timer', - help="Technical field used to display the timer if the encoding unit is 'Hours'.") def _compute_encoding_uom_id(self): for analytic_line in self: @@ -198,48 +194,3 @@ class AccountAnalyticLine(models.Model): 'amount': amount_converted, }) return result - - def _compute_display_timer(self): - uom_hour = self.env.ref('uom.product_uom_hour') - for analytic_line in self: - analytic_line.display_timer = analytic_line.encoding_uom_id == uom_hour - - def action_timer_start(self): - """ Start a timer if it isn't already started and the - timesheets allow to track time - """ - if not self.user_timer_id.timer_start and self.display_timer: - super().action_timer_start() - - def action_timer_stop(self): - """ Stop the current timer - """ - if self.user_timer_id.timer_start and self.display_timer: - minutes_spent = super().action_timer_stop() - self._add_timesheet_time(minutes_spent) - - def _add_timesheet_time(self, minutes_spent): - if self.unit_amount == 0 and minutes_spent < 1 and not self._context.get('prevent_deletion', False): - # Check if unit_amount equals 0 and minutes_spent is less than 1 minute, - # if yes, then remove the timesheet - self.unlink() - else: - if minutes_spent < 1: - amount = self.unit_amount - else: - minimum_duration = int(self.env['ir.config_parameter'].sudo().get_param('hr_timesheet.timesheet_min_duration', 0)) - rounding = int(self.env['ir.config_parameter'].sudo().get_param('hr_timesheet.timesheet_rounding', 0)) - minutes_spent = self._timer_rounding(minutes_spent, minimum_duration, rounding) - amount = self.unit_amount + minutes_spent * 60 / 3600 - self.write({'unit_amount': amount}) - - def _action_interrupt_user_timers(self): - self.action_timer_stop() - - def unlink(self): - res = super(AccountAnalyticLine, self).unlink() - self.env['timer.timer'].search([ - ('res_model', '=', self._name), - ('res_id', 'in', self.ids) - ]).unlink() - return res diff --git a/addons/hr_timesheet/models/project.py b/addons/hr_timesheet/models/project.py index 686acad3409..ed0ac3a5bad 100644 --- a/addons/hr_timesheet/models/project.py +++ b/addons/hr_timesheet/models/project.py @@ -16,12 +16,6 @@ class Project(models.Model): ('partner_id', '=?', partner_id), ]""" ) - allow_timesheet_timer = fields.Boolean( - 'Timesheet Timer', - compute='_compute_allow_timesheet_timer', - readonly=False, - store=True, - help="Use a timer to record timesheets on tasks") timesheet_ids = fields.One2many('account.analytic.line', 'project_id', 'Associated Timesheets') timesheet_encode_uom_id = fields.Many2one('uom.uom', related='company_id.timesheet_encode_uom_id') @@ -29,10 +23,6 @@ class Project(models.Model): compute='_compute_total_timesheet_time', help="Total number of time (in the proper UoM) recorded in the project, rounded to the unit.") - _sql_constraints = [ - ('timer_only_when_timesheet', "CHECK((allow_timesheets = 'f' AND allow_timesheet_timer = 'f') OR (allow_timesheets = 't'))", 'The timesheet timer can only be activated on project allowing timesheets.'), - ] - @api.onchange('analytic_account_id') def _onchange_analytic_account(self): if not self.analytic_account_id and self._origin: @@ -44,11 +34,6 @@ class Project(models.Model): if project.allow_timesheets and not project.analytic_account_id: raise ValidationError(_('To allow timesheet, your project %s should have an analytic account set.' % (project.name,))) - @api.depends('allow_timesheets') - def _compute_allow_timesheet_timer(self): - for project in self: - project.allow_timesheet_timer = project.allow_timesheets - @api.depends('timesheet_ids') def _compute_total_timesheet_time(self): for project in self: @@ -87,13 +72,7 @@ class Project(models.Model): for project in self: if not project.analytic_account_id and not values.get('analytic_account_id'): project._create_analytic_account() - result = super(Project, self).write(values) - if 'allow_timesheet_timer' in values and not values.get('allow_timesheet_timer'): - self.with_context(active_test=False).mapped('task_ids').write({ - 'timer_start': False, - 'timer_pause': False, - }) - return result + return super(Project, self).write(values) @api.model def _init_data_analytic_account(self): @@ -120,7 +99,7 @@ class Project(models.Model): class Task(models.Model): _name = "project.task" - _inherit = ["project.task", "timer.mixin"] + _inherit = "project.task" analytic_account_active = fields.Boolean("Active Analytic Account", compute='_compute_analytic_account_active') allow_timesheets = fields.Boolean("Allow timesheets", related='project_id.allow_timesheets', help="Timesheets can be logged on this task.", readonly=True) @@ -132,38 +111,6 @@ class Task(models.Model): subtask_effective_hours = fields.Float("Sub-tasks Hours Spent", compute='_compute_subtask_effective_hours', store=True, help="Time spent on the sub-tasks (and their own sub-tasks) of this task.") timesheet_ids = fields.One2many('account.analytic.line', 'task_id', 'Timesheets') - # YTI FIXME: Those field seems quite useless - timesheet_timer_first_start = fields.Datetime("Timesheet Timer First Use", readonly=True) - timesheet_timer_last_stop = fields.Datetime("Timesheet Timer Last Use", readonly=True) - display_timesheet_timer = fields.Boolean("Display Timesheet Time", compute='_compute_display_timesheet_timer') - - display_timer_start_secondary = fields.Boolean(compute='_compute_display_timer_buttons') - - @api.depends('display_timesheet_timer', 'timer_start', 'timer_pause', 'total_hours_spent') - def _compute_display_timer_buttons(self): - for task in self: - if not task.display_timesheet_timer: - task.update({ - 'display_timer_start_primary': False, - 'display_timer_start_secondary': False, - 'display_timer_stop': False, - 'display_timer_pause': False, - 'display_timer_resume': False, - }) - else: - super(Task, task)._compute_display_timer_buttons() - task.display_timer_start_secondary = task.display_timer_start_primary - if not task.timer_start: - task.update({ - 'display_timer_stop': False, - 'display_timer_pause': False, - 'display_timer_resume': False, - }) - if not task.total_hours_spent: - task.display_timer_start_secondary = False - else: - task.display_timer_start_primary = False - @api.depends('project_id.analytic_account_id.active') def _compute_analytic_account_active(self): """ Overridden in sale_timesheet """ @@ -204,11 +151,6 @@ class Task(models.Model): for task in self: task.subtask_effective_hours = sum(child_task.effective_hours + child_task.subtask_effective_hours for child_task in task.child_ids) - @api.depends('allow_timesheets', 'project_id.allow_timesheet_timer', 'analytic_account_active') - def _compute_display_timesheet_timer(self): - for task in self: - task.display_timesheet_timer = task.allow_timesheets and task.project_id.allow_timesheet_timer and task.analytic_account_active - def action_view_subtask_timesheet(self): self.ensure_one() tasks = self._get_all_subtasks() @@ -256,35 +198,6 @@ class Task(models.Model): result['arch'] = self.env['account.analytic.line']._apply_timesheet_label(result['arch']) return result - def action_timer_start(self): - if not self.user_timer_id.timer_start and self.display_timesheet_timer: - super(Task, self).action_timer_start() - - def action_timer_stop(self): - # timer was either running or paused - if self.user_timer_id.timer_start and self.display_timesheet_timer: - minutes_spent = super().action_timer_stop() - minimum_duration = int(self.env['ir.config_parameter'].sudo().get_param('hr_timesheet.timesheet_min_duration', 0)) - rounding = int(self.env['ir.config_parameter'].sudo().get_param('hr_timesheet.timesheet_rounding', 0)) - minutes_spent = self._timer_rounding(minutes_spent, minimum_duration, rounding) - return self._action_create_timesheet(minutes_spent * 60 / 3600) - return False - - def _action_create_timesheet(self, time_spent): - return { - "name": _("Validate Spent Time"), - "type": 'ir.actions.act_window', - "res_model": 'project.task.create.timesheet', - "views": [[False, "form"]], - "target": 'new', - "context": { - **self.env.context, - 'active_id': self.id, - 'active_model': self._name, - 'default_time_spent': time_spent, - }, - } - def unlink(self): """ If some tasks to unlink have some timesheets entries, these diff --git a/addons/hr_timesheet/static/src/js/timesheet_kanban_view.js b/addons/hr_timesheet/static/src/js/timesheet_kanban_view.js deleted file mode 100644 index 9a577a9895d..00000000000 --- a/addons/hr_timesheet/static/src/js/timesheet_kanban_view.js +++ /dev/null @@ -1,34 +0,0 @@ -odoo.define('hr_timesheet.timesheet_kanban_view', function (require) { -"use strict"; - -const KanbanController = require('web.KanbanController'); -const KanbanView = require('web.KanbanView'); -const viewRegistry = require('web.view_registry'); - -/** - * @override the KanbanController to add a trigger when a timer is launched or stopped - */ -const TimesheetKanbanController = KanbanController.extend({ - custom_events: _.extend({}, KanbanController.prototype.custom_events, { - 'timer_changed': '_onTimerChanged', - }), - /** - * When a timer is launched or stopped, we reload the view to see the updating. - * @param {Object} event - */ - _onTimerChanged: function (event) { - this.reload(); - } -}); - -const TimesheetKanbanView = KanbanView.extend({ - config: _.extend({}, KanbanView.prototype.config, { - Controller: TimesheetKanbanController - }) -}); - -viewRegistry.add('timesheet_kanban_view', TimesheetKanbanView); - -return { TimesheetKanbanController, TimesheetKanbanView }; - -}); diff --git a/addons/hr_timesheet/static/src/js/timesheet_list_view.js b/addons/hr_timesheet/static/src/js/timesheet_list_view.js deleted file mode 100644 index 903352a35de..00000000000 --- a/addons/hr_timesheet/static/src/js/timesheet_list_view.js +++ /dev/null @@ -1,34 +0,0 @@ -odoo.define('hr_timesheet.timesheet_list_view', function (require) { -"use strict"; - -const ListController = require('web.ListController'); -var ListView = require('web.ListView'); -var viewRegistry = require('web.view_registry'); - -/** - * @override the ListController to add a trigger when the timer is launched or stopped - */ -const TimesheetListController = ListController.extend({ - custom_events: _.extend({}, ListController.prototype.custom_events, { - 'timer_changed': '_onTimerChanged', - }), - /** - * When a timer is launched or stopped, we reload the view to see the updating. - * @param {Object} event - */ - _onTimerChanged: function (event) { - this.reload(); - } -}); - -const TimesheetListView = ListView.extend({ - config: _.extend({}, ListView.prototype.config, { - Controller: TimesheetListController - }) -}); - -viewRegistry.add('timesheet_tree', TimesheetListView); - -return { TimesheetListController, TimesheetListView }; - -}); diff --git a/addons/hr_timesheet/static/src/js/timesheet_uom.js b/addons/hr_timesheet/static/src/js/timesheet_uom.js index acfd9fc6e5b..45979121bfa 100644 --- a/addons/hr_timesheet/static/src/js/timesheet_uom.js +++ b/addons/hr_timesheet/static/src/js/timesheet_uom.js @@ -6,8 +6,6 @@ const fieldUtils = require('web.field_utils'); const fieldRegistry = require('web.field_registry'); -const Timer = require('timer.Timer'); - // We need the field registry to be populated, as we bind the // timesheet_uom widget on existing field widgets. require('web._field_registry'); @@ -74,8 +72,7 @@ const FieldTimesheetToggle = basicFields.FieldFloatToggle.extend({ /** - * Extend float time widget to add the using of a timer for duration - * (unit_amount) field. + * Extend float time widget */ const FieldTimesheetTime = basicFields.FieldFloatTime.extend({ init: function () { @@ -85,54 +82,7 @@ const FieldTimesheetTime = basicFields.FieldFloatTime.extend({ this.nodeOptions.factor = session.timesheet_uom_factor; this.parseOptions.factor = session.timesheet_uom_factor; } - }, - willstart() { - const timePromise = this._rpc({ - model: 'timer.timer', - method: 'get_server_time', - args: [] - }).then((time) => { - this.serverTime = time; - }); - return Promise.all([ - this._super(...arguments), - timePromise, - ]); - }, - - _render: async function () { - await this._super.apply(this, arguments); - // Check if the timer_start exists and it's not false - // In other word, when user clicks on play button, this button - // launches the "action_timer_start". - if (this.recordData.timer_start && !this.recordData.timer_pause) { - this.time = Timer.createTimer(this.recordData.unit_amount, this.recordData.timer_start, this.serverTime); - this._startTimeCounter(); - } - }, - /** - * @override - */ - destroy: function () { - clearTimeout(this.timer); - this._super.apply(this, arguments); - }, - _startTimeCounter: function () { - if (this.time) { - this.timer = setInterval(() => { - this.time.addSecond(); - if (this.$el.children().length) { - this.$el.contents()[1].replaceWith(this.time.toString()); - } else { - this.$el.text(this.time.toString()); - } - this.$el.addClass('font-weight-bold text-danger'); - }, 1000); - } else { - clearTimeout(this.timer); - this.$el.removeClass('font-weight-bold text-danger'); - } - }, + } }); diff --git a/addons/hr_timesheet/static/src/js/timesheet_uom_timer.js b/addons/hr_timesheet/static/src/js/timesheet_uom_timer.js index 165dfa6eb92..4eae761f444 100644 --- a/addons/hr_timesheet/static/src/js/timesheet_uom_timer.js +++ b/addons/hr_timesheet/static/src/js/timesheet_uom_timer.js @@ -48,12 +48,11 @@ const FieldTimesheetTimeTimer = TimesheetUom.FieldTimesheetTime.extend({ _onToggleButton: async function (event) { const context = this.record.getContext(); - const prevent_deletion = this.attrs.options && this.attrs.options.prevent_deletion || false; event.stopPropagation(); const result = await this._rpc({ model: this.model, method: this._getActionButton(), - context: $.extend({}, context, {prevent_deletion: prevent_deletion}), + context: context, args: [this.res_id] }); diff --git a/addons/hr_timesheet/static/src/scss/timer_button.scss b/addons/hr_timesheet/static/src/scss/timer_button.scss deleted file mode 100644 index 8b269fa8b20..00000000000 --- a/addons/hr_timesheet/static/src/scss/timer_button.scss +++ /dev/null @@ -1,26 +0,0 @@ -.o-timer-button { - &:focus { - border: none !important; - outline: 0 !important; - } - - & > i { - transition: 0.3s; - - &.o-timer-play-button { - color: $link-color !important; - } - - &.o-timer-stop-button { - color: $red !important; - } - } - - &:hover > i.o-timer-play-button { - color: $link-hover-color !important; - } - - &:hover > i.o-timer-stop-button { - color: darken($red, 15%) !important; - } -} diff --git a/addons/hr_timesheet/tests/test_timesheet.py b/addons/hr_timesheet/tests/test_timesheet.py index f0cdc38a0da..463c0fdbdac 100644 --- a/addons/hr_timesheet/tests/test_timesheet.py +++ b/addons/hr_timesheet/tests/test_timesheet.py @@ -4,8 +4,6 @@ from odoo.tests.common import TransactionCase from odoo.exceptions import AccessError, UserError -from datetime import datetime, timedelta - class TestCommonTimesheet(TransactionCase): @@ -37,7 +35,6 @@ class TestCommonTimesheet(TransactionCase): 'allow_timesheets': True, 'partner_id': self.partner.id, 'analytic_account_id': self.analytic_account.id, - 'allow_timesheet_timer': True }) self.task1 = self.env['project.task'].create({ 'name': 'Task One', @@ -172,7 +169,6 @@ class TestTimesheet(TestCommonTimesheet): non_tracked_project = self.env['project.project'].create({ 'name': 'Project without timesheet', 'allow_timesheets': False, - 'allow_timesheet_timer': False, 'partner_id': self.partner.id, }) self.assertFalse(non_tracked_project.analytic_account_id, "A non time-tracked project shouldn't generate an analytic account") @@ -289,77 +285,3 @@ class TestTimesheet(TestCommonTimesheet): }, { 'amount': -12.0, }]) - - def test_minutes_computing_after_timer_stop(self): - """ Test if unit_amount is updated after stoping a timer """ - Timesheet = self.env['account.analytic.line'] - timesheet_1 = Timesheet.with_user(self.user_employee).create({ - 'project_id': self.project_customer.id, - 'task_id': self.task1.id, - 'name': '/', - 'unit_amount': 1, - }) - - # When the timer is less than 1 minute - now = datetime.now() - timesheet_1.with_user(self.user_employee).action_timer_start() - timesheet_1.with_user(self.user_employee).user_timer_id.timer_start = now - timedelta(seconds=28) - timesheet_1.with_user(self.user_employee).action_timer_stop() - - self.assertEqual(timesheet_1.unit_amount, 1, 'unit_amount still should have the same value') - - # When the timer is greater than 1 minute - now = datetime.now() - timesheet_1.with_user(self.user_employee).action_timer_start() - timesheet_1.with_user(self.user_employee).user_timer_id.timer_start = now - timedelta(minutes=1, seconds=28) - timesheet_1.with_user(self.user_employee).action_timer_stop() - - self.assertGreater(timesheet_1.unit_amount, 1, 'unit_amount should be greated than his last value') - - def test_allow_timesheets_and_timer(self): - """ - Check that a modification of the 'allow_timesheets' field updates correctly the - 'allow_timesheet_timer' field. - """ - Project = self.env['project.project'] - - # case 1: create a project with allow_timesheets set to FALSE - project_1 = Project.create({ - 'name': 'Project 1', - 'allow_timesheets': False, - 'partner_id': self.partner.id - }) - - self.assertFalse( - project_1.allow_timesheet_timer, - "On project creation with 'allow_timesheets' set to FALSE, 'allow_timesheet_timer' shall be set to FALSE") - - # case 2: create a project with allow_timesheets set to TRUE - project_2 = Project.create({ - 'name': 'Project 2', - 'allow_timesheets': True, - 'partner_id': self.partner.id, - 'analytic_account_id': self.analytic_account.id - }) - - self.assertTrue( - project_2.allow_timesheet_timer, - "On project creation with 'allow_timesheets' set to TRUE, 'allow_timesheet_timer' shall be set to TRUE") - - # case 3: change 'allow_timesheets' from FALSE to TRUE - project_1.write({ - 'allow_timesheets': True - }) - - self.assertTrue( - project_1.allow_timesheet_timer, - "On 'allow_timesheets' change to TRUE, 'allow_timesheet_timer' shall be set to TRUE") - - # case 4: change 'allow_timesheets' from TRUE to FALSE - project_2.write({ - 'allow_timesheets': False - }) - - self.assertFalse( - project_2.allow_timesheet_timer, - "On 'allow_timesheets' change to FALSE, 'allow_timesheet_timer' shall be set to FALSE") diff --git a/addons/hr_timesheet/views/assets.xml b/addons/hr_timesheet/views/assets.xml index b20bdf051b8..816f36f5c53 100644 --- a/addons/hr_timesheet/views/assets.xml +++ b/addons/hr_timesheet/views/assets.xml @@ -2,12 +2,8 @@ <odoo> <template id="assets_backend" name="timesheet assets" inherit_id="web.assets_backend"> <xpath expr="." position="inside"> - <link type="text/scss" href="/hr_timesheet/static/src/scss/timer_button.scss" rel="stylesheet"/> <script type="text/javascript" src="/hr_timesheet/static/src/js/task_with_hours.js"></script> <script type="text/javascript" src="/hr_timesheet/static/src/js/timesheet_uom.js"/> - <script type="text/javascript" src="/hr_timesheet/static/src/js/timesheet_uom_timer.js"/> - <script type="text/javascript" src="/hr_timesheet/static/src/js/timesheet_list_view.js"/> - <script type="text/javascript" src="/hr_timesheet/static/src/js/timesheet_kanban_view.js"/> </xpath> </template> </odoo> diff --git a/addons/hr_timesheet/views/hr_timesheet_views.xml b/addons/hr_timesheet/views/hr_timesheet_views.xml index 994b4ec80f7..bb3ecd7a776 100644 --- a/addons/hr_timesheet/views/hr_timesheet_views.xml +++ b/addons/hr_timesheet/views/hr_timesheet_views.xml @@ -21,16 +21,13 @@ <field name="name">account.analytic.line.tree.hr_timesheet</field> <field name="model">account.analytic.line</field> <field name="arch" type="xml"> - <tree editable="top" string="Timesheet Activities" js_class="timesheet_tree"> + <tree editable="top" string="Timesheet Activities"> <field name="date"/> - <field name="project_id" required="1" context="{'form_view_ref': 'project.project_project_view_form_simplified',}"/> - <field name="task_id" optional="show" widget="task_with_hours" context="{'default_project_id': project_id}" domain="[('project_id', '=', project_id)]"/> + <field name="project_id" required="1" options="{'no_create_edit': True}" context="{'form_view_ref': 'project.project_project_view_form_simplified',}"/> + <field name="task_id" optional="show" options="{'no_create_edit': True}" widget="task_with_hours" context="{'default_project_id': project_id}" domain="[('project_id', '=', project_id)]"/> <field name="name" optional="show" required="0"/> - <field name="is_timer_running" invisible="1"/> - <field name="unit_amount" optional="show" widget="timesheet_uom_timer" sum="Total" attrs="{'readonly': [('id', '!=', False), ('timer_start', '!=', False)]}" decoration-danger="unit_amount > 24"/> + <field name="unit_amount" optional="show" widget="timesheet_uom" sum="Total" decoration-danger="unit_amount > 24"/> <field name="company_id" invisible="1"/> - <field name="timer_start" invisible="1"/> - <field name="display_timer" invisible="1"/> <field name="user_id" invisible="1"/> </tree> </field> @@ -93,9 +90,8 @@ </group> <group> <field name="amount"/> - <field name="unit_amount" widget="timesheet_uom" attrs="{'readonly': [('id', '!=', False), ('timer_start', '!=', False)]}" decoration-danger="unit_amount > 24"/> + <field name="unit_amount" widget="timesheet_uom" decoration-danger="unit_amount > 24"/> <field name="currency_id" invisible="1"/> - <field name="timer_start" invisible="1"/> </group> </group> </sheet> @@ -160,15 +156,13 @@ <field name="name">account.analytic.line.kanban</field> <field name="model">account.analytic.line</field> <field name="arch" type="xml"> - <kanban class="o_kanban_mobile" js_class="timesheet_kanban_view"> + <kanban class="o_kanban_mobile"> <field name="date"/> <field name="user_id"/> <field name="name"/> <field name="project_id"/> <field name="task_id" context="{'default_project_id': project_id}" domain="[('project_id', '=', project_id)]"/> <field name="unit_amount" widget="timesheet_uom"/> - <field name="timer_start" invisible="1"/> - <field name="display_timer" invisible="1"/> <templates> <t t-name="kanban-box"> <div t-attf-class="oe_kanban_global_click"> @@ -184,9 +178,7 @@ <span> <t t-esc="record.name.value"/> </span> - <div class="float-right"> - <field name="is_timer_running" widget="timer_toggle_button" options="{'prevent_deletion': True}" attrs="{ 'invisible': [('display_timer', '=', False)] }" /> - </div> + <div class="float-right" id="bottom_right"/> </div> </div> </div> @@ -214,7 +206,6 @@ <field name="view_mode">tree,form</field> <field name="domain">[('project_id', '!=', False), ('user_id', '=', uid)]</field> <field name="context">{ - "my_timesheet_display_timer": True, "search_default_week":1, }</field> <field name="search_view_id" ref="hr_timesheet_line_my_timesheet_search"/> diff --git a/addons/hr_timesheet/views/project_views.xml b/addons/hr_timesheet/views/project_views.xml index a1cfd5eb110..4323bfb9ef4 100644 --- a/addons/hr_timesheet/views/project_views.xml +++ b/addons/hr_timesheet/views/project_views.xml @@ -71,39 +71,6 @@ </field> </record> - <record id="project_view_form_inherit" model="ir.ui.view"> - <field name="name">project.view.form.inherit</field> - <field name="model">project.project</field> - <field name="inherit_id" ref="hr_timesheet.project_invoice_form"/> - <field name="arch" type="xml"> - <xpath expr="//div[@id='timesheet_settings']" position="after"> - <div class="col-lg-6 o_setting_box" attrs="{'invisible': [('allow_timesheets', '=', False)]}" id="timer_setting"> - <div class="o_setting_left_pane"> - <field name="allow_timesheet_timer"/> - </div> - <div class="o_setting_right_pane"> - <label for="allow_timesheet_timer"/> - <div class="text-muted"> - Track your time using a timer - </div> - </div> - </div> - </xpath> - </field> - </record> - - <record id="project_project_view_form_simplified_inherit" model="ir.ui.view"> - <field name="name">project.project.view.form.simplified.inherit</field> - <field name="model">project.project</field> - <field name="inherit_id" ref="project.project_project_view_form_simplified"/> - <field name="priority">32</field> - <field name="arch" type="xml"> - <xpath expr="//field[@name='allow_timesheets']" position="after"> - <field name="allow_timesheet_timer" invisible="1"/> - </xpath> - </field> - </record> - <record model="ir.ui.view" id="view_task_form2_inherited"> <field name="name">project.task.form.inherited</field> <field name="model">project.task</field> @@ -263,40 +230,6 @@ </field> </record> - <record id="project_task_view_form" model="ir.ui.view"> - <field name="name">project.task.view.form.inherit.sale.timesheet.enterprise</field> - <field name="model">project.task</field> - <field name="inherit_id" ref="project.view_task_form2"/> - <field name="arch" type="xml"> - <xpath expr="//header" position='inside'> - <field name="company_id" invisible="1"/> - <field name="display_timesheet_timer" invisible="1"/> - <field name="timer_pause" invisible="1" /> - <field name="display_timer_start_primary" invisible="1"/> - <field name="display_timer_start_secondary" invisible="1"/> - <field name="display_timer_stop" invisible="1"/> - <field name="display_timer_pause" invisible="1"/> - <field name="display_timer_resume" invisible="1"/> - <button class="btn-primary" name="action_timer_start" type="object" string="Start" - attrs="{'invisible': [('display_timer_start_primary', '=', False)]}" groups="hr_timesheet.group_hr_timesheet_user"/> - <button class="btn-secondary" name="action_timer_start" type="object" string="Start" - attrs="{'invisible': [('display_timer_start_secondary', '=', False)]}" groups="hr_timesheet.group_hr_timesheet_user"/> - <button class="btn-primary btn-danger o_fsm_stop" name="action_timer_stop" type="object" string="Stop" - attrs="{'invisible': [('display_timer_stop', '=', False)]}" groups="hr_timesheet.group_hr_timesheet_user"/> - <button class="btn-primary" name="action_timer_pause" type="object" string="Pause" - attrs="{'invisible': [('display_timer_pause', '=', False)]}" groups="hr_timesheet.group_hr_timesheet_user"/> - <button class="btn-primary btn-info" name="action_timer_resume" type="object" string="Resume" - attrs="{'invisible': [('display_timer_resume', '=', False)]}" groups="hr_timesheet.group_hr_timesheet_user"/> - </xpath> - <xpath expr="//field[@name='stage_id']" position="attributes"> - <attribute name="class">ml-2</attribute> - </xpath> - <xpath expr="//field[@name='stage_id']" position="before"> - <field name="timer_start" widget="timer_timer" class="text-danger ml-auto h2 ml-4 font-weight-bold" groups="hr_timesheet.group_hr_timesheet_user"/> - </xpath> - </field> - </record> - <record id="project_task_view_search" model="ir.ui.view"> <field name="name">project.task.view.search.inherit.sale.timesheet.enterprise</field> <field name="model">project.task</field> @@ -308,24 +241,5 @@ </field> </record> - <!-- Improve the task kanban in Project --> - <record id="project_task_view_kanban" model="ir.ui.view"> - <field name="name">project.task.kanban.timer</field> - <field name="model">project.task</field> - <field name="inherit_id" ref="project.view_task_kanban"/> - <field name="arch" type="xml"> - <xpath expr="//div[@name='date_deadline']" position="before"> - <field name="display_timesheet_timer" invisible="1"/> - <field name="timer_start" invisible="1"/> - <field name="timer_pause" invisible="1"/> - <t t-if="record.display_timesheet_timer && record.timer_pause.raw_value"> - <i class="fa fa-pause text-warning" title="Timer is Paused"></i> - </t> - <t t-elif="record.display_timesheet_timer && record.timer_start.raw_value"> - <i class="fa fa-play text-success" title="Timer is Running"></i> - </t> - </xpath> - </field> - </record> </data> </odoo> diff --git a/addons/hr_timesheet/wizard/project_task_create_timesheet.py b/addons/hr_timesheet/wizard/project_task_create_timesheet.py index d24792804a1..df74d492a10 100644 --- a/addons/hr_timesheet/wizard/project_task_create_timesheet.py +++ b/addons/hr_timesheet/wizard/project_task_create_timesheet.py @@ -36,9 +36,4 @@ class ProjectTaskCreateTimesheet(models.TransientModel): 'user_id': self.env.uid, 'unit_amount': self.time_spent, } - self.task_id.write({ - 'timer_start': False, - 'timer_pause': False, - 'timesheet_timer_last_stop': fields.datetime.now(), - }) return self.env['account.analytic.line'].create(values) diff --git a/addons/sale_timesheet/models/project.py b/addons/sale_timesheet/models/project.py index 42ceb21ff93..4cf6b451ca6 100644 --- a/addons/sale_timesheet/models/project.py +++ b/addons/sale_timesheet/models/project.py @@ -176,14 +176,13 @@ class ProjectTask(models.Model): display_create_order = fields.Boolean(compute='_compute_display_create_order') @api.depends( - 'allow_billable', 'allow_timesheets', 'sale_order_id', 'display_timesheet_timer', - 'timer_start') + 'allow_billable', 'allow_timesheets', 'sale_order_id') def _compute_display_create_order(self): for task in self: show = True if not task.allow_billable or not task.allow_timesheets or \ task.billable_type == 'employee_rate' or not task.partner_id or \ - task.sale_order_id or (task.display_timesheet_timer and task.timer_start): + task.sale_order_id: show = False task.display_create_order = show diff --git a/addons/sale_timesheet/models/sale_order.py b/addons/sale_timesheet/models/sale_order.py index 4078537eb7a..9ae4af48edd 100644 --- a/addons/sale_timesheet/models/sale_order.py +++ b/addons/sale_timesheet/models/sale_order.py @@ -114,7 +114,7 @@ class SaleOrderLine(models.Model): def _timesheet_create_project(self): project = super()._timesheet_create_project() - project.write({'allow_timesheets': True, 'allow_timesheet_timer': True}) + project.write({'allow_timesheets': True}) return project def _recompute_qty_to_invoice(self, date): diff --git a/addons/sale_timesheet/views/project_task_views.xml b/addons/sale_timesheet/views/project_task_views.xml index c57cfac4ca7..54d2a598a7b 100644 --- a/addons/sale_timesheet/views/project_task_views.xml +++ b/addons/sale_timesheet/views/project_task_views.xml @@ -52,9 +52,9 @@ <record id="project_project_view_form_simplified_inherit" model="ir.ui.view"> <field name="name">project.project.view.form.simplified.inherit</field> <field name="model">project.project</field> - <field name="inherit_id" ref="hr_timesheet.project_project_view_form_simplified_inherit"/> + <field name="inherit_id" ref="hr_timesheet.project_project_view_form_simplified_inherit_timesheet"/> <field name="arch" type="xml"> - <field name="allow_timesheet_timer" position="after"> + <field name="allow_timesheets" position="after"> <field name="billable_type" invisible="1"/> <field name="company_id" invisible="1"/> <field name="allow_billable" attrs="{'invisible': [('billable_type', '=', 'employee_rate')]}"/> diff --git a/addons/test_timer/__init__.py b/addons/test_timer/__init__.py deleted file mode 100644 index dc5e6b693d1..00000000000 --- a/addons/test_timer/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from . import models diff --git a/addons/test_timer/__manifest__.py b/addons/test_timer/__manifest__.py deleted file mode 100644 index 12bd6e31e32..00000000000 --- a/addons/test_timer/__manifest__.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- - -{ - 'name': 'Timer Tests', - 'version': '1.0', - 'category': 'Hidden/Tests', - 'sequence': 8765, - 'summary': 'Timer Tests: feature and performance tests for timer', - 'description': """This module contains tests related to timer. Those are -contained in a separate module as it contains models used only to perform -tests independently to functional aspects of other models. """, - 'depends': ['timer'], - 'data': [ - 'security/ir.model.access.csv', - ], - 'demo': [ - ], - 'installable': True, - 'application': False, -} diff --git a/addons/test_timer/models/__init__.py b/addons/test_timer/models/__init__.py deleted file mode 100644 index e2a77737638..00000000000 --- a/addons/test_timer/models/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from . import timer_test diff --git a/addons/test_timer/models/timer_test.py b/addons/test_timer/models/timer_test.py deleted file mode 100644 index 5eb26b7618d..00000000000 --- a/addons/test_timer/models/timer_test.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo import fields, models - - -class TimerTest(models.Model): - """ A very simple model only inheriting from timer.mixin to test - timer features """ - _description = 'Timer Model' - _name = 'timer.test' - _inherit = ['timer.mixin'] - - name = fields.Char(required=1) - - -class OverrideInterruptionTimerTest(models.Model): - """ A very simple model inheriting from timer.mixin and - overriding _action_interrupt_user_timers() """ - _description = 'Interruption Timer Model' - _name = 'interruption.timer.test' - _inherit = ['timer.mixin'] - - def _action_interrupt_user_timers(self): - self.action_timer_stop() diff --git a/addons/test_timer/security/ir.model.access.csv b/addons/test_timer/security/ir.model.access.csv deleted file mode 100644 index d3c447a94e4..00000000000 --- a/addons/test_timer/security/ir.model.access.csv +++ /dev/null @@ -1,3 +0,0 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_timer_test_user,timer.test.user,model_timer_test,base.group_user,1,1,1,1 -access_interruption_timer_test_user,timer.interruption.test.user,model_interruption_timer_test,base.group_user,1,1,1,1 diff --git a/addons/test_timer/tests/__init__.py b/addons/test_timer/tests/__init__.py deleted file mode 100644 index a52db405139..00000000000 --- a/addons/test_timer/tests/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from . import test_timer
\ No newline at end of file diff --git a/addons/test_timer/tests/test_timer.py b/addons/test_timer/tests/test_timer.py deleted file mode 100644 index 427210524da..00000000000 --- a/addons/test_timer/tests/test_timer.py +++ /dev/null @@ -1,141 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo.exceptions import AccessError - -from odoo.tests.common import SavepointCase - - -class TestTimer(SavepointCase): - - @classmethod - def setUpClass(cls): - super(TestTimer, cls).setUpClass() - - # Setup mixin - cls.test_timer = cls.env['timer.test'].create({'name': 'Timer 1'}) - cls.test_timer_bis = cls.env['timer.test'].create({'name': 'Timer 2'}) - - # Setup users - cls.usr1 = cls.env['res.users'].create({ - 'name': 'Usr1', - 'login': 'Usr1', - 'email': 'usr1@test.com', - 'groups_id': [(6, 0, [cls.env.ref('base.group_user').id])], - }) - - cls.usr2 = cls.env['res.users'].create({ - 'name': 'Usr2', - 'login': 'Usr2', - 'email': 'usr2@test.com', - 'groups_id': [(6, 0, [cls.env.ref('base.group_user').id])], - }) - - - def test_timer_from_self_user(self): - - # Start and stop - self.test_timer.action_timer_start() - self.assertEqual(len(self.test_timer.user_timer_id), 1, 'It should have created one timer') - - self.test_timer.action_timer_stop() - self.assertEqual(len(self.test_timer.user_timer_id), 0, 'It should have delete the timer') - - # Start the first timer then the second one - self.test_timer.action_timer_start() - self.test_timer_bis.action_timer_start() - - self.assertEqual(len(self.env['timer.timer'].search([])), 2, 'It should have created 2 timers for the same user') - self.assertFalse(self.test_timer.is_timer_running, "The first timer should be in pause because the second one interrupt it") - self.assertTrue(self.test_timer_bis.is_timer_running, 'The second timer should be running') - - # Resume the first one - self.test_timer.action_timer_resume() - - self.assertTrue(self.test_timer.is_timer_running, 'The first timer should be running after being resumed') - self.assertFalse(self.test_timer_bis.is_timer_running, 'The second timer should be in pause when another timer has been started') - - # Start a new test timer with interruption override - override_test_timer = self.env['interruption.timer.test'].create({}) - override_test_timer.action_timer_start() - - self.assertEqual(len(self.env['timer.timer'].search([])), 3, 'A third timer should be created') - self.assertFalse(self.test_timer.is_timer_running, 'The first timer has been interrupted and should be in pause') - self.assertFalse(self.test_timer_bis.is_timer_running, 'The second timer has been interrupted and should be in pause') - self.assertTrue(override_test_timer.is_timer_running, 'The third timer should be running') - - # Resume another timer to interrupt the new one - self.test_timer_bis.action_timer_resume() - - self.assertEqual(len(self.env['timer.timer'].search([])), 2, 'It should remains only 2 timers') - self.assertEqual(len(override_test_timer.user_timer_id), 0, 'The third timer should be deleted because of his override method') - - def test_timer_with_many_users(self): - - # 2 users, 1 record = 2 timers - self.test_timer.with_user(self.usr1).action_timer_start() - self.test_timer.with_user(self.usr2).action_timer_start() - - self.assertEqual(len(self.env['timer.timer'].search([])), 2, 'It should have created two timers') - self.assertEqual(len(self.test_timer.with_user(self.usr1).user_timer_id), 1, 'It should exist only one timer for this user, model and record') - self.assertEqual(len(self.test_timer.with_user(self.usr2).user_timer_id), 1, 'It should exist only one timer for this user, model and record') - - # Stop one of them - self.test_timer.with_user(self.usr2).action_timer_stop() - - self.assertEqual(len(self.env['timer.timer'].search([])), 1, 'It should have deleted one timer') - self.assertEqual(len(self.test_timer.with_user(self.usr1).user_timer_id), 1, 'It should exist only one timer for this user, model and record') - self.assertEqual(len(self.test_timer.with_user(self.usr2).user_timer_id), 0, 'It shouldn\'t exit one timer for this user, model and record') - - def test_timer_rounding(self): - - minutes_spent, minimum, rounding = 4.5,10,5 - result = self.test_timer._timer_rounding(minutes_spent, minimum, rounding) - self.assertEqual(result, 10, 'It should have been round to the minimum amount') - - minutes_spent = 12.4 - result = self.test_timer._timer_rounding(minutes_spent, minimum, rounding) - self.assertEqual(result, 15, 'It should have been round to the next multiple of 15') - - def test_timer_access_security(self): - - # Create usr1's timer1 - timer1 = self.env['timer.timer'].with_user(self.usr1).create({ - 'timer_start' : False, - 'timer_pause' : False, - 'is_timer_running' : False, - 'res_model' : self.test_timer._name, - 'res_id' : self.test_timer.id, - 'user_id' : self.usr1.id, - }) - - # Create usr1's timer2 - timer2 = self.env['timer.timer'].with_user(self.usr1).create({ - 'timer_start' : False, - 'timer_pause' : False, - 'is_timer_running' : False, - 'res_model' : self.test_timer_bis._name, - 'res_id' : self.test_timer_bis.id, - 'user_id' : self.usr1.id, - }) - - # Start timer2 - timer2.action_timer_start() - - with self.assertRaises(AccessError): - - # Try to create a timer with usr1 for usr2 (Create) - self.env['timer.timer'].with_user(self.usr1).create({ - 'timer_start' : False, - 'timer_pause' : False, - 'is_timer_running' : False, - 'res_model' : self.test_timer._name, - 'res_id' : self.test_timer.id, - 'user_id' : self.usr2.id, - }) - - # Try to start the timer1 with another usr2 (Write) - timer1.with_user(self.usr2).action_timer_start() - - # Try to stop the timer2 with usr2 (Unlink) - timer2.with_user(self.usr2).action_timer_stop() diff --git a/addons/timer/__init__.py b/addons/timer/__init__.py deleted file mode 100644 index dc5e6b693d1..00000000000 --- a/addons/timer/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from . import models diff --git a/addons/timer/__manifest__.py b/addons/timer/__manifest__.py deleted file mode 100644 index ee8832dfe1b..00000000000 --- a/addons/timer/__manifest__.py +++ /dev/null @@ -1,27 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - - -{ - 'name': 'Timer', - 'version': '1.0', - 'sequence': 24, - 'summary': 'Record time', - 'category': 'Services/Timesheets', - 'description': """ -This module implements a timer. -========================================== - -It adds a timer to a view for time recording purpose - """, - 'depends': ['web', 'mail'], - 'data': [ - 'security/timer_security.xml', - 'security/ir.model.access.csv', - 'views/assets.xml', - ], - 'demo': [], - 'installable': True, - 'application': False, - 'auto_install': False, -} diff --git a/addons/timer/i18n/timer.pot b/addons/timer/i18n/timer.pot deleted file mode 100644 index e9ffea53b48..00000000000 --- a/addons/timer/i18n/timer.pot +++ /dev/null @@ -1,127 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * timer -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server saas~13.2\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-02-13 07:24+0000\n" -"PO-Revision-Date: 2020-02-13 07:24+0000\n" -"Last-Translator: \n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Plural-Forms: \n" - -#. module: timer -#: model:ir.model.fields,field_description:timer.field_timer_timer__create_uid -msgid "Created by" -msgstr "" - -#. module: timer -#: model:ir.model.fields,field_description:timer.field_timer_timer__create_date -msgid "Created on" -msgstr "" - -#. module: timer -#: model:ir.model.fields,field_description:timer.field_timer_mixin__display_name -#: model:ir.model.fields,field_description:timer.field_timer_timer__display_name -msgid "Display Name" -msgstr "" - -#. module: timer -#: model:ir.model.fields,field_description:timer.field_timer_mixin__display_timer_pause -msgid "Display Timer Pause" -msgstr "" - -#. module: timer -#: model:ir.model.fields,field_description:timer.field_timer_mixin__display_timer_resume -msgid "Display Timer Resume" -msgstr "" - -#. module: timer -#: model:ir.model.fields,field_description:timer.field_timer_mixin__display_timer_start_primary -msgid "Display Timer Start Primary" -msgstr "" - -#. module: timer -#: model:ir.model.fields,field_description:timer.field_timer_mixin__display_timer_stop -msgid "Display Timer Stop" -msgstr "" - -#. module: timer -#: model:ir.model.fields,field_description:timer.field_timer_mixin__id -#: model:ir.model.fields,field_description:timer.field_timer_timer__id -msgid "ID" -msgstr "" - -#. module: timer -#: model:ir.model.fields,field_description:timer.field_timer_mixin__is_timer_running -#: model:ir.model.fields,field_description:timer.field_timer_timer__is_timer_running -msgid "Is Timer Running" -msgstr "" - -#. module: timer -#: model:ir.model.fields,field_description:timer.field_timer_mixin____last_update -#: model:ir.model.fields,field_description:timer.field_timer_timer____last_update -msgid "Last Modified on" -msgstr "" - -#. module: timer -#: model:ir.model.fields,field_description:timer.field_timer_timer__write_uid -msgid "Last Updated by" -msgstr "" - -#. module: timer -#: model:ir.model.fields,field_description:timer.field_timer_timer__write_date -msgid "Last Updated on" -msgstr "" - -#. module: timer -#: model:ir.model.constraint,message:timer.constraint_timer_timer_unique_timer -msgid "Only one timer occurrence by model, record and user" -msgstr "" - -#. module: timer -#: model:ir.model.fields,field_description:timer.field_timer_timer__res_id -msgid "Res" -msgstr "" - -#. module: timer -#: model:ir.model.fields,field_description:timer.field_timer_timer__res_model -msgid "Res Model" -msgstr "" - -#. module: timer -#: model:ir.model.fields,field_description:timer.field_timer_mixin__timer_pause -#: model:ir.model.fields,field_description:timer.field_timer_timer__timer_pause -msgid "Timer Last Pause" -msgstr "" - -#. module: timer -#: model:ir.model,name:timer.model_timer_mixin -msgid "Timer Mixin" -msgstr "" - -#. module: timer -#: model:ir.model,name:timer.model_timer_timer -msgid "Timer Module" -msgstr "" - -#. module: timer -#: model:ir.model.fields,field_description:timer.field_timer_mixin__timer_start -#: model:ir.model.fields,field_description:timer.field_timer_timer__timer_start -msgid "Timer Start" -msgstr "" - -#. module: timer -#: model:ir.model.fields,field_description:timer.field_timer_timer__user_id -msgid "User" -msgstr "" - -#. module: timer -#: model:ir.model.fields,field_description:timer.field_timer_mixin__user_timer_id -msgid "User Timer" -msgstr "" diff --git a/addons/timer/models/__init__.py b/addons/timer/models/__init__.py deleted file mode 100644 index 66c7f179a40..00000000000 --- a/addons/timer/models/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from . import timer -from . import timer_mixin diff --git a/addons/timer/models/timer.py b/addons/timer/models/timer.py deleted file mode 100644 index 0da18794cd2..00000000000 --- a/addons/timer/models/timer.py +++ /dev/null @@ -1,70 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo import models, fields, api -from odoo.exceptions import ValidationError - -class TimerTimer(models.Model): - _name = 'timer.timer' - _description = 'Timer Module' - - timer_start = fields.Datetime("Timer Start") - timer_pause = fields.Datetime("Timer Last Pause") - is_timer_running = fields.Boolean(compute="_compute_is_timer_running") - res_model = fields.Char(required=True) - res_id = fields.Integer(required=True) - user_id = fields.Many2one('res.users') - - _sql_constraints = [( - 'unique_timer', 'UNIQUE(res_model, res_id, user_id)', - 'Only one timer occurrence by model, record and user')] - - @api.depends('timer_start', 'timer_pause') - def _compute_is_timer_running(self): - for record in self: - record.is_timer_running = record.timer_start and not record.timer_pause - - @api.model - def create(self, vals): - # Reset the user_timer_id to force the recomputation - self.env[vals['res_model']].invalidate_cache(fnames=['user_timer_id'], ids=[vals['res_id']]) - return super().create(vals) - - def action_timer_start(self): - if not self.timer_start: - self.write({'timer_start': fields.Datetime.now()}) - - def action_timer_stop(self): - """ Stop the timer and return the spent minutes since it started - :return minutes_spent if the timer is started, - otherwise return False - """ - if not self.timer_start: - return False - minutes_spent = self._get_minutes_spent() - self.write({'timer_start': False, 'timer_pause': False}) - return minutes_spent - - def _get_minutes_spent(self): - start_time = self.timer_start - stop_time = fields.Datetime.now() - # timer was either running or paused - if self.timer_pause: - start_time += (stop_time - self.timer_pause) - return (stop_time - start_time).total_seconds() / 60 - - def action_timer_pause(self): - self.write({'timer_pause': fields.Datetime.now()}) - - def action_timer_resume(self): - new_start = self.timer_start + (fields.Datetime.now() - self.timer_pause) - self.write({'timer_start': new_start, 'timer_pause': False}) - - @api.model - def get_server_time(self): - """ Returns the server time. - The timer widget needs the server time instead of the client time - to avoid time desynchronization issues like the timer beginning at 0:00 - and not 23:59 and so on. - """ - return fields.Datetime.now() diff --git a/addons/timer/security/ir.model.access.csv b/addons/timer/security/ir.model.access.csv deleted file mode 100644 index 852a5f208df..00000000000 --- a/addons/timer/security/ir.model.access.csv +++ /dev/null @@ -1,2 +0,0 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_timer_user,timer.timer.user,timer.model_timer_timer,base.group_user,1,1,1,1 diff --git a/addons/timer/security/timer_security.xml b/addons/timer/security/timer_security.xml deleted file mode 100644 index 8bad09e2641..00000000000 --- a/addons/timer/security/timer_security.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<odoo noupdate="1"> - - <record id="timer_user_rule_create-write-delete" model="ir.rule"> - <field name="name">timer.user.rule.create-write-delete</field> - <field name="model_id" ref="timer.model_timer_timer"/> - <field name="domain_force">[ - ('user_id', '=', user.id) - ]</field> - <field name="groups" eval="[(4, ref('base.group_user'))]"/> - <field name="perm_create" eval="1"/> - <field name="perm_write" eval="1"/> - <field name="perm_unlink" eval="1"/> - <field name="perm_read" eval="1"/> - </record> - - <record id="timer_not_user_rule_create-write-delete" model="ir.rule"> - <field name="name">timer.not.user.rule.create-write-delete</field> - <field name="model_id" ref="timer.model_timer_timer"/> - <field name="domain_force">[ - ('user_id', '!=', user.id) - ]</field> - <field name="groups" eval="[(4, ref('base.group_user'))]"/> - <field name="perm_create" eval="0"/> - <field name="perm_write" eval="0"/> - <field name="perm_unlink" eval="0"/> - <field name="perm_read" eval="1"/> - </record> - -</odoo> diff --git a/addons/timer/static/src/js/timer.js b/addons/timer/static/src/js/timer.js deleted file mode 100644 index 0042ebfaead..00000000000 --- a/addons/timer/static/src/js/timer.js +++ /dev/null @@ -1,63 +0,0 @@ -odoo.define('timer.timer', function (require) { -"use strict"; - -var fieldRegistry = require('web.field_registry'); -var AbstractField = require('web.AbstractField'); -var Timer = require('timer.Timer'); - -var TimerFieldWidget = AbstractField.extend({ - - /** - * @override - * @private - */ - isSet: function () { - return true; - }, - /** - * @override - * @private - */ - _render: function () { - this._super.apply(this, arguments); - this._startTimeCounter(); - }, - /** - * @override - */ - destroy: function () { - this._super.apply(this, arguments); - clearInterval(this.timer); - }, - /** - * @private - */ - _startTimeCounter: async function () { - if (this.record.data.timer_start) { - const serverTime = this.record.data.timer_pause || await this._getServerTime(); - this.time = Timer.createTimer(0, this.record.data.timer_start, serverTime); - this.$el.text(this.time.toString()); - this.timer = setInterval(() => { - if (this.record.data.timer_pause) { - clearInterval(this.timer); - } else { - this.time.addSecond(); - this.$el.text(this.time.toString()); - } - }, 1000); - } else if (!this.record.data.timer_pause){ - clearInterval(this.timer); - } - }, - _getServerTime: function () { - return this._rpc({ - model: 'timer.timer', - method: 'get_server_time', - args: [] - }); - } -}); - -fieldRegistry.add('timer_timer', TimerFieldWidget); - -}); diff --git a/addons/timer/static/src/js/timer_mixin.js b/addons/timer/static/src/js/timer_mixin.js deleted file mode 100644 index 7a70e81341e..00000000000 --- a/addons/timer/static/src/js/timer_mixin.js +++ /dev/null @@ -1,119 +0,0 @@ -odoo.define('timer.Timer', function (require) { -"use strict"; - - /** - * This class improves the timer display using the - * unit_amount field on account.analytic.line. - */ - class Timer { - constructor(hours, minutes, seconds) { - this.hours = hours; - this.minutes = minutes; - this.seconds = seconds; - } - - /** - * Convert float to time - * @param {number} float - */ - static convertFloatToTime(float) { - if (float === 0) { - return new Timer(0, 0, 0); - } - - let minutes = float % 1; - const hours = float - minutes; - minutes *= 60; - - return new Timer(hours, Math.round(minutes), 0); - } - - /** - * Create timer - * @param {number} unit_amount - * @param {String} timer_start - * @param {String} serverTime - */ - static createTimer(unit_amount, timer_start, serverTime) { - const timer = this.convertFloatToTime(unit_amount); - - timer.addTime( - moment.utc( - Math.abs(moment.utc(serverTime) - .diff(moment.utc(timer_start)) - )).format("HH:mm:ss") - ); - - return timer; - } - - addHours(hours) { - this.hours += hours; - } - - addMinutes(minutes) { - minutes += this.minutes; - - this.minutes = minutes % 60; - this.addHours(Math.floor(minutes / 60)); - } - - addSeconds(seconds) { - seconds += this.seconds; - this.seconds = seconds % 60; - this.addMinutes(Math.floor(seconds / 60)); - } - - display2digits(number) { - return number > 9 ? "" + number : "0" + number; - } - - addSecond() { - this.seconds += 1; - if (this.seconds === 60) { - this.minutes += 1; - this.seconds = 0; - - if (this.minutes === 60) { - this.hours += 1; - this.minutes = 0; - } - } - } - - addTime(time) { - if (typeof time == 'string' && time.indexOf(':') !== -1) { - let [hour, minute, second] = time.split(':'); - - hour = parseInt(hour); - minute = parseInt(minute); - second = (second === undefined) ? 0 : parseInt(second); - - this.addSeconds(second); - this.addMinutes(minute); - this.addHours(hour); - } - } - - convertToFloat() { - return (this.hours * 60 + this.minutes) * 60 / 3600; - } - - convertToSeconds() { - return (this.hours * 60 + this.minutes) * 60 + this.seconds; - } - - toString() { - const time = { - hours: this.display2digits(this.hours), - minutes: this.display2digits(this.minutes), - seconds: this.display2digits(this.seconds) - }; - - return `${time.hours}:${time.minutes}:${time.seconds}`; - } - } - - return Timer; - -}); diff --git a/addons/timer/static/src/js/timer_toggle_button.js b/addons/timer/static/src/js/timer_toggle_button.js index 78274e05e0c..d189d996502 100644 --- a/addons/timer/static/src/js/timer_toggle_button.js +++ b/addons/timer/static/src/js/timer_toggle_button.js @@ -52,12 +52,11 @@ const TimerToggleButton = FieldToggleBoolean.extend({ */ _onToggleButton: async function (event) { const context = this.record.getContext(); - const prevent_deletion = this.attrs.options && this.attrs.options.prevent_deletion || false; event.stopPropagation(); const result = await this._rpc({ model: this.model, method: this._getActionButton(), - context: $.extend({}, context, {prevent_deletion: prevent_deletion}), + context: context, args: [this.res_id] }); diff --git a/addons/timer/static/src/scss/timer_button.scss b/addons/timer/static/src/scss/timer_button.scss deleted file mode 100644 index 8b269fa8b20..00000000000 --- a/addons/timer/static/src/scss/timer_button.scss +++ /dev/null @@ -1,26 +0,0 @@ -.o-timer-button { - &:focus { - border: none !important; - outline: 0 !important; - } - - & > i { - transition: 0.3s; - - &.o-timer-play-button { - color: $link-color !important; - } - - &.o-timer-stop-button { - color: $red !important; - } - } - - &:hover > i.o-timer-play-button { - color: $link-hover-color !important; - } - - &:hover > i.o-timer-stop-button { - color: darken($red, 15%) !important; - } -} diff --git a/addons/timer/views/assets.xml b/addons/timer/views/assets.xml deleted file mode 100644 index a8565a53515..00000000000 --- a/addons/timer/views/assets.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0"?> -<odoo> - <template id="assets_backend" name="timer assets" inherit_id="web.assets_backend"> - <xpath expr="." position="inside"> - <link type="text/scss" href="/timer/static/src/scss/timer_button.scss" rel="stylesheet"/> - <script type="text/javascript" src="/timer/static/src/js/timer_mixin.js"/> - <script type="text/javascript" src="/timer/static/src/js/timer.js"/> - <script type="text/javascript" src="/timer/static/src/js/timer_toggle_button.js"/> - </xpath> - </template> -</odoo> |
