| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797 |
- package com.punchsettle.server.service.manager.impl;
- import java.math.BigDecimal;
- import java.math.RoundingMode;
- import java.text.SimpleDateFormat;
- import java.time.LocalDate;
- import java.time.LocalTime;
- import java.time.YearMonth;
- import java.time.temporal.ChronoUnit;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Comparator;
- import java.util.List;
- import java.util.Map;
- import java.util.Objects;
- import java.util.Optional;
- import java.util.function.Function;
- import java.util.stream.Collectors;
- import com.punchsettle.server.atomic.entity.PunchInMultiTask;
- import com.punchsettle.server.atomic.entity.PunchInMultiTaskExt;
- import com.punchsettle.server.atomic.entity.PunchInMultiTaskHistory;
- import com.punchsettle.server.atomic.entity.PunchInStatsMonth;
- import com.punchsettle.server.atomic.entity.PunchInStatsWeek;
- import com.punchsettle.server.atomic.entity.PunchInStatus;
- import com.punchsettle.server.atomic.entity.PunchInTaskExt;
- import com.punchsettle.server.constant.ConsecutiveStatusEnum;
- import com.punchsettle.server.constant.FullAttendancePeriodEnum;
- import com.punchsettle.server.constant.PunchInDimensionEnum;
- import com.punchsettle.server.constant.PunchInExtraMethodEnum;
- import com.punchsettle.server.constant.PunchInMethodMultiEnum;
- import com.punchsettle.server.constant.RepeatCategoryEnum;
- import com.punchsettle.server.service.manager.ICalendarManager;
- import org.springframework.beans.BeanUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import org.springframework.util.CollectionUtils;
- import com.punchsettle.server.atomic.entity.PunchIn;
- import com.punchsettle.server.atomic.entity.PunchInRecord;
- import com.punchsettle.server.atomic.entity.PunchInTask;
- import com.punchsettle.server.atomic.entity.PunchInTaskHistory;
- import com.punchsettle.server.atomic.service.IPunchInRecordService;
- import com.punchsettle.server.atomic.service.IPunchInService;
- import com.punchsettle.server.common.exception.BusinessException;
- import com.punchsettle.server.common.utils.Assert;
- import com.punchsettle.server.common.constant.CommonEnableStatusEnum;
- import com.punchsettle.server.constant.CompareRuleEnum;
- import com.punchsettle.server.constant.PunchInCategoryEnum;
- import com.punchsettle.server.constant.PunchInMethodEnum;
- import com.punchsettle.server.constant.PunchInSettleTypeEnum;
- import com.punchsettle.server.constant.PunchInStatusEnum;
- import com.punchsettle.server.constant.PunchInStatusV1Enum;
- import com.punchsettle.server.constant.PunchInStatusViewEnum;
- import com.punchsettle.server.pojo.punchin.PunchInCalendarDataVO;
- import com.punchsettle.server.pojo.punchin.PunchInDataQuery;
- import com.punchsettle.server.pojo.punchin.PunchInDataVO;
- import com.punchsettle.server.pojo.punchin.PunchInQuery;
- import com.punchsettle.server.pojo.punchin.PunchInRecordDataVO;
- import com.punchsettle.server.pojo.punchin.PunchInRecordQuery;
- import com.punchsettle.server.pojo.punchin.PunchInRecordRequest;
- import com.punchsettle.server.pojo.punchin.PunchInRecordVO;
- import com.punchsettle.server.pojo.punchin.PunchInRequest;
- import com.punchsettle.server.pojo.punchin.PunchInVO;
- import com.punchsettle.server.pojo.punchin.PunchInWithRecordVO;
- import com.punchsettle.server.service.manager.IPunchInManager;
- import com.punchsettle.server.service.manager.ISettleManager;
- import com.punchsettle.server.utiis.DateUtils;
- import com.punchsettle.server.utiis.UserUtils;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.util.StringUtils;
- /**
- * @author tyuio
- * @version 1.0.0
- * @description 打卡结算任务 服务类
- * @date 2024/11/25 15:12
- */
- @Slf4j
- @Service
- public class PunchInManagerImpl implements IPunchInManager {
- @Autowired
- private IPunchInService punchInService;
- @Autowired
- private IPunchInRecordService punchInRecordService;
- @Autowired
- private ISettleManager settleManager;
- /**
- * 数值100
- */
- private static final BigDecimal ONE_HUNDRED = new BigDecimal(100);
- @Override
- public List<PunchInWithRecordVO> queryPunchInAndRecord() {
- // 获取当前用户ID
- Long currentUserId = Optional.ofNullable(UserUtils.getCurrentUserId())
- .orElseThrow(() -> BusinessException.fail("无法获取当前用户信息,无法查询打卡任务"));
- // 查询打卡任务
- PunchInQuery punchInQuery = new PunchInQuery();
- punchInQuery.setArchiveFlag(false);
- punchInQuery.setUserIds(Arrays.asList(currentUserId));
- List<PunchIn> punchIns = punchInService.listByCondition(punchInQuery);
- if (CollectionUtils.isEmpty(punchIns)) {
- log.info("用户:{} 没有查询到生效的打卡任务");
- return List.of();
- }
- // 获取一周的起始日期范围
- List<LocalDate> weeklyDateRange = DateUtils.getWeeklyDateRange();
- // 获取打卡任务ID
- List<Long> punchInIds = punchIns.stream().map(PunchIn::getId).collect(Collectors.toList());
- // 找出范围内的打卡记录
- PunchInRecordQuery punchInRecordQuery = new PunchInRecordQuery();
- punchInRecordQuery.setPunchInIds(punchInIds);
- punchInRecordQuery.setStartDate(weeklyDateRange.getFirst().toString());
- punchInRecordQuery.setEndDate(weeklyDateRange.getLast().toString());
- List<PunchInRecord> punchInRecords = punchInRecordService.listByCondition(punchInRecordQuery);
- // 打卡任务-打卡记录 分组
- Map<Long, List<PunchInRecord>> recordMap =
- punchInRecords.stream().collect(Collectors.groupingBy(PunchInRecord::getPunchInId));
- // 日期格式化
- SimpleDateFormat sdf = DateUtils.buildDateFormat();
- // 当前日期
- LocalDate today = LocalDate.now();
- // 构建打卡记录
- List<PunchInWithRecordVO> punchInWithRecordVOS = new ArrayList<>();
- // 初始化的时间记录
- LocalTime initRecordTimeTrack = LocalTime.parse("00:00:00.000");
- for (PunchIn punchIn : punchIns) {
- // 一周的打卡记录容器
- List<PunchInRecordVO> weeklyRecords = new ArrayList<>();
- // 打卡任务信息
- PunchInWithRecordVO punchInWithRecordVO = new PunchInWithRecordVO();
- BeanUtils.copyProperties(punchIn, punchInWithRecordVO);
- punchInWithRecordVO.setPunchInId(punchIn.getId());
- punchInWithRecordVO.setPunchInRecords(weeklyRecords);
- punchInWithRecordVO.setRecordTimeTrack(initRecordTimeTrack);
- punchInWithRecordVO.setRecordCountTrack(0);
- punchInWithRecordVOS.add(punchInWithRecordVO);
- // 打卡任务创建日期
- LocalDate punchInCreationDate = LocalDate.parse(sdf.format(punchIn.getCreationTime()));
- // 获取打卡任务对应的打卡记录,并转为打卡日期-打卡记录map
- List<PunchInRecord> records =
- Optional.ofNullable(recordMap.get(punchInWithRecordVO.getPunchInId())).orElse(List.of());
- Map<String, PunchInRecord> weeklyRecordMap = records.stream()
- .collect(Collectors.toMap(PunchInRecord::getPunchInDate, Function.identity(), (key1, key2) -> key1));
- for (LocalDate weeklyDate : weeklyDateRange) {
- String weeklyDateStr = weeklyDate.toString();
- // 获取打卡记录
- PunchInRecord punchInRecord = weeklyRecordMap.get(weeklyDateStr);
- // 根据过往打卡记录设置打卡状态
- PunchInStatusViewEnum punchInStatus =
- judgePunchInStatus(today, weeklyDate, punchInCreationDate, punchIn, punchInRecord);
- // 设置打卡记录
- PunchInRecordVO punchInRecordVO = new PunchInRecordVO();
- punchInRecordVO.setPunchInDate(weeklyDateStr);
- punchInRecordVO.setPunchInStatus(punchInStatus);
- weeklyRecords.add(punchInRecordVO);
- // 如果是今天的打卡记录,设置计数/计时属性
- if (!Objects.isNull(punchInRecord) && today.isEqual(weeklyDate)) {
- punchInWithRecordVO.setRecordTimeTrack(punchInRecord.getTimeTrack());
- punchInWithRecordVO.setRecordCountTrack(punchInRecord.getCountTrack());
- }
- // 如果是今天设置状态控制页面显示
- if (today.isEqual(weeklyDate)) {
- punchInWithRecordVO.setPunchInStatus(punchInStatus);
- }
- }
- }
- return punchInWithRecordVOS;
- }
- private PunchInStatusViewEnum judgePunchInStatus(LocalDate today, LocalDate weeklyDate,
- LocalDate punchInCreationDate, PunchIn punchIn, PunchInRecord punchInRecord) {
- // 一周某天还没到,无法打卡
- if (weeklyDate.isAfter(today)) {
- return PunchInStatusViewEnum.FUTURE_TIME;
- }
- // 一周某天早于任务创建时间,无法打卡
- if (weeklyDate.isBefore(punchInCreationDate)) {
- return PunchInStatusViewEnum.UNCREATED;
- }
- // 一周某天在今天之前存在打卡记录,则需要判断是否完成打卡
- if (!Objects.isNull(punchInRecord) && weeklyDate.isBefore(today)) {
- if (PunchInStatusV1Enum.FINISH.equals(punchInRecord.getPunchInStatus())
- || PunchInStatusV1Enum.REMAKE_FINISH.equals(punchInRecord.getPunchInStatus())) {
- return PunchInStatusViewEnum.PUNCH_IN;
- }
- }
- // 一周的某天是今天,且存在打卡记录,则判断是否完成打卡
- if (weeklyDate.isEqual(today) && !Objects.isNull(punchInRecord)) {
- PunchInStatusV1Enum punchInStatusV1Enum = settleManager.judgePunchInStatus(punchIn, punchInRecord);
- if (PunchInStatusV1Enum.FINISH.equals(punchInStatusV1Enum)
- || PunchInStatusV1Enum.REMAKE_FINISH.equals(punchInStatusV1Enum)) {
- return PunchInStatusViewEnum.PUNCH_IN;
- }
- // 当天存在打卡记录,但是还没满足打卡条件,则认为打卡状态未知
- return PunchInStatusViewEnum.TODAY_UNKNOWN;
- }
- // 一周的某天是今天,且不存在打卡记录,则还没进行打卡
- if (weeklyDate.isEqual(today) && Objects.isNull(punchInRecord)) {
- return PunchInStatusViewEnum.TODAY_UNKNOWN;
- }
- // 不符合任何情况则是未打卡
- return PunchInStatusViewEnum.UN_PUNCH_IN;
- }
- @Override
- public PunchInVO queryPunchInById(Long punchInId) {
- Assert.isNullInBusiness(punchInId, "请传入待查询的任务ID");
- return Optional.ofNullable(punchInService.getById(punchInId)).map(punchIn -> {
- PunchInVO punchInVO = new PunchInVO();
- BeanUtils.copyProperties(punchIn, punchInVO);
- return punchInVO;
- }).orElseThrow(() -> BusinessException.fail("无法查询到该打卡任务"));
- }
- @Override
- public void saveOrUpdatePunchIn(PunchInRequest request) {
- Assert.isNullInBusiness(request, "请传入任务信息");
- if (PunchInCategoryEnum.COUNT.equals(request.getCategory())
- && (Objects.isNull(request.getRule()) || Objects.isNull(request.getCountTrack()))) {
- throw BusinessException.fail("打卡类型:计数,比较规则和次数不能为空");
- }
- if (PunchInCategoryEnum.TIME.equals(request.getCategory())
- && (Objects.isNull(request.getRule()) || Objects.isNull(request.getTimeTrack()))) {
- throw BusinessException.fail("打卡类型:计时,比较规则和时间不能为空");
- }
- PunchIn punchIn = new PunchIn();
- BeanUtils.copyProperties(request, punchIn);
- punchIn.setArchiveFlag(false);
- if (Objects.isNull(punchIn.getId())) {
- punchInService.insert(punchIn);
- } else {
- punchInService.update(punchIn);
- }
- }
- @Override
- public void deletePunchIn(Long punchInId) {
- Assert.isNullInBusiness(punchInId, "请传入待删除的任务");
- punchInService.delete(punchInId);
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void doPunchIn(PunchInRequest request) {
- if (Objects.isNull(request) || Objects.isNull(request.getId())) {
- BusinessException.throwFail("请传入待打卡的任务");
- }
- PunchIn punchIn = Optional.ofNullable(punchInService.getById(request.getId()))
- .orElseThrow(() -> BusinessException.fail("无法查询到该打卡任务"));
- if (PunchInCategoryEnum.TIME.equals(punchIn.getCategory()) && Objects.isNull(request.getTimeTrack())) {
- BusinessException.throwFail("打卡类型:计时,请传入时间记录");
- }
- // 查询今天的打卡记录
- LocalDate today = LocalDate.now();
- PunchInRecordQuery punchInRecordQuery = new PunchInRecordQuery();
- punchInRecordQuery.setPunchInDate(today.toString());
- punchInRecordQuery.setPunchInId(request.getId());
- PunchInRecord oldPunchInRecord = punchInRecordService.selectOneByCondition(punchInRecordQuery);
- // 打卡类型:单次打卡,需要判断是否重复打卡
- if (PunchInCategoryEnum.SINGLE.equals(punchIn.getCategory()) && !Objects.isNull(oldPunchInRecord)) {
- throw BusinessException.fail("已打卡,无须重复打卡");
- }
- // 获取或创建打卡记录
- PunchInRecord punchInRecord = Optional.ofNullable(oldPunchInRecord).orElseGet(() -> {
- PunchInRecord record = new PunchInRecord();
- record.setPunchInId(request.getId());
- record.setPunchInDate(LocalDate.now().toString());
- return record;
- });
- // 打卡类型:计数,需要累加打卡次数
- if (PunchInCategoryEnum.COUNT.equals(punchIn.getCategory())) {
- punchInRecord.setCountTrack(Optional.ofNullable(punchInRecord.getCountTrack()).orElse(0) + 1);
- }
- // 打卡类型:计时,需要记录最新打卡时长
- if (PunchInCategoryEnum.TIME.equals(punchIn.getCategory())) {
- punchInRecord.setTimeTrack(request.getTimeTrack());
- }
- // 新增或更新
- if (Objects.isNull(punchInRecord.getId())) {
- punchInRecordService.insert(punchInRecord);
- } else {
- punchInRecordService.update(punchInRecord);
- }
- }
- @Override
- public void archivePunchIn(Long punchInId) {
- Assert.isNullInBusiness(punchInId, "请选择待归档的任务");
- PunchIn punchIn = new PunchIn();
- punchIn.setId(punchInId);
- punchIn.setArchiveFlag(true);
- punchInService.update(punchIn);
- }
- @Override
- public void remakePunchIn(PunchInRecordRequest request) {
- // 待补卡的打卡日期
- LocalDate punchInDate = LocalDate.parse(request.getPunchInDate());
- // 如果补打卡日期是今天,则不允许补卡
- if (punchInDate.isEqual(LocalDate.now())) {
- BusinessException.throwFail("补打卡日期不能为今天");
- }
- // 获取打卡任务
- PunchIn punchIn = Optional.ofNullable(punchInService.getById(request.getPunchInId()))
- .orElseThrow(() -> BusinessException.fail("无法查询到该打卡任务"));
- // 补打卡的打卡日期不能早于打卡任务创建日期
- if (punchInDate.isBefore(punchIn.getCreationTime().toLocalDateTime().toLocalDate())) {
- BusinessException.throwFail("补打卡日期不能早于打卡任务创建日期");
- }
- settleManager.settleHandler(PunchInSettleTypeEnum.REMAKE, punchInDate,
- Arrays.asList(UserUtils.getCurrentUserId()), Arrays.asList(request.getPunchInId()));
- }
- @Override
- public void revokePunchIn(PunchInRecordRequest request) {
- // 获取打卡任务
- PunchIn punchIn = Optional.ofNullable(punchInService.getById(request.getPunchInId()))
- .orElseThrow(() -> BusinessException.fail("无法查询到该打卡任务"));
- PunchInRecordQuery punchInRecordQuery = new PunchInRecordQuery();
- punchInRecordQuery.setPunchInId(request.getPunchInId());
- punchInRecordQuery.setPunchInDate(LocalDate.now().toString());
- PunchInRecord punchInRecord = punchInRecordService.selectOneByCondition(punchInRecordQuery);
- if (Objects.isNull(punchInRecord)) {
- log.info("打卡任务:{},打卡日期:{} 没有找到当天打卡记录,进行撤销", punchInRecordQuery.getPunchInId(),
- punchInRecordQuery.getPunchInDate());
- return;
- }
- // 单次打卡/计时打卡 直接删除记录即可
- if (PunchInCategoryEnum.SINGLE.equals(punchIn.getCategory())
- || PunchInCategoryEnum.TIME.equals(punchIn.getCategory())) {
- punchInRecordService.delete(punchInRecord.getId());
- }
- // 计数打卡,需要减去打卡次数
- if (PunchInCategoryEnum.COUNT.equals(punchIn.getCategory())
- && Optional.ofNullable(punchInRecord.getCountTrack()).orElse(0) > 0) {
- PunchInRecord updateRecord = new PunchInRecord();
- updateRecord.setId(punchInRecord.getId());
- updateRecord.setCountTrack(punchInRecord.getCountTrack() - 1);
- punchInRecordService.update(updateRecord);
- if (updateRecord.getCountTrack() == 0) {
- punchInRecordService.delete(punchInRecord.getId());
- }
- }
- }
- @Override
- public PunchInDataVO queryPunchInData(PunchInDataQuery query) {
- PunchIn punchIn = Optional.ofNullable(punchInService.getById(query.getId()))
- .orElseThrow(() -> BusinessException.fail("找到指定的打卡任务"));
- SimpleDateFormat sdf = DateUtils.buildDateFormat();
- YearMonth yearMonth = YearMonth.of(query.getYear(), query.getMonth());
- // 本月第一日
- LocalDate firstOfMonth = yearMonth.atDay(1);
- // 本月最后以日
- LocalDate endOfMonth = yearMonth.atEndOfMonth();
- // 任务创建日期
- LocalDate punchInCreationDate = punchIn.getCreationTime().toLocalDateTime().toLocalDate();
- // 获取打卡记录
- PunchInRecordQuery punchInRecordQuery = new PunchInRecordQuery();
- punchInRecordQuery.setPunchInId(punchIn.getId());
- punchInRecordQuery.setStartDate(String.format("%s 00:00:00.000", firstOfMonth));
- punchInRecordQuery.setEndDate(String.format("%s 23:59:59.999", endOfMonth));
- List<PunchInRecord> punchInRecords = punchInRecordService.listByCondition(punchInRecordQuery);
- // 构造数据,日历部分的数据只需要已打卡的数据
- List<PunchInCalendarDataVO> punchInCalendarDataVOS = new ArrayList<>();
- List<PunchInRecordDataVO> punchInRecordDtoList = new ArrayList<>();
- for (PunchInRecord punchInRecord : punchInRecords) {
- PunchInRecordDataVO punchInRecordDataVO = new PunchInRecordDataVO();
- BeanUtils.copyProperties(punchInRecord, punchInRecordDataVO);
- punchInRecordDtoList.add(punchInRecordDataVO);
- if (PunchInStatusV1Enum.UN_FINISH.equals(punchInRecord.getPunchInStatus())
- || PunchInStatusV1Enum.DOING.equals(punchInRecord.getPunchInStatus())) {
- continue;
- }
- PunchInCalendarDataVO punchInCalendarDataVO = new PunchInCalendarDataVO();
- punchInCalendarDataVO.setPunchInDate(punchInRecord.getPunchInDate());
- punchInCalendarDataVO.setInfo("打卡");
- punchInCalendarDataVO.setDate(punchInRecord.getPunchInDate());
- punchInCalendarDataVOS.add(punchInCalendarDataVO);
- }
- // 计算全勤率
- BigDecimal punchInRate = BigDecimal.ZERO;
- // 要考虑任务刚创建的情况,任务较迟创建的话则使用任务创建时间
- long dayLength = ChronoUnit.DAYS
- .between(firstOfMonth.isBefore(punchInCreationDate) ? punchInCreationDate : firstOfMonth, LocalDate.now());
- if (dayLength != 0) {
- punchInRate = BigDecimal.valueOf(punchInCalendarDataVOS.size())
- .divide(BigDecimal.valueOf(dayLength), 4, RoundingMode.HALF_DOWN).multiply(ONE_HUNDRED);
- }
- // 构造返回结果
- PunchInDataVO punchInDataVO = new PunchInDataVO();
- punchInDataVO.setStartDate(sdf.format(punchIn.getCreationTime()));
- punchInDataVO.setEndDate(LocalDate.now().toString());
- punchInDataVO.setPunchInNum(punchInCalendarDataVOS.size());
- punchInDataVO.setCalendarSelected(punchInCalendarDataVOS);
- punchInDataVO.setPunchInRecords(punchInRecordDtoList);
- punchInDataVO.setPunchInRate(punchInRate);
- return punchInDataVO;
- }
- /**
- * 默认打卡完成率
- */
- private static final BigDecimal DEFAULT_PUNCH_IN_DONE_RATE = new BigDecimal("101.00");
- @Autowired
- private ICalendarManager calendarManager;
- @Override
- public boolean judgeRepeat(PunchInTask punchInTask, String repeatDateStr) {
- // 每天
- if (RepeatCategoryEnum.EVERYDAY.equals(punchInTask.getRepeatCategory())) {
- return true;
- }
- // 法定工作日
- if (RepeatCategoryEnum.WORKDAY.equals(punchInTask.getRepeatCategory())) {
- return !calendarManager.judgeHoliday(repeatDateStr);
- }
- // 法定节假日(含周末)
- if (RepeatCategoryEnum.HOLIDAY.equals(punchInTask.getRepeatCategory())) {
- return !calendarManager.judgeHoliday(repeatDateStr);
- }
- // 自定义
- if (RepeatCategoryEnum.CUSTOM.equals(punchInTask.getRepeatCategory())) {
- if (!StringUtils.hasText(punchInTask.getRepeatCustomDay())) {
- BusinessException.throwFail(String.format("打卡任务ID:%s, 重复周期类型:自定义重复,没有设定自定义重复日期"));
- }
- LocalDate repeatDate = LocalDate.parse(repeatDateStr);
- int dayOfWeekValue = repeatDate.getDayOfWeek().getValue();
- return punchInTask.getRepeatCustomDay().contains(String.valueOf(dayOfWeekValue));
- }
- return false;
- }
- @Override
- public PunchInStatusEnum judgePunchInStatusInTask(PunchInTask punchInTask, PunchInTaskHistory punchInTaskHistory, boolean holidayFlag) {
- Assert.isNullInBusiness(punchInTask, "打卡任务不能为空 ");
- // 没有打卡记录,直接没完成
- if (Objects.isNull(punchInTaskHistory)) {
- return PunchInStatusEnum.UNDONE;
- }
- // 单次打卡,不区分是否节假日
- if (PunchInMethodEnum.SINGLE.equals(punchInTask.getPunchInMethod())) {
- int countTrack = Optional.ofNullable(punchInTask.getCountTrack()).orElse(0);
- return countTrack > 0 ? PunchInStatusEnum.DONE : PunchInStatusEnum.UNDONE;
- }
- // 打卡任务的节假日启用配置
- CommonEnableStatusEnum holidayStatus = Optional.ofNullable(punchInTask.getHolidayStatus()).orElse(CommonEnableStatusEnum.DISABLED);
- boolean enableHolidayFlag = CommonEnableStatusEnum.ENABLED.equals(holidayStatus) && holidayFlag;
- // 计数打卡,要区分是否节假日使用不同的判断标准
- if (PunchInMethodEnum.COUNT.equals(punchInTask.getPunchInMethod())) {
- int countTrack = enableHolidayFlag ? punchInTask.getHolidayCountTrack() : punchInTask.getCountTrack();
- int punchInCountTrack = Optional.ofNullable(punchInTaskHistory.getCountTrack()).orElse(0);
- if (CompareRuleEnum.GTE.equals(punchInTask.getCompareRule()) && punchInCountTrack >= countTrack) {
- return PunchInStatusEnum.DONE;
- }
- if (CompareRuleEnum.LTE.equals(punchInTask.getCompareRule()) && punchInCountTrack <= countTrack) {
- return PunchInStatusEnum.DONE;
- }
- return PunchInStatusEnum.UNDONE;
- }
- // 计时打卡,要区分是否节假日使用不同的判断标准
- if (PunchInCategoryEnum.TIME.equals(punchInTask.getPunchInMethod())) {
- LocalTime timeTrack = enableHolidayFlag ? punchInTask.getHolidayTimeTrack() : punchInTask.getTimeTrack();
- LocalTime punchInTimeTrack = Optional.ofNullable(punchInTaskHistory.getTimeTrack()).orElse(LocalTime.parse("00:00:00.000"));
- if (CompareRuleEnum.GTE.equals(punchInTask.getCompareRule()) && punchInTimeTrack.compareTo(timeTrack) > -1) {
- return PunchInStatusEnum.DONE;
- }
- if (CompareRuleEnum.LTE.equals(punchInTask.getCompareRule()) && punchInTimeTrack.compareTo(timeTrack) < 1) {
- return PunchInStatusEnum.DONE;
- }
- return PunchInStatusEnum.UNDONE;
- }
- return PunchInStatusEnum.UNDONE;
- }
- @Override
- public PunchInStatusEnum judgePunchInStatusInMultiTask(PunchInMultiTask punchInMultiTask, List<PunchInTaskHistory> punchInTaskHistoryList, int multiTaskNum) {
- if (CollectionUtils.isEmpty(punchInTaskHistoryList) || multiTaskNum == 0) {
- return PunchInStatusEnum.UNDONE;
- }
- // 完成的打卡数量
- long punchInDoneCount = punchInTaskHistoryList.stream().filter(v -> PunchInStatusEnum.DONE.equals(v.getPunchInStatus())).count();
- // 次数,当天打卡次数大于等于设置的次数,则完成打卡
- if (PunchInMethodMultiEnum.COUNT.equals(punchInMultiTask.getPunchInMethod())) {
- // 没有设置时默认设置一个较大的数,避免出现打卡次数为0的情况
- Integer doneCount = Optional.ofNullable(punchInMultiTask.getPunchInDoneCount()).orElse(punchInTaskHistoryList.size() + 1);
- return punchInDoneCount >= doneCount ? PunchInStatusEnum.DONE : PunchInStatusEnum.UNDONE;
- }
- // 比率,当天打卡完成比率大于等于设置的比率,则完成打卡
- if (PunchInMethodMultiEnum.RATE.equals(punchInMultiTask.getPunchInMethod())) {
- // 没有设置时默认设置一个较大的数,避免出现打卡完成率为0的情况
- BigDecimal doneRate = Optional.ofNullable(punchInMultiTask.getPunchInDoneRate()).orElse(DEFAULT_PUNCH_IN_DONE_RATE);
- BigDecimal punchInDoneRate = BigDecimal.valueOf(punchInDoneCount).divide(BigDecimal.valueOf(multiTaskNum), 2, RoundingMode.HALF_UP);
- return punchInDoneRate.compareTo(doneRate) > -1 ? PunchInStatusEnum.DONE : PunchInStatusEnum.UNDONE;
- }
- return PunchInStatusEnum.UNDONE;
- }
- @Override
- public int calculatePointsInTask(PunchInTask punchInTask, List<PunchInTaskExt> punchInTaskExts, PunchInTaskHistory punchInTaskHistory, PunchInStatsWeek punchInStatsWeek, PunchInStatsMonth punchInStatsMonth, PunchInStatus punchInStatus) {
- // 未完成打卡,积分为0
- if (PunchInStatusEnum.UNDONE.equals(punchInTaskHistory.getPunchInStatus())) {
- return 0;
- }
- // 单次打卡中使用的拓展信息
- List<PunchInTaskExt> punchInExtList = punchInTaskExts.stream().filter(v -> PunchInDimensionEnum.ONE_DAY.equals(v.getDimension())).collect(Collectors.toList());
- // 打卡任务使用的拓展信息
- List<PunchInTaskExt> punchInTaskExtList = punchInTaskExts.stream().filter(v -> PunchInDimensionEnum.MULTI_DAY.equals(v.getDimension())).collect(Collectors.toList());
- // 单个任务积分=基本积分+(可选)额外积分+(可选)连续完成额外积分+法定节假日(含周末)双倍奖励+全勤双倍奖励
- // 基本积分
- int basicPoints = Optional.ofNullable(punchInTask.getPoints()).orElse(0);
- // 额外积分
- basicPoints += calculateExtraPointsInTask(punchInTask, punchInExtList, punchInTaskHistory, calendarManager.judgeHoliday(punchInTaskHistory.getPunchInDate()));
- // 启用了全勤奖励
- int fullAttendancePoints = 0;
- if (CommonEnableStatusEnum.ENABLED.equals(punchInTask.getFullAttendanceStatus())) {
- LocalDate punchInDate = LocalDate.parse(punchInTaskHistory.getPunchInDate());
- // 结算周期:周,并且结算日是周末,则双倍奖励;
- if (FullAttendancePeriodEnum.WEEK.equals(punchInTask.getFullAttendancePeriod()) && punchInDate.getDayOfWeek().getValue() == 7) {
- int undoneCount = punchInStatsWeek.getPunchInTotalCount() - punchInStatsWeek.getPunchInDoneCount();
- if (undoneCount <= punchInTask.getFullAttendanceFaultToleranceCnt()) {
- fullAttendancePoints = basicPoints;
- }
- }
- // 结算周期:月,结算日是当月最后一天,则双倍奖励;
- if (FullAttendancePeriodEnum.MONTH.equals(punchInTask.getFullAttendancePeriod()) && punchInDate.lengthOfMonth() == punchInDate.getDayOfMonth()) {
- int undoneCount = punchInStatsMonth.getPunchInTotalCount() - punchInStatsMonth.getPunchInDoneCount();
- if (undoneCount <= punchInTask.getFullAttendanceFaultToleranceCnt()) {
- fullAttendancePoints = basicPoints;
- }
- }
- }
- // 启用了法定节假日(含周末)双倍奖励
- int holidayPoints = 0;
- if (CommonEnableStatusEnum.ENABLED.equals(punchInTask.getHolidayStatus()) && calendarManager.judgeHoliday(punchInTaskHistory.getPunchInDate())) {
- holidayPoints = basicPoints;
- }
- // 连续完成额外积分
- int taskPoints = 0;
- if (CommonEnableStatusEnum.ENABLED.equals(punchInTask.getTaskPointsStatus()) && ConsecutiveStatusEnum.CONSECUTIVE.equals(punchInStatus.getConsecutiveStatus())) {
- // punchInTaskExtList 根据InitialValue倒序排列
- punchInTaskExtList.sort(Comparator.comparing(PunchInTaskExt::getInitialValue).reversed());
- // 第二轮标志
- boolean secondRound = false;
- // 上一轮的值
- int prevInitialValue = 0;
- for (PunchInTaskExt punchInTaskExt : punchInTaskExtList) {
- // 比较结果
- int compareValue = punchInStatus.getConsecutiveDay().compareTo(punchInTaskExt.getInitialValue());
- // 如果连续日期小于initialValue,则跳过
- if (compareValue == -1) {
- continue;
- }
- // 额外奖励数
- int extraCount = 0;
- // 如果连续日期大于等于initialValue,则进行第一次计算,并把第二轮标志位设置为true,第二轮/后续轮只需要用上一轮的值进行计算
- if (secondRound) {
- extraCount = prevInitialValue - punchInTaskExt.getInitialValue();
- } else if (compareValue >= 0) {
- extraCount = punchInStatus.getConsecutiveDay() - punchInTaskExt.getInitialValue() + 1;
- secondRound = true;
- }
- taskPoints += punchInTaskExt.getExtraPoints() * extraCount;
- prevInitialValue = punchInTaskExt.getInitialValue();
- }
- }
- return basicPoints + fullAttendancePoints + holidayPoints + taskPoints;
- }
- /**
- * 计算额外积分
- * @param punchInTask
- * @param punchInTaskExtList
- * @return
- */
- private int calculateExtraPointsInTask(PunchInTask punchInTask, List<PunchInTaskExt> punchInTaskExtList, PunchInTaskHistory punchInTaskHistory, boolean holidayFlag) {
- // 单次打卡或者没有启用额外积分计算则跳过
- if (PunchInExtraMethodEnum.NONE.equals(punchInTask.getExtraMethod())
- || PunchInMethodEnum.SINGLE.equals(punchInTask.getPunchInMethod())) {
- return 0;
- }
- // 计算超出部分,
- int extraCountTrack = 0;
- // 计数打卡
- if (PunchInMethodEnum.COUNT.equals(punchInTask.getPunchInMethod())) {
- extraCountTrack = punchInTaskHistory.getCountTrack() - (holidayFlag ? punchInTask.getHolidayCountTrack() : punchInTask.getCountTrack());
- }
- // 计时打卡
- if (PunchInMethodEnum.TIMING.equals(punchInTask.getPunchInMethod())) {
- // 超出的时间按照时间间隔转换成次数
- long timeTrack = punchInTaskHistory.getTimeTrack().until((holidayFlag ? punchInTask.getHolidayTimeTrack() : punchInTask.getTimeTrack()), ChronoUnit.MINUTES);
- extraCountTrack = BigDecimal.valueOf(timeTrack).divide(BigDecimal.valueOf(punchInTask.getExtraTimeStep()), 0, RoundingMode.FLOOR).intValue();
- }
- // 如果等于0则没有超出部分,不用计算
- if (extraCountTrack == 0) {
- return 0;
- }
- // 固定计算
- if (PunchInExtraMethodEnum.FIXED.equals(punchInTask.getExtraMethod())) {
- Integer extraPoints = Optional.ofNullable(punchInTask.getExtraPoints()).orElse(0);
- return extraCountTrack * extraPoints;
- }
- // 区间计算
- if (PunchInExtraMethodEnum.INTERVAL.equals(punchInTask.getExtraMethod()) && !CollectionUtils.isEmpty(punchInTaskExtList)) {
- int basicPoints = 0;
- int prevInitialValue = 0;
- for (PunchInTaskExt punchInTaskExt : punchInTaskExtList) {
- Integer initialValue = Optional.ofNullable(punchInTaskExt.getInitialValue()).orElse(0);
- // 第一轮:initialValue - extraCountTrack的值v1
- // 如果v1≤0则超出initialValue范围,使用initialValue计算;
- // 如果v1>0则在initialValue范围内 使用extraCountTrack
- // 后续轮:本轮initialValue - extraCountTrack的值v1、
- // 如果v1≤0则超出本轮initialValue范围,使用上一轮initialValue-本轮initialValue的值v2计算;
- // 如果v1>0则在本轮initialValue范围内 使用extraCountTrack-上一轮initialValue的值v3计算
- // 下面的代码不适合第一轮的计算
- if (initialValue - extraCountTrack <= 0) {
- basicPoints = punchInTaskExt.getExtraPoints() * Math.abs(prevInitialValue - initialValue);
- } else {
- basicPoints = punchInTaskExt.getExtraPoints() * (extraCountTrack - prevInitialValue);
- }
- prevInitialValue = initialValue;
- }
- return basicPoints;
- }
- return 0;
- }
- @Override
- public int calculatePointsInMultiTask(PunchInMultiTask punchInMultiTask, List<PunchInMultiTaskExt> punchInMultiTaskExts, PunchInMultiTaskHistory punchInMultiTaskHistory, PunchInStatus punchInStatus) {
- // 未完成打卡或没有启用多任务积分计算,积分为0
- if (PunchInStatusEnum.UNDONE.equals(punchInMultiTaskHistory.getPunchInStatus())
- || CommonEnableStatusEnum.ENABLED.equals(punchInMultiTask.getTaskPointsStatus())) {
- return 0;
- }
- // 单次打卡中使用的拓展信息
- List<PunchInMultiTaskExt> punchInExtList = punchInMultiTaskExts.stream().filter(v -> PunchInDimensionEnum.ONE_DAY.equals(v.getDimension())).collect(Collectors.toList());
- // 打卡任务使用的拓展信息
- List<PunchInMultiTaskExt> punchInTaskExtList = punchInMultiTaskExts.stream().filter(v -> PunchInDimensionEnum.MULTI_DAY.equals(v.getDimension())).collect(Collectors.toList());
- // 多个任务积分=多任务基本积分+多任务额外积分+连续完成额外积分
- // 基本积分
- int basicPoints = punchInMultiTask.getPoints();
- // 额外积分
- int extraPoints = 0;
- // 额外次数
- int extractCount = punchInMultiTaskHistory.getPunchInDoneCount() - punchInMultiTask.getPunchInDoneCount();
- // 固定计算
- if (PunchInExtraMethodEnum.FIXED.equals(punchInMultiTask.getExtraMethod())) {
- extraPoints = extractCount * punchInMultiTask.getExtraPoints();
- }
- // 区间计算
- if (PunchInExtraMethodEnum.INTERVAL.equals(punchInMultiTask.getExtraMethod()) && !CollectionUtils.isEmpty(punchInMultiTaskExts)) {
- // punchInTaskExtList 根据InitialValue倒序排列
- punchInExtList.sort(Comparator.comparing(PunchInMultiTaskExt::getInitialValue).reversed());
- // 第二轮标志
- boolean secondRound = false;
- // 上一轮的值
- int prevInitialValue = 0;
- for (PunchInMultiTaskExt punchInTaskExt : punchInTaskExtList) {
- // 比较结果
- int compareValue = Integer.compare(extractCount, punchInTaskExt.getInitialValue());
- // 如果连续日期小于initialValue,则跳过
- if (compareValue == -1) {
- continue;
- }
- // 额外奖励数
- int tempExtraCount = 0;
- // 如果连续日期大于等于initialValue,则进行第一次计算,并把第二轮标志位设置为true,第二轮/后续轮只需要用上一轮的值进行计算
- if (secondRound) {
- tempExtraCount = prevInitialValue - punchInTaskExt.getInitialValue();
- } else if (compareValue >= 0) {
- tempExtraCount = extractCount - punchInTaskExt.getInitialValue() + 1;
- secondRound = true;
- }
- extraPoints += punchInTaskExt.getExtraPoints() * tempExtraCount;
- prevInitialValue = punchInTaskExt.getInitialValue();
- }
- }
- // 连续完成额外积分
- int taskPoints = 0;
- if (CommonEnableStatusEnum.ENABLED.equals(punchInMultiTask.getTaskPointsStatus()) && ConsecutiveStatusEnum.CONSECUTIVE.equals(punchInStatus.getConsecutiveStatus())) {
- // punchInTaskExtList 根据InitialValue倒序排列
- punchInTaskExtList.sort(Comparator.comparing(PunchInMultiTaskExt::getInitialValue).reversed());
- // 第二轮标志
- boolean secondRound = false;
- // 上一轮的值
- int prevInitialValue = 0;
- for (PunchInMultiTaskExt punchInTaskExt : punchInTaskExtList) {
- // 比较结果
- int compareValue = punchInStatus.getConsecutiveDay().compareTo(punchInTaskExt.getInitialValue());
- // 如果连续日期小于initialValue,则跳过
- if (compareValue == -1) {
- continue;
- }
- // 额外奖励数
- int tempExtraCount = 0;
- // 如果连续日期大于等于initialValue,则进行第一次计算,并把第二轮标志位设置为true,第二轮/后续轮只需要用上一轮的值进行计算
- if (secondRound) {
- tempExtraCount = prevInitialValue - punchInTaskExt.getInitialValue();
- } else if (compareValue >= 0) {
- tempExtraCount = punchInStatus.getConsecutiveDay() - punchInTaskExt.getInitialValue() + 1;
- secondRound = true;
- }
- taskPoints += punchInTaskExt.getExtraPoints() * tempExtraCount;
- prevInitialValue = punchInTaskExt.getInitialValue();
- }
- }
- return basicPoints + extraPoints + taskPoints;
- }
- }
|