package com.kingdee.eas.custom.attendanceexception.task;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.kingdee.bos.metadata.entity.*;
import com.kingdee.bos.metadata.query.util.CompareType;
import com.kingdee.eas.basedata.org.AdminOrgUnitCollection;
import com.kingdee.eas.basedata.org.AdminOrgUnitFactory;
import com.kingdee.eas.basedata.org.AdminOrgUnitInfo;
import com.kingdee.eas.basedata.org.IAdminOrgUnit;
import com.kingdee.eas.custom.attendanceexception.*;
import com.kingdee.eas.custom.attendanceexception.bean.SyncAttendanceDataBean;
import com.kingdee.eas.custom.attendanceexception.bizEnum.PushTypeEnum;
import com.kingdee.eas.fi.arap.util.DBUtil;
import com.kingdee.eas.hr.ats.AttendanceFileCollection;
import com.kingdee.eas.hr.ats.AttendanceFileFactory;
import com.kingdee.eas.hr.ats.IAttendanceFile;
import com.kingdee.eas.hr.ats.util.AtsDateUtils;
import com.kingdee.jdbc.rowset.IRowSet;
import com.kingdee.shr.base.syssetting.CallStatusEnum;
import com.kingdee.util.DateTimeUtils;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import com.kingdee.bos.*;
import com.kingdee.eas.common.EASBizException;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.String;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

public class AttendanceExceptionFacadeControllerBean extends AbstractAttendanceExceptionFacadeControllerBean {
    private static Logger logger = Logger.getLogger(AttendanceExceptionFacadeControllerBean.class);
    private Properties propt = new Properties();
    //来源标识
    private static final String SOURCE = "EHR";


    public AttendanceExceptionFacadeControllerBean() throws BOSException {
        String syncOAConfigPath = System.getProperty("EAS_HOME") + "/server/properties/scy/attendanceException.properties";
        try {
            propt.load(new FileInputStream(syncOAConfigPath));
        } catch (IOException e) {
            e.printStackTrace();
            String errorMsg = "获取配置文件报错，请检查配置：" + syncOAConfigPath + "   " + e.getMessage();
            throw new BOSException(errorMsg);
        }
    }

    /**
     * 员工个人异常提醒
     *
     * @param ctx
     * @throws BOSException
     * @throws EASBizException
     */
    @Override
    protected void _notifyEmployeeException(Context ctx) throws BOSException, EASBizException {
        long startTime = System.currentTimeMillis();
        if (logger.isInfoEnabled()) {
            logger.info("AttendanceExceptionFacadeControllerBean.notifyEmployeeException start");
        }
        super._notifyEmployeeException(ctx);
        IAttendanceExceptionLog iAttendanceExceptionLog = AttendanceExceptionLogFactory.getLocalInstance(ctx);
        PushTypeEnum pushTypeEnum = PushTypeEnum.EMPLOYEEREMINDER;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd E HH:mm:ss");
        //昨天
        Date preDay = AtsDateUtils.getPreDay(new Date());
        logger.error("_notifyEmployeeCumulativeException preDay: " + sdf.format(preDay));
        //1.查询异常数据
        Map<String, List<SyncAttendanceDataBean>> exceptionData = getAttendanceExceptionData(ctx, preDay, preDay, pushTypeEnum, 0);
        String yearMonthDay = DateTimeUtils.format(preDay, "yyyy年MM月dd日");
        for (String personNumber : exceptionData.keySet()) {
            String msgId = UUID.randomUUID().toString();
            AttendanceExceptionLogInfo logInfo = new AttendanceExceptionLogInfo();
            logInfo.setMessageId(msgId);
            logInfo.setPushType(pushTypeEnum);
            try {
                //发送异常消息
                JSONObject dingMsgBean = new JSONObject();
                dingMsgBean.put("msgTempCode", "work_notice_03");
                dingMsgBean.put("toAllUser", false);
                dingMsgBean.put("userIdList", personNumber);
                dingMsgBean.put("source", SOURCE);
                JSONObject param = new JSONObject();
                //消息id
                param.put("msgId", msgId);
                //时间
                param.put("time", yearMonthDay);
                dingMsgBean.put("param", param);
                sendAttendanceExceptionMsg(dingMsgBean, logInfo);
                //推送异常数据
                List<SyncAttendanceDataBean> syncAttendanceDataBeans = exceptionData.get(personNumber);
                syncAttendanceDataBeans.stream().forEach(syncAttendanceDataBean -> {
                    syncAttendanceDataBean.setMsgId(msgId);
                });
                pushAttendanceExceptionData(syncAttendanceDataBeans, logInfo);
            } catch (Exception e) {
                String message = e.getMessage();
                logger.error("员工个人异常提醒报错 " + message, e);
                if (message.contains("connect timed out")) {
                    iAttendanceExceptionLog.save(logInfo);
                    break;
                }
                logInfo.setPushStatus(CallStatusEnum.failure);
                logInfo.setPushResult(message);
            }
            //保存消息记录
            iAttendanceExceptionLog.save(logInfo);
        }
        if (logger.isInfoEnabled()) {
            long endTime = System.currentTimeMillis();
            float duration = (endTime - startTime) / 1000f;
            logger.info(String.format("AttendanceExceptionFacadeControllerBean.notifyEmployeeException end, duration: %fS", duration));
        }
    }

    /**
     * 员工考勤异常关怀提醒
     *
     * @param ctx
     * @param exceptionLimit 异常次数上限
     * @throws BOSException
     * @throws EASBizException
     */
    @Override
    protected void _notifyEmployeeCumulativeException(
            Context ctx,
            String exceptionLimit
    ) throws BOSException, EASBizException {
        long startTime = System.currentTimeMillis();
        if (logger.isInfoEnabled()) {
            logger.info("AttendanceExceptionFacadeControllerBean.notifyEmployeeCumulativeException start");
        }
        super._notifyEmployeeCumulativeException(ctx, exceptionLimit);
        int limit = 5;
        if (StringUtils.isNotBlank(exceptionLimit)) {
            limit = Integer.parseInt(exceptionLimit);
        }
        IAttendanceExceptionLog iAttendanceExceptionLog = AttendanceExceptionLogFactory.getLocalInstance(ctx);
        PushTypeEnum pushTypeEnum = PushTypeEnum.EMPLOYEEEXCEPTIONALERT;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd E HH:mm:ss");
        Date today = new Date();
        //当前月第一天
        Date currentFirstDay = AtsDateUtils.getCurrentFirstDay(today);
        logger.error("_notifyEmployeeCumulativeException currentFirstDay: " + sdf.format(currentFirstDay));
        //昨天
        Date preDay = AtsDateUtils.getPreDay(today);
        logger.error("_notifyEmployeeCumulativeException preDay: " + sdf.format(preDay));
        //查询异常数据
        Map<String, List<SyncAttendanceDataBean>> exceptionData = getAttendanceExceptionData(ctx, currentFirstDay, preDay, pushTypeEnum, limit);
        String yearMonth = DateTimeUtils.format(today, "yyyy年MM月");
        for (String personNumber : exceptionData.keySet()) {
            String msgId = UUID.randomUUID().toString();
            AttendanceExceptionLogInfo logInfo = new AttendanceExceptionLogInfo();
            logInfo.setMessageId(msgId);
            logInfo.setPushType(pushTypeEnum);
            try {
                //发送异常消息
                JSONObject dingMsgBean = new JSONObject();
                dingMsgBean.put("msgTempCode", "work_notice_02");
                dingMsgBean.put("toAllUser", false);
                dingMsgBean.put("userIdList", personNumber);
                dingMsgBean.put("source", SOURCE);
                JSONObject param = new JSONObject();
                //消息id
                param.put("msgId", msgId);
                //时间
                param.put("time", yearMonth);
                //考勤异常人数
                param.put("eorNum", limit);
                dingMsgBean.put("param", param);
                sendAttendanceExceptionMsg(dingMsgBean, logInfo);
                //推送异常数据
                List<SyncAttendanceDataBean> syncAttendanceDataBeans = exceptionData.get(personNumber);
                syncAttendanceDataBeans.stream().forEach(syncAttendanceDataBean -> {
                    syncAttendanceDataBean.setMsgId(msgId);
                });
                pushAttendanceExceptionData(syncAttendanceDataBeans, logInfo);
                //写入提醒记录
                addRemindRecord(ctx, yearMonth, personNumber);
            } catch (Exception e) {
                String message = e.getMessage();
                logger.error("提醒员工累计异常报错: " + message, e);
                if (message.contains("connect timed out")) {
                    iAttendanceExceptionLog.save(logInfo);
                    break;
                }
                logInfo.setPushStatus(CallStatusEnum.failure);
                logInfo.setPushResult(message);
            }
            //保存消息记录
            iAttendanceExceptionLog.save(logInfo);
        }
        if (logger.isInfoEnabled()) {
            long endTime = System.currentTimeMillis();
            float duration = (endTime - startTime) / 1000f;
            logger.info(String.format("AttendanceExceptionFacadeControllerBean.notifyEmployeeCumulativeException end, duration: %fS", duration));
        }
    }


    /**
     * 提醒中心负责人累计异常
     *
     * @param ctx
     * @throws BOSException
     * @throws EASBizException
     */
    @Override
    protected void _alertLeaderExceptionTotal(Context ctx) throws BOSException, EASBizException {
        long startTime = System.currentTimeMillis();
        if (logger.isInfoEnabled()) {
            logger.info("AttendanceExceptionFacadeControllerBean.alertLeaderExceptionTotal start");
        }
        super._alertLeaderExceptionTotal(ctx);
        IAttendanceExceptionLog iAttendanceExceptionLog = AttendanceExceptionLogFactory.getLocalInstance(ctx);
        //中心负责人关系表
        ICenterLeaderRelation iCenterLeaderRelation = CenterLeaderRelationFactory.getLocalInstance(ctx);
        //获取中心负责人
        Map<String, String> leaders = iCenterLeaderRelation.getLeaders();
        PushTypeEnum pushTypeEnum = PushTypeEnum.CENTERLEADERREMINDER;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd E HH:mm:ss");
        //获取考勤异常数据,本周周一至周五中心考勤异常数据
        Calendar calendar = Calendar.getInstance();
        //Date endDate = calendar.getTime();
        int intWeek = calendar.get(7);
        calendar.add(Calendar.DAY_OF_WEEK, 2 - intWeek);
        Date monday = calendar.getTime();
        logger.error("_alertLeaderExceptionTotal startDate: " + sdf.format(monday));
        //if (intWeek > 6) {
        calendar.add(Calendar.DAY_OF_WEEK, 4);
        Date endDate = calendar.getTime();
        //}
        logger.error("_alertLeaderExceptionTotal endDate: " + sdf.format(endDate));
        //1.查询异常数据
        List<Map<String, Object>> exceptionDataList = getAttendanceExceptionDataForLeader(ctx, monday, endDate, pushTypeEnum);
        String mondayFormat = DateTimeUtils.format(monday, "yyyy年MM月dd日");
        String endDateFormat = DateTimeUtils.format(endDate, "yyyy年MM月dd日");
        for (String orgLongNumber : leaders.keySet()) {
            AttendanceExceptionLogInfo logInfo = new AttendanceExceptionLogInfo();
            String msgId = UUID.randomUUID().toString();
            logInfo.setMessageId(msgId);
            logInfo.setPushType(pushTypeEnum);
            try {
                //获取组织名称
                AdminOrgUnitInfo orgInfo = getOrgInfo(ctx, orgLongNumber);
                String orgName = orgInfo.getName();
                //负责人
                String alertUsers = leaders.get(orgLongNumber);
                if (StringUtils.isBlank(alertUsers)) {
                    throw new BOSException(orgName + "的负责人为空!");
                }
                //考勤总人数(包含下级)
                Integer attendanceCount = getAttendanceCount(ctx, orgLongNumber);
                //迟到人数
                Set<String> lateEmployees = new HashSet<>();
                //早退人数
                Set<String> earlyLeaveEmployees = new HashSet<>();
                //旷工人数
                Set<String> absentEmployees = new HashSet<>();
                //异常人数
                Set<String> exceptionEmployees = new HashSet<>();
                //遍历人员
                List<SyncAttendanceDataBean> syncAttendanceDataBeans = new ArrayList<>();
                exceptionDataList.stream().forEach(map -> {
                    SyncAttendanceDataBean exceptionDataBean = (SyncAttendanceDataBean) map.get("data");
                    //部门长编码
                    String departmentManagerCode = exceptionDataBean.getDepartmentManagerCode();
                    if (departmentManagerCode.startsWith(orgLongNumber)) {
                        Map<String, Boolean> attendanceFlags = (Map<String, Boolean>) map.get("attendanceFlags");
                        String personNumber = exceptionDataBean.getEmployeeId();
                        exceptionDataBean.setMsgId(msgId);
                        syncAttendanceDataBeans.add(exceptionDataBean);
                        exceptionEmployees.add(personNumber);
                        if (attendanceFlags.get("lateEmployees")) {
                            //迟到
                            lateEmployees.add(personNumber);
                        }
                        if (attendanceFlags.get("earlyLeaveEmployees")) {
                            //早退
                            earlyLeaveEmployees.add(personNumber);
                        }
                        if (attendanceFlags.get("absentEmployees")) {
                            //旷工
                            absentEmployees.add(personNumber);
                        }
                    }
                });
                if (syncAttendanceDataBeans.isEmpty()) {
                    //没有异常数据,不发送
                    continue;
                }
                JSONObject dingMsgBean = new JSONObject();
                dingMsgBean.put("msgTempCode", "work_notice_01");
                dingMsgBean.put("toAllUser", false);
                dingMsgBean.put("userIdList", alertUsers);
                dingMsgBean.put("source", SOURCE);
                JSONObject param = new JSONObject();
                //消息id
                param.put("msgId", msgId);
                //时间
                param.put("time", mondayFormat + "-" + endDateFormat);
                //考勤总人数
                param.put("centerNum", attendanceCount);
                //考勤异常人数
                param.put("eorNum", exceptionEmployees.size());
                //迟到人数
                param.put("lateNum", lateEmployees.size());
                //早退人数
                param.put("earlyNum", earlyLeaveEmployees.size());
                //旷工人数
                param.put("hookyNum", absentEmployees.size());
                //中心
                param.put("depart", orgName);
                dingMsgBean.put("param", param);
                //发送异常消息
                sendAttendanceExceptionMsg(dingMsgBean, logInfo);
                //推送异常数据
                pushAttendanceExceptionData(syncAttendanceDataBeans, logInfo);
            } catch (Exception e) {
                String message = e.getMessage();
                logger.error("提醒中心负责人累计异常报错 " + message, e);
                if (message.contains("connect timed out")) {
                    iAttendanceExceptionLog.save(logInfo);
                    break;
                }
                logInfo.setPushStatus(CallStatusEnum.failure);
                logInfo.setPushResult(message);
            }
            //保存消息记录
            iAttendanceExceptionLog.save(logInfo);
        }
        if (logger.isInfoEnabled()) {
            long endTime = System.currentTimeMillis();
            float duration = (endTime - startTime) / 1000f;
            logger.info(String.format("AttendanceExceptionFacadeControllerBean.alertLeaderExceptionTotal end, duration: %fS", duration));
        }
    }

    /**
     * 获取考勤异常数据
     *
     * @param ctx
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return
     * @throws BOSException
     * @throws EASBizException
     */
    protected Map<String, List<SyncAttendanceDataBean>> getAttendanceExceptionData(
            Context ctx,
            Date startDate,
            Date endDate,
            PushTypeEnum pushType,
            int limit
    ) throws BOSException {
        String sql = getSql(startDate, endDate, pushType);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            IRowSet iRowSet = DBUtil.executeQuery(ctx, sql);
            Map<String, List<SyncAttendanceDataBean>> result = new HashMap<>();
            Map<String, Integer> personExceptionTimes = new HashMap<>();
            while (iRowSet.next()) {
                //设置考勤结果和次数
                SyncAttendanceDataBean data = setAttendanceResult(iRowSet, sdf, pushType);
                int times = data.getTimes();
                String personNumber = data.getEmployeeId();
                //累计员工期间总异常次数
                if (personExceptionTimes.containsKey(personNumber)) {
                    Integer i = personExceptionTimes.get(personNumber);
                    personExceptionTimes.put(personNumber, i + times);
                } else {
                    personExceptionTimes.put(personNumber, times);
                }
                if (!result.containsKey(personNumber)) {
                    result.put(personNumber, new ArrayList<>());
                }
                result.get(personNumber).add(data);
            }
            if (PushTypeEnum.EMPLOYEEEXCEPTIONALERT.equals(pushType)) {
                String yearMonth = DateTimeUtils.format(startDate, "yyyy年MM月");
                //获取提醒记录
                Set<String> remindRecord = getRemindRecord(ctx, yearMonth);
                //员工累计异常提醒
                for (Map.Entry<String, Integer> entry : personExceptionTimes.entrySet()) {
                    if (entry.getValue() < limit || remindRecord.contains(entry.getKey())) {
                        //移除没有达到预警上限的数据,获取已经提醒过的人员
                        result.remove(entry.getKey());
                    }
                }
            }
            return result;
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }


    /**
     * 获取中心考勤异常数据
     *
     * @param ctx
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return
     * @throws BOSException
     * @throws EASBizException
     */
    protected List<Map<String, Object>> getAttendanceExceptionDataForLeader(
            Context ctx,
            Date startDate,
            Date endDate,
            PushTypeEnum pushType
    ) throws BOSException {
        String sql = getSql(startDate, endDate, pushType);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        List<Map<String, Object>> attendanceExceptionDatas = new ArrayList<Map<String, Object>>();
        try {
            IRowSet iRowSet = DBUtil.executeQuery(ctx, sql);
            while (iRowSet.next()) {
                Map<String, Object> map = new HashMap<String, Object>();
                //设置考勤结果和次数
                SyncAttendanceDataBean data = setAttendanceResult(iRowSet, sdf, pushType);
                Map<String, Boolean> attendanceFlags = new LinkedHashMap<>();
                attendanceFlags.put("lateEmployees", iRowSet.getInt("s19") > 0);//迟到
                attendanceFlags.put("earlyLeaveEmployees", iRowSet.getInt("s21") > 0);//早退
                attendanceFlags.put("absentEmployees", iRowSet.getBigDecimal("s23").compareTo(BigDecimal.ZERO) > 0);//旷工
                map.put("data", data);
                map.put("attendanceFlags", attendanceFlags);
                attendanceExceptionDatas.add(map);
            }
            return attendanceExceptionDatas;
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 设置考勤结果和次数
     *
     * @param iRowSet
     * @param sdf
     * @throws SQLException
     */
    protected SyncAttendanceDataBean setAttendanceResult(
            IRowSet iRowSet,
            SimpleDateFormat sdf,
            PushTypeEnum pushType
    ) throws SQLException {
        SyncAttendanceDataBean data = new SyncAttendanceDataBean();
        data.setEmployeeId(iRowSet.getString("personNumber"));
        data.setEmployeeName(iRowSet.getString("personName"));
        Date attenceDate = iRowSet.getDate("attenceDate");
        if (attenceDate != null) {
            data.setExceptionDate(sdf.format(attenceDate));
        }
        data.setDepartmentCode(iRowSet.getString("adminOrgNumber"));
        data.setDepartmentName(iRowSet.getString("adminOrgName"));
        data.setDepartmentManagerCode(iRowSet.getString("adminOrgLongNumber"));
        data.setDepartmentSortCode(iRowSet.getString("sortCode"));
        String displayName = iRowSet.getString("displayName");
        if (StringUtils.isNotBlank(displayName)) {
            displayName = displayName.substring(displayName.indexOf("_") + 1, displayName.length());
        }
        data.setDepartmentManagerName(displayName);
        StringBuilder attendanceResult = new StringBuilder();
        int times = 0;
        Map<String, Boolean> attendanceFlags = new LinkedHashMap<>();
        int s19 = iRowSet.getInt("s19");
        int s21 = iRowSet.getInt("s21");
        BigDecimal s23 = iRowSet.getBigDecimal("s23");
        attendanceFlags.put("迟到", s19 > 0);
        attendanceFlags.put("早退", s21 > 0);
        attendanceFlags.put("旷工", s23.compareTo(BigDecimal.ZERO) > 0);
        if (PushTypeEnum.EMPLOYEEEXCEPTIONALERT.equals(pushType)) {
            //员工考勤异常关怀 需要统计 个人原因补卡次数
            int s113 = iRowSet.getInt("s113");
            attendanceFlags.put("个人原因补卡次数", s113 > 0);
        }
        for (Map.Entry<String, Boolean> entry : attendanceFlags.entrySet()) {
            if (entry.getValue()) {
                times++;
                attendanceResult.append(entry.getKey()).append("、");
            }
        }
        // 移除最后一个顿号
        if (attendanceResult.length() > 0) {
            attendanceResult.setLength(attendanceResult.length() - 1);
        }
        data.setTimes(times);
        data.setAttendanceResult(attendanceResult.toString());
        return data;
    }

    /**
     * 获取考勤异常查询sql
     *
     * @param startDate
     * @param endDate
     * @return
     * @throws BOSException
     */
    protected String getSql(
            Date startDate,
            Date endDate,
            PushTypeEnum pushType
    ) throws BOSException {
        if (startDate == null || endDate == null) {
            logger.error("getAttendanceExceptionData startDate or endDate is null");
            throw new BOSException("getAttendanceExceptionData startDate or endDate is null");
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        StringBuilder sql = new StringBuilder()
                .append("select").append("\n")
                .append("    person.fid as personId,").append("\n")
                .append("    person.fnumber as personNumber,").append("\n")
                .append("    person.Fname_l2 as personName,").append("\n")
                .append("    attendanceResult.FAttenceDate as attenceDate,").append("\n")
                .append("    attendanceResult.s19 as s19,").append("\n")
                .append("    attendanceResult.s21 as s21,").append("\n")
                .append("    attendanceResult.s23 as s23,").append("\n")
                .append("    attendanceResult.s113 as s113,").append("\n")
                .append("    adminOrg.fid as adminOrgId,").append("\n")
                .append("    adminOrg.fnumber as adminOrgNumber,").append("\n")
                .append("    adminOrg.fname_l2 as adminOrgName,").append("\n")
                .append("    adminOrg.FLongNumber as adminOrgLongNumber,").append("\n")
                .append("    adminOrg.FSortCode as sortCode,").append("\n")
                .append("    adminOrg.FDisplayName_L2 as displayName").append("\n")
//                .append("    admintwo.fid as admintwoId,").append("\n")
//                .append("    admintwo.fnumber as admintwoNumber,").append("\n")
//                .append("    admintwo.Fname_l2 as admintwoName").append("\n")
                .append("from").append("\n")
                .append("    T_HR_ATS_AttendanceResult attendanceResult").append("\n")
                .append("    left join t_bd_person person on person.fid = attendanceResult.FProposerID").append("\n")
                .append("    left join T_ORG_admin adminOrg on attendanceResult.FAdminOrgUnitID = adminOrg.fid").append("\n")
                //.append("    left join T_ORG_admin admintwo on adminOrg.FLevelTwoGroupID = admintwo.fid").append("\n")
                .append("where").append("\n")
                .append("    attendanceResult.FAttenceDate >= { TS '").append(sdf.format(startDate)).append("' }").append("\n")
                .append("    and attendanceResult.FAttenceDate <= { TS '").append(sdf.format(endDate)).append("' }").append("\n")
                .append("    and (").append("\n")
                .append("        attendanceResult.s19 > 0").append("\n")
                .append("        or attendanceResult.s21 > 0").append("\n")
                .append("        or attendanceResult.s23 > 0").append("\n");
        if (PushTypeEnum.EMPLOYEEEXCEPTIONALERT.equals(pushType)) {
            //员工考勤异常关怀 需要统计 个人原因补卡次数
            sql.append("         or attendanceResult.S113 > 0").append("\n");
        }
        sql.append("    );").append("\n");
        if (logger.isInfoEnabled()) {
            logger.info(String.format("AttendanceExceptionFacadeControllerBean.getSql: %s", sql.toString()));
        }
        return sql.toString();
    }

    /**
     * 发送考勤异常消息
     *
     * @param dingMsgBean
     * @param logInfo
     * @throws BOSException
     */
    protected void sendAttendanceExceptionMsg(
            JSONObject dingMsgBean,
            AttendanceExceptionLogInfo logInfo
    ) throws BOSException {
        try {
            String url = propt.getProperty("sendDingMsgUrl");
            if (url == null || url.isEmpty()) {
                logger.error("pushAttendanceExceptionData url is null");
                throw new BOSException("pushAttendanceExceptionData url is null");
            }
            logger.error("pushAttendanceExceptionData url: " + url);
            if (dingMsgBean == null) {
                logger.error("pushAttendanceExceptionData dingMsgBean is null");
                throw new BOSException("pushAttendanceExceptionData dingMsgBean is null");
            }
            String params = dingMsgBean.toJSONString();
            logInfo.setMessageRequest(params);
            OkHttpClient client = new OkHttpClient();
            MediaType mediaType = MediaType.parse("application/json");
            RequestBody body = RequestBody.create(mediaType, params);
            Request request = new Request.Builder()
                    .url(url)
                    .post(body)
                    .addHeader("Accept", "*/*")
                    .addHeader("Accept-Encoding", "gzip, deflate, br")
                    .addHeader("User-Agent", "PostmanRuntime-ApipostRuntime/1.1.0")
                    .addHeader("Connection", "keep-alive")
                    .addHeader("Content-Type", "application/json")
                    .build();
            Response response = client.newCall(request).execute();
            logger.error("response----" + response.isSuccessful());
            if (response.isSuccessful()) {
                String resultBody = response.body().string();
                logInfo.setMessageResponse(resultBody);
                logger.error("resultBody----" + resultBody);
                JSONObject result = JSONObject.parseObject(resultBody);
                if (result.getBoolean("success")) {
                    logInfo.setPushStatus(CallStatusEnum.success);
                } else {
                    //推送失败
                    throw new BOSException(result.getString("msg"));
                }
            } else {
                throw new BOSException("接口请求超时");
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new BOSException("发送考勤异常消息报错: " + e.getMessage());
        }
    }


    /**
     * 推送考勤异常数据
     *
     * @param list
     * @param logInfo
     * @throws BOSException
     */
    protected void pushAttendanceExceptionData(
            List list,
            AttendanceExceptionLogInfo logInfo
    ) throws BOSException {
        try {
            String url = propt.getProperty("syncAttendanceDataUrl");
            if (url == null || url.isEmpty()) {
                logger.error("pushAttendanceExceptionData url is null");
                throw new BOSException("pushAttendanceExceptionData url is null");
            }
            logger.error("pushAttendanceExceptionData url: " + url);
            if (list == null || list.size() <= 0) {
                logger.error("pushAttendanceExceptionData list is null");
                throw new BOSException("pushAttendanceExceptionData list is null");
            }
            String params = JSON.toJSONString(list);
            logInfo.setDataPushRequest(params);
            OkHttpClient client = new OkHttpClient.Builder()
                    .connectTimeout(120, TimeUnit.SECONDS)
                    .writeTimeout(120, TimeUnit.SECONDS)
                    .readTimeout(120, TimeUnit.SECONDS)
                    .build();
            MediaType mediaType = MediaType.parse("application/json");
            RequestBody body = RequestBody.create(mediaType, params);
            Request request = new Request.Builder()
                    .url(url)
                    .post(body)
                    .addHeader("Accept", "*/*")
                    .addHeader("Accept-Encoding", "gzip, deflate, br")
                    .addHeader("User-Agent", "PostmanRuntime-ApipostRuntime/1.1.0")
                    .addHeader("Connection", "keep-alive")
                    .addHeader("Content-Type", "application/json")
                    .build();
            Response response = client.newCall(request).execute();
            logger.error("pushAttendanceExceptionData response----" + response.isSuccessful());
            if (response.isSuccessful()) {
                String resultBody = response.body().string();
                logInfo.setDataPushResponse(resultBody);
                logger.error("resultBody----" + resultBody);
                JSONObject result = JSONObject.parseObject(resultBody);
                if (result.getBoolean("success")) {
                    logInfo.setPushStatus(CallStatusEnum.success);
                } else {
                    //推送失败
                    throw new BOSException(result.getString("msg"));
                }
            } else {
                throw new BOSException("接口请求超时");
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new BOSException("推送考勤数据报错: " + e.getMessage());
        }
    }

    /**
     * set转字符串
     *
     * @param set
     * @return
     */
    public String convertSetToString(Set set) {
        if (set != null && set.size() > 0) {
            Iterator iter = set.iterator();
            StringBuffer sql = new StringBuffer();
            while (iter.hasNext()) {
                sql.append(iter.next()).append(",");
            }
            sql.deleteCharAt(sql.length() - 1);
            return sql.toString();
        } else {
            return "";
        }
    }

    /**
     * 获取组织考勤总人数(包含下级)
     *
     * @param ctx
     * @return
     */
    public int getAttendanceCount(Context ctx, String orgLongNumber) {
        try {
            IAttendanceFile iAttendanceFile = AttendanceFileFactory.getLocalInstance(ctx);
            FilterInfo filterInfo = new FilterInfo();
            FilterItemCollection filterItems = filterInfo.getFilterItems();
            filterItems.add(new FilterItemInfo("attendFileState", "1"));
            //打卡考勤
            filterItems.add(new FilterItemInfo("isAttendance", "1"));
            filterItems.add(new FilterItemInfo("adminOrgUnit.longNumber", orgLongNumber + "%", CompareType.LIKE));
            EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, null, null);
            AttendanceFileCollection attendanceFileCol = iAttendanceFile.getAttendanceFileCollection(viewInfo);
            return attendanceFileCol.size();
        } catch (BOSException e) {
            logger.error("获取" + orgLongNumber + "考勤总人数报错: " + e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }


    /**
     * 根据长编码获取组织
     *
     * @param ctx
     * @return
     */
    public AdminOrgUnitInfo getOrgInfo(Context ctx, String orgLongNumber) throws BOSException {
        AdminOrgUnitCollection adminOrgUnitCollection = null;
        try {
            IAdminOrgUnit iAdminOrgUnit = AdminOrgUnitFactory.getLocalInstance(ctx);
            FilterInfo filterInfo = new FilterInfo();
            FilterItemCollection filterItems = filterInfo.getFilterItems();
            //组织层级为一级组织
            filterItems.add(new FilterItemInfo("unitLayerType", "00000000-0000-0000-0000-00000000000362824988"));
            filterItems.add(new FilterItemInfo("longNumber", "0"));
            SelectorItemCollection sic = new SelectorItemCollection();
            sic.add("number");
            sic.add("name");
            adminOrgUnitCollection = iAdminOrgUnit.getAdminOrgUnitCollection("where longNumber = '" + orgLongNumber + "'");
        } catch (Exception e) {
            logger.error("获取组织报错: " + e.getMessage(), e);
            throw new BOSException(e);
        }
        if (adminOrgUnitCollection == null || adminOrgUnitCollection.size() == 0) {
            throw new BOSException("未找到长编码为[" + orgLongNumber + "]的组织");
        }
        return adminOrgUnitCollection.get(0);
    }

    /**
     * 获取提醒记录
     *
     * @param ctx
     * @param yearMonth
     * @return
     */
    private Set<String> getRemindRecord(Context ctx, String yearMonth) {
        Set<String> remindRecordSet = new HashSet<>();
        try {
            String querySql = "select personNumber from T_Remind_Record where yearMonth=?";
            IRowSet iRowSet = DBUtil.executeQuery(ctx, querySql, new Object[]{yearMonth});
            while (iRowSet.next()) {
                remindRecordSet.add(iRowSet.getString("personNumber"));
            }
        } catch (Exception e) {
            logger.error("获取提醒记录报错: " + e.getMessage(), e);
            throw new RuntimeException(e);
        }
        return remindRecordSet;
    }

    /**
     * 新增提醒记录
     *
     * @param ctx
     * @param yearMonth
     */
    private void addRemindRecord(Context ctx, String yearMonth, String personNumber) {
        try {
            String querySql = "insert into T_Remind_Record(yearMonth,personNumber) values (?,?)";
            DBUtil.execute(ctx, querySql, new Object[]{yearMonth, personNumber});
        } catch (Exception e) {
            logger.error("新增提醒记录报错: " + e.getMessage(), e);
            throw new RuntimeException("新增提醒记录报错: " + e.getMessage());
        }
    }
}