diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/hr_holidays/report | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/hr_holidays/report')
| -rw-r--r-- | addons/hr_holidays/report/__init__.py | 6 | ||||
| -rw-r--r-- | addons/hr_holidays/report/holidays_summary_report.py | 124 | ||||
| -rw-r--r-- | addons/hr_holidays/report/hr_holidays_reports.xml | 28 | ||||
| -rw-r--r-- | addons/hr_holidays/report/hr_holidays_templates.xml | 82 | ||||
| -rw-r--r-- | addons/hr_holidays/report/hr_leave_report.py | 111 | ||||
| -rw-r--r-- | addons/hr_holidays/report/hr_leave_report_calendar.py | 68 | ||||
| -rw-r--r-- | addons/hr_holidays/report/hr_leave_report_calendar.xml | 40 | ||||
| -rw-r--r-- | addons/hr_holidays/report/hr_leave_reports.xml | 118 |
8 files changed, 577 insertions, 0 deletions
diff --git a/addons/hr_holidays/report/__init__.py b/addons/hr_holidays/report/__init__.py new file mode 100644 index 00000000..c59b1e68 --- /dev/null +++ b/addons/hr_holidays/report/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import holidays_summary_report +from . import hr_leave_report +from . import hr_leave_report_calendar diff --git a/addons/hr_holidays/report/holidays_summary_report.py b/addons/hr_holidays/report/holidays_summary_report.py new file mode 100644 index 00000000..74d41d19 --- /dev/null +++ b/addons/hr_holidays/report/holidays_summary_report.py @@ -0,0 +1,124 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import calendar + +from datetime import timedelta +from dateutil.relativedelta import relativedelta +from odoo import api, fields, models, _ +from odoo.exceptions import UserError + + +class HrHolidaySummaryReport(models.AbstractModel): + _name = 'report.hr_holidays.report_holidayssummary' + _description = 'Holidays Summary Report' + + def _get_header_info(self, start_date, holiday_type): + st_date = fields.Date.from_string(start_date) + return { + 'start_date': fields.Date.to_string(st_date), + 'end_date': fields.Date.to_string(st_date + relativedelta(days=59)), + 'holiday_type': 'Confirmed and Approved' if holiday_type == 'both' else holiday_type + } + + def _date_is_day_off(self, date): + return date.weekday() in (calendar.SATURDAY, calendar.SUNDAY,) + + def _get_day(self, start_date): + res = [] + start_date = fields.Date.from_string(start_date) + for x in range(0, 60): + color = '#ababab' if self._date_is_day_off(start_date) else '' + res.append({'day_str': start_date.strftime('%a'), 'day': start_date.day , 'color': color}) + start_date = start_date + relativedelta(days=1) + return res + + def _get_months(self, start_date): + # it works for geting month name between two dates. + res = [] + start_date = fields.Date.from_string(start_date) + end_date = start_date + relativedelta(days=59) + while start_date <= end_date: + last_date = start_date + relativedelta(day=1, months=+1, days=-1) + if last_date > end_date: + last_date = end_date + month_days = (last_date - start_date).days + 1 + res.append({'month_name': start_date.strftime('%B'), 'days': month_days}) + start_date += relativedelta(day=1, months=+1) + return res + + def _get_leaves_summary(self, start_date, empid, holiday_type): + res = [] + count = 0 + start_date = fields.Date.from_string(start_date) + end_date = start_date + relativedelta(days=59) + for index in range(0, 60): + current = start_date + timedelta(index) + res.append({'day': current.day, 'color': ''}) + if self._date_is_day_off(current) : + res[index]['color'] = '#ababab' + # count and get leave summary details. + holiday_type = ['confirm','validate'] if holiday_type == 'both' else ['confirm'] if holiday_type == 'Confirmed' else ['validate'] + holidays = self.env['hr.leave'].search([ + ('employee_id', '=', empid), ('state', 'in', holiday_type), + ('date_from', '<=', str(end_date)), + ('date_to', '>=', str(start_date)) + ]) + for holiday in holidays: + # Convert date to user timezone, otherwise the report will not be consistent with the + # value displayed in the interface. + date_from = fields.Datetime.from_string(holiday.date_from) + date_from = fields.Datetime.context_timestamp(holiday, date_from).date() + date_to = fields.Datetime.from_string(holiday.date_to) + date_to = fields.Datetime.context_timestamp(holiday, date_to).date() + for index in range(0, ((date_to - date_from).days + 1)): + if date_from >= start_date and date_from <= end_date: + res[(date_from-start_date).days]['color'] = holiday.holiday_status_id.color_name + date_from += timedelta(1) + count += holiday.number_of_days + employee = self.env['hr.employee'].browse(empid) + return {'emp': employee.name, 'display': res, 'sum': count} + + def _get_data_from_report(self, data): + res = [] + Employee = self.env['hr.employee'] + if 'depts' in data: + for department in self.env['hr.department'].browse(data['depts']): + res.append({ + 'dept': department.name, + 'data': [ + self._get_leaves_summary(data['date_from'], emp.id, data['holiday_type']) + for emp in Employee.search([('department_id', '=', department.id)]) + ], + 'color': self._get_day(data['date_from']), + }) + elif 'emp' in data: + res.append({'data': [ + self._get_leaves_summary(data['date_from'], emp.id, data['holiday_type']) + for emp in Employee.browse(data['emp']) + ]}) + return res + + def _get_holidays_status(self): + res = [] + for holiday in self.env['hr.leave.type'].search([]): + res.append({'color': holiday.color_name, 'name': holiday.name}) + return res + + @api.model + def _get_report_values(self, docids, data=None): + if not data.get('form'): + raise UserError(_("Form content is missing, this report cannot be printed.")) + + holidays_report = self.env['ir.actions.report']._get_report_from_name('hr_holidays.report_holidayssummary') + holidays = self.env['hr.leave'].browse(self.ids) + return { + 'doc_ids': self.ids, + 'doc_model': holidays_report.model, + 'docs': holidays, + 'get_header_info': self._get_header_info(data['form']['date_from'], data['form']['holiday_type']), + 'get_day': self._get_day(data['form']['date_from']), + 'get_months': self._get_months(data['form']['date_from']), + 'get_data_from_report': self._get_data_from_report(data['form']), + 'get_holidays_status': self._get_holidays_status(), + } diff --git a/addons/hr_holidays/report/hr_holidays_reports.xml b/addons/hr_holidays/report/hr_holidays_reports.xml new file mode 100644 index 00000000..fbec8363 --- /dev/null +++ b/addons/hr_holidays/report/hr_holidays_reports.xml @@ -0,0 +1,28 @@ +<?xml version="1.0"?> +<odoo> + + <record id="action_report_holidayssummary" model="ir.actions.report"> + <field name="name">Time Off Summary</field> + <field name="model">hr.holidays.summary.dept</field> + <field name="report_type">qweb-pdf</field> + <field name="report_name">hr_holidays.report_holidayssummary</field> + <field name="report_file">hr_holidays.report_holidayssummary</field> + </record> + + <record id="action_report_holidayssummary" model="ir.actions.report"> + <field name="paperformat_id" ref="hr_holidays.paperformat_hrsummary"/> + </record> + + <record id="action_report_holidayssummary2" model="ir.actions.report"> + <field name="name">Time Off Summary</field> + <field name="model">hr.leave.allocation</field> + <field name="report_type">qweb-pdf</field> + <field name="report_name">hr_holidays.report_holidayssummary</field> + <field name="report_file">hr_holidays.report_holidayssummary</field> + </record> + + <record id="action_report_holidayssummary" model="ir.actions.report"> + <field name="paperformat_id" ref="hr_holidays.paperformat_hrsummary"/> + </record> + +</odoo> diff --git a/addons/hr_holidays/report/hr_holidays_templates.xml b/addons/hr_holidays/report/hr_holidays_templates.xml new file mode 100644 index 00000000..dc2d46b8 --- /dev/null +++ b/addons/hr_holidays/report/hr_holidays_templates.xml @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + +<template id="report_holidayssummary"> + <t t-call="web.html_container"> + <t t-call="web.internal_layout"> + <div class="page"> + <h3 class="mb32">Time Off Summary</h3> + <t t-set="info" t-value="get_header_info"/> + <h3 class="text-center mb32"> + Analyze from <u><t t-esc="info['start_date']"/></u> to <u><t t-esc="info['end_date']"/></u> of the <u><t t-esc="info['holiday_type']"/></u> Time Off. + </h3> + + <table class="table table-bordered mb32" style="table-layout:auto"> + <thead> + <tr> + <th>Month</th> + <t t-foreach="get_months" t-as="month"> + <th class="text-center" colspan=<t t-esc="month['days']"/>><t t-esc="month['month_name']"/></th> + </t> + <th/> + </tr> + <tr> + <td rowspan="2"> + <strong>Departments and Employees</strong> + </td> + <t t-foreach="get_day" t-as="day"> + <td class="text-center oe_leftfit oe_rightfit" style="background-color:<t t-esc="day['color']"/>!important; font-size: 8px; min-width: 18px"> <t t-esc="day['day_str']"/></td> + </t> + <td/> + </tr> + <tr> + <t t-foreach="get_day" t-as="day"> + <td class="text-center oe_leftfit oe_rightfit" style="background-color:<t t-esc="day['color']"/>!important; font-size: 10px" > <t t-esc="day['day']"/></td> + </t> + <td class="text-center">Sum</td> + </tr> + </thead> + <tbody> + <t t-foreach="get_data_from_report" t-as="obj"> + <tr t-if="'dept' in obj"> + <td style="background-color:#ababab"> + <strong><t t-esc="obj['dept']"/></strong> + </td> + <t t-foreach="obj['color']" t-as="c"> + <td style=background-color:<t t-esc="c['color']"/> !important/> + </t> + <td/> + </tr> + <tr t-foreach="obj['data']" t-as="emp"> + <td><t t-esc="emp['emp']"/></td> + <t t-foreach="emp['display']" t-as="details"> + <td style=background-color:<t t-esc="details['color']"/> !important /> + </t> + <td class="text-center"><strong><t t-esc="emp['sum']"/></strong></td> + </tr> + </t> + </tbody> + </table> + + <div class="col-3 offset-5 mt32"> + <table class="table table-bordered"> + <thead> + <tr> + <th class="col-1">Color</th> + <th class="text-center">Time Off Type</th> + </tr> + </thead> + <tbody> + <tr t-foreach="get_holidays_status" t-as="status"> + <td style=background-color:<t t-esc="status['color']"/>!important ></td> + <td><t t-esc="status['name']"/></td> + </tr> + </tbody> + </table> + </div> + </div> + </t> + </t> +</template> + +</odoo> diff --git a/addons/hr_holidays/report/hr_leave_report.py b/addons/hr_holidays/report/hr_leave_report.py new file mode 100644 index 00000000..3ea1f0e7 --- /dev/null +++ b/addons/hr_holidays/report/hr_leave_report.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models, tools, exceptions, _ +from odoo.osv import expression + + +class LeaveReport(models.Model): + _name = "hr.leave.report" + _description = 'Time Off Summary / Report' + _auto = False + _order = "date_from DESC, employee_id" + + employee_id = fields.Many2one('hr.employee', string="Employee", readonly=True) + name = fields.Char('Description', readonly=True) + number_of_days = fields.Float('Number of Days', readonly=True) + leave_type = fields.Selection([ + ('allocation', 'Allocation'), + ('request', 'Time Off') + ], string='Request Type', readonly=True) + department_id = fields.Many2one('hr.department', string='Department', readonly=True) + category_id = fields.Many2one('hr.employee.category', string='Employee Tag', readonly=True) + holiday_status_id = fields.Many2one("hr.leave.type", string="Leave Type", readonly=True) + state = fields.Selection([ + ('draft', 'To Submit'), + ('cancel', 'Cancelled'), + ('confirm', 'To Approve'), + ('refuse', 'Refused'), + ('validate1', 'Second Approval'), + ('validate', 'Approved') + ], string='Status', readonly=True) + holiday_type = fields.Selection([ + ('employee', 'By Employee'), + ('category', 'By Employee Tag') + ], string='Allocation Mode', readonly=True) + date_from = fields.Datetime('Start Date', readonly=True) + date_to = fields.Datetime('End Date', readonly=True) + payslip_status = fields.Boolean('Reported in last payslips', readonly=True) + + def init(self): + tools.drop_view_if_exists(self._cr, 'hr_leave_report') + + self._cr.execute(""" + CREATE or REPLACE view hr_leave_report as ( + SELECT row_number() over(ORDER BY leaves.employee_id) as id, + leaves.employee_id as employee_id, leaves.name as name, + leaves.number_of_days as number_of_days, leaves.leave_type as leave_type, + leaves.category_id as category_id, leaves.department_id as department_id, + leaves.holiday_status_id as holiday_status_id, leaves.state as state, + leaves.holiday_type as holiday_type, leaves.date_from as date_from, + leaves.date_to as date_to, leaves.payslip_status as payslip_status + from (select + allocation.employee_id as employee_id, + allocation.private_name as name, + allocation.number_of_days as number_of_days, + allocation.category_id as category_id, + allocation.department_id as department_id, + allocation.holiday_status_id as holiday_status_id, + allocation.state as state, + allocation.holiday_type, + null as date_from, + null as date_to, + FALSE as payslip_status, + 'allocation' as leave_type + from hr_leave_allocation as allocation + union all select + request.employee_id as employee_id, + request.private_name as name, + (request.number_of_days * -1) as number_of_days, + request.category_id as category_id, + request.department_id as department_id, + request.holiday_status_id as holiday_status_id, + request.state as state, + request.holiday_type, + request.date_from as date_from, + request.date_to as date_to, + request.payslip_status as payslip_status, + 'request' as leave_type + from hr_leave as request) leaves + ); + """) + + @api.model + def action_time_off_analysis(self): + domain = [('holiday_type', '=', 'employee')] + + if self.env.context.get('active_ids'): + domain = expression.AND([ + domain, + [('employee_id', 'in', self.env.context.get('active_ids', []))] + ]) + + return { + 'name': _('Time Off Analysis'), + 'type': 'ir.actions.act_window', + 'res_model': 'hr.leave.report', + 'view_mode': 'tree,pivot,form', + 'search_view_id': self.env.ref('hr_holidays.view_hr_holidays_filter_report').id, + 'domain': domain, + 'context': { + 'search_default_group_type': True, + 'search_default_year': True, + 'search_default_validated': True, + } + } + + @api.model + def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True): + if not self.user_has_groups('hr_holidays.group_hr_holidays_user') and 'name' in groupby: + raise exceptions.UserError(_('Such grouping is not allowed.')) + return super(LeaveReport, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) diff --git a/addons/hr_holidays/report/hr_leave_report_calendar.py b/addons/hr_holidays/report/hr_leave_report_calendar.py new file mode 100644 index 00000000..0a5b45db --- /dev/null +++ b/addons/hr_holidays/report/hr_leave_report_calendar.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models, tools, SUPERUSER_ID + +from odoo.addons.base.models.res_partner import _tz_get + + +class LeaveReportCalendar(models.Model): + _name = "hr.leave.report.calendar" + _description = 'Time Off Calendar' + _auto = False + _order = "start_datetime DESC, employee_id" + + name = fields.Char(string='Name', readonly=True) + start_datetime = fields.Datetime(string='From', readonly=True) + stop_datetime = fields.Datetime(string='To', readonly=True) + tz = fields.Selection(_tz_get, string="Timezone", readonly=True) + duration = fields.Float(string='Duration', readonly=True) + employee_id = fields.Many2one('hr.employee', readonly=True) + company_id = fields.Many2one('res.company', readonly=True) + state = fields.Selection([ + ('draft', 'To Submit'), + ('cancel', 'Cancelled'), # YTI This state seems to be unused. To remove + ('confirm', 'To Approve'), + ('refuse', 'Refused'), + ('validate1', 'Second Approval'), + ('validate', 'Approved') + ], readonly=True) + + def init(self): + tools.drop_view_if_exists(self._cr, 'hr_leave_report_calendar') + self._cr.execute("""CREATE OR REPLACE VIEW hr_leave_report_calendar AS + (SELECT + row_number() OVER() AS id, + CONCAT(em.name, ': ', hl.duration_display) AS name, + hl.date_from AS start_datetime, + hl.date_to AS stop_datetime, + hl.employee_id AS employee_id, + hl.state AS state, + em.company_id AS company_id, + CASE + WHEN hl.holiday_type = 'employee' THEN rr.tz + ELSE %s + END AS tz + FROM hr_leave hl + LEFT JOIN hr_employee em + ON em.id = hl.employee_id + LEFT JOIN resource_resource rr + ON rr.id = em.resource_id + WHERE + hl.state IN ('confirm', 'validate', 'validate1') + ORDER BY id); + """, [self.env.company.resource_calendar_id.tz or self.env.user.tz or 'UTC']) + + def _read(self, fields): + res = super()._read(fields) + if self.env.context.get('hide_employee_name') and 'employee_id' in self.env.context.get('group_by', []): + name_field = self._fields['name'] + for record in self.with_user(SUPERUSER_ID): + self.env.cache.set(record, name_field, record.name.split(':')[-1].strip()) + return res + + @api.model + def get_unusual_days(self, date_from, date_to=None): + # Checking the calendar directly allows to not grey out the leaves taken + # by the employee + return self.env['hr.leave'].get_unusual_days(date_from, date_to=date_to) diff --git a/addons/hr_holidays/report/hr_leave_report_calendar.xml b/addons/hr_holidays/report/hr_leave_report_calendar.xml new file mode 100644 index 00000000..c7f8a78e --- /dev/null +++ b/addons/hr_holidays/report/hr_leave_report_calendar.xml @@ -0,0 +1,40 @@ +<?xml version='1.0' encoding='UTF-8' ?> +<odoo> + <record id="action_hr_holidays_dashboard" model="ir.actions.act_window"> + <field name="name">All Time Off</field> + <field name="res_model">hr.leave.report.calendar</field> + <field name="view_mode">calendar</field> + <!-- YTI : Ecrabouille explicitely those fields, as this is deployed on + a stable release. --> + <field name="view_id"/> + <field name="search_view_id"/> + <field name="domain">[('employee_id.active','=',True)]</field> + <field name="context">{'hide_employee_name': 1}</field> + </record> + + <record id="hr_leave_report_calendar_view" model="ir.ui.view"> + <field name="name">hr.leave.report.calendar.view</field> + <field name="model">hr.leave.report.calendar</field> + <field name="arch" type="xml"> + <calendar string="Time Off" date_start="start_datetime" date_stop="stop_datetime" mode="month" quick_add="False" color="employee_id" event_open_popup="True" js_class="time_off_calendar_all" show_unusual_days="True"> + <field name="name"/> + <field name="employee_id" filters="1" invisible="1"/> + </calendar> + </field> + </record> + + <record id="hr_leave_report_calendar_view_form" model="ir.ui.view"> + <field name="name">hr.leave.report.calendar.view.form</field> + <field name="model">hr.leave.report.calendar</field> + <field name="arch" type="xml"> + <form string="Time Off"> + <group> + <field name="name"/> + <field name="start_datetime"/> + <field name="stop_datetime"/> + <field name="employee_id" /> + </group> + </form> + </field> + </record> +</odoo> diff --git a/addons/hr_holidays/report/hr_leave_reports.xml b/addons/hr_holidays/report/hr_leave_reports.xml new file mode 100644 index 00000000..efe3f81b --- /dev/null +++ b/addons/hr_holidays/report/hr_leave_reports.xml @@ -0,0 +1,118 @@ +<?xml version="1.0"?> +<odoo> + + <record id="view_hr_holidays_filter_report" model="ir.ui.view"> + <field name="name">hr.holidays.filter</field> + <field name="model">hr.leave.report</field> + <field name="arch" type="xml"> + <search string="Search Time Off"> + <field name="name"/> + <filter domain="[('state','in',('confirm','validate1'))]" string="To Approve" name="approve"/> + <filter string="Approved Requests" domain="[('state', '=', 'validate')]" name="validated"/> + <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 Team Time Off" domain="[('employee_id.parent_id.user_id', '=', uid)]" groups="hr_holidays.group_hr_holidays_manager" help="Time Off of Your Team Member"/> + <separator/> + <filter name="year" string="Current Year" + domain="[('holiday_status_id.active', '=', True)]" help="Active Time Off"/> + <separator/> + <filter string="My Requests" name="my_leaves" domain="[('employee_id.user_id', '=', uid)]"/> + <separator/> + <field name="employee_id"/> + <field name="department_id" operator="child_of"/> + <field name="holiday_status_id"/> + <group expand="0" string="Group By"> + <filter name="group_employee" string="Employee" context="{'group_by':'employee_id'}"/> + <filter name="group_type" string="Type" context="{'group_by':'holiday_status_id'}"/> + <separator/> + <filter name="group_date_from" string="Start Date" context="{'group_by':'date_from'}"/> + </group> + </search> + </field> + </record> + + <record id="hr_leave_report_tree" model="ir.ui.view"> + <field name="name">report.hr.holidays.report.leave_all.tree</field> + <field name="model">hr.leave.report</field> + <field name="arch" type="xml"> + <tree create="0" edit="0" delete="0"> + <field name="employee_id"/> + <field name="number_of_days" string="Number of Days" sum="Remaining Days"/> + <field name="leave_type"/> + <field name="date_from"/> + <field name="date_to"/> + <field name="state"/> + <field name="name"/> + </tree> + </field> + </record> + + <!-- TODO: See if we need to keep this --> + <record id="hr_leave_report_kanban" model="ir.ui.view"> + <field name="name">report.hr.holidays.report.leave_all.kanban</field> + <field name="model">hr.leave.report</field> + <field name="arch" type="xml"> + <kanban class="o_kanban_mobile" create="0"> + <field name="employee_id"/> + <field name="date_from"/> + <field name="date_to"/> + <field name="name"/> + <field name="number_of_days"/> + <templates> + <t t-name="kanban-box"> + <div t-attf-class="oe_kanban_global_click"> + <div> + <span> + <img t-att-src="kanban_image('hr.employee', 'image_128', record.employee_id.raw_value)" t-att-title="record.employee_id.value" t-att-alt="record.employee_id.value" class="oe_kanban_avatar o_image_40_cover float-left mr4"/> + </span> + <span> + <div> + <strong class="o_kanban_record_title"><t t-esc="record.employee_id.value"/></strong> + <span class="float-right"> + <field name="state" widget="label_selection" options="{'classes': {'draft': 'default', 'validate': 'success','confirm': 'default', 'cancel': 'danger'}}"/> + </span> + </div> + <div class="text-muted o_kanban_record_subtitle"> + <t t-esc="record.name.value"/> + </div> + </span> + </div> + <hr class="mt4 mb8"/> + <div class="o_kanban_record_bottom mt8 mb4"> + <div t-attf-class="oe_kanban_bottom_left #{record.date_from.value ? 'mt8 mb4': ''}"> + <table class="text-right" t-if="record.date_from.value"> + <tr> + <td style="padding-bottom:4px"><small class="text-muted">from</small></td> + <td style="padding:0 0 4px 4px"><t t-esc="record.date_from.value"/></td> + </tr> + <tr> + <td><small class="text-muted">to</small></td> + <td style="padding-left:4px"><t t-esc="record.date_to.value"/></td> + </tr> + </table> + </div> + <div t-attf-class="oe_kanban_bottom_right #{record.date_from.value ? 'mt8': ''}"> + <span class="badge badge-pill"><t t-esc="record.number_of_days.value"/> days</span> + </div> + </div> + </div> + </t> + </templates> + </kanban> + </field> + </record> + + <record id="act_hr_employee_holiday_request" model="ir.actions.server"> + <field name="name">Time off Analysis</field> + <field name="model_id" ref="hr_holidays.model_hr_leave_report"/> + <field name="binding_model_id" ref="hr.model_hr_employee"/> + <field name="state">code</field> + <field name="groups_id" eval="[(4, ref('base.group_user'))]"/> + <field name="code"> + action = model.action_time_off_analysis() + </field> + </record> + +</odoo> |
