[FIX] hr_holidays: Improve general UX (Back2basics)

General fixes for usability

- Time off type configuration visual : https://tinyurl.com/yj2z6okp
- When you create an allocation, the end date should have a place holder "no limit". If there is no end date recorded, that value should be displayed on loading.
- In Overview, remove filter "people i manage"
- In Approvals / time off : change filters : https://i.imgur.com/uDNjZv8.png
- In Approvals / approvals : change filters like in point 5 (remove people I manage replace with my team)
- In Reporting / By Employee : filters : https://tinyurl.com/yg3u3rkf
- In Reporting / By Type : filters : https://tinyurl.com/yhbpgz5m
- Remove Allocations smartbutton from Employee App
- When you click on TimeOff Smartbutton from Employee App, you should be redirect to this screen : https://tinyurl.com/ygwxzx5b
- When an allocation is created, the validity is added to the name of the allocation like "Allocation X (validity Date --> Date) and hide the validity field in "My allocations".
- Users will have the information of the validity from the name of the allocation

task-2643692

closes odoo/odoo#77376

X-original-commit: 7f92c830d3607167bd76bc43d992fbf720a3ef29
Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
This commit is contained in:
Philippe Wauthy
2021-09-29 08:33:26 +00:00
parent b948b197da
commit 6367ff2b33
13 changed files with 430 additions and 78 deletions
+1
View File
@@ -66,6 +66,7 @@ A synchronization with an internal agenda (Meetings of the CRM module) is also p
],
'web.assets_backend': [
'hr_holidays/static/src/js/time_off_calendar.js',
'hr_holidays/static/src/js/time_off_calendar_employee.js',
'hr_holidays/static/src/js/radio_image.js',
'hr_holidays/static/src/js/leave_stats_widget.js',
'hr_holidays/static/src/models/*/*.js',
+17 -1
View File
@@ -4,7 +4,7 @@
import datetime
from dateutil.relativedelta import relativedelta
from odoo import api, fields, models
from odoo import _, api, fields, models
from odoo.tools.float_utils import float_round
@@ -246,3 +246,19 @@ class HrEmployee(models.Model):
def _get_user_m2o_to_empty_on_archived_employees(self):
return super()._get_user_m2o_to_empty_on_archived_employees() + ['leave_manager_id']
def action_time_off_dashboard(self):
domain = []
if self.env.context.get('active_ids'):
domain = [('employee_id', 'in', self.env.context.get('active_ids', []))]
return {
'name': _('Time Off Dashboard'),
'type': 'ir.actions.act_window',
'res_model': 'hr.leave',
'views': [[self.env.ref('hr_holidays.hr_leave_employee_view_dashboard').id, 'calendar']],
'domain': domain,
'context': {
'employee_id': self.ids,
},
}
@@ -41,6 +41,7 @@ class HolidaysAllocation(models.Model):
return [('employee_requests', '=', 'yes')]
name = fields.Char('Description', compute='_compute_description', inverse='_inverse_description', search='_search_description', compute_sudo=False)
name_validity = fields.Char('Description with validity', compute='_compute_description_validity')
active = fields.Boolean(default=True)
private_name = fields.Char('Allocation Description', groups='hr_holidays.group_hr_holidays_user')
state = fields.Selection([
@@ -181,6 +182,15 @@ class HolidaysAllocation(models.Model):
allocations = self.sudo().search(domain)
return [('id', 'in', allocations.ids)]
@api.depends('name', 'date_from', 'date_to')
def _compute_description_validity(self):
for allocation in self:
if allocation.date_to:
name_validity = _("%s (from %s to %s)", allocation.name, allocation.date_from.strftime("%b %d %Y"), allocation.date_to.strftime("%b %d %Y"))
else:
name_validity = _("%s (from %s to No Limit)", allocation.name, allocation.date_from.strftime("%b %d %Y"))
allocation.name_validity = name_validity
@api.depends('employee_id', 'holiday_status_id', 'taken_leave_ids.number_of_days', 'taken_leave_ids.state')
def _compute_leaves(self):
for allocation in self:
+2 -1
View File
@@ -327,7 +327,8 @@ class HolidaysType(models.Model):
employee_id = self._get_contextual_employee_id()
if employee_id:
data_days = self.get_employees_days([employee_id])[employee_id]
data_days = (self.get_employees_days(employee_id)[employee_id[0]] if isinstance(employee_id, list) else
self.get_employees_days([employee_id])[employee_id])
for holiday_status in self:
result = data_days.get(holiday_status.id, {})
@@ -37,10 +37,9 @@
<field name="department_id"/>
<field name="job_id"/>
<filter name="my_team" string="My Team" domain="['|', ('employee_id.user_id', '=', uid), ('employee_id.parent_id.user_id', '=', uid)]"/>
<filter string="My Department" name="department" domain="['|', ('department_id.member_ids.user_id', '=', uid), ('employee_id.user_id', '=', uid)]" help="My Department Time Off"/>
<filter string="People I Manage" name="managed_people" domain="[('employee_id.leave_manager_id', '=', uid)]" help="Time off of people you are manager of"/>
<filter string="My Department" name="department" domain="['|', ('department_id.member_ids.user_id', '=', uid), ('employee_id.user_id', '=', uid)]" help="My Department"/>
<separator/>
<filter string="Off Today" name="off_today" domain="[('start_datetime', '&lt;=', context_today().strftime('%Y-%m-%d')), ('stop_datetime', '&gt;=', context_today().strftime('%Y-%m-%d'))]" help="My Department Time Off"/>
<filter string="Off Today" name="off_today" domain="[('start_datetime', '&lt;=', context_today().strftime('%Y-%m-%d')), ('stop_datetime', '&gt;=', context_today().strftime('%Y-%m-%d'))]" help="My Department"/>
<separator/>
<filter string="Approved" name="validate" domain="[('state', '=', 'validate')]" help="validate"/>
<filter string="Waiting for Approval" name="approve" domain="[('state','in',('confirm','validate1'))]"/>
@@ -13,8 +13,7 @@
<separator/>
<filter name="active_types" string="Active Types" domain="[('holiday_status_id.active', '=', True)]" help="Filters only on requests that belong to an time off type that is 'active' (active field is True)"/>
<separator/>
<filter string="My Department Time Off" name="department" domain="[('department_id.manager_id.user_id', '=', uid)]" help="My Department Time Off"/>
<filter name="my_team_leaves" string="My Department Time Off" domain="[('employee_id.parent_id.user_id', '=', uid)]" groups="hr_holidays.group_hr_holidays_manager" help="Time Off of Your Team Member"/>
<filter string="My Department" name="department" domain="[('department_id.manager_id.user_id', '=', uid)]" help="My Department"/>
<separator/>
<filter string="Active Employee" name="active_employee" domain="[('active_employee','=',True)]"/>
<separator/>
@@ -8,6 +8,7 @@ odoo.define('hr_holidays.dashboard.view_custo', function(require) {
var CalendarRenderer = require("web.CalendarRenderer");
var CalendarModel = require("web.CalendarModel");
var CalendarView = require("web.CalendarView");
var dialogs = require('web.view_dialogs');
var viewRegistry = require('web.view_registry');
var _t = core._t;
@@ -82,12 +83,32 @@ odoo.define('hr_holidays.dashboard.view_custo', function(require) {
* @private
*/
_onNewTimeOff: function () {
var self = this;
//use formViewId for this view?
this.do_action('hr_holidays.hr_leave_action_my_request', {
on_close: function () {
self.reload();
}
let self = this;
let domain = [
['name', '=', 'hr.leave.view.form.dashboard.new.time.off'],
['model', '=', 'hr.leave']
];
self._rpc({
model: 'ir.ui.view',
method: 'search',
args: [domain],
}).then(function(ids) {
self.timeOffDialog = new dialogs.FormViewDialog(self, {
res_model: "hr.leave",
view_id: ids,
context: {
'default_date_from': moment().format('YYYY-MM-DD'),
'default_date_to': moment().add(1, 'days').format('YYYY-MM-DD'),
},
title: _t("New time off"),
disable_multiple_selection: true,
on_saved: function() {
self.reload();
},
});
self.timeOffDialog.open();
});
},
@@ -97,18 +118,32 @@ odoo.define('hr_holidays.dashboard.view_custo', function(require) {
* @private
*/
_onNewAllocation: function () {
var self = this;
this.do_action({
type: 'ir.actions.act_window',
res_model: 'hr.leave.allocation',
name: 'New Allocation Request',
views: [[false,'form']],
context: {'form_view_ref': 'hr_holidays.hr_leave_allocation_view_form_dashboard'},
target: 'new',
}, {
on_close: function () {
self.reload();
}
let self = this;
let domain = [
['name', '=', 'hr.leave.view.form.dashboard'],
['model', '=', 'hr.leave.allocation']
];
self._rpc({
model: 'ir.ui.view',
method: 'search',
args: [domain],
}).then(function(ids) {
self.allocationDialog = new dialogs.FormViewDialog(self, {
res_model: "hr.leave.allocation",
view_id: ids,
context: {
'default_employee_ids': self.context.employee_id,
'default_state': 'confirm',
},
title: _t("New Allocation"),
disable_multiple_selection: true,
on_saved: function() {
self.reload();
},
});
self.allocationDialog.open();
});
},
@@ -0,0 +1,266 @@
odoo.define('hr_holidays.employee.dashboard.views', function(require) {
'use strict';
var core = require('web.core');
const config = require('web.config');
var CalendarController = require("web.CalendarController");
var CalendarRenderer = require("web.CalendarRenderer");
var CalendarPopover = require('web.CalendarPopover');
var CalendarView = require("web.CalendarView");
var dialogs = require('web.view_dialogs');
var viewRegistry = require('web.view_registry');
var _t = core._t;
var QWeb = core.qweb;
// TODO in master: Split the timeoff calendar components into several files to reuse or extend them here
var TimeOffCalendarPopover = CalendarPopover.extend({
template: 'hr_holidays.calendar.popover',
init: function (parent, eventInfo) {
this._super.apply(this, arguments);
const state = this.event.extendedProps.record.state;
this.canDelete = state && ['validate', 'refuse'].indexOf(state) === -1;
this.canEdit = state !== undefined;
this.displayFields = [];
if (this.modelName === "hr.leave.report.calendar") {
const duration = this.event.extendedProps.record.display_name.split(':').slice(-1);
this.display_name = _.str.sprintf(_t("Time Off : %s"), duration);
} else {
this.display_name = this.event.extendedProps.record.display_name;
}
},
});
var TimeOffPopoverRenderer = CalendarRenderer.extend({
template: "TimeOff.CalendarView.extend",
/**
* We're overriding this to display the weeknumbers on the year view
*
* @override
* @private
*/
_getFullCalendarOptions: function () {
const oldOptions = this._super(...arguments);
// Parameters
oldOptions.views.dayGridYear.weekNumbers = true;
oldOptions.views.dayGridYear.weekNumbersWithinDays = false;
return oldOptions;
},
config: _.extend({}, CalendarRenderer.prototype.config, {
CalendarPopover: TimeOffCalendarPopover,
}),
_getPopoverParams: function (eventData) {
let params = this._super.apply(this, arguments);
let calendarIcon;
let state = eventData.extendedProps.record.state;
if (state === 'validate') {
calendarIcon = 'fa-calendar-check-o';
} else if (state === 'refuse') {
calendarIcon = 'fa-calendar-times-o';
} else if(state) {
calendarIcon = 'fa-calendar-o';
}
params['title'] = eventData.extendedProps.record.display_name.split(':').slice(0, -1).join(':');
params['template'] = QWeb.render('hr_holidays.calendar.popover.placeholder', {color: this.getColor(eventData.color_index), calendarIcon: calendarIcon});
return params;
},
_render: function () {
var self = this;
return this._super.apply(this, arguments).then(function () {
self.$el.parent().find('.o_calendar_mini').hide();
});
},
/**
* @override
* @private
*/
_renderCalendar: function() {
this._super.apply(this, arguments);
let weekNumbers = this.$el.find('.fc-week-number');
weekNumbers.each( function() {
let weekRow = this.parentNode;
// By default, each month has 6 weeks displayed, hide the week number if there is no days for the week
if(!weekRow.children[1].classList.length && !weekRow.children[weekRow.children.length-1].classList.length) {
this.innerHTML = '';
}
});
},
});
var TimeOffCalendarRenderer = TimeOffPopoverRenderer.extend({
_render: function () {
var self = this;
return this._super.apply(this, arguments).then(function () {
return self._rpc({
model: 'hr.leave.type',
method: 'get_days_all_request',
context: self.state.context,
});
}).then(function (result) {
self.$el.parent().find('.o_calendar_mini').hide();
self.$el.parent().find('.o_timeoff_container').remove();
// Do not display header if there is no element to display
if (result.length > 0) {
if (config.device.isMobile) {
result.forEach((data) => {
const elem = QWeb.render('hr_holidays.dashboard_calendar_header_mobile', {
timeoff: data,
});
self.$el.find('.o_calendar_filter_item[data-value=' + data[4] + '] .o_cw_filter_title').append(elem);
});
} else {
const elem = QWeb.render('hr_holidays.dashboard_calendar_header', {
timeoffs: result,
});
self.$el.before(elem);
}
}
});
},
});
var TimeOffCalendarEmployeeController = CalendarController.extend({
events: _.extend({}, CalendarController.prototype.events, {
'click .btn-time-off': '_onNewTimeOff',
'click .btn-allocation': '_onNewAllocation',
}),
/**
* @override
*/
start: function () {
this.$el.addClass('o_timeoff_calendar');
return this._super(...arguments);
},
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
/**
* Render the buttons and add new button about
* time off and allocations request
*
* @override
*/
renderButtons: function ($node) {
this._super.apply(this, arguments);
$(QWeb.render('hr_holidays.dashboard.calendar.button', {
time_off: _t('New Time Off'),
request: _t('New Allocation Request'),
})).appendTo(this.$buttons);
if ($node) {
this.$buttons.appendTo($node);
} else {
this.$('.o_calendar_buttons').replaceWith(this.$buttons);
}
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* Action: create a new time off request
*
* @private
*/
_onNewTimeOff: function () {
let self = this;
let domain = [
['name', '=', 'hr.leave.view.form.dashboard.new.time.off']
];
self._rpc({
model: 'ir.ui.view',
method: 'search',
args: [domain],
}).then(function(ids) {
self.timeOffDialog = new dialogs.FormViewDialog(self, {
res_model: "hr.leave",
view_id: ids,
context: {
'default_employee_id': self.context.employee_id[0],
'default_date_from': moment().format('YYYY-MM-DD'),
'default_date_to': moment().add(1, 'days').format('YYYY-MM-DD'),
},
title: _t("New time off"),
disable_multiple_selection: true,
on_saved: function() {
self.reload();
},
});
self.timeOffDialog.open();
});
},
/**
* Action: create a new allocation request
*
* @private
*/
_onNewAllocation: function () {
let self = this;
let domain = [
['name', '=', 'hr.leave.allocation.view.form.manager.dashboard']
];
self._rpc({
model: 'ir.ui.view',
method: 'search',
args: [domain],
}).then(function(ids) {
self.allocationDialog = new dialogs.FormViewDialog(self, {
res_model: "hr.leave.allocation",
view_id: ids,
context: {
'default_employee_ids': self.context.employee_id,
'default_state': 'confirm',
},
title: _t("New Allocation"),
disable_multiple_selection: true,
on_saved: function() {
self.reload();
},
});
self.allocationDialog.open();
});
},
_onOpenCreate: function () {
this.context['default_employee_id'] = this.context.employee_id[0];
this._super(...arguments);
},
/**
* @override
*/
_setEventTitle: function () {
return _t('Time Off Request');
},
});
var TimeOffCalendarEmployeeView = CalendarView.extend({
config: _.extend({}, CalendarView.prototype.config, {
Controller: TimeOffCalendarEmployeeController,
Renderer: TimeOffCalendarRenderer,
}),
});
viewRegistry.add('time_off_employee_calendar', TimeOffCalendarEmployeeView);
});
@@ -17,8 +17,8 @@
<separator/>
<filter string="Unread Messages" name="message_needaction" domain="[('message_needaction','=',True)]"/>
<separator/>
<filter string="People I Manage" name="managed_people" domain="[('employee_id.leave_manager_id', '=', uid)]" help="Time off of people you are manager of"/>
<filter string="My Department Time Off" name="my_team_leaves" domain="[('employee_id.parent_id.user_id', '=', uid)]" groups="hr_holidays.group_hr_holidays_manager" help="Time Off of Your Team Member"/>
<filter string="My Team" name="my_team" domain="['|', ('employee_id.leave_manager_id', '=', uid), ('employee_id.user_id', '=', uid)]" help="Time off of people you are manager of"/>
<filter string="My Department" name="my_team_leaves" domain="[('employee_id.parent_id.user_id', '=', uid)]" groups="hr_holidays.group_hr_holidays_manager" help="Time Off of Your Team Member"/>
<separator/>
<filter string="Active Employee" name="active_employee" domain="[('active_employee','=',True)]"/>
<filter string="Archived" name="inactive" domain="[('active','=',False)]"/>
@@ -90,8 +90,9 @@
</div>
</button>
</div>
<div class="oe_title">
<h2><field name="name" placeholder="e.g. Public Holiday Allocation" attrs="{'readonly': [('state', 'not in', ('draft', 'confirm'))]}" required="1"/></h2>
<div id="title" class="oe_title">
<h2><field name="name" placeholder="e.g. Time Off type (From validity start to validity end / no limit)" attrs="{'invisible': [('state', 'not in', ('draft', 'confirm'))]}" required="1"/>
<field name="name_validity" attrs="{'invisible': [('state', 'in', ('draft', 'confirm'))]}"/></h2>
</div>
<group>
<group>
@@ -103,14 +104,15 @@
<field name="is_officer" invisible="1"/>
<field name="accrual_plan_id" attrs="{'invisible': [('allocation_type', '=', 'regular')], 'readonly': ['|', ('is_officer', '=', False), ('state', 'not in', ('draft', 'confirm'))]}"/>
<div class="o_td_label">
<label for="date_from" string="Validity Period" attrs="{'invisible': [('allocation_type', '=', 'accrual')]}"/>
<label for="date_from" string="Validity Period" attrs="{'invisible': ['|', ('allocation_type', '=', 'accrual'), ('state', 'not in', ('draft', 'confirm'))]}"/>
<label for="date_from" string="Start Date" attrs="{'invisible': [('allocation_type', '=', 'regular')]}"/>
</div>
<div class="o_row" name="validity">
<field name="date_from" widget="date" nolabel="1" readonly="1"/>
<i class="fa fa-long-arrow-right mx-2" aria-label="Arrow icon" title="Arrow" attrs="{'invisible': [('allocation_type', '=', 'accrual')]}"/>
<field name="date_from" widget="date" nolabel="1" readonly="1" attrs="{'invisible': ['&amp;', ('allocation_type', '=', 'regular'), ('state', 'not in', ('draft', 'confirm'))]}"/>
<i class="fa fa-long-arrow-right mx-2" aria-label="Arrow icon" title="Arrow" attrs="{'invisible': ['|', ('allocation_type', '=', 'accrual'), ('state', 'not in', ('draft', 'confirm'))]}"/>
<label class="mx-2" for="date_to" string="Run until" attrs="{'invisible': [('allocation_type', '=', 'regular')]}"/>
<field name="date_to" widget="date" nolabel="1" readonly="1"/>
<field name="date_to" widget="date" nolabel="1" readonly="1" placeholder="No Limit" attrs="{'invisible': ['&amp;', ('allocation_type', '=', 'regular'), ('state', 'not in', ('draft', 'confirm'))]}"/>
<div id="no_limit_label" class="oe_read_only" attrs="{'invisible': ['|', '|', ('id', '=', False), ('date_to', '!=', False), ('state', 'not in', ('draft', 'confirm'))]}">No limit</div>
</div>
<field name="number_of_days" invisible="1"/>
@@ -157,6 +159,11 @@
<button string="Mark as Draft" name="action_draft" type="object"
attrs="{'invisible': ['|', ('can_reset', '=', False), ('state', 'not in', ['confirm', 'refuse'])]}"/>
</xpath>
<xpath expr="//div[@id='title']" position="replace">
<div class="oe_title">
<h2><field name="name" placeholder="e.g. Time Off type (From validity start to validity end / no limit)" required="1"/></h2>
</div>
</xpath>
<xpath expr="//field[@name='employee_id']" position="before">
<field name="holiday_type" string="Mode" groups="hr_holidays.group_hr_holidays_user" context="{'employee_id':employee_id}" />
</xpath>
@@ -185,13 +192,20 @@
<xpath expr="//field[@name='allocation_type']" position="attributes">
<attribute name="invisible">0</attribute>
</xpath>
<xpath expr="//field[@name='date_from']" position="attributes">
<attribute name="readonly">0</attribute>
<attribute name="attrs">{'readonly': [('allocation_type', '=', 'accrual'), ('state', 'not in', ('draft', 'confirm'))]}</attribute>
<xpath expr="//label[@for='date_from']" position="replace">
<label for="date_from" string="Validity Period" attrs="{'invisible': [('allocation_type', '=', 'accrual')]}"/>
</xpath>
<xpath expr="//field[@name='date_to']" position="attributes">
<attribute name="readonly">0</attribute>
<attribute name="attrs">{'readonly': [('allocation_type', '=', 'accrual'), ('state', 'not in', ('draft', 'confirm'))]}</attribute>
<xpath expr="//field[@name='date_from']" position="replace">
<field name="date_from" widget="date" nolabel="1" readonly="0" attrs="{'readonly': [('allocation_type', '=', 'accrual'), ('state', 'not in', ('draft', 'confirm'))]}"/>
</xpath>
<xpath expr="//i[hasclass('fa-long-arrow-right')]" position="replace">
<i class="fa fa-long-arrow-right mx-2" aria-label="Arrow icon" title="Arrow" attrs="{'invisible': [('allocation_type', '=', 'accrual')]}"/>
</xpath>
<xpath expr="//field[@name='date_to']" position="replace">
<field name="date_to" widget="date" nolabel="1" readonly="0" placeholder="No Limit" attrs="{'readonly': [('allocation_type', '=', 'accrual'), ('state', 'not in', ('draft', 'confirm'))]}"/>
</xpath>
<xpath expr="//div[@id='no_limit_label']" position="replace">
<div id="no_limit_label" class="oe_read_only" attrs="{'invisible': ['|', ('id', '=', False), ('date_to', '!=', False)]}">No limit</div>
</xpath>
</field>
</record>
@@ -215,12 +229,22 @@
<label for="date_from" position="attributes">
<attribute name="invisible">1</attribute>
</label>
<xpath expr="//sheet" position="after">
<footer>
<button string="Confirm" name="action_confirm" states="draft" type="object" class="oe_highlight"/>
<button string="Discard" special="cancel" data-hotkey="z" />
</footer>
</field>
</record>
<record id="hr_leave_allocation_view_form_manager_dashboard" model="ir.ui.view">
<field name="name">hr.leave.allocation.view.form.manager.dashboard</field>
<field name="model">hr.leave.allocation</field>
<field name="inherit_id" ref="hr_holidays.hr_leave_allocation_view_form_manager"/>
<field name="mode">primary</field>
<field name="priority">16</field>
<field name="arch" type="xml">
<xpath expr="//header" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<div name="button_box" position="attributes">
<attribute name="invisible">1</attribute>
</div>
</field>
</record>
@@ -287,7 +311,7 @@
<xpath expr="//filter[@name='message_needaction']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//filter[@name='managed_people']" position="attributes">
<xpath expr="//filter[@name='my_team']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//filter[@name='my_team_leaves']" position="attributes">
@@ -448,7 +472,7 @@
<field name="name">Allocations</field>
<field name="res_model">hr.leave.allocation</field>
<field name="view_mode">tree,form,kanban,activity</field>
<field name="context">{'search_default_managed_people': 1,'search_default_approve': 2, 'search_default_active_employee': 3}</field>
<field name="context">{'search_default_my_team': 1,'search_default_approve': 2, 'search_default_active_employee': 3}</field>
<field name="domain">[]</field>
<field name="search_view_id" ref="hr_holidays.hr_leave_allocation_view_search_manager"/>
<field name="help" type="html">
@@ -53,7 +53,7 @@
attrs="{
'invisible': [('leave_validation_type', 'in', ['no_validation', 'manager']), '|', ('requires_allocation', '=', 'no'), ('allocation_validation_type', '=', 'officer')]}"/>
<field name="request_unit" widget="radio-inline"/>
<field name="support_document"/>
<field name="support_document" string="Allow To Join Supporting Document" />
<field name="company_id" groups="base.group_multi_company"/>
</group>
<group name="allocation_validation" id="allocation_requests">
@@ -65,11 +65,14 @@
</group>
<group>
<group id="payroll">
</group>
<group name="visual" id="visual">
<h2>Visual</h2>
<field name="color" widget="color_picker"/>
</group>
<group name="visual" id="visual" >
<group colspan="4">
<h2>Display Option</h2>
</group>
<group colspan="4">
<field name="color" widget="color_picker" />
<field class="d-flex flex-wrap" name="icon_id" widget="radio_image" options="{'horizontal': true}"/>
</group>
</group>
+18 -4
View File
@@ -48,9 +48,9 @@
<filter domain="[('state', '=', 'validate1')]" string="Need Second Approval" name="second_approval"/>
<filter string="Approved Time Off" domain="[('state', '=', 'validate')]" name="validated"/>
<separator/>
<filter string="My Department Time Off" name="department" domain="['|', ('department_id.member_ids.user_id', '=', uid), ('employee_id.user_id', '=', uid)]" help="My Department Time Off"/>
<filter string="People I Manage" name="managed_people" domain="[('employee_id.leave_manager_id', '=', uid)]" help="Time off of people you are manager of"/>
<filter string="My Time Off" name="my_leaves" domain="[('employee_id.user_id', '=', uid)]"/>
<filter string="My Team" name="my_team" domain="['|', ('employee_id.leave_manager_id', '=', uid), ('employee_id.user_id', '=', uid)]" help="Time off of people you are manager of"/>
<filter string="My Department" name="department" domain="['|', ('department_id.member_ids.user_id', '=', uid), ('employee_id.user_id', '=', uid)]" help="My Department"/>
<separator/>
<filter string="Active Employee" name="active_employee" domain="[('active_employee','=',True)]"/>
<filter name="filter_date_from" date="date_from"/>
@@ -384,6 +384,20 @@
</field>
</record>
<record id="hr_leave_employee_view_dashboard" model="ir.ui.view">
<field name="name">hr.leave.view.dashboard</field>
<field name="model">hr.leave</field>
<field name="arch" type="xml">
<calendar string="Time Off Request" js_class="time_off_employee_calendar" form_view_id="%(hr_holidays.hr_leave_view_form_dashboard_new_time_off)d" event_open_popup="true" date_start="date_from" date_stop="date_to" mode="year" quick_add="False" show_unusual_days="True" color="color" hide_time="True">
<field name="display_name"/>
<field name="holiday_status_id" filters="1" invisible="1" color="color"/>
<field name="state" invisible="1"/>
<field name="is_hatched" invisible="1" />
<field name="is_striked" invisible="1"/>
</calendar>
</field>
</record>
<record id="hr_leave_view_form_manager" model="ir.ui.view">
<field name="name">hr.leave.view.form.manager</field>
<field name="model">hr.leave</field>
@@ -524,7 +538,7 @@
<xpath expr="//filter[@name='department']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//filter[@name='managed_people']" position="attributes">
<xpath expr="//filter[@name='my_team']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//filter[@name='active_employee']" position="attributes">
@@ -643,7 +657,7 @@
<field name="search_view_id" ref="hr_holidays.hr_leave_view_search_manager"/>
<field name="context">{
'search_default_approve': 1,
'search_default_managed_people': 2,
'search_default_my_team': 2,
'search_default_active_employee': 3,
'search_default_active_time_off': 4,
'hide_employee_name': 1}
+4 -21
View File
@@ -168,10 +168,10 @@
</xpath>
<div name="button_box" position="inside">
<field name="show_leaves" invisible="1"/>
<field name="allocations_count" invisible="1"/>
<field name="is_absent" invisible="1"/>
<field name="hr_icon_display" invisible="1"/>
<button disabled="1"
<button name="action_time_off_dashboard"
type="object"
class="oe_stat_button"
context="{'search_default_employee_id': active_id}"
attrs="{'invisible': [('is_absent', '=', False)]}">
@@ -188,8 +188,8 @@
</span>
</div>
</button>
<button name="%(act_hr_employee_holiday_request)d"
type="action"
<button name="action_time_off_dashboard"
type="object"
class="oe_stat_button"
icon="fa-calendar"
attrs="{'invisible': [('show_leaves','=', False)]}"
@@ -210,23 +210,6 @@
</span>
</div>
</button>
<button name="%(act_hr_employee_holiday_request)d"
type="action"
class="oe_stat_button"
icon="fa-sun-o"
attrs="{'invisible': [('allocations_count','&lt;', 1)]}"
context="{'search_default_employee_id': active_id}"
groups="base.group_user"
help="Remaining leaves">
<div class="o_field_widget o_stat_info">
<span class="o_stat_value">
<field name="allocations_count"/>
</span>
<span class="o_stat_text">
Allocations
</span>
</div>
</button>
</div>
</field>
</record>
@@ -6,8 +6,9 @@
<field name="model">hr.leave.type</field>
<field name="inherit_id" ref="hr_holidays.edit_holiday_status_form"/>
<field name="arch" type="xml">
<xpath expr="//group[@name='visual']" position="after">
<group name="timesheet" string="Timesheets" groups="base.group_no_one">
<xpath expr="//group[@name='visual']" position="before">
<group name="timesheet" groups="base.group_no_one" style="width:50%">
<h2>Timesheets</h2>
<field name="timesheet_project_id" context="{'active_test': False}"/>
<field name="timesheet_task_id" context="{'active_test': False}" attrs="{'required': [('timesheet_project_id', '!=', False)]}"/>
<field name="timesheet_generate" invisible="1"/>