diff options
| author | Yannick Tivisse <yti@odoo.com> | 2020-05-14 13:44:05 +0000 |
|---|---|---|
| committer | Yannick Tivisse <yti@odoo.com> | 2020-05-25 12:44:14 +0000 |
| commit | 45f3659305359fff5b0c7bf3de7d49a25ba5c36d (patch) | |
| tree | 05eb674b1adf2cf31f96d8344dfef83bbced4a03 /addons | |
| parent | f27baf0c94d978d21900cbc85368d97c113fea2a (diff) | |
[IMP] project,...: Improve list views with new widgets
Purpose
=======
Task 2195254 introduced many wonderful widgets to pimp the list view.
This task aims at implemeting them into the Services apps: project,
timesheets, helpdesk, expense, planning and field service.
Remaining days: https://drive.google.com/file/d/1o4Wn47445GxLqBkw-ifH9MgtFU_437xz/view
Avatar: https://drive.google.com/file/d/1yDwJWP0MZCUKZbqCa8hte1ziVTYRMMtb/view
Activities: https://drive.google.com/file/d/1e_rXH50eZq4zY2HOzw7_pfgiD39SoRIl/view
Field-specific decorations: https://drive.google.com/file/d/1WFnqJ-jkyDFftRHxWW4bgomoWrOpOuaY/view
More control on buttons
Specifications
==============
You will find below a list of which widgets to apply to which fields by
model. Some changes have to be done in the form/kanban views as well.
1) project.task
remaining days -> date_deadline -> list + kanban + form views
hide this field if is_closed is true
avatar -> user_id -> list view
activities -> 'next activity' field to be added -> list view
field-specific decorations
https://nimb.ws/ACewrY remove the current orange/red decorations we have
if planned_hours > 0, display the remaining_hours field in (list view):
red if progress is > 100%
orange if progress is between 80% and 100%
green if progress is <80%
display unit_amount in red if > 24:00 -> form view
2) rating.rating
display the rating in:
green = satisfied
orange = not_satisfied
red = highly_dissatisfied
list + form views
3) project.project
avatar -> user_id -> list + form views
4) account.analytic.line
avatar -> employee_id -> list view
display unit_amount in red if > 24:00 -> list + kanban + form view
https://nimb.ws/eIWa7E merge the timer and duration fields together
5) helpdesk.ticket
avatar
user_id -> list view
employee_id under timesheet_ids -> form view
remaining hours -> sla_deadline
activities -> 'next activity' field to be added -> list view
field specific decoration -> display unit_amount in red if > 24:00 -> form view
6) hr.expense
avatar -> employee_id -> list view
activities -> 'next activity' field to be added -> list view
badge -> state -> list view
draft = blue
reported = green
approved = green
done = green
refused = red
combine the unit_amount and the currency_id fields (see the total_amount field for reference) -> list view (idem for the expense_line_ids one2many on hr.expense.sheet)
display the total_amount in bold
move 'company_id' before 'amount'
7) hr.expense.sheet
avatar
employee_id -> list view
user_id -> list view
activities -> 'next activity' field to be added -> list view
badge -> state -> list view
draft = blue
submit = green
approve = green
post = green
done = green
cancel = red
display the total_amount in bold
move 'company_id' before 'amount'
8) planning.slot
avatar -> employee_id -> list view
decoration
display the allocated_percentage field in red if > 100% -> list + form view
display the forecast_hours field in red if > planned hours and if planned_hours > 0 -> form view
display the effective_hours field in red if > forecast_hours and if forecast_hours > 0 -> form view
9) misc
calendar.event -> avatar -> user_id -> form view
mail.activity.type -> combine the delay_count and delay_unit fields together -> list view
note.note -> 'next activity' field to be added -> list view
crm.lead.mining.request
combine the lead_number and lead_type fields together -> list view
display the name in bold
badge -> state
draft = blue
done = green
error = red
planning.slot.template -> display the duration field in red if it is = 0
closes odoo/odoo#51271
Taskid: 2248351
Related: odoo/enterprise#10605
Related: odoo/upgrade#1252
Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
Diffstat (limited to 'addons')
| -rw-r--r-- | addons/calendar/views/calendar_views.xml | 2 | ||||
| -rw-r--r-- | addons/crm_iap_lead/models/crm_iap_lead_mining_request.py | 12 | ||||
| -rw-r--r-- | addons/crm_iap_lead/views/crm_iap_lead_views.xml | 7 | ||||
| -rw-r--r-- | addons/hr_expense/views/hr_expense_views.xml | 32 | ||||
| -rw-r--r-- | addons/hr_timesheet/static/src/js/timesheet_uom.js | 7 | ||||
| -rw-r--r-- | addons/hr_timesheet/static/src/js/timesheet_uom_timer.js | 107 | ||||
| -rw-r--r-- | addons/hr_timesheet/views/assets.xml | 1 | ||||
| -rw-r--r-- | addons/hr_timesheet/views/hr_timesheet_views.xml | 8 | ||||
| -rw-r--r-- | addons/hr_timesheet/views/project_views.xml | 21 | ||||
| -rw-r--r-- | addons/mail/models/mail_activity.py | 9 | ||||
| -rw-r--r-- | addons/mail/views/mail_activity_views.xml | 3 | ||||
| -rw-r--r-- | addons/note/views/note_views.xml | 1 | ||||
| -rw-r--r-- | addons/project/models/project.py | 6 | ||||
| -rw-r--r-- | addons/project/static/src/js/project.js | 47 | ||||
| -rw-r--r-- | addons/project/views/project_assets.xml | 1 | ||||
| -rw-r--r-- | addons/project/views/project_views.xml | 31 | ||||
| -rw-r--r-- | addons/rating/views/rating_rating_views.xml | 2 | ||||
| -rw-r--r-- | addons/timer/static/src/js/timer_toggle_button.js | 5 |
18 files changed, 183 insertions, 119 deletions
diff --git a/addons/calendar/views/calendar_views.xml b/addons/calendar/views/calendar_views.xml index a5b1d080b63..5d8e8f598f7 100644 --- a/addons/calendar/views/calendar_views.xml +++ b/addons/calendar/views/calendar_views.xml @@ -233,7 +233,7 @@ <page name="page_misc" string="Misc" groups="base.group_no_one"> <group> <label for="user_id" string="Owner"/> - <field name="user_id" nolabel="1"/> + <field name="user_id" nolabel="1" widget="many2one_avatar_user"/> </group> </page> </notebook> diff --git a/addons/crm_iap_lead/models/crm_iap_lead_mining_request.py b/addons/crm_iap_lead/models/crm_iap_lead_mining_request.py index 598fe68d8d6..6f30f596d2a 100644 --- a/addons/crm_iap_lead/models/crm_iap_lead_mining_request.py +++ b/addons/crm_iap_lead/models/crm_iap_lead_mining_request.py @@ -37,7 +37,8 @@ class CRMLeadMiningRequest(models.Model): error = fields.Text(string='Error', readonly=True) # Lead / Opportunity Data - lead_type = fields.Selection([('lead', 'Lead'), ('opportunity', 'Opportunity')], string='Type', required=True, default=_default_lead_type) + lead_type = fields.Selection([('lead', 'Leads'), ('opportunity', 'Opportunities')], string='Type', required=True, default=_default_lead_type) + display_lead_label = fields.Char(compute='_compute_display_lead_label') team_id = fields.Many2one('crm.team', string='Sales Team', domain="[('use_opportunities', '=', True)]") user_id = fields.Many2one('res.users', string='Salesperson') tag_ids = fields.Many2many('crm.tag', string='Tags') @@ -64,6 +65,15 @@ class CRMLeadMiningRequest(models.Model): lead_contacts_credits = fields.Char(compute='_compute_tooltip', readonly=True) lead_total_credits = fields.Char(compute='_compute_tooltip', readonly=True) + @api.depends('lead_type', 'lead_number') + def _compute_display_lead_label(self): + selection_description_values = { + e[0]: e[1] for e in self._fields['lead_type']._description_selection(self.env)} + for request in self: + lead_type = selection_description_values[request.lead_type] + request.display_lead_label = '%s %s' % (request.lead_number, lead_type) + + @api.onchange('lead_number', 'contact_number') def _compute_tooltip(self): for record in self: diff --git a/addons/crm_iap_lead/views/crm_iap_lead_views.xml b/addons/crm_iap_lead/views/crm_iap_lead_views.xml index f76fb55013c..5621f10109e 100644 --- a/addons/crm_iap_lead/views/crm_iap_lead_views.xml +++ b/addons/crm_iap_lead/views/crm_iap_lead_views.xml @@ -116,15 +116,14 @@ <field name="model">crm.iap.lead.mining.request</field> <field name="arch" type="xml"> <tree> - <field name="name"/> - <field name="lead_number"/> - <field name="lead_type"/> + <field name="name" decoration-bf="1"/> + <field name="display_lead_label" string="Number of Leads"/> <field name="search_type"/> <field name="country_ids" widget="many2many_tags"/> <field name="team_id"/> <field name="user_id"/> <field name="tag_ids" widget="many2many_tags"/> - <field name="state" readonly="1"/> + <field name="state" readonly="1" decoration-info="state == 'draft'" decoration-success="state == 'done'" decoration-danger="state == 'error'" widget="badge"/> </tree> </field> </record> diff --git a/addons/hr_expense/views/hr_expense_views.xml b/addons/hr_expense/views/hr_expense_views.xml index 72192d284a0..8468611276e 100644 --- a/addons/hr_expense/views/hr_expense_views.xml +++ b/addons/hr_expense/views/hr_expense_views.xml @@ -38,27 +38,28 @@ <field name="name">hr.expense.tree</field> <field name="model">hr.expense</field> <field name="arch" type="xml"> - <tree string="Expenses" decoration-bf="message_unread == True" class="o_expense_tree" js_class="hr_expense_tree_dashboard_upload" decoration-info="state == 'draft'" decoration-muted="state == 'cancel'" multi_edit="1"> + <tree string="Expenses" multi_edit="1"> <field name="attachment_number" invisible="True"/> <field name="date" optional="show"/> <field name="accounting_date" optional="hide" groups="account.group_account_invoice,account.group_account_readonly"/> <field name="name"/> - <field name="employee_id"/> + <field name="employee_id" widget="many2one_avatar_employee"/> <field name="sheet_id" optional="show" invisible="not context.get('show_report', False)" readonly="1"/> <field name="payment_mode" optional="show"/> <field name="reference" optional="hide"/> <field name="analytic_account_id" optional="show" groups="analytic.group_analytic_accounting"/> <field name="analytic_tag_ids" optional="hide" widget="many2many_tags" groups="analytic.group_analytic_tags"/> <field name="account_id" optional="hide"/> - <field name="unit_amount" optional="hide"/> + <field name="company_id" optional="show" groups="base.group_multi_company" readonly="1"/> + <field name="unit_amount" optional="hide" widget="monetary" options="{'currency_field': 'currency_id'}"/> <field name="currency_id" optional="hide"/> <field name="quantity" optional="hide"/> + <field name="activity_ids" widget="list_activity" optional="show"/> <field name="tax_ids" optional="show" widget="many2many_tags" groups="account.group_account_user"/> - <field name="total_amount" optional="show" sum="Total Amount" widget="monetary" options="{'currency_field': 'currency_id'}"/> + <field name="total_amount" optional="show" sum="Total Amount" widget="monetary" options="{'currency_field': 'currency_id'}" decoration-bf="True"/> <button name="action_get_attachment_view" string="Attachments" type="object" icon="fa-paperclip" attrs="{'invisible': [('attachment_number', '=', 0)]}"/> <field name="message_unread" invisible="1"/> - <field name="state" optional="show" readonly="1"/> - <field name="company_id" optional="show" groups="base.group_multi_company" readonly="1"/> + <field name="state" optional="show" readonly="1" decoration-info="state == 'draft'" decoration-success="state in ['reported', 'approved', 'done']" decoration-danger="state in 'refused'" widget="badge"/> <field name="activity_exception_decoration" widget="activity_exception"/> </tree> </field> @@ -460,17 +461,18 @@ <field name="name">hr.expense.sheet.tree</field> <field name="model">hr.expense.sheet</field> <field name="arch" type="xml"> - <tree string="Expense Reports" decoration-warning="state=='draft'" decoration-bf="message_unread == True" decoration-danger="state=='cancel'"> + <tree string="Expense Reports"> <field name="accounting_date" optional="show" groups="account.group_account_manager"/> <field name="create_date" optional="hide"/> <field name="name" string="Expense Report"/> - <field name="employee_id"/> - <field name="user_id" optional="show"/> - <field name="total_amount" optional="show" sum="Total Amount"/> + <field name="employee_id" widget="many2one_avatar_employee"/> + <field name="user_id" optional="show" widget="many2one_avatar_user"/> + <field name="company_id" optional="show" groups="base.group_multi_company"/> + <field name="total_amount" optional="show" sum="Total Amount" decoration-bf="True"/> <field name="currency_id" optional="hide"/> <field name="journal_id" optional="hide"/> - <field name="state" optional="show"/> - <field name="company_id" optional="show" groups="base.group_multi_company"/> + <field name="state" optional="show" decoration-info="state == 'draft'" decoration-success="state in ['submit', 'approve', 'post', 'done']" decoration-danger="state == 'cancel'" widget="badge"/> + <field name="activity_ids" widget="list_activity" optional="show"/> <field name="message_unread" invisible="1"/> <field name="activity_exception_decoration" widget="activity_exception"/> </tree> @@ -522,9 +524,9 @@ </div> <group> <group name="employee_details"> - <field name="employee_id" context="{'default_company_id': company_id}"/> + <field name="employee_id" context="{'default_company_id': company_id}" widget="many2one_avatar_employee"/> <field name="payment_mode"/> - <field name="user_id" domain="[('share', '=', False)]"/> + <field name="user_id" domain="[('share', '=', False)]" widget="many2one_avatar_user"/> <field name="address_id" invisible="1" context="{'default_company_id': company_id}"/> <field name="department_id" invisible="1" context="{'default_company_id': company_id}"/> <field name="company_id" groups="base.group_multi_company"/> @@ -544,7 +546,7 @@ <field name="message_unread" invisible="1"/> <field name="attachment_number" string=" "/> <button name="action_get_attachment_view" string="View Attachments" type="object" icon="fa-paperclip"/> - <field name="unit_amount" optional="hide"/> + <field name="unit_amount" optional="hide" widget="monetary" options="{'currency_field': 'currency_id'}"/> <field name="currency_id" optional="hide"/> <field name="quantity" optional="hide"/> <field name="company_id" invisible="1"/> diff --git a/addons/hr_timesheet/static/src/js/timesheet_uom.js b/addons/hr_timesheet/static/src/js/timesheet_uom.js index 6e6a3f2e953..acfd9fc6e5b 100644 --- a/addons/hr_timesheet/static/src/js/timesheet_uom.js +++ b/addons/hr_timesheet/static/src/js/timesheet_uom.js @@ -121,7 +121,11 @@ const FieldTimesheetTime = basicFields.FieldFloatTime.extend({ if (this.time) { this.timer = setInterval(() => { this.time.addSecond(); - this.$el.text(this.time.toString()); + if (this.$el.children().length) { + this.$el.contents()[1].replaceWith(this.time.toString()); + } else { + this.$el.text(this.time.toString()); + } this.$el.addClass('font-weight-bold text-danger'); }, 1000); } else { @@ -155,7 +159,6 @@ if (widgetName === 'float_toggle') { fieldRegistry.get(widgetName).extend({}) ) || FieldTimesheetFactor; } - fieldRegistry.add('timesheet_uom', FieldTimesheetUom); diff --git a/addons/hr_timesheet/static/src/js/timesheet_uom_timer.js b/addons/hr_timesheet/static/src/js/timesheet_uom_timer.js new file mode 100644 index 00000000000..1355ea009a5 --- /dev/null +++ b/addons/hr_timesheet/static/src/js/timesheet_uom_timer.js @@ -0,0 +1,107 @@ +odoo.define('hr_timesheet.timesheet_uom_timer', function (require) { +"use strict"; + +const fieldRegistry = require('web.field_registry'); +const TimesheetUom = require('hr_timesheet.timesheet_uom'); +const { _lt } = require('web.core'); +const session = require('web.session'); + +/** + * Extend float time widget to add the using of a timer for duration + * (unit_amount) field. + */ +const FieldTimesheetTimeTimer = TimesheetUom.FieldTimesheetTime.extend({ + init: function () { + this._super.apply(this, arguments); + this.isTimerRunning = this.record.data.is_timer_running; + }, + + _render: function () { + this._super.apply(this, arguments); + const my_timesheets = this.record.getContext().my_timesheet_display_timer; + const display_timer = this.record.data.display_timer; + if (my_timesheets && display_timer) { + const title = this.isTimerRunning ? _lt('Stop') : _lt('Play'); + const name = this.isTimerRunning ? 'action_timer_stop' : 'action_timer_start'; + const label = this.isTimerRunning ? _lt('Stop') : _lt('Start'); + + const button = $('<button>', { + 'class': 'o_icon_button o-timer-button mr8', + 'title': title, + 'name': name, + 'aria-label': label, + 'aria-pressed': this.isTimerRunning, + 'type': 'button', + 'role': 'button', + }); + button.html('<i/>'); + button.find('i') + .addClass('fa') + .toggleClass('fa-stop-circle o-timer-stop-button', this.isTimerRunning) + .toggleClass('fa-play-circle o-timer-play-button', !this.isTimerRunning) + .attr('title', title); + button.on('click', this._onToggleButton.bind(this)); + this.$el.prepend(button); + } + }, + + _onToggleButton: async function (event) { + const context = this.record.getContext(); + const prevent_deletion = this.attrs.options && this.attrs.options.prevent_deletion || false; + event.stopPropagation(); + const result = await this._rpc({ + model: this.model, + method: this._getActionButton(), + context: $.extend({}, context, {prevent_deletion: prevent_deletion}), + args: [this.res_id] + }); + + this.trigger_up('field_changed', { + dataPointID: this.dataPointID, + changes: { + 'is_timer_running': !this.isTimerRunning, + }, + }); + this.trigger_up('timer_changed', { + id: this.res_id, + is_timer_running: !this.isTimerRunning + }); + }, + + _getActionButton: function () { + return this.isTimerRunning ? 'action_timer_stop' : 'action_timer_start'; + } + +}); + +/** + * Binding depending on Company Preference + * + * determine wich widget will be the timesheet one. + * Simply match the 'timesheet_uom' widget key with the correct + * implementation (float_time, float_toggle, ...). The default + * value will be 'float_factor'. +**/ +const widgetName = 'timesheet_uom' in session ? + session.timesheet_uom.timesheet_widget : 'float_factor'; + +let FieldTimesheetUom = null; + +if (widgetName === 'float_toggle') { + FieldTimesheetUom = TimesheetUom.FieldTimesheetToggle; +} else if (widgetName === 'float_time') { + FieldTimesheetUom = FieldTimesheetTimeTimer; +} else { + FieldTimesheetUom = ( + fieldRegistry.get(widgetName) && + fieldRegistry.get(widgetName).extend({}) + ) || TimesheetUom.FieldTimesheetFactor; +} +fieldRegistry.add('timesheet_uom_timer', FieldTimesheetUom); + + +return { + FieldTimesheetTimeTimer, +}; + +}); diff --git a/addons/hr_timesheet/views/assets.xml b/addons/hr_timesheet/views/assets.xml index 34f25b9ab14..b20bdf051b8 100644 --- a/addons/hr_timesheet/views/assets.xml +++ b/addons/hr_timesheet/views/assets.xml @@ -5,6 +5,7 @@ <link type="text/scss" href="/hr_timesheet/static/src/scss/timer_button.scss" rel="stylesheet"/> <script type="text/javascript" src="/hr_timesheet/static/src/js/task_with_hours.js"></script> <script type="text/javascript" src="/hr_timesheet/static/src/js/timesheet_uom.js"/> + <script type="text/javascript" src="/hr_timesheet/static/src/js/timesheet_uom_timer.js"/> <script type="text/javascript" src="/hr_timesheet/static/src/js/timesheet_list_view.js"/> <script type="text/javascript" src="/hr_timesheet/static/src/js/timesheet_kanban_view.js"/> </xpath> diff --git a/addons/hr_timesheet/views/hr_timesheet_views.xml b/addons/hr_timesheet/views/hr_timesheet_views.xml index d84f61e320c..994b4ec80f7 100644 --- a/addons/hr_timesheet/views/hr_timesheet_views.xml +++ b/addons/hr_timesheet/views/hr_timesheet_views.xml @@ -26,8 +26,8 @@ <field name="project_id" required="1" context="{'form_view_ref': 'project.project_project_view_form_simplified',}"/> <field name="task_id" optional="show" widget="task_with_hours" context="{'default_project_id': project_id}" domain="[('project_id', '=', project_id)]"/> <field name="name" optional="show" required="0"/> - <field name="is_timer_running" string="Timer" optional="show" widget="timer_toggle_button" readonly="1" attrs="{ 'invisible': [('display_timer', '=', False)] }" invisible="not context.get('my_timesheet_display_timer')" /> - <field name="unit_amount" optional="show" widget="timesheet_uom" sum="Total" attrs="{'readonly': [('id', '!=', False), ('timer_start', '!=', False)]}"/> + <field name="is_timer_running" invisible="1"/> + <field name="unit_amount" optional="show" widget="timesheet_uom_timer" sum="Total" attrs="{'readonly': [('id', '!=', False), ('timer_start', '!=', False)]}" decoration-danger="unit_amount > 24"/> <field name="company_id" invisible="1"/> <field name="timer_start" invisible="1"/> <field name="display_timer" invisible="1"/> @@ -93,7 +93,7 @@ </group> <group> <field name="amount"/> - <field name="unit_amount" widget="timesheet_uom" attrs="{'readonly': [('id', '!=', False), ('timer_start', '!=', False)]}"/> + <field name="unit_amount" widget="timesheet_uom" attrs="{'readonly': [('id', '!=', False), ('timer_start', '!=', False)]}" decoration-danger="unit_amount > 24"/> <field name="currency_id" invisible="1"/> <field name="timer_start" invisible="1"/> </group> @@ -196,7 +196,7 @@ <t t-esc="record.date.value"/> </span> <span class="float-right"> - <strong>Duration: </strong><field name="unit_amount" widget="timesheet_uom"/> + <strong>Duration: </strong><field name="unit_amount" widget="timesheet_uom" decoration-danger="unit_amount > 24"/> </span> </div> </t> diff --git a/addons/hr_timesheet/views/project_views.xml b/addons/hr_timesheet/views/project_views.xml index 2cfea29a39a..1e7cc08f383 100644 --- a/addons/hr_timesheet/views/project_views.xml +++ b/addons/hr_timesheet/views/project_views.xml @@ -121,18 +121,18 @@ <tree editable="bottom" string="Timesheet Activities" default_order="date"> <field name="date"/> <field name="user_id" invisible="1"/> - <field name="employee_id" required="1"/> + <field name="employee_id" required="1" widget="many2one_avatar_employee"/> <field name="name" required="0"/> - <field name="unit_amount" widget="timesheet_uom"/> + <field name="unit_amount" widget="timesheet_uom" decoration-danger="unit_amount > 24"/> <field name="project_id" invisible="1"/> <field name="company_id" invisible="1"/> </tree> <kanban class="o_kanban_mobile"> <field name="date"/> <field name="user_id"/> - <field name="employee_id"/> + <field name="employee_id" widget="many2one_avatar_employee"/> <field name="name"/> - <field name="unit_amount"/> + <field name="unit_amount" decoration-danger="unit_amount > 24"/> <field name="project_id"/> <templates> <t t-name="kanban-box"> @@ -164,9 +164,9 @@ <group> <field name="date"/> <field name="user_id" invisible="1"/> - <field name="employee_id" required="1"/> + <field name="employee_id" required="1" widget="many2one_avatar_employee"/> <field name="name"/> - <field name="unit_amount" string="Duration" widget="float_time"/> + <field name="unit_amount" string="Duration" widget="float_time" decoration-danger="unit_amount > 24"/> <field name="project_id" invisible="1"/> <field name="company_id" invisible="1"/> </group> @@ -193,13 +193,10 @@ <field name="inherit_id" ref="project.view_task_tree2" /> <field eval="2" name="priority"/> <field name="arch" type="xml"> - <xpath expr="//tree" position="attributes"> - <attribute name="decoration-warning">planned_hours and (effective_hours>planned_hours)</attribute> - </xpath> <field name="user_id" position="after"> <field name="planned_hours" widget="float_time" sum="Initially Planned Hours" optional="show"/> <field name="effective_hours" widget="float_time" sum="Effective Hours" optional="show"/> - <field name="remaining_hours" widget="float_time" sum="Remaining Hours" optional="show"/> + <field name="remaining_hours" widget="float_time" sum="Remaining Hours" optional="show" decoration-danger="progress >= 100" decoration-warning="progress >= 80 and progress < 100"/> <field name="progress" widget="progressbar" optional="show" groups="hr_timesheet.group_hr_timesheet_user"/> </field> </field> @@ -240,7 +237,7 @@ </templates> <div class="oe_kanban_bottom_left" position="inside"> <t t-if="record.planned_hours.raw_value > 0 and record.allow_timesheets.raw_value"> - <t t-set="badge" t-value="" t-if="record.progress.raw_value < 80"/> + <t t-set="badge" t-value=""/> <t t-set="badge" t-value="'badge-warning'" t-if="record.progress.raw_value >= 80 and record.progress.raw_value <= 100"/> <t t-set="badge" t-value="'badge-danger'" t-if="record.remaining_hours.raw_value < 0"/> <div t-attf-class="oe_kanban_align badge {{ badge }}" title="Remaining hours"> @@ -302,7 +299,7 @@ <field name="model">project.task</field> <field name="inherit_id" ref="project.view_task_kanban"/> <field name="arch" type="xml"> - <xpath expr="//span[@name='date']" position="before"> + <xpath expr="//div[@name='date_deadline']" position="before"> <field name="display_timesheet_timer" invisible="1"/> <field name="timer_start" invisible="1"/> <field name="timer_pause" invisible="1"/> diff --git a/addons/mail/models/mail_activity.py b/addons/mail/models/mail_activity.py index 0822c3adb06..ca6caf35635 100644 --- a/addons/mail/models/mail_activity.py +++ b/addons/mail/models/mail_activity.py @@ -45,6 +45,7 @@ class MailActivityType(models.Model): ('days', 'days'), ('weeks', 'weeks'), ('months', 'months')], string="Delay units", help="Unit of delay", required=True, default='days') + delay_label = fields.Char(compute='_compute_delay_label') delay_from = fields.Selection([ ('current_date', 'after validation date'), ('previous_activity', 'after previous activity deadline')], string="Delay Type", help="Type of delay", required=True, default='previous_activity') @@ -91,6 +92,14 @@ class MailActivityType(models.Model): for activity_type in self: activity_type.initial_res_model_id = activity_type.res_model_id + @api.depends('delay_unit', 'delay_count') + def _compute_delay_label(self): + selection_description_values = { + e[0]: e[1] for e in self._fields['delay_unit']._description_selection(self.env)} + for activity_type in self: + unit = selection_description_values[activity_type.delay_unit] + activity_type.delay_label = '%s %s' % (activity_type.delay_count, unit) + class MailActivity(models.Model): """ An actual activity to perform. Activities are linked to diff --git a/addons/mail/views/mail_activity_views.xml b/addons/mail/views/mail_activity_views.xml index eaea8c27cb0..337455bae57 100644 --- a/addons/mail/views/mail_activity_views.xml +++ b/addons/mail/views/mail_activity_views.xml @@ -70,8 +70,7 @@ <field name="sequence" widget="handle"/> <field name="name"/> <field name="summary"/> - <field name="delay_count" string="Planned in"/> - <field name="delay_unit" string="Unit"/> + <field name="delay_label" string="Planned in" class="text-right"/> <field name="delay_from" string="Type"/> <field name="res_model_id" groups="base.group_no_one"/> <field name="icon" groups="base.group_no_one"/> diff --git a/addons/note/views/note_views.xml b/addons/note/views/note_views.xml index b6c586157d5..2f10994aa04 100644 --- a/addons/note/views/note_views.xml +++ b/addons/note/views/note_views.xml @@ -141,6 +141,7 @@ <field name="open"/> <field name="stage_id"/> <field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color'}"/> + <field name="activity_ids" widget="list_activity" optional="show"/> <field name="activity_exception_decoration" widget="activity_exception"/> </tree> </field> diff --git a/addons/project/models/project.py b/addons/project/models/project.py index cc90d132df1..3cbed1b1107 100644 --- a/addons/project/models/project.py +++ b/addons/project/models/project.py @@ -559,7 +559,6 @@ class Task(models.Model): date_end = fields.Datetime(string='Ending Date', index=True, copy=False) date_assign = fields.Datetime(string='Assigning Date', index=True, copy=False, readonly=True) date_deadline = fields.Date(string='Deadline', index=True, copy=False, tracking=True) - date_deadline_formatted = fields.Char(compute='_compute_date_deadline_formatted') date_last_stage_update = fields.Datetime(string='Last Stage Update', index=True, copy=False, @@ -624,11 +623,6 @@ class Task(models.Model): user_names = ', '.join(portal_users[:10].mapped('name')) raise ValidationError(_("The project visibility setting doesn't allow portal users to see the project's tasks. (%s)") % user_names) - @api.depends('date_deadline') - def _compute_date_deadline_formatted(self): - for task in self: - task.date_deadline_formatted = format_date(self.env, task.date_deadline) if task.date_deadline else None - def _compute_attachment_ids(self): for task in self: attachment_ids = self.env['ir.attachment'].search([('res_id', '=', task.id), ('res_model', '=', 'project.task')]).ids diff --git a/addons/project/static/src/js/project.js b/addons/project/static/src/js/project.js deleted file mode 100644 index 5e0062a9965..00000000000 --- a/addons/project/static/src/js/project.js +++ /dev/null @@ -1,47 +0,0 @@ -odoo.define('project.update_kanban', function (require) { -'use strict'; - -var KanbanRecord = require('web.KanbanRecord'); -var basic_fields = require('web.basic_fields'); -var registry = require('web.field_registry'); - -KanbanRecord.include({ - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - - /** - * @override - * @private - */ - _openRecord: function () { - if (this.modelName === 'project.project' && this.$(".o_project_kanban_boxes a").length) { - this.$('.o_project_kanban_boxes a').first().click(); - } else { - this._super.apply(this, arguments); - } - }, - -}); - -var FieldTaskClosedDeadline = basic_fields.FieldDate.extend({ - _renderReadonly: function () { - if (this.value && this.value.toISOString()) { - var deadline = moment(this.value.toISOString()).startOf('day'); - var task_closed = 'is_closed' in this.record.data && this.record.data.is_closed; - - if (!task_closed && deadline < moment().startOf('day')) { - this.$el.addClass('text-danger font-weight-bold'); - } else if (!task_closed && deadline < moment().endOf('day')) { - this.$el.addClass('text-warning font-weight-bold'); - } - } - - this.$el.text(this._formatValue(this.value)); - } -}); - -registry.add('task_closed_deadline', FieldTaskClosedDeadline); - -return FieldTaskClosedDeadline; -}); diff --git a/addons/project/views/project_assets.xml b/addons/project/views/project_assets.xml index 347f620f386..e6e6dddeea2 100644 --- a/addons/project/views/project_assets.xml +++ b/addons/project/views/project_assets.xml @@ -3,7 +3,6 @@ <template id="assets_backend" name="project assets" inherit_id="web.assets_backend"> <xpath expr="." position="inside"> <link rel="stylesheet" href="/project/static/src/css/project.css"/> - <script type="text/javascript" src="/project/static/src/js/project.js"></script> <script type="text/javascript" src="/project/static/src/js/project_kanban.js"></script> <script type="text/javascript" src="/project/static/src/js/project_task_kanban_examples.js"></script> <script type="text/javascript" src="/project/static/src/js/tours/project.js"></script> diff --git a/addons/project/views/project_views.xml b/addons/project/views/project_views.xml index 80f725c5f0f..f35e189f9ae 100644 --- a/addons/project/views/project_views.xml +++ b/addons/project/views/project_views.xml @@ -291,7 +291,7 @@ <group> <group> <field name="active" invisible="1"/> - <field name="user_id" string="Project Manager" attrs="{'readonly':[('active','=',False)]}" domain="[('share', '=', False)]"/> + <field name="user_id" string="Project Manager" widget="many2one_avatar_user" attrs="{'readonly':[('active','=',False)]}" domain="[('share', '=', False)]"/> <field name="partner_id" string="Customer"/> </group> <group> @@ -404,7 +404,7 @@ <field name="message_needaction" invisible="1"/> <field name="active" invisible="1"/> <field name="name" string="Project Name"/> - <field name="user_id" optional="show" string="Project Manager"/> + <field name="user_id" optional="show" string="Project Manager" widget="many2one_avatar_user"/> <field name="partner_id" optional="show" string="Contact"/> <field name="analytic_account_id" optional="hide"/> <field name="privacy_visibility" optional="hide"/> @@ -666,7 +666,7 @@ domain="[('parent_id', '=', False)]" attrs="{'invisible' : [('allow_subtasks', '=', False)]}" /> - <field name="date_deadline" widget="task_closed_deadline" /> + <field name="date_deadline" widget="remaining_days" attrs="{'invisible': [('is_closed', '=', True)]}"/> <field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color', 'no_create_edit': True}"/> </group> </group> @@ -761,8 +761,6 @@ <field name="user_id"/> <field name="partner_id"/> <field name="sequence"/> - <field name="date_deadline"/> - <field name="date_deadline_formatted"/> <field name="is_closed"/> <field name="partner_is_company"/> <field name="displayed_image_id"/> @@ -823,19 +821,9 @@ <span style="font-weight:bold;" class="fa fa-fw mt4 fa-meh-o text-warning" t-if="record.rating_last_value.value == 3" title="Latest Rating: Not Satisfied" role="img" aria-label="Neutral face"/> <span style="font-weight:bold;" class="fa fa-fw mt4 fa-frown-o text-danger" t-if="record.rating_last_value.value == 1" title="Latest Rating: Higly Dissatisfied" role="img" aria-label="Sad face"/> </b> - <!-- formating of the date --> - <t t-set="date_format" t-value="'MM/DD/YY'" /> - <t t-set="date" t-value=""/> - <!-- color of the span --> - <t t-if="!record.is_closed.raw_value and record.date_deadline.raw_value and moment(record.date_deadline.raw_value.toISOString()).startOf('day') lt moment().startOf('day')"> - <t t-set="deadline_class" t-value="'oe_kanban_text_red'" /> - </t> - <t t-elif="!record.is_closed.raw_value and record.date_deadline.raw_value and moment(record.date_deadline.raw_value.toISOString()).startOf('day') lt moment().endOf('day')"> - <t t-set="deadline_class" t-value="'text-warning font-weight-bold'" /> - </t> - <!-- Date value --> - <t t-if="record.date_deadline.raw_value" t-set="date" t-value="record.date_deadline_formatted.raw_value" /> - <span name="date" title="Deadline" t-attf-class="#{deadline_class || ''}"><t t-esc="date" /></span> + <div name="date_deadline" attrs="{'invisible': [('is_closed', '=', True)]}"> + <field name="date_deadline" widget="remaining_days"/> + </div> </div> <div class="oe_kanban_bottom_right" t-if="!selection_mode"> <field name="kanban_state" widget="state_selection" groups="base.group_user" invisible="context.get('fsm_mode', False)"/> @@ -856,7 +844,7 @@ <field name="model">project.task</field> <field eval="2" name="priority"/> <field name="arch" type="xml"> - <tree decoration-danger="not is_closed and date_deadline and (date_deadline<current_date)" string="Tasks" multi_edit="1"> + <tree string="Tasks" multi_edit="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"/> @@ -865,8 +853,9 @@ <field name="project_id" invisible="context.get('user_invisible', False)" optional="show" readonly="1"/> <field name="partner_id" optional="hide"/> <field name="parent_id" groups="project.group_subtask_project" optional="show"/> - <field name="user_id" invisible="context.get('user_invisible', False)" optional="show"/> - <field name="date_deadline" optional="hide"/> + <field name="user_id" invisible="context.get('user_invisible', False)" optional="show" widget="many2one_avatar_user"/> + <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="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'}"/> <field name="company_id" groups="base.group_multi_company" optional="show"/> diff --git a/addons/rating/views/rating_rating_views.xml b/addons/rating/views/rating_rating_views.xml index a41c404019d..9ed2ca1029e 100644 --- a/addons/rating/views/rating_rating_views.xml +++ b/addons/rating/views/rating_rating_views.xml @@ -10,7 +10,7 @@ <field name="parent_res_name"/> <field name="rated_partner_id"/> <field name="partner_id"/> - <field name="rating_text"/> + <field name="rating_text" decoration-danger="rating_text == 'highly_dissatisfied'" decoration-warning="rating_text == 'not_satisfied'" decoration-success="rating_text == 'satisfied'"/> <field name="feedback"/> <field name="create_date" string="Submitted on"/> </tree> diff --git a/addons/timer/static/src/js/timer_toggle_button.js b/addons/timer/static/src/js/timer_toggle_button.js index 1bb5c2185d7..78274e05e0c 100644 --- a/addons/timer/static/src/js/timer_toggle_button.js +++ b/addons/timer/static/src/js/timer_toggle_button.js @@ -3,6 +3,7 @@ odoo.define('timer.timer_toggle_button', function (require) { const fieldRegistry = require('web.field_registry'); const { FieldToggleBoolean } = require("web.basic_fields"); +const { _lt } = require('web.core'); /** * The TimerToggleButton is used to display correctly the button @@ -16,9 +17,9 @@ const TimerToggleButton = FieldToggleBoolean.extend({ */ _render: function () { // When the is_timer_running field is false, then the button is used to start the timer - const title = this.value ? 'stop' : 'play'; + const title = this.value ? _lt('Stop') : _lt('Play'); const name = this.value ? 'action_timer_stop' : 'action_timer_start'; - const label = this.value ? 'stop' : 'start'; + const label = this.value ? _lt('Stop') : _lt('Start'); this.$('i') .addClass('fa') |
