[IMP] hr modules: needaction, subtypes and department-based improvements.
authorMansi Kariya <mka@openerp.com>
Wed, 21 May 2014 10:01:12 +0000 (15:31 +0530)
committerThibault Delavallée <tde@openerp.com>
Thu, 31 Jul 2014 14:59:29 +0000 (16:59 +0200)
This commit prepares some cleaning in various hr-related modules that are
about to land in master. There are mainly improvements on subtypes. The
subtypes are now linked to department subtypes, allowing to follow some records
based on the department (like project/task/issue).

23 files changed:
addons/hr/hr.py
addons/hr/hr_data.xml
addons/hr/hr_view.xml
addons/hr/res_users.py
addons/hr_attendance/hr_attendance_view.xml
addons/hr_contract/hr_contract.py
addons/hr_contract/hr_contract_data.xml
addons/hr_contract/hr_contract_view.xml
addons/hr_evaluation/hr_evaluation.py
addons/hr_evaluation/hr_evaluation_data.xml
addons/hr_evaluation/hr_evaluation_view.xml
addons/hr_expense/hr_expense.py
addons/hr_expense/hr_expense_data.xml
addons/hr_expense/hr_expense_view.xml
addons/hr_holidays/hr_holidays.py
addons/hr_holidays/hr_holidays_data.xml
addons/hr_holidays/hr_holidays_view.xml
addons/hr_recruitment/hr_recruitment.py
addons/hr_recruitment/hr_recruitment_data.xml
addons/hr_recruitment/hr_recruitment_view.xml
addons/hr_timesheet_sheet/hr_timesheet_sheet.py
addons/hr_timesheet_sheet/hr_timesheet_sheet_data.xml
addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml

index 5e081fa..963f338 100644 (file)
@@ -2,7 +2,7 @@
 ##############################################################################
 #
 #    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
@@ -94,7 +94,7 @@ class hr_job(osv.Model):
 
     _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',
@@ -368,19 +368,21 @@ class hr_employee(osv.osv):
 
 
 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'),
@@ -420,13 +422,27 @@ class hr_department(osv.osv):
             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)
index 382cc4d..d38268f 100644 (file)
@@ -16,6 +16,8 @@ Leave Management (keep track of employee leaves), Expense Management (manage emp
         <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>
 
index a045baa..708387d 100644 (file)
@@ -9,7 +9,7 @@
             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"/>
 
@@ -93,7 +93,7 @@
                         </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>
index e6f2ca3..eff3b8b 100644 (file)
@@ -4,13 +4,15 @@ from openerp.osv import fields, osv
 
 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"),
     }
 
index 5075cc1..1a5d010 100644 (file)
         </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">
index 8b58c3e..593faf3 100644 (file)
@@ -2,7 +2,7 @@
 ##############################################################################
 #
 #    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
@@ -18,6 +18,7 @@
 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 ##############################################################################
+
 import time
 
 from openerp.osv import fields, osv
@@ -31,7 +32,7 @@ class hr_employee(osv.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:
@@ -65,26 +66,40 @@ class hr_contract_type(osv.osv):
         '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):
@@ -93,26 +108,33 @@ class hr_contract(osv.osv):
 
     _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)
index 9720091..bdb344f 100644 (file)
             <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>
index 3c06c47..f0e1510 100644 (file)
@@ -13,7 +13,7 @@
             <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>
 
@@ -77,6 +81,9 @@
             <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"/>
@@ -90,6 +97,7 @@
                             <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>
index 068af5b..dc35b28 100644 (file)
@@ -2,7 +2,7 @@
 ##############################################################################
 #
 #    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
@@ -135,7 +135,7 @@ class hr_employee(osv.Model):
 
 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),
@@ -157,7 +157,7 @@ class hr_evaluation(osv.Model):
             ('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 = {
@@ -270,7 +270,7 @@ class hr_evaluation(osv.Model):
 
 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 = {
index 38171b0..fb3fad5 100644 (file)
@@ -57,6 +57,5 @@
            <field eval="'run_employee_evaluation'" name="function" />
            <field eval="'(False,)'" name="args" />
         </record>
-     </data>
-
+    </data>
 </openerp>
index 7ec83cd..5f1b2db 100644 (file)
@@ -72,9 +72,9 @@
         </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'}"/>
index eb8a096..1cdfc5e 100644 (file)
@@ -53,7 +53,7 @@ class hr_expense_expense(osv.osv):
         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 = {
@@ -69,6 +69,7 @@ class hr_expense_expense(osv.osv):
         '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,
@@ -77,7 +78,7 @@ class hr_expense_expense(osv.osv):
                                   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'),
@@ -126,15 +127,20 @@ class hr_expense_expense(osv.osv):
     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)
@@ -226,22 +232,22 @@ class hr_expense_expense(osv.osv):
         '''
         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': '/',
@@ -254,7 +260,7 @@ class hr_expense_expense(osv.osv):
                     })
 
             #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:
index ddb6bdd..ac5df67 100644 (file)
         <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>
index 8e91312..2d72636 100644 (file)
             <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>
@@ -46,7 +47,7 @@
                     <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>
index 8084894..a8e2656 100644 (file)
 #
 ##############################################################################
 
+
+import calendar
 import datetime
+from datetime import date
 import math
 import time
 from operator import attrgetter
@@ -111,13 +114,14 @@ class hr_holidays(osv.osv):
     _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
@@ -172,6 +176,9 @@ class hr_holidays(osv.osv):
             \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),
@@ -201,7 +208,8 @@ class hr_holidays(osv.osv):
         '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']),
@@ -304,7 +312,6 @@ class hr_holidays(osv.osv):
         """
         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.'))
@@ -317,7 +324,6 @@ class hr_holidays(osv.osv):
             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):
@@ -347,14 +353,13 @@ class hr_holidays(osv.osv):
         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:
@@ -447,23 +452,12 @@ class hr_holidays(osv.osv):
                                 '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"
@@ -473,9 +467,8 @@ class resource_calendar_leaves(osv.osv):
     }
 
 
-
-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
@@ -550,23 +543,25 @@ class hr_employee(osv.osv):
         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:
index 703fa74..1bdcb13 100644 (file)
@@ -1,6 +1,7 @@
 <?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>
index 5ee1ec8..cc9b931 100644 (file)
@@ -7,10 +7,15 @@
             <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','&gt;=', context_today().strftime("%Y-%m-1")), ('date_from','&lt;', ((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>
index 4908532..caa4430 100644 (file)
@@ -83,6 +83,9 @@ class hr_applicant(osv.Model):
     _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,
@@ -232,7 +235,7 @@ class hr_applicant(osv.Model):
         '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"),
     }
@@ -571,6 +574,7 @@ 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)
         job = self.browse(cr, uid, job_id, context=context)
@@ -610,5 +614,3 @@ class applicant_category(osv.osv):
     _columns = {
         'name': fields.char('Name', required=True, translate=True),
     }
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
index aa08217..3093dea 100644 (file)
         <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>
index 21c4af2..82c649e 100644 (file)
@@ -5,6 +5,7 @@
     <menuitem name="Recruitment"
         id="menu_hr_recruitment_recruitment"
         parent="hr.menu_hr_configuration"
+        groups="base.group_hr_manager"
         sequence="40"/>
 
     <act_window
index 96be836..824fb4c 100644 (file)
@@ -31,10 +31,17 @@ from openerp.tools.translate import _
 
 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
@@ -165,6 +172,7 @@ class hr_timesheet_sheet(osv.osv):
             ('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.'),
index 095a92c..4bb9a31 100644 (file)
 
         <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>
index afe10cb..7eb5cb3 100644 (file)
                     </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>