2009-10-13 05:58:37 +00:00
# -*- coding: utf-8 -*-
2008-09-18 15:42:10 +00:00
##############################################################################
2009-11-26 11:59:07 +00:00
#
2009-10-14 11:15:34 +00:00
# OpenERP, Open Source Management Solution
2010-01-12 09:18:39 +00:00
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
2008-09-18 15:42:10 +00:00
#
2008-11-03 19:18:56 +00:00
# This program is free software: you can redistribute it and/or modify
2009-10-14 11:15:34 +00:00
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
2008-09-18 15:42:10 +00:00
#
2008-11-03 19:18:56 +00:00
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2009-10-14 11:15:34 +00:00
# GNU Affero General Public License for more details.
2008-09-18 15:42:10 +00:00
#
2009-10-14 11:15:34 +00:00
# You should have received a copy of the GNU Affero General Public License
2009-11-26 11:59:07 +00:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2008-09-18 15:42:10 +00:00
#
##############################################################################
2008-09-16 14:29:24 +00:00
import time
2014-04-22 16:30:49 +00:00
from datetime import datetime
2008-09-16 14:29:24 +00:00
2012-12-06 14:56:32 +00:00
from openerp . osv import fields , osv
from openerp . tools . translate import _
2008-09-16 14:29:24 +00:00
2014-04-24 09:26:39 +00:00
2008-09-16 14:29:24 +00:00
class hr_action_reason ( osv . osv ) :
_name = " hr.action.reason "
2010-05-19 18:32:32 +00:00
_description = " Action Reason "
2008-09-16 14:29:24 +00:00
_columns = {
2014-05-21 09:52:05 +00:00
' name ' : fields . char ( ' Reason ' , required = True , help = ' Specifies the reason for Signing In/Signing Out. ' ) ,
2011-04-14 09:40:54 +00:00
' action_type ' : fields . selection ( [ ( ' sign_in ' , ' Sign in ' ) , ( ' sign_out ' , ' Sign out ' ) ] , " Action Type " ) ,
2008-09-16 14:29:24 +00:00
}
_defaults = {
2010-07-03 10:21:52 +00:00
' action_type ' : ' sign_in ' ,
2008-09-16 14:29:24 +00:00
}
2010-08-13 06:44:34 +00:00
2008-09-16 14:29:24 +00:00
2010-04-13 05:37:36 +00:00
def _employee_get ( obj , cr , uid , context = None ) :
2010-07-26 06:15:27 +00:00
ids = obj . pool . get ( ' hr.employee ' ) . search ( cr , uid , [ ( ' user_id ' , ' = ' , uid ) ] , context = context )
2010-10-29 07:24:30 +00:00
return ids and ids [ 0 ] or False
2008-09-16 14:29:24 +00:00
2014-04-24 09:26:39 +00:00
2008-09-16 14:29:24 +00:00
class hr_attendance ( osv . osv ) :
_name = " hr.attendance "
_description = " Attendance "
2010-03-18 17:39:33 +00:00
2014-04-22 16:30:49 +00:00
def _worked_hours_compute ( self , cr , uid , ids , fieldnames , args , context = None ) :
""" For each hr.attendance record of action sign-in: assign 0.
For each hr . attendance record of action sign - out : assign number of hours since last sign - in .
"""
res = { }
for obj in self . browse ( cr , uid , ids , context = context ) :
if obj . action == ' sign_in ' :
res [ obj . id ] = 0
elif obj . action == ' sign_out ' :
# Get the associated sign-in
last_signin_id = self . search ( cr , uid , [
( ' employee_id ' , ' = ' , obj . employee_id . id ) ,
( ' name ' , ' < ' , obj . name ) , ( ' action ' , ' = ' , ' sign_in ' )
] , limit = 1 , order = ' name DESC ' )
2014-07-22 08:03:16 +00:00
if last_signin_id :
2014-07-18 09:53:19 +00:00
last_signin = self . browse ( cr , uid , last_signin_id , context = context ) [ 0 ]
2014-04-22 16:30:49 +00:00
2014-07-18 09:53:19 +00:00
# Compute time elapsed between sign-in and sign-out
last_signin_datetime = datetime . strptime ( last_signin . name , ' % Y- % m- %d % H: % M: % S ' )
signout_datetime = datetime . strptime ( obj . name , ' % Y- % m- %d % H: % M: % S ' )
workedhours_datetime = ( signout_datetime - last_signin_datetime )
2014-11-10 00:11:16 +00:00
res [ obj . id ] = ( ( workedhours_datetime . seconds ) / 60 ) / 60.0
2014-07-18 09:53:19 +00:00
else :
res [ obj . id ] = False
2014-04-22 16:30:49 +00:00
return res
2008-09-16 14:29:24 +00:00
_columns = {
2010-07-03 10:21:52 +00:00
' name ' : fields . datetime ( ' Date ' , required = True , select = 1 ) ,
' action ' : fields . selection ( [ ( ' sign_in ' , ' Sign In ' ) , ( ' sign_out ' , ' Sign Out ' ) , ( ' action ' , ' Action ' ) ] , ' Action ' , required = True ) ,
2010-08-13 06:44:34 +00:00
' action_desc ' : fields . many2one ( " hr.action.reason " , " Action Reason " , domain = " [( ' action_type ' , ' = ' , action)] " , help = ' Specifies the reason for Signing In/Signing Out in case of extra hours. ' ) ,
2012-09-17 08:14:51 +00:00
' employee_id ' : fields . many2one ( ' hr.employee ' , " Employee " , required = True , select = True ) ,
2014-04-22 16:30:49 +00:00
' worked_hours ' : fields . function ( _worked_hours_compute , type = ' float ' , string = ' Worked Hours ' , store = True ) ,
2008-09-16 14:29:24 +00:00
}
_defaults = {
2010-10-29 07:24:30 +00:00
' name ' : lambda * a : time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) , #please don't remove the lambda, if you remove it then the current time will not change
2010-07-03 10:21:52 +00:00
' employee_id ' : _employee_get ,
2008-09-16 14:29:24 +00:00
}
2009-11-26 11:59:07 +00:00
2010-11-19 13:48:01 +00:00
def _altern_si_so ( self , cr , uid , ids , context = None ) :
2012-01-24 13:06:50 +00:00
""" Alternance sign_in/sign_out check.
Previous ( if exists ) must be of opposite action .
Next ( if exists ) must be of opposite action .
2012-01-11 13:01:21 +00:00
"""
2012-01-24 13:06:50 +00:00
for att in self . browse ( cr , uid , ids , context = context ) :
2012-01-11 13:01:21 +00:00
# search and browse for first previous and first next records
prev_att_ids = self . search ( cr , uid , [ ( ' employee_id ' , ' = ' , att . employee_id . id ) , ( ' name ' , ' < ' , att . name ) , ( ' action ' , ' in ' , ( ' sign_in ' , ' sign_out ' ) ) ] , limit = 1 , order = ' name DESC ' )
next_add_ids = self . search ( cr , uid , [ ( ' employee_id ' , ' = ' , att . employee_id . id ) , ( ' name ' , ' > ' , att . name ) , ( ' action ' , ' in ' , ( ' sign_in ' , ' sign_out ' ) ) ] , limit = 1 , order = ' name ASC ' )
2012-01-24 13:06:50 +00:00
prev_atts = self . browse ( cr , uid , prev_att_ids , context = context )
next_atts = self . browse ( cr , uid , next_add_ids , context = context )
# check for alternance, return False if at least one condition is not satisfied
if prev_atts and prev_atts [ 0 ] . action == att . action : # previous exists and is same action
2012-01-11 13:01:21 +00:00
return False
2012-01-24 13:06:50 +00:00
if next_atts and next_atts [ 0 ] . action == att . action : # next exists and is same action
2011-12-20 09:45:52 +00:00
return False
2012-01-24 13:06:50 +00:00
if ( not prev_atts ) and ( not next_atts ) and att . action != ' sign_in ' : # first attendance must be sign_in
2008-09-16 14:29:24 +00:00
return False
return True
2009-11-26 11:59:07 +00:00
2012-07-25 12:13:54 +00:00
_constraints = [ ( _altern_si_so , ' Error ! Sign in (resp. Sign out) must follow Sign out (resp. Sign in) ' , [ ' action ' ] ) ]
2008-09-16 14:29:24 +00:00
_order = ' name desc '
2010-08-13 06:44:34 +00:00
2008-09-16 14:29:24 +00:00
class hr_employee ( osv . osv ) :
_inherit = " hr.employee "
_description = " Employee "
2009-11-26 11:59:07 +00:00
2010-04-13 05:37:36 +00:00
def _state ( self , cr , uid , ids , name , args , context = None ) :
2008-09-16 14:29:24 +00:00
result = { }
2010-09-03 10:09:03 +00:00
if not ids :
return result
2008-09-16 14:29:24 +00:00
for id in ids :
result [ id ] = ' absent '
cr . execute ( ' SELECT hr_attendance.action, hr_attendance.employee_id \
FROM ( \
SELECT MAX ( name ) AS name , employee_id \
FROM hr_attendance \
WHERE action in ( \' sign_in \' , \' sign_out \' ) \
GROUP BY employee_id \
) AS foo \
LEFT JOIN hr_attendance \
ON ( hr_attendance . employee_id = foo . employee_id \
AND hr_attendance . name = foo . name ) \
2010-06-10 13:34:19 +00:00
WHERE hr_attendance . employee_id IN % s ' ,(tuple(ids),))
2008-09-16 14:29:24 +00:00
for res in cr . fetchall ( ) :
result [ res [ 1 ] ] = res [ 0 ] == ' sign_in ' and ' present ' or ' absent '
return result
2014-04-24 09:26:39 +00:00
2012-09-07 12:23:37 +00:00
def _last_sign ( self , cr , uid , ids , name , args , context = None ) :
result = { }
if not ids :
return result
for id in ids :
result [ id ] = False
cr . execute ( """ select max(name) as name
from hr_attendance
where action in ( ' sign_in ' , ' sign_out ' ) and employee_id = % s """ ,(id,))
for res in cr . fetchall ( ) :
result [ id ] = res [ 0 ]
return result
2009-11-26 11:59:07 +00:00
2012-09-21 13:44:05 +00:00
def _attendance_access ( self , cr , uid , ids , name , args , context = None ) :
2012-09-24 06:39:51 +00:00
# this function field use to hide attendance button to singin/singout from menu
2015-02-09 04:55:54 +00:00
visible = self . pool . get ( " res.users " ) . has_group ( cr , uid , " base.group_hr_attendance " )
2012-09-24 06:39:51 +00:00
return dict ( [ ( x , visible ) for x in ids ] )
2012-09-21 13:44:05 +00:00
2008-09-16 14:29:24 +00:00
_columns = {
2011-07-01 23:41:24 +00:00
' state ' : fields . function ( _state , type = ' selection ' , selection = [ ( ' absent ' , ' Absent ' ) , ( ' present ' , ' Present ' ) ] , string = ' Attendance ' ) ,
2012-09-07 12:23:37 +00:00
' last_sign ' : fields . function ( _last_sign , type = ' datetime ' , string = ' Last Sign ' ) ,
2012-12-05 08:37:31 +00:00
' attendance_access ' : fields . function ( _attendance_access , string = ' Attendance Access ' , type = ' boolean ' ) ,
2010-08-26 04:52:04 +00:00
}
2009-11-26 11:59:07 +00:00
2010-07-03 10:21:52 +00:00
def _action_check ( self , cr , uid , emp_id , dt = False , context = None ) :
2010-08-26 04:52:04 +00:00
cr . execute ( ' SELECT MAX(name) FROM hr_attendance WHERE employee_id= %s ' , ( emp_id , ) )
2008-09-16 14:29:24 +00:00
res = cr . fetchone ( )
return not ( res and ( res [ 0 ] > = ( dt or time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ) ) )
2012-05-11 05:47:11 +00:00
def attendance_action_change ( self , cr , uid , ids , context = None ) :
if context is None :
context = { }
action_date = context . get ( ' action_date ' , False )
action = context . get ( ' action ' , False )
hr_attendance = self . pool . get ( ' hr.attendance ' )
warning_sign = { ' sign_in ' : _ ( ' Sign In ' ) , ' sign_out ' : _ ( ' Sign Out ' ) }
for employee in self . browse ( cr , uid , ids , context = context ) :
if not action :
if employee . state == ' present ' : action = ' sign_out '
if employee . state == ' absent ' : action = ' sign_in '
if not self . _action_check ( cr , uid , employee . id , action_date , context ) :
raise osv . except_osv ( _ ( ' Warning ' ) , _ ( ' You tried to %s with a date anterior to another event ! \n Try to contact the HR Manager to correct attendances. ' ) % ( warning_sign [ action ] , ) )
vals = { ' action ' : action , ' employee_id ' : employee . id }
if action_date :
vals [ ' name ' ] = action_date
hr_attendance . create ( cr , uid , vals , context = context )
2009-12-21 11:03:05 +00:00
return True
2010-04-13 05:37:36 +00:00
2009-11-26 11:59:07 +00:00
2010-12-29 12:39:00 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: