make new module named hr_attendance
authorPriyesh <solanki.priyesh@gmail.com>
Tue, 16 Sep 2008 14:29:24 +0000 (19:59 +0530)
committerPriyesh <solanki.priyesh@gmail.com>
Tue, 16 Sep 2008 14:29:24 +0000 (19:59 +0530)
bzr revid: solanki.priyesh@gmail.com-20080916142924-e8b4augwkzfx2vz6

addons/hr_attendance/__init__.py [new file with mode: 0644]
addons/hr_attendance/__terp__.py [new file with mode: 0644]
addons/hr_attendance/hr_attendance.py [new file with mode: 0644]
addons/hr_attendance/hr_attendance_demo.xml [new file with mode: 0644]
addons/hr_attendance/hr_attendance_view.xml [new file with mode: 0644]
addons/hr_attendance/hr_attendance_wizard.xml [new file with mode: 0644]
addons/hr_attendance/wizard/__init__.py [new file with mode: 0644]
addons/hr_attendance/wizard/sign_in_out.py [new file with mode: 0644]

diff --git a/addons/hr_attendance/__init__.py b/addons/hr_attendance/__init__.py
new file mode 100644 (file)
index 0000000..01b3a0e
--- /dev/null
@@ -0,0 +1,2 @@
+import hr_attendance
+import wizard
\ No newline at end of file
diff --git a/addons/hr_attendance/__terp__.py b/addons/hr_attendance/__terp__.py
new file mode 100644 (file)
index 0000000..465ec1d
--- /dev/null
@@ -0,0 +1,15 @@
+{
+    "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"
+    ],
+    "active": False,
+    "installable": True,
+}
diff --git a/addons/hr_attendance/hr_attendance.py b/addons/hr_attendance/hr_attendance.py
new file mode 100644 (file)
index 0000000..f6e1600
--- /dev/null
@@ -0,0 +1,128 @@
+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()
+    
+    
\ No newline at end of file
diff --git a/addons/hr_attendance/hr_attendance_demo.xml b/addons/hr_attendance/hr_attendance_demo.xml
new file mode 100644 (file)
index 0000000..542138b
--- /dev/null
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        
+        <record id="employee1" model="hr.employee">
+            <field name="name">Fabien Pinckaers</field>
+            <!--<field name="regime">45</field>-->
+            <field name="user_id" ref="base.user_root"/>
+            <!--<field name="holiday_max">25</field>-->
+        </record>
+        
+        <record model="hr.action.reason">
+            <field name="name">Start of shift</field>
+            <field name="action_type">sign_in</field>
+        </record>
+        <record model="hr.action.reason">
+            <field name="name">End of shift</field>
+            <field name="action_type">sign_out</field>
+        </record>
+        <record model="hr.action.reason">
+            <field name="name">Meal Break</field>
+            <field name="action_type">sign_in</field>
+        </record>
+        <record model="hr.action.reason">
+            <field name="name">Meal Break</field>
+            <field name="action_type">sign_out</field>
+        </record>
+        <record model="hr.action.reason">
+            <field name="name">Early exit (sick)</field>
+            <field name="action_type">sign_out</field>
+        </record>
+        <record model="hr.action.reason">
+            <field name="name">Early exit (work injury)</field>
+            <field name="action_type">sign_out</field>
+        </record>
+
+               <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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="employee1"/>
+        </record>
+    </data>
+</openerp>
diff --git a/addons/hr_attendance/hr_attendance_view.xml b/addons/hr_attendance/hr_attendance_view.xml
new file mode 100644 (file)
index 0000000..fe2b1e6
--- /dev/null
@@ -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 (file)
index 0000000..8948a1c
--- /dev/null
@@ -0,0 +1,10 @@
+<?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"/>
+
+        <menuitem action="si_so" id="menu_si_so" parent="menu_hr_attendance" type="wizard"/>
+        
+    </data>
+</openerp>
\ No newline at end of file
diff --git a/addons/hr_attendance/wizard/__init__.py b/addons/hr_attendance/wizard/__init__.py
new file mode 100644 (file)
index 0000000..cb0866e
--- /dev/null
@@ -0,0 +1 @@
+import sign_in_out
\ No newline at end of file
diff --git a/addons/hr_attendance/wizard/sign_in_out.py b/addons/hr_attendance/wizard/sign_in_out.py
new file mode 100644 (file)
index 0000000..a3e82b9
--- /dev/null
@@ -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:
+