[IMP] *.*: update the tooltips in various modules

The goal of this task is to review the copywriting of the tooltips
because some of them are not correct in English and others are not
valid anymore. This is also a good opportunity to make an inventory
of the tooltips we have and to add some that could be missing.

task-2862283

closes odoo/odoo#93261

Related: odoo/enterprise#28225
Signed-off-by: Laurent Stukkens (ltu) <ltu@odoo.com>
This commit is contained in:
Vishal Padhiyar
2022-09-20 16:29:13 +02:00
committed by Barad Mahendra
parent 4fb0933986
commit 812644b120
7 changed files with 69 additions and 50 deletions
+4 -4
View File
@@ -28,7 +28,7 @@ class Project(models.Model):
allow_timesheets = fields.Boolean(
"Timesheets", compute='_compute_allow_timesheets', store=True, readonly=False,
default=True, help="Enable timesheeting on the project.")
default=True)
analytic_account_id = fields.Many2one(
# note: replaces ['|', ('company_id', '=', False), ('company_id', '=', company_id)]
domain="""[
@@ -232,11 +232,11 @@ class Task(models.Model):
analytic_account_active = fields.Boolean("Active Analytic Account", compute='_compute_analytic_account_active', compute_sudo=True)
allow_timesheets = fields.Boolean("Allow timesheets", related='project_id.allow_timesheets', help="Timesheets can be logged on this task.", readonly=True)
remaining_hours = fields.Float("Remaining Hours", compute='_compute_remaining_hours', store=True, readonly=True, help="Total remaining time, can be re-estimated periodically by the assignee of the task.")
remaining_hours = fields.Float("Remaining Hours", compute='_compute_remaining_hours', store=True, readonly=True, help="Number of allocated hours minus the number of hours spent.")
remaining_hours_percentage = fields.Float(compute='_compute_remaining_hours_percentage', search='_search_remaining_hours_percentage')
effective_hours = fields.Float("Hours Spent", compute='_compute_effective_hours', compute_sudo=True, store=True, help="Time spent on this task, excluding its sub-tasks.")
total_hours_spent = fields.Float("Total Hours", compute='_compute_total_hours_spent', store=True, help="Time spent on this task, including its sub-tasks.")
progress = fields.Float("Progress", compute='_compute_progress_hours', store=True, group_operator="avg", help="Display progress of current task.")
total_hours_spent = fields.Float("Total Hours", compute='_compute_total_hours_spent', store=True, help="Time spent on this task and its sub-tasks (and their own sub-tasks).")
progress = fields.Float("Progress", compute='_compute_progress_hours', store=True, group_operator="avg")
overtime = fields.Float(compute='_compute_progress_hours', store=True)
subtask_effective_hours = fields.Float("Sub-tasks Hours Spent", compute='_compute_subtask_effective_hours', recursive=True, store=True, help="Time spent on the sub-tasks (and their own sub-tasks) of this task.")
timesheet_ids = fields.One2many('account.analytic.line', 'task_id', 'Timesheets')
+47 -35
View File
@@ -78,28 +78,29 @@ class ProjectTaskType(models.Model):
description = fields.Text(translate=True)
sequence = fields.Integer(default=1)
project_ids = fields.Many2many('project.project', 'project_task_type_rel', 'type_id', 'project_id', string='Projects',
default=_get_default_project_ids)
default=_get_default_project_ids,
help="Projects in which this stage is present. If you follow a similar workflow in several projects,"
" you can share this stage among them and get consolidated information this way.")
legend_blocked = fields.Char(
'Red Kanban Label', default=lambda s: _('Blocked'), translate=True, required=True,
help='Override the default value displayed for the blocked state for kanban selection when the task or issue is in that stage.')
'Red Kanban Label', default=lambda s: _('Blocked'), translate=True, required=True)
legend_done = fields.Char(
'Green Kanban Label', default=lambda s: _('Ready'), translate=True, required=True,
help='Override the default value displayed for the done state for kanban selection when the task or issue is in that stage.')
'Green Kanban Label', default=lambda s: _('Ready'), translate=True, required=True)
legend_normal = fields.Char(
'Grey Kanban Label', default=lambda s: _('In Progress'), translate=True, required=True,
help='Override the default value displayed for the normal state for kanban selection when the task or issue is in that stage.')
'Grey Kanban Label', default=lambda s: _('In Progress'), translate=True, required=True)
mail_template_id = fields.Many2one(
'mail.template',
string='Email Template',
domain=[('model', '=', 'project.task')],
help="If set, an email will be sent to the customer when the task or issue reaches this step.")
help="If set, an email will be automatically sent to the customer when the task reaches this stage.")
fold = fields.Boolean(string='Folded in Kanban',
help='This stage is folded in the kanban view when there are no records in that stage to display.')
help='If enabled, this stage will be displayed as folded in the Kanban view of your tasks. Tasks in a folded stage are considered as closed.')
rating_template_id = fields.Many2one(
'mail.template',
string='Rating Email Template',
domain=[('model', '=', 'project.task')],
help="If set and if the project's rating configuration is 'Rating when changing stage', then an email will be sent to the customer when the task reaches this step.")
help="If set, a rating request will automatically be sent by email to the customer when the task reaches this stage. \n"
"Alternatively, it will be sent at a regular interval as long as the task remains in this stage, depending on the configuration of your project. \n"
"To use this feature make sure that the 'Customer Ratings' option is enabled on your project.")
auto_validation_kanban_state = fields.Boolean('Automatic Kanban Status', default=False,
help="Automatically modify the kanban state when the customer replies to the feedback for this stage.\n"
" * Good feedback from the customer will update the kanban state to 'ready for the new stage' (green bullet).\n"
@@ -283,11 +284,12 @@ class Project(models.Model):
def _read_group_stage_ids(self, stages, domain, order):
return self.env['project.project.stage'].search([], order=order)
name = fields.Char("Name", index='trigram', required=True, tracking=True, translate=True, default_export_compatible=True)
description = fields.Html()
name = fields.Char("Name", index='trigram', required=True, tracking=True, translate=True, default_export_compatible=True,
help="Name of your project. It can be anything you want e.g. the name of a customer or a service.")
description = fields.Html(help="Description to provide more information and context about this project")
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.")
sequence = fields.Integer(default=10)
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',
@@ -300,8 +302,10 @@ class Project(models.Model):
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',
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", check_company=True,
help="Analytic account to which this project is linked for financial management. "
"Use an analytic account to record cost and revenue on your project.")
help="Analytic account to which this project, its tasks and its timesheets are linked. \n"
"Track the costs and revenues of your project by setting this analytic account on your related documents (e.g. sales orders, invoices, purchase orders, vendor bills, expenses etc.).\n"
"This analytic account can be changed on each task individually if necessary.\n"
"An analytic account is required in order to use timesheets.")
analytic_account_balance = fields.Monetary(related="analytic_account_id.balance")
favorite_user_ids = fields.Many2many(
@@ -310,7 +314,8 @@ class Project(models.Model):
string='Members')
is_favorite = fields.Boolean(compute='_compute_is_favorite', inverse='_inverse_is_favorite', compute_sudo=True,
string='Show Project on Dashboard')
label_tasks = fields.Char(string='Use Tasks as', default='Tasks', help="Label used for tasks in this project (e.g. Tasks, Features, Tickets, etc).", translate=True)
label_tasks = fields.Char(string='Use Tasks as', default='Tasks', translate=True,
help="Name used to refer to the tasks of your project e.g. tasks, tickets, sprints, etc...")
tasks = fields.One2many('project.task', 'project_id', string="Task Activities")
resource_calendar_id = fields.Many2one(
'resource.calendar', string='Working Time',
@@ -349,7 +354,8 @@ class Project(models.Model):
access_instruction_message = fields.Char('Access Instruction Message', compute='_compute_access_instruction_message')
doc_count = fields.Integer(compute='_compute_attached_docs_count', string="Number of documents attached")
date_start = fields.Date(string='Start Date')
date = fields.Date(string='Expiration Date', index=True, tracking=True)
date = fields.Date(string='Expiration Date', index=True, tracking=True,
help="Date on which this project ends. The timeframe defined on the project is taken into account when viewing its planning.")
allow_subtasks = fields.Boolean('Sub-tasks', default=lambda self: self.env.user.has_group('project.group_subtask_project'))
allow_recurring_tasks = fields.Boolean('Recurring Tasks', default=lambda self: self.env.user.has_group('project.group_project_recurring_tasks'))
allow_task_dependencies = fields.Boolean('Task Dependencies', default=lambda self: self.env.user.has_group('project.group_project_task_dependencies'))
@@ -368,10 +374,9 @@ class Project(models.Model):
[('stage', 'Rating when changing stage'),
('periodic', 'Periodic rating')
], 'Customer Ratings Status', default="stage", required=True,
help="How to get customer feedback?\n"
"- Rating when changing stage: an email will be sent when a task is pulled to another stage.\n"
"- Periodic rating: an email will be sent periodically.\n\n"
"Don't forget to set up the email templates on the stages for which you want to get customer feedback.")
help="Collect feedback from your customers by sending them a rating request when a task enters a certain stage. To do so, define a rating email template on the corresponding stages.\n"
"Rating when changing stage: an email will be automatically sent when the task reaches the stage on which the rating email template is set.\n"
"Periodic rating: an email will be automatically sent at regular intervals as long as the task remains in the stage in which the rating email template is set.")
rating_status_period = fields.Selection([
('daily', 'Daily'),
('weekly', 'Weekly'),
@@ -382,7 +387,10 @@ class Project(models.Model):
# Not `required` since this is an option to enable in project settings.
stage_id = fields.Many2one('project.project.stage', string='Stage', ondelete='restrict', groups="project.group_project_stages",
tracking=True, index=True, copy=False, default=_default_stage_id, group_expand='_read_group_stage_ids')
tracking=True, index=True, copy=False, default=_default_stage_id, group_expand='_read_group_stage_ids',
help="The step, or stage, that your project is in. You can add, remove, and move stages around to adapt the pipeline to your own needs.\n"
"Via the stage configuration you can set up email templates and automate the sending of emails when a project moves into the stage.\n"
"Projects in a folded stage are considered as closed.")
update_ids = fields.One2many('project.update', 'project_id')
last_update_id = fields.Many2one('project.update', string='Last Update', copy=False)
@@ -1092,7 +1100,8 @@ class Task(models.Model):
store=True, readonly=False, ondelete='restrict', tracking=True, index=True,
default=_get_default_stage_id, group_expand='_read_group_stage_ids',
domain="[('project_ids', '=', project_id)]", copy=False, task_dependency_tracking=True)
tag_ids = fields.Many2many('project.tags', string='Tags')
tag_ids = fields.Many2many('project.tags', string='Tags',
help="You can only see tags that are already present in your project. If you try creating a tag that is already existing in other projects, it won't generate any duplicates.")
kanban_state = fields.Selection([
('normal', 'In Progress'),
('done', 'Ready'),
@@ -1102,13 +1111,16 @@ class Task(models.Model):
create_date = fields.Datetime("Created On", readonly=True)
write_date = fields.Datetime("Last Updated On", readonly=True)
date_end = fields.Datetime(string='Ending Date', index=True, copy=False)
date_assign = fields.Datetime(string='Assigning Date', copy=False, readonly=True)
date_deadline = fields.Date(string='Deadline', index=True, copy=False, tracking=True, task_dependency_tracking=True, help="The deadline for the task, which appears in the calendar view.")
date_assign = fields.Datetime(string='Assigning Date', copy=False, readonly=True,
help="Date on which this task was last assigned (or unassigned). Based on this, you can get statistics on the time it usually takes to assign tasks.")
date_deadline = fields.Date(string='Deadline', index=True, copy=False, tracking=True, task_dependency_tracking=True)
date_last_stage_update = fields.Datetime(string='Last Stage Update',
index=True,
copy=False,
readonly=True)
readonly=True,
help="Date on which the stage of your task has last been modified.\n"
"Based on this information you can identify tasks that are stalling and get statistics on the time it usually takes to move tasks from one stage to another.")
project_id = fields.Many2one('project.project', string='Project', recursive=True,
compute='_compute_project_id', store=True, readonly=False,
index=True, tracking=True, check_company=True, change_default=True)
@@ -1117,9 +1129,9 @@ class Task(models.Model):
# A -> project_id=P, display_project_id=P
# B -> project_id=P (to inherit from ACL/security rules), display_project_id=False
display_project_id = fields.Many2one('project.project', index=True)
planned_hours = fields.Float("Initially Planned Hours", help='Time planned to achieve this task (including its sub-tasks).', tracking=True)
planned_hours = fields.Float("Initially Planned Hours", tracking=True)
subtask_planned_hours = fields.Float("Sub-tasks Planned Hours", compute='_compute_subtask_planned_hours',
help="Sum of the time planned of all the sub-tasks linked to this task. Usually less than or equal to the initially planned time of this task.")
help="Sum of the hours allocated for all the sub-tasks (and their own sub-tasks) linked to this task. Usually less than or equal to the allocated hours of this task.")
# Tracking of this field is done in the write function
user_ids = fields.Many2many('res.users', relation='project_task_user_rel', column1='task_id', column2='user_id', string='Assignees', context={'active_test': False}, tracking=True)
# User names displayed in project sharing views
@@ -1152,6 +1164,7 @@ class Task(models.Model):
compute='_compute_partner_phone', inverse='_inverse_partner_phone',
string="Phone", readonly=False, store=True, copy=False)
partner_city = fields.Char(related='partner_id.city', readonly=False)
email_cc = fields.Char(help='Email addresses that were in the CC of the incoming emails from this task and that are not currently linked to an existing customer.')
manager_id = fields.Many2one('res.users', string='Project Manager', related='project_id.user_id', readonly=True)
company_id = fields.Many2one(
'res.company', string='Company', compute='_compute_company_id', store=True, readonly=False,
@@ -1193,9 +1206,7 @@ class Task(models.Model):
readonly=False,
store=True,
tracking=True,
help="Track major progress points that must be reached to achieve success (e.g. Product Launch). "
"After all the tasks connected to this milestone are completed, you will be invited to mark it as reached if you wish. "
"You can deliver your services automatically when a milestone is reached by linking it to a sales order item."
help="Deliver your services automatically when a milestone is reached by linking it to a sales order item."
)
has_late_and_unreached_milestone = fields.Boolean(
compute='_compute_has_late_and_unreached_milestone',
@@ -1303,9 +1314,9 @@ class Task(models.Model):
# Account analytic
analytic_account_id = fields.Many2one('account.analytic.account', ondelete='set null', compute='_compute_analytic_account_id', store=True, readonly=False,
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", check_company=True,
help="Analytic account to which this task is linked for financial management. "
"Use an analytic account to record cost and revenue on your task. "
"If empty, the analytic account of the project will be used.")
help="Analytic account to which this task and its timesheets are linked.\n"
"Track the costs and revenues of your task by setting its analytic account on your related documents (e.g. sales orders, invoices, purchase orders, vendor bills, expenses etc.).\n"
"By default, the analytic account of the project is set. However, it can be changed on each task individually if necessary.")
is_analytic_account_id_changed = fields.Boolean('Is Analytic Account Manually Changed', compute='_compute_is_analytic_account_id_changed', store=True)
project_analytic_account_id = fields.Many2one('account.analytic.account', string='Project Analytic Account', related='project_id.analytic_account_id')
@@ -2620,7 +2631,8 @@ class ProjectTags(models.Model):
return randint(1, 11)
name = fields.Char('Name', required=True, translate=True)
color = fields.Integer(string='Color', default=_get_default_color)
color = fields.Integer(string='Color', default=_get_default_color,
help="Transparent tags are not visible in the kanban view of your projects and tasks.")
project_ids = fields.Many2many('project.project', 'project_project_project_tags_rel', string='Projects')
task_ids = fields.Many2many('project.task', string='Tasks')
@@ -12,5 +12,6 @@ class ProjectProjectStage(models.Model):
sequence = fields.Integer(default=50)
name = fields.Char(required=True, translate=True)
mail_template_id = fields.Many2one('mail.template', string='Email Template', domain=[('model', '=', 'project.project')],
help="If set, an email will be sent to the customer when the project reaches this step.")
fold = fields.Boolean('Folded in Kanban')
help="If set, an email will be automatically sent to the customer when the project reaches this stage.")
fold = fields.Boolean('Folded in Kanban',
help="If enabled, this stage will be displayed as folded in the Kanban view of your projects. Projects in a folded stage are considered as closed.")
+2 -1
View File
@@ -8,4 +8,5 @@ class ProjectProjectStage(models.Model):
_inherit = 'project.project.stage'
sms_template_id = fields.Many2one('sms.template', string="SMS Template",
domain=[('model', '=', 'project.project')], help="SMS sent when a task is moved to this stage.")
domain=[('model', '=', 'project.project')],
help="If set, an SMS Text Message will be automatically sent to the customer when the project reaches this stage.")
@@ -8,4 +8,5 @@ class ProjectTaskType(models.Model):
_inherit = "project.task.type"
sms_template_id = fields.Many2one('sms.template', string="SMS Template",
domain=[('model', '=', 'project.task')], help="SMS sent when a task is moved to this stage.")
domain=[('model', '=', 'project.task')],
help="If set, an SMS Text Message will be automatically sent to the customer when the task reaches this stage.")
+7 -4
View File
@@ -12,13 +12,14 @@ from odoo.tools import Query
class Project(models.Model):
_inherit = 'project.project'
allow_billable = fields.Boolean("Billable", help="Invoice your time and material from tasks.")
allow_billable = fields.Boolean("Billable")
sale_line_id = fields.Many2one(
'sale.order.line', 'Sales Order Item', copy=False,
compute="_compute_sale_line_id", store=True, readonly=False, index='btree_not_null',
domain="[('is_service', '=', True), ('is_expense', '=', False), ('state', 'in', ['sale', 'done']), ('order_partner_id', '=?', partner_id), '|', ('company_id', '=', False), ('company_id', '=', company_id)]",
help="Sales order item to which the project is linked. Link the timesheet entry to the sales order item defined on the project. "
"Only applies on tasks without sale order item defined, and if the employee is not in the 'Employee/Sales Order Item Mapping' of the project.")
help="Sales order item that will be selected by default on the tasks and timesheets of this project,"
" except if the employee set on the timesheets is explicitely linked to another sales order item on the project.\n"
"It can be modified on each task and timesheet entry individually if necessary.")
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', groups='sales_team.group_sale_salesman')
@@ -472,7 +473,9 @@ class ProjectTask(models.Model):
copy=True, tracking=True, index='btree_not_null', recursive=True,
compute='_compute_sale_line', store=True, readonly=False,
domain="[('company_id', '=', company_id), ('is_service', '=', True), ('order_partner_id', '=?', partner_id), ('is_expense', '=', False), ('state', 'in', ['sale', 'done'])]",
help="Sales Order Item to which the time spent on this task will be added, in order to be invoiced to your customer.")
help="Sales Order Item to which the time spent on this task will be added in order to be invoiced to your customer.\n"
"By default the sales order item set on the project will be selected. In the absence of one, the last prepaid sales order item that has time remaining will be used.\n"
"Remove the sales order item in order to make this task non billable. You can also change or remove the sales order item of each timesheet entry individually.")
project_sale_order_id = fields.Many2one('sale.order', string="Project's sale order", related='project_id.sale_order_id')
task_to_invoice = fields.Boolean("To invoice", compute='_compute_task_to_invoice', search='_search_task_to_invoice', groups='sales_team.group_sale_salesman_all_leads')
+4 -3
View File
@@ -35,8 +35,9 @@ class Project(models.Model):
search='_search_pricing_type',
help='The task rate is perfect if you would like to bill different services to different customers at different rates. The fixed rate is perfect if you bill a service at a fixed rate per hour or day worked regardless of the employee who performed it. The employee rate is preferable if your employees deliver the same service at a different rate. For instance, junior and senior consultants would deliver the same service (= consultancy), but at a different rate because of their level of seniority.')
sale_line_employee_ids = fields.One2many('project.sale.line.employee.map', 'project_id', "Sale line/Employee map", copy=False,
help="Employee/Sale Order Item Mapping:\n Defines to which sales order item an employee's timesheet entry will be linked."
"By extension, it defines the rate at which an employee's time on the project is billed.")
help="Sales order item that will be selected by default on the timesheets of the corresponding employee. It bypasses the sales order item defined on the project and the task, and can be modified on each timesheet entry if necessary. In other words, it defines the rate at which an employee's time is billed based on their expertise, skills or experience, for instance.\n"
"If you would like to bill the same service at a different rate, you need to create two separate sales order items as each sales order item can only have a single unit price at a time.\n"
"You can also define the hourly company cost of your employees for their timesheets on this project specifically. It will bypass the timesheet cost set on the employee.")
billable_percentage = fields.Integer(
compute='_compute_billable_percentage', groups='hr_timesheet.group_hr_timesheet_approver',
help="% of timesheets that are billable compared to the total number of timesheets linked to the AA of the project, rounded to the unit.")
@@ -48,7 +49,7 @@ class Project(models.Model):
('invoice_policy', '=', 'delivery'),
('service_type', '=', 'timesheet'),
'|', ('company_id', '=', False), ('company_id', '=', company_id)]""",
help='Select a Service product with which you would like to bill your time spent on tasks.',
help='Service that will be used by default when invoicing the time spent on a task. It can be modified on each task individually by selecting a specific sales order item.',
compute="_compute_timesheet_product_id", store=True, readonly=False,
default=_default_timesheet_product_id)
warning_employee_rate = fields.Boolean(compute='_compute_warning_employee_rate', compute_sudo=True)