[IMP] hr_department: new kanban view for HR Departments.
hr add a simple kanban view that is updated by the various hr modules. Each module adds statistics and links in the kanban vignette, either in a to do or to approve column. The department kanban view can be seen as a small dashboard to have the main data about the department displayed. Links allow the HR manager to be redirected towards the various things to do or to approve in its department.
This commit is contained in:
@@ -42,7 +42,19 @@ You can manage:
|
||||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'website': 'https://www.odoo.com/page/employees',
|
||||
'depends': ['base_setup', 'mail', 'resource', 'board', 'web_tip'],
|
||||
'images': [
|
||||
'images/hr_department.jpeg',
|
||||
'images/hr_employee.jpeg',
|
||||
'images/hr_job_position.jpeg',
|
||||
'static/src/img/default_image.png',
|
||||
],
|
||||
'depends': [
|
||||
'base_setup',
|
||||
'mail',
|
||||
'resource',
|
||||
'board',
|
||||
'web_kanban',
|
||||
],
|
||||
'data': [
|
||||
'security/hr_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
@@ -64,5 +76,5 @@ You can manage:
|
||||
'installable': True,
|
||||
'application': True,
|
||||
'auto_install': False,
|
||||
'qweb': [ 'static/src/xml/suggestions.xml' ],
|
||||
'qweb': ['static/src/xml/suggestions.xml'],
|
||||
}
|
||||
|
||||
+5
-2
@@ -391,6 +391,7 @@ class hr_department(osv.osv):
|
||||
'member_ids': fields.one2many('hr.employee', 'department_id', 'Members', readonly=True),
|
||||
'jobs_ids': fields.one2many('hr.job', 'department_id', 'Jobs'),
|
||||
'note': fields.text('Note'),
|
||||
'color': fields.integer('Color Index'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
@@ -414,10 +415,12 @@ class hr_department(osv.osv):
|
||||
]
|
||||
|
||||
def name_get(self, cr, uid, ids, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
if not ids:
|
||||
return []
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
if context is None:
|
||||
context = {}
|
||||
reads = self.read(cr, uid, ids, ['name','parent_id'], context=context)
|
||||
res = []
|
||||
for record in reads:
|
||||
|
||||
+85
-16
@@ -45,14 +45,14 @@
|
||||
<page string="Public Information">
|
||||
<group>
|
||||
<group string="Contact Information">
|
||||
<field name="address_id" on_change="onchange_address_id(address_id)"
|
||||
context="{'show_address': 1}"
|
||||
<field name="address_id" on_change="onchange_address_id(address_id)"
|
||||
context="{'show_address': 1}"
|
||||
options='{"always_reload": True, "highlight_first_line": True}'/>
|
||||
<field name="mobile_phone"/>
|
||||
<field name="work_location"/>
|
||||
</group>
|
||||
<group string="Position">
|
||||
<field name="department_id" on_change="onchange_department_id(department_id)"/>
|
||||
<field name="department_id" groups="hr.group_multi_departments" on_change="onchange_department_id(department_id)"/>
|
||||
<field name="job_id"/>
|
||||
<field name="parent_id"/>
|
||||
<field name="coach_id"/>
|
||||
@@ -75,8 +75,8 @@
|
||||
<field name="otherid" groups="base.group_hr_user"/>
|
||||
</group>
|
||||
<group string="Contact Information">
|
||||
<field name="address_home_id"
|
||||
context="{'show_address': 1}"
|
||||
<field name="address_home_id"
|
||||
context="{'show_address': 1}"
|
||||
options='{"always_reload": True, "highlight_first_line": True}'/>
|
||||
</group>
|
||||
<group string="Status">
|
||||
@@ -114,7 +114,7 @@
|
||||
<field name="work_phone"/>
|
||||
<field name="work_email"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<field name="department_id"/>
|
||||
<field name="department_id" groups="hr.group_multi_departments"/>
|
||||
<field name="job_id"/>
|
||||
<field name="parent_id"/>
|
||||
<field name="coach_id" invisible="1"/>
|
||||
@@ -129,14 +129,14 @@
|
||||
<field name="arch" type="xml">
|
||||
<search string="Employees">
|
||||
<field name="name" string="Employees" filter_domain="['|',('work_email','ilike',self),('name','ilike',self)]"/>
|
||||
<field name="department_id" />
|
||||
<field name="department_id" groups="hr.group_multi_departments"/>
|
||||
<field name="category_ids" groups="base.group_hr_user"/>
|
||||
<field name="job_id" />
|
||||
<filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="Manager" icon="terp-personal" domain="[]" context="{'group_by':'parent_id'}"/>
|
||||
<filter string="Coach" icon="terp-personal" domain="[]" context="{'group_by':'coach_id'}"/>
|
||||
<filter string="Department" icon="terp-personal+" domain="[]" context="{'group_by':'department_id'}"/>
|
||||
<filter string="Department" domain="[]" context="{'group_by':'department_id'}" groups="hr.group_multi_departments"/>
|
||||
<filter string="Job" icon="terp-gtk-select-all" domain="[]" context="{'group_by':'job_id'}"/>
|
||||
<filter string="Company" icon="terp-go-home" domain="[]" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
@@ -181,7 +181,7 @@
|
||||
<t t-raw="record.message_summary.raw_value"/>
|
||||
<span title='Messages'><i class='fa fa-comments'/><t t-esc="record.message_ids.raw_value.length"/></span>
|
||||
<span title='Followers'><i class='fa fa-users'/><t t-esc="record.message_follower_ids.raw_value.length"/></span>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="oe_followers" groups="base.group_user">
|
||||
<button t-if="record.message_is_follower.raw_value" name="action_unfollow" type="object" class="oe_follower oe_following">
|
||||
@@ -251,7 +251,7 @@
|
||||
<field name="work_phone"/>
|
||||
<field name="work_email"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<field name="department_id"/>
|
||||
<field name="department_id" groups="hr.group_multi_departments"/>
|
||||
<field name="job_id"/>
|
||||
<field name="coach_id" invisible="1"/>
|
||||
<field name="parent_id" invisible="1"/>
|
||||
@@ -358,9 +358,8 @@
|
||||
</div>
|
||||
<div class="oe_right" name="buttons"/>
|
||||
<group name="employee_data">
|
||||
<field name="department_id" class="oe_inline"/>
|
||||
<field name="department_id" groups="hr.group_multi_departments" class="oe_inline"/>
|
||||
<field name="no_of_recruitment" class="oe_inline" />
|
||||
|
||||
</group>
|
||||
<div attrs="{'invisible': [('state', '!=', 'recruit')]}">
|
||||
<label for="description"/>
|
||||
@@ -385,7 +384,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Job" fonts="bold:message_unread==True">
|
||||
<field name="name"/>
|
||||
<field name="department_id"/>
|
||||
<field name="department_id" groups="hr.group_multi_departments"/>
|
||||
<field name="no_of_employee"/>
|
||||
<field name="no_of_recruitment"/>
|
||||
<field name="expected_employees"/>
|
||||
@@ -404,11 +403,11 @@
|
||||
<field name="name" string="Job"/>
|
||||
<filter domain="[('state','=','open')]" string="In Position"/>
|
||||
<filter domain="[('state','=','recruit')]" string="In Recruitment" name="in_recruitment"/>
|
||||
<field name="department_id"/>
|
||||
<field name="department_id" groups="hr.group_multi_departments"/>
|
||||
<separator/>
|
||||
<filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="Department" domain="[]" context="{'group_by':'department_id'}"/>
|
||||
<filter string="Department" domain="[]" context="{'group_by':'department_id'}" groups="hr.group_multi_departments"/>
|
||||
<filter string="Status" domain="[]" context="{'group_by':'state'}"/>
|
||||
<filter string="Company" domain="[]" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
@@ -441,6 +440,18 @@
|
||||
|
||||
<menuitem name="Recruitment" id="base.menu_crm_case_job_req_main" parent="menu_hr_root" groups="base.group_hr_user"/>
|
||||
|
||||
<record model="ir.actions.act_window" id="act_employee_from_department">
|
||||
<field name="name">Employees</field>
|
||||
<field name="res_model">hr.employee</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">kanban,form,tree</field>
|
||||
<field name="search_view_id" ref="view_employee_filter"/>
|
||||
<field name="context">{
|
||||
"search_default_department_id": [active_id],
|
||||
"default_department_id": active_id}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- hr.department -->
|
||||
<record id="view_department_form" model="ir.ui.view">
|
||||
<field name="name">hr.department.form</field>
|
||||
@@ -474,6 +485,57 @@
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_department_view_kanban" model="ir.ui.view" >
|
||||
<field name="name">hr.department.kanban</field>
|
||||
<field name="model">hr.department</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban class="oe_background_grey">
|
||||
<field name="name"/>
|
||||
<field name="manager_id"/>
|
||||
<field name="color"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_card oe_kanban_global_click oe_kanban_department">
|
||||
<div class="oe_dropdown_toggle oe_dropdown_kanban">
|
||||
<i class="fa fa-bars fa-lg"/>
|
||||
<ul class="oe_dropdown_menu">
|
||||
<li t-if="widget.view.is_action_enabled('edit')"><a type="edit">Department Settings</a></li>
|
||||
<li t-if="widget.view.is_action_enabled('delete')"><a type="delete">Delete</a></li>
|
||||
<li t-if="widget.view.is_action_enabled('edit')"><ul class="oe_kanban_colorpicker" data-field="color"/></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="oe_kanban_content container">
|
||||
<div class="row">
|
||||
<a type="action" name="%(act_employee_from_department)d"/>
|
||||
<t t-if="record.manager_id.raw_value">
|
||||
<img t-att-src="kanban_image('hr.employee', 'image_small', record.manager_id.raw_value[0])" t-att-title="record.manager_id.value" class="oe_avatar oe_kanban_avatar_smallbox pull-right"/>
|
||||
</t>
|
||||
<t t-if="record.manager_id.raw_value === false">
|
||||
<img t-att-src='_s + "/base/static/src/img/avatar.png"' title="No manager" class="oe_avatar oe_kanban_avatar_smallbox pull-right"/>
|
||||
</t>
|
||||
<h3 class="text-center oe_kanban_ellipsis"><field name="name"/></h3>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-xs-6 oe_form_invisible" name="to_approve">
|
||||
<strong>To Approve</strong>
|
||||
</div>
|
||||
<div class="col-md-6 col-xs-6 oe_form_invisible" name="to_do">
|
||||
<strong>To Do</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div name="gauge_to_approve" class="col-md-6 col-xs-6 oe_form_invisible"/>
|
||||
<div name="gauge_to_do" class="col-md-6 col-xs-6 oe_form_invisible"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oe_clear"/>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_department_filter" model="ir.ui.view">
|
||||
<field name="name">Departments</field>
|
||||
<field name="model">hr.department</field>
|
||||
@@ -489,6 +551,7 @@
|
||||
<field name="name">Departments</field>
|
||||
<field name="res_model">hr.department</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">kanban,tree,form</field>
|
||||
<field name="search_view_id" ref="view_department_filter"/>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
@@ -500,7 +563,13 @@
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem action="open_module_tree_department" id="menu_hr_department_tree" parent="hr.menu_hr_configuration_employees" sequence="2" groups="base.group_hr_manager,base.group_hr_user"/>
|
||||
|
||||
<menuitem
|
||||
action="open_module_tree_department"
|
||||
id="menu_hr_department_tree"
|
||||
parent="menu_hr_main"
|
||||
sequence="1"
|
||||
groups="group_multi_departments"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -50,6 +50,10 @@ class hr_config_settings(osv.osv_memory):
|
||||
help ="""This installs the module hr_payroll."""),
|
||||
'module_website_hr_recruitment': fields.boolean('Publish jobs on your website',
|
||||
help ="""This installs the module website_hr_recruitment"""),
|
||||
'group_multi_departments': fields.boolean(
|
||||
"Manage employees by department",
|
||||
implied_group='hr.group_multi_departments', group="base.group_hr_user",
|
||||
help="""Allows you to manage employees by department."""),
|
||||
}
|
||||
|
||||
def onchange_hr_timesheet(self, cr, uid, ids, timesheet, context=None):
|
||||
|
||||
@@ -60,6 +60,10 @@
|
||||
<field name="module_hr_gamification" class="oe_inline"/>
|
||||
<label for="module_hr_gamification"/>
|
||||
</div>
|
||||
<div>
|
||||
<field name="group_multi_departments" class="oe_inline"/>
|
||||
<label for="group_multi_departments"/>
|
||||
</div>
|
||||
</div>
|
||||
</group>
|
||||
<group name="timesheet_grp">
|
||||
|
||||
@@ -20,6 +20,11 @@
|
||||
<field name="users" eval="[(4, ref('base.user_root'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="group_multi_departments" model="res.groups">
|
||||
<field name="name">Manage employees by department</field>
|
||||
<field name="category_id" ref="base.module_category_hidden"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
<data noupdate="1">
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
openerp.hr = function(openerp) {
|
||||
"use strict";
|
||||
|
||||
openerp.web_kanban.KanbanRecord.include({
|
||||
on_card_clicked: function() {
|
||||
if (this.view.dataset.model === 'hr.department') {
|
||||
this.$('.oe_kanban_department .oe_kanban_content a').first().click();
|
||||
} else {
|
||||
this._super.apply(this, arguments);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
.openerp {
|
||||
.oe_kanban_view .oe_kanban_department {
|
||||
width: 365px;
|
||||
.container{
|
||||
width: inherit;
|
||||
}
|
||||
.oe_kanban_content div:first-child{
|
||||
margin-right: 0px
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,9 @@
|
||||
<template id="assets_backend" name="hr assets" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<link rel="stylesheet" href="/hr/static/src/css/hr.css"/>
|
||||
<link rel="stylesheet" href="/hr/static/src/less/hr_department.less"/>
|
||||
<script type="text/javascript" src="/hr/static/src/js/suggestions.js"></script>
|
||||
<script type="text/javascript" src="/hr/static/src/js/hr.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
</data>
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
<field name="date_end"/>
|
||||
<field name="working_hours"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="department_id" groups="hr.group_multi_departments"/>
|
||||
<field name="state"/>
|
||||
<filter string="To Renew" name="to_renew" domain="[('state', '=', 'pending')]"/>
|
||||
<separator />
|
||||
@@ -96,7 +96,7 @@
|
||||
<field name="job_id"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="department_id"/>
|
||||
<field name="department_id" groups="hr.group_multi_departments"/>
|
||||
<field name="type_id"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
@@ -19,5 +19,6 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import hr_department
|
||||
import hr_evaluation
|
||||
import report
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from openerp import api, fields, models
|
||||
|
||||
|
||||
class hr_department(models.Model):
|
||||
_inherit = 'hr.department'
|
||||
|
||||
@api.multi
|
||||
def _compute_interview_request(self):
|
||||
Interview = self.env['hr.evaluation.interview']
|
||||
for department in self:
|
||||
department.interview_request_count = Interview.search_count([
|
||||
('user_to_review_id.department_id', '=', department.id),
|
||||
('state', '=', 'waiting_answer')
|
||||
])
|
||||
|
||||
@api.multi
|
||||
def _compute_appraisal_to_start(self):
|
||||
Evaluation = self.env['hr_evaluation.evaluation']
|
||||
for department in self:
|
||||
department.appraisal_to_start_count = Evaluation.search_count([
|
||||
('employee_id.department_id', '=', department.id),
|
||||
('state', '=', 'draft')
|
||||
])
|
||||
|
||||
appraisal_to_start_count = fields.Integer(
|
||||
compute='_compute_appraisal_to_start', string='Appraisal to Start')
|
||||
interview_request_count = fields.Integer(
|
||||
compute='_compute_interview_request', string='Interview Request')
|
||||
@@ -147,7 +147,7 @@
|
||||
</group>
|
||||
</xpath>
|
||||
<xpath expr="//div[@name='button_box']" position="inside">
|
||||
<button name="%(act_hr_employee_2_hr__evaluation_interview)d"
|
||||
<button name="%(act_hr_employee_2_hr__evaluation_interview)d"
|
||||
class="oe_stat_button"
|
||||
icon="fa-sitemap"
|
||||
type="action">
|
||||
@@ -227,6 +227,7 @@
|
||||
<field name="date"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="plan_id"/>
|
||||
<field name="state"/>
|
||||
<filter icon="terp-check" string="Pending" domain="[('state','=','wait')]" help="Appraisal that are in Plan In Progress state"/>
|
||||
<filter icon="terp-camera_test" string="In progress" domain="[('state','=','progress')]" help="Appraisal that are in waiting appreciation state"/>
|
||||
<separator/>
|
||||
@@ -337,6 +338,7 @@
|
||||
<field name="user_to_review_id"/>
|
||||
<field name="user_id" string="Interviewer"/>
|
||||
<field name="deadline"/>
|
||||
<field name="state"/>
|
||||
<filter icon="terp-gtk-go-back-rtl" string="To Do" name="todo" domain="[('state','=','waiting_answer')]"/>
|
||||
<separator/>
|
||||
<filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
@@ -413,5 +415,55 @@
|
||||
'default_body': 'Hello,\n\nKindly post your response for the survey interview.\n\nThanks',
|
||||
'default_subject': 'Reminder to fill up Survey'}"/>
|
||||
|
||||
<record id="hr_evaluation_interview_action_from_department" model="ir.actions.act_window">
|
||||
<field name="name">Interview Requests</field>
|
||||
<field name="res_model">hr.evaluation.interview</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" eval="False"/>
|
||||
<field name="context">{'search_default_state': 'waiting_answer'}</field>
|
||||
<field name="domain">[('user_to_review_id.department_id', '=', active_id)]</field>
|
||||
<field name="search_view_id" ref="view_hr_evaluation_interview_search"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_appraisal_action_from_department" model="ir.actions.act_window">
|
||||
<field name="name">Appraisal to start</field>
|
||||
<field name="res_model">hr_evaluation.evaluation</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="hr_evaluation.evaluation_search"/>
|
||||
<field name="context">{'search_default_state': 'draft'}</field>
|
||||
<field name="domain">[('employee_id.department_id', '=', active_id)]</field>
|
||||
</record>
|
||||
|
||||
<!--Hr Department Inherit Kanban view-->
|
||||
<record id="hr_department_view_kanban" model="ir.ui.view">
|
||||
<field name="name">hr.department.kanban.inherit</field>
|
||||
<field name="model">hr.department</field>
|
||||
<field name="inherit_id" ref="hr.hr_department_view_kanban"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<xpath expr="//templates" position="before">
|
||||
<field name="appraisal_to_start_count"/>
|
||||
<field name="interview_request_count"/>
|
||||
</xpath>
|
||||
<xpath expr="//div[@name='to_do']" position="attributes">
|
||||
<attribute name="class">col-md-6 col-xs-6</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//div[@name='to_do']" position="inside">
|
||||
<div>
|
||||
<a name="%(hr_evaluation_interview_action_from_department)d" type="action">
|
||||
<t t-esc="record.interview_request_count.raw_value or 0"/> Interview Requests
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<a name="%(hr_appraisal_action_from_department)d" type="action">
|
||||
<t t-esc="record.appraisal_to_start_count.raw_value or 0"/> Appraisal to Start
|
||||
</a>
|
||||
</div>
|
||||
</xpath>
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -19,5 +19,6 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import hr_department
|
||||
import hr_expense
|
||||
import report
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from openerp import api, fields, models
|
||||
|
||||
|
||||
class hr_department(models.Model):
|
||||
_inherit = 'hr.department'
|
||||
|
||||
@api.multi
|
||||
def _compute_expense_to_approve(self):
|
||||
expense_data = self.env['hr.expense.expense'].read_group([('department_id', 'in', self.ids), ('state', '=', 'confirm')], ['department_id'], ['department_id'])
|
||||
result = dict((data['department_id'][0], data['department_id_count']) for data in expense_data)
|
||||
for department in self:
|
||||
department.expense_to_approve_count = result.get(department.id, 0)
|
||||
|
||||
expense_to_approve_count = fields.Integer(
|
||||
compute='_compute_expense_to_approve', string='Expenses to Approve')
|
||||
@@ -41,7 +41,7 @@
|
||||
<record id="mt_department_expense_confirmed" model="mail.message.subtype">
|
||||
<field name="name">Expenses To Approve</field>
|
||||
<field name="res_model">hr.department</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="parent_id" eval="ref('mt_expense_confirmed')"/>
|
||||
<field name="relation_field">department_id</field>
|
||||
<field name="sequence" eval="10"/>
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<tree colors="blue:state == 'draft';black:state in ('confirm','accepted','done');gray:state == 'cancelled'" string="Expenses" editable="top">
|
||||
<field name="employee_id"/>
|
||||
<field name="date"/>
|
||||
<field name="department_id"/>
|
||||
<field name="department_id" groups="hr.group_multi_departments"/>
|
||||
<field name="name" string="Expense Sheet"/>
|
||||
<field name="amount"/>
|
||||
<field name="state"/>
|
||||
@@ -76,7 +76,7 @@
|
||||
<group>
|
||||
<field name="employee_id" on_change="onchange_employee_id(employee_id)"/>
|
||||
<field name="date"/>
|
||||
<field name="department_id"/>
|
||||
<field name="department_id" groups="hr.group_multi_departments"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group>
|
||||
@@ -107,7 +107,7 @@
|
||||
<field name="unit_amount"/>
|
||||
<label for="unit_quantity"/>
|
||||
<div>
|
||||
<field name="unit_quantity" class="oe_inline"/>
|
||||
<field name="unit_quantity" class="oe_inline"/>
|
||||
<field name="uom_id" on_change="onchange_uom(product_id, uom_id, context)" class="oe_inline"/>
|
||||
</div>
|
||||
<field name="date_value" />
|
||||
@@ -156,7 +156,7 @@
|
||||
<field name="name" string="Expenses"/>
|
||||
<field name="date"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id" string="Department" context="{'invisible_department': False}"/>
|
||||
<field name="department_id" groups="hr.group_multi_departments" string="Department" context="{'invisible_department': False}"/>
|
||||
<filter domain="[('state','=','draft')]" string="New" help="New Expense"/>
|
||||
<filter domain="[('state','=','confirm')]" string="To Approve" name="confirm" help="Confirmed Expenses"/>
|
||||
<filter domain="[('state','=','accepted')]" string="To Pay" name="approved" help="Expenses to Invoice"/>
|
||||
@@ -166,7 +166,7 @@
|
||||
<filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="Employee" domain="[]" context="{'group_by':'employee_id'}"/>
|
||||
<filter string="Department" domain="[]" context="{'group_by':'department_id'}"/>
|
||||
<filter string="Department" domain="[]" context="{'group_by':'department_id'}" groups="hr.group_multi_departments"/>
|
||||
<filter string="Expenses Month" domain="[]" context="{'group_by':'date'}" help="Expenses by Month"/>
|
||||
</group>
|
||||
</search>
|
||||
@@ -181,7 +181,7 @@
|
||||
<field name="view_id" ref="view_expenses_tree"/>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to register new expenses.
|
||||
Click to register new expenses.
|
||||
</p><p>
|
||||
Odoo will ensure the whole process is followed; the expense
|
||||
sheet is validated by manager(s), the employee is reimbursed
|
||||
@@ -215,7 +215,7 @@
|
||||
<field name="search_view_id" ref="product.product_search_form_view"/>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to create a new expense category.
|
||||
Click to create a new expense category.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
@@ -226,9 +226,9 @@
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_expenses_tree"/>
|
||||
<field name="domain">[('state','=','accepted')]</field>
|
||||
<field name="domain">[('state','=','accepted')]</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="action_request_approve_expense" model="ir.actions.act_window">
|
||||
<field name="name">Expenses to Approve</field>
|
||||
<field name="res_model">hr.expense.expense</field>
|
||||
@@ -238,7 +238,7 @@
|
||||
<field name="view_id" ref="view_expenses_tree"/>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to register new expenses.
|
||||
Click to register new expenses.
|
||||
</p><p>
|
||||
OpenERP will ensure the whole process is followed; the expense
|
||||
sheet is validated by manager(s), the employee is reimbursed
|
||||
@@ -247,12 +247,47 @@
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_expense_approved" parent="account.menu_finance_payables" action="action_approved_expense" sequence="8"/>
|
||||
|
||||
<menuitem id="menu_expense_approved" parent="account.menu_finance_payables" action="action_approved_expense" sequence="8"/>
|
||||
<menuitem id="menu_hr_product" name="Expense Products" parent="hr.menu_hr_configuration_expenses" action="hr_expense_product" groups="base.group_hr_manager"/>
|
||||
<menuitem id="next_id_49" name="Expenses" sequence="15" parent="hr.menu_hr_root"/>
|
||||
<menuitem action="expense_all" id="menu_expense_all" name="Expenses" parent="next_id_49"/>
|
||||
<menuitem action="action_request_approve_expense" id="menu_expense_to_approve" name="Expenses to Approve" parent="next_id_49" groups="base.group_hr_user"/>
|
||||
|
||||
|
||||
<record id="hr_expense_action_from_department" model="ir.actions.act_window">
|
||||
<field name="name">Expenses To Approve</field>
|
||||
<field name="res_model">hr.expense.expense</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="view_hr_expense_filter"/>
|
||||
<field name="context">{
|
||||
'search_default_confirm': 1,
|
||||
'search_default_department_id': [active_id],
|
||||
'default_department_id': active_id}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--Hr Department Inherit Kanban view-->
|
||||
<record id="hr_department_view_kanban" model="ir.ui.view">
|
||||
<field name="name">hr.department.kanban.inherit</field>
|
||||
<field name="model">hr.department</field>
|
||||
<field name="inherit_id" ref="hr.hr_department_view_kanban"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<xpath expr="//templates" position="before">
|
||||
<field name="expense_to_approve_count"/>
|
||||
</xpath>
|
||||
<xpath expr="//div[@name='to_approve']" position="attributes">
|
||||
<attribute name="class">col-md-6 col-xs-6</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//div[@name='to_approve']" position="inside">
|
||||
<div>
|
||||
<a name="%(hr_expense_action_from_department)d" type="action"><t t-esc="record.expense_to_approve_count.raw_value or 0"/> Expenses</a>
|
||||
</div>
|
||||
</xpath>
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<filter string="Approved" domain="[('state','=','accepted')]" help="Approved Expenses"/>
|
||||
<filter string="Done" domain="[('state','=', 'done')]" help="Done Expenses"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="department_id" groups="hr.group_multi_departments"/>
|
||||
<group expand="0" string="Extended Filters...">
|
||||
<field name="product_id"/>
|
||||
<field name="user_id"/>
|
||||
@@ -47,7 +47,7 @@
|
||||
</group>
|
||||
<group expand="1" string="Group By">
|
||||
<filter string="Validation User" name="User" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Department" context="{'group_by':'department_id'}"/>
|
||||
<filter string="Department" groups="hr.group_multi_departments" context="{'group_by':'department_id'}"/>
|
||||
<filter string="Product" context="{'group_by':'product_id'}"/>
|
||||
<filter string="Status" context="{'group_by':'state'}"/>
|
||||
<filter string="Company" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import hr_department
|
||||
import hr_holidays
|
||||
import report
|
||||
import wizard
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from openerp import api, fields, models
|
||||
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
|
||||
|
||||
class hr_department(models.Model):
|
||||
_inherit = 'hr.department'
|
||||
|
||||
@api.multi
|
||||
def _compute_leave_count(self):
|
||||
Holiday = self.env['hr.holidays']
|
||||
today_date = datetime.datetime.utcnow().date()
|
||||
today_start = today_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT) # get the midnight of the current utc day
|
||||
today_end = (today_date + relativedelta(hours=23, minutes=59, seconds=59)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
|
||||
leave_data = Holiday.read_group(
|
||||
[('department_id', 'in', self.ids),
|
||||
('state', '=', 'confirm'), ('type', '=', 'remove')],
|
||||
['department_id'], ['department_id'])
|
||||
allocation_data = Holiday.read_group(
|
||||
[('department_id', 'in', self.ids),
|
||||
('state', '=', 'confirm'), ('type', '=', 'add')],
|
||||
['department_id'], ['department_id'])
|
||||
absence_data = Holiday.read_group(
|
||||
[('department_id', 'in', self.ids), ('state', 'not in', ['cancel', 'refuse']),
|
||||
('date_from', '<=', today_end), ('date_to', '>=', today_start), ('type', '=', 'remove')],
|
||||
['department_id'], ['department_id'])
|
||||
|
||||
res_leave = dict((data['department_id'][0], data['department_id_count']) for data in leave_data)
|
||||
res_allocation = dict((data['department_id'][0], data['department_id_count']) for data in allocation_data)
|
||||
res_absence = dict((data['department_id'][0], data['department_id_count']) for data in absence_data)
|
||||
|
||||
for department in self:
|
||||
department.leave_to_approve_count = res_leave.get(department.id, 0)
|
||||
department.allocation_to_approve_count = res_allocation.get(department.id, 0)
|
||||
department.absence_of_today = res_absence.get(department.id, 0)
|
||||
|
||||
|
||||
@api.multi
|
||||
def _compute_total_employee(self):
|
||||
emp_data = self.env['hr.employee'].read_group([('department_id', 'in', self.ids)], ['department_id'], ['department_id'])
|
||||
result = dict((data['department_id'][0], data['department_id_count']) for data in emp_data)
|
||||
for department in self:
|
||||
department.total_employee = result.get(department.id, 0)
|
||||
|
||||
absence_of_today = fields.Integer(
|
||||
compute='_compute_leave_count', string='Absence by Today')
|
||||
leave_to_approve_count = fields.Integer(
|
||||
compute='_compute_leave_count', string='Leave to Approve')
|
||||
allocation_to_approve_count = fields.Integer(
|
||||
compute='_compute_leave_count', string='Allocation to Approve')
|
||||
total_employee = fields.Integer(
|
||||
compute='_compute_total_employee', string='Total Employee')
|
||||
@@ -25,15 +25,22 @@
|
||||
import calendar
|
||||
import datetime
|
||||
from datetime import date
|
||||
import logging
|
||||
import math
|
||||
import time
|
||||
from operator import attrgetter
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import pytz
|
||||
|
||||
from openerp.exceptions import UserError, AccessError
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp import tools
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class hr_holidays_status(osv.osv):
|
||||
_name = "hr.holidays.status"
|
||||
@@ -236,7 +243,7 @@ class hr_holidays(osv.osv):
|
||||
]
|
||||
|
||||
_sql_constraints = [
|
||||
('type_value', "CHECK( (holiday_type='employee' AND employee_id IS NOT NULL) or (holiday_type='category' AND category_id IS NOT NULL))",
|
||||
('type_value', "CHECK( (holiday_type='employee' AND employee_id IS NOT NULL) or (holiday_type='category' AND category_id IS NOT NULL))",
|
||||
"The employee or employee category of this request is missing. Please make sure that your user login is linked to an employee."),
|
||||
('date_check2', "CHECK ( (type='add') OR (date_from <= date_to))", "The start date must be anterior to the end date."),
|
||||
('date_check', "CHECK ( number_of_days_temp >= 0 )", "The number of days must be greater than 0."),
|
||||
@@ -404,11 +411,11 @@ class hr_holidays(osv.osv):
|
||||
'allday': False,
|
||||
'state': 'open', # to block that meeting date in the calendar
|
||||
'class': 'confidential'
|
||||
}
|
||||
#Add the partner_id (if exist) as an attendee
|
||||
}
|
||||
#Add the partner_id (if exist) as an attendee
|
||||
if record.user_id and record.user_id.partner_id:
|
||||
meeting_vals['partner_ids'] = [(4,record.user_id.partner_id.id)]
|
||||
|
||||
|
||||
ctx_no_email = dict(context or {}, no_email=True)
|
||||
meeting_id = meeting_obj.create(cr, uid, meeting_vals, context=ctx_no_email)
|
||||
self._create_resource_leave(cr, uid, [record], context=context)
|
||||
@@ -587,6 +594,32 @@ class hr_employee(osv.Model):
|
||||
res[employee_id] = {'leaves_count': leaves, 'approved_leaves_count': approved_leaves}
|
||||
return res
|
||||
|
||||
def _absent_employee(self, cr, uid, ids, field_name, arg, context=None):
|
||||
today_date = datetime.datetime.utcnow().date()
|
||||
today_start = today_date.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT) # get the midnight of the current utc day
|
||||
today_end = (today_date + relativedelta(hours=23, minutes=59, seconds=59)).strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
data = self.pool['hr.holidays'].read_group(cr, uid,
|
||||
[('employee_id', 'in', ids), ('state', 'not in', ['cancel', 'refuse']),
|
||||
('date_from', '<=', today_end), ('date_to', '>=', today_start), ('type', '=', 'remove')],
|
||||
['employee_id'], ['employee_id'], context=context)
|
||||
result = dict.fromkeys(ids, False)
|
||||
for d in data:
|
||||
if d['employee_id_count'] >= 1:
|
||||
result[d['employee_id'][0]] = True
|
||||
return result
|
||||
|
||||
def _search_absent_employee(self, cr, uid, obj, name, args, context=None):
|
||||
today_date = datetime.datetime.utcnow().date()
|
||||
today_start = today_date.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT) # get the midnight of the current utc day
|
||||
today_end = (today_date + relativedelta(hours=23, minutes=59, seconds=59)).strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
holiday_ids = self.pool['hr.holidays'].search_read(cr, uid, [
|
||||
('state', 'not in', ['cancel', 'refuse']),
|
||||
('date_from', '<=', today_end),
|
||||
('date_to', '>=', today_start),
|
||||
('type', '=', 'remove')], ['employee_id'], context=context)
|
||||
absent_employee_ids = [holiday['employee_id'][0] for holiday in holiday_ids if holiday['employee_id']]
|
||||
return [('id', 'in', absent_employee_ids)]
|
||||
|
||||
_columns = {
|
||||
'remaining_leaves': fields.function(_get_remaining_days, string='Remaining Legal Leaves', fnct_inv=_set_remaining_days, type="float", help='Total number of legal leaves allocated to this employee, change this value to create allocation/leave request. Total based on all the leave types without overriding limit.'),
|
||||
'current_leave_state': fields.function(
|
||||
@@ -598,4 +631,5 @@ class hr_employee(osv.Model):
|
||||
'leave_date_to': fields.function(_get_leave_status, multi='leave_status', type='date', string='To Date'),
|
||||
'leaves_count': fields.function(_leaves_count, multi='_leaves_count', type='integer', string='Number of Leaves (current month)'),
|
||||
'approved_leaves_count': fields.function(_leaves_count, multi='_leaves_count', type='integer', string='Approved Leaves not in Payslip', help="These leaves are approved but not taken into account for payslip"),
|
||||
'is_absent_totay': fields.function(_absent_employee, fnct_search=_search_absent_employee, type="boolean", string="Absent Today", default=False)
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
<record id="mt_department_holidays_confirmed" model="mail.message.subtype">
|
||||
<field name="name">Leaves/Allocations: first approval</field>
|
||||
<field name="res_model">hr.department</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="parent_id" eval="ref('mt_holidays_confirmed')"/>
|
||||
<field name="relation_field">department_id</field>
|
||||
<field name="sequence" eval="6"/>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<separator/>
|
||||
<filter string="My Department Leaves" help="My Department Leaves" domain="[('department_id.manager_id','=',uid)]"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="department_id" groups="hr.group_multi_departments"/>
|
||||
<field name="holiday_status_id"/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter name="group_name" string="Description" context="{'group_by':'name'}"/>
|
||||
@@ -87,7 +87,7 @@
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name" attrs="{'readonly':[('state','!=','draft'),('state','!=','confirm')], 'required': [('type', '=', 'add')]}"/>
|
||||
<field name="name" attrs="{'readonly':[('state','!=','draft'),('state','!=','confirm')]}" required="1"/>
|
||||
<field name="holiday_status_id" context="{'employee_id':employee_id}"/>
|
||||
<label for="number_of_days_temp" string="Duration"/>
|
||||
<div>
|
||||
@@ -242,11 +242,11 @@
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="edit_holiday_new"/>
|
||||
<field name="context">{
|
||||
'default_type': 'remove',
|
||||
'default_type': 'remove',
|
||||
'search_default_my_leaves':1,
|
||||
'needaction_menu_ref':
|
||||
'needaction_menu_ref':
|
||||
[
|
||||
'hr_holidays.menu_open_company_allocation',
|
||||
'hr_holidays.menu_open_company_allocation',
|
||||
]
|
||||
}</field>
|
||||
<field name="domain">[('type','=','remove'), ('employee_id.user_id','=', uid)]</field>
|
||||
@@ -291,12 +291,12 @@
|
||||
<field name="res_model">hr.holidays</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="context">{
|
||||
'default_type': 'remove',
|
||||
'search_default_approve':1,
|
||||
'needaction_menu_ref':
|
||||
'default_type': 'remove',
|
||||
'search_default_approve':1,
|
||||
'needaction_menu_ref':
|
||||
[
|
||||
'hr_holidays.menu_open_ask_holidays_new',
|
||||
'hr_holidays.menu_open_company_allocation',
|
||||
'hr_holidays.menu_open_ask_holidays_new',
|
||||
'hr_holidays.menu_open_company_allocation',
|
||||
'hr_holidays.menu_open_employee_leave',
|
||||
]
|
||||
}</field>
|
||||
@@ -326,11 +326,11 @@
|
||||
<field name="res_model">hr.holidays</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="context">{
|
||||
'default_type':'add',
|
||||
'default_type':'add',
|
||||
'search_default_my_leaves':1,
|
||||
'needaction_menu_ref':
|
||||
'needaction_menu_ref':
|
||||
[
|
||||
'hr_holidays.menu_open_company_allocation',
|
||||
'hr_holidays.menu_open_company_allocation',
|
||||
]
|
||||
}</field>
|
||||
<field name="domain">[('type','=','add'), ('employee_id.user_id','=', uid)]</field>
|
||||
@@ -359,11 +359,11 @@
|
||||
<field name="res_model">hr.holidays</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="context">{
|
||||
'default_type': 'add',
|
||||
'search_default_approve':1,
|
||||
'needaction_menu_ref':
|
||||
'default_type': 'add',
|
||||
'search_default_approve':1,
|
||||
'needaction_menu_ref':
|
||||
[
|
||||
'hr_holidays.menu_open_allocation_holidays',
|
||||
'hr_holidays.menu_open_allocation_holidays',
|
||||
'hr_holidays.menu_open_company_allocation'
|
||||
]
|
||||
}</field>
|
||||
@@ -395,9 +395,9 @@
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" eval="view_holiday_simple"/>
|
||||
<field name="context">{
|
||||
'search_default_group_type': 1,
|
||||
'search_default_group_type': 1,
|
||||
'search_default_year': 1 ,
|
||||
'needaction_menu_ref':
|
||||
'needaction_menu_ref':
|
||||
[
|
||||
'hr_holidays.menu_open_ask_holidays_new',
|
||||
'hr_holidays.menu_request_approve_holidays',
|
||||
@@ -411,7 +411,7 @@
|
||||
</record>
|
||||
|
||||
<menuitem name="Leaves Summary" parent="menu_open_ask_holidays" id="menu_open_company_allocation" action="open_company_allocation" sequence="40"/>
|
||||
|
||||
|
||||
<record model="ir.actions.act_window" id="open_employee_leaves">
|
||||
<field name="name">Employee's Leaves</field>
|
||||
<field name="res_model">hr.holidays</field>
|
||||
@@ -531,7 +531,7 @@
|
||||
<field name="domain">[('type','=','remove')]</field>
|
||||
<field name="view_id" eval="view_holiday"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="act_hr_employee_holiday_request_approved" model="ir.actions.act_window">
|
||||
<field name="name">Leaves to be reported in Payslip</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
@@ -605,6 +605,18 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--Hr Employee inherit search view-->
|
||||
<record id="hr_employee_view_search" model="ir.ui.view">
|
||||
<field name="name">hr.employee.search.view.inherit</field>
|
||||
<field name="model">hr.employee</field>
|
||||
<field name="inherit_id" ref="hr.view_employee_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='department_id']" position="after">
|
||||
<filter name="is_absent_totay" string="Absent Today" domain="[('is_absent_totay', '=', True)]"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="hr_kanban_view_employees_kanban">
|
||||
<field name="name">HR - Employees Kanban with leave status</field>
|
||||
<field name="model">hr.employee</field>
|
||||
@@ -634,5 +646,98 @@
|
||||
view_mode="tree,form,calendar,gantt"
|
||||
view_type="form"/>
|
||||
|
||||
<record id="hr_holidays_action_request_from_department" model="ir.actions.act_window">
|
||||
<field name="name">Leave Request to Approve</field>
|
||||
<field name="res_model">hr.holidays</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{
|
||||
'default_type': 'remove',
|
||||
'search_default_department_id': [active_id],
|
||||
'default_department_id': active_id,
|
||||
'search_default_approve':1}
|
||||
</field>
|
||||
<field name="domain">[('type','=','remove')]</field>
|
||||
<field name="view_id" ref="view_holiday"/>
|
||||
<field name="search_view_id" ref="view_hr_holidays_filter"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_action_allocation_from_department" model="ir.actions.act_window">
|
||||
<field name="name">Allocation Requests to Approve</field>
|
||||
<field name="res_model">hr.holidays</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{
|
||||
'default_type': 'add',
|
||||
'search_default_department_id': [active_id],
|
||||
'default_department_id': active_id,
|
||||
'search_default_approve':1}
|
||||
</field>
|
||||
<field name="domain">[('type','=','add')]</field>
|
||||
<field name="search_view_id" ref="view_hr_holidays_filter"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_employee_action_from_department" model="ir.actions.act_window">
|
||||
<field name="name">Absent Employees</field>
|
||||
<field name="res_model">hr.employee</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">kanban,tree,form</field>
|
||||
<field name="context">{
|
||||
'search_default_is_absent_totay': 1,
|
||||
'search_default_department_id': [active_id],
|
||||
'default_department_id': active_id}
|
||||
</field>
|
||||
<field name="search_view_id" ref="hr_employee_view_search"/>
|
||||
</record>
|
||||
|
||||
<!--Hr Department Inherit Kanban view-->
|
||||
<record id="hr_department_view_kanban" model="ir.ui.view">
|
||||
<field name="name">hr.department.kanban.inherit</field>
|
||||
<field name="model">hr.department</field>
|
||||
<field name="inherit_id" ref="hr.hr_department_view_kanban"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<xpath expr="//templates" position="before">
|
||||
<field name="leave_to_approve_count"/>
|
||||
<field name="allocation_to_approve_count"/>
|
||||
<field name="total_employee"/>
|
||||
</xpath>
|
||||
<xpath expr="//div[@name='to_approve']" position="attributes">
|
||||
<attribute name="class">col-md-6 col-xs-6</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//div[@name='to_approve']" position="inside">
|
||||
<div>
|
||||
<a name="%(hr_holidays_action_request_from_department)d" type="action">
|
||||
<t t-esc="record.leave_to_approve_count.raw_value or 0"/> Leave Requests
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<a name="%(hr_holidays_action_allocation_from_department)d" type="action">
|
||||
<t t-esc="record.allocation_to_approve_count.raw_value or 0"/> Allocation Requests
|
||||
</a>
|
||||
</div>
|
||||
</xpath>
|
||||
<xpath expr="//div[@name='gauge_to_approve']" position="attributes">
|
||||
<attribute name="class">col-md-6 col-xs-6</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//div[@name='gauge_to_approve']" position="inside">
|
||||
<div class="row">
|
||||
<a name="%(hr_employee_action_from_department)d" type="action">
|
||||
<field name="absence_of_today"
|
||||
options="{
|
||||
'max_field': 'total_employee',
|
||||
'label': 'Absence(s) of Today',
|
||||
'levelcolors': ['#a9d70b', '#f9c802', '#ff0000']}"
|
||||
widget="gauge"
|
||||
style="width:160px; height: 120px; cursor: pointer;">Absence(s) of Today
|
||||
</field>
|
||||
</a>
|
||||
</div>
|
||||
</xpath>
|
||||
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
import hr_department
|
||||
import hr_recruitment
|
||||
import report
|
||||
import wizard
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from openerp import api, fields, models
|
||||
|
||||
|
||||
class hr_department(models.Model):
|
||||
_inherit = 'hr.department'
|
||||
|
||||
@api.multi
|
||||
def _compute_new_applicant_count(self):
|
||||
applicant_data = self.env['hr.applicant'].read_group(
|
||||
[('department_id', 'in', self.ids), ('stage_id.sequence', '<=', '1')],
|
||||
['department_id'], ['department_id'])
|
||||
result = dict((data['department_id'][0], data['department_id_count']) for data in applicant_data)
|
||||
for department in self:
|
||||
department.new_applicant_count = result.get(department.id, 0)
|
||||
|
||||
@api.multi
|
||||
def _compute_recruitment_stats(self):
|
||||
job_data = self.env['hr.job'].read_group(
|
||||
[('department_id', 'in', self.ids)],
|
||||
['no_of_hired_employee', 'no_of_recruitment', 'department_id'], ['department_id'])
|
||||
new_emp = dict((data['department_id'][0], data['no_of_hired_employee']) for data in job_data)
|
||||
expected_emp = dict((data['department_id'][0], data['no_of_recruitment']) for data in job_data)
|
||||
for department in self:
|
||||
department.new_hired_employee = new_emp.get(department.id, 0)
|
||||
department.expected_employee = expected_emp.get(department.id, 0)
|
||||
|
||||
new_applicant_count = fields.Integer(
|
||||
compute='_compute_new_applicant_count', string='New Applicant')
|
||||
new_hired_employee = fields.Integer(
|
||||
compute='_compute_recruitment_stats', string='New Hired Employee')
|
||||
expected_employee = fields.Integer(
|
||||
compute='_compute_recruitment_stats', string='Expected Employee')
|
||||
@@ -590,6 +590,12 @@ class hr_job(osv.osv):
|
||||
_name = "hr.job"
|
||||
_inherits = {'mail.alias': 'alias_id'}
|
||||
|
||||
_track = {
|
||||
'state': {
|
||||
'hr_recruitment.mt_job_new': lambda self, cr, uid, obj, ctx=None: obj.state == 'open'
|
||||
},
|
||||
}
|
||||
|
||||
def _get_attached_docs(self, cr, uid, ids, field_name, arg, context=None):
|
||||
res = {}
|
||||
attachment_obj = self.pool.get('ir.attachment')
|
||||
@@ -642,9 +648,11 @@ class hr_job(osv.osv):
|
||||
'hr.applicant', self._columns['alias_id'], 'name', alias_prefix='job+', alias_defaults={'job_id': 'id'}, context=context)
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
# TDE note: shouldn't it be in mail_create_nolog ?
|
||||
alias_context = dict(context, alias_model_name='hr.applicant', alias_parent_model_name=self._name)
|
||||
job_id = super(hr_job, self).create(cr, uid, vals, context=alias_context)
|
||||
create_context = dict(context,
|
||||
alias_model_name='hr.applicant',
|
||||
mail_create_nolog=True,
|
||||
alias_parent_model_name=self._name)
|
||||
job_id = super(hr_job, self).create(cr, uid, vals, context=create_context)
|
||||
job = self.browse(cr, uid, job_id, context=context)
|
||||
self.pool.get('mail.alias').write(cr, uid, [job.alias_id.id], {'alias_parent_thread_id': job_id, "alias_defaults": {'job_id': job_id}}, context)
|
||||
return job_id
|
||||
@@ -682,3 +690,26 @@ class applicant_category(osv.osv):
|
||||
_columns = {
|
||||
'name': fields.char('Name', required=True, translate=True),
|
||||
}
|
||||
|
||||
|
||||
class hr_employee(osv.Model):
|
||||
_inherit = "hr.employee"
|
||||
|
||||
def _newly_hired_employee(self, cr, uid, ids, field_name, arg, context=None):
|
||||
data = self.pool['hr.applicant'].read_group(cr, uid,
|
||||
[('emp_id', 'in', ids), ('job_id.state', '=', 'recruit')],
|
||||
['emp_id'], ['emp_id'], context=context)
|
||||
result = dict.fromkeys(ids, False)
|
||||
for d in data:
|
||||
if d['emp_id_count'] >= 1:
|
||||
result[d['emp_id'][0]] = True
|
||||
return result
|
||||
|
||||
def _search_newly_hired_employee(self, cr, uid, obj, name, args, context=None):
|
||||
applicant_ids = self.pool['hr.applicant'].search_read(cr, uid, [('job_id.state', '=', 'recruit')], ['emp_id'], context=context)
|
||||
hired_emp_ids = [applicant['emp_id'][0] for applicant in applicant_ids if applicant['emp_id']]
|
||||
return [('id', 'in', hired_emp_ids)]
|
||||
|
||||
_columns = {
|
||||
'newly_hired_employee': fields.function(_newly_hired_employee, fnct_search=_search_newly_hired_employee, type='boolean', string='Newly hired employees')
|
||||
}
|
||||
|
||||
@@ -131,6 +131,12 @@
|
||||
</record>
|
||||
|
||||
<!-- Job-related subtypes for messaging / Chatter -->
|
||||
<record id="mt_job_new" model="mail.message.subtype">
|
||||
<field name="name">Job Position created</field>
|
||||
<field name="res_model">hr.job</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="hidden" eval="True"/>
|
||||
</record>
|
||||
<record id="mt_job_applicant_new" model="mail.message.subtype">
|
||||
<field name="name">Applicant Created</field>
|
||||
<field name="res_model">hr.job</field>
|
||||
@@ -153,6 +159,15 @@
|
||||
<field name="relation_field">job_id</field>
|
||||
</record>
|
||||
|
||||
<!-- Department-related (parent) subtypes for messaging / Chatter -->
|
||||
<record id="mt_department_new" model="mail.message.subtype">
|
||||
<field name="name">Job Position Created</field>
|
||||
<field name="res_model">hr.department</field>
|
||||
<field name="sequence" eval="1"/>
|
||||
<field name="parent_id" eval="ref('mt_job_new')"/>
|
||||
<field name="relation_field">department_id</field>
|
||||
</record>
|
||||
|
||||
<!-- Applicant Categories(Tag) -->
|
||||
<record id="tag_applicant_reserve" model="hr.applicant_category">
|
||||
<field name="name">Reserve</field>
|
||||
|
||||
@@ -71,16 +71,16 @@
|
||||
help="Schedule interview with this applicant">
|
||||
<div>Meetings</div>
|
||||
</button>
|
||||
<button name="action_start_survey"
|
||||
<button name="action_start_survey"
|
||||
class="oe_stat_button"
|
||||
icon="fa-user"
|
||||
icon="fa-user"
|
||||
type="object"
|
||||
help="Answer related job question"
|
||||
context="{'survey_id': survey}"
|
||||
attrs="{'invisible':[('survey','=',False)]}">
|
||||
<div>Start<br/>Interview</div>
|
||||
</button>
|
||||
<button name="action_print_survey"
|
||||
<button name="action_print_survey"
|
||||
class="oe_stat_button"
|
||||
icon="fa-print"
|
||||
type="object"
|
||||
@@ -88,7 +88,7 @@
|
||||
attrs="{'invisible':[('survey','=',False)]}">
|
||||
<div>Print<br/>Interview</div>
|
||||
</button>
|
||||
<button name="action_get_attachment_tree_view"
|
||||
<button name="action_get_attachment_tree_view"
|
||||
class="oe_stat_button"
|
||||
icon="fa-book"
|
||||
type="object">
|
||||
@@ -139,7 +139,7 @@
|
||||
<field name="survey" invisible="1"/>
|
||||
<field name="response_id" invisible="1"/>
|
||||
<field name="job_id" on_change="onchange_job(job_id)"/>
|
||||
<field name="department_id" on_change="onchange_department_id(department_id, stage_id)"/>
|
||||
<field name="department_id" on_change="onchange_department_id(department_id, stage_id)" groups="hr.group_multi_departments"/>
|
||||
<field name="company_id" />
|
||||
<label for="availability"/>
|
||||
<div>
|
||||
@@ -212,7 +212,7 @@
|
||||
<separator/>
|
||||
<filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<field name="job_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="department_id" groups="hr.group_multi_departments"/>
|
||||
<field name="user_id"/>
|
||||
<field name="stage_id" domain="[]"/>
|
||||
<separator/>
|
||||
@@ -270,7 +270,7 @@
|
||||
<ul class="oe_kanban_tooltip">
|
||||
<li t-if="record.type_id.raw_value"><b>Degree:</b> <field name="type_id"/></li>
|
||||
<li t-if="record.partner_id.raw_value"><b>Contact:</b> <field name="partner_id"/></li>
|
||||
<li t-if="record.department_id.raw_value"><b>Departement:</b> <field name="department_id"/></li>
|
||||
<li t-if="record.department_id.raw_value"><b>Departement:</b> <field name="department_id" groups="hr.group_multi_departments"/></li>
|
||||
</ul>
|
||||
</t>
|
||||
<t t-name="kanban-box">
|
||||
@@ -407,14 +407,14 @@
|
||||
</xpath>
|
||||
<xpath expr="//div[@name='buttons']" position="inside">
|
||||
<div class="oe_button_box" >
|
||||
<button class="oe_stat_button"
|
||||
<button class="oe_stat_button"
|
||||
icon="fa-file-o"
|
||||
name="%(action_hr_job_applications)d"
|
||||
context="{'default_user_id': user_id}"
|
||||
name="%(action_hr_job_applications)d"
|
||||
context="{'default_user_id': user_id}"
|
||||
type="action">
|
||||
<field name="application_count" widget="statinfo" string="Applications"/>
|
||||
</button>
|
||||
<button class="oe_stat_button"
|
||||
<button class="oe_stat_button"
|
||||
icon="fa-users"
|
||||
name="%(action_hr_job_no_employee)d"
|
||||
type="action">
|
||||
@@ -422,7 +422,7 @@
|
||||
</button>
|
||||
<button class="oe_stat_button"
|
||||
icon="fa-book"
|
||||
name="action_get_attachment_tree_view"
|
||||
name="action_get_attachment_tree_view"
|
||||
type="object">
|
||||
<field name="documents_count" widget="statinfo" string="Documents"/>
|
||||
</button>
|
||||
@@ -481,7 +481,7 @@
|
||||
<strong><field name="name"/></strong>
|
||||
</div>
|
||||
<div class="text-center oe_job_font oe_kanban_ellipsis">
|
||||
<strong><field name="department_id"/>
|
||||
<strong><field name="department_id" groups="hr.group_multi_departments"/>
|
||||
<span t-if="record.manager_id.value" class="oe_manager_name">
|
||||
(<t t-esc="record.manager_id.value"/>)
|
||||
</span></strong>
|
||||
@@ -566,7 +566,7 @@
|
||||
<tree string="Stages">
|
||||
<field name="sequence" invisible="1"/>
|
||||
<field name="name"/>
|
||||
<field name="department_id"/>
|
||||
<field name="department_id" groups="hr.group_multi_departments"/>
|
||||
<field name="fold"/>
|
||||
</tree>
|
||||
</field>
|
||||
@@ -581,7 +581,7 @@
|
||||
<group string="Stage Definition">
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="department_id"/>
|
||||
<field name="department_id" groups="hr.group_multi_departments"/>
|
||||
<field name="sequence"/>
|
||||
<field name="template_id" domain= "[('model_id.model', '=', 'hr.applicant')]"/>
|
||||
</group>
|
||||
@@ -701,5 +701,80 @@
|
||||
groups="base.group_no_one"
|
||||
sequence="10"/>
|
||||
|
||||
<record id="hr_applicant_action_from_department" model="ir.actions.act_window">
|
||||
<field name="name">New Applications</field>
|
||||
<field name="res_model">hr.applicant</field>
|
||||
<field name="view_mode">kanban,tree,form,graph,calendar</field>
|
||||
<field name="context">{
|
||||
'search_default_department_id': [active_id],
|
||||
'default_department_id': active_id}
|
||||
</field>
|
||||
<field name="domain">[('stage_id.sequence','<=','1')]</field>
|
||||
</record>
|
||||
|
||||
<!--Hr Employee inherit search view-->
|
||||
<record id="hr_employee_view_search" model="ir.ui.view">
|
||||
<field name="name">hr.employee.search.inherit</field>
|
||||
<field name="model">hr.employee</field>
|
||||
<field name="inherit_id" ref="hr.view_employee_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='department_id']" position="after">
|
||||
<filter name="newly_hired_employee" string="New Hired" domain="[('newly_hired_employee', '=', True)]"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_employee_action_from_department" model="ir.actions.act_window">
|
||||
<field name="name">Newly Hired Employees</field>
|
||||
<field name="res_model">hr.employee</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">kanban,tree,form</field>
|
||||
<field name="context">{
|
||||
'search_default_newly_hired_employee': 1,
|
||||
'search_default_department_id': [active_id],
|
||||
'default_department_id': active_id}
|
||||
</field>
|
||||
<field name="search_view_id" ref="hr_employee_view_search"/>
|
||||
</record>
|
||||
|
||||
<!--Hr Department Inherit Kanban view-->
|
||||
<record id="hr_department_view_kanban" model="ir.ui.view">
|
||||
<field name="name">hr.department.kanban.inherit</field>
|
||||
<field name="model">hr.department</field>
|
||||
<field name="inherit_id" ref="hr.hr_department_view_kanban"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<xpath expr="//templates" position="before">
|
||||
<field name="new_applicant_count"/>
|
||||
<field name="new_hired_employee"/>
|
||||
<field name="expected_employee"/>
|
||||
</xpath>
|
||||
<xpath expr="//div[@name='to_do']" position="attributes">
|
||||
<attribute name="class">col-md-6 col-xs-6</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//div[@name='to_do']" position="inside">
|
||||
<div>
|
||||
<a name="%(hr_applicant_action_from_department)d" type="action">
|
||||
<t t-esc="record.new_applicant_count.raw_value or 0"/> New Applicant
|
||||
</a>
|
||||
</div>
|
||||
</xpath>
|
||||
<xpath expr="//div[@name='gauge_to_do']" position="attributes">
|
||||
<attribute name="class">col-md-6 col-xs-6</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//div[@name='gauge_to_do']" position="inside">
|
||||
<div class="row">
|
||||
<a name="%(hr_employee_action_from_department)d" type="action">
|
||||
<field name="new_hired_employee" widget="gauge"
|
||||
options="{'max_field': 'expected_employee', 'label': 'Hired Employee(s)',}"
|
||||
style="width:160px; height: 120px; cursor: pointer;">Newly Hired Employee(s)
|
||||
</field>
|
||||
</a>
|
||||
</div>
|
||||
</xpath>
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
##############################################################################
|
||||
|
||||
import hr_timesheet_sheet
|
||||
import hr_department
|
||||
import wizard
|
||||
import report
|
||||
import res_config
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from openerp import api, fields, models
|
||||
|
||||
|
||||
class hr_department(models.Model):
|
||||
_inherit = 'hr.department'
|
||||
|
||||
@api.multi
|
||||
def _compute_timesheet_to_approve(self):
|
||||
timesheet_data = self.env['hr_timesheet_sheet.sheet'].read_group(
|
||||
[('department_id', 'in', self.ids), ('state', '=', 'confirm')], ['department_id'], ['department_id'])
|
||||
result = dict((data['department_id'][0], data['department_id_count']) for data in timesheet_data)
|
||||
for department in self:
|
||||
department.timesheet_to_approve_count = result.get(department.id, 0)
|
||||
|
||||
timesheet_to_approve_count = fields.Integer(
|
||||
compute='_compute_timesheet_to_approve', string='Timesheet to Approve')
|
||||
@@ -183,10 +183,10 @@
|
||||
<filter name="to_approve" string="To Approve" domain="[('state','=','confirm')]" help="Confirmed Timesheets"/>
|
||||
<filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="department_id" groups="hr.group_multi_departments"/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="Employees" icon="terp-personal" domain="[]" context="{'group_by':'employee_id'}"/>
|
||||
<filter string="Department" icon="terp-personal+" domain="[]" context="{'group_by':'department_id'}"/>
|
||||
<filter string="Department" domain="[]" context="{'group_by':'department_id'}" groups="hr.group_multi_departments"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
@@ -356,7 +356,7 @@
|
||||
</record>
|
||||
|
||||
<!-- Timesheet Button on Employee Form -->
|
||||
|
||||
|
||||
<record id="act_hr_employee_2_hr_timesheet" model="ir.actions.act_window">
|
||||
<field name="res_model">hr_timesheet_sheet.sheet</field>
|
||||
<field name="view_type">form</field>
|
||||
@@ -364,17 +364,17 @@
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{'search_default_employee_id': [active_id], 'default_employee_id': active_id}</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="hr_timesheet_sheet_employee_extd_form" model="ir.ui.view">
|
||||
<field name="name">hr.timesheet.sheet.employee.extd_form</field>
|
||||
<field name="model">hr.employee</field>
|
||||
<field name="inherit_id" ref="hr_timesheet.hr_timesheet_employee_extd_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@name='button_box']" position="inside">
|
||||
<button name="%(act_hr_employee_2_hr_timesheet)d"
|
||||
<button name="%(act_hr_employee_2_hr_timesheet)d"
|
||||
type="action"
|
||||
class="oe_stat_button"
|
||||
icon="fa-clock-o"
|
||||
icon="fa-clock-o"
|
||||
groups="base.group_hr_manager">
|
||||
<field name="timesheet_count" widget="statinfo" string="Timesheets"/>
|
||||
</button>
|
||||
@@ -382,5 +382,41 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_timesheet_action_from_department" model="ir.actions.act_window">
|
||||
<field name="name">Timesheets to Approve</field>
|
||||
<field name="res_model">hr_timesheet_sheet.sheet</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{
|
||||
'search_default_department_id': [active_id],
|
||||
'default_department_id': active_id,
|
||||
'search_default_to_approve': 1}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--Hr Department Inherit Kanban view-->
|
||||
<record id="hr_department_view_kanban" model="ir.ui.view">
|
||||
<field name="name">hr.department.kanban.inherit</field>
|
||||
<field name="model">hr.department</field>
|
||||
<field name="inherit_id" ref="hr.hr_department_view_kanban"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<xpath expr="//templates" position="before">
|
||||
<field name="timesheet_to_approve_count"/>
|
||||
</xpath>
|
||||
<xpath expr="//div[@name='to_approve']" position="attributes">
|
||||
<attribute name="class">col-md-6 col-xs-6</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//div[@name='to_approve']" position="inside">
|
||||
<div>
|
||||
<a name="%(hr_timesheet_action_from_department)d" type="action">
|
||||
<t t-esc="record.timesheet_to_approve_count.raw_value or 0"/> Timesheet
|
||||
</a>
|
||||
</div>
|
||||
</xpath>
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
Reference in New Issue
Block a user