[IMP] hr_holidays: improve dashboard
- Switch position of leaves taken / remaining - Change the "To" date when requesting a leave - Take into account the leaves to be validated in the dashboard - UX improvements to the popover closes odoo/odoo#46210 Taskid: 2198615 Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
This commit is contained in:
@@ -318,6 +318,9 @@ class HolidaysRequest(models.Model):
|
||||
self.date_to = False
|
||||
return
|
||||
|
||||
if self.request_date_from > self.request_date_to:
|
||||
self.request_date_to = self.request_date_from
|
||||
|
||||
resource_calendar_id = self.employee_id.resource_calendar_id or self.env.company.resource_calendar_id
|
||||
domain = [('calendar_id', '=', resource_calendar_id.id), ('display_type', '=', False)]
|
||||
attendances = self.env['resource.calendar.attendance'].read_group(domain, ['ids:array_agg(id)', 'hour_from:min(hour_from)', 'hour_to:max(hour_to)', 'week_type', 'dayofweek', 'day_period'], ['week_type', 'dayofweek', 'day_period'], lazy=False)
|
||||
|
||||
@@ -63,6 +63,9 @@ class HolidaysType(models.Model):
|
||||
virtual_remaining_leaves = fields.Float(
|
||||
compute='_compute_leaves', search='_search_virtual_remaining_leaves', string='Virtual Remaining Time Off',
|
||||
help='Maximum Time Off Allowed - Time Off Already Taken - Time Off Waiting Approval')
|
||||
virtual_leaves_taken = fields.Float(
|
||||
compute='_compute_leaves', string='Virtual Time Off Already Taken',
|
||||
help='Sum of validated and non validated time off requests.')
|
||||
group_days_allocation = fields.Float(
|
||||
compute='_compute_group_days_allocation', string='Days Allocated')
|
||||
group_days_leave = fields.Float(
|
||||
@@ -187,7 +190,7 @@ class HolidaysType(models.Model):
|
||||
|
||||
def get_days(self, employee_id):
|
||||
# need to use `dict` constructor to create a dict per id
|
||||
result = dict((id, dict(max_leaves=0, leaves_taken=0, remaining_leaves=0, virtual_remaining_leaves=0)) for id in self.ids)
|
||||
result = dict((id, dict(max_leaves=0, leaves_taken=0, remaining_leaves=0, virtual_remaining_leaves=0, virtual_leaves_taken=0)) for id in self.ids)
|
||||
|
||||
requests = self.env['hr.leave'].search([
|
||||
('employee_id', '=', employee_id),
|
||||
@@ -206,6 +209,9 @@ class HolidaysType(models.Model):
|
||||
status_dict['virtual_remaining_leaves'] -= (request.number_of_hours_display
|
||||
if request.leave_type_request_unit == 'hour'
|
||||
else request.number_of_days)
|
||||
status_dict['virtual_leaves_taken'] += (request.number_of_hours_display
|
||||
if request.leave_type_request_unit == 'hour'
|
||||
else request.number_of_days)
|
||||
if request.state == 'validate':
|
||||
status_dict['leaves_taken'] += (request.number_of_hours_display
|
||||
if request.leave_type_request_unit == 'hour'
|
||||
@@ -240,6 +246,7 @@ class HolidaysType(models.Model):
|
||||
'virtual_remaining_leaves': ('%.2f' % lt.virtual_remaining_leaves).rstrip('0').rstrip('.'),
|
||||
'max_leaves': ('%.2f' % lt.max_leaves).rstrip('0').rstrip('.'),
|
||||
'leaves_taken': ('%.2f' % lt.leaves_taken).rstrip('0').rstrip('.'),
|
||||
'virtual_leaves_taken': ('%.2f' % lt.virtual_leaves_taken).rstrip('0').rstrip('.'),
|
||||
'request_unit': lt.request_unit,
|
||||
}, lt.allocation_type, lt.validity_stop)
|
||||
for lt in leave_types]
|
||||
@@ -266,6 +273,7 @@ class HolidaysType(models.Model):
|
||||
holiday_status.leaves_taken = result.get('leaves_taken', 0)
|
||||
holiday_status.remaining_leaves = result.get('remaining_leaves', 0)
|
||||
holiday_status.virtual_remaining_leaves = result.get('virtual_remaining_leaves', 0)
|
||||
holiday_status.virtual_leaves_taken = result.get('virtual_leaves_taken', 0)
|
||||
|
||||
def _compute_group_days_allocation(self):
|
||||
domain = [
|
||||
|
||||
@@ -2,6 +2,7 @@ odoo.define('hr_holidays.dashboard.view_custo', function(require) {
|
||||
'use strict';
|
||||
|
||||
var core = require('web.core');
|
||||
var CalendarPopover = require('web.CalendarPopover');
|
||||
var CalendarController = require("web.CalendarController");
|
||||
var CalendarRenderer = require("web.CalendarRenderer");
|
||||
var CalendarView = require("web.CalendarView");
|
||||
@@ -10,6 +11,18 @@ odoo.define('hr_holidays.dashboard.view_custo', function(require) {
|
||||
var _t = core._t;
|
||||
var QWeb = core.qweb;
|
||||
|
||||
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.display_name = this.event.extendedProps.record.display_name;
|
||||
this.displayFields = [];
|
||||
},
|
||||
});
|
||||
|
||||
var TimeOffCalendarController = CalendarController.extend({
|
||||
events: _.extend({}, CalendarController.prototype.events, {
|
||||
@@ -83,7 +96,32 @@ odoo.define('hr_holidays.dashboard.view_custo', function(require) {
|
||||
});
|
||||
},
|
||||
});
|
||||
var TimeOffCalendarRenderer = CalendarRenderer.extend({
|
||||
|
||||
var TimeOffPopoverRenderer = CalendarRenderer.extend({
|
||||
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;
|
||||
},
|
||||
});
|
||||
|
||||
var TimeOffCalendarRenderer = TimeOffPopoverRenderer.extend({
|
||||
_render: function () {
|
||||
var self = this;
|
||||
return this._super.apply(this, arguments).then(function () {
|
||||
@@ -108,5 +146,15 @@ odoo.define('hr_holidays.dashboard.view_custo', function(require) {
|
||||
}),
|
||||
});
|
||||
|
||||
/**
|
||||
* Calendar shown in the "Everyone" menu
|
||||
*/
|
||||
var TimeOffCalendarAllView = CalendarView.extend({
|
||||
config: _.extend({}, CalendarView.prototype.config, {
|
||||
Renderer: TimeOffPopoverRenderer,
|
||||
}),
|
||||
});
|
||||
|
||||
viewRegistry.add('time_off_calendar', TimeOffCalendarView);
|
||||
viewRegistry.add('time_off_calendar_all', TimeOffCalendarAllView);
|
||||
});
|
||||
|
||||
@@ -13,17 +13,17 @@
|
||||
|
||||
<div class="mt-2">
|
||||
<t t-if="need_allocation">
|
||||
<span t-esc="timeoff[1]['leaves_taken']" class="o_timeoff_big o_timeoff_purple"/> / <span t-esc="timeoff[1]['max_leaves']"/> <t t-if="timeoff[1]['request_unit'] == 'hour'">Hours</t><t t-else="">Days</t>
|
||||
<span t-esc="timeoff[1]['virtual_remaining_leaves']" class="o_timeoff_big o_timeoff_purple"/> / <span t-esc="timeoff[1]['max_leaves']"/> <t t-if="timeoff[1]['request_unit'] == 'hour'">Hours</t><t t-else="">Days</t>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span t-esc="timeoff[1]['leaves_taken']" class="o_timeoff_big o_timeoff_purple"/> <t t-if="timeoff[1]['request_unit'] == 'hour'">Hours</t><t t-else="">Days</t>
|
||||
<span t-esc="timeoff[1]['virtual_leaves_taken']" class="o_timeoff_big o_timeoff_purple"/> <t t-if="timeoff[1]['request_unit'] == 'hour'">Hours</t><t t-else="">Days</t>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<b><span t-esc="timeoff[0]" class="o_timeoff_name"/></b>
|
||||
|
||||
<span class="mb-4" t-if="need_allocation">
|
||||
<span t-attf-class="mr-1 font-weight-bold {{ cl }}" t-esc="timeoff[1]['remaining_leaves']"/><span>remaining</span>
|
||||
<span t-attf-class="mr-1 font-weight-bold {{ cl }}" t-esc="timeoff[1]['virtual_leaves_taken']"/><span>taken</span>
|
||||
<t t-if="timeoff[3]"> (Expire on <span t-esc="moment(timeoff[3]).format('L')"/>)</t>
|
||||
</span>
|
||||
</div>
|
||||
@@ -38,4 +38,41 @@
|
||||
<t t-esc="request"/>
|
||||
</button>
|
||||
</t>
|
||||
|
||||
<t t-name="hr_holidays.calendar.popover.placeholder">
|
||||
<div t-attf-class="o_cw_popover popover card shadow #{typeof color === 'number' ? _.str.sprintf('o_calendar_color_%s', color) : ''}" role="tooltip">
|
||||
<div class="arrow"/>
|
||||
<div class="card-header d-flex justify-content-between py-2 pr-2">
|
||||
<h4 class="popover-header border-0 p-0 pt-1"/>
|
||||
<div class="ml-4">
|
||||
<i t-if="calendarIcon" t-attf-class="fa {{calendarIcon}}"></i>
|
||||
<span class="o_cw_popover_close ml-1"><i class="fa fa-close small"/></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="o_cw_body">
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="hr_holidays.calendar.popover">
|
||||
<div class="o_cw_body">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li t-if="!widget.hideDate and widget.eventDate.date" class="list-group-item">
|
||||
<b class="text-capitalize" t-esc="widget.eventDate.date"/> <small t-if="widget.eventDate.duration"><b t-esc="_.str.sprintf('(%s)', widget.eventDate.duration)"/></small>
|
||||
</li>
|
||||
<li t-if="!widget.hideTime and widget.eventTime.time" class="list-group-item">
|
||||
<b t-esc="widget.eventTime.time"/> <small t-if="widget.eventTime.duration"><b t-esc="_.str.sprintf('(%s)', widget.eventTime.duration)"/></small>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="list-group list-group-flush o_cw_popover_fields_secondary" t-if="widget.display_name">
|
||||
<li class="list-group-item">
|
||||
<span class="o_field_char o_field_widget" t-esc="widget.display_name" />
|
||||
</li>
|
||||
</ul>
|
||||
<div class="card-footer border-top" t-if="widget.canEdit or widget.canDelete">
|
||||
<a t-if="widget.canEdit" href="#" class="btn btn-primary o_cw_popover_edit">Edit</a>
|
||||
<a t-if="widget.canDelete" href="#" class="btn btn-secondary o_cw_popover_delete ml-2">Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
|
||||
@@ -359,6 +359,7 @@
|
||||
<calendar js_class="time_off_calendar" string="Time Off Request" form_view_id="%(hr_holidays.hr_leave_view_form_dashboard)d" event_open_popup="true" date_start="date_from" date_stop="date_to" mode="month" quick_add="False" show_unusual_days="True" color="employee_id" hide_time="True">
|
||||
<field name="display_name"/>
|
||||
<field name="employee_id" filters="1" invisible="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
</calendar>
|
||||
</field>
|
||||
</record>
|
||||
@@ -432,7 +433,7 @@
|
||||
<field name="name">hr.leave.view.calendar</field>
|
||||
<field name="model">hr.leave</field>
|
||||
<field name="arch" type="xml">
|
||||
<calendar string="Time Off Request" event_open_popup="true" date_start="date_from" date_stop="date_to" mode="month" quick_add="False" color="employee_id">
|
||||
<calendar js_class="time_off_calendar_all" string="Time Off Request" event_open_popup="true" date_start="date_from" date_stop="date_to" mode="month" quick_add="False" color="employee_id">
|
||||
<field name="display_name"/>
|
||||
<field name="employee_id" filters="1" invisible="1"/>
|
||||
</calendar>
|
||||
|
||||
Reference in New Issue
Block a user