-
-
-
-
-
-
-
- Date |
- Employee |
- Project |
- Task |
- Description |
- Duration (days) |
- Duration (hours) |
-
-
-
- |
- |
- |
- |
- |
-
-
-
- |
-
-
+
+
+
+
+
+
+
+
+
+
+
+ Date |
+ Employee |
+ Project |
+ Task |
+ Description |
+ Duration (days) |
+ Duration (hours) |
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+
+ |
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+ Timesheets for sales order item:
+
+
+ ( Ordered, Remaining)
+
+
+ |
+
+
+ Total:
+
+
+ Total:
+
+ |
+
+
+
+ Sale Order Item |
+
+
+ |
diff --git a/addons/sale_timesheet_edit/__init__.py b/addons/sale_timesheet_edit/__init__.py
new file mode 100644
index 0000000000000..dc5e6b693d19d
--- /dev/null
+++ b/addons/sale_timesheet_edit/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import models
diff --git a/addons/sale_timesheet_edit/__manifest__.py b/addons/sale_timesheet_edit/__manifest__.py
new file mode 100644
index 0000000000000..6178dbe013584
--- /dev/null
+++ b/addons/sale_timesheet_edit/__manifest__.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+# TODO: [XBO] merge with sale_timesheet module in master
+{
+ 'name': 'Sales Timesheet Edit',
+ 'category': 'Hidden',
+ 'summary': 'Edit the sale order line linked in the timesheets',
+ 'description': """
+Allow to edit sale order line in the timesheets
+===============================================
+
+This module adds the edition of the sale order line
+set in the timesheets. This allows adds more flexibility
+to the user to easily change the sale order line on a
+timesheet in task form view when it is needed.
+""",
+ 'depends': ['sale_timesheet'],
+ 'data': [
+ 'views/assets.xml',
+ 'views/project_task.xml',
+ ],
+ 'demo': [],
+ 'auto_install': True,
+}
diff --git a/addons/sale_timesheet_edit/models/__init__.py b/addons/sale_timesheet_edit/models/__init__.py
new file mode 100644
index 0000000000000..bf8826f4bc040
--- /dev/null
+++ b/addons/sale_timesheet_edit/models/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import account_analytic_line
+from . import project
diff --git a/addons/sale_timesheet_edit/models/account_analytic_line.py b/addons/sale_timesheet_edit/models/account_analytic_line.py
new file mode 100644
index 0000000000000..5ff797ddc34d7
--- /dev/null
+++ b/addons/sale_timesheet_edit/models/account_analytic_line.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models
+
+
+# TODO: [XBO] merge with account.analytic.line in the sale_timesheet module in master.
+class AccountAnalyticLine(models.Model):
+ _inherit = 'account.analytic.line'
+
+ is_so_line_edited = fields.Boolean()
+
+ @api.depends('task_id.sale_line_id', 'project_id.sale_line_id', 'project_id.allow_billable', 'employee_id')
+ def _compute_so_line(self):
+ super(AccountAnalyticLine, self.filtered(lambda t: not t.is_so_line_edited))._compute_so_line()
+
+ def _check_sale_line_in_project_map(self):
+ # TODO: [XBO] remove me in master, now we authorize to manually edit the so_line, then this so_line can be different of the one in task/project/map_entry
+ # !!! Override of the method in sale_timesheet !!!
+ return
diff --git a/addons/sale_timesheet_edit/models/project.py b/addons/sale_timesheet_edit/models/project.py
new file mode 100644
index 0000000000000..b10bafddbcf8a
--- /dev/null
+++ b/addons/sale_timesheet_edit/models/project.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models
+
+
+class Project(models.Model):
+ _inherit = 'project.project'
+
+ def _get_not_billed_timesheets(self):
+ """ Get the timesheets not invoiced and the SOL has not manually been edited
+ FIXME: [XBO] this change must be done in the _update_timesheets_sale_line_id
+ rather than this method in master to keep the initial behaviour of this method.
+ """
+ return super(Project, self)._get_not_billed_timesheets() - self.mapped('timesheet_ids').filtered('is_so_line_edited')
diff --git a/addons/sale_timesheet_edit/static/src/js/so_line_one2many.js b/addons/sale_timesheet_edit/static/src/js/so_line_one2many.js
new file mode 100644
index 0000000000000..bc638b04b3451
--- /dev/null
+++ b/addons/sale_timesheet_edit/static/src/js/so_line_one2many.js
@@ -0,0 +1,28 @@
+odoo.define('sale_timesheet_edit.so_line_many2one', function (require) {
+"use strict";
+
+const fieldRegistry = require('web.field_registry');
+const FieldOne2Many = require('web.relational_fields').FieldOne2Many;
+
+const SoLineOne2Many = FieldOne2Many.extend({
+ _onFieldChanged: function (ev) {
+ if (
+ ev.data.changes &&
+ ev.data.changes.hasOwnProperty('timesheet_ids') &&
+ ev.data.changes.timesheet_ids.operation === 'UPDATE' &&
+ ev.data.changes.timesheet_ids.data.hasOwnProperty('so_line')) {
+ const line = this.value.data.find(line => {
+ return line.id === ev.data.changes.timesheet_ids.id;
+ });
+ if (!line.is_so_line_edited) {
+ ev.data.changes.timesheet_ids.data.is_so_line_edited = true;
+ }
+ }
+ this._super.apply(this, arguments);
+ }
+});
+
+
+fieldRegistry.add('so_line_one2many', SoLineOne2Many);
+
+});
diff --git a/addons/sale_timesheet_edit/views/assets.xml b/addons/sale_timesheet_edit/views/assets.xml
new file mode 100644
index 0000000000000..b8909b4496452
--- /dev/null
+++ b/addons/sale_timesheet_edit/views/assets.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/sale_timesheet_edit/views/project_task.xml b/addons/sale_timesheet_edit/views/project_task.xml
new file mode 100644
index 0000000000000..f9f7e38e3eecf
--- /dev/null
+++ b/addons/sale_timesheet_edit/views/project_task.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+ project.task.form.view.form.inherit.sale.timesheet.edit
+ project.task
+
+
+
+ so_line_one2many
+
+
+ 0
+ [('is_service', '=', True), ('order_partner_id', 'child_of', parent.commercial_partner_id), ('is_expense', '=', False), ('state', 'in', ['sale', 'done']), ('order_id', '=?', parent.project_sale_order_id)]
+ {'no_create': True, 'no_open': True}
+
+
+
+
+
+
+ project.task.form.view.form.inherit.sale.timesheet.editable
+ project.task
+
+
+
+ {'no_create': True}
+
+
+
+
+
+
+
+
+