东宝资讯
聚焦东宝动态,了解行业前沿

智能识别加班场景计算员工用餐补贴

日期2024-11-08浏览量162次 发布者网站运营

1、需求场景:

某客户企业为上市公司,公司员工规模800人左右,根据公司企业发展需要,后续公司员工规模还会持续性增长。因客户没有人力资源管理系统,所有的考勤、薪资、计件都是人工手动计算,同时客户班次分类较多、较杂,当每个月每个事业部的考勤文员在核算员工的考勤时都比较痛苦,其中有一个加班补贴的核算场景,文员都是人工根据打卡数据以及纸质单据识别出来的加班餐补补贴。现客户使用东宝人力资源管理系统,希望此需求能通过系统自动计算,减少人工成本。规则如下:

加班餐补.jpg

①加班需要打卡,并且提交加班单才计算加班餐补补贴。

②满足以下场景,才计算加班餐补补贴。

③日报统计加班餐补补贴次数,薪资核算加班餐补补贴。


2、解决方案:

通过在东宝DHG系统配置的自定义过程实现,系统自动根据员工的打卡或加班单来统计不同的餐次次数。考勤汇总餐补次数,薪酬核算餐补费用。

考勤数据.jpg

加班单.jpg

工时日报.jpg

以下是自定义识别加班场景来计算餐补的代码实现部分:

/*  加班统计餐次
脚本执行的标识:工时日报-工时计算最后处理
1. 根据日报班段时间,将其中加班段处理为 "找餐时间段"
   - 如果员工的考勤制度勾选了加班需申请,那餐补次数的统计需要根据员工的加班单结合打卡时间来计算餐补次数。否则,只需要根据打卡来计算加班餐补的次数。
     - 无需特殊处理:该控制会影响日报的班段结果,直接按日报班段结果处理即可
2. 固定的餐补应上下班时间、餐补
3. 匹配就餐
    - “找餐时间段” 匹配 “就餐应上下班时间段”,计加班餐次
*/
var debug = type.new("java.lang.StringBuilder");
try {
    // 处理前置空(保障更新原本算出来,现在算不出来的数据)
    // 早餐
    workHourDayDTO.attWorkHourDay.extField['c_overtime_breakfast'] = 0;
    // 中餐
    workHourDayDTO.attWorkHourDay.extField['c_overtime_lunch'] = 0;
    // 晚餐
    workHourDayDTO.attWorkHourDay.extField['c_overtime_dinner'] = 0;
    // 夜宵
    workHourDayDTO.attWorkHourDay.extField['c_overtime_night_snack'] = 0;


    // 1. 根据日报班段时间,将其中加班段处理为 "找餐时间段"
    var workBucketDTOList = workHourDayDTO.workShiftDTO.workBucketDTOList;
    // 4-请假 6-停工 7-旷工 8-休假
    // 1-正班 3-休息
    // 5-出差正班 51-出差加班 52-出差其他加班 62-出差推后加班 61-出差提前加班
    // 11-正班提前加班 12-正班推后加班 2-正班加班
    // 81-休假加班 82-休假其他加班
    var overtimeBucketType = @com.google.common.collect.Sets.newHashSet(5, 51, 52, 61, 62, 11, 12, 2, 81, 82);
    var currFindRepastRange = null;
    var findRepastRangeList = [];
    for (var workBucketDTO in workBucketDTOList) {
        for (var workHourDayBucketDTO in workBucketDTO.workHourDayBucketDTOList) {
            @debug.append("

[").append(workHourDayBucketDTO.workBucketType).append("]");
            @debug.append(workHourDayBucketDTO.workTimeBegin).append(" - ").append(workHourDayBucketDTO.workTimeEnd);
            if (workHourDayBucketDTO.effectiveWorkHour && @overtimeBucketType.contains(workHourDayBucketDTO.workBucketType)) {
                @debug.append("
有效加班段");
                if (currFindRepastRange == null) {
                    var begin = workHourDayBucketDTO.cardTimeBegin != null
                            ? workHourDayBucketDTO.cardTimeBegin
                            : workHourDayBucketDTO.workTimeBegin;

                    var end = workHourDayBucketDTO.cardTimeEnd != null
                            ? workHourDayBucketDTO.cardTimeEnd
                            : workHourDayBucketDTO.workTimeEnd;
                    currFindRepastRange = {
                            begin: begin,
                            end: end
                    };
                    @debug.append("
初始找餐时间段:").append(currFindRepastRange.begin).append(" - ").append(currFindRepastRange.end);
                } else {
                    currFindRepastRange.end = workHourDayBucketDTO.cardTimeEnd != null
                            ? workHourDayBucketDTO.cardTimeEnd
                            : workHourDayBucketDTO.workTimeEnd;
                    @debug.append("
合并紧邻的有效加班段:~ ").append(currFindRepastRange.end);
                }
            } else {
                @debug.append(workHourDayBucketDTO.effectiveWorkHour ? "
非加班段" : "
无效时段");
                if (currFindRepastRange != null) {
                    @debug.append("
记录当前的找餐时间段:");
                    @debug.append(currFindRepastRange.begin).append(" - ").append(currFindRepastRange.end);
                    @findRepastRangeList.add(currFindRepastRange);
                    currFindRepastRange = null;
                }
            }
        }
    }
    if (currFindRepastRange != null) {
        @debug.append("
记录最后的找餐时间段:");
        @debug.append(currFindRepastRange.begin).append(" - ").append(currFindRepastRange.end);
        @findRepastRangeList.add(currFindRepastRange);
    }

    // 2. 固定的餐补应上下班时间、餐补
    var repastTimeConfList = [
            // 早餐:6元/次,打卡时间为7:00前(含7点整);
            { flag: "breakfast", begin: "07:00", end: "07:00", cnt: 0 },
            // 中餐:15元/次,上班打卡时间为10:00前(含10点整)并加班餐补下班打卡时间为14:00后(含14点整);
            { flag: "lunch", begin: "10:00", end: "14:00", cnt: 0 },
            // 晚餐:15元/次,打卡时间为20:00后(含20点整);
            { flag:"dinner", begin: "20:00", end: "20:00", cnt: 0 },
            // 夜宵:6元/次,打卡时间为24:00后(含24点整)。
            { flag: "night_snack", begin: "00:00", end: "00:00", cnt: 0 }
            //
    ];
    // 取进三天就餐具体时间
    var repastDateTimeRangeList = [];
    var attendanceDate = workHourDayDTO.attWorkHourDay.attendanceDate;
    for (var i = -1; i <= 1; i++) {
        var date = @com.dongbao.core.util.DateUtil.dayOffset(attendanceDate, i);
        for (var repastTimeConf in repastTimeConfList) {
            @repastDateTimeRangeList.add({
                    conf: repastTimeConf,
                    begin: @com.dongbao.core.util.DateUtil.getDateTime(date, repastTimeConf.begin),
                    end: @com.dongbao.core.util.DateUtil.getDateTime(date, repastTimeConf.end)
            });
        }
    }

    // 3. 匹配就餐
    var i = 0;
    var j = 0;
    while (i < @findRepastRangeList.size() && j < @repastDateTimeRangeList.size()) {
        var findRepastRange = findRepastRangeList[i];
        var repastDateTimeRange = repastDateTimeRangeList[j];
        var isLater = repastDateTimeRange.begin < findRepastRange.begin;
        var isEarly = repastDateTimeRange.end > findRepastRange.end;
        if (isLater) {
            // 饭点过了——就餐时间早于找餐时间,接着找下段就餐时间
            j++;
        } else if (isEarly) {
            // 饭点没到——就餐时间晚于找餐时间,接着找下一段加班时间
            i++;
        } else {
            // 包含饭点——匹配,计对应加班餐次,接着找下段就餐时间
            @debug.append("

匹配到餐点:");
            @debug.append(repastDateTimeRange.begin).append(" - ").append(repastDateTimeRange.end);
            @debug.append("
加班时间段:");
            @debug.append(findRepastRange.begin).append(" - ").append(findRepastRange.end);
            var conf = repastDateTimeRange.conf;
            conf.cnt = conf.cnt + 1;
            @debug.append("
餐补次数 - ").append(conf.flag).append(": ").append(conf.cnt);
            j++;
        }
    }

    // 4. 自定义字段赋值
    for (var conf in repastTimeConfList) {
        workHourDayDTO.attWorkHourDay.extField["c_overtime_" + conf.flag] = conf.cnt;
    }
} catch (e) {
    var writer = type.new("StringWriter");
    var printer = @org.codehaus.groovy.runtime.IOGroovyMethods.newPrintWriter(writer);
    @e.printStackTrace(printer);
    @debug.append("

").append(writer);
}

3、应用价值:

①系统自动根据班次、打卡、加班单识别不同类型的加班餐次,考勤文员由原来每月人工识别,缩短为系统实时数据更新,省时省力。

②日考勤机准确率提升至100%,同时每月能快速高效完结考勤月报。