超实用的精细化处理考勤(原创)

如何精细化处理考勤

新单位对考勤的核算要求比较高,员工在平时工作日和周末的加班要分开核算,普员和中干的加班核算方式不同,中干的平时加班是不算加班费的,加班小时数要按季度算工作,员工可以在季末申请剩余的小时数结转到下个季度,加班要逐次累计,有加班数才可以调休,调休数不可以大于可用的加班数。员工要能实时看见自己的可用加班数。如果没有或不够,不让建流程。要方便考勤人员查看每个人的数据确定考勤,因为必须得一个一个看。
怎么样,是不是有点晕啊。
开始吧。

设计

首先声明,公司的OA系统是基于泛微Ecology8. 总体需要考虑几个大的部分:
1、员工考勤数据的可视化和流程控制,强调实时性
这要包含具体的流程表单的控制,也要有统计报表。
2、方便考勤人员核算
主要是通过流程节点控制和优化,当然,完全的自动化考勤是不可能的。

技术实现

第一部分:考勤数据可视化

后台建立两个表:
考勤数据的明细表:包含加班时数、调休时数、请假时数,公休日和工作日用一个flag区分,如HD是公休日,WD是工作日。
考勤数据余额表:这个表是记录季度余额的表,其实也可以不设这个表,但是因为考勤是按季度核算的,有些人的考勤余额要转到下个季度,为了数据清晰和系统性能,还是设计这个表(我不想一下子把1年或几年的数据都查出来),这样最后出来的最多的是余额+本季的数据。

形成
调用
结转
加班流程
明细表
调休流程
余额表

效果

加班流程表单:
超实用的精细化处理考勤(原创)_第1张图片
生成的明细表:
超实用的精细化处理考勤(原创)_第2张图片

季末形成的余额表,这个通过泛微的计划任务接口做:
超实用的精细化处理考勤(原创)_第3张图片

调休时可根据明细表和余额表计算得出可用的调休时数,并显示出来。
超实用的精细化处理考勤(原创)_第4张图片

剩余可用时数的显示,泛微有现成的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,流程就不能提交了。

超实用的精细化处理考勤(原创)_第5张图片

至此第一部分就完成了。

第二部分 方便考勤人员

由于考勤人员需要对每个人核对考勤,还要换算保留两位小数,可以看到考勤人员的工作量还是比较大的。
思路是整合考勤系统,在具体的审批单的考勤节点设置两个按钮“查考勤”和“填考勤”,查考勤功能通过ajax获取申请人那一天的考勤数据,形成一个页面,然后返回给主单据页面,祝单据页面在适当位置建立一个iframe,src指向这个页面就OK了。当然这个页面除了显示考勤数据外,还要有计算加班时数的功能,要能区分工作日和公休日,考勤数据没有形成的时候也不至于报错。
效果如下:
超实用的精细化处理考勤(原创)_第6张图片
点击“查考勤"按钮:
超实用的精细化处理考勤(原创)_第7张图片

点击”填考勤“按钮,会将实际考勤时数填写。
超实用的精细化处理考勤(原创)_第8张图片

怎么样,是不是极大的提高了效率。
转载请注明出处。

你可能感兴趣的:(泛微OA,泛微,流程,考勤,接口)