[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:
@@ -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',
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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', '<=', context_today().strftime('%Y-%m-%d')), ('stop_datetime', '>=', context_today().strftime('%Y-%m-%d'))]" help="My Department Time Off"/>
|
||||
<filter string="Off Today" name="off_today" domain="[('start_datetime', '<=', context_today().strftime('%Y-%m-%d')), ('stop_datetime', '>=', 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': ['&', ('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': ['&', ('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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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','<', 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"/>
|
||||
|
||||
Reference in New Issue
Block a user