新单位对考勤的核算要求比较高,员工在平时工作日和周末的加班要分开核算,普员和中干的加班核算方式不同,中干的平时加班是不算加班费的,加班小时数要按季度算工作,员工可以在季末申请剩余的小时数结转到下个季度,加班要逐次累计,有加班数才可以调休,调休数不可以大于可用的加班数。员工要能实时看见自己的可用加班数。如果没有或不够,不让建流程。要方便考勤人员查看每个人的数据确定考勤,因为必须得一个一个看。
怎么样,是不是有点晕啊。
开始吧。
首先声明,公司的OA系统是基于泛微Ecology8. 总体需要考虑几个大的部分:
1、员工考勤数据的可视化和流程控制,强调实时性
这要包含具体的流程表单的控制,也要有统计报表。
2、方便考勤人员核算
主要是通过流程节点控制和优化,当然,完全的自动化考勤是不可能的。
后台建立两个表:
考勤数据的明细表:包含加班时数、调休时数、请假时数,公休日和工作日用一个flag区分,如HD是公休日,WD是工作日。
考勤数据余额表:这个表是记录季度余额的表,其实也可以不设这个表,但是因为考勤是按季度核算的,有些人的考勤余额要转到下个季度,为了数据清晰和系统性能,还是设计这个表(我不想一下子把1年或几年的数据都查出来),这样最后出来的最多的是余额+本季的数据。
调休时可根据明细表和余额表计算得出可用的调休时数,并显示出来。
剩余可用时数的显示,泛微有现成的doFieldMath()函数,也可以使用ajax,这里不再赘述。
流程生成报表可以泛微的流程节点附加操作挂在自定义接口来实现。在这里加班和调休使用相同的接口,根据标志的不同而进行区分,加班的接口放在归档处(因为需要人事专员确认实际的加班时数),调休的接口放在人事专员之前。
上接口代码:
package develop.workflow;
import weaver.interfaces.workflow.action.Action;
import weaver.general.BaseBean;
import weaver.soa.workflow.request.RequestInfo;
import weaver.soa.workflow.request.Property;
import weaver.conn.RecordSet;
import weaver.general.Util;
import java.text.SimpleDateFormat;
import java.util.*;
public class overTime extends BaseBean implements Action {
public String execute(RequestInfo requestinfo) {
String requestid = requestinfo.getRequestid();
Property[] properties = requestinfo.getMainTableInfo().getProperty();// 获取表单主字段信息
String ymd = Util.null2String(properties[26].getValue());
String userid = Util.null2String(properties[16].getValue());
String avaliable = Util.null2String(properties[30].getValue());
String realhour = Util.null2String(properties[4].getValue());
String series = Util.null2String(properties[34].getValue());
String thistime = Util.null2String(properties[22].getValue());
String qt = Util.null2String(properties[11].getValue());
String sal = Util.null2String(properties[24].getValue());
String delayhour = Util.null2String(properties[25].getValue());
String leave = Util.null2String(properties[10].getValue());
String type = Util.null2String(properties[9].getValue());
String ifconvert = Util.null2String(properties[3].getValue());
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//
String datetime = df.format(new Date());// new Date()
Calendar calendar=Calendar.getInstance();
int mth = calendar.get(Calendar.MONTH) + 1;
int yr = calendar.get(Calendar.YEAR);
String year = String.valueOf(yr);
String month = String.valueOf(mth);
String[] fa = {"1","2","3"};
String[] sa = {"4","5","6"};
String[] ta = {"7","8","9"};
String[] la = {"10","11","12"};
String quarter = "";
String note = "";
String sql = "";
if (Arrays.asList(fa).contains(month)) {
quarter = "1";
}else if(Arrays.asList(sa).contains(month)){
quarter = "2";
}else if(Arrays.asList(ta).contains(month)){
quarter = "3";
}else if(Arrays.asList(la).contains(month)){
quarter = "4";
}
RecordSet rs = new RecordSet();
//计算加班时数,工作日和周末分开,WD工作日。HD周末,法定节假日乘2
if (realhour != "") {
int type1 = Integer.parseInt(type);
if (type1 == 2) {
note = "HD";
double r = Double.valueOf(realhour);
r = r * 2;
String r1 = String.valueOf(r);
sql = "insert into formtable_main_902(requestid,userid,overtime,series,quarter,datetime,year,month,note) values('"+requestid+"','"+userid+"','"+r1+"','"+series+"','"+quarter+"','"+datetime+"','"+year+"', '"+month+"','"+note+"')";
rs.executeSql(sql);
}else {
if (type1 == 0) {
note = "WD";
} else if (type1 == 1) {
note = "HD";
}
sql = "insert into formtable_main_902(requestid,userid,overtime,series,quarter,datetime,year,month,note) values('"+requestid+"','"+userid+"','"+realhour+"','"+series+"','"+quarter+"','"+datetime+"','"+year+"', '"+month+"','"+note+"')";
rs.executeSql(sql);
}
}
//计算无调休的请假,全部请假
note = "LV";
int cv = Integer.parseInt(ifconvert);
if (ifconvert != "") {
if (cv == 0) {
sql = "insert into formtable_main_902(requestid,userid,on_leave,series,quarter,datetime,year,month,note) values('"+requestid+"','"+userid+"','"+leave+"','"+series+"','"+quarter+"','"+datetime+"','"+year+"', '"+month+"','"+note+"')";
rs.executeSql(sql);
}
else if (cv == 1) {
// 部分请假
float pt1 = Float.parseFloat(leave);
float pt2 = Float.parseFloat(thistime);
float pt3 = pt1 - pt2;
if (pt3 > 0) {
//请假的部分
String pt = String.valueOf(pt3);
sql = "insert into formtable_main_902(requestid,userid,on_leave,series,quarter,datetime,year,month,note) values('"+requestid+"','"+userid+"','"+pt+"','"+series+"','"+quarter+"','"+datetime+"','"+year+"', '"+month+"','"+note+"')";
rs.executeSql(sql);
}
}
}
//计算调休
if (thistime != "" && cv != 0) {
note = "OF";
sql = "insert into formtable_main_902(requestid,userid,overoff,series,quarter,datetime,year,month,note) values('"+requestid+"','"+userid+"','"+thistime+"','"+series+"','"+quarter+"','"+datetime+"','"+year+"', '"+month+"','"+note+"')";
rs.executeSql(sql);
}
//季末延迟调休
if (qt != "") {
//发薪部分
if (sal != "") {
note = "Q_SAL";
sql = "insert into formtable_main_905(requestid,userid,sal,series,quarter,datetime,year,month,note) values('"+requestid+"','"+userid+"','"+sal+"','"+series+"','"+quarter+"','"+datetime+"','"+year+"', '"+month+"','"+note+"')";
rs.executeSql(sql);
sql = "insert into formtable_main_902(requestid,userid,sal,series,quarter,datetime,year,month,note) values('"+requestid+"','"+userid+"','"+sal+"','"+series+"','"+quarter+"','"+datetime+"','"+year+"', '"+month+"','"+note+"')";
rs.executeSql(sql);
}
//平衡本季余额
note = "Q_END";
sql = "insert into formtable_main_902(requestid,userid,overoff,series,quarter,datetime,year,month,note) values('"+requestid+"','"+userid+"','"+avaliable+"','"+series+"','"+quarter+"','"+datetime+"','"+year+"', '"+month+"','"+note+"')";
rs.executeSql(sql);
//将结转部分转到下月期初
float s1 = 0;
float s2 = 0;
float off = 0;
float q_bal_hd = 0;
float q_bal_wd = 0;
float q_lv = 0;
String quarter1 ="";
String year1 ="";
String month1 = "";
//本季总的平时加班数
note = "WD";
sql = "select sum(overtime) as sum from formtable_main_902 where note = '"+note+"' and quarter = '"+quarter+"' and year = '"+year+"' and userid = '"+userid+"'";
rs.executeSql(sql);
if (rs.next()) {
s1 = rs.getFloat("sum");
}
//周末加班数
note = "HD";
sql = "select sum(overtime) as sum from formtable_main_902 where note = '"+note+"' and year = '"+year+"' and quarter = '"+quarter+"' and userid = '"+userid+"'";
rs.executeSql(sql);
if (rs.next()) {
s2 = rs.getFloat("sum");
}
//调休数
note = "OF";
sql ="select sum(overoff) as sum from formtable_main_902 where note = '"+note+"' and quarter = '"+quarter+"' and year = '"+year+"' and userid = '"+userid+"'";
rs.executeSql(sql);
if (rs.next()) {
off = rs.getFloat("sum");
if(off < 0)
off = 0;
}
//上季度加班余额
note = "Q_BAL_WD";
sql = "select sum(overtime) as overtime from formtable_main_905 where note = '"+note+"' and quarter = '"+quarter+"' and year = '"+year+"' and userid = '"+userid+"'";
rs.executeSql(sql);
if (rs.next()) {
q_bal_wd = rs.getFloat("overtime");
if (q_bal_wd < 0)
q_bal_wd = 0;
}
s1 = s1 + q_bal_wd;
note = "Q_BAL_HD";
sql = "select sum(overtime) as overtime from formtable_main_905 where note = '"+note+"' and quarter = '"+quarter+"' and year = '"+year+"' and userid = '"+userid+"'";
rs.executeSql(sql);
if (rs.next()) {
q_bal_hd = rs.getFloat("overtime");
if (q_bal_hd < 0)
q_bal_hd = 0;
}
s2 = s2 + q_bal_hd;
float s3 = s1 - off;
float hd_bal = 0;
float wd_bal = 0;
if (s3 < 0) {
hd_bal = s2 + s3;
wd_bal = 0;
} else {
wd_bal = s3;
hd_bal = s2;
}
float d1 = Float.parseFloat(sal);
float s4 = wd_bal - d1;
if (s4 < 0) {
hd_bal = hd_bal + s4;
wd_bal = 0;
} else {
// hd_bal = hd_bal;
wd_bal = s4;
}
//结转到下季
if (quarter == "1" || quarter == "2" || quarter == "3") {
int q = Integer.parseInt(quarter);
q = q + 1;
quarter1 = String.valueOf(q);
year1 = year;
int mth1 = mth + 1;
month1 = String.valueOf(mth1);
} else if (quarter == "4") {
quarter1 = "1";
int y = Integer.parseInt(year);
y = y + 1;
year1 = String.valueOf(y);
month1 = "1";
}
if (hd_bal > 0) {
note = "Q_BAL_HD";
sql = "insert into formtable_main_905(requestid,userid,overtime,series,quarter,datetime,year,month,note) values('"+requestid+"','"+userid+"','"+hd_bal+"','"+series+"','"+quarter1+"','"+datetime+"','"+year1+"', '"+month1+"','"+note+"')";
rs.executeSql(sql);
}
if (wd_bal > 0) {
note = "Q_BAL_WD";
sql = "insert into formtable_main_905(requestid,userid,overtime,series,quarter,datetime,year,month,note) values('"+requestid+"','"+userid+"','"+wd_bal+"','"+series+"','"+quarter1+"','"+datetime+"','"+year1+"', '"+month1+"','"+note+"')";
rs.executeSql(sql);
}
sql = "select sum(on_leave) as sum from formtable_main_902 where year = '"+year+"' and quarter = '"+quarter+"' and userid = '"+userid+"'";
rs.executeSql(sql);
if (rs.next()) {
q_lv = rs.getFloat("sum");
if (q_lv > 0) {
note = "Q_LV";
sql = "insert into formtable_main_905(requestid,userid,on_leave,quarter,datetime,year,month,note) values('"+requestid+"','"+userid+"','"+q_lv+"','"+quarter+"','"+datetime+"','"+year+"', '"+month+"','"+note+"')";
rs.executeSql(sql);
}
}
}
return SUCCESS ;
}
}
到这里第一部分基本完成了,但是还需要再加一点工作,就是流程的校验,比如可调休时数为0,不允许提交流程,不允许调休超过可调休时数的流程。就用泛微提供的函数:checkCustomize,该函数在流程提交时进行校验,如果不通过就返回 false,流程就不能提交了。
至此第一部分就完成了。
由于考勤人员需要对每个人核对考勤,还要换算保留两位小数,可以看到考勤人员的工作量还是比较大的。
思路是整合考勤系统,在具体的审批单的考勤节点设置两个按钮“查考勤”和“填考勤”,查考勤功能通过ajax获取申请人那一天的考勤数据,形成一个页面,然后返回给主单据页面,祝单据页面在适当位置建立一个iframe,src指向这个页面就OK了。当然这个页面除了显示考勤数据外,还要有计算加班时数的功能,要能区分工作日和公休日,考勤数据没有形成的时候也不至于报错。
效果如下:
点击“查考勤"按钮:
怎么样,是不是极大的提高了效率。
转载请注明出处。