[IMP] hr_,sale_(timesheet, project),purchase: generic improvements for the project
Purpose of the commit is to do the generic improvements for project. So in this commit did the following changes: - adding a label 'last update' to the stat button in project form view. - indicate 'my project' in the tab instead of 'project sharing view in portal' in project sharing. - set the first non-folded stage of the project as default on newly created tasks. - remove user confirming the SO as the default project manager. - hide fields service_tracking, service_upsell_threshold if sale_ok is false. - set purchase_method to purchase by default if product is of service type. - remove the : next to the totals labels and decrease the font-size for values of 'total hours' and 'remaining hours' in timesheets notebook in project task form view. task-2897867 closes odoo/odoo#96548 Related: odoo/enterprise#29774 Signed-off-by: Xavier Bol (xbo) <xbo@odoo.com> Co-authored-by: Manisha Tulsiyani <matu@odoo.com>
This commit is contained in:
committed by
Prakash Prajapati
co-authored by
Manisha Tulsiyani
parent
cfade861be
commit
23cf931808
@@ -65,8 +65,7 @@
|
||||
</xpath>
|
||||
<xpath expr="//div[hasclass('o_project_kanban_boxes')]" position="after">
|
||||
<t t-set="badgeColor" t-value="'border-success'"/>
|
||||
<t t-set="badgeColor" t-value="'border-warning'" t-if="record.remaining_hours.raw_value / record.allocated_hours.raw_value < 0.2 and record.remaining_hours.raw_value / record.allocated_hours.raw_value > 0"/>
|
||||
<t t-set="badgeColor" t-value="'border-danger'" t-elif="record.remaining_hours.raw_value < 0"/>
|
||||
<t t-set="badgeColor" t-value="'border-danger'" t-if="record.remaining_hours.raw_value < 0"/>
|
||||
<t t-set="title" t-value="'Remaining days'" t-if="record.encode_uom_in_days.raw_value"/>
|
||||
<t t-set="title" t-value="'Remaining hours'" t-else=""/>
|
||||
<div t-if="record.allow_timesheets.raw_value and record.allocated_hours.raw_value > 0"
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
<group name="group_general">
|
||||
<field name="active" invisible="1"/>
|
||||
<field name="detailed_type"/>
|
||||
<field name="product_tooltip" string="" class="fst-italic text-muted"/>
|
||||
<field name="product_tooltip" string="" class="fst-italic text-muted" attrs="{'invisible': [('type', '=', 'service'), ('sale_ok', '=', False)]}"/>
|
||||
<field name="uom_id" groups="uom.group_uom" options="{'no_create': True}"/>
|
||||
<field name="uom_po_id" groups="uom.group_uom" options="{'no_create': True}"/>
|
||||
</group>
|
||||
|
||||
@@ -87,7 +87,7 @@ class Task(models.Model):
|
||||
project_id = self.env.context.get('default_project_id')
|
||||
if not project_id:
|
||||
return False
|
||||
return self.stage_find(project_id, [('fold', '=', False)])
|
||||
return self.stage_find(project_id, order="fold, sequence, id")
|
||||
|
||||
@api.model
|
||||
def _default_personal_stage_type_id(self):
|
||||
|
||||
+11
@@ -20,11 +20,22 @@ export class ProjectStatusWithColorSelectionField extends SelectionField {
|
||||
return this.colors[value] ? this.colorPrefix + this.colors[value] : "";
|
||||
}
|
||||
}
|
||||
|
||||
ProjectStatusWithColorSelectionField.props = {
|
||||
...SelectionField.props,
|
||||
statusLabel: { type: String, optional: true },
|
||||
};
|
||||
|
||||
ProjectStatusWithColorSelectionField.template = 'project.ProjectStatusWithColorSelectionField';
|
||||
|
||||
export const projectStatusWithColorSelectionField = {
|
||||
...selectionField,
|
||||
component: ProjectStatusWithColorSelectionField,
|
||||
extractProps: (fieldInfo, dynamicInfo) => {
|
||||
const props = selectionField.extractProps(fieldInfo, dynamicInfo);
|
||||
props.statusLabel = fieldInfo.attrs.status_label;
|
||||
return props;
|
||||
},
|
||||
};
|
||||
|
||||
registry.category("fields").add("status_with_color", projectStatusWithColorSelectionField);
|
||||
|
||||
+7
-2
@@ -4,8 +4,13 @@
|
||||
<t t-name="project.ProjectStatusWithColorSelectionField" t-inherit="web.SelectionField" t-inherit-mode="primary" owl="1">
|
||||
<xpath expr="//t[@t-if='props.readonly']/span" position="replace">
|
||||
<div class="d-flex align-items-center">
|
||||
<span t-attf-class="o_status {{ statusColor(currentValue) }} "/>
|
||||
<span class="ps-1" t-out="string" t-att-raw-value="value" />
|
||||
<div>
|
||||
<span t-attf-class="o_status {{ statusColor(currentValue) }} d-inline-block"/>
|
||||
</div>
|
||||
<div class="ps-2">
|
||||
<div class="" t-out="string" t-att-raw-value="value"/>
|
||||
<div class="fw-normal" t-if="this.props.statusLabel" t-out="this.props.statusLabel"/>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
@@ -29,15 +29,15 @@
|
||||
<sheet string="Project">
|
||||
<div class="oe_button_box" name="button_box" groups="base.group_user">
|
||||
<button class="oe_stat_button" name="project_update_all_action" type="object" groups="project.group_project_manager">
|
||||
<div class="ps-4">
|
||||
<div>
|
||||
<field name="last_update_color" invisible="1"/>
|
||||
<field name="last_update_status" readonly="1" widget="status_with_color"/>
|
||||
<field name="last_update_status" readonly="1" widget="status_with_color" status_label="Project Status"/>
|
||||
</div>
|
||||
</button>
|
||||
<button class="oe_stat_button o_project_not_clickable" disabled="disabled" groups="!project.group_project_manager">
|
||||
<div class="ps-4">
|
||||
<div>
|
||||
<field name="last_update_color" invisible="1"/>
|
||||
<field name="last_update_status" readonly="1" widget="status_with_color"/>
|
||||
<field name="last_update_status" readonly="1" widget="status_with_color" status_label="Project Status"/>
|
||||
</div>
|
||||
</button>
|
||||
<button class="oe_stat_button" name="%(project.project_collaborator_action)d" type="action" icon="fa-users" groups="project.group_project_manager" attrs="{'invisible':[('privacy_visibility', '!=', 'portal')]}">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<template id="project_sharing_portal" name="Project Sharing View in Portal">
|
||||
<template id="project_sharing_portal" name="My Project">
|
||||
<t t-call="portal.frontend_layout">
|
||||
<!-- To add the class on div#wrapwrap to remove the overflow -->
|
||||
<t t-set="pageName" t-value="'o_project_sharing_container'"/>
|
||||
|
||||
@@ -288,7 +288,7 @@
|
||||
</div>
|
||||
</button>
|
||||
<button name="%(project_task_action_sub_task)d" type="action" class="oe_stat_button" icon="fa-tasks"
|
||||
attrs="{'invisible' : ['|', ('id', '=', False), ('subtask_count', '=', 0)]}" context="{'default_user_ids': user_ids}">
|
||||
attrs="{'invisible' : ['|', ('id', '=', False), ('subtask_count', '=', 0)]}" context="{'default_user_ids': user_ids, 'default_project_id': project_id}">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span class="o_stat_value">
|
||||
<field name="subtask_count" widget="statinfo" nolabel="1"/>
|
||||
|
||||
@@ -15,11 +15,17 @@ class ProductTemplate(models.Model):
|
||||
purchase_method = fields.Selection([
|
||||
('purchase', 'On ordered quantities'),
|
||||
('receive', 'On received quantities'),
|
||||
], string="Control Policy", help="On ordered quantities: Control bills based on ordered quantities.\n"
|
||||
"On received quantities: Control bills based on received quantities.", default="receive")
|
||||
], string="Control Policy", compute='_compute_purchase_method', store=True, readonly=False,
|
||||
help="On ordered quantities: Control bills based on ordered quantities.\n"
|
||||
"On received quantities: Control bills based on received quantities.")
|
||||
purchase_line_warn = fields.Selection(WARNING_MESSAGE, 'Purchase Order Line Warning', help=WARNING_HELP, required=True, default="no-message")
|
||||
purchase_line_warn_msg = fields.Text('Message for Purchase Order Line')
|
||||
|
||||
@api.depends('detailed_type')
|
||||
def _compute_purchase_method(self):
|
||||
for product in self:
|
||||
product.purchase_method = 'purchase' if product.detailed_type == 'service' else 'receive'
|
||||
|
||||
def _compute_purchased_product_qty(self):
|
||||
for template in self:
|
||||
template.purchased_product_qty = float_round(sum([p.purchased_product_qty for p in template.product_variant_ids]), precision_rounding=template.uom_id.rounding)
|
||||
|
||||
@@ -13,8 +13,8 @@ class TestAccruedPurchaseOrders(AccountTestInvoicingCommon):
|
||||
super().setUpClass(chart_template_ref=chart_template_ref)
|
||||
cls.alt_exp_account = cls.company_data['default_account_expense'].copy()
|
||||
# set 'type' to 'service' to allow manualy set 'qty_delivered' even with purchase_stock installed
|
||||
cls.product_a.type = 'service'
|
||||
cls.product_b.type = 'service'
|
||||
cls.product_a.update({'type': 'service', 'purchase_method': 'receive'})
|
||||
cls.product_b.update({'type': 'service', 'purchase_method': 'receive'})
|
||||
cls.product_b.property_account_expense_id = cls.alt_exp_account
|
||||
cls.purchase_order = cls.env['purchase.order'].with_context(tracking_disable=True).create({
|
||||
'partner_id': cls.partner_a.id,
|
||||
|
||||
@@ -49,10 +49,10 @@ class ProductTemplate(models.Model):
|
||||
if not product.service_policy and product.type == 'service':
|
||||
product.service_policy = 'ordered_prepaid'
|
||||
|
||||
@api.depends('service_tracking', 'service_policy', 'type')
|
||||
@api.depends('service_tracking', 'service_policy', 'type', 'sale_ok')
|
||||
def _compute_product_tooltip(self):
|
||||
super()._compute_product_tooltip()
|
||||
for record in self.filtered(lambda record: record.type == 'service'):
|
||||
for record in self.filtered(lambda record: record.type == 'service' and record.sale_ok):
|
||||
if record.service_policy == 'ordered_prepaid':
|
||||
if record.service_tracking == 'no':
|
||||
record.product_tooltip = _(
|
||||
|
||||
@@ -108,6 +108,7 @@ class SaleOrderLine(models.Model):
|
||||
'active': True,
|
||||
'company_id': self.company_id.id,
|
||||
'allow_billable': True,
|
||||
'user_id': False,
|
||||
}
|
||||
|
||||
def _timesheet_create_project(self):
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</field>
|
||||
<field name="invoice_policy" position="after">
|
||||
<field name="service_policy" string="Invoicing Policy" attrs="{'invisible': [('type', '!=', 'service')], 'required': [('type', '=', 'service')]}"/>
|
||||
<field name="service_tracking" required="1" attrs="{'invisible': [('type', '!=', 'service')]}"/>
|
||||
<field name="service_tracking" required="1" attrs="{'invisible': [('type', '=', 'service'), ('sale_ok', '=', False)]}"/>
|
||||
<field name="project_id" context="{'default_allow_billable': True}" attrs="{'invisible':[('service_tracking','!=','task_global_project')], 'required':[('service_tracking','==','task_global_project')]}"/>
|
||||
<field name="project_template_id" context="{'active_test': False, 'default_allow_billable': True}" attrs="{'invisible':[('service_tracking','not in',['task_in_project', 'project_only'])]}"/>
|
||||
</field>
|
||||
|
||||
@@ -41,10 +41,10 @@ class ProductTemplate(models.Model):
|
||||
product_template.visible_expense_policy = visibility
|
||||
return super(ProductTemplate, self)._compute_visible_expense_policy()
|
||||
|
||||
@api.depends('service_tracking', 'service_policy', 'type')
|
||||
@api.depends('service_tracking', 'service_policy', 'type', 'sale_ok')
|
||||
def _compute_product_tooltip(self):
|
||||
super()._compute_product_tooltip()
|
||||
for record in self.filtered(lambda record: record.type == 'service'):
|
||||
for record in self.filtered(lambda record: record.type == 'service' and record.sale_ok):
|
||||
if record.service_policy == 'delivered_timesheet':
|
||||
if record.service_tracking == 'no':
|
||||
record.product_tooltip = _(
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<field name="inherit_id" ref="sale.product_template_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="product_tooltip" position="after">
|
||||
<label for="product_tooltip" string="" attrs="{'invisible': ['|', ('type', '!=', 'service'), ('service_policy', '!=', 'ordered_prepaid')]}"/>
|
||||
<div attrs="{'invisible': ['|', ('type', '!=', 'service'), ('service_policy', '!=', 'ordered_prepaid')]}" class="fst-italic text-muted">
|
||||
<label for="product_tooltip" string="" attrs="{'invisible': ['|', '|', ('type', '!=', 'service'), ('service_policy', '!=', 'ordered_prepaid'), ('sale_ok', '=', False)]}"/>
|
||||
<div attrs="{'invisible': ['|', '|', ('type', '!=', 'service'), ('service_policy', '!=', 'ordered_prepaid'), ('sale_ok', '=', False)]}" class="fst-italic text-muted">
|
||||
Warn the salesperson for an upsell when work done exceeds
|
||||
<field name="service_upsell_threshold" widget="percentage" class="oe_inline"/>
|
||||
of hours sold. <field name="service_upsell_threshold_ratio" class="oe_inline" attrs="{'invisible': [('service_upsell_threshold_ratio', '=', False)]}"/>
|
||||
|
||||
Reference in New Issue
Block a user