+ Create a new quotation, the first step of a new sale!
+
+ Once the quotation is confirmed, it becomes a sales order. You will be able to create an invoice and collect the payment.
+
+
+
+
tree
diff --git a/addons/sale_project/models/project.py b/addons/sale_project/models/project.py
index a1695c461d5..0e3806ff538 100644
--- a/addons/sale_project/models/project.py
+++ b/addons/sale_project/models/project.py
@@ -16,6 +16,7 @@ class Project(models.Model):
help="Sales order item to which the project is linked. Link the timesheet entry to the sales order item defined on the project. "
"Only applies on tasks without sale order item defined, and if the employee is not in the 'Employee/Sales Order Item Mapping' of the project.")
sale_order_id = fields.Many2one('sale.order', 'Sales Order', domain="[('partner_id', '=', partner_id)]", copy=False, help="Sales order to which the project is linked.")
+ project_overview = fields.Boolean('Show Project Overview', compute='_compute_project_overview')
_sql_constraints = [
('sale_order_required_if_sale_line', "CHECK((sale_line_id IS NOT NULL AND sale_order_id IS NOT NULL) OR (sale_line_id IS NULL))", 'The project should be linked to a sale order to select a sale order item.'),
@@ -27,6 +28,13 @@ class Project(models.Model):
defaults['sale_line_id'] = False
return defaults
+ @api.depends('analytic_account_id')
+ def _compute_project_overview(self):
+ overview = self.env['project.project']
+ if self.user_has_groups('analytic.group_analytic_accounting'):
+ overview = self.filtered(lambda p: p.analytic_account_id)
+ overview.project_overview = True
+ (self - overview).project_overview = False
class ProjectTask(models.Model):
_inherit = "project.task"
diff --git a/addons/sale_project/models/sale_order.py b/addons/sale_project/models/sale_order.py
index e779902dcc4..065105b9e8c 100644
--- a/addons/sale_project/models/sale_order.py
+++ b/addons/sale_project/models/sale_order.py
@@ -17,6 +17,8 @@ class SaleOrder(models.Model):
'project.project', 'Project', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]},
help='Select a non billable project on which tasks can be created.')
project_ids = fields.Many2many('project.project', compute="_compute_project_ids", string='Projects', copy=False, groups="project.group_project_user", help="Projects used in this sales order.")
+ project_overview = fields.Boolean('Show Project Overview', compute='_compute_project_overview')
+ project_count = fields.Integer(string='Number of Projects', compute='_compute_project_ids', groups='project.group_project_user')
@api.depends('order_line.product_id.project_id')
def _compute_tasks_ids(self):
@@ -33,6 +35,12 @@ class SaleOrder(models.Model):
service_tracking == 'task_in_project' for service_tracking in order.order_line.mapped('product_id.service_tracking')
)
+ @api.depends('project_ids')
+ def _compute_project_overview(self):
+ for order in self:
+ billable_projects = order.project_ids.filtered('sale_line_id')
+ order.project_overview = len(order.project_ids) == 1 and len(billable_projects) == 1 and billable_projects.project_overview
+
@api.depends('order_line.product_id', 'order_line.project_id')
def _compute_project_ids(self):
for order in self:
@@ -40,6 +48,7 @@ class SaleOrder(models.Model):
projects |= order.order_line.mapped('project_id')
projects |= order.project_id
order.project_ids = projects
+ order.project_count = len(projects)
@api.onchange('project_id')
def _onchange_project_id(self):
@@ -92,16 +101,22 @@ class SaleOrder(models.Model):
def action_view_project_ids(self):
self.ensure_one()
+ if len(self.project_ids) == 1 and self.project_overview:
+ return self.project_id.action_view_account_analytic_line()
+
view_form_id = self.env.ref('project.edit_project').id
view_kanban_id = self.env.ref('project.view_project_kanban').id
action = {
'type': 'ir.actions.act_window',
'domain': [('id', 'in', self.project_ids.ids)],
- 'views': [(view_kanban_id, 'kanban'), (view_form_id, 'form')],
'view_mode': 'kanban,form',
'name': _('Projects'),
'res_model': 'project.project',
}
+ if len(self.project_ids) == 1:
+ action.update({'views': [(view_form_id, 'form')], 'res_id': self.project_ids.id})
+ else:
+ action['views'] = [(view_kanban_id, 'kanban'), (view_form_id, 'form')]
return action
def write(self, values):
diff --git a/addons/sale_project/views/sale_order_views.xml b/addons/sale_project/views/sale_order_views.xml
index 49c4e7cf519..6d2fcf9afd8 100644
--- a/addons/sale_project/views/sale_order_views.xml
+++ b/addons/sale_project/views/sale_order_views.xml
@@ -10,9 +10,12 @@
-