[IMP] project: follow up the project overview removal
The project overview is a significant technical debt as it is a custom qweb view. It is quite limited: It is not possible to group the data, to filter on dates, SOs or Field Service projects. Improving this is very difficult and would require weeks of development that are not worth it. In any case, all the information provided by the project overview can be found elsewhere. The stat buttons of the report are basically duplicates of the ones from the project form view. Therefore, we are removing this report and its twin, the Project Costs and Revenues. In addition, analytic items lack context for the user to understand what generated a certain cost or revenue: there is no link to the source document; the entries are not categorized (e.g. it is not easy to understand if a cost comes from a timesheet cost, a purchase order or an expense); the billable type group by works fine for timesheets but then all the other entries are flagged as Undefined, which is not very helpful; there is no option to easily isolate costs from revenues. task-2646234 See odoo/enterprise#20936 closes odoo/odoo#76553 Signed-off-by: Laurent Stukkens (ltu) <ltu@odoo.com>
This commit is contained in:
@@ -22,6 +22,6 @@ class Project(models.Model):
|
||||
'action_type': 'object',
|
||||
'action': 'action_open_project_invoices',
|
||||
'show': bool(self.analytic_account_id) and self.invoice_count > 0,
|
||||
'sequence': 11,
|
||||
'sequence': 30,
|
||||
})
|
||||
return buttons
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
<field name="name">project.project.form.inherit</field>
|
||||
<field name="model">project.project</field>
|
||||
<field name="inherit_id" ref="project.edit_project"/>
|
||||
<field name="priority">50</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//button[@name='%(project.action_project_task_burndown_chart_report)d']" position="after">
|
||||
<xpath expr="//button[@name='action_view_analytic_account_entries']" position="after">
|
||||
<button name="action_open_project_invoices" type="object" class="oe_stat_button" icon="fa-pencil-square-o"
|
||||
attrs="{'invisible': ['|', ('invoice_count', '=', 0), ('analytic_account_id', '=', False)]}"
|
||||
groups="account.group_account_readonly">
|
||||
|
||||
@@ -224,7 +224,7 @@ class Project(models.Model):
|
||||
'action_type': 'object',
|
||||
'action': 'action_show_timesheets_by_employee_invoice_type',
|
||||
'show': self.allow_timesheets,
|
||||
'sequence': 4,
|
||||
'sequence': 6,
|
||||
})
|
||||
return buttons
|
||||
|
||||
|
||||
@@ -33,6 +33,20 @@
|
||||
<field name="name">External</field>
|
||||
</record>
|
||||
|
||||
<!-- Analytic Accounts -->
|
||||
<!-- Needed so that we can have the same analytic accounts on hr_timesheet and project_account_budget -->
|
||||
<record id="analytic_office_design" model="account.analytic.account">
|
||||
<field name="name">Office Design</field>
|
||||
</record>
|
||||
|
||||
<record id="analytic_research_development" model="account.analytic.account">
|
||||
<field name="name">Research & Development</field>
|
||||
</record>
|
||||
|
||||
<record id="analytic_renovations" model="account.analytic.account">
|
||||
<field name="name">Renovations</field>
|
||||
</record>
|
||||
|
||||
<!-- Task Stages -->
|
||||
<record id="project_stage_0" model="project.task.type">
|
||||
<field name="sequence">1</field>
|
||||
@@ -71,6 +85,7 @@
|
||||
<field name="favorite_user_ids" eval="[(4, ref('base.user_admin'))]"/>
|
||||
<field name="tag_ids" eval="[(4, ref('project.project_tags_05'))]"/>
|
||||
<field name="stage_id" ref="project.project_project_stage_1"/>
|
||||
<field name="analytic_account_id" ref="project.analytic_office_design"/>
|
||||
</record>
|
||||
|
||||
<record id="project_project_2" model="project.project">
|
||||
@@ -81,6 +96,7 @@
|
||||
<field name="favorite_user_ids" eval="[(4, ref('base.user_admin'))]"/>
|
||||
<field name="tag_ids" eval="[(4, ref('project.project_tags_04'))]"/>
|
||||
<field name="stage_id" ref="project.project_project_stage_1"/>
|
||||
<field name="analytic_account_id" ref="project.analytic_research_development"/>
|
||||
</record>
|
||||
|
||||
<record id="project_project_3" model="project.project">
|
||||
@@ -92,6 +108,7 @@
|
||||
<field name="favorite_user_ids" eval="[(4, ref('base.user_admin'))]"/>
|
||||
<field name="tag_ids" eval="[(4, ref('project_tags_04')), (4, ref('project_tags_02'))]"/>
|
||||
<field name="stage_id" ref="project.project_project_stage_2"/>
|
||||
<field name="analytic_account_id" ref="project.analytic_renovations"/>
|
||||
</record>
|
||||
|
||||
<!-- Personal Stages: Mitchell Admin-->
|
||||
|
||||
@@ -703,7 +703,7 @@ class Project(models.Model):
|
||||
'active_id': self.id,
|
||||
}),
|
||||
'show': True,
|
||||
'sequence': 2,
|
||||
'sequence': 3,
|
||||
}]
|
||||
if self.user_has_groups('project.group_project_rating'):
|
||||
buttons.append({
|
||||
@@ -713,7 +713,7 @@ class Project(models.Model):
|
||||
'action_type': 'object',
|
||||
'action': 'action_view_all_rating',
|
||||
'show': self.rating_active and self.rating_percentage_satisfaction > -1,
|
||||
'sequence': 5,
|
||||
'sequence': 15,
|
||||
})
|
||||
if self.user_has_groups('project.group_project_manager'):
|
||||
buttons.append({
|
||||
@@ -725,7 +725,7 @@ class Project(models.Model):
|
||||
'active_id': self.id,
|
||||
}),
|
||||
'show': True,
|
||||
'sequence': 7,
|
||||
'sequence': 60,
|
||||
})
|
||||
buttons.append({
|
||||
'icon': 'users',
|
||||
@@ -737,7 +737,7 @@ class Project(models.Model):
|
||||
'active_id': self.id,
|
||||
}),
|
||||
'show': True,
|
||||
'sequence': 23,
|
||||
'sequence': 66,
|
||||
})
|
||||
if self.user_has_groups('analytic.group_analytic_accounting'):
|
||||
buttons.append({
|
||||
@@ -747,7 +747,7 @@ class Project(models.Model):
|
||||
'action_type': 'object',
|
||||
'action': 'action_view_analytic_account_entries',
|
||||
'show': True,
|
||||
'sequence': 18,
|
||||
'sequence': 24,
|
||||
})
|
||||
return buttons
|
||||
|
||||
|
||||
@@ -322,19 +322,6 @@
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
<button name="%(action_project_task_burndown_chart_report)d" type="action" class="oe_stat_button" icon="fa-area-chart" groups="project.group_project_manager">
|
||||
<span class="o_stat_text">
|
||||
Burndown Chart
|
||||
</span>
|
||||
</button>
|
||||
<button class="oe_stat_button" type="object" name="action_view_analytic_account_entries" icon="fa-usd" attrs="{'invisible': [('analytic_account_id', '=', False)]}" groups="analytic.group_analytic_accounting">
|
||||
<div class="o_form_field o_stat_info">
|
||||
<span class="o_stat_value">
|
||||
<field name="analytic_account_balance"/>
|
||||
</span>
|
||||
<span class="o_stat_text">Gross Margin</span>
|
||||
</div>
|
||||
</button>
|
||||
<button class="oe_stat_button" name="%(project.project_update_all_action)d" type="action" groups="project.group_project_manager">
|
||||
<div class="pl-4">
|
||||
<field name="last_update_color" invisible="1"/>
|
||||
@@ -347,6 +334,19 @@
|
||||
<field name="last_update_status" readonly="1" widget="status_with_color" options="{'color_field': 'last_update_color', 'no_quick_edit': 1}"/>
|
||||
</div>
|
||||
</button>
|
||||
<button class="oe_stat_button" type="object" name="action_view_analytic_account_entries" icon="fa-usd" attrs="{'invisible': [('analytic_account_id', '=', False)]}" groups="analytic.group_analytic_accounting">
|
||||
<div class="o_form_field o_stat_info">
|
||||
<span class="o_stat_value">
|
||||
<field name="analytic_account_balance" widget="monetary"/>
|
||||
</span>
|
||||
<span class="o_stat_text">Gross Margin</span>
|
||||
</div>
|
||||
</button>
|
||||
<button name="%(action_project_task_burndown_chart_report)d" type="action" class="oe_stat_button" icon="fa-area-chart" groups="project.group_project_manager">
|
||||
<span class="o_stat_text">
|
||||
Burndown Chart
|
||||
</span>
|
||||
</button>
|
||||
<button class="oe_stat_button" name="%(project.project_collaborator_action)d" type="action" icon="fa-users" groups="project.group_project_manager">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span class="o_stat_value">
|
||||
|
||||
@@ -54,6 +54,6 @@ class Project(models.Model):
|
||||
'action_type': 'object',
|
||||
'action': 'action_open_project_expenses',
|
||||
'show': self.expenses_count > 0,
|
||||
'sequence': 10,
|
||||
'sequence': 33,
|
||||
})
|
||||
return buttons
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
<field name="name">project.project.form.inherit</field>
|
||||
<field name="model">project.project</field>
|
||||
<field name="inherit_id" ref="project.edit_project"/>
|
||||
<field name="priority">40</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//button[@name='%(project.action_project_task_burndown_chart_report)d']" position="after">
|
||||
<xpath expr="//button[@name='action_view_analytic_account_entries']" position="after">
|
||||
<button name="action_open_project_expenses" type="object" class="oe_stat_button" icon="fa-money" attrs="{'invisible': [('expenses_count', '=', 0)]}" groups="hr_expense.group_hr_expense_team_approver">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span class="o_stat_value">
|
||||
|
||||
@@ -46,7 +46,7 @@ class Project(models.Model):
|
||||
'action_type': 'object',
|
||||
'action': 'action_view_mrp_production',
|
||||
'show': self.production_count > 0,
|
||||
'sequence': 19,
|
||||
'sequence': 39,
|
||||
},
|
||||
{
|
||||
'icon': 'cog',
|
||||
@@ -55,7 +55,7 @@ class Project(models.Model):
|
||||
'action_type': 'object',
|
||||
'action': 'action_view_workorder',
|
||||
'show': self.workorder_count > 0,
|
||||
'sequence': 20,
|
||||
'sequence': 42,
|
||||
},
|
||||
{
|
||||
'icon': 'flask',
|
||||
@@ -64,6 +64,6 @@ class Project(models.Model):
|
||||
'action_type': 'object',
|
||||
'action': 'action_view_mrp_bom',
|
||||
'show': self.bom_count > 0,
|
||||
'sequence': 21,
|
||||
'sequence': 45,
|
||||
}])
|
||||
return buttons
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<field name="name">project.project.view.inherited</field>
|
||||
<field name="model">project.project</field>
|
||||
<field name="inherit_id" ref="project.edit_project" />
|
||||
<field eval="14" name="priority"/>
|
||||
<field eval="20" name="priority"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//button[@name='action_view_analytic_account_entries']" position="after">
|
||||
<button class="oe_stat_button" type="object" name="action_view_mrp_production"
|
||||
|
||||
@@ -57,6 +57,6 @@ class Project(models.Model):
|
||||
'action_type': 'object',
|
||||
'action': 'action_open_project_purchase_orders',
|
||||
'show': self.purchase_orders_count > 0,
|
||||
'sequence': 13,
|
||||
'sequence': 36,
|
||||
})
|
||||
return buttons
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
<field name="name">project.project.view.inherited</field>
|
||||
<field name="model">project.project</field>
|
||||
<field name="inherit_id" ref="project.edit_project"/>
|
||||
<field name="priority">30</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//button[@name='%(project.action_project_task_burndown_chart_report)d']" position="after">
|
||||
<xpath expr="//button[@name='action_view_analytic_account_entries']" position="after">
|
||||
<button name="action_open_project_purchase_orders" type="object" class="oe_stat_button" icon="fa-credit-card" attrs="{'invisible': [('purchase_orders_count', '=', 0)]}" groups="purchase.group_purchase_user">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span class="o_stat_value">
|
||||
|
||||
@@ -18,6 +18,7 @@ class Project(models.Model):
|
||||
sale_order_id = fields.Many2one(string='Sales Order', related='sale_line_id.order_id', help="Sales order to which the project is linked.")
|
||||
has_any_so_to_invoice = fields.Boolean('Has SO to Invoice', compute='_compute_has_any_so_to_invoice')
|
||||
sale_order_count = fields.Integer(compute='_compute_sale_order_count')
|
||||
has_any_so_with_nothing_to_invoice = fields.Boolean('Has a SO with an invoice status of No', compute='_compute_has_any_so_with_nothing_to_invoice')
|
||||
|
||||
@api.model
|
||||
def _map_tasks_default_valeus(self, task, project):
|
||||
@@ -56,7 +57,6 @@ class Project(models.Model):
|
||||
project.sale_order_count = len(project._get_all_sales_orders())
|
||||
|
||||
def action_view_sos(self):
|
||||
# Opens all the sales orders linked to the project and the project's tasks
|
||||
self.ensure_one()
|
||||
all_sale_orders = self._get_all_sales_orders()
|
||||
action_window = {
|
||||
@@ -78,15 +78,27 @@ class Project(models.Model):
|
||||
})
|
||||
return action_window
|
||||
|
||||
@api.depends('sale_order_id.invoice_status', 'tasks.sale_order_id.invoice_status')
|
||||
def _compute_has_any_so_with_nothing_to_invoice(self):
|
||||
"""Has any Sale Order whose invoice_status is set as No"""
|
||||
project_nothing_to_invoice = self.env['project.project'].search([
|
||||
'|',
|
||||
('sale_order_id.invoice_status', '=', 'no'),
|
||||
('tasks.sale_order_id.invoice_status', '=', 'no'),
|
||||
('id', 'in', self.ids)
|
||||
])
|
||||
project_nothing_to_invoice.has_any_so_with_nothing_to_invoice = True
|
||||
(self - project_nothing_to_invoice).has_any_so_with_nothing_to_invoice = False
|
||||
|
||||
def action_create_invoice(self):
|
||||
if not self.has_any_so_to_invoice:
|
||||
raise UserError(_("There is nothing to invoice in this project."))
|
||||
action = self.env["ir.actions.actions"]._for_xml_id("sale.action_view_sale_advance_payment_inv")
|
||||
so_ids = (self.sale_order_id | self.task_ids.sale_order_id).filtered(lambda so: so.invoice_status == 'to invoice').ids
|
||||
action['context'] = {
|
||||
'active_id': so_ids[0] if len(so_ids) == 1 else False,
|
||||
'active_ids': so_ids
|
||||
}
|
||||
if not self.has_any_so_to_invoice:
|
||||
action['context']['default_advance_payment_method'] = 'percentage'
|
||||
return action
|
||||
|
||||
# ----------------------------
|
||||
|
||||
@@ -30,9 +30,11 @@
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//header" position="inside">
|
||||
<field name="has_any_so_to_invoice" invisible="1"/>
|
||||
<button name="action_create_invoice" string="Create Invoice" type="object" class="oe_highlight oe_read_only" groups="sales_team.group_sale_salesman_all_leads" attrs="{'invisible': [('has_any_so_to_invoice', '=', False)]}"/>
|
||||
<field name="has_any_so_with_nothing_to_invoice" invisible="1"/>
|
||||
<button name="action_create_invoice" string="Create Invoice" type="object" class="btn-primary" groups="sales_team.group_sale_salesman_all_leads" attrs="{'invisible': [('has_any_so_to_invoice', '=', False)]}"/>
|
||||
<button name="action_create_invoice" string="Create Invoice" type="object" class="btn-secondary" groups="sales_team.group_sale_salesman_all_leads" attrs="{'invisible': ['|', ('has_any_so_with_nothing_to_invoice', '=', False), ('has_any_so_to_invoice', '=', True)]}"/>
|
||||
</xpath>
|
||||
<xpath expr="//button[@name='%(project.act_project_project_2_project_task_all)d']" position="before">
|
||||
<xpath expr="//button[@name='%(project.project_update_all_action)d']" position="after">
|
||||
<button class="d-none d-md-inline oe_stat_button"
|
||||
type="object" name="action_view_sos" icon="fa-dollar"
|
||||
attrs="{'invisible': [('sale_order_count', '=', 0)]}"
|
||||
|
||||
@@ -43,6 +43,6 @@ class Project(models.Model):
|
||||
'action_type': 'object',
|
||||
'action': 'action_open_project_vendor_bills',
|
||||
'show': self.vendor_bill_count > 0,
|
||||
'sequence': 14,
|
||||
'sequence': 48,
|
||||
})
|
||||
return buttons
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
<field name="name">project.project.form.inherit</field>
|
||||
<field name="model">project.project</field>
|
||||
<field name="inherit_id" ref="project.edit_project"/>
|
||||
<field name="priority">10</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//button[@name='%(project.action_project_task_burndown_chart_report)d']" position="after">
|
||||
<xpath expr="//button[@name='action_view_analytic_account_entries']" position="after">
|
||||
<button name="action_open_project_vendor_bills" type="object" class="oe_stat_button" icon="fa-pencil-square-o" attrs="{'invisible': [('vendor_bill_count', '=', 0)]}" groups="account.group_account_readonly">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span class="o_stat_value">
|
||||
|
||||
@@ -408,6 +408,16 @@ class Project(models.Model):
|
||||
'show': self.allow_timesheets and bool(self.analytic_account_id),
|
||||
'sequence': 9,
|
||||
})
|
||||
if self.user_has_groups('sales_team.group_sale_salesman_all_leads'):
|
||||
buttons.append({
|
||||
'icon': 'dollar',
|
||||
'text': _('Sales Orders'),
|
||||
'number': self.sale_order_count,
|
||||
'action_type': 'object',
|
||||
'action': 'action_view_sos',
|
||||
'show': self.sale_order_count > 0,
|
||||
'sequence': 18,
|
||||
})
|
||||
return buttons
|
||||
|
||||
class ProjectTask(models.Model):
|
||||
|
||||
@@ -294,8 +294,8 @@ tour.register('sale_timesheet_tour', {
|
||||
content: 'Check the user sees Total Sold section',
|
||||
run: function () {},
|
||||
}, {
|
||||
trigger: ".oe_button_box .o_stat_text:contains('Sales Order')",
|
||||
content: 'Check the user sees Sales Order Stat Button',
|
||||
trigger: ".oe_button_box .o_stat_text:contains('Sales Orders')",
|
||||
content: 'Check the user sees Sales Orders Stat Button',
|
||||
run: function () {},
|
||||
}, {
|
||||
trigger: ".o_rightpanel_header:eq(1) .o_rightpanel_right_col:contains('Hours')",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<xpath expr="//button[@name='action_view_sos']" position="attributes">
|
||||
<attribute name="attrs">{'invisible': ['|', ('allow_billable', '=', False), ('sale_order_count', '=', 0)]}</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//button[@name='%(project.action_project_task_burndown_chart_report)d']" position="after">
|
||||
<xpath expr="//button[@name='action_show_timesheets_by_employee_invoice_type']" position="after">
|
||||
<button name="action_billable_time_button" type="object" class="oe_stat_button" icon="fa-clock-o" attrs="{'invisible': ['|', ('allow_timesheets', '=', False), ('analytic_account_id', '=', False)]}" groups="hr_timesheet.group_hr_timesheet_approver">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<div class="oe_inline">
|
||||
@@ -29,10 +29,6 @@
|
||||
</div>
|
||||
</button>
|
||||
</xpath>
|
||||
<xpath expr="//header" position="inside">
|
||||
<!-- To be removed in master -->
|
||||
<button name="action_make_billable" string="Create Sales Order" type="object" groups="sales_team.group_sale_salesman" invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//page[@name='settings']" position="after">
|
||||
<page name="billing_employee_rate" string="Invoicing" attrs="{'invisible': ['|', ('allow_billable', '=', False), ('partner_id', '=', False)]}">
|
||||
<group>
|
||||
|
||||
Reference in New Issue
Block a user