##############################################################################
#
# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
+# Copyright (C) 2004-Today OpenERP S.A. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
_name = "hr.job"
_description = "Job Position"
- _inherit = ['mail.thread', 'ir.needaction_mixin']
+ _inherit = ['mail.thread']
_columns = {
'name': fields.char('Job Name', required=True, select=True),
'expected_employees': fields.function(_get_nbr_employees, string='Total Forecasted Employees',
class hr_department(osv.osv):
+ _name = "hr.department"
+ _description = "HR Department"
+ _inherit = ['mail.thread', 'ir.needaction_mixin']
def _dept_name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
res = self.name_get(cr, uid, ids, context=context)
return dict(res)
- _name = "hr.department"
_columns = {
'name': fields.char('Department Name', required=True),
'complete_name': fields.function(_dept_name_get_fnc, type="char", string='Name'),
'company_id': fields.many2one('res.company', 'Company', select=True, required=False),
'parent_id': fields.many2one('hr.department', 'Parent Department', select=True),
'child_ids': fields.one2many('hr.department', 'parent_id', 'Child Departments'),
- 'manager_id': fields.many2one('hr.employee', 'Manager'),
+ 'manager_id': fields.many2one('hr.employee', 'Manager', track_visibility='onchange'),
'member_ids': fields.one2many('hr.employee', 'department_id', 'Members', readonly=True),
'jobs_ids': fields.one2many('hr.job', 'department_id', 'Jobs'),
'note': fields.text('Note'),
res.append((record['id'], name))
return res
-
-class res_users(osv.osv):
- _name = 'res.users'
- _inherit = 'res.users'
- _columns = {
- 'employee_ids': fields.one2many('hr.employee', 'user_id', 'Related employees'),
- }
-
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+ def create(self, cr, uid, vals, context=None):
+ # TDE note: auto-subscription of manager done by hand, because currently
+ # the tracking allows to track+subscribe fields linked to a res.user record
+ # An update of the limited behavior should come, but not currently done.
+ manager_id = vals.get("manager_id")
+ new_id = super(hr_department, self).create(cr, uid, vals, context=context)
+ if manager_id:
+ employee = self.pool.get('hr.employee').browse(cr, uid, manager_id, context=context)
+ if employee.user_id:
+ self.message_subscribe_users(cr, uid, [new_id], user_ids=[employee.user_id.id], context=context)
+ return new_id
+
+ def write(self, cr, uid, ids, vals, context=None):
+ # TDE note: auto-subscription of manager done by hand, because currently
+ # the tracking allows to track+subscribe fields linked to a res.user record
+ # An update of the limited behavior should come, but not currently done.
+ if isinstance(ids, (int, long)):
+ ids = [ids]
+ manager_id = vals.get("manager_id")
+ if manager_id:
+ employee = self.pool.get('hr.employee').browse(cr, uid, manager_id, context=context)
+ if employee.user_id:
+ self.message_subscribe_users(cr, uid, [ids], user_ids=[employee.user_id.id], context=context)
+ return super(hr_department, self).write(cr, uid, ids, vals, context=context)
<record id="employee" model="hr.employee">
<field name="name">Administrator</field>
<field name="user_id" ref="base.user_root"/>
+ <field name="address_id" ref="base.partner_root"/>
+ <field name="address_home_id" ref="base.partner_root"/>
<field name="image" type="base64" file="hr/static/img/employee-image.png"/>
</record>
sequence="90"/>
<menuitem id="menu_hr_reporting" parent="base.menu_reporting" name="Human Resources" sequence="40" />
<menuitem id="menu_hr_main" parent="menu_hr_root" name="Human Resources" sequence="0"/>
- <menuitem id="menu_hr_configuration" name="Configuration" parent="hr.menu_hr_root" groups="base.group_hr_manager" sequence="50"/>
+ <menuitem id="menu_hr_configuration" name="Configuration" parent="hr.menu_hr_root" groups="base.group_hr_user" sequence="50"/>
<menuitem id="menu_hr_reporting_timesheet" name="Reports"
parent="menu_hr_reporting" sequence="6"/>
</notebook>
</sheet>
<div class="oe_chatter">
- <field name="message_follower_ids" widget="mail_followers"/>
+ <field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
<field name="name">hr.employee.tree</field>
<field name="model">hr.employee</field>
<field name="arch" type="xml">
- <tree string="Employees">
+ <tree string="Employees" fonts="bold:message_unread==True">
<field name="name"/>
<field name="work_phone"/>
<field name="work_email"/>
<field name="job_id"/>
<field name="parent_id"/>
<field name="coach_id" invisible="1"/>
+ <field name="message_unread" invisible="1"/>
</tree>
</field>
</record>
<field name="name" string="Employees" filter_domain="['|',('work_email','ilike',self),('name','ilike',self)]"/>
<field name="department_id" />
<field name="category_ids" groups="base.group_hr_user"/>
+ <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'}"/>
<field name="message_is_follower"/>
<field name="message_follower_ids"/>
<field name="message_ids"/>
+ <field name="message_summary"/>
+ <field name="message_unread"/>
<templates>
<t t-name="kanban-box">
<div class="oe_employee_vignette">
<li t-if="record.work_email.raw_value"><a t-attf-href="mailto:#{record.work_email.value}"><field name="work_email"/></a></li>
</ul>
<div class="oe_kanban_footer_left">
+ <t t-raw="record.message_summary.raw_value"/>
<span title='Messages'><span class='oe_e'>9</span><t t-esc="record.message_ids.raw_value.length"/></span>
<span title='Followers'><span class='oe_e'>+</span><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">
</record>
<menuitem action="open_view_categ_form" id="menu_view_employee_category_form"
- parent="hr.menu_hr_configuration" sequence="1" groups="base.group_no_one"/>
+ parent="hr.menu_hr_configuration" sequence="1" groups="base.group_no_one,base.group_hr_manager"/>
<record id="hr_employee_normal_action_tree" model="ir.actions.act_window">
<field name="name">Employees</field>
<field name="name">hr.job.tree</field>
<field name="model">hr.job</field>
<field name="arch" type="xml">
- <tree string="Job">
+ <tree string="Job" fonts="bold:message_unread==True">
<field name="name"/>
<field name="department_id"/>
<field name="no_of_employee"/>
<field name="expected_employees"/>
<field name="no_of_hired_employee"/>
<field name="state"/>
+ <field name="message_unread" invisible="1"/>
</tree>
</field>
</record>
<filter domain="[('state','=','open')]" string="In Position"/>
<filter domain="[('state','=','recruit')]" string="In Recruitment" name="in_recruitment"/>
<field name="department_id"/>
+ <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="Status" domain="[]" context="{'group_by':'state'}"/>
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
</group>
</sheet>
+ <div class="oe_chatter">
+ <field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
+ <field name="message_ids" widget="mail_thread"/>
+ </div>
</form>
</field>
</record>
<search string="Departments">
<field name="name" string="Department"/>
<field name="manager_id" />
+ <filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
</search>
</field>
</record>
</p>
</field>
</record>
- <menuitem action="open_module_tree_department" id="menu_hr_department_tree" parent="hr.menu_hr_configuration" sequence="5"/>
+ <menuitem action="open_module_tree_department" id="menu_hr_department_tree" parent="hr.menu_hr_configuration" sequence="5" groups="base.group_hr_manager,base.group_hr_user"/>
</data>
</openerp>
class res_users(osv.Model):
""" Update of res.users class
- - if adding groups to an user, check if base.group_user is in it
- (member of 'Employee'), create an employee form linked to it.
- """
+
+ - add field for the related employee of the user
+ - if adding groups to an user, check if base.group_user is in it (member of
+ 'Employee'), create an employee form linked to it. """
_name = 'res.users'
_inherit = ['res.users']
_columns = {
+ 'employee_ids': fields.one2many('hr.employee', 'user_id', 'Related employees'),
'display_employees_suggestions': fields.boolean("Display Employees Suggestions"),
}
</record>
<menuitem
- sequence="35" id="hr.menu_open_view_attendance_reason_new_config" parent="hr.menu_hr_configuration" groups="base.group_hr_attendance" name="Attendance"/>
+ sequence="35" id="hr.menu_open_view_attendance_reason_new_config" parent="hr.menu_hr_configuration" groups="base.group_hr_attendance,base.group_hr_manager" name="Attendance"/>
<menuitem action="open_view_attendance_reason" id="menu_open_view_attendance_reason" parent="hr.menu_open_view_attendance_reason_new_config" groups="base.group_hr_attendance"/>
<record id="hr_attendance_employee" model="ir.ui.view">
##############################################################################
#
# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
+# Copyright (C) 2004-Today OpenERP S.A. (<http://www.openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
+
import time
from openerp.osv import fields, osv
res = {}
obj_contract = self.pool.get('hr.contract')
for emp in self.browse(cr, uid, ids, context=context):
- contract_ids = obj_contract.search(cr, uid, [('employee_id','=',emp.id),], order='date_start', context=context)
+ contract_ids = obj_contract.search(cr, uid, [('employee_id', '=', emp.id)], order='date_start', context=context)
if contract_ids:
res[emp.id] = contract_ids[-1:][0]
else:
'name': fields.char('Contract Type', required=True),
}
+
class hr_contract(osv.osv):
_name = 'hr.contract'
_description = 'Contract'
+ _inherit = ['mail.thread', 'ir.needaction_mixin']
+
+ _track = {
+ 'state': {
+ 'hr_contract.mt_contract_pending': lambda self, cr, uid, obj, ctx=None: obj.state == 'pending',
+ 'hr_contract.mt_contract_close': lambda self, cr, uid, obj, ctx=None: obj.state == 'close',
+ },
+ }
+
_columns = {
'name': fields.char('Contract Reference', required=True),
'employee_id': fields.many2one('hr.employee', "Employee", required=True),
- 'department_id': fields.related('employee_id','department_id', type='many2one', relation='hr.department', string="Department", readonly=True),
+ 'department_id': fields.many2one('hr.department', string="Department"),
'type_id': fields.many2one('hr.contract.type', "Contract Type", required=True),
'job_id': fields.many2one('hr.job', 'Job Title'),
'date_start': fields.date('Start Date', required=True),
'date_end': fields.date('End Date'),
'trial_date_start': fields.date('Trial Start Date'),
'trial_date_end': fields.date('Trial End Date'),
- 'working_hours': fields.many2one('resource.calendar','Working Schedule'),
- 'wage': fields.float('Wage', digits=(16,2), required=True, help="Basic Salary of the employee"),
+ 'working_hours': fields.many2one('resource.calendar', 'Working Schedule'),
+ 'wage': fields.float('Wage', digits=(16, 2), required=True, help="Basic Salary of the employee"),
'advantages': fields.text('Advantages'),
'notes': fields.text('Notes'),
'permit_no': fields.char('Work Permit No', required=False, readonly=False),
'visa_no': fields.char('Visa No', required=False, readonly=False),
'visa_expire': fields.date('Visa Expire Date'),
+ 'state': fields.selection(
+ [('draft', 'New'), ('open', 'Running'), ('pending', 'To Renew'), ('close', 'Expired')],
+ string='Status', track_visibility='onchange',
+ help='Status of the contract'),
}
def _get_type(self, cr, uid, context=None):
_defaults = {
'date_start': lambda *a: time.strftime("%Y-%m-%d"),
- 'type_id': _get_type
+ 'type_id': _get_type,
+ 'state': 'draft',
}
def onchange_employee_id(self, cr, uid, ids, employee_id, context=None):
if not employee_id:
- return {'value': {'job_id': False}}
+ return {'value': {'job_id': False, 'department_id': False}}
emp_obj = self.pool.get('hr.employee').browse(cr, uid, employee_id, context=context)
- job_id = False
+ job_id = dept_id = False
if emp_obj.job_id:
job_id = emp_obj.job_id.id
- return {'value': {'job_id': job_id}}
+ if emp_obj.department_id:
+ dept_id = emp_obj.department_id.id
+ return {'value': {'job_id': job_id, 'department_id': dept_id}}
def _check_dates(self, cr, uid, ids, context=None):
for contract in self.read(cr, uid, ids, ['date_start', 'date_end'], context=context):
- if contract['date_start'] and contract['date_end'] and contract['date_start'] > contract['date_end']:
- return False
+ if contract['date_start'] and contract['date_end'] and contract['date_start'] > contract['date_end']:
+ return False
return True
_constraints = [
(_check_dates, 'Error! Contract start-date must be less than contract end-date.', ['date_start', 'date_end'])
]
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+ def set_as_pending(self, cr, uid, ids, context=None):
+ return self.write(cr, uid, ids, {'state': 'pending'}, context=context)
+
+ def set_as_close(self, cr, uid, ids, context=None):
+ return self.write(cr, uid, ids, {'state': 'close'}, context=context)
<field name="name">Subcontractor</field>
</record>
+ <!-- Contract-related subtypes for messaging / Chatter -->
+ <record id="mt_contract_pending" model="mail.message.subtype">
+ <field name="name">To Renew</field>
+ <field name="res_model">hr.contract</field>
+ <field name="default" eval="True"/>
+ <field name="description">Contract about to expire</field>
+ </record>
+ <record id="mt_contract_close" model="mail.message.subtype">
+ <field name="name">Expired</field>
+ <field name="res_model">hr.contract</field>
+ <field name="default" eval="False"/>
+ <field name="description">Contract expired</field>
+ </record>
+ <!-- Department-related (parent) subtypes for messaging / Chatter -->
+ <record id="mt_department_contract_pending" model="mail.message.subtype">
+ <field name="name">Contract to Renew</field>
+ <field name="res_model">hr.department</field>
+ <field name="default" eval="False"/>
+ <field name="parent_id" eval="ref('mt_contract_pending')"/>
+ <field name="relation_field">department_id</field>
+ <field name="description">Contract about to expire</field>
+ </record>
+
+ <!-- base action rule about "Expiring Soon" contracts -->
+ <record id="contract_open" model="ir.filters">
+ <field name="name">Open Contracts</field>
+ <field name="model_id">hr.contract</field>
+ <field name="domain">[('state', '=', 'open')]</field>
+ <field name="user_id" eval="False"/>
+ </record>
+ <record id="contract_set_as_pending" model="ir.actions.server">
+ <field name="name">HR Contract: set as pending</field>
+ <field name="model_id" ref="model_hr_contract"/>
+ <field name="condition">True</field>
+ <field name="type">ir.actions.server</field>
+ <field name="state">code</field>
+ <field name="code">object.set_as_pending()</field>
+ </record>
+ <record id="rule_contract_1_set_as_pending" model="base.action.rule">
+ <field name="name">HR Contract: check for pending</field>
+ <field name="model_id" ref="model_hr_contract"/>
+ <field name="sequence">50</field>
+ <field name="kind">on_time</field>
+ <field name="filter_id" ref="contract_open"/>
+ <field name="trg_date_id" ref="hr_contract.field_hr_contract_date_end"/>
+ <field name="trg_date_range">-7</field>
+ <field name="trg_date_range_type">day</field>
+ <field name="server_action_ids" eval="[(6, 0, [ref('contract_set_as_pending')])]"/>
+ </record>
+ <record id="rule_contract_2_set_as_pending" model="base.action.rule">
+ <field name="name">HR Contract: check for pending</field>
+ <field name="model_id" ref="model_hr_contract"/>
+ <field name="sequence">51</field>
+ <field name="kind">on_time</field>
+ <field name="filter_id" ref="contract_open"/>
+ <field name="trg_date_id" ref="hr_contract.field_hr_contract_visa_expire"/>
+ <field name="trg_date_range">-60</field>
+ <field name="trg_date_range_type">day</field>
+ <field name="server_action_ids" eval="[(6, 0, [ref('contract_set_as_pending')])]"/>
+ </record>
+ <!-- base action rule about "Expired" contracts -->
+ <record id="contract_set_as_close" model="ir.actions.server">
+ <field name="name">HR Contract: set as close</field>
+ <field name="model_id" ref="model_hr_contract"/>
+ <field name="condition">True</field>
+ <field name="type">ir.actions.server</field>
+ <field name="state">code</field>
+ <field name="code">object.set_as_close()</field>
+ </record>
+ <record id="rule_contract_3_set_as_close" model="base.action.rule">
+ <field name="name">HR Contract: check for close</field>
+ <field name="model_id" ref="model_hr_contract"/>
+ <field name="sequence">52</field>
+ <field name="kind">on_time</field>
+ <field name="trg_date_id" ref="hr_contract.field_hr_contract_date_end"/>
+ <field name="trg_date_range">1</field>
+ <field name="trg_date_range_type">day</field>
+ <field name="server_action_ids" eval="[(6, 0, [ref('contract_set_as_close')])]"/>
+ </record>
+ <record id="rule_contract_4_set_as_close" model="base.action.rule">
+ <field name="name">HR Contract: check for close</field>
+ <field name="model_id" ref="model_hr_contract"/>
+ <field name="sequence">53</field>
+ <field name="kind">on_time</field>
+ <field name="trg_date_id" ref="hr_contract.field_hr_contract_visa_expire"/>
+ <field name="trg_date_range">1</field>
+ <field name="trg_date_range_type">day</field>
+ <field name="server_action_ids" eval="[(6, 0, [ref('contract_set_as_close')])]"/>
+ </record>
+
</data>
</openerp>
<field name="context">{'search_default_employee_id': [active_id], 'default_employee_id': active_id}</field>
</record>
- <menuitem id="next_id_56" name="Contract" parent="hr.menu_hr_configuration" sequence="30" groups="base.group_no_one"/>
+ <menuitem id="next_id_56" name="Contract" parent="hr.menu_hr_configuration" sequence="30" groups="base.group_no_one,base.group_hr_manager"/>
<record id="hr_hr_employee_view_form2" model="ir.ui.view">
<field name="name">hr.hr.employee.view.form2</field>
<field name="model">hr.employee</field>
<field name="model">hr.contract</field>
<field name="arch" type="xml">
<search string="Search Contract">
- <field name="name" string="Contracts"/>
- <field name="date_start"/>
- <field name="date_end"/>
- <field name="working_hours"/>
- <field name="employee_id"/>
- <group expand="0" string="Group By">
- <filter string="Employee" icon="terp-personal" domain="[]" context="{'group_by':'employee_id'}"/>
- <filter string="Working Schedule" icon="terp-go-week" domain="[]" context="{'group_by':'working_hours'}"/>
- <filter string="Job" icon="terp-gtk-select-all" domain="[]" context="{'group_by':'job_id'}"/>
- <filter string="Contract Type" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by':'type_id'}"/>
- </group>
- </search>
+ <field name="name" string="Contracts"/>
+ <field name="date_start"/>
+ <field name="date_end"/>
+ <field name="working_hours"/>
+ <field name="employee_id"/>
+ <field name="department_id"/>
+ <field name="state"/>
+ <filter string="To Renew" name="to_renew" domain="[('state', '=', 'pending')]"/>
+ <separator />
+ <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="Job" domain="[]" context="{'group_by':'job_id'}"/>
+ <filter string="Contract Type" domain="[]" context="{'group_by':'type_id'}"/>
+ </group>
+ </search>
</field>
</record>
<field name="model">hr.contract</field>
<field name="arch" type="xml">
<form string="Contract">
+ <header>
+ <field name="state" widget="statusbar" clickable="1"/>
+ </header>
<sheet>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
<field name="job_id"/>
</group>
<group>
+ <field name="department_id"/>
<field name="type_id"/>
</group>
</group>
</page>
</notebook>
</sheet>
+ <div class="oe_chatter">
+ <field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
+ <field name="message_ids" widget="mail_thread"/>
+ </div>
</form>
</field>
</record>
<field name="name">hr.contract.view.tree</field>
<field name="model">hr.contract</field>
<field name="arch" type="xml">
- <tree string="Contracts">
+ <tree string="Contracts" fonts="bold:message_unread == True">
<field name="name"/>
<field name="employee_id"/>
<field name="type_id"/>
<field name="date_start"/>
<field name="date_end"/>
<field name="wage" invisible="1"/>
+ <field name="message_unread" invisible="1"/>
</tree>
</field>
</record>
##############################################################################
#
# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
+# Copyright (C) 2004-Today OpenERP S.A. (<http://www.openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
class hr_evaluation(osv.Model):
_name = "hr_evaluation.evaluation"
- _inherit = "mail.thread"
+ _inherit = ['mail.thread']
_description = "Employee Appraisal"
_columns = {
'date': fields.date("Appraisal Deadline", required=True, select=True),
('wait', 'Plan In Progress'),
('progress', 'Waiting Appreciation'),
('done', 'Done'),
- ], 'Status', required=True, readonly=True, copy=False),
+ ], 'Status', required=True, readonly=True, track_visibility='onchange', copy=False),
'date_close': fields.date('Ending Date', select=True),
}
_defaults = {
class hr_evaluation_interview(osv.Model):
_name = 'hr.evaluation.interview'
- _inherit = 'mail.thread'
+ _inherit = ['mail.thread']
_rec_name = 'user_to_review_id'
_description = 'Appraisal Interview'
_columns = {
<field eval="'run_employee_evaluation'" name="function" />
<field eval="'(False,)'" name="args" />
</record>
- </data>
-
+ </data>
</openerp>
</record>
<menuitem name="Appraisal" parent="hr.menu_hr_root" id="menu_eval_hr" sequence="25"/>
- <menuitem name="Periodic Appraisal" parent="hr.menu_hr_configuration" id="menu_eval_hr_config" sequence="4"/>
+ <menuitem name="Periodic Appraisal" parent="hr.menu_hr_configuration" id="menu_eval_hr_config" sequence="4" groups="base.group_hr_manager"/>
<menuitem parent="hr.menu_hr_configuration" id="menu_open_view_hr_evaluation_plan_tree"
- action="open_view_hr_evaluation_plan_tree" sequence="15"/>
+ action="open_view_hr_evaluation_plan_tree" sequence="15" groups="base.group_hr_manager"/>
<record model="ir.ui.view" id="view_hr_evaluation_plan_phase_form">
<field name="name">hr_evaluation.plan.phase.form</field>
<field name="name">hr_evaluation.evaluation.tree</field>
<field name="model">hr_evaluation.evaluation</field>
<field name="arch" type="xml">
- <tree colors="blue:state == 'draft';black:state in ('wait','progress');gray:state in('done','cancel')" string="Appraisal">
+ <tree colors="blue:state == 'draft';black:state in ('wait','progress');gray:state in('done','cancel')" string="Appraisal"
+ fonts="bold: message_unread == True">
<field name="employee_id"/>
<field name="plan_id"/>
<field name="date"/>
<field name="rating"/>
<field name="state"/>
+ <field name="message_unread" invisible="1"/>
</tree>
</field>
</record>
<field name="arch" type="xml">
<search string="Search Appraisal">
<field name="date"/>
+ <field name="employee_id"/>
+ <field name="plan_id"/>
<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"/>
- <field name="employee_id" />
- <field name="plan_id"/>
+ <separator/>
+ <filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
<group expand='0' string='Group by...'>
<filter string='Employee' icon="terp-personal" domain="[]" context="{'group_by' : 'employee_id'}" />
<filter string='Plan' icon="terp-stock_align_left_24" domain="[]" context="{'group_by' : 'plan_id'}" />
<field name="name">hr_evaluation.interview.tree</field>
<field name="model">hr.evaluation.interview</field>
<field name="arch" type="xml">
- <tree string="Interview Appraisal">
+ <tree string="Interview Appraisal" fonts="bold: message_unread == True">
<field name="deadline" string="Deadline Date"/>
<field name="survey_id" domain="[('res_model','=','hr_evaluation')]"/>
<field name="user_id" string="Interviewer"/>
<button name="action_print_survey" string="Print Survey" type="object" icon="gtk-print" attrs="{'readonly':[('survey_id','=',False)]}"/>
<button name="%(mail.action_email_compose_message_wizard)d" string="Send Reminder Email" icon="terp-mail-message-new" type="action" states="waiting_answer"/>
<field name="state"/>
+ <field name="message_unread" invisible="1"/>
<button string="Send Request" name="survey_req_waiting_answer" states="draft" type="object" icon="gtk-yes" />
<button string="Done" name="survey_req_done" states="waiting_answer" type="object" icon="gtk-jump-to" />
</tree>
<field name="model">hr.evaluation.interview</field>
<field name="arch" type="xml">
<search string="Search Appraisal">
- <field name="deadline"/>
- <filter icon="terp-gtk-go-back-rtl" string="To Do" name="todo" domain="[('state','=','waiting_answer')]"/>
<field name="user_to_review_id"/>
<field name="user_id" string="Interviewer"/>
+ <field name="deadline"/>
+ <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)]"/>
<group expand="0" string="Group By">
<filter string="Interviewer" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
<filter string="Survey" icon="terp-stock_align_left_24" domain="[]" context="{'group_by':'survey_id'}"/>
return user.company_id.currency_id.id
_name = "hr.expense.expense"
- _inherit = ['mail.thread']
+ _inherit = ['mail.thread', 'ir.needaction_mixin']
_description = "Expense"
_order = "id desc"
_track = {
'id': fields.integer('Sheet ID', readonly=True),
'date': fields.date('Date', select=True, readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
'journal_id': fields.many2one('account.journal', 'Force Journal', help = "The journal used when the expense is done."),
+ 'employee_payable_account_id': fields.many2one('account.account', 'Employee Account', help="Employee payable account"),
'employee_id': fields.many2one('hr.employee', "Employee", required=True, readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
'user_id': fields.many2one('res.users', 'User', required=True),
'date_confirm': fields.date('Confirmation Date', select=True, copy=False,
help="Date of the acceptation of the sheet expense. It's filled when the button Accept is pressed."),
'user_valid': fields.many2one('res.users', 'Validation By', readonly=True, copy=False,
states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
- 'account_move_id': fields.many2one('account.move', 'Ledger Posting', copy=False),
+ 'account_move_id': fields.many2one('account.move', 'Ledger Posting', copy=False, track_visibility="onchange"),
'line_ids': fields.one2many('hr.expense.line', 'expense_id', 'Expense Lines', copy=True,
readonly=True, states={'draft':[('readonly',False)]} ),
'note': fields.text('Note'),
def onchange_employee_id(self, cr, uid, ids, employee_id, context=None):
emp_obj = self.pool.get('hr.employee')
department_id = False
+ employee_payable_account_id = False
company_id = False
if employee_id:
employee = emp_obj.browse(cr, uid, employee_id, context=context)
department_id = employee.department_id.id
company_id = employee.company_id.id
- return {'value': {'department_id': department_id, 'company_id': company_id}}
+ if employee.address_home_id and employee.address_home_id.property_account_payable:
+ employee_payable_account_id = employee.address_home_id.property_account_payable.id
+ return {'value': {'department_id': department_id, 'company_id': company_id, 'employee_payable_account_id': employee_payable_account_id}}
def expense_confirm(self, cr, uid, ids, context=None):
for expense in self.browse(cr, uid, ids):
+ if not expense.line_ids:
+ raise osv.except_osv(_('Error!'),_('You cannot submit expense which has no expense line.'))
if expense.employee_id and expense.employee_id.parent_id.user_id:
self.message_subscribe_users(cr, uid, [expense.id], user_ids=[expense.employee_id.parent_id.user_id.id])
return self.write(cr, uid, ids, {'state': 'confirm', 'date_confirm': time.strftime('%Y-%m-%d')}, context=context)
'''
move_obj = self.pool.get('account.move')
for exp in self.browse(cr, uid, ids, context=context):
- if not exp.employee_id.address_home_id:
- raise osv.except_osv(_('Error!'), _('The employee must have a home address.'))
- if not exp.employee_id.address_home_id.property_account_payable.id:
- raise osv.except_osv(_('Error!'), _('The employee must have a payable account set on his home address.'))
+ if not exp.employee_payable_account_id:
+ raise osv.except_osv(_('Error!'), _('No employee account payable found for the expense '))
+
company_currency = exp.company_id.currency_id.id
- diff_currency_p = exp.currency_id.id <> company_currency
-
+ diff_currency_p = exp.currency_id.id != company_currency
+
#create the move that will contain the accounting entries
move_id = move_obj.create(cr, uid, self.account_move_get(cr, uid, exp.id, context=context), context=context)
-
+
#one account.move.line per expense line (+taxes..)
eml = self.move_line_get(cr, uid, exp.id, context=context)
-
+
#create one more move line, a counterline for the total on payable account
total, total_currency, eml = self.compute_expense_totals(cr, uid, exp, company_currency, exp.name, eml, context=context)
- acc = exp.employee_id.address_home_id.property_account_payable.id
+
+ acc = exp.employee_payable_account_id.id or False
eml.append({
'type': 'dest',
'name': '/',
})
#convert eml into an osv-valid format
- lines = map(lambda x:(0,0,self.line_get_convert(cr, uid, x, exp.employee_id.address_home_id, exp.date_confirm, context=context)), eml)
+ lines = map(lambda x:(0,0,self.line_get_convert(cr, uid, x, exp.employee_id.company_id.partner_id, exp.date_confirm, context=context)), eml)
journal_id = move_obj.browse(cr, uid, move_id, context).journal_id
# post the journal entry if 'Skip 'Draft' State for Manual Entries' is checked
if journal_id.entry_posted:
<record id="mt_expense_approved" model="mail.message.subtype">
<field name="name">Approved</field>
<field name="res_model">hr.expense.expense</field>
+ <field name="default" eval="False"/>
<field name="description">Expense approved</field>
</record>
<record id="mt_expense_refused" model="mail.message.subtype">
<field name="name">Refused</field>
<field name="res_model">hr.expense.expense</field>
+ <field name="default" eval="False"/>
<field name="description">Expense refused</field>
</record>
<record id="mt_expense_confirmed" model="mail.message.subtype">
<field name="name">To Approve</field>
<field name="res_model">hr.expense.expense</field>
<field name="description">Expense confirmed, waiting confirmation</field>
+ <field name="default" eval="True"/>
+ </record>
+ <!-- Department (Parent) related subtypes for messaging / Chatter -->
+ <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="parent_id" eval="ref('mt_expense_confirmed')"/>
+ <field name="relation_field">department_id</field>
+ <field name="sequence" eval="10"/>
</record>
</data>
<field name="name">hr.expense.expense.tree</field>
<field name="model">hr.expense.expense</field>
<field name="arch" type="xml">
- <tree string="Expenses" colors="blue:state=='draft'">
+ <tree string="Expenses" colors="blue:state=='draft'" fonts="bold: message_unread == True">
<field name="employee_id"/>
<field name="department_id" invisible="1"/>
<field name="date"/>
<field name="user_id" invisible="1"/>
- <field name="name"/>
+ <field name="name" string="Expense Sheet"/>
<field name="currency_id" groups="base.group_multi_currency"/>
<field name="amount" sum="Total Amount"/>
<field name="state"/>
+ <field name="message_unread" invisible="1"/>
</tree>
</field>
</record>
<field name="employee_id"/>
<field name="date"/>
<field name="department_id"/>
- <field name="name"/>
+ <field name="name" string="Expense Sheet"/>
<field name="amount"/>
<field name="state"/>
<button name="confirm" states="draft" string="Confirm" type="workflow" icon="gtk-apply"/>
<field name="company_id" groups="base.group_multi_company"/>
</group>
<group>
- <field name="name"/>
+ <field name="name" string="Expense Sheet" placeholder="e.g. Business travel at Chicago"/>
<field name="user_valid" attrs="{'invisible': [('state','=','draft')]}" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'base.group_hr_user']}"/>
<field name="currency_id" groups="base.group_multi_currency" on_change="onchange_currency_id(currency_id, company_id)"/>
</group>
+ <group>
+ <field name="journal_id" widget="selection" attrs="{'readonly':[('state','=','done')]}" domain="[('type', '=', 'purchase')]" string="Journal" groups="account.group_account_user"/>
+ <field name="employee_payable_account_id" widget="selection" attrs="{'readonly':[('state','=','done')]}" domain="[('type', '=', 'payable')]" groups="account.group_account_user"/>
+ </group>
+ <group>
+ <label class="oe_grey" groups="account.group_account_user" string="If this field is empty, entries will be generated in the purchase journal."/>
+ </group>
</group>
<notebook>
- <page string="Description">
+ <page string="Expense Lines">
<field name="line_ids" context="{'currency_id': currency_id, 'default_analytic_account': context.get('analytic_account', '')}">
<form string="Expense Lines">
<group>
<field name="sequence" invisible="1"/>
<field name="product_id" on_change="onchange_product_id(product_id, context)" context="{'default_hr_expense_ok':1}"/>
<field name="date_value" string="Expense Date"/>
- <field name="name"/>
+ <field name="name" string="Description"/>
<field name="ref"/>
<field domain="[('type','in',['normal','contract'])]" name="analytic_account" groups="analytic.group_analytic_accounting"/>
<field name="uom_id" on_change="onchange_uom(product_id, uom_id, context)"/>
</field>
<group>
<div>
- <separator string="Notes"/>
+ <separator string="Description"/>
<field name="note" placeholder="Free Notes"/>
</div>
<group class="oe_subtotal_footer oe_right">
</group>
</group>
</page>
- <page string="Accounting" groups="account.group_account_user">
- <group>
- <group string="Accounting Data">
- <field name="journal_id" widget="selection" domain="[('type', '=', 'purchase')]"/>
- <field name="account_move_id"/>
- </group>
- </group>
- </page>
</notebook>
</sheet>
<div class="oe_chatter">
<search string="Expense">
<field name="name" string="Expenses"/>
<field name="date"/>
- <filter icon="terp-document-new" domain="[('state','=','draft')]" string="New" help="New Expense"/>
- <filter icon="terp-camera_test" domain="[('state','=','confirm')]" string="To Approve" help="Confirmed Expenses"/>
- <filter icon="terp-dolar" domain="['|',('state','=','accepted'),('state','=','done')]" string="To Pay" help="Expenses to Invoice"/>
- <separator/>
- <filter domain="[('user_id', '=', uid)]" string="My Expenses"/>
<field name="employee_id"/>
<field name="department_id" 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"/>
+ <separator />
+ <filter domain="[('user_id', '=', uid)]" string="My Expenses"/>
+ <separator />
+ <filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
<group expand="0" string="Group By">
- <filter string="Employee" icon="terp-personal" domain="[]" context="{'group_by':'employee_id'}"/>
- <filter string="Department" icon="terp-personal+" domain="[]" context="{'group_by':'department_id'}"/>
- <filter string="Expenses Month" icon="terp-go-month" domain="[]" context="{'group_by':'date'}" help="Expenses by Month"/>
+ <filter string="Employee" domain="[]" context="{'group_by':'employee_id'}"/>
+ <filter string="Department" domain="[]" context="{'group_by':'department_id'}"/>
+ <filter string="Expenses Month" domain="[]" context="{'group_by':'date'}" help="Expenses by Month"/>
</group>
</search>
</field>
</field>
</record>
-
<record id="view_product_hr_expense_form" model="ir.ui.view">
<field name="name">product.template.expense.form</field>
<field name="model">product.template</field>
</field>
</record>
- <menuitem id="menu_hr_product" name="Expense Categories" parent="hr.menu_hr_configuration" action="hr_expense_product"/>
+ <record id="action_approved_expense" model="ir.actions.act_window">
+ <field name="name">Expenses</field>
+ <field name="res_model">hr.expense.expense</field>
+ <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>
+ </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>
+ <field name="view_type">form</field>
+ <field name="context">{'search_default_confirm':1, 'needaction_menu_ref': 'hr_expense.menu_expense_all'}</field>
+ <field name="search_view_id" ref="view_hr_expense_filter"/>
+ <field name="view_id" ref="view_expenses_tree"/>
+ <field name="help" type="html">
+ <p class="oe_view_nocontent_create">
+ 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
+ from his expenses, some expenses must be re-invoiced to the
+ customers.
+ </p>
+ </field>
+ </record>
+
+ <menuitem id="menu_expense_approved" parent="account.menu_finance_payables" action="action_approved_expense" sequence="101"/>
+ <menuitem id="menu_hr_product" name="Expense Categories" parent="hr.menu_hr_configuration" 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"/>
+
</data>
</openerp>
#
##############################################################################
+
+import calendar
import datetime
+from datetime import date
import math
import time
from operator import attrgetter
_inherit = ['mail.thread', 'ir.needaction_mixin']
_track = {
'state': {
+ 'hr_holidays.mt_holidays_confirmed': lambda self, cr, uid, obj, ctx=None: obj.state == 'confirm',
+ 'hr_holidays.mt_holidays_first_validated': lambda self, cr, uid, obj, ctx=None: obj.state == 'validate1',
'hr_holidays.mt_holidays_approved': lambda self, cr, uid, obj, ctx=None: obj.state == 'validate',
'hr_holidays.mt_holidays_refused': lambda self, cr, uid, obj, ctx=None: obj.state == 'refuse',
- 'hr_holidays.mt_holidays_confirmed': lambda self, cr, uid, obj, ctx=None: obj.state == 'confirm',
},
}
- def _employee_get(self, cr, uid, context=None):
+ def _employee_get(self, cr, uid, context=None):
emp_id = context.get('default_employee_id', False)
if emp_id:
return emp_id
\nThe status is \'To Approve\', when holiday request is confirmed by user.\
\nThe status is \'Refused\', when holiday request is refused by manager.\
\nThe status is \'Approved\', when holiday request is approved by manager.'),
+ 'payslip_status': fields.boolean(string='Payslip Status',
+ help='Check this field when the leave has been taken into account in the payslip.'),
+ 'report_note': fields.text('Comment by Manager'),
'user_id':fields.related('employee_id', 'user_id', type='many2one', relation='res.users', string='User', store=True),
'date_from': fields.datetime('Start Date', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}, select=True, copy=False),
'date_to': fields.datetime('End Date', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}, copy=False),
'state': 'confirm',
'type': 'remove',
'user_id': lambda obj, cr, uid, context: uid,
- 'holiday_type': 'employee'
+ 'holiday_type': 'employee',
+ 'payslip_status': False,
}
_constraints = [
(_check_date, 'You can not have 2 leaves that overlaps on same day!', ['date_from','date_to']),
"""
Update the number_of_days.
"""
-
# date_to has to be greater than date_from
if (date_from and date_to) and (date_from > date_to):
raise osv.except_osv(_('Warning!'),_('The start date must be anterior to the end date.'))
result['value']['number_of_days_temp'] = round(math.floor(diff_day))+1
else:
result['value']['number_of_days_temp'] = 0
-
return result
def create(self, cr, uid, values, context=None):
obj_emp = self.pool.get('hr.employee')
ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)])
manager = ids2 and ids2[0] or False
- self.holidays_first_validate_notificate(cr, uid, ids, context=context)
- return self.write(cr, uid, ids, {'state':'validate1', 'manager_id': manager})
+ return self.write(cr, uid, ids, {'state': 'validate1', 'manager_id': manager}, context=context)
def holidays_validate(self, cr, uid, ids, context=None):
obj_emp = self.pool.get('hr.employee')
ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)])
manager = ids2 and ids2[0] or False
- self.write(cr, uid, ids, {'state':'validate'})
+ self.write(cr, uid, ids, {'state': 'validate'}, context=context)
data_holiday = self.browse(cr, uid, ids)
for record in data_holiday:
if record.double_validation:
'Please verify also the leaves waiting for validation.'))
return True
- # -----------------------------
- # OpenChatter and notifications
- # -----------------------------
+ def set_payslip_status(self, cr, uid, ids, context=None):
+ return self.write(cr, uid, ids, {'payslip_status': True}, context=context)
- def _needaction_domain_get(self, cr, uid, context=None):
- emp_obj = self.pool.get('hr.employee')
- empids = emp_obj.search(cr, uid, [('parent_id.user_id', '=', uid)], context=context)
- dom = ['&', ('state', '=', 'confirm'), ('employee_id', 'in', empids)]
- # if this user is a hr.manager, he should do second validations
- if self.pool.get('res.users').has_group(cr, uid, 'base.group_hr_manager'):
- dom = ['|'] + dom + [('state', '=', 'validate1')]
- return dom
+ def unset_payslip_status(self, cr, uid, ids, context=None):
+ return self.write(cr, uid, ids, {'payslip_status': False}, context=context)
- def holidays_first_validate_notificate(self, cr, uid, ids, context=None):
- for obj in self.browse(cr, uid, ids, context=context):
- self.message_post(cr, uid, [obj.id],
- _("Request approved, waiting second validation."), context=context)
class resource_calendar_leaves(osv.osv):
_inherit = "resource.calendar.leaves"
}
-
-class hr_employee(osv.osv):
- _inherit="hr.employee"
+class hr_employee(osv.Model):
+ _inherit = "hr.employee"
def create(self, cr, uid, vals, context=None):
# don't pass the value of remaining leave if it's 0 at the creation time, otherwise it will trigger the inverse
return result
def _leaves_count(self, cr, uid, ids, field_name, arg, context=None):
+ res = {}
Holidays = self.pool['hr.holidays']
- return {
- employee_id: Holidays.search_count(cr,uid, [('employee_id', '=', employee_id)], context=context)
- for employee_id in ids
- }
+ date_begin = date.today().replace(day=1)
+ date_end = date_begin.replace(day=calendar.monthrange(date_begin.year, date_begin.month)[1])
+ for employee_id in ids:
+ leaves = Holidays.search_count(cr, uid, [('employee_id', '=', employee_id), ('type', '=', 'remove')], context=context)
+ approved_leaves = Holidays.search_count(cr, uid, [('employee_id', '=', employee_id), ('type', '=', 'remove'), ('date_from', '>=', date_begin.strftime(tools.DEFAULT_SERVER_DATE_FORMAT)), ('date_from', '<=', date_end.strftime(tools.DEFAULT_SERVER_DATE_FORMAT)), ('state', '=', 'validate'), ('payslip_status', '=', False)], context=context)
+ res[employee_id] = {'leaves_count': leaves, 'approved_leaves_count': approved_leaves}
+ return res
_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(_get_leave_status, multi="leave_status", string="Current Leave Status", type="selection",
+ 'current_leave_state': fields.function(
+ _get_leave_status, multi="leave_status", string="Current Leave Status", type="selection",
selection=[('draft', 'New'), ('confirm', 'Waiting Approval'), ('refuse', 'Refused'),
- ('validate1', 'Waiting Second Approval'), ('validate', 'Approved'), ('cancel', 'Cancelled')]),
- 'current_leave_id': fields.function(_get_leave_status, multi="leave_status", string="Current Leave Type",type='many2one', relation='hr.holidays.status'),
+ ('validate1', 'Waiting Second Approval'), ('validate', 'Approved'), ('cancel', 'Cancelled')]),
+ 'current_leave_id': fields.function(_get_leave_status, multi="leave_status", string="Current Leave Type", type='many2one', relation='hr.holidays.status'),
'leave_date_from': fields.function(_get_leave_status, multi='leave_status', type='date', string='From Date'),
'leave_date_to': fields.function(_get_leave_status, multi='leave_status', type='date', string='To Date'),
- 'leaves_count': fields.function(_leaves_count, type='integer', string='Leaves'),
-
+ '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"),
}
-
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<?xml version="1.0"?>
<openerp>
<data noupdate="1">
+
<!-- After installation of the module, open the related menu -->
<record id="base.open_menu" model="ir.actions.todo">
<field name="action_id" ref="hr.action_client_hr_menu"/>
<!-- Holidays-related subtypes for messaging / Chatter -->
<record id="mt_holidays_confirmed" model="mail.message.subtype">
- <field name="name">To Approve</field>
+ <field name="name">Confirmed</field>
+ <field name="res_model">hr.holidays</field>
+ <field name="description">Request created and waiting confirmation</field>
+ </record>
+ <record id="mt_holidays_first_validated" model="mail.message.subtype">
+ <field name="name">Waiting Second Validation</field>
<field name="res_model">hr.holidays</field>
- <field name="description">Request confirmed and waiting approval</field>
+ <field name="default" eval="False"/>
+ <field name="description">Request validated, waiting second validation</field>
</record>
<record id="mt_holidays_approved" model="mail.message.subtype">
<field name="name">Approved</field>
<field name="description">Request refused</field>
</record>
+ <!-- Department related subtypes for messaging / Chatter -->
+ <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="parent_id" eval="ref('mt_holidays_confirmed')"/>
+ <field name="relation_field">department_id</field>
+ <field name="sequence" eval="6"/>
+ </record>
+ <record id="mt_department_holidays_first_validated" model="mail.message.subtype">
+ <field name="name">Leaves/Allocations: second approval</field>
+ <field name="res_model">hr.department</field>
+ <field name="default" eval="False"/>
+ <field name="parent_id" eval="ref('mt_holidays_first_validated')"/>
+ <field name="relation_field">department_id</field>
+ <field name="sequence" eval="7"/>
+ </record>
+ <record id="mt_department_holidays_approved" model="mail.message.subtype">
+ <field name="name">Leaves/Allocation Approved</field>
+ <field name="res_model">hr.department</field>
+ <field name="default" eval="False"/>
+ <field name="parent_id" eval="ref('mt_holidays_approved')"/>
+ <field name="relation_field">department_id</field>
+ <field name="sequence" eval="8"/>
+ </record>
+ <record id="mt_department_holidays_refused" model="mail.message.subtype">
+ <field name="name">Leaves/Allocation Refused</field>
+ <field name="res_model">hr.department</field>
+ <field name="default" eval="False"/>
+ <field name="parent_id" eval="ref('mt_holidays_refused')"/>
+ <field name="relation_field">department_id</field>
+ <field name="sequence" eval="9"/>
+ </record>
+
</data>
</openerp>
<field name="arch" type="xml">
<search string="Search Leave">
<field name="name"/>
+ <filter domain="[('state','=','draft')]" string="To Confirm"/>
+ <filter domain="[('state','in',('confirm','validate1'))]" string="To Approve" name="approve"/>
+ <filter domain="[('state','=','validate')]" string="Validated" name="validated"/>
<separator/>
- <filter icon="terp-check" domain="[('state','=','draft')]" string="To Confirm"/>
- <filter icon="terp-camera_test" domain="[('state','in',('confirm','validate1'))]" string="To Approve" name="approve"/>
- <filter icon="terp-camera_test" domain="[('state','=','validate')]" string="Validated" name="validated"/>
+ <filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
+ <separator/>
+ <filter string="Approved Leaves" name="validated" domain="[('state','=','validate')]"/>
+ <separator/>
+ <filter string="To Report in Payslip" name="gray" domain="[('payslip_status', '=', False)]" groups="base.group_hr_manager"/>
<separator/>
<filter icon="terp-go-year" name="year" string="Year" domain="[('holiday_status_id.active','=',True)]" help="Filters only on allocations and requests that belong to an holiday type that is 'active' (active field is True)"/>
<separator/>
<field name="employee_id" attrs="{'required':[('holiday_type','=','employee')],'invisible':[('holiday_type','=','category')]}" on_change="onchange_employee(employee_id)" groups="base.group_hr_user"/>
<field name="category_id" attrs="{'required':[('holiday_type','=','category')], 'readonly': [('type', '=', 'remove'),('state','!=','draft'), ('state','!=','confirm')], 'invisible':[('holiday_type','=','employee')]}"/>
<field name="department_id" attrs="{'readonly':['|', ('type','=','add'),('holiday_type','=','category')],'invisible':[('holiday_type','=','category')]}" groups="base.group_hr_user"/>
+ <field name="payslip_status" groups="base.group_hr_manager" attrs="{'invisible':[('type','=','add')]}"/>
</group>
+ <field name="notes" nolabel="1" colspan="4" placeholder="Add a reason..." attrs="{'invisible': [('type', '=', 'remove')]}"/>
+ <div groups="base.group_hr_manager" attrs="{'invisible':[('type','=','add')]}">
+ <separator string="Comment by Manager"/>
+ <field name="report_note" placeholder="e.g. Report to the next month..."/>
+ </div>
</group>
- <field name="notes" nolabel="1" colspan="4" placeholder="Add a reason..." attrs="{'invisible': [('type', '=', 'remove')]}"/>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="name">hr.holidays.allocation.tree</field>
<field name="model">hr.holidays</field>
<field name="arch" type="xml">
- <tree colors="red:state == 'refuse';blue:state == 'draft';black:state in ('confirm','validate','validate1')" string="Allocation Requests">
+ <tree colors="red:state == 'refuse';blue:state == 'draft';black:state in ('confirm','validate','validate1')" string="Allocation Requests"
+ fonts="bold: message_unread == True">
<field name="employee_id"/>
<field name="holiday_type"/>
<field name="category_id"/>
<field name="manager_id" invisible="1"/>
<field name="user_id" invisible="1"/>
<field name="date_from" invisible="1"/>
- <!--field name="type"/-->
+ <field name="message_unread" invisible="1"/>
<field name="state"/>
</tree>
</field>
</record>
-
- <!-- Holidays: Leaves Management -->
- <record model="ir.ui.view" id="allocation_company_new">
- <field name="name">Leaves Management</field>
+ <record model="ir.ui.view" id="view_holiday_allocation_tree_customize">
+ <field name="name">hr.holidays.allocation.tree.customize</field>
<field name="model">hr.holidays</field>
<field name="arch" type="xml">
- <form string="Leaves Management">
- <header>
- <button string="Submit to Manager" name="confirm" states="draft" type="workflow" icon="gtk-yes"/>
- <button string="Approve" name="validate" states="confirm" type="workflow" icon="gtk-apply"/>
- <button string="Refuse" name="refuse" states="confirm,validate,draft" type="workflow" icon="gtk-no"/>
- <button string="Reset to Draft" name="reset" states="confirm" type="workflow" groups="base.group_hr_manager"/>
- <field name="state"/>
- </header>
- <group col="4">
- <field name="holiday_status_id"/>
- <field name="type"/>
- <field name="date_from" on_change="onchange_date_from(date_to, date_from)" attrs="{'readonly':[('type','=','add')], 'required':[('type','=','remove')]}"/>
- <field name="date_to" on_change="onchange_date_from(date_to, date_from)" attrs="{'readonly':[('type','=','add')], 'required':[('type','=','remove')]}"/>
- <field name="number_of_days_temp"/>
- <field name="manager_id"/>
- </group>
- <field name="name" placeholder="Add a reason..."/>
- </form>
+ <tree string="Allocation Requests" editable="top">
+ <field name="employee_id"/>
+ <field name="holiday_type"/>
+ <field name="holiday_status_id"/>
+ <field name="name" readonly="1"/>
+ <field name="date_from" required="1" on_change="onchange_date_from(date_to, date_from)"/>
+ <field name="date_to" required="1" on_change="onchange_date_to(date_to, date_from)"/>
+ <field name="number_of_days_temp" string="Allocated Days" sum="Remaining Days"/>
+ <field name="state"/>
+ <field name="report_note" groups="base.group_hr_manager"/>
+ <field name="payslip_status" invisible="1"/>
+ <button string="To Report in Payslip" name="set_payslip_status"
+ type="object" class="oe_link oe_right" icon="gtk-normal"
+ attrs="{'invisible': [('payslip_status', '=', True)]}" groups="base.group_hr_manager"/>
+ <button string="Reported in last payslips" name="unset_payslip_status"
+ type="object" class="oe_link oe_right" icon="gtk-yes"
+ attrs="{'invisible': [('payslip_status', '=', False)]}" groups="base.group_hr_manager"/>
+ </tree>
</field>
</record>
<field name="model">hr.holidays</field>
<field name="priority">20</field>
<field name="arch" type="xml">
- <tree colors="red:state == 'refuse';blue:state == ' draft';black:state in ('confirm','validate','validate1')" string="Leaves Summary">
+ <tree colors="red:state == 'refuse';blue:state == 'draft';black:state in ('confirm','validate','validate1')" string="Leaves Summary">
<field name="employee_id"/>
<field name="category_id" invisible="1"/>
<field name="department_id" invisible="1"/>
</field>
</record>
+ <record model="ir.ui.view" id="view_holiday_employee">
+ <field name="name">hr.holidays.report_employee_tree</field>
+ <field name="model">hr.holidays</field>
+ <field name="priority">21</field>
+ <field name="arch" type="xml">
+ <tree colors="red:state == 'refuse';blue:state == 'draft';black:state in ('confirm','validate','validate1')" string="Employee's Leave">
+ <field name="employee_id"/>
+ <field name="type"/>
+ <field name="name"/>
+ <field name="number_of_days" string="Number of Days" sum="Remaining Days"/>
+ <field name="date_from"/>
+ <field name="date_to"/>
+ <field name="holiday_status_id"/>
+ <field name="state"/>
+ <field name="report_note"/>
+ <field name="payslip_status" invisible="1"/>
+ <button string="To Report in Payslip" name="set_payslip_status"
+ type="object" class="oe_link oe_right"
+ attrs="{'invisible': [('payslip_status', '=', True)]}" groups="base.group_hr_manager"/>
+ <button string="Reported in last payslips" name="unset_payslip_status"
+ type="object" class="oe_link oe_right"
+ attrs="{'invisible': [('payslip_status', '=', False)]}" groups="base.group_hr_manager"/>
+ </tree>
+ </field>
+ </record>
+
<record model="ir.ui.view" id="view_holiday">
<field name="name">hr.holidays.tree</field>
<field name="model">hr.holidays</field>
<field name="arch" type="xml">
- <tree colors="red:state == 'refuse';blue:state == ' draft';black:state in ('confirm','validate','validate1')" string="Leave Requests">
+ <tree colors="red:state == 'refuse';blue:state == ' draft';black:state in ('confirm','validate','validate1')" string="Leave Requests"
+ fonts="bold: message_unread == True">
<field name="employee_id"/>
<field name="holiday_type" string="Mode" groups="base.group_no_one"/>
<field name="holiday_status_id"/>
<field name="date_to"/>
<field name="number_of_days" string="Number of Days" sum="Remaining Days"/>
<field name="state"/>
+ <field name="payslip_status" invisible="1"/>
+ <button string="To Report in Payslip" name="set_payslip_status"
+ type="object" class="oe_link oe_right"
+ attrs="{'invisible': [('payslip_status', '=', True)]}" groups="base.group_hr_manager"/>
+ <button string="Reported in last payslips" name="unset_payslip_status"
+ type="object" class="oe_link oe_right"
+ attrs="{'invisible': [('payslip_status', '=', False)]}" groups="base.group_hr_manager"/>
<field name="category_id" invisible="1"/>
<field name="department_id" invisible="not context.get('set_visible',False)"/>
<field name="manager_id" invisible="1"/>
<field name="user_id" invisible="1"/>
+ <field name="message_unread" invisible="1"/>
</tree>
</field>
</record>
<field name="res_model">hr.holidays</field>
<field name="view_type">form</field>
<field name="view_id" ref="edit_holiday_new"/>
- <field name="context">{'default_type': 'remove', 'search_default_my_leaves':1}</field>
- <field name="domain">[('type','=','remove')]</field>
+ <field name="context">{
+ 'default_type': 'remove',
+ 'search_default_my_leaves':1,
+ 'needaction_menu_ref':
+ [
+ 'hr_holidays.menu_open_company_allocation',
+ ]
+ }</field>
+ <field name="domain">[('type','=','remove'), ('employee_id.user_id','=', uid)]</field>
<field name="search_view_id" ref="view_hr_holidays_filter"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
<field name="name">Requests to Approve</field>
<field name="res_model">hr.holidays</field>
<field name="view_type">form</field>
- <field name="context">{'default_type': 'remove', 'search_default_approve':1}</field>
+ <field name="context">{
+ '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_employee_leave',
+ ]
+ }</field>
<field name="domain">[('type','=','remove')]</field>
<field name="view_id" ref="edit_holiday_new"/>
<field name="search_view_id" ref="view_hr_holidays_filter"/>
<field name="name">Allocation Requests</field>
<field name="res_model">hr.holidays</field>
<field name="view_type">form</field>
- <field name="context">{'default_type':'add', 'search_default_my_leaves':1}</field>
- <field name="domain">[('type','=','add')]</field>
+ <field name="context">{
+ 'default_type':'add',
+ 'search_default_my_leaves':1,
+ 'needaction_menu_ref':
+ [
+ 'hr_holidays.menu_open_company_allocation',
+ ]
+ }</field>
+ <field name="domain">[('type','=','add'), ('employee_id.user_id','=', uid)]</field>
<field name="view_id" ref="edit_holiday_new"/>
<field name="search_view_id" ref="view_hr_holidays_filter"/>
</record>
<field name="name">Allocation Requests to Approve</field>
<field name="res_model">hr.holidays</field>
<field name="view_type">form</field>
- <field name="context">{'default_type': 'add', 'search_default_approve':1}</field>
+ <field name="context">{
+ 'default_type': 'add',
+ 'search_default_approve':1,
+ 'needaction_menu_ref':
+ [
+ 'hr_holidays.menu_open_allocation_holidays',
+ 'hr_holidays.menu_open_company_allocation'
+ ]
+ }</field>
<field name="domain">[('type','=','add')]</field>
<field name="view_id" ref="edit_holiday_new"/>
<field name="search_view_id" ref="view_hr_holidays_filter"/>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" eval="view_holiday_simple"/>
- <field name="context">{'search_default_group_type': 1}</field>
- <field name="domain">[('holiday_type','=','employee'), ('state', '!=', 'refuse')]</field>
+ <field name="context">{
+ 'search_default_group_type': 1,
+ 'search_default_year': 1 ,
+ 'needaction_menu_ref':
+ [
+ 'hr_holidays.menu_open_ask_holidays_new',
+ 'hr_holidays.menu_request_approve_holidays',
+ 'hr_holidays.menu_open_allocation_holidays',
+ 'hr_holidays.menu_request_approve_allocation',
+ 'hr_holidays.menu_open_employee_leave',
+ ]
+ }</field>
+ <field name="domain">[('holiday_type','=','employee')]</field>
<field name="search_view_id" ref="view_hr_holidays_filter"/>
</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>
+ <field name="view_type">form</field>
+ <field name="view_mode">tree,form</field>
+ <field name="view_id" eval="view_holiday_employee"/>
+ <field name="context">{'default_type': 'remove', 'search_default_gray': 1, 'search_default_year': 1, 'search_default_group_employee': 1}</field>
+ <field name="domain">[('type','=','remove')]</field>
+ <field name="search_view_id" ref="view_hr_holidays_filter"/>
+ </record>
+
+ <menuitem name="Employee's Leaves" parent="menu_open_ask_holidays" id="menu_open_employee_leave" groups="base.group_hr_manager,base.group_hr_user" action="open_employee_leaves" sequence="41"/>
<!-- Holidays status -->
<record id="view_holidays_status_filter" model="ir.ui.view">
<field name="search_view_id" ref="view_hr_holidays_status_search"/>
</record>
- <menuitem sequence="3" id="hr.menu_open_view_attendance_reason_config" parent="hr.menu_hr_configuration" name="Leaves"/>
- <menuitem name="Leaves Types" action="open_view_holiday_status" id="menu_open_view_holiday_status" parent="hr.menu_hr_configuration" sequence="10"/>
+ <menuitem sequence="3" id="hr.menu_open_view_attendance_reason_config" parent="hr.menu_hr_configuration" name="Leaves" groups="base.group_hr_manager"/>
+ <menuitem name="Leaves Types" action="open_view_holiday_status" id="menu_open_view_holiday_status" parent="hr.menu_hr_configuration" sequence="10" groups="base.group_hr_manager"/>
<!-- Holiday on resource leave -->
<record id="resource_calendar_leave_form_inherit" model="ir.ui.view">
<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>
+ <field name="res_model">hr.holidays</field>
+ <field name="src_model">hr.employee</field>
+ <field name="view_type">form</field>
+ <field name="view_mode">tree,form</field>
+ <field name="context">{'search_default_employee_id': [active_id], 'search_default_validated': True, 'search_default_gray': True}</field>
+ <field name="domain">[('date_from','>=', context_today().strftime("%Y-%m-1")), ('date_from','<', ((context_today() + relativedelta(months=1)).strftime('%Y-%m-1')) )]</field>
+ <field name="view_id" eval="view_holiday_allocation_tree_customize"/>
+ </record>
<!-- Assing leave -->
<record id="hr_holidays_leaves_assign_tree_view" model="ir.ui.view">
</group>
</xpath>
<xpath expr="//div[@name='button_box']" position="inside">
+ <button name="%(act_hr_employee_holiday_request_approved)d"
+ icon="fa-calendar"
+ class="oe_stat_button"
+ type="action"
+ groups="base.group_hr_user">
+ <field name="approved_leaves_count" widget="statinfo"/>
+ </button>
<button name="%(act_hr_employee_holiday_request)d"
- type="action"
- class="oe_stat_button"
- icon="fa-calendar"
- groups="base.group_hr_user">
- <field name="leaves_count" widget="statinfo" string="Leaves"/>
+ type="action"
+ class="oe_stat_button"
+ icon="fa-calendar"
+ groups="base.group_hr_user">
+ <field name="leaves_count" widget="statinfo"/>
</button>
</xpath>
</field>
_inherit = ['mail.thread', 'ir.needaction_mixin']
_track = {
+ 'emp_id': {
+ 'hr_recruitment.mt_applicant_hired': lambda self, cr, uid, obj, ctx=None: obj.emp_id,
+ },
'stage_id': {
# this is only an heuristics; depending on your particular stage configuration it may not match all 'new' stages
'hr_recruitment.mt_applicant_new': lambda self, cr, uid, obj, ctx=None: obj.stage_id and obj.stage_id.sequence <= 1,
'day_close': fields.function(_compute_day, string='Days to Close', \
multi='day_close', type="float", store=True),
'color': fields.integer('Color Index'),
- 'emp_id': fields.many2one('hr.employee', string='Employee', help='Employee linked to the applicant.'),
+ 'emp_id': fields.many2one('hr.employee', string='Employee', track_visibility='onchange', help='Employee linked to the applicant.'),
'user_email': fields.related('user_id', 'email', type='char', string='User Email', readonly=True),
'attachment_number': fields.function(_get_attachment_number, string='Number of Attachments', type="integer"),
}
'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)
job = self.browse(cr, uid, job_id, context=context)
_columns = {
'name': fields.char('Name', required=True, translate=True),
}
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<field name="name">New Applicant</field>
<field name="res_model">hr.applicant</field>
<field name="default" eval="False"/>
+ <field name="hidden" eval="True"/>
<field name="description">Applicant created</field>
</record>
<record id="mt_applicant_stage_changed" model="mail.message.subtype">
<record id="mt_applicant_hired" model="mail.message.subtype">
<field name="name">Applicant Hired</field>
<field name="res_model">hr.applicant</field>
- <field name="default" eval="False"/>
+ <field name="default" eval="True"/>
<field name="description">Applicant hired</field>
</record>
+
<!-- Job-related subtypes for messaging / Chatter -->
<record id="mt_job_applicant_new" model="mail.message.subtype">
<field name="name">Applicant Created</field>
<record id="mt_job_applicant_stage_changed" model="mail.message.subtype">
<field name="name">Applicant Stage Changed</field>
<field name="res_model">hr.job</field>
- <field name="default" eval="True"/>
+ <field name="default" eval="False"/>
<field name="parent_id" eval="ref('mt_applicant_stage_changed')"/>
<field name="relation_field">job_id</field>
</record>
<menuitem name="Recruitment"
id="menu_hr_recruitment_recruitment"
parent="hr.menu_hr_configuration"
+ groups="base.group_hr_manager"
sequence="40"/>
<act_window
class hr_timesheet_sheet(osv.osv):
_name = "hr_timesheet_sheet.sheet"
- _inherit = "mail.thread"
+ _inherit = ['mail.thread', 'ir.needaction_mixin']
_table = 'hr_timesheet_sheet_sheet'
_order = "id desc"
- _description="Timesheet"
+ _description = "Timesheet"
+
+ _track = {
+ 'state': {
+ 'hr_timesheet_sheet.mt_timesheet_confirmed': lambda self, cr, uid, obj, ctx=None: obj.state == 'confirm',
+ 'hr_timesheet_sheet.mt_timesheet_approved': lambda self, cr, uid, obj, ctx=None: obj.state == 'done',
+ },
+ }
def _total(self, cr, uid, ids, name, args, context=None):
""" Compute the attendances, analytic lines timesheets and differences between them
('draft','Open'),
('confirm','Waiting Approval'),
('done','Approved')], 'Status', select=True, required=True, readonly=True,
+ track_visibility='onchange',
help=' * The \'Draft\' status is used when a user is encoding a new and unconfirmed timesheet. \
\n* The \'Confirmed\' status is used for to confirm the timesheet by user. \
\n* The \'Done\' status is used when users timesheet is accepted by his/her senior.'),
<menuitem name="My Current Timesheet" id="menu_act_hr_timesheet_sheet_form_my_current" parent="hr_attendance.menu_hr_time_tracking" action="ir_actions_server_timsheet_sheet" sequence="1"/>
+ <!-- Timesheet sheet related subtypes for messaging / Chatter -->
+ <record id="mt_timesheet_confirmed" model="mail.message.subtype">
+ <field name="name">Waiting Approval</field>
+ <field name="res_model">hr_timesheet_sheet.sheet</field>
+ <field name="default" eval="True"/>
+ <field name="description">waiting approval</field>
+ </record>
+ <record id="mt_timesheet_approved" model="mail.message.subtype">
+ <field name="name">Approved</field>
+ <field name="res_model">hr_timesheet_sheet.sheet</field>
+ <field name="default" eval="True"/>
+ <field name="description">Timesheet approved</field>
+ </record>
+ <!-- Department (Parent) related subtypes for messaging / Chatter -->
+ <record id="mt_department_timesheet_confirmed" model="mail.message.subtype">
+ <field name="name">Timesheets to Approve</field>
+ <field name="res_model">hr.department</field>
+ <field name="default" eval="False"/>
+ <field name="parent_id" eval="ref('mt_timesheet_confirmed')"/>
+ <field name="relation_field">department_id</field>
+ <field name="sequence" eval="5"/>
+ </record>
+ <record id="mt_department_timesheet_approved" model="mail.message.subtype">
+ <field name="name">Timesheets Approved</field>
+ <field name="res_model">hr.department</field>
+ <field name="default" eval="False"/>
+ <field name="parent_id" eval="ref('mt_timesheet_approved')"/>
+ <field name="relation_field">department_id</field>
+ <field name="sequence" eval="5"/>
+ </record>
+
</data>
</openerp>
</notebook>
</sheet>
<div class="oe_chatter">
- <field name="message_ids" widget="mail_thread"/>
<field name="message_follower_ids" widget="mail_followers"/>
+ <field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
<field name="date_from"/>
<filter name="new" string="In Draft" domain="[('state','in',('draft', 'new'))]" help="Unvalidated Timesheets"/>
<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"/>
<group expand="0" string="Group By">
</record>
<record id="act_hr_timesheet_sheet_form" model="ir.actions.act_window">
- <field name="name">Timesheets to Validate</field>
+ <field name="name">Timesheets to Approve</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">hr_timesheet_sheet.sheet</field>
<field name="view_type">form</field>
</record>
<menuitem action="act_hr_timesheet_sheet_form" id="menu_act_hr_timesheet_sheet_form" parent="hr_attendance.menu_hr_time_tracking"
- sequence="2" groups="base.group_hr_user"/>
+ sequence="11" groups="base.group_hr_user"/>
<!--
Company inheritancy
<field name="model">hr_timesheet_sheet.sheet</field>
<field eval="10" name="priority"/>
<field name="arch" type="xml">
- <tree colors="blue:state == 'draft';black:state in ('confirm','new');gray:state == 'done'" string="Timesheets">
+ <tree colors="blue:state == 'draft';black:state in ('confirm','new');gray:state == 'done'" fonts="bold: message_unread == True" string="Timesheets">
<field name="employee_id"/>
<field name="date_from"/>
<field name="date_to"/>
<field name="total_timesheet" widget="float_time"/>
<field name="total_difference" widget="float_time" groups="base.group_hr_attendance"/>
<field name="state"/>
+ <field name="message_unread" invisible="1"/>
</tree>
</field>
</record>