diff options
| author | Harshad Modi <hmo@tinyerp.com> | 2008-09-18 21:12:10 +0530 |
|---|---|---|
| committer | Harshad Modi <hmo@tinyerp.com> | 2008-09-18 21:12:10 +0530 |
| commit | 9b7fb1feb0b0faa1bc5a8e8bf26a0e2a63651396 (patch) | |
| tree | 3d66db663c5db673abda8458aea8cbd0eb4b255c /addons/hr_attendance | |
| parent | ba2373da640562c5384ffe767bede1c2869ffed9 (diff) | |
| parent | 7c56005927d4b6471a6e2895b1b0ee90a6510888 (diff) | |
merge pso branch
bzr revid: hmo@tinyerp.com-20080918154210-24ewi2d25azyom9i
Diffstat (limited to 'addons/hr_attendance')
| -rw-r--r-- | addons/hr_attendance/__init__.py | 35 | ||||
| -rw-r--r-- | addons/hr_attendance/__terp__.py | 16 | ||||
| -rw-r--r-- | addons/hr_attendance/hr_attendance.py | 158 | ||||
| -rw-r--r-- | addons/hr_attendance/hr_attendance_demo.xml | 108 | ||||
| -rw-r--r-- | addons/hr_attendance/hr_attendance_report.xml | 6 | ||||
| -rw-r--r-- | addons/hr_attendance/hr_attendance_view.xml | 102 | ||||
| -rw-r--r-- | addons/hr_attendance/hr_attendance_wizard.xml | 11 | ||||
| -rw-r--r-- | addons/hr_attendance/report/__init__.py | 32 | ||||
| -rw-r--r-- | addons/hr_attendance/report/attendance_errors.py | 88 | ||||
| -rw-r--r-- | addons/hr_attendance/report/attendance_errors.rml | 158 | ||||
| -rw-r--r-- | addons/hr_attendance/wizard/__init__.py | 33 | ||||
| -rw-r--r-- | addons/hr_attendance/wizard/sign_in_out.py | 194 |
12 files changed, 941 insertions, 0 deletions
diff --git a/addons/hr_attendance/__init__.py b/addons/hr_attendance/__init__.py new file mode 100644 index 00000000000..917959631a7 --- /dev/null +++ b/addons/hr_attendance/__init__.py @@ -0,0 +1,35 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (c) 2004-2008 TINY SPRL. (http://tiny.be) All Rights Reserved. +# +# $Id$ +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +import hr_attendance +import wizard +import report + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/hr_attendance/__terp__.py b/addons/hr_attendance/__terp__.py new file mode 100644 index 00000000000..0dd9eff1013 --- /dev/null +++ b/addons/hr_attendance/__terp__.py @@ -0,0 +1,16 @@ +{ + "name" : "Attendances Of Employees", + "version" : "1.0", + "author" : "Tiny", + "category" : "Generic Modules/Human Resources", + "description": "This module aims to manage employee's attendances.", + "depends" : ["base","hr",], + "demo_xml" : ["hr_attendance_demo.xml"], + "update_xml" : [ + "hr_attendance_view.xml", + "hr_attendance_wizard.xml", + "hr_attendance_report.xml" + ], + "active": False, + "installable": True, +} diff --git a/addons/hr_attendance/hr_attendance.py b/addons/hr_attendance/hr_attendance.py new file mode 100644 index 00000000000..7550ec18847 --- /dev/null +++ b/addons/hr_attendance/hr_attendance.py @@ -0,0 +1,158 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (c) 2004-2008 TINY SPRL. (http://tiny.be) All Rights Reserved. +# +# $Id$ +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +from mx import DateTime +import time + +from osv import fields, osv +from tools.translate import _ + +class hr_action_reason(osv.osv): + _name = "hr.action.reason" + _description = "Action reason" + _columns = { + 'name' : fields.char('Reason', size=64, required=True), + 'action_type' : fields.selection([('sign_in', 'Sign in'), ('sign_out', 'Sign out')], "Action's type"), + } + _defaults = { + 'action_type' : lambda *a: 'sign_in', + } +hr_action_reason() + +def _employee_get(obj,cr,uid,context={}): + ids = obj.pool.get('hr.employee').search(cr, uid, [('user_id','=', uid)]) + if ids: + return ids[0] + return False + +class hr_attendance(osv.osv): + _name = "hr.attendance" + _description = "Attendance" + _columns = { + 'name' : fields.datetime('Date', required=True), + 'action' : fields.selection([('sign_in', 'Sign In'), ('sign_out', 'Sign Out'),('action','Action')], 'Action', required=True), + 'action_desc' : fields.many2one("hr.action.reason", "Action reason", domain="[('action_type', '=', action)]"), + 'employee_id' : fields.many2one('hr.employee', 'Employee', required=True, select=True), + } + _defaults = { + 'name' : lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), + 'employee_id' : _employee_get, + } + + def _altern_si_so(self, cr, uid, ids): + for id in ids: + sql = ''' + select action, name + from hr_attendance as att + where employee_id = (select employee_id from hr_attendance where id=%s) + and action in ('sign_in','sign_out') + and name <= (select name from hr_attendance where id=%s) + order by name desc + limit 2 + ''' % (id, id) + cr.execute(sql) + atts = cr.fetchall() + if not ((len(atts)==1 and atts[0][0] == 'sign_in') or (atts[0][0] != atts[1][0] and atts[0][1] != atts[1][1])): + return False + return True + + _constraints = [(_altern_si_so, 'Error: Sign in (resp. Sign out) must follow Sign out (resp. Sign in)', ['action'])] + _order = 'name desc' +hr_attendance() + +class hr_employee(osv.osv): + _inherit = "hr.employee" + _description = "Employee" + + def _state(self, cr, uid, ids, name, args, context={}): + result = {} + 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) \ + WHERE hr_attendance.employee_id \ + in (' + ','.join([str(x) for x in ids]) + ')') + for res in cr.fetchall(): + result[res[1]] = res[0] == 'sign_in' and 'present' or 'absent' + return result + + _columns = { + 'state': fields.function(_state, method=True, type='selection', selection=[('absent', 'Absent'), ('present', 'Present')], string='Attendance'), + } + + def sign_change(self, cr, uid, ids, context={}, dt=False): + for emp in self.browse(cr, uid, ids): + if not self._action_check(cr, uid, emp.id, dt, context): + raise osv.except_osv(_('Warning'), _('You tried to sign with a date anterior to another event !\nTry to contact the administrator to correct attendances.')) + res = {'action':'action', 'employee_id':emp.id} + if dt: + res['name'] = dt + att_id = self.pool.get('hr.attendance').create(cr, uid, res, context=context) + return True + + def sign_out(self, cr, uid, ids, context={}, dt=False, *args): + id = False + for emp in self.browse(cr, uid, ids): + if not self._action_check(cr, uid, emp.id, dt, context): + raise osv.except_osv(_('Warning'), _('You tried to sign out with a date anterior to another event !\nTry to contact the administrator to correct attendances.')) + res = {'action':'sign_out', 'employee_id':emp.id} + if dt: + res['name'] = dt + att_id = self.pool.get('hr.attendance').create(cr, uid, res, context=context) + id = att_id + return id + + def _action_check(self, cr, uid, emp_id, dt=False,context={}): + cr.execute('select max(name) from hr_attendance where employee_id=%d', (emp_id,)) + res = cr.fetchone() + return not (res and (res[0]>=(dt or time.strftime('%Y-%m-%d %H:%M:%S')))) + + def sign_in(self, cr, uid, ids, context={}, dt=False, *args): + id = False + for emp in self.browse(cr, uid, ids): + if not self._action_check(cr, uid, emp.id, dt, context): + raise osv.except_osv(_('Warning'), _('You tried to sign in with a date anterior to another event !\nTry to contact the administrator to correct attendances.')) + res = {'action':'sign_in', 'employee_id':emp.id} + if dt: + res['name'] = dt + id = self.pool.get('hr.attendance').create(cr, uid, res, context=context) + return id + +hr_employee() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/hr_attendance/hr_attendance_demo.xml b/addons/hr_attendance/hr_attendance_demo.xml new file mode 100644 index 00000000000..640d6b5257a --- /dev/null +++ b/addons/hr_attendance/hr_attendance_demo.xml @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="utf-8"?> +<openerp> + <data> + + + + <record id="attendance1" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-01 08:21')" name="name"/> + <field name="action">sign_in</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance2" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-01 11:51')" name="name"/> + <field name="action">sign_out</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance3" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-02 12:47')" name="name"/> + <field name="action">sign_in</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance4" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-02 19:53')" name="name"/> + <field name="action">sign_out</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance5" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-03 07:32')" name="name"/> + <field name="action">sign_in</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance6" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-03 12:32')" name="name"/> + <field name="action">sign_out</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance7" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-04 14:01')" name="name"/> + <field name="action">sign_in</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance8" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-04 17:21')" name="name"/> + <field name="action">sign_out</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance9" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-05 09:10')" name="name"/> + <field name="action">sign_in</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance10" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-05 12:42')" name="name"/> + <field name="action">sign_out</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance11" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-06 13:10')" name="name"/> + <field name="action">sign_in</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance12" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-06 18:34')" name="name"/> + <field name="action">sign_out</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance13" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-07 08:21')" name="name"/> + <field name="action">sign_in</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance14" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-07 18:21')" name="name"/> + <field name="action">sign_out</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance15" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-08 08:21')" name="name"/> + <field name="action">sign_in</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance16" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-08 12:54')" name="name"/> + <field name="action">sign_out</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance17" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-09 13:32')" name="name"/> + <field name="action">sign_in</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance18" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-09 19:31')" name="name"/> + <field name="action">sign_out</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance19" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-10 07:10')" name="name"/> + <field name="action">sign_in</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + <record id="attendance20" model="hr.attendance"> + <field eval="time.strftime('%Y-%m-10 12:34')" name="name"/> + <field name="action">sign_out</field> + <field name="employee_id" ref="hr.employee1"/> + </record> + </data> +</openerp> diff --git a/addons/hr_attendance/hr_attendance_report.xml b/addons/hr_attendance/hr_attendance_report.xml new file mode 100644 index 00000000000..a0d3497c9aa --- /dev/null +++ b/addons/hr_attendance/hr_attendance_report.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<openerp> + <data> + <report auto="False" id="attendance_error_report" keyword="client_print_multi" menu="False" model="hr.employee" multi="True" name="hr.timesheet.attendance.error" rml="hr/report/attendance_errors.rml" string="Attendance Error Report"/> + </data> +</openerp> diff --git a/addons/hr_attendance/hr_attendance_view.xml b/addons/hr_attendance/hr_attendance_view.xml new file mode 100644 index 00000000000..fe2b1e6f0dc --- /dev/null +++ b/addons/hr_attendance/hr_attendance_view.xml @@ -0,0 +1,102 @@ +<?xml version="1.0" encoding="utf-8"?> +<openerp> + <data> + + <record id="view_attendance_form" model="ir.ui.view"> + <field name="name">hr.attendance.form</field> + <field name="model">hr.attendance</field> + <field name="type">form</field> + <field name="arch" type="xml"> + <form string="Employee attendance"> + <field name="employee_id" select="1"/> + <field colspan="4" name="name" select="1"/> + <field name="action" select="1"/> + <field name="action_desc" select="1"/> + </form> + </field> + </record> + <record id="view_attendance_tree" model="ir.ui.view"> + <field name="name">hr.attendance.tree</field> + <field name="model">hr.attendance</field> + <field name="type">tree</field> + <field name="arch" type="xml"> + <tree string="Employee attendances"> + <field name="name"/> + <field name="action"/> + <field name="action_desc"/> + </tree> + </field> + </record> + + <record id="view_attendance_who" model="ir.ui.view"> + <field name="name">hr.attendance.tree</field> + <field name="model">hr.attendance</field> + <field name="type">tree</field> + <field eval="3" name="priority"/> + <field name="arch" type="xml"> + <tree string="Employee attendance"> + <field name="employee_id"/> + <field name="name"/> + <field name="action"/> + <field name="action_desc"/> + </tree> + </field> + </record> + <record id="open_view_attendance" model="ir.actions.act_window"> + <field name="name">Attendances</field> + <field name="res_model">hr.attendance</field> + <field name="view_type">form</field> + <field name="view_mode">tree,form</field> + </record> + <menuitem id="menu_hr_attendance" name="Attendances" parent="hr.menu_hr_root"/> + <menuitem action="open_view_attendance" id="menu_open_view_attendance" parent="menu_hr_attendance"/> + + + <record id="edit_attendance_reason" model="ir.ui.view"> + <field name="name">hr.action.reason.form</field> + <field name="model">hr.action.reason</field> + <field name="type">form</field> + <field name="arch" type="xml"> + <form string="Define attendance reason"> + <field colspan="4" name="name" select="1"/> + <field name="action_type" select="1"/> + </form> + </field> + </record> + <record id="view_attendance_reason" model="ir.ui.view"> + <field name="name">hr.action.reason.tree</field> + <field name="model">hr.action.reason</field> + <field name="type">tree</field> + <field name="arch" type="xml"> + <tree string="Attendance reasons"> + <field name="name"/> + <field name="action_type"/> + </tree> + </field> + </record> + <record id="open_view_attendance_reason" model="ir.actions.act_window"> + <field name="name">Attendance Reasons</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">hr.action.reason</field> + <field name="view_type">form</field> + <field name="view_mode">tree,form</field> + <field name="view_id" ref="view_attendance_reason"/> + </record> + <menuitem action="open_view_attendance_reason" id="menu_open_view_attendance_reason" parent="hr.menu_hr_configuration"/> + + <record id="hr_attendance_employee" model="ir.ui.view"> + <field name="name">hr.employee.form1</field> + <field name="model">hr.employee</field> + <field name="type">form</field> + <field name="inherit_id" ref="hr.view_employee_form"/> + <field name="arch" type="xml"> + <field name="parent_id" position="after"> + <field name="state"/> + <button name="sign_in" states="absent" string="Sign In" type="object"/> + <button name="sign_out" states="present" string="Sign Out" type="object"/> + </field> + </field> + </record> + + </data> +</openerp> diff --git a/addons/hr_attendance/hr_attendance_wizard.xml b/addons/hr_attendance/hr_attendance_wizard.xml new file mode 100644 index 00000000000..707e63a4460 --- /dev/null +++ b/addons/hr_attendance/hr_attendance_wizard.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<openerp> + <data> + + <wizard id="si_so" model="hr.employee" name="hr.si_so" string="Sign in / Sign out"/> + <wizard id="wizard_attendance_error" keyword="client_print_multi" model="hr.employee" name="hr.timesheet.attendance.report" string="Print Attendance Error Report"/> + + <menuitem action="si_so" id="menu_si_so" parent="menu_hr_attendance" type="wizard"/> + + </data> +</openerp> diff --git a/addons/hr_attendance/report/__init__.py b/addons/hr_attendance/report/__init__.py new file mode 100644 index 00000000000..c9f1ff7008a --- /dev/null +++ b/addons/hr_attendance/report/__init__.py @@ -0,0 +1,32 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (c) 2004-2008 TINY SPRL. (http://tiny.be) All Rights Reserved. +# +# $Id$ +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## +import attendance_errors + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/hr_attendance/report/attendance_errors.py b/addons/hr_attendance/report/attendance_errors.py new file mode 100644 index 00000000000..286fad59f67 --- /dev/null +++ b/addons/hr_attendance/report/attendance_errors.py @@ -0,0 +1,88 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (c) 2004-2008 TINY SPRL. (http://tiny.be) All Rights Reserved. +# +# $Id$ +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + + +import time +from report import report_sxw + +class attendance_print(report_sxw.rml_parse): + def __init__(self, cr, uid, name, context): + super(attendance_print, self).__init__(cr, uid, name, context) + self.localcontext.update({ + 'time': time, + 'lst': self._lst, + 'total': self._lst_total, + }) + + def _sign(self, dt): + if abs(dt.days)>1: + format = '%d day'+(((abs(dt.days)>=2) and 's') or '')+' %H:%M:%S' + else: + format = '%H:%M:%S' + if dt.seconds<0: + return dt.strftime('- '+format) + else: + return dt.strftime(format) + + def _lst(self, employee_id, dt_from, dt_to, max, *args): + self.cr.execute('select name as date, create_date, action, create_date-name as delay from hr_attendance where employee_id=%d and name<=%s and name>=%s and action in (%s,%s) order by name', (employee_id, dt_to, dt_from, 'sign_in', 'sign_out')) + res = self.cr.dictfetchall() + for r in res: + if r['action']=='sign_out': + r['delay'] = - r['delay'] + temp = r['delay'].seconds + r['delay'] = self._sign(r['delay']) + if abs(temp) < max*60: + r['delay2'] = r['delay'] + else: + r['delay2'] = '/' + return res + + def _lst_total(self, employee_id, dt_from, dt_to, max, *args): + self.cr.execute('select name as date, create_date, action, create_date-name as delay from hr_attendance where employee_id=%d and name<=%s and name>=%s and action in (%s,%s)', (employee_id, dt_to, dt_from, 'sign_in', 'sign_out')) + res = self.cr.dictfetchall() + if not res: + return ('/','/') + total = 0 + total2 = 0 + for r in res: + if r['action']=='sign_out': + r['delay'] = - r['delay'] + total += r['delay'] + if abs(r['delay'].seconds) < max*60: + total2 += r['delay'] + + return (self._sign(total),total2 and self._sign(total2)) + +report_sxw.report_sxw('report.hr.timesheet.attendance.error', 'hr.employee', 'addons/hr_attendance/report/attendance_errors.rml',parser=attendance_print) + + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + diff --git a/addons/hr_attendance/report/attendance_errors.rml b/addons/hr_attendance/report/attendance_errors.rml new file mode 100644 index 00000000000..aacdde99e06 --- /dev/null +++ b/addons/hr_attendance/report/attendance_errors.rml @@ -0,0 +1,158 @@ +<?xml version="1.0"?> +<document filename="test.pdf"> + <template pageSize="(595.0,842.0)" title="Test" author="Martin Simon" allowSplitting="20"> + <pageTemplate id="first"> + <frame id="first" x1="57.0" y1="57.0" width="481" height="728"/> + </pageTemplate> + </template> + <stylesheet> + <blockTableStyle id="Standard_Outline"> + <blockAlignment value="LEFT"/> + <blockValign value="TOP"/> + </blockTableStyle> + <blockTableStyle id="Table_employee_detail_header"> + <blockAlignment value="LEFT"/> + <blockValign value="TOP"/> + <lineStyle kind="LINEBELOW" colorName="#000000" start="0,-1" stop="0,-1"/> + <lineStyle kind="LINEBELOW" colorName="#000000" start="1,-1" stop="1,-1"/> + <lineStyle kind="LINEBELOW" colorName="#000000" start="2,-1" stop="2,-1"/> + <lineStyle kind="LINEBELOW" colorName="#000000" start="3,-1" stop="3,-1"/> + <lineStyle kind="LINEBELOW" colorName="#000000" start="4,-1" stop="4,-1"/> + </blockTableStyle> + <blockTableStyle id="tbl_detail"> + <blockAlignment value="LEFT"/> + <blockValign value="TOP"/> + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="1,-1" stop="1,-1"/> + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="2,-1" stop="2,-1"/> + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="3,-1" stop="3,-1"/> + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="4,-1" stop="4,-1"/> + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="5,-1" stop="5,-1"/> + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,-1" stop="0,-1"/> + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="1,-1" stop="1,-1"/> + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="2,-1" stop="2,-1"/> + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="3,-1" stop="3,-1"/> + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="4,-1" stop="4,-1"/> + </blockTableStyle> + <blockTableStyle id="Table_employee_detail_content"> + <blockAlignment value="LEFT"/> + <blockValign value="TOP"/> + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,-1" stop="0,-1"/> + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="1,-1" stop="1,-1"/> + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="2,-1" stop="2,-1"/> + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="3,-1" stop="3,-1"/> + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="4,-1" stop="4,-1"/> + </blockTableStyle> + <blockTableStyle id="Table_employee_total"> + <blockAlignment value="LEFT"/> + <blockValign value="TOP"/> + <lineStyle kind="LINEABOVE" colorName="#ffffff" start="0,0" stop="0,0"/> + <lineStyle kind="LINEABOVE" colorName="#ffffff" start="1,0" stop="1,0"/> + <lineStyle kind="LINEABOVE" colorName="#ffffff" start="2,0" stop="2,0"/> + </blockTableStyle> + <initialize> + <paraStyle name="all" alignment="justify"/> + </initialize> + <paraStyle name="Standard" fontName="Times-Roman"/> + <paraStyle name="Text body" fontName="Times-Roman" spaceBefore="0.0" spaceAfter="6.0"/> + <paraStyle name="Heading" fontName="Helvetica" fontSize="14.0" leading="17" spaceBefore="12.0" spaceAfter="6.0"/> + <paraStyle name="List" fontName="Times-Roman" spaceBefore="0.0" spaceAfter="6.0"/> + <paraStyle name="Table Contents" fontName="Times-Roman"/> + <paraStyle name="Caption" fontName="Times-Roman" fontSize="12.0" leading="15" spaceBefore="6.0" spaceAfter="6.0"/> + <paraStyle name="Index" fontName="Times-Roman"/> + <paraStyle name="terp_header" fontName="Helvetica-Bold" fontSize="12.0" leading="15" alignment="LEFT" spaceBefore="12.0" spaceAfter="6.0"/> + <paraStyle name="terp_default_8" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> + <paraStyle name="terp_default_9" fontName="Helvetica" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> + <paraStyle name="terp_header_Centre" fontName="Helvetica-Bold" fontSize="14.0" leading="17" alignment="CENTER" spaceBefore="12.0" spaceAfter="6.0"/> + <paraStyle name="terp_tblheader_Details" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="6.0" spaceAfter="6.0"/> + <paraStyle name="terp_tblheader_Details_Centre" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/> + <paraStyle name="terp_default_Centre_8" fontName="Helvetica" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/> + <paraStyle name="terp_default_Centre_9" fontName="Helvetica" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/> + <paraStyle name="terp_default_Bold_8" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> + <paraStyle name="terp_default_Bold_9" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> + <paraStyle name="terp_default_Centre_9_Bold" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/> + <paraStyle name="Footer" fontName="Times-Roman"/> + <paraStyle name="Table Heading" fontName="Times-Roman" alignment="CENTER"/> + <paraStyle name="Horizontal Line" fontName="Times-Roman" fontSize="6.0" leading="8" spaceBefore="0.0" spaceAfter="14.0"/> + <paraStyle name="Heading 9" fontName="Helvetica-Bold" fontSize="75%" leading="NaN" spaceBefore="12.0" spaceAfter="6.0"/> + <paraStyle name="terp_tblheader_General" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="6.0" spaceAfter="6.0"/> + <paraStyle name="terp_tblheader_General_Centre" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/> + <paraStyle name="terp_tblheader_General_Right" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="RIGHT" spaceBefore="6.0" spaceAfter="6.0"/> + <paraStyle name="terp_tblheader_Details_Right" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="RIGHT" spaceBefore="6.0" spaceAfter="6.0"/> + <paraStyle name="terp_default_Right_8" fontName="Helvetica" fontSize="8.0" leading="10" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/> + <paraStyle name="terp_header_Right" fontName="Helvetica-Bold" fontSize="15.0" leading="19" alignment="LEFT" spaceBefore="12.0" spaceAfter="6.0"/> + <paraStyle name="terp_default_address" fontName="Helvetica" fontSize="10.0" leading="13" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> + <paraStyle name="terp_default_Right_9" fontName="Helvetica" fontSize="9.0" leading="11" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/> + </stylesheet> + <images/> + <story> + <para style="terp_default_8">[[ repeatIn(objects,'employee') ]]</para> + <para style="terp_header_Centre">Attendance Errors</para> + <para style="terp_header">[[ employee.name ]]</para> + <para style="terp_default_8"> + <font color="white"> </font> + </para> + <blockTable colWidths="60.0,114.0,146.0,85.0,77.0" style="Table_employee_detail_header"> + <tr> + <td> + <para style="terp_tblheader_Details_Centre">Operation</para> + </td> + <td> + <para style="terp_tblheader_Details_Centre">Date Signed</para> + </td> + <td> + <para style="terp_tblheader_Details_Centre">Date Recorded</para> + </td> + <td> + <para style="terp_tblheader_Details_Centre">Delay</para> + </td> + <td> + <para style="terp_tblheader_Details_Centre">Min Delay</para> + </td> + </tr> + </blockTable> + <blockTable colWidths="482.0" style="tbl_detail"> + <tr> + <td> + <para style="terp_default_8">[[ repeatIn(lst(employee.id,data['form']['init_date'], data['form']['end_date'], data['form']['max_delay']), 'att') ]]</para> + <blockTable colWidths="58.0,114.0,143.0,93.0,69.0" style="Table_employee_detail_content"> + <tr> + <td> + <para style="terp_default_Centre_9">[[ att['action'] ]]</para> + </td> + <td> + <para style="terp_default_Centre_9">[[ att['date'] ]]</para> + </td> + <td> + <para style="terp_default_Centre_9">[[ att['create_date'] ]]</para> + </td> + <td> + <para style="terp_default_Centre_9">[[ att['delay'] ]]</para> + </td> + <td> + <para style="terp_default_Centre_9">[[ att['delay2'] ]]</para> + </td> + </tr> + </blockTable> + </td> + </tr> + </blockTable> + <blockTable colWidths="319.0,99.0,63.0" style="Table_employee_total"> + <tr> + <td> + <para style="terp_default_Bold_9">Total period:</para> + </td> + <td> + <para style="terp_default_Centre_9_Bold">[[ total(employee.id,data['form']['init_date'], data['form']['end_date'], data['form']['max_delay'])[0] ]]</para> + </td> + <td> + <para style="terp_default_Centre_9_Bold">[[ total(employee.id,data['form']['init_date'], data['form']['end_date'], data['form']['max_delay'])[1] ]]</para> + </td> + </tr> + </blockTable> + <para style="terp_default_8"> + <font color="white"> </font> + </para> + <para style="terp_default_8">(*) A positive delay means that the employee worked less than recorded.</para> + <para style="terp_default_8">(*) A negative delay means that the employee worked more than encoded.</para> + </story> +</document> diff --git a/addons/hr_attendance/wizard/__init__.py b/addons/hr_attendance/wizard/__init__.py new file mode 100644 index 00000000000..447b2047f2c --- /dev/null +++ b/addons/hr_attendance/wizard/__init__.py @@ -0,0 +1,33 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (c) 2004-2008 TINY SPRL. (http://tiny.be) All Rights Reserved. +# +# $Id$ +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## +import sign_in_out +import print_attendance_error + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/hr_attendance/wizard/sign_in_out.py b/addons/hr_attendance/wizard/sign_in_out.py new file mode 100644 index 00000000000..a3e82b9d669 --- /dev/null +++ b/addons/hr_attendance/wizard/sign_in_out.py @@ -0,0 +1,194 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (c) 2004-2008 TINY SPRL. (http://tiny.be) All Rights Reserved. +# +# $Id$ +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# 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 +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +import wizard +import netsvc +import time +from tools.translate import _ + +si_so_form ='''<?xml version="1.0"?> +<form string="Sign in / Sign out"> + <separator string="You are now ready to sign in or out of the attendance follow up" colspan="4" /> + <field name="name" readonly="True" /> + <field name="state" readonly="True" /> +</form>''' + +si_so_fields = { + 'name' : {'string' : "Employee's name", 'type':'char', 'required':True, 'readonly':True}, + 'state' : {'string' : "Current state", 'type' : 'char', 'required' : True, 'readonly': True}, +} + +si_form = '''<?xml version="1.0" ?> +<form string="Sign in status"> + <seperator string="This is the status of your sign in request. Check it out maybe you were already signed in." colspan="4" /> + <field name="success" readonly="True" /> +</form>''' + +si_fields = { + 'success' : {'string' : "Sign in's status", 'type' : 'char', 'required' : True, 'readonly' : True}, +} + +so_form = '''<?xml version="1.0" ?> +<form string="Sign in status"> + <seperator string="This is the status of your sign out request. Check it out maybe you were already signed out." colspan="4" /> + <field name="success" readonly="True" /> +</for>''' + +so_fields = { + 'success' : {'string' : "Sign out's status", 'type' : 'char', 'required' : True, 'readonly' : True}, +} + +def _get_empid(self, cr, uid, data, context): + service = netsvc.LocalService('object_proxy') + emp_id = service.execute(cr.dbname, uid, 'hr.employee', 'search', [('user_id', '=', uid)]) + print "EMP :::::::::", emp_id + if emp_id: + print "IF ::::::::" + employee = service.execute(cr.dbname, uid, 'hr.employee', 'read', emp_id)[0] + print "employee .........", employee + return {'name': employee['name'], 'state': employee['state'], 'emp_id': emp_id[0]} + return {} + +def _sign_in(self, cr, uid, data, context): + service = netsvc.LocalService('object_proxy') + emp_id = data['form']['emp_id'] + if 'last_time' in data['form'] : + if data['form']['last_time'] > time.strftime('%Y-%m-%d'): + raise wizard.except_wizard(_('UserError'), _('The sign-out date must be in the past')) + return {'success': False} + service.execute(cr.dbname, uid, 'hr.attendance', 'create', { + 'name': data['form']['last_time'], + 'action': 'sign_out', + 'employee_id': emp_id + }) + try: + success = service.execute(cr.dbname, uid, 'hr.employee', 'sign_in', [emp_id]) + print success + except: + raise wizard.except_wizard(_('UserError'), _('A sign-in must be right after a sign-out !')) + return {'success': success} + +def _sign_out(self, cr, uid, data, context): + service = netsvc.LocalService('object_proxy') + emp_id = data['form']['emp_id'] + if 'last_time' in data['form'] : + if data['form']['last_time'] > time.strftime('%Y-%m-%d'): + raise wizard.except_wizard(_('UserError'), _('The Sign-in date must be in the past')) + return {'success': False} + service.execute(cr.dbname, uid, 'hr.attendance', 'create', {'name':data['form']['last_time'], 'action':'sign_in', 'employee_id':emp_id}) + try: + success = service.execute(cr.dbname, uid, 'hr.employee', 'sign_out', [emp_id]) + except: + raise wizard.except_wizard(_('UserError'), _('A sign-out must be right after a sign-in !')) + + return {'success' : success} + +so_ask_form ='''<?xml version="1.0"?> +<form string="Sign in / Sign out"> + <separator string="You did not signed out the last time. Please enter the date and time you signed out." colspan="4" /> + <field name="name" readonly="True" /> + <field name="last_time" /> +</form>''' + +so_ask_fields = { + 'name' : {'string' : "Employee's name", 'type':'char', 'required':True, 'readonly':True}, + 'last_time' : {'string' : "Your last sign out", 'type' : 'datetime', 'required' : True}, +} + +def _si_check(self, cr, uid, data, context): + states = {True : 'si', False: 'si_ask_so'} + service = netsvc.LocalService('object_proxy') + emp_id = data['form']['emp_id'] + att_id = service.execute(cr.dbname, uid, 'hr.attendance', 'search', [('employee_id', '=', emp_id)], limit=1, order='name desc') + last_att = service.execute(cr.dbname, uid, 'hr.attendance', 'read', att_id) + if last_att: + last_att = last_att[0] + cond = not last_att or last_att['action'] == 'sign_out' + return states[cond] + +si_ask_form ='''<?xml version="1.0"?> +<form string="Sign in / Sign out"> + <separator string="You did not signed in the last time. Please enter the date and time you signed in." colspan="4" /> + <field name="name" readonly="True" /> + <field name="last_time" /> +</form>''' + +si_ask_fields = { + 'name' : {'string' : "Employee's name", 'type':'char', 'required':True, 'readonly':True}, + 'last_time' : {'string' : "Your last sign in", 'type' : 'datetime', 'required' : True}, +} + +def _so_check(self, cr, uid, data, context): + states = {True : 'so', False: 'so_ask_si'} + service = netsvc.LocalService('object_proxy') + emp_id = data['form']['emp_id'] + att_id = service.execute(cr.dbname, uid, 'hr.attendance', 'search', [('employee_id', '=', emp_id)], limit=1, order='name desc') + last_att = service.execute(cr.dbname, uid, 'hr.attendance', 'read', att_id) + if last_att: + last_att = last_att[0] + cond = last_att and last_att['action'] == 'sign_in' + return states[cond] + +class wiz_si_so(wizard.interface): + states = { + 'init' : { + 'actions' : [_get_empid], + 'result' : {'type' : 'form', 'arch' : si_so_form, 'fields' : si_so_fields, 'state' : [('end', 'Cancel'),('si_test', 'Sign in'),('so_test', 'Sign out')] } + }, + 'si_test' : { + 'actions' : [], + 'result' : {'type' : 'choice', 'next_state': _si_check} + }, + 'si_ask_so' : { + 'actions' : [], + 'result' : {'type' : 'form', 'arch' : so_ask_form, 'fields' : so_ask_fields, 'state' : [('end', 'Cancel'),('si', 'Sign in') ] } + }, + 'si' : { + 'actions' : [_sign_in], + 'result' : {'type' : 'state', 'state':'end'} + }, + 'so_test' : { + 'actions' : [], + 'result' : {'type' : 'choice', 'next_state': _so_check } + }, + 'so_ask_si' : { + 'actions' : [], + 'result' : {'type' : 'form', 'arch' : si_ask_form, 'fields' : si_ask_fields, 'state' : [('end', 'Cancel'),('so', 'Sign out')] } + }, + 'so' : { + 'actions' : [_sign_out], + 'result' : {'type' : 'state', 'state':'end'} + }, + } +wiz_si_so('hr.si_so') + + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + |
