summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authordka-odoo <dka@openerp.com>2015-01-20 13:53:07 +0100
committerJérome Maes <jem@openerp.com>2015-02-25 11:25:40 +0100
commitd27910a8f2f2b29810dfa8022ad748cce64df00a (patch)
tree52776525b58ddb4d4c1b01ac63f2d0ac9e411b99 /addons
parente5875acc6aa19ca0a41ea1b4be9081bfd674005e (diff)
[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.
Diffstat (limited to 'addons')
-rw-r--r--addons/hr/__openerp__.py16
-rw-r--r--addons/hr/hr.py7
-rw-r--r--addons/hr/hr_view.xml101
-rw-r--r--addons/hr/res_config.py4
-rw-r--r--addons/hr/res_config_view.xml4
-rw-r--r--addons/hr/security/hr_security.xml5
-rw-r--r--addons/hr/static/src/js/hr.js14
-rw-r--r--addons/hr/static/src/less/hr_department.less11
-rw-r--r--addons/hr/views/hr.xml2
-rw-r--r--addons/hr_contract/hr_contract_view.xml4
-rw-r--r--addons/hr_evaluation/__init__.py1
-rw-r--r--addons/hr_evaluation/hr_department.py29
-rw-r--r--addons/hr_evaluation/hr_evaluation_view.xml54
-rw-r--r--addons/hr_expense/__init__.py1
-rw-r--r--addons/hr_expense/hr_department.py16
-rw-r--r--addons/hr_expense/hr_expense_data.xml2
-rw-r--r--addons/hr_expense/hr_expense_view.xml61
-rw-r--r--addons/hr_expense/report/hr_expense_report_view.xml4
-rw-r--r--addons/hr_holidays/__init__.py1
-rw-r--r--addons/hr_holidays/hr_department.py56
-rw-r--r--addons/hr_holidays/hr_holidays.py42
-rw-r--r--addons/hr_holidays/hr_holidays_data.xml2
-rw-r--r--addons/hr_holidays/hr_holidays_view.xml147
-rw-r--r--addons/hr_recruitment/__init__.py1
-rw-r--r--addons/hr_recruitment/hr_department.py33
-rw-r--r--addons/hr_recruitment/hr_recruitment.py37
-rw-r--r--addons/hr_recruitment/hr_recruitment_data.xml15
-rw-r--r--addons/hr_recruitment/hr_recruitment_view.xml105
-rw-r--r--addons/hr_timesheet_sheet/__init__.py1
-rw-r--r--addons/hr_timesheet_sheet/hr_department.py17
-rw-r--r--addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml48
31 files changed, 752 insertions, 89 deletions
diff --git a/addons/hr/__openerp__.py b/addons/hr/__openerp__.py
index 3830b5fe60f..6b118d426b8 100644
--- a/addons/hr/__openerp__.py
+++ b/addons/hr/__openerp__.py
@@ -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'],
}
diff --git a/addons/hr/hr.py b/addons/hr/hr.py
index 25b8939569c..8a6f828f730 100644
--- a/addons/hr/hr.py
+++ b/addons/hr/hr.py
@@ -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:
diff --git a/addons/hr/hr_view.xml b/addons/hr/hr_view.xml
index fff137c964e..c2e7515fc91 100644
--- a/addons/hr/hr_view.xml
+++ b/addons/hr/hr_view.xml
@@ -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>
diff --git a/addons/hr/res_config.py b/addons/hr/res_config.py
index f4fca22ea21..83508dbe8e1 100644
--- a/addons/hr/res_config.py
+++ b/addons/hr/res_config.py
@@ -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):
diff --git a/addons/hr/res_config_view.xml b/addons/hr/res_config_view.xml
index 7e7da1a0a88..4cc4dde095e 100644
--- a/addons/hr/res_config_view.xml
+++ b/addons/hr/res_config_view.xml
@@ -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">
diff --git a/addons/hr/security/hr_security.xml b/addons/hr/security/hr_security.xml
index 4383f2d6c74..09776a25e76 100644
--- a/addons/hr/security/hr_security.xml
+++ b/addons/hr/security/hr_security.xml
@@ -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">
diff --git a/addons/hr/static/src/js/hr.js b/addons/hr/static/src/js/hr.js
new file mode 100644
index 00000000000..90e37bd35b8
--- /dev/null
+++ b/addons/hr/static/src/js/hr.js
@@ -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);
+ }
+ },
+ });
+
+};
diff --git a/addons/hr/static/src/less/hr_department.less b/addons/hr/static/src/less/hr_department.less
new file mode 100644
index 00000000000..7f6b3bb0214
--- /dev/null
+++ b/addons/hr/static/src/less/hr_department.less
@@ -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
+ }
+ }
+}
diff --git a/addons/hr/views/hr.xml b/addons/hr/views/hr.xml
index ad153be42eb..aa6238469a6 100644
--- a/addons/hr/views/hr.xml
+++ b/addons/hr/views/hr.xml
@@ -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>
diff --git a/addons/hr_contract/hr_contract_view.xml b/addons/hr_contract/hr_contract_view.xml
index aa812a4bef5..8daf1b7e88b 100644
--- a/addons/hr_contract/hr_contract_view.xml
+++ b/addons/hr_contract/hr_contract_view.xml
@@ -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>
diff --git a/addons/hr_evaluation/__init__.py b/addons/hr_evaluation/__init__.py
index c98e428757a..0be2db9fc23 100644
--- a/addons/hr_evaluation/__init__.py
+++ b/addons/hr_evaluation/__init__.py
@@ -19,5 +19,6 @@
#
##############################################################################
+import hr_department
import hr_evaluation
import report
diff --git a/addons/hr_evaluation/hr_department.py b/addons/hr_evaluation/hr_department.py
new file mode 100644
index 00000000000..2f0783ee029
--- /dev/null
+++ b/addons/hr_evaluation/hr_department.py
@@ -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')
diff --git a/addons/hr_evaluation/hr_evaluation_view.xml b/addons/hr_evaluation/hr_evaluation_view.xml
index b91af7b4653..da24b8b914c 100644
--- a/addons/hr_evaluation/hr_evaluation_view.xml
+++ b/addons/hr_evaluation/hr_evaluation_view.xml
@@ -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>
diff --git a/addons/hr_expense/__init__.py b/addons/hr_expense/__init__.py
index 3cfbc6389fd..a14418afdc3 100644
--- a/addons/hr_expense/__init__.py
+++ b/addons/hr_expense/__init__.py
@@ -19,5 +19,6 @@
#
##############################################################################
+import hr_department
import hr_expense
import report
diff --git a/addons/hr_expense/hr_department.py b/addons/hr_expense/hr_department.py
new file mode 100644
index 00000000000..b4fa2a5668f
--- /dev/null
+++ b/addons/hr_expense/hr_department.py
@@ -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')
diff --git a/addons/hr_expense/hr_expense_data.xml b/addons/hr_expense/hr_expense_data.xml
index ac5df674885..c87aa55ceaf 100644
--- a/addons/hr_expense/hr_expense_data.xml
+++ b/addons/hr_expense/hr_expense_data.xml
@@ -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"/>
diff --git a/addons/hr_expense/hr_expense_view.xml b/addons/hr_expense/hr_expense_view.xml
index bb9d5d9ecd3..93ab55d4c75 100644
--- a/addons/hr_expense/hr_expense_view.xml
+++ b/addons/hr_expense/hr_expense_view.xml
@@ -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>
diff --git a/addons/hr_expense/report/hr_expense_report_view.xml b/addons/hr_expense/report/hr_expense_report_view.xml
index 14408d8c6ee..d61e90e46a6 100644
--- a/addons/hr_expense/report/hr_expense_report_view.xml
+++ b/addons/hr_expense/report/hr_expense_report_view.xml
@@ -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"/>
diff --git a/addons/hr_holidays/__init__.py b/addons/hr_holidays/__init__.py
index b0de80b8f72..75d9194131c 100644
--- a/addons/hr_holidays/__init__.py
+++ b/addons/hr_holidays/__init__.py
@@ -19,6 +19,7 @@
#
##############################################################################
+import hr_department
import hr_holidays
import report
import wizard
diff --git a/addons/hr_holidays/hr_department.py b/addons/hr_holidays/hr_department.py
new file mode 100644
index 00000000000..0218160642b
--- /dev/null
+++ b/addons/hr_holidays/hr_department.py
@@ -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')
diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py
index 757148ba3de..d8be826362e 100644
--- a/addons/hr_holidays/hr_holidays.py
+++ b/addons/hr_holidays/hr_holidays.py
@@ -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)
}
diff --git a/addons/hr_holidays/hr_holidays_data.xml b/addons/hr_holidays/hr_holidays_data.xml
index 1f4292a9d7c..da741e835c9 100644
--- a/addons/hr_holidays/hr_holidays_data.xml
+++ b/addons/hr_holidays/hr_holidays_data.xml
@@ -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"/>
diff --git a/addons/hr_holidays/hr_holidays_view.xml b/addons/hr_holidays/hr_holidays_view.xml
index d3870356462..628bf15ced8 100644
--- a/addons/hr_holidays/hr_holidays_view.xml
+++ b/addons/hr_holidays/hr_holidays_view.xml
@@ -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>
diff --git a/addons/hr_recruitment/__init__.py b/addons/hr_recruitment/__init__.py
index 517121c792d..d11c8800dc8 100644
--- a/addons/hr_recruitment/__init__.py
+++ b/addons/hr_recruitment/__init__.py
@@ -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
diff --git a/addons/hr_recruitment/hr_department.py b/addons/hr_recruitment/hr_department.py
new file mode 100644
index 00000000000..372274d7ec2
--- /dev/null
+++ b/addons/hr_recruitment/hr_department.py
@@ -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')
diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py
index 876444858b2..8af4a11b8b4 100644
--- a/addons/hr_recruitment/hr_recruitment.py
+++ b/addons/hr_recruitment/hr_recruitment.py
@@ -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')
+ }
diff --git a/addons/hr_recruitment/hr_recruitment_data.xml b/addons/hr_recruitment/hr_recruitment_data.xml
index d5b6377a3a2..695c472c1ae 100644
--- a/addons/hr_recruitment/hr_recruitment_data.xml
+++ b/addons/hr_recruitment/hr_recruitment_data.xml
@@ -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>
diff --git a/addons/hr_recruitment/hr_recruitment_view.xml b/addons/hr_recruitment/hr_recruitment_view.xml
index 8bf91cd0ffa..1dd04d7a4af 100644
--- a/addons/hr_recruitment/hr_recruitment_view.xml
+++ b/addons/hr_recruitment/hr_recruitment_view.xml
@@ -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','&lt;=','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>
diff --git a/addons/hr_timesheet_sheet/__init__.py b/addons/hr_timesheet_sheet/__init__.py
index 4cbb652c06c..5c6bdbf4cf7 100644
--- a/addons/hr_timesheet_sheet/__init__.py
+++ b/addons/hr_timesheet_sheet/__init__.py
@@ -20,6 +20,7 @@
##############################################################################
import hr_timesheet_sheet
+import hr_department
import wizard
import report
import res_config
diff --git a/addons/hr_timesheet_sheet/hr_department.py b/addons/hr_timesheet_sheet/hr_department.py
new file mode 100644
index 00000000000..733b2361fd1
--- /dev/null
+++ b/addons/hr_timesheet_sheet/hr_department.py
@@ -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')
diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml b/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
index 4b2e884134e..9287c12e288 100644
--- a/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
+++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
@@ -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>