summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--addons/hr_timesheet/tests/test_timesheet.py1
-rw-r--r--addons/pad_project/models/project.py5
-rw-r--r--addons/pad_project/views/project_views.xml8
-rw-r--r--addons/project/models/project.py38
-rw-r--r--addons/project/views/project_views.xml120
-rw-r--r--addons/project/views/rating_views.xml3
-rw-r--r--addons/rating/views/rating_rating_views.xml2
-rw-r--r--addons/sale_timesheet/data/sale_timesheet_filters.xml2
-rw-r--r--addons/sale_timesheet/report/project_profitability_report_analysis_views.xml1
9 files changed, 108 insertions, 72 deletions
diff --git a/addons/hr_timesheet/tests/test_timesheet.py b/addons/hr_timesheet/tests/test_timesheet.py
index 4113b052ea0..fdd64970c79 100644
--- a/addons/hr_timesheet/tests/test_timesheet.py
+++ b/addons/hr_timesheet/tests/test_timesheet.py
@@ -21,6 +21,7 @@ class TestCommonTimesheet(TransactionCase):
self.partner = self.env['res.partner'].create({
'name': 'Customer Task',
'email': 'customer@task.com',
+ 'phone': '42',
})
self.analytic_account = self.env['account.analytic.account'].create({
diff --git a/addons/pad_project/models/project.py b/addons/pad_project/models/project.py
index 919755b9987..abc0342671a 100644
--- a/addons/pad_project/models/project.py
+++ b/addons/pad_project/models/project.py
@@ -42,8 +42,11 @@ class ProjectTask(models.Model):
class ProjectProject(models.Model):
- _inherit = "project.project"
+ _name = "project.project"
+ _inherit = ["project.project", 'pad.common']
+ _description = 'Project'
+ description_pad = fields.Char('Pad URL', pad_content_field='description', copy=False)
use_pads = fields.Boolean("Use collaborative pads", default=True,
help="Use collaborative pad for the tasks on this project.")
diff --git a/addons/pad_project/views/project_views.xml b/addons/pad_project/views/project_views.xml
index d4dee168f2a..3539d850e5c 100644
--- a/addons/pad_project/views/project_views.xml
+++ b/addons/pad_project/views/project_views.xml
@@ -20,6 +20,14 @@
<field name="model">project.project</field>
<field name="inherit_id" ref="project.edit_project"/>
<field name="arch" type="xml">
+ <xpath expr="//field[@name='description']" position="attributes">
+ <attribute name="attrs">{'invisible': [('use_pads', '=', True)], 'readonly': [('use_pads', '=', True)]}</attribute>
+ </xpath>
+ <field name="description" position="after">
+ <field name="use_pads" invisible="1"/>
+ <field name="description_pad" widget="pad" nolabel="1"
+ attrs="{'invisible': [('use_pads', '=', False)], 'readonly': [('use_pads', '=', False)]}"/>
+ </field>
<xpath expr="//div[@id='rating_settings']" position="after">
<div class="col-lg-6 o_setting_box" id="pad_settings">
<div class="o_setting_left_pane">
diff --git a/addons/project/models/project.py b/addons/project/models/project.py
index d2b8e97d264..d24d6e4e4b3 100644
--- a/addons/project/models/project.py
+++ b/addons/project/models/project.py
@@ -155,11 +155,17 @@ class Project(models.Model):
return [(6, 0, [self.env.uid])]
name = fields.Char("Name", index=True, required=True, tracking=True)
- description = fields.Text()
+ description = fields.Html()
active = fields.Boolean(default=True,
help="If the active field is set to False, it will allow you to hide the project without removing it.")
sequence = fields.Integer(default=10, help="Gives the sequence order when displaying a list of Projects.")
partner_id = fields.Many2one('res.partner', string='Customer', auto_join=True, tracking=True, domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
+ partner_email = fields.Char(
+ compute='_compute_partner_email', inverse='_inverse_partner_email',
+ string='Email', readonly=False, store=True)
+ partner_phone = fields.Char(
+ compute='_compute_partner_phone', inverse='_inverse_partner_phone',
+ string="Phone", readonly=False, store=True)
company_id = fields.Many2one('res.company', string='Company', required=True, default=lambda self: self.env.company)
currency_id = fields.Many2one('res.currency', related="company_id.currency_id", string="Currency", readonly=True)
analytic_account_id = fields.Many2one('account.analytic.account', string="Analytic Account", copy=False, ondelete='set null',
@@ -237,6 +243,28 @@ class Project(models.Model):
('project_date_greater', 'check(date >= date_start)', 'Error! project start-date must be lower than project end-date.')
]
+ @api.depends('partner_id.email')
+ def _compute_partner_email(self):
+ for project in self:
+ if project.partner_id and project.partner_id.email != project.partner_email:
+ project.partner_email = project.partner_id.email
+
+ def _inverse_partner_email(self):
+ for project in self:
+ if project.partner_id and project.partner_email != project.partner_id.email:
+ project.partner_id.email = project.partner_email
+
+ @api.depends('partner_id.phone')
+ def _compute_partner_phone(self):
+ for project in self:
+ if project.partner_id and project.partner_phone != project.partner_id.phone:
+ project.partner_phone = project.partner_id.phone
+
+ def _inverse_partner_phone(self):
+ for project in self:
+ if project.partner_id and project.partner_phone != project.partner_id.phone:
+ project.partner_id.phone = project.partner_phone
+
def _compute_alias_enabled(self):
for project in self:
project.alias_enabled = project.alias_domain and project.alias_id.alias_name
@@ -396,7 +424,11 @@ class Project(models.Model):
self.mapped('tasks').message_subscribe(
partner_ids=partner_ids, channel_ids=channel_ids, subtype_ids=task_subtypes)
if partner_ids:
- self.allowed_portal_user_ids |= self.env['res.partner'].browse(partner_ids).user_ids.filtered('share')
+ all_users = self.env['res.partner'].browse(partner_ids).user_ids
+ portal_users = all_users.filtered('share')
+ internal_users = all_users - portal_users
+ self.allowed_portal_user_ids |= portal_users
+ self.allowed_internal_user_ids |= internal_users
return res
def message_unsubscribe(self, partner_ids=None, channel_ids=None):
@@ -1384,7 +1416,7 @@ class ProjectTags(models.Model):
return randint(1, 11)
name = fields.Char('Name', required=True)
- color = fields.Integer(string='Color Index', default=_get_default_color)
+ color = fields.Integer(string='Color', default=_get_default_color)
_sql_constraints = [
('name_uniq', 'unique (name)', "Tag name already exists!"),
diff --git a/addons/project/views/project_views.xml b/addons/project/views/project_views.xml
index 115164f23c9..9c23ab71bc8 100644
--- a/addons/project/views/project_views.xml
+++ b/addons/project/views/project_views.xml
@@ -64,7 +64,7 @@
<field name="search_view_id" ref="view_task_search_form"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
- Click <i>Create</i> to start a new task
+ No tasks found. Let's create one!
</p><p>
To get things done, use activities and status on tasks.<br/>
Chat in real time or by email to collaborate efficiently.
@@ -79,7 +79,7 @@
<field name="search_view_id" ref="project.view_task_search_form"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
- Click <i>Create</i> to start a new task
+ No tasks found. Let's create one!
</p><p>
To get things done, use activities and status on tasks.<br/>
Chat in real time or by email to collaborate efficiently.
@@ -284,22 +284,44 @@
</div>
</div>
</div>
- <field name="description" placeholder="Describe your project..."/>
<notebook>
+ <page name="description_page" string="Description">
+ <field name="description" nolabel="1" placeholder="Describe your project..." type="html"/>
+ <div class="oe_clear"/>
+ </page>
<page name="settings" string="Settings">
<group>
<group>
<field name="active" invisible="1"/>
<field name="user_id" string="Project Manager" widget="many2one_avatar_user" attrs="{'readonly':[('active','=',False)]}" domain="[('share', '=', False)]"/>
<field name="partner_id" string="Customer"/>
+ <field name="partner_phone" widget="phone"
+ attrs="{'invisible': [('partner_id', '=', False)]}"/>
+ <field name="partner_email" widget="email"
+ attrs="{'invisible': [('partner_id', '=', False)]}"/>
<div name="alias_def" colspan="2" attrs="{'invisible': [('alias_domain', '=', False)]}">
- <label for="alias_enabled" class="font-weight-bold" string="Create tasks by sending an email to"/>
- <field name="alias_enabled"/>
- <span attrs="{'invisible': [('alias_enabled', '=', False)]}">
- <field name="alias_name" class="oe_inline" attrs="{'required': [('alias_enabled', '=', True)]}"/>@<field name="alias_domain" class="oe_inline" readonly="1" />
+ <!-- Always display the whole alias in edit mode. It depends in read only -->
+ <label for="alias_enabled" class="font-weight-bold" string="Create tasks by sending an email"/>
+ <field name="alias_enabled" invisible="1"/>
+ <span>
+ <span class="font-weight-bold oe_read_only" attrs="{'invisible': [('alias_name', '=', False)]}">to </span>
+ <span class="font-weight-bold oe_edit_only">to </span>
+ <field name="alias_name" class="oe_inline"/>
+ <span class="oe_read_only" attrs="{'invisible': [('alias_name', '=', False)]}">@</span>
+ <span class="oe_edit_only">@</span>
+ <field name="alias_domain"
+ attrs="{'invisible': [('alias_name', '=', False)]}"
+ class="oe_inline oe_read_only"
+ readonly="1"/>
+ <field name="alias_domain"
+ class="oe_inline oe_edit_only"
+ readonly="1"/>
</span>
</div>
- <field name="alias_contact" class="oe_inline oe_edit_only" string="Accept Emails From" attrs="{'invisible': ['|', ('alias_domain', '=', False), ('alias_enabled', '=', False)]}"/>
+ <!-- the alias contact must appear when the user start typing and it must disappear
+ when the string is deleted. -->
+ <field name="alias_contact" class="oe_inline oe_edit_only" string="Accept Emails From"
+ attrs="{'invisible': ['|', ('alias_name', '=', ''), ('alias_name', '=', False)]}"/>
</group>
<group>
<field name="analytic_account_id" domain="['|', ('company_id', '=', company_id), ('company_id', '=', False)]" context="{'default_partner_id': partner_id}" groups="analytic.group_analytic_accounting"/>
@@ -404,7 +426,7 @@
<field name="sequence" optional="show" widget="handle"/>
<field name="message_needaction" invisible="1"/>
<field name="active" invisible="1"/>
- <field name="name" string="Name"/>
+ <field name="name" string="Name" class="font-weight-bold"/>
<field name="user_id" optional="show" string="Project Manager" widget="many2one_avatar_user"/>
<field name="partner_id" optional="show" string="Customer"/>
<field name="analytic_account_id" optional="hide"/>
@@ -416,37 +438,6 @@
</field>
</record>
- <record id="project_view_kanban" model="ir.ui.view">
- <field name="name">project.project.kanban</field>
- <field name="model">project.project</field>
- <field name="arch" type="xml">
- <kanban class="o_kanban_mobile">
- <field name="user_id" string="Project Manager"/>
- <templates>
- <t t-name="kanban-box">
- <div t-attf-class="oe_kanban_content oe_kanban_global_click o_kanban_get_form">
- <div class="row">
- <div class="col-12">
- <strong><field name="name" string="Project Name"/></strong>
- </div>
- </div>
- <div class="row">
- <div class="col-8">
- <field name="partner_id" string="Contact"/>
- </div>
- <div class="col-4">
- <div class="oe_kanban_bottom_right float-right">
- <field name="user_id" widget="many2one_avatar_user"/>
- </div>
- </div>
- </div>
- </div>
- </t>
- </templates>
- </kanban>
- </field>
- </record>
-
<record id="project_project_view_form_simplified" model="ir.ui.view">
<field name="name">project.project.view.form.simplified</field>
<field name="model">project.project</field>
@@ -459,12 +450,10 @@
<field name="allow_recurring_tasks" groups="project.group_project_recurring_tasks" />
</group>
<div name="alias_def" colspan="2" attrs="{'invisible': [('alias_domain', '=', False)]}">
- <label for="alias_enabled" class="oe_inline" string="Create tasks by sending an email to"/>
- <field name="alias_enabled"/>
- <span attrs="{'invisible': [('alias_enabled', '=', False)]}">
- <field name="alias_name" class="oe_inline" attrs="{'required': [('alias_enabled', '=', True)]}" placeholder="e.g. office-party"/>
- @
- <field name="alias_domain" class="oe_inline" readonly="1" />
+ <label for="alias_name" class="oe_inline" string="Create tasks by sending an email to"/>
+ <field name="alias_enabled" invisible="1"/>
+ <span>
+ <field name="alias_name" class="oe_inline" placeholder="e.g. office-party"/>@<field name="alias_domain" class="oe_inline" readonly="1" />
</span>
</div>
</form>
@@ -585,7 +574,7 @@
<field name="target">main</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
- Create a project
+ No projects found. Let's create one!
</p><p>
Projects regroup tasks on the same topic and each have their own dashboard.
</p>
@@ -599,12 +588,12 @@
<field name="view_mode">tree,kanban,form</field>
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('view_project')}),
- (0, 0, {'view_mode': 'kanban', 'view_id': ref('project_view_kanban')})]"/>
+ (0, 0, {'view_mode': 'kanban', 'view_id': ref('view_project_kanban')})]"/>
<field name="search_view_id" ref="view_project_project_filter"/>
<field name="context">{}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
- Create a project
+ No projects found. Let's create one!
</p><p>
Projects regroup tasks on the same topic and each have their own dashboard.
</p>
@@ -677,14 +666,14 @@
</group>
<group>
<field name="project_id" required="1" domain="[('active', '=', True), ('company_id', '=', company_id)]"/>
- <field name="user_id"
- class="o_task_user_field"
- domain="[('share', '=', False)]"/>
<field
name="parent_id"
domain="[('parent_id', '=', False)]"
attrs="{'invisible' : [('allow_subtasks', '=', False)]}"
/>
+ <field name="user_id"
+ class="o_task_user_field"
+ domain="[('share', '=', False)]"/>
<field name="date_deadline" widget="remaining_days" attrs="{'invisible': [('is_closed', '=', True)]}"/>
<field name="recurring_task" attrs="{'invisible': [('allow_recurring_tasks', '=', False)]}" />
<field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color', 'no_create_edit': True}"/>
@@ -861,7 +850,7 @@
<span class="fa fa-ellipsis-v"/>
</a>
<div class="dropdown-menu" role="menu">
- <a t-if="widget.editable" role="menuitem" type="set_cover" data-auto-open="1" class="dropdown-item" data-field="displayed_image_id">Set Cover Image</a>
+ <a t-if="widget.editable" role="menuitem" type="set_cover" class="dropdown-item" data-field="displayed_image_id">Set Cover Image</a>
<a name="%(portal.portal_share_action)d" role="menuitem" type="action" class="dropdown-item">Share</a>
<a t-if="widget.editable" role="menuitem" type="edit" class="dropdown-item">Edit</a>
<a t-if="widget.editable" role="menuitem" class="dropdown-item" name="toggle_active" type="object">
@@ -915,18 +904,17 @@
<tree string="Tasks" multi_edit="1" sample="1">
<field name="message_needaction" invisible="1" readonly="1"/>
<field name="is_closed" invisible="1" />
- <field name="sequence" invisible="not context.get('seq_visible', False)" readonly="1"/>
+ <field name="sequence" invisible="1" readonly="1"/>
<field name="name"/>
- <!-- YTI TODO user_invisible and seq_visible seem to be useless -->
- <field name="project_id" invisible="context.get('user_invisible', False)" optional="show" readonly="1"/>
+ <field name="project_id" optional="show" readonly="1"/>
<field name="partner_id" optional="hide"/>
<field name="parent_id" groups="project.group_subtask_project" optional="hide"/>
- <field name="user_id" invisible="context.get('user_invisible', False)" optional="show" widget="many2one_avatar_user"/>
+ <field name="user_id" optional="show" widget="many2one_avatar_user"/>
<field name="company_id" groups="base.group_multi_company" optional="show"/>
<field name="activity_ids" widget="list_activity" optional="show"/>
<field name="date_deadline" optional="hide" widget="remaining_days" attrs="{'invisible': [('is_closed', '=', True)]}"/>
+ <field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color'}"/>
<field name="stage_id" invisible="context.get('set_visible',False)" optional="show" readonly="1"/>
- <field name="tag_ids" optional="hide" widget="many2many_tags" options="{'color_field': 'color'}"/>
</tree>
</field>
</record>
@@ -1013,10 +1001,10 @@
<field name="search_view_id" ref="view_task_search_form"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
- Create a new task
+ No tasks found. Let's create one!
</p><p>
- Odoo's project management allows you to manage the pipeline of your tasks efficiently.<br/>
- You can track progress, discuss on tasks, attach documents, etc.
+ To get things done, use activities and status on tasks.<br/>
+ Chat in real time or by email to collaborate efficiently.
</p>
</field>
</record>
@@ -1029,10 +1017,10 @@
<field name="search_view_id" ref="view_task_search_form"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
- Create a new task
+ No tasks found. Let's create one!
</p><p>
- Odoo's project management allows you to manage the pipeline of your tasks efficiently.<br/>
- You can track progress, discuss on tasks, attach documents, etc.
+ To get things done, use activities and status on tasks.<br/>
+ Chat in real time or by email to collaborate efficiently.
</p>
</field>
</record>
@@ -1136,10 +1124,10 @@
<field name="res_model">project.tags</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
- Create a new tag
+ No tags found. Let's create one!
</p>
<p>
- Tags are perfect to categorize your tasks.
+ Tags are perfect to categorize your tasks.
</p>
</field>
</record>
diff --git a/addons/project/views/rating_views.xml b/addons/project/views/rating_views.xml
index 08b133554fc..48a01e909bb 100644
--- a/addons/project/views/rating_views.xml
+++ b/addons/project/views/rating_views.xml
@@ -42,6 +42,9 @@
<div name="rating_image_container" position="replace">
<field name="rating_text" string="Rating"/>
</div>
+ <xpath expr="//field[@name='is_internal']" position="attributes">
+ <attribute name="invisible">1</attribute>
+ </xpath>
</field>
</record>
diff --git a/addons/rating/views/rating_rating_views.xml b/addons/rating/views/rating_rating_views.xml
index 758103dc695..07dddb12892 100644
--- a/addons/rating/views/rating_rating_views.xml
+++ b/addons/rating/views/rating_rating_views.xml
@@ -54,7 +54,7 @@
<field name="name">rating.rating.kanban</field>
<field name="model">rating.rating</field>
<field name="arch" type="xml">
- <kanban create="false">
+ <kanban create="false" sample="1">
<field name="rating"/>
<field name="res_name"/>
<field name="feedback"/>
diff --git a/addons/sale_timesheet/data/sale_timesheet_filters.xml b/addons/sale_timesheet/data/sale_timesheet_filters.xml
index 2894ad05c76..3794aff0342 100644
--- a/addons/sale_timesheet/data/sale_timesheet_filters.xml
+++ b/addons/sale_timesheet/data/sale_timesheet_filters.xml
@@ -7,7 +7,7 @@
<field name="user_id" eval="False"/>
<field name="is_default" eval="True"/>
<field name="context">{
- 'group_by': ['project_id', 'sale_line_id'],
+ 'group_by': ['line_date'],
'pivot_measures': ['amount_untaxed_to_invoice', 'amount_untaxed_invoiced', 'timesheet_cost', 'timesheet_unit_amount']
}</field>
</record>
diff --git a/addons/sale_timesheet/report/project_profitability_report_analysis_views.xml b/addons/sale_timesheet/report/project_profitability_report_analysis_views.xml
index b6d8b72adf8..2f28170dabb 100644
--- a/addons/sale_timesheet/report/project_profitability_report_analysis_views.xml
+++ b/addons/sale_timesheet/report/project_profitability_report_analysis_views.xml
@@ -25,6 +25,7 @@
<field name="amount_untaxed_invoiced" type="measure"/>
<field name="timesheet_cost" type="measure"/>
<field name="other_revenues" type="measure"/>
+ <field name="margin" type="measure"/>
</graph>
</field>
</record>