19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:32:12 +01:00
parent 79f83631d5
commit 73afc09215
6267 changed files with 1534193 additions and 1130106 deletions

View file

@ -7,16 +7,68 @@
<field name="inherit_id" ref="sale.product_template_form_view"/>
<field name="arch" type="xml">
<field name="invoice_policy" position="attributes">
<attribute name="invisible">False</attribute>
<attribute name="attrs">{'invisible': [('type', '=', 'service'), ('sale_ok', '=', True)]}</attribute>
<attribute name="invisible" separator="or" add="type == 'service'"/>
</field>
<field name="invoice_policy" position="after">
<field name="service_policy" string="Invoicing Policy" attrs="{'invisible': ['|', ('type', '!=', 'service'), ('sale_ok', '=', False)], 'required': [('type', '=', 'service'), ('sale_ok', '=', True)]}"/>
<field name="service_tracking" required="1" attrs="{'invisible': [('type', '!=', 'service')]}"/>
<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 name="service_tracking" position="attributes">
<attribute name="invisible" remove="1" separator="or"/>
</field>
<field name="service_tracking" position="after">
<div class="o_td_label d-inline-flex" invisible="service_tracking != 'task_global_project'">
<label for='project_id'/>
</div>
<field name="project_id" context="{'default_allow_billable': True}" invisible="service_tracking != 'task_global_project'" nolabel="1" placeholder="Defined on quotation"/>
<div class="o_td_label d-inline-flex" invisible="service_tracking not in ['task_in_project', 'project_only']">
<label for='project_template_id'/>
</div>
<field name="project_template_id" context="{'active_test': False, 'default_allow_billable': True, 'default_is_template': True}" invisible="service_tracking not in ['task_in_project', 'project_only']" nolabel="1" placeholder="Empty project"/>
<div class="o_td_label d-inline-flex"
invisible="not project_id or service_tracking != 'task_global_project'">
<label for="task_template_id" />
</div>
<!-- field for project manager -->
<field name="task_template_id"
groups="project.group_project_manager"
context="{'default_is_template': True, 'default_project_id': project_id or project_template_id}"
invisible="not project_id or service_tracking != 'task_global_project'"
nolabel="1" />
<!-- field for non-project manager -->
<field name="task_template_id"
groups="!project.group_project_manager"
options="{'no_open': True, 'no_create_edit': True, 'no_create': True}"
invisible="not project_id or service_tracking != 'task_global_project'"
nolabel="1" />
<field name="service_policy"
string="Invoicing Policy"
invisible="type != 'service' or sale_ok == False"
required="type == 'service' and sale_ok == True"/>
</field>
</field>
</record>
<!-- TODO: remove me in master -->
<record id="product_template_form_view_inherit_sale_project" model="ir.ui.view">
<field name="name">product.template.sale.project.form</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="sale.product_template_form_view"/>
<field name="mode">primary</field>
<field name="priority">999</field>
<field name="arch" type="xml">
<field name="type" position="attributes">
<attribute name="invisible">1</attribute>
</field>
</field>
</record>
<record id="product_product_form_view_inherit_sale_project" model="ir.ui.view">
<field name="name">product.product.sale.project.form</field>
<field name="model">product.product</field>
<field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="mode">primary</field>
<field name="priority">999</field>
<field name="arch" type="xml">
<field name="type" position="attributes">
<attribute name="invisible">1</attribute>
</field>
</field>
</record>
</odoo>

View file

@ -4,40 +4,65 @@
<record id="project_sharing_inherit_project_task_view_form" model="ir.ui.view">
<field name="name">project.task.view.inherit</field>
<field name="model">project.task</field>
<field name="priority">300</field>
<field name="inherit_id" ref="project.project_sharing_project_task_view_form"/>
<field name="arch" type="xml">
<div name="button_box" position="inside">
<field name="display_sale_order_button" invisible="1"/>
<field name="allow_billable" invisible="1"/>
<button class="oe_stat_button"
type="object" name="action_project_sharing_view_so" icon="fa-dollar"
attrs="{'invisible': [('display_sale_order_button', '=', False)]}"
string="Sales Order"/>
invisible="not display_sale_order_button">
<div class="o_stat_info">
<span class="o_stat_text">Sales Order</span>
</div>
</button>
</div>
<xpath expr="//field[@name='partner_id']" position="attributes">
<attribute name="options">{'no_open': True, 'no_create': True, 'no_edit': True}</attribute>
<attribute name="context">{'res_partner_search_mode': 'customer'}</attribute>
<attribute name="invisible">not allow_billable</attribute>
</xpath>
<xpath expr="//field[@name='partner_id']" position="after">
<field name="commercial_partner_id" invisible="1" />
<field name="sale_line_id" string="Sales Order Item" attrs="{'invisible': [('partner_id', '=', False)]}" options='{"no_open": True}' readonly="1" context="{'create': False, 'edit': False, 'delete': False}"/>
<field name="sale_line_id" string="Sales Order Item" options='{"no_open": True}' readonly="1" invisible="not partner_id" context="{'create': False, 'edit': False, 'delete': False}"/>
</xpath>
<xpath expr="//field[@name='child_ids']/list/field[@name='partner_id']" position="after">
<field name="allow_billable" column_invisible="1"/>
</xpath>
<xpath expr="//field[@name='depend_on_ids']/list/field[@name='partner_id']" position="after">
<field name="allow_billable" column_invisible="1"/>
</xpath>
<xpath expr="//field[@name='child_ids']/list/field[@name='partner_id']" position="attributes">
<attribute name="column_invisible">not parent.allow_billable</attribute>
<attribute name="invisible">not allow_billable</attribute>
</xpath>
<xpath expr="//field[@name='depend_on_ids']/list/field[@name='partner_id']" position="attributes">
<attribute name="column_invisible">not parent.allow_billable</attribute>
<attribute name="invisible">not allow_billable</attribute>
</xpath>
</field>
</record>
<record id="project_sharing_inherit_project_task_view_search" model="ir.ui.view">
<field name="name">project.task.search.inherit</field>
<record id="project_sharing_inherit_project_task_view_tree" model="ir.ui.view">
<field name="name">project.task.view.list.inherit</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.project_sharing_project_task_view_search"/>
<field name="priority">300</field>
<field name="inherit_id" ref="project.project_sharing_project_task_view_tree"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='partner_id']" position="after">
<field name="sale_order_id" string="Sale Order" filter_domain="['|', ('sale_order_id', 'ilike', self), ('sale_line_id', 'ilike', self)]"/>
</xpath>
<xpath expr="//group/filter[@name='customer']" position="after">
<!-- TODO: Remove me in master -->
<filter name="sale_order_id" string="Sales Order Id" invisible="1" />
<filter name="group_by_sale_order" string="Sales Order" context="{'group_by': 'sale_order_id'}" />
<field name="allow_milestones" position="after">
<field name="allow_billable" column_invisible="1"/>
</field>
<xpath expr="//field[@name='partner_id']" position="attributes">
<attribute name="column_invisible">not allow_billable</attribute>
</xpath>
</field>
</record>
<record id="project.project_sharing_project_task_action" model="ir.actions.act_window">
<field name="context">{
'default_project_id': active_id,
'active_id_chatter': active_id,
'delete': false,
'sale_show_partner_name': true,
}</field>
</record>
</odoo>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="task_type_edit_inherit_sale_project" model="ir.ui.view">
<field name="name">project.task.type.form.inherit.sale_project</field>
<field name="model">project.task.type</field>
<field name="inherit_id" ref="project.task_type_edit"/>
<field name="arch" type="xml">
<xpath expr="//span[@name='rating_status_helper']" position="replace">
<span name="rating_status_helper">
<span invisible="rating_status == 'periodic'">A rating request will be sent as soon as a task reaches this stage, provided the project is billable.</span>
<span invisible="rating_status == 'stage'">Rating requests will be sent as long as the task remains in this stage, provided the project is billable.</span>
</span>
</xpath>
<xpath expr="//group[@name='group_customer_rating']" position="attributes">
<attribute name="invisible">not show_rating_active</attribute>
</xpath>
</field>
</record>
</odoo>

View file

@ -1,25 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="project.action_view_task" model="ir.actions.act_window">
<field name="context">{'sale_show_partner_name': True, 'search_default_my_tasks': 1}</field>
</record>
<record id="project.action_view_my_task" model="ir.actions.act_window">
<field name="context">{'search_default_open_tasks': 1, 'my_tasks': 1, 'default_user_ids': [(4, uid)], 'sale_show_partner_name': True}</field>
</record>
<record id="project.action_view_all_task" model="ir.actions.act_window">
<field name="context">{'search_default_open_tasks': 1, 'default_user_ids': [(4, uid)], 'sale_show_partner_name': True}</field>
</record>
<record id="project.action_project_task_user_tree" model="ir.actions.act_window">
<field name="context">{'group_by': [], 'graph_measure': '__count__', 'sale_show_partner_name': True}</field>
</record>
<record id="project_project_view_inherit_project_filter" model="ir.ui.view">
<field name="name">project.project.select.inherit.project</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.view_project_project_filter"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='partner_id']" position="after">
<field name="sale_order_id"/>
<field name="sale_order_id" invisible="context.get('default_is_template')"/>
</xpath>
</field>
</record>
<record id="project_project_view_tree_inherit_sale_project" model="ir.ui.view">
<field name="name">project.project.tree.inherit.sale.project</field>
<field name="name">project.project.list.inherit.sale.project</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.view_project"/>
<field name="priority">50</field>
<field name="arch" type="xml">
<xpath expr="//field[@name='partner_id']" position="after">
<field name="sale_line_id" optional="hide" readonly="1"/>
<field name="allow_billable" column_invisible="True"/>
</xpath>
<xpath expr="//field[@name='partner_id']" position="attributes">
<attribute name="invisible">not allow_billable or is_template</attribute>
</xpath>
</field>
</record>
@ -29,58 +49,223 @@
<field name="model">project.project</field>
<field name="inherit_id" ref="project.edit_project"/>
<field name="arch" type="xml">
<div name="button_box" position="inside">
<field name="display_sales_stat_buttons" invisible="1"/>
<field name="allow_billable" invisible="1" />
<field name="privacy_visibility" invisible="1" />
<button class="oe_stat_button" type="object" name="action_customer_preview" icon="fa-globe icon" invisible="not partner_id or not allow_billable or privacy_visibility not in ['invited_users', 'portal'] or is_template">
<div class="o_field_widget o_stat_info">
<span class="o_stat_text">Preview</span>
</div>
</button>
<button
class="oe_stat_button"
type="object"
name="action_view_sos"
icon="fa-dollar"
invisible="not display_sales_stat_buttons or sale_order_count == 0 or is_template"
groups="sales_team.group_sale_salesman_all_leads"
context="{
'create_for_project_id': id,
'default_project_id': id,
'default_partner_id': partner_id
}">
<div class="o_field_widget o_stat_info">
<span class="o_stat_value">
<field name="sale_order_count" nolabel="1"/>
</span>
<span class="o_stat_text">
Sales Orders
</span>
</div>
</button>
<button
class="oe_stat_button"
type="object"
name="action_view_sos"
icon="fa-dollar"
invisible="not display_sales_stat_buttons or sale_order_count != 0 or is_template"
groups="sales_team.group_sale_salesman_all_leads"
context="{
'create_for_project_id': id,
'default_project_id': id,
'default_partner_id': partner_id
}">
<div class="o_field_widget o_stat_info">
<span class="o_stat_text">
<span class="o_stat_value">0</span> Sales Order
</span>
<span class="o_stat_text">
Make Billable
</span>
</div>
</button>
</div>
<xpath expr="//header" position="inside">
<field name="has_any_so_to_invoice" invisible="1"/>
<field name="has_any_so_with_nothing_to_invoice" invisible="1"/>
<!-- remove me in master -->
<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)]}" data-hotkey="w" invisible="1"/>
<!-- remove me in master -->
<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)]}" data-hotkey="w" invisible="1"/>
</xpath>
<xpath expr="//field[@name='partner_id']" position="attributes">
<attribute name="options">{'always_reload': True}</attribute>
<attribute name="context">{'res_partner_search_mode': 'customer'}</attribute>
<attribute name="invisible">not allow_billable or is_template</attribute>
</xpath>
<xpath expr="//group[@name='group_time_managment']" position="after">
<xpath expr="//group[@name='group_time_managment']" position="before">
<group name="group_sales_invoicing" string="Sales &amp; Invoicing" col="1" class="row mt16 o_settings_container col-lg-6">
<div>
<div class="o_setting_box" id="allow_billable_container">
<div class="o_setting_left_pane">
<field name="allow_billable"/>
</div>
<div class="o_setting_right_pane">
<label for="allow_billable"/>
<div class="text-muted" id="allow_billable_setting">
Invoice your time and material to customers
</div>
</div>
</div>
<setting class="col-lg-12" help="Invoice your time and material to customers" id="allow_billable_container">
<field name="allow_billable"/>
</setting>
</div>
</group>
</xpath>
<xpath expr="//page[@name='settings']//field[@name='privacy_visibility']" position="after">
<field name="reinvoiced_sale_order_id" invisible="not allow_billable or not partner_id or is_template" context="{'default_partner_id': partner_id}"/>
<label for="sale_line_id" invisible="not allow_billable or not partner_id or is_template"/>
<div
class="o_row"
invisible="not allow_billable or not partner_id or is_template">
<field name="sale_line_id"
groups="!sales_team.group_sale_salesman"
options="{'no_create': True, 'no_edit': True, 'delete': False, 'no_open': True}"/>
<field name="sale_line_id"
groups="sales_team.group_sale_salesman"
options="{'no_create': True}"
/>
<span
class="fa fa-exclamation-triangle text-warning"
title="The sales order associated with this project has been cancelled. We recommend either updating the sales order item or cancelling this project in alignment with the cancellation of the sales order."
invisible="sale_order_state != 'cancel'"/>
</div>
<field name="sale_order_state" invisible="1"/>
</xpath>
</field>
</record>
<record id="view_sale_project_quick_create_task_form" model="ir.ui.view">
<field name="name">project.task.view.inherit</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.quick_create_task_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='project_id']" position="attributes">
<attribute name="context">{'default_allow_billable': True, 'default_type_ids': [(4, context.get('default_stage_id', False))]}
</attribute>
</xpath>
</field>
</record>
<record id="view_sale_project_inherit_form" model="ir.ui.view">
<field name="name">project.task.view.inherit</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_form2"/>
<field name="priority">100</field>
<field name="arch" type="xml">
<xpath expr="//span[@id='start_rating_buttons']" position="before">
<button class="oe_stat_button"
type="object" name="action_view_so" icon="fa-dollar"
attrs="{'invisible': [('sale_order_id', '=', False)]}"
string="Sales Order"
groups="sales_team.group_sale_salesman_all_leads"/>
invisible="not sale_order_id or has_template_ancestor or has_project_template"
groups="sales_team.group_sale_salesman">
<div class="o_stat_info">
<span class="o_stat_text">Sales Order</span>
</div>
</button>
</xpath>
<xpath expr="//field[@name='milestone_id']" position="attributes">
<attribute name="context">{'default_project_id': project_id, 'default_sale_line_id': sale_line_id}</attribute>
</xpath>
<xpath expr="//field[@name='partner_id']" position="attributes">
<attribute name="options">{'always_reload': True}</attribute>
<attribute name="context">{'res_partner_search_mode': 'customer'}</attribute>
<attribute name="invisible">not allow_billable or has_template_ancestor or has_project_template</attribute>
</xpath>
<xpath expr="//field[@name='partner_phone']" position="after">
<field name="sale_order_id" attrs="{'invisible': True}" groups="sales_team.group_sale_salesman"/>
<field name="sale_line_id" groups="!sales_team.group_sale_salesman" string="Sales Order Item" options='{"no_open": True}' readonly="1"/>
<field name="sale_line_id" groups="sales_team.group_sale_salesman" string="Sales Order Item" options='{"no_create": True}' readonly="0" context="{'create': False, 'edit': False, 'delete': False, 'with_price_unit': True}"/>
<field name="commercial_partner_id" invisible="1" />
<xpath expr="//field[@name='partner_id']" position="after">
<field name="project_sale_order_id" invisible="1"/>
<field name="sale_order_id" invisible="True" groups="sales_team.group_sale_salesman"/>
<label for="sale_line_id" invisible="not allow_billable or not project_id or not partner_id or has_template_ancestor or has_project_template"/>
<div
name="sale_line_div"
class="o_row"
invisible="not allow_billable or not project_id or not partner_id or has_template_ancestor or has_project_template">
<field name="sale_line_id"
groups="!sales_team.group_sale_salesman"
string="Sales Order Item"
options='{"no_open": True}'
readonly="1"
invisible="not sale_line_id"/>
<field name="sale_line_id"
groups="sales_team.group_sale_salesman"
string="Sales Order Item"
options="{'no_create': True}"
readonly="0"
context="{
'so_form_view_ref': 'sale_project.view_order_simple_form',
'create_for_task_id': id,
'default_partner_id': partner_id,
'default_company_id': company_id,
'default_project_id': project_id,
'with_price_unit': True,
'dialog_size': 'large',
}"
widget="so_line_create_button"
placeholder="Non-billable"/>
<span
class="fa fa-exclamation-triangle text-warning"
title="The sales order associated with this task has been cancelled. We recommend either updating the sales order item or cancelling this task in alignment with the cancellation of the sales order."
invisible="sale_order_state != 'cancel'"/>
</div>
<field name="allow_billable" invisible="1"/>
<field name="sale_order_state" invisible="1"/>
</xpath>
<xpath expr="//field[@name='child_ids']/list/field[@name='partner_id']" position="after">
<field name="sale_line_id"
optional="hide"
options='{"no_create": True}'
context="{'create': False, 'edit': False, 'delete': False, 'with_price_unit': True}"
placeholder="Non-billable"
groups="sales_team.group_sale_salesman"
invisible="not allow_billable"
column_invisible="parent.has_template_ancestor or parent.has_project_template"/>
<field name="sale_line_id" optional="hide" options="{'no_open': True}" readonly="1" groups="!sales_team.group_sale_salesman" column_invisible="parent.has_template_ancestor or parent.has_project_template"/>
<field name="allow_billable" column_invisible="True"/>
</xpath>
<xpath expr="//field[@name='child_ids']/list/field[@name='partner_id']" position="attributes">
<attribute name="column_invisible">not parent.allow_billable</attribute>
<attribute name="invisible">not allow_billable</attribute>
</xpath>
<xpath expr="//field[@name='depend_on_ids']/list/field[@name='partner_id']" position="after">
<field name="sale_line_id" optional="hide" readonly="1" groups="sales_team.group_sale_salesman" column_invisible="parent.has_template_ancestor or parent.has_project_template"/>
<field name="sale_line_id" optional="hide" options="{'no_open': True}" readonly="1" groups="!sales_team.group_sale_salesman" column_invisible="parent.has_template_ancestor or parent.has_project_template"/>
<field name="allow_billable" column_invisible="True"/>
</xpath>
<xpath expr="//field[@name='depend_on_ids']/list/field[@name='partner_id']" position="attributes">
<attribute name="column_invisible">not parent.allow_billable</attribute>
<attribute name="invisible">not allow_billable</attribute>
</xpath>
<field name="project_id" position="attributes">
<attribute name="context">{'default_allow_billable': True}</attribute>
</field>
</field>
</record>
<record id="project_task_view_tree_main_base" model="ir.ui.view">
<field name="name">project.task.main.list.inherit</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.project_task_view_tree_main_base"/>
<field name="arch" type="xml">
<field name="partner_id" position="after">
<field name="allow_billable" column_invisible="True"/>
</field>
<field name="partner_id" position="attributes">
<attribute name="column_invisible">context.get('hide_partner') or context.get('default_is_template')</attribute>
<attribute name="invisible">not allow_billable</attribute>
</field>
</field>
</record>
<record id="view_task_tree2_inherit_sale_project" model="ir.ui.view">
<field name="name">project.task.form.inherit.sale.project</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.project_task_view_tree_base"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='partner_id']" position="after">
<field name="sale_line_id" optional="hide" groups="sales_team.group_sale_salesman" options="{'no_create': True}" column_invisible="not context.get('allow_billable') or context.get('template_project')"/>
<field name="sale_line_id" optional="hide" options="{'no_open': True}" readonly="1" groups="!sales_team.group_sale_salesman" column_invisible="not context.get('allow_billable') or context.get('template_project')"/>
</xpath>
</field>
</record>
@ -88,14 +273,19 @@
<record id="project_task_view_search" model="ir.ui.view">
<field name="name">project.task.search.inherit</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_search_form"/>
<field name="inherit_id" ref="project.view_task_search_form_project_base"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='partner_id']" position="after">
<field name="sale_order_id" string="Sale Order" filter_domain="['|', ('sale_order_id', 'ilike', self), ('sale_line_id', 'ilike', self)]"/>
</xpath>
<xpath expr="//search/group/filter[@name='customer']" position="after">
<filter string="Sales Order Item" name="sale_line_id" context="{'group_by': 'sale_line_id'}"/>
</xpath>
<field name="partner_id" position="after">
<field name="sale_order_id"
filter_domain="['|', ('sale_order_id', 'ilike', self), ('sale_line_id', 'ilike', self)]"
invisible="context.get('template_project')"/>
</field>
<field name="partner_id" position="attributes">
<attribute name="invisible">context.get('hide_partner') or context.get('template_project')</attribute>
</field>
<filter name="customer" position="attributes">
<attribute name="invisible">context.get('hide_partner') or context.get('template_project')</attribute>
</filter>
</field>
</record>
@ -106,53 +296,93 @@
<field name="arch" type="xml">
<xpath expr="//group[@name='main_details']" position="after">
<field name="allow_billable" invisible="1"/>
<group attrs="{'invisible': [('allow_billable', '=', False)]}">
<group invisible="not allow_billable">
<field name="project_partner_id" invisible="1"/>
<field name="sale_line_id" groups="!sales_team.group_sale_salesman" placeholder="Non-billable" options="{'no_open': True}" readonly="1"/>
<field name="sale_line_id" groups="sales_team.group_sale_salesman" options="{'no_create': True}" placeholder="Non-billable" readonly="0"/>
<field name="quantity_percentage" groups="!sales_team.group_sale_salesman" widget="percentage" readonly="1"/>
<field name="quantity_percentage" class="w-25" groups="sales_team.group_sale_salesman" widget="percentage" readonly="0"/>
<label for="quantity_percentage" invisible="not sale_line_id"/>
<div class="col-6" invisible="not sale_line_id">
<field name="quantity_percentage" groups="!sales_team.group_sale_salesman" widget="percentage" readonly="1" class="mw-25"/>
<field name="quantity_percentage" class="mw-25" groups="sales_team.group_sale_salesman"
widget="percentage" decoration-danger="quantity_percentage &lt; 0 or 1 &lt; quantity_percentage" readonly="0"/>
<span>
(<field name="product_uom_qty" class="mw-25" decoration-danger="quantity_percentage &lt; 0 or 1 &lt; quantity_percentage"/>
<field name="product_uom_id" class="w-auto text-end" groups="uom.group_uom" options="{'no_open': True}"/>
<span>)</span>
</span>
</div>
</group>
</xpath>
<xpath expr="//button[@name='%(project.action_view_task_from_milestone)d']" position="before">
<button name="action_view_sale_order" type="object" class="oe_stat_button" icon="fa-dollar" invisible="not sale_line_id">
<div class="o_stat_info">
<span class="o_stat_text">Sales Order</span>
</div>
</button>
</xpath>
</field>
</record>
<record id="project_milestone_view_tree" model="ir.ui.view">
<field name="name">project.milestone.view.tree.inherit</field>
<field name="name">project.milestone.view.list.inherit</field>
<field name="model">project.milestone</field>
<field name="inherit_id" ref="project.project_milestone_view_tree"/>
<field name="mode">primary</field>
<field name="arch" type="xml">
<xpath expr="//field[@name='name']" position="after">
<field name="project_partner_id" invisible="1"/>
<field name="allow_billable" invisible="1"/>
<field name="sale_line_id" optional="hide" options="{'no_open': True}" placeholder="Non-billable" readonly="1" groups="!sales_team.group_sale_salesman"/>
<field name="sale_line_id" optional="hide" options="{'no_create': True}" placeholder="Non-billable" groups="sales_team.group_sale_salesman"/>
<field name="quantity_percentage" optional="hide" widget="percentage" readonly="1" groups="!sales_team.group_sale_salesman"/>
<field name="quantity_percentage" optional="hide" widget="percentage" groups="sales_team.group_sale_salesman"/>
<field name="project_partner_id" column_invisible="True"/>
<field name="allow_billable" column_invisible="True"/>
<field name="sale_line_id" options="{'no_open': True}" placeholder="Non-billable" readonly="1" groups="!sales_team.group_sale_salesman"/>
<field name="sale_line_id" options="{'no_create': True}" placeholder="Non-billable" groups="sales_team.group_sale_salesman"/>
<field name="quantity_percentage" string="Quantity (%)" widget="percentage" readonly="not sale_line_id" groups="!sales_team.group_sale_salesman"/>
<field name="quantity_percentage" string="Quantity (%)" widget="percentage" readonly="not sale_line_id" groups="sales_team.group_sale_salesman"/>
<field name="product_uom_qty" optional="hide" groups="!sales_team.group_sale_salesman" readonly="1"/>
<field name="product_uom_qty" optional="hide" groups="sales_team.group_sale_salesman"/>
</xpath>
<xpath expr="//button[@name='action_view_tasks']" position="after">
<button name="action_view_sale_order" type="object" string="View Sales Order"
class="btn btn-link float-end" invisible="not sale_line_id"/>
</xpath>
</field>
</record>
<record id="sale_project_milestone_view_tree" model="ir.ui.view">
<field name="name">project.milestone.view.tree.inherit</field>
<field name="model">project.milestone</field>
<field name="inherit_id" ref="sale_project.project_milestone_view_tree"/>
<field name="mode">primary</field>
<!-- Views for 'Tasks' stat button via Contact form -->
<record id="view_task_form_res_partner" model="ir.ui.view">
<field name="name">project.task.form.res.partner.inherit.sale_project</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_form_res_partner"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='sale_line_id'][1]" position="attributes">
<attribute name="optional">show</attribute>
</xpath>
<xpath expr="//field[@name='sale_line_id'][2]" position="attributes">
<attribute name="optional">show</attribute>
</xpath>
<xpath expr="//field[@name='quantity_percentage'][1]" position="attributes">
<attribute name="optional">show</attribute>
</xpath>
<xpath expr="//field[@name='quantity_percentage'][2]" position="attributes">
<attribute name="optional">show</attribute>
<xpath expr="//group//field[@name='project_id']" position="attributes">
<attribute name="domain">['&amp;', ('allow_billable', '=', True), '&amp;',('active', '=', True), '|', ('company_id', '=', False), ('company_id', '=?', company_id)]</attribute>
</xpath>
</field>
</record>
<record id="quick_create_task_form_res_partner" model="ir.ui.view">
<field name="name">project.task.form.quick_create.res.partner.inherit.sale_project</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.quick_create_task_form_res_partner"/>
<field name="arch" type="xml">
<xpath expr="//group//field[@name='project_id']" position="attributes">
<attribute name="domain">[('allow_billable', '=', True), ('type_ids', 'in', context['default_stage_id'])] if context.get('default_stage_id') else []</attribute>
</xpath>
</field>
</record>
<record id="project_milestone_view_kanban_inherit_sale_project" model="ir.ui.view">
<field name="name">project.milestone.view.kanban.inherit</field>
<field name="model">project.milestone</field>
<field name="inherit_id" ref="project.project_milestone_view_kanban"/>
<field name="arch" type="xml">
<field name="is_deadline_exceeded" position="after">
<field name="quantity_percentage"/>
</field>
<xpath expr="//field[@name='name']" position="after">
<t t-if="record.sale_line_display_name.raw_value and record.quantity_percentage.raw_value">
<field name="sale_line_display_name"/>(
<field name="quantity_percentage" widget="percentage" class="d-contents"/>)
</t>
</xpath>
</field>
</record>
</odoo>

View file

@ -0,0 +1,59 @@
<?xml version="1.0"?>
<odoo>
<template id="sale_project.milestone_deadline_inherit" inherit_id="project.milestone_deadline">
<xpath expr="//t[@t-if=&quot;milestone['deadline']&quot;]" position="before">
<t t-if="milestone['quantity_percentage']">
<font style="color: rgb(190, 190, 190);">
<t t-if="milestone['sale_line_display_name']">
(<t t-out="milestone['sale_line_display_name']"/> -
</t>
<t t-out="100 * milestone['quantity_percentage']"/>%)</font>
</t>
</xpath>
</template>
<template id="project_update_default_description" inherit_id="project.project_update_default_description">
<xpath expr="//tr[hasclass('revenue_data')]" position="replace">
<tr>
<td t-out="profitability['labels'][revenue['id']]"/>
<td class="text-end" t-out="format_monetary(revenue['invoiced'] + revenue['to_invoice'])"/>
<td class="text-end" t-out="format_monetary(revenue['to_invoice'])"/>
<td class="text-end" t-out="format_monetary(revenue['invoiced'])"/>
</tr>
<tr>
<td colspan="4">
<div class="mt-2">
<table class="table table-sm table-bordered">
<thead>
<tr>
<td class="w-55" style="font-weight: bolder;">Sales Order Items</td>
<td style="font-weight: bolder; text-align: right; width: 15%;">Sold</td>
<td style="font-weight: bolder; text-align: right; width: 15%;">Delivered</td>
<td style="font-weight: bolder; text-align: right; width: 15%;">Invoiced</td>
</tr>
</thead>
<tbody>
<tr t-foreach="revenue['sol']" t-as="sol">
<td>
<t t-out="sol['name']"/>
</td>
<td class="text-end">
<t t-out="sol['product_uom_qty']"/> <t t-out="sol['product_uom_id'][1]"/>
</td>
<td class="text-end">
<t t-out="sol['qty_delivered']"/> <t t-out="sol['product_uom_id'][1]"/>
</td>
<td class="text-end">
<t t-out="sol['qty_invoiced']"/> <t t-out="sol['product_uom_id'][1]"/>
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</xpath>
</template>
</odoo>

View file

@ -1,15 +1,118 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<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">25</field>
<field name="arch" type="xml">
<xpath expr="//div[hasclass('o_settings_container')]" position="inside">
<field name="company_id" invisible="1"/>
<setting class="col-lg-12" help="Invoice your time and material to customers" invisible="context.get('hide_allow_billable', False)">
<field name="allow_billable"/>
<div invisible="not allow_billable" class="d-flex flex-column flex-sm-row align-items-baseline">
<label for="partner_id"/>
<field name="partner_id" class="ms-1" widget="res_partner_many2one" context="{'res_partner_search_mode': 'customer'}"
options="{'no_create_edit': True, 'no_open': True}" placeholder="Select who to bill..."/>
</div>
</setting>
</xpath>
</field>
</record>
<record id="project_embedded_action_invoices" model="ir.embedded.actions">
<field name="parent_res_model">project.project</field>
<field name="sequence">60</field>
<field name="name">Invoices</field>
<field name="parent_action_id" ref="project.act_project_project_2_project_task_all"/>
<field name="python_method">action_open_project_invoices</field>
<field name="context">{"from_embedded_action": true}</field>
<field name="groups_ids" eval="[(4, ref('account.group_account_invoice')), (4, ref('sales_team.group_sale_salesman'))]" />
<field name="domain">[('allow_billable', '=', True)]</field>
</record>
<record id="project_embedded_action_sales_orders" model="ir.embedded.actions">
<field name="parent_res_model">project.project</field>
<field name="sequence">50</field>
<field name="name">Sales Orders</field>
<field name="parent_action_id" ref="project.act_project_project_2_project_task_all"/>
<field name="python_method">action_view_sos</field>
<field name="context">{"from_embedded_action": true}</field>
<field name="groups_ids" eval="[(4, ref('sales_team.group_sale_salesman'))]" />
<field name="domain">[('allow_billable', '=', True)]</field>
</record>
<record id="project_embedded_action_invoices_dashboard" model="ir.embedded.actions">
<field name="parent_res_model">project.project</field>
<field name="sequence">60</field>
<field name="name">Invoices</field>
<field name="parent_action_id" ref="project.project_update_all_action"/>
<field name="python_method">action_open_project_invoices</field>
<field name="context">{"from_embedded_action": true}</field>
<field name="groups_ids" eval="[(4, ref('account.group_account_invoice')), (4, ref('sales_team.group_sale_salesman'))]" />
<field name="domain">[('allow_billable', '=', True)]</field>
</record>
<record id="project_embedded_action_sales_orders_dashboard" model="ir.embedded.actions">
<field name="parent_res_model">project.project</field>
<field name="sequence">50</field>
<field name="name">Sales Orders</field>
<field name="parent_action_id" ref="project.project_update_all_action"/>
<field name="python_method">action_view_sos</field>
<field name="context">{"from_embedded_action": true}</field>
<field name="groups_ids" eval="[(4, ref('sales_team.group_sale_salesman'))]" />
<field name="domain">[('allow_billable', '=', True)]</field>
</record>
<record id="project_embedded_action_vendor_bills" model="ir.embedded.actions">
<field name="parent_res_model">project.project</field>
<field name="sequence">75</field>
<field name="name">Vendor Bills</field>
<field name="parent_action_id" ref="project.act_project_project_2_project_task_all"/>
<field name="python_method">action_open_project_vendor_bills</field>
<field name="context">{"from_embedded_action": true}</field>
<field name="groups_ids" eval="[(4, ref('account.group_account_invoice')), (4, ref('sales_team.group_sale_salesman'))]"/>
<field name="domain">[('allow_billable', '=', True)]</field>
</record>
<record id="project_embedded_action_vendor_bills_dashboard" model="ir.embedded.actions">
<field name="parent_res_model">project.project</field>
<field name="sequence">75</field>
<field name="name">Vendor Bills</field>
<field name="parent_action_id" ref="project.project_update_all_action"/>
<field name="python_method">action_open_project_vendor_bills</field>
<field name="context">{"from_embedded_action": true}</field>
<field name="groups_ids" eval="[(4, ref('account.group_account_invoice')), (4, ref('sales_team.group_sale_salesman'))]"/>
<field name="domain">[('allow_billable', '=', True)]</field>
</record>
<record id="project.open_view_project_all_config" model="ir.actions.act_window">
<field name="context">{'default_allow_billable': True}</field>
<field name="context">{'default_allow_billable': True, 'sale_show_partner_name': True, 'display_milestone_deadline': True}</field>
</record>
<record id="project.open_view_project_all_config_group_stage" model="ir.actions.act_window">
<field name="context">{'default_allow_billable': True}</field>
<field name="context">{
'default_allow_billable': True,
'sale_show_partner_name': True,
'display_milestone_deadline': True
}</field>
</record>
<record id="project.open_view_project_all" model="ir.actions.act_window">
<field name="context">{'default_allow_billable': True}</field>
<field name="context">{'default_allow_billable': True, 'sale_show_partner_name': True, 'display_milestone_deadline': True}</field>
</record>
<record id="project.open_view_project_all_group_stage" model="ir.actions.act_window">
<field name="context">{'default_allow_billable': True, 'search_default_groupby_stage': 1}</field>
<field name="context">{
'default_allow_billable': True,
'sale_show_partner_name': True,
'display_milestone_deadline': True
}</field>
</record>
<record id="project_templates_view_list" model="ir.ui.view">
<field name="name">project.project.template.list</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.project_templates_view_list"/>
<field name="arch" type="xml">
<field name="sale_line_id" position="replace"/>
</field>
</record>
</odoo>

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_order_line_tree_with_create" model="ir.ui.view">
<field name="name">sale.order.line.list.with.create</field>
<field name="model">sale.order.line</field>
<field name="inherit_id" ref="sale.view_order_line_tree"/>
<field name="mode">primary</field>
<field name="priority">999</field>
<field name="arch" type="xml">
<list position="attributes">
<attribute name="create">true</attribute>
</list>
</field>
</record>
<record id="sale_order_line_view_form_editable" model="ir.ui.view">
<field name="name">sale.order.line.view.form.editable</field>
<field name="model">sale.order.line</field>
<field name="inherit_id" ref="sale.sale_order_line_view_form_readonly"/>
<field name="mode">primary</field>
<field name="priority">999</field>
<field name="arch" type="xml">
<form position="attributes">
<attribute name="edit">true</attribute>
</form>
<field name="product_id" position="attributes">
<attribute name="domain">[('type', '=', 'service')]</attribute>
<attribute name="context">{
'default_type': 'service',
'default_service_policy': 'ordered_prepaid',
'form_view_ref': 'sale_project.product_product_form_view_inherit_sale_project',
}</attribute>
</field>
</field>
</record>
</odoo>

View file

@ -7,23 +7,81 @@
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="priority">10</field>
<field name="arch" type="xml">
<xpath expr="//button[@name='action_view_invoice']" position="before">
<field name="project_ids" invisible="1"/>
<field name="is_product_milestone" invisible="1"/>
<button type="object" name="action_view_project_ids" class="oe_stat_button" icon="fa-puzzle-piece" attrs="{'invisible': ['|', ('state', 'in', ['draft', 'sent']), ('project_ids', '=', [])]}" groups="project.group_project_user">
<field name="project_count" widget="statinfo" string="Projects"/>
<button name="action_view_invoice" position="before">
<button
name="action_view_project_ids"
type="object"
class="oe_stat_button"
icon="fa-puzzle-piece"
invisible="not show_project_button"
groups="project.group_project_user"
>
<div class="o_stat_info">
<div class="o_row">
<span class="o_stat_value order-first">
<field name="project_count"/>
</span>
<span class="o_stat_text"> Projects</span>
</div>
<div class="o_row">
<span class="o_stat_value order-first">
<field name="tasks_count"/>
</span>
<span class="o_stat_text"> Tasks</span>
</div>
</div>
</button>
<button class="oe_stat_button" name="action_view_milestone" type="object" icon="fa-check-square-o" attrs="{'invisible': ['|', '|', ('is_product_milestone', '=', False), ('project_ids', '=', []), ('state', '=', 'draft')]}" groups="project.group_project_milestone">
<button
name="action_view_milestone"
type="object"
class="oe_stat_button"
icon="fa-check-square-o"
invisible="not is_product_milestone or not project_ids or state == 'draft'"
groups="project.group_project_milestone"
>
<field name="milestone_count" widget="statinfo" string="Milestones"/>
</button>
<button type="object" name="action_view_task" class="oe_stat_button" icon="fa-tasks" attrs="{'invisible': [('tasks_count', '=', 0)]}" groups="project.group_project_user">
<field name="tasks_count" widget="statinfo" string="Tasks"/>
</button>
</xpath>
<xpath expr="//field[@name='analytic_account_id']" position="after">
<field name="visible_project" invisible="1"/>
<field name="project_id" options="{'no_create': True}" attrs="{'invisible': [('visible_project', '=', False)]}"/>
</xpath>
</button>
<field name="journal_id" position="before">
<field name="project_id" groups="project.group_project_user"
context="{'default_allow_billable': True, 'default_partner_id': partner_id, 'order_id': id, 'order_state' : state}"/>
</field>
</field>
</record>
<record id="view_sales_order_filter_inherit_sale_project" model="ir.ui.view">
<field name="name">sale.order.list.select.inherit.sale_project</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_sales_order_filter"/>
<field name="arch" type="xml">
<field name="order_line" position="after">
<field name="project_id" groups="project.group_project_user"/>
</field>
</field>
</record>
<record id="model_sale_order_action_create_project" model="ir.actions.server">
<field name="name">Create Project</field>
<field name="model_id" ref="sale.model_sale_order"/>
<field name="binding_model_id" ref="sale.model_sale_order"/>
<field name="binding_view_types">form</field>
<field name="state">code</field>
<field name="code">action = records.action_create_project()</field>
</record>
<record id="view_order_simple_form" model="ir.ui.view">
<field name="name">sale.order.form.from.task</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="mode">primary</field>
<field name="arch" type="xml">
<header position="replace"/>
<sheet position="after">
<footer>
<button string="Confirm &amp; Close" special="save" class="btn btn-primary"/>
<button string="Discard" special="cancel" class="btn btn-secondary"/>
</footer>
</sheet>
</field>
</record>

View file

@ -2,15 +2,11 @@
<odoo>
<template id="portal_tasks_list_inherit" inherit_id="project.portal_tasks_list">
<xpath expr="//t[@t-foreach='grouped_tasks']/tbody/tr[hasclass('table-light')]" position="inside">
<th t-if="groupby == 'sale_order'" t-attf-colspan="{{grouped_tasks_colspan}}">
<span t-if="tasks[0].sudo().sale_order_id" class="text-truncate" t-field="tasks[0].sudo().sale_order_id"/>
<span t-else="">No Sales Order</span>
</th>
<th t-if="groupby == 'sale_line'" t-attf-colspan="{{grouped_tasks_colspan}}">
<xpath expr="//th[@name='groupby_name_col']" position="inside">
<t t-if="groupby == 'sale_line_id'">
<span t-if="tasks[0].sudo().sale_line_id" class="text-truncate" t-field="tasks[0].sudo().sale_line_id"/>
<span t-else="">No Sales Order Item</span>
</th>
<span t-else="">Not Billed</span>
</t>
</xpath>
</template>