Odoo中文网|Odoo实施培训

 找回密码
 立即注册
搜索
热搜: Odoo OpenERP 实施
查看: 20008|回复: 2
打印 上一主题 下一主题

openerp 7.0 升级笔记 ---HR考勤

  [复制链接]

3

主题

8

帖子

21

积分

新手上路

Rank: 1

积分
21
跳转到指定楼层
楼主
发表于 2015-9-2 20:11:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 就是不注册 于 2015-9-2 20:36 编辑

签到功能说明:
1、右上角的签入签出按钮,动作之间没有时间限制,如果员工误操作,点击两次,则有可能签入之后紧接着就签出,造成数据错误,因此需要限制签入后三分钟之内不能进行签出操作。
2、考虑员工签到的几种实际情况:
     (1)正常上下班签到,这个不需要再做任何设置。
     (2)上班迟到,一个小时之内,弹出对话框,提示迟到时间,提醒员工注意。如员工因公迟到,或不可抗力迟到,或已到公司却忘记打卡,可以填写说明,提交主管,由主管根据情况,决定是否将员工此次迟到记录在案。需要开发
     (3)上班迟到,超过一个小时,不允许再签入,此时已经不能按照迟到处理。员工需要根据实际情况,填写请假单(按照请假处理),因公外出单,或忘记打卡说明单,由主管审批。需要开发
     (4)下班前超过一个小时,不能签出,如有事需提前离开,需要填写请假单或因公外出单。需要开发
     (5)下班前一个小时之内,可以签出,但是需要说明理由,主管根据员工工作表现和具体情况,决定此次早退是否视为请假。需要开发。
对hr_attendance类进行扩展。
第一个问题比较简单,重载create函数,针对当前时间和最后一次签到时间做一个比较,小于设定值则不允许签到。
代码如下:
  1. def create(self,cr,uid,vals,context=None):        now=datetime.datetime.now()        employee_id=self._employee_get(cr,uid,context=context)        last_sign=self._last_sign(cr,uid,employee_id,context=context)        last=datetime.datetime.strptime(last_sign,'%Y-%m-%d %H:%M:%S')        if (now-last).seconds<180:            raise osv.except_osv(_('错误!'),_('你已经签到,请勿重复操作。'))            return False        return super(hr_attendance,self).create(cr,uid,vals,context=context)   
复制代码


这里要记录一个问题,在获取最后一次签到时间的时候,一开始的代码如下:
cr.execute("""select max(name) as name              from hr_attendance              where action in ('sign_in', 'sign_out') and employee_id = %s""",(employee_id,))
这个时候我要同时获取最后一次签到的动作类型,是sign_in或者sing_out,如果直接将代码改成:
cr.execute("""select max(name) as name,action              from hr_attendance              where action in ('sign_in', 'sign_out') and employee_id = %s group by action""",(employee_id,))
这样得到的结果是:
"2012-12-02 09:33:48";"sign_out"
"2012-12-02 09:24:03";"sign_in"
这就不是我想要的结果了,我需要的是9点33分的那个结果的action类型,也就是sign_out,而不是每一个action都获取一个最大值。
经过google,最终的代码如下:
select a.name,a.action from hr_attendance a inner join (select max(name) as maxf from hr_attendance) b on a.name=b.maxfwhere  employee_id=1

第二个问题,首先需要设置一个上下班的时间,OE自带的resource.canlendar.attendance类可以设置上下班时间,具体设置位置在:设置->底层对象->资源->工作时间。
系统自带的设置我认为并不太适合中国的情况,每一天的时间都要单独设置,难道老外每天上班的时间都不同的?不过貌似这个工作时间主要是用来设置劳动合同中的工作时间项目的。
不管怎样,现在只要设置一天的时间即可,通过当前时间与设置时间的比较,来判断是否迟到,以及是否过了或还未到打卡时间。
代码如下:

  1. work_time=self._get_work_time(cr,uid,context=context)#[(8.75, 17.5)]work_time_in=string.atof(work_time[0][0])current_time=now.hour+now.minute/60if current_time>work_time_in:     diff=current_time-work_time_in     diff_f=diff-int(diff)#取小数位计算分钟数     raise osv.except_osv(_('错误!'),_("今天你迟到了%s小时%s分钟"%(int(diff),int(diff_f*60))))     return False
复制代码

这里要提到两个问题,一个是设置上下班时间后,系统内的时间字段的定义是否float型的,也就是说,你设置的8:30的上班时间,取值出来则是8.5,xml中有一个新的widget被使用,这个在6.1下是没有见过的:
<field name="hour_from" widget="float_time"/>
另外一个问题是Python本身的问题,如2/3在一般情况下的返回值是0,要想得到实际的计算结果,就必须加入:
from  __future__  import division
另外,7.0下的时区还是有问题,datetime.datetime.today()取不到正确的时间,令人郁闷。


回复

使用道具 举报

3

主题

8

帖子

21

积分

新手上路

Rank: 1

积分
21
沙发
 楼主| 发表于 2015-9-2 20:14:48 | 只看该作者
要想实现在一定条件下,点击签到图标弹出对话窗口,还是有一定的麻烦,使用一般的窗口弹出代码没有效果,经过2个晚上的研究,才通过修改js程序实现了这个目的。

在hr_attendance下有个static目录,全部copy到extension目录下,删除css和xml,只保留js,因为hr_attendance_extension类继承自hr_attendance,因此这个新的js文件将完全代替原目录下的js文件,这点和django是一样的。

修改原来的do_update_attendance函数,如下:
复制代码

do_update_attendance: function () {
            var self = this;
            //jerry add start 弹出考勤说明对话框
            var action = {
                type: 'ir.actions.act_window',
                res_model: 'hr.attendance.reason',
                view_mode: 'form',
                view_type: 'form',
                views: [[false, 'form']],
                target: 'new',
                context: {}
            };
            var hr_attendance_extension =new instance.web.Model("hr.attendance")
            var self = this;
            hr_attendance_extension.call('get_status', [[]]).then(function (result){               
                //员工迟到1小时之内,或者下班前一小时之内,弹出对话框               
                if(result=='late' || result=='leave_early'){
                    instance.client.action_manager.do_action(action);
                }
                //原计划弹出对话框后,先不要将考勤情况写入,图标也不要变化,但是实现不了。
                //因此改成,点击对话框的确定按钮后,更新之前的记录,加入考勤说明
            //jerry add end*************************************
                var hr_employee = new instance.web.DataSet(self, 'hr.employee');
                hr_employee.call('attendance_action_change', [
                    [self.employee.id]
                ]).done(function (result) {
                        //签到图标更换
                        self.last_sign = new Date();
                        self.set({"signed_in": ! self.get("signed_in")});
                    });
            });
        },

复制代码

由于对js一点也不熟悉,导致走了好多冤枉路,不过最终有成果,还是令人欣慰的。

这里记录一下遇到的问题,和仍有价值的弯路。

1、javescript时间计算,copy自网络,感谢原作者。
复制代码

/*
         * 获得时间差,时间格式为 年-月-日 小时:分钟:秒 或者 年/月/日 小时:分钟:秒
         * 其中,年月日为全格式,例如 : 2010-10-12 01:00:00
         * 返回精度为:秒,分,小时,天
         */
        GetDateDiff:function(startTime, endTime, diffType) {
            //将xxxx-xx-xx的时间格式,转换为 xxxx/xx/xx的格式
            //startTime = startTime.replace(/\-/g, "/");
            //endTime = endTime.replace(/\-/g, "/");
            //将计算间隔类性字符转换为小写
            diffType = diffType.toLowerCase();
            var sTime = new Date(startTime); //开始时间
            var eTime = new Date(endTime); //结束时间
            //作为除数的数字
            var divNum = 1;
            switch (diffType) {
                case "second":
                    divNum = 1000;
                    break;
                case "minute":
                    divNum = 1000 * 60;
                    break;
                case "hour":
                    divNum = 1000 * 3600;
                    break;
                case "day":
                    divNum = 1000 * 3600 * 24;
                    break;
                default:
                    break;
            }
            return parseInt((eTime.getTime() - sTime.getTime()) / parseInt(divNum));
        },

复制代码

一开始为了使用这个函数,计算当前时间和设定的工作时间的差,在py文件中建立了一个获取work_time的函数,并且转为datetime类型的,然后在js中调用,结果总是提示internal 500 error,耽误了不少时间,后来直接将所有的动作都在py中完成,只将status传进来,就再也没有问题了。

2、Float转datetime的函数,也许以后会用到。
复制代码

def _time_to_datetime(self,time):
        now=datetime.datetime.now()
        float_time=string.atof(time)
        h=int(float_time)
        m=int((float_time-h)*60)
        datetime_time=datetime.datetime(year=now.year,month=now.month,day=now.day,hour=h,minute=m)
        return datetime_time

复制代码

考勤的基本功能就是这样,接下来是数据统计,准备来尝试实现考勤的报表,另外与工资模块结合,晚点再做。

回复 支持 反对

使用道具 举报

3

主题

8

帖子

21

积分

新手上路

Rank: 1

积分
21
板凳
 楼主| 发表于 2015-9-2 20:15:47 | 只看该作者
官方模块hr_holiday中可以通过配置实现,包括请假,外出,出差等行为的管理,但是菜单的名称Leave Request的翻译,却是个问题。在群里讨论了一下,翻译成请假申请和外出申请都不太合适,除非新建其他的菜单管理出差等事项。

因此最终决定自定义菜单,上层菜单:考勤管理,子菜单包括:个人考勤,准假分配,考勤审批,考勤查询(菜单名称参考了某OA,我觉得这样更符合国人的习惯)。



记录一个问题,系统中默认的日历视图的第一天是周日,但是我们一般认为周一是第一天,因此需要修改:addons/web/static/lib/datejs/globalization/zh-CN.js文件下的:

firstDayOfWeek: 1, #默认是0

修改完后注意要清空浏览器缓存,否则视图不会变化。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|技术支持|开发手册|Odoo中文网-远鼎旗下odoo培训网站 ( 苏ICP备15039516号 )

GMT+8, 2024-4-24 01:44 , Processed in 0.011568 second(s), 8 queries , Xcache On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表