package com.jpsoft.shinestar.modules.business.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.jpsoft.shinestar.config.WxConfig;
import com.jpsoft.shinestar.modules.base.constant.AttendanceTypes;
import com.jpsoft.shinestar.modules.base.dao.AlarmConfigDAO;
import com.jpsoft.shinestar.modules.base.dao.CompanyInfoDAO;
import com.jpsoft.shinestar.modules.base.dao.DeviceInfoDAO;
import com.jpsoft.shinestar.modules.base.dao.PersonInfoDAO;
import com.jpsoft.shinestar.modules.base.entity.*;
import com.jpsoft.shinestar.modules.base.service.*;
import com.jpsoft.shinestar.modules.business.dao.WorkAttendanceDAO;
import com.jpsoft.shinestar.modules.business.entity.WorkAttendance;
import com.jpsoft.shinestar.modules.business.service.RequestForLeaveInfoService;
import com.jpsoft.shinestar.modules.business.service.WorkAttendanceService;
import com.jpsoft.shinestar.modules.common.dto.Sort;
import com.jpsoft.shinestar.modules.common.utils.JwtUtil2;
import com.jpsoft.shinestar.modules.common.utils.StringUtils;
import com.jpsoft.shinestar.modules.common.utils.WechatMessageUtil;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Transactional
@Component(value="workAttendanceService")
public class WorkAttendanceServiceImpl implements WorkAttendanceService {
	@Resource(name="workAttendanceDAO")
	private WorkAttendanceDAO workAttendanceDAO;

	@Autowired
	private PersonInfoDAO personInfoDAO;

	@Autowired
	private CompanyInfoDAO companyInfoDAO;

	@Autowired
	private AlarmConfigDAO alarmConfigDAO;

	@Autowired
	private DeviceInfoDAO deviceInfoDAO;

	@Autowired
	private HolidayInfoService holidayInfoService;

	@Autowired
	private PersonDeviceLogService personDeviceLogService;

	@Autowired
	private AlarmConfigService alarmConfigService;

	@Autowired
	private CompanyInfoService companyInfoService;

	@Autowired
	private PersonPopedomService personPopedomService;

	@Autowired
	private RequestForLeaveInfoService requestForLeaveInfoService;

	@Autowired
	private BusinessOutService businessOutService;

	@Value("${jwt.secret}")
	private String jwtSecret;

	@Autowired
	private WxConfig wxConfig;

	@Autowired
	private ValueOperations<String,Object> valueOperations;

	@Override
	public WorkAttendance get(String id) {
		// TODO Auto-generated method stub
		return workAttendanceDAO.get(id);
	}

	@Override
	public int insert(WorkAttendance model) {
		// TODO Auto-generated method stub
		//model.setId(UUID.randomUUID().toString());
		
		return workAttendanceDAO.insert(model);
	}

	@Override
	public int update(WorkAttendance model) {
		// TODO Auto-generated method stub
		return workAttendanceDAO.update(model);		
	}

	@Override
	public int delete(String id) {
		// TODO Auto-generated method stub
		return workAttendanceDAO.delete(id);
	}

	@Override
	public boolean exist(String id) {
		// TODO Auto-generated method stub
		int count = workAttendanceDAO.exist(id);
		
		return count > 0 ? true : false;
	}
	
	@Override
	public List<WorkAttendance> list() {
		// TODO Auto-generated method stub
		return workAttendanceDAO.list();
	}
		
	@Override
	public Page<WorkAttendance> pageSearch(Map<String, Object> searchParams, int pageNumber, int pageSize,boolean count,List<Sort> sortList) {
        Page<WorkAttendance> page = PageHelper.startPage(pageNumber,pageSize,count).doSelectPage(()->{
            workAttendanceDAO.search(searchParams,sortList);
        });
        
        return page;
	}

	@Override
	public List<WorkAttendance> findByPersonIdAndDate(Long personId, Date startDate, Date endDate) {
		return workAttendanceDAO.findByPersonIdAndDate(personId,startDate,endDate);
	}

	@Override
	public int deleteByCompanyCodeAndDate(String companyCode,String alarmConfigId, Date startDate, Date endDate,String sources,List<String> excludeCompanyList) {
		return workAttendanceDAO.deleteByCompanyCodeAndDate(companyCode,alarmConfigId,startDate,endDate,sources, excludeCompanyList);
	}

	@Override
	public boolean punchIn(String deviceNo,Long personId, BigDecimal temperature, Date recordDate) {
		boolean result = false;

		try {
			DateTime recordTime = new DateTime(recordDate);
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
			String date = recordTime.toString("yyyy-MM-dd");

			Date startDate = recordTime.minusDays(7).toDate();
			Date endDate = recordTime.plusDays(1).toDate();

			PersonInfo personInfo = personInfoDAO.get(personId);

			if (personInfo==null){
				log.error("设备上保存的人员编号与服务器不一致，personId=" + personId);
				return false;
			}

//			DeviceInfo deviceInfo = deviceInfoDAO.findByDeviceNo(deviceNo);

			List<PersonPopedom> popedomList = personPopedomService.findByPersonId(personId);

			for (PersonPopedom personPopedom : popedomList) {
			    if (StringUtils.isEmpty(personPopedom.getCompanyId())){
			        continue;
                }

				CompanyInfo companyInfo = companyInfoDAO.get(personPopedom.getCompanyId());

			    if(companyInfo==null){
					continue;
                }

			    //当前身份不需要考勤
				if (!personPopedom.getEnableAttendance()){
					continue;
				}

				//是否节假日(上级设置节假日、则下级查询时也要带出来)
				Set<String> holidaySet = holidayInfoService.getHolidaySetByDate(companyInfo.getCode(), startDate,endDate,false);

				//虽然放假但正常上班(上级设置节假日、则下级查询时也要带出来)
				Map<String, HolidayInfo> fakeHolidayMap = holidayInfoService.getHolidayMapByDate(companyInfo.getCode(), startDate, endDate,true);

				//是节假日，并且所在部门不值班
//				if (holidaySet.contains(date) && !fakeHolidayMap.containsKey(date)){
//					return false;
//				}

                //todo 如果是上班考勤说明该人员回公司正常上班
                if ("2".equals(personInfo.getWorkStatus())
				||  "3".equals(personInfo.getWorkStatus())) {
                    //1分钟之内只通知一次
                    boolean absent = valueOperations.setIfAbsent("out_" + personInfo.getId(),true,1, TimeUnit.MINUTES);

                    if (absent){
                        //查询最近外出、出差没有结束时间的记录
                        BusinessOut businessOut = businessOutService.findLastActiveByPersonId(personInfo.getId());

                        //微信通知人员确认是否回单位
                        if (businessOut != null) {
                            String outUrl = "";
                            String type = "";

                            if ("1".equals(businessOut.getType())) {
                                type = "外出";
                                outUrl = wxConfig.getPortalUrl() + "master/egress/info";
                            } else if ("3".equals(businessOut.getType())) {
                                type = "出差";
                                outUrl = wxConfig.getPortalUrl() + "master/businessTravel/info";
                            }

                            if (StringUtils.isNotEmpty(outUrl)) {
                                String token = JwtUtil2.createToken(jwtSecret, String.valueOf(personInfo.getId()), DateTime.now().plusMonths(1).toDate());

                                WechatMessageUtil.sendEvenMessage(personInfo.getOpenId(),  type + "归来通知",
                                        personInfo.getName(),
                                        businessOut.getId().substring(0, 5),
                                        "前往处理",
                                        MessageFormat.format(outUrl + "?id={0}&wm=1&exchange=1&role_id={1}&token={2}&time={3}",
										businessOut.getId(), personPopedom.getId(), token, URLEncoder.encode(recordTime.toString("yyyy-MM-dd HH:mm:ss"),"UTF-8")),
                                        wxConfig.getAppId(), wxConfig.getAppSecret());
                            }
                        }
                    }
                }

				String[] arr = companyInfo.getCode().split(",");

				List<AlarmConfig> configList = null;

				//从当前单位开始向上级单位查询
				for (int i = arr.length - 1; i >= 0; i--) {
					//设备打卡只可能是内勤打卡(需要实时统计考勤)
					configList = alarmConfigDAO.findByCompanyIdAndType(arr[i], AttendanceTypes.IN);

					if (configList != null && configList.size() > 0) {
						break;
					}
				}

				if (configList != null && configList.size()>0) {
					int weekday = recordTime.getDayOfWeek();

					if(fakeHolidayMap.containsKey(date)){
						//虽然放假但需要工作
						HolidayInfo holidayInfo = fakeHolidayMap.get(date);

						//参考工作日
						weekday = holidayInfo.getRefWeekday();
					}

					for (AlarmConfig alarmConfig : configList) {
						//是否工作日
						if (alarmConfig.getWeekdays().indexOf(String.valueOf(weekday)) == -1) {
							continue;
						}

						DateTime startTime = new DateTime(sdf.parse(date + " " + alarmConfig.getStartTime()));
						DateTime attendanceTime = new DateTime(sdf.parse(date + " " + alarmConfig.getAttendanceTime()));
						DateTime endTime = new DateTime(sdf.parse(date + " " + alarmConfig.getEndTime()));

						String attendanceResult = "";

						if (alarmConfig.getClassifier().equals(1)) {
							//todo 上班考勤

							//上班加1分钟
							if (recordTime.compareTo(startTime)>=0 && recordTime.compareTo(attendanceTime.plusMinutes(1))<0){
								attendanceResult = WorkAttendance.SUCCESS;
							}
							else if(recordTime.compareTo(attendanceTime.plusMinutes(1))>=0 && recordTime.compareTo(endTime)<=0){
								attendanceResult = WorkAttendance.LATE;

								if ("2".equals(personInfo.getWorkStatus()) ||"3".equals(personInfo.getWorkStatus())) {
									//如果当前状态是外出、出差则不算迟到
									attendanceResult = "";
								}

								if(holidaySet.contains(date) && !fakeHolidayMap.containsKey(date)){
									//节假日不算迟到
									attendanceResult = "";
								}
							}

							if(StringUtils.isNotEmpty(attendanceResult)){
								//当天是否已经有该时段上班打卡记录，如果有则不记录
								List<WorkAttendance> workAttendances = workAttendanceDAO.findByPeriod(personId,alarmConfig.getId(),recordTime.toDate());

								if (workAttendances.size()>0){
									//可能存在考勤机离线后没有实时传输回打卡记录,这时需要判断数据库中已有该时间段打卡时间<当前打卡时间的数量
									long count = workAttendances.stream().filter(item->item.getRecordTime().compareTo(recordDate)<0).count();

									if (count==0){
										//说明当前打卡时间更早，故删除现有该时间段打卡记录
										for (WorkAttendance workAttendance : workAttendances) {
											workAttendance.setDelFlag(true);
											workAttendance.setUpdateTime(new Date());

											workAttendanceDAO.update(workAttendance);
										}
									}
									else{
										//数据库中已有该时间段打卡时间<当前打卡时间，则忽略当前考勤记录
										continue;
									}
								}
							}
						} else {
							//todo 下班考勤

							//早退
							if (recordTime.compareTo(startTime)>=0 && recordTime.compareTo(attendanceTime)<0){
								attendanceResult = WorkAttendance.LEAVE_EARLY;

								if ("2".equals(personInfo.getWorkStatus()) ||"3".equals(personInfo.getWorkStatus())) {
									//如果当前状态是外出、出差则不算早退
									attendanceResult = "";
								}

								if(holidaySet.contains(date) && !fakeHolidayMap.containsKey(date)){
									//节假日不算早退
									attendanceResult = "";
								}
							}
							else if(recordTime.compareTo(attendanceTime)>=0 && recordTime.compareTo(endTime)<=0){
								attendanceResult = WorkAttendance.SUCCESS;
							}

							if(StringUtils.isNotEmpty(attendanceResult)) {
								//查询当天该下班时段考勤记录
								List<WorkAttendance> workAttendances = workAttendanceDAO.findByPeriod(personId, alarmConfig.getId(), recordTime.toDate());

								boolean latest = true;

								for (WorkAttendance workAttendance : workAttendances) {
									//下班只保存最后一次记录
									if(workAttendance.getRecordTime().compareTo(recordTime.toDate())<0) {
										workAttendance.setDelFlag(true);
										workAttendance.setUpdateTime(new Date());

										workAttendanceDAO.update(workAttendance);
									}
									else{
										latest = false;
									}
								}

								if (!latest){
									//数据库中有更迟的下班考勤记录（针对数据补发有这种可能）
									continue;
								}
							}
						}

						if (StringUtils.isNotEmpty(attendanceResult)) {
							WorkAttendance workAttendance = new WorkAttendance();
							workAttendance.setId(UUID.randomUUID().toString());
							workAttendance.setPersonId(personInfo.getId());
							workAttendance.setAlarmConfigId(alarmConfig.getId());
							workAttendance.setCreateTime(new Date());
							workAttendance.setDelFlag(false);
							workAttendance.setSources("1"); //设备打卡

							workAttendance.setWorkStatus(personInfo.getWorkStatus());
							workAttendance.setTemperature(temperature);
							workAttendance.setResult(attendanceResult);
							workAttendance.setRecordTime(recordDate);

							int affectCount = workAttendanceDAO.insert(workAttendance);

							result = affectCount > 0;

							break;
						}
					}

					if(result){
						//考勤只记录一次即可
						break;
					}
				}
			}
		}
		catch (Exception ex){
			result = false;
			log.error(ex.getMessage(),ex);
		}

		return result;
	}

	@Override
	public List<PersonInfo> queryUnAttendanceList(String companyCode, Date startDate, Date endDate) {
		return workAttendanceDAO.queryUnAttendanceList(companyCode,startDate,endDate);
	}

	@Override
	public WorkAttendance findByPersonIdAndPeriod(Long personId, Date queryDate, String alarmConfigId) {
		return workAttendanceDAO.findByPersonIdAndPeriod(personId,queryDate,alarmConfigId);
	}

	@Override
	public int batchUpdate(String companyId,String alarmConfigId,Date startDate,Date endDate) {
		DateTime dt1 = new DateTime(startDate);
		DateTime dt2 = new DateTime(endDate);

		int days = Days.daysBetween(dt1,dt2).getDays();

		//只更新内勤打卡记录
		List<AlarmConfig> configList = alarmConfigService.findByCompanyIdAndType(companyId,AttendanceTypes.IN);

		CompanyInfo companyInfo = companyInfoService.get(companyId);

		//查询子单位是否有考勤设置，如果有要排除子单位
		List<String> excludeCompanyList = alarmConfigService.findSubCompanyList(companyInfo.getCode() + "%" , companyInfo.getId());

		//只删除设备测温打卡记录
		//deleteByCompanyCodeAndDate(companyInfo.getCode() + "%",alarmConfigId,startDate,endDate, "1", excludeCompanyList);

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");

		int affectCount = 0;

		for (AlarmConfig alarmConfig : configList) {
			//如果指定了考勤时段则只更新该考勤时段数据
			if(StringUtils.isNotEmpty(alarmConfigId) && !alarmConfigId.equals(alarmConfig.getId())){
				continue;
			}

			//查询当前考勤关联单位
			List<CompanyInfo> relatedCompanyList = new ArrayList<>();

			if (alarmConfig.getSubordinate()!=null && alarmConfig.getSubordinate()){
				relatedCompanyList = companyInfoService.findAllCompanyByCode(companyInfo.getCode() + "%");
			}
			else{
				relatedCompanyList.add(companyInfo);
			}

			//针对每个单位、部门进行统计
			for (CompanyInfo relatedCompany : relatedCompanyList) {
				//下级单位单独设置了考勤
				if(excludeCompanyList.contains(relatedCompany.getId())){
					continue;
				}

				//放假日期
				Set<String> realHolidaySet = holidayInfoService.getHolidaySetByDate(relatedCompany.getCode(),startDate,endDate,false);

				//虽然放假但正常上班
				Map<String,HolidayInfo> fakeHolidayMap = holidayInfoService.getHolidayMapByDate(relatedCompany.getCode(),startDate,endDate,true);

				for (int i=0;i<days;i++) {
					DateTime current = dt1.plusDays(i);

					//不能生成超过当前时间的考勤记录
					if (current.compareTo(DateTime.now()) > 0) {
						break;
					}

					String date = current.toString("yyyy-MM-dd");
					int weekday = current.getDayOfWeek();

					if (realHolidaySet.contains(date) && !fakeHolidayMap.containsKey(date)){
						//当天为节假日，当前部门不值班
						continue;
					}

					if (fakeHolidayMap.containsKey(date)) {
						//虽然放假但需要工作
						HolidayInfo holidayInfo = fakeHolidayMap.get(date);

						//当前参考工作日
						weekday = holidayInfo.getRefWeekday();
					}

					if (alarmConfig.getWeekdays().indexOf(String.valueOf(weekday)) == -1) {
						//当前日期不属于本轮考勤设置的工作日
						continue;
					}

					try {
						DateTime startTime = new DateTime(sdf.parse(date + " " + alarmConfig.getStartTime()));
						DateTime attendanceTime = new DateTime(sdf.parse(date + " " + alarmConfig.getAttendanceTime()));
						DateTime endTime = new DateTime(sdf.parse(date + " " + alarmConfig.getEndTime()));

						if(DateTime.now().compareTo(endTime)<0){
							//当前考勤时段还未结束，不需要更新考勤记录
							continue;
						}

						//todo 查询当前时间段打卡情况
						List<Long> attendanceList = personDeviceLogService.queryAttendanceListByCompanyId(relatedCompany.getId(), startTime.toDate(), endTime.toDate());

						//这里只读取该部门需要考勤的人员的考勤记录
						for (Long personId : attendanceList) {
//							PersonPopedom personPopedom = personPopedomService.hasEnableAttendanceByCompanyId(personId,relatedCompany.getId());

							//当前用户没有在该单位中要求考勤
//							if (personPopedom==null){
								//删除考勤记录,如果一个人关联考勤单位的两个部门，一个要求考勤，一个不要求；这里删除可以会把要考勤部门的记录删除
								//workAttendanceDAO.deleteByPersonIdAndDate(personId,alarmConfig.getId(),startTime.toDate(),endTime.toDate(),"1");
//								continue;
//							}

							WorkAttendance workAttendance = new WorkAttendance();
							workAttendance.setId(UUID.randomUUID().toString());
							workAttendance.setPersonId(personId);
							workAttendance.setAlarmConfigId(alarmConfig.getId());
							workAttendance.setCreateTime(new Date());
							workAttendance.setDelFlag(false);
							workAttendance.setSources("1");

							List<PersonDeviceLog> logList = personDeviceLogService.findByPersonAndDate(personId, startTime.toDate(), endTime.toDate());

							if (logList.size() > 0) {
								PersonDeviceLog personDeviceLog = null;

								if (alarmConfig.getClassifier().equals(1)) {
									//上班算最早一次考勤
									personDeviceLog = logList.get(0);

									//上班加1分钟
									if (personDeviceLog.getRecordTime().compareTo(startTime.toDate()) >= 0 && personDeviceLog.getRecordTime().compareTo(attendanceTime.plusMinutes(1).toDate()) < 0) {
										workAttendance.setResult(WorkAttendance.SUCCESS);
									} else if (personDeviceLog.getRecordTime().compareTo(attendanceTime.plusMinutes(1).toDate()) >= 0 && personDeviceLog.getRecordTime().compareTo(endTime.toDate()) <= 0) {
										workAttendance.setResult(WorkAttendance.LATE);

										//查询该时段用户是否请假或外出
										List<BusinessOut> businessOutList = businessOutService.findByPersonIdAndDate(personId,personDeviceLog.getRecordTime());

										if (businessOutList.size()>0){
											//本次考勤时段该用户不记录迟到
											continue;
										}
									}
								} else {
									//下班算最迟一次考勤
									personDeviceLog = logList.get(logList.size() - 1);

									if (personDeviceLog.getRecordTime().compareTo(startTime.toDate()) >= 0 && personDeviceLog.getRecordTime().compareTo(attendanceTime.toDate()) < 0) {
										workAttendance.setResult(WorkAttendance.LEAVE_EARLY);

										//查询该时段用户是否请假或外出
										List<BusinessOut> businessOutList = businessOutService.findByPersonIdAndDate(personId,personDeviceLog.getRecordTime());

										if (businessOutList.size()>0){
											//本次考勤时段该用户不记录早退
											continue;
										}
									} else if (personDeviceLog.getRecordTime().compareTo(attendanceTime.toDate()) >= 0 && personDeviceLog.getRecordTime().compareTo(endTime.toDate()) <= 0) {
										workAttendance.setResult(WorkAttendance.SUCCESS);
									}
								}

								workAttendance.setRecordTime(personDeviceLog.getRecordTime());

								workAttendance.setTemperature(personDeviceLog.getTemperature());
							}

							//查询该时段人员打卡记录
							List<WorkAttendance> workAttendances = workAttendanceDAO.findByPersonIdAndDate(personId,startTime.toDate(), endTime.toDate());

							//查询该时段是否有补卡记录
							boolean hasPatch = false;

							for (WorkAttendance attendance : workAttendances) {
								if(alarmConfig.getId().equals(attendance.getAlarmConfigId())
										&& "2".equals(attendance.getSources())
										&& "2".equals(attendance.getType())){
									hasPatch = true;
									break;
								}
							}

							String workStatus = "";

							if (workAttendances.size()>0){
								workStatus = workAttendances.get(0).getWorkStatus();
							}

							workAttendance.setWorkStatus(workStatus);

							//删除之前该考勤时段设备打卡生成的考勤记录
							workAttendanceDAO.deleteByPersonIdAndDate(personId,alarmConfig.getId(),startTime.toDate(),endTime.toDate(),"1");

							//如果有补卡则以补卡记录为准
							if(!hasPatch) {
								affectCount += insert(workAttendance);
							}
						}

						//统计缺卡
						affectCount += recordUnAttendance(relatedCompany.getId(),alarmConfig, startTime.toDate(), attendanceTime.toDate(), endTime.toDate(), WorkAttendance.MISSING);
					}
					catch (Exception ex){
						log.error(ex.getMessage(),ex);
					}
				}
			}
		}

		return affectCount;
	}



	/**
	 * 记录未考勤人员
	 * @param  companyId 当前考勤单位/部门
	 * @param alarmConfig
	 * @param startDate
	 * @param endDate
	 * @param result
	 */
	@Override
	public int recordUnAttendance(String companyId,AlarmConfig alarmConfig, Date startDate,Date attendanceDate, Date endDate, String result) {
		int affectCount = 0;

		//todo 查询该单位当前时间段未设备打卡人员列表
		List<Long> attendanceList = personDeviceLogService.queryUnAttendanceListByCompanyId(companyId, startDate, endDate);

		//统计需要考勤但未打卡的人
		for (Long personId : attendanceList) {
			//todo 当前用户在当前单位是否需要考勤

			//当天时段
			DateTime startTimeOfDay = new DateTime(startDate).withTimeAtStartOfDay();
			DateTime endTimeOfDay = startTimeOfDay.plusDays(1);

			String sources = String.valueOf(alarmConfig.getAttendanceType());

			//todo 查询当前考勤记录中的工作状态
			List<WorkAttendance> workAttendances = workAttendanceDAO.findByPeriod(personId,alarmConfig.getId(),attendanceDate);

			boolean hasManualFill = false;

			for (WorkAttendance workAttendance : workAttendances) {
				//外勤打卡、补卡
				if (StringUtils.isNotEmpty(workAttendance.getType())){
					hasManualFill = true;
					break;
				}
			}

			//todo 删除当天设备打卡记录（人工填报记录不删除，考勤时段修改后，以最新时段为标准）
			workAttendanceDAO.deleteByPersonIdAndDate(personId , alarmConfig.getId(), startTimeOfDay.toDate(),endTimeOfDay.toDate(), "1");

			//todo 没有人工填报记录才添加新记录
			if(!hasManualFill) {
				//todo 查询用户本月请假日期
				Set<String> leaveHalfDays = requestForLeaveInfoService.findHalfDaysByPersonIdAndDate(personId, startTimeOfDay.toDate(),endTimeOfDay.toDate());
				Date outDate = attendanceDate;

				//todo 查询当前考勤是否申请外出或出差
				if (alarmConfig.getClassifier()!=null && alarmConfig.getClassifier()==2){
					//下班考勤用结束时间判断
					outDate = endDate;
				}

				List<BusinessOut> businessOutList = businessOutService.findByPersonIdAndDate(personId,outDate);
				String workStatus = "1";

				if(businessOutList.size()>0) {
					//当天出差
					workStatus = businessOutList.get(0).getType().equals("1") ? WorkStatus.OUT : WorkStatus.TRAVEL;
				}

				//todo 重新保存缺卡或休假记录
				WorkAttendance workAttendance = new WorkAttendance();
				workAttendance.setId(UUID.randomUUID().toString());
				workAttendance.setPersonId(personId);
				workAttendance.setAlarmConfigId(alarmConfig.getId());
				workAttendance.setCreateTime(new Date());
				workAttendance.setRecordTime(attendanceDate);
				workAttendance.setDelFlag(false);
				workAttendance.setWorkStatus(workStatus);

				//如果当前用户外出、出差中，则不记录内勤
				if (WorkStatus.TRAVEL.equals(workAttendance.getWorkStatus())
				 || WorkStatus.OUT.equals(workAttendance.getWorkStatus())) {
					if (alarmConfig.getAttendanceType().equals(AttendanceTypes.IN)) {
						continue;
					}
				} else {
					//如果当前用户未出差，则不记录外勤
					if (alarmConfig.getAttendanceType().equals(AttendanceTypes.OUT)) {
						continue;
					}
				}

				//1：设备打卡(内勤)，2：人工填报（外勤）
				workAttendance.setSources(sources);

				DateTime recordTime = new DateTime(attendanceDate);

				if (WorkStatus.OUT.equals(workAttendance.getWorkStatus()))
				{
					//外出未归来时，星期天不算未打卡
					if(recordTime.getDayOfWeek()==7){
						continue;
					}
				}

				String halfDay = null;

				//如果下午上班时，在下午1点前打了卡，就肯定不是缺卡
				if (recordTime.getHourOfDay() < 13) {
					halfDay = recordTime.toString("yyyy-MM-dd") + " 上午";
				} else {
					halfDay = recordTime.toString("yyyy-MM-dd") + " 下午";
				}

				if (!leaveHalfDays.contains(halfDay)) {
					//未休假、同时没有机器打卡和外勤打卡记录，则算缺卡
					workAttendance.setResult(result);
				} else {
					//本次考勤时段有对应请假记录
					workAttendance.setResult(WorkAttendance.REST);
				}

				affectCount += insert(workAttendance);
			}
		}

		return affectCount;
	}

	@Override
	public int deleteByPersonIdAndDate(Long personId, String alarmConfigId,Date startDate, Date endDate,String sources) {
		return workAttendanceDAO.deleteByPersonIdAndDate(personId,alarmConfigId,startDate,endDate,sources);
	}

	public static void main(String[] args) {
		System.out.println(DateTime.now().getDayOfWeek());
	}
}