SettleManagerImpl.java 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. package com.punchsettle.server.service.manager.impl;
  2. import java.time.DayOfWeek;
  3. import java.time.LocalDate;
  4. import java.util.ArrayList;
  5. import java.util.Arrays;
  6. import java.util.HashMap;
  7. import java.util.List;
  8. import java.util.Map;
  9. import java.util.Objects;
  10. import java.util.Optional;
  11. import java.util.Set;
  12. import java.util.function.Function;
  13. import java.util.stream.Collectors;
  14. import org.springframework.beans.BeanUtils;
  15. import org.springframework.beans.factory.annotation.Autowired;
  16. import org.springframework.cache.annotation.Cacheable;
  17. import org.springframework.stereotype.Service;
  18. import org.springframework.transaction.annotation.Transactional;
  19. import org.springframework.util.CollectionUtils;
  20. import com.punchsettle.server.atomic.ContinueTask;
  21. import com.punchsettle.server.atomic.entity.Account;
  22. import com.punchsettle.server.atomic.entity.AccountTransferHistory;
  23. import com.punchsettle.server.atomic.entity.PiStatus;
  24. import com.punchsettle.server.atomic.entity.PiTask;
  25. import com.punchsettle.server.atomic.entity.PiTaskExt;
  26. import com.punchsettle.server.atomic.entity.PiTaskHistory;
  27. import com.punchsettle.server.atomic.entity.SettleTaskRelaHistory;
  28. import com.punchsettle.server.atomic.entity.SettleUserHistory;
  29. import com.punchsettle.server.atomic.entity.User;
  30. import com.punchsettle.server.atomic.service.IAccountService;
  31. import com.punchsettle.server.atomic.service.IAccountTransferHistoryService;
  32. import com.punchsettle.server.atomic.service.IPiStatusService;
  33. import com.punchsettle.server.atomic.service.IPiTaskExtService;
  34. import com.punchsettle.server.atomic.service.IPiTaskHistoryService;
  35. import com.punchsettle.server.atomic.service.IPiTaskService;
  36. import com.punchsettle.server.atomic.service.ISettleTaskRelaHistoryService;
  37. import com.punchsettle.server.atomic.service.ISettleUserHistoryService;
  38. import com.punchsettle.server.atomic.service.IUserService;
  39. import com.punchsettle.server.common.utils.Assert;
  40. import com.punchsettle.server.constant.AccountCategoryEnum;
  41. import com.punchsettle.server.constant.ArchiveStatusEnum;
  42. import com.punchsettle.server.constant.CacheNameConstant;
  43. import com.punchsettle.server.constant.ContinueStageEnum;
  44. import com.punchsettle.server.constant.ContinueStatusEnum;
  45. import com.punchsettle.server.constant.PointsDistributeStatusEnum;
  46. import com.punchsettle.server.constant.PunchInResultEnum;
  47. import com.punchsettle.server.constant.SettleResultEnum;
  48. import com.punchsettle.server.constant.TransferCategoryEnum;
  49. import com.punchsettle.server.constant.VersionStatusEnum;
  50. import com.punchsettle.server.pojo.account.AccountQuery;
  51. import com.punchsettle.server.pojo.punchIn.PiStatusQuery;
  52. import com.punchsettle.server.pojo.punchIn.PiTaskData;
  53. import com.punchsettle.server.pojo.punchIn.PiTaskExtQuery;
  54. import com.punchsettle.server.pojo.punchIn.PiTaskHistoryQuery;
  55. import com.punchsettle.server.pojo.punchIn.PiTaskQuery;
  56. import com.punchsettle.server.pojo.settle.SettleData;
  57. import com.punchsettle.server.pojo.settle.SettleUserHistoryQuery;
  58. import com.punchsettle.server.pojo.settle.SettleUserHistoryVO;
  59. import com.punchsettle.server.service.manager.IAccountManager;
  60. import com.punchsettle.server.service.manager.ICacheManager;
  61. import com.punchsettle.server.service.manager.IPunchInCoreManager;
  62. import com.punchsettle.server.service.manager.ISettleCoreManager;
  63. import com.punchsettle.server.service.manager.ISettleManager;
  64. import com.punchsettle.server.utiis.DateUtils;
  65. import lombok.extern.slf4j.Slf4j;
  66. /**
  67. * @author tyuio
  68. * @version 1.0.0
  69. * @description 结算服务类
  70. * @date 2024/12/12 22:29
  71. */
  72. @Slf4j
  73. @Service
  74. public class SettleManagerImpl implements ISettleManager {
  75. @Autowired
  76. private ISettleUserHistoryService settleUserHistoryService;
  77. @Autowired
  78. private IPiTaskService piTaskService;
  79. @Autowired
  80. private IPiTaskExtService piTaskExtService;
  81. @Autowired
  82. private IPiTaskHistoryService piTaskHistoryService;
  83. @Autowired
  84. private IPiStatusService piStatusService;
  85. @Autowired
  86. private IPunchInCoreManager punchInCoreManager;
  87. @Autowired
  88. private ISettleCoreManager settleCoreManager;
  89. @Autowired
  90. private ISettleTaskRelaHistoryService settleTaskRelaHistoryService;
  91. @Autowired
  92. private IUserService userService;
  93. @Autowired
  94. private IAccountService accountService;
  95. @Autowired
  96. private IAccountTransferHistoryService accountTransferHistoryService;
  97. @Autowired
  98. private ICacheManager cacheManager;
  99. @Autowired
  100. private IAccountManager accountManager;
  101. @Override
  102. @Cacheable(cacheNames = CacheNameConstant.SETTLE_USER_HISTORY, key = "#userId+'_'+#settleMonth", condition = "#userId != null && #settleMonth != null && !#settleMonth.isBlank()")
  103. public List<SettleUserHistoryVO> querySettleUserHistory(Long userId, String settleMonth) {
  104. Assert.isNullInBusiness(settleMonth, "结算月份不能为空");
  105. Assert.isNullInBusiness(userId, "用户ID不能为空");
  106. SettleUserHistoryQuery settleUserHistoryQuery = new SettleUserHistoryQuery();
  107. settleUserHistoryQuery.setUserId(userId);
  108. settleUserHistoryQuery.setSettleDateLike(settleMonth);
  109. List<SettleUserHistory> settleUserHistories = settleUserHistoryService.querySettleUserHistory(settleUserHistoryQuery);
  110. if (CollectionUtils.isEmpty(settleUserHistories)) {
  111. return List.of();
  112. }
  113. return settleUserHistories.stream().map(settleUserHistory -> {
  114. SettleUserHistoryVO settleUserHistoryVO = new SettleUserHistoryVO();
  115. BeanUtils.copyProperties(settleUserHistory, settleUserHistoryVO);
  116. return settleUserHistoryVO;
  117. }).collect(Collectors.toList());
  118. }
  119. @Override
  120. @Transactional(rollbackFor = Exception.class)
  121. public void settle(List<Long> userIds, String punchInDateStr, Long settleTaskHistoryId) {
  122. // 打卡日期
  123. LocalDate punchInDate = LocalDate.parse(punchInDateStr);
  124. // 是否周一
  125. boolean isMonday = DayOfWeek.MONDAY.equals(punchInDate.getDayOfWeek());
  126. // 是否打卡所在月第一天
  127. boolean isFirstDayOfMonth = punchInDate.getDayOfMonth() == 1;
  128. // 周期数
  129. String yearWeek = DateUtils.getYearWeek(punchInDate);
  130. // 月份数
  131. String yearMonth = DateUtils.getYearMonth(punchInDate);
  132. // 打卡状态 更新列表
  133. List<PiStatus> addPiStatusList = new ArrayList<>();
  134. // 新增结算用户记录
  135. List<SettleUserHistory> addSettleUserHistories = new ArrayList<>();
  136. // 用户ID-结算任务关联记录
  137. Map<Long, List<SettleTaskRelaHistory>> settleTaskRelaHistoryMap = new HashMap<>();
  138. // 获取结算数据
  139. List<SettleData> settleDataList = getSettleData(userIds, punchInDate);
  140. for (SettleData settleData : settleDataList) {
  141. // 新增结算用户记录
  142. SettleUserHistory addSettleUserHistory = new SettleUserHistory();
  143. addSettleUserHistory.setUserId(settleData.getUserId());
  144. addSettleUserHistory.setSettleDate(punchInDateStr);
  145. addSettleUserHistory.setSettleTaskHistoryId(settleTaskHistoryId);
  146. addSettleUserHistory.setBeforeSettlePoints(0);
  147. addSettleUserHistory.setAfterSettlePoints(0);
  148. addSettleUserHistory.setSettleResult(SettleResultEnum.SETTLED);
  149. addSettleUserHistory.setDistributeStatus(PointsDistributeStatusEnum.NOT_DISTRIBUTE);
  150. addSettleUserHistories.add(addSettleUserHistory);
  151. // 不存在打卡任务则跳过
  152. if (CollectionUtils.isEmpty(settleData.getPiTaskDataList())) {
  153. addSettleUserHistory.setSettlePoints(0);
  154. continue;
  155. }
  156. // 总结算积分
  157. int totalSettlePoints = 0;
  158. // 新增结算任务关联记录
  159. List<SettleTaskRelaHistory> addSettleTaskRelaHistories = new ArrayList<>();
  160. settleTaskRelaHistoryMap.put(settleData.getUserId(), addSettleTaskRelaHistories);
  161. // 单任务处理
  162. for (PiTaskData piTaskData : settleData.getPiTaskDataList()) {
  163. // 打卡任务
  164. PiTask piTask = piTaskData.getPiTask();
  165. // 结算任务关联记录
  166. SettleTaskRelaHistory addSettleTaskRelaHistory = new SettleTaskRelaHistory();
  167. addSettleTaskRelaHistory.setSettleTaskHistoryId(settleTaskHistoryId);
  168. addSettleTaskRelaHistory.setUserId(settleData.getUserId());
  169. addSettleTaskRelaHistory.setSettleDate(punchInDateStr);
  170. addSettleTaskRelaHistory.setPiTaskId(piTask.getId());
  171. addSettleTaskRelaHistory.setPiTaskUniqueId(piTask.getUniqueId());
  172. // 有打卡任务,但是今天无需结算
  173. boolean repeatResult = punchInCoreManager.judgeRepeat(piTask, punchInDate);
  174. if (!repeatResult) {
  175. addSettleTaskRelaHistory.setSettleResult(SettleResultEnum.NO_SETTLED);
  176. addSettleTaskRelaHistory.setSettlePoints(0);
  177. addSettleTaskRelaHistories.add(addSettleTaskRelaHistory);
  178. continue;
  179. }
  180. // 打卡任务打卡记录
  181. PiTaskHistory piTaskHistory = piTaskData.getPiTaskHistory();
  182. // 打卡任务状态(旧)
  183. PiStatus oldPiStatus = piTaskData.getPiStatus();
  184. // 打卡任务拖扎信息
  185. List<PiTaskExt> piTaskExtList = piTaskData.getPiTaskExtList();
  186. // 复制昨天的打卡记录
  187. PiStatus addPiStatus =new PiStatus();
  188. if (Objects.nonNull(oldPiStatus)) {
  189. BeanUtils.copyProperties(oldPiStatus, addPiStatus);
  190. addPiStatus.setId(null);
  191. } else {
  192. addPiStatus.setUserId(piTask.getCreatedBy());
  193. addPiStatus.setTaskUniqueId(piTask.getId());
  194. addPiStatus.setTaskContinueStatus(ContinueStatusEnum.INTERRUPTED);
  195. addPiStatus.setTaskContinueDay(0);
  196. addPiStatus.setRepeatCategory(piTask.getRepeatCategory());
  197. addPiStatus.setRepeatCustomDay(piTask.getRepeatCustomDay());
  198. }
  199. addPiStatus.setStatusDate(punchInDateStr);
  200. addPiStatusList.add(addPiStatus);
  201. // 更新打卡状态
  202. refreshPiStatus(addPiStatus, piTask, piTaskHistory, punchInDate, isMonday, isFirstDayOfMonth, yearWeek, yearMonth);
  203. // 计算积分,要先刷新打卡状态
  204. int settlePoints = settleCoreManager.calculatePointsInTask(piTask, piTaskExtList, piTaskHistory, addPiStatus);
  205. // 计算总积分
  206. totalSettlePoints += settlePoints;
  207. // 没有打过卡时,没有打卡记录
  208. if (Objects.nonNull(piTaskHistory)) {
  209. addSettleTaskRelaHistory.setPiTaskHistoryId(piTaskHistory.getId());
  210. }
  211. addSettleTaskRelaHistory.setSettleResult(SettleResultEnum.SETTLED);
  212. addSettleTaskRelaHistory.setSettlePoints(settlePoints);
  213. addSettleTaskRelaHistories.add(addSettleTaskRelaHistory);
  214. }
  215. // TODO 未处理多任务结算
  216. // 设置总结算积分
  217. addSettleUserHistory.setSettlePoints(totalSettlePoints);
  218. }
  219. // 数据入库
  220. if (!CollectionUtils.isEmpty(addSettleUserHistories)) {
  221. settleUserHistoryService.insertList(addSettleUserHistories);
  222. // 处理关联数据
  223. List<SettleTaskRelaHistory> addSettleTaskRelaHistories = addSettleUserHistories.stream().map(settleUserHistory -> {
  224. List<SettleTaskRelaHistory> settleTaskRelaHistories = settleTaskRelaHistoryMap.get(settleUserHistory.getUserId());
  225. if (!CollectionUtils.isEmpty(settleTaskRelaHistories)) {
  226. settleTaskRelaHistories.stream().forEach(v -> v.setSettleUserHistoryId(settleUserHistory.getId()));
  227. }
  228. return settleTaskRelaHistories;
  229. }).flatMap(List::stream) // 将每个List中的元素展平
  230. .collect(Collectors.toList());
  231. if (!CollectionUtils.isEmpty(addSettleTaskRelaHistories)) {
  232. settleTaskRelaHistoryService.insertList(addSettleTaskRelaHistories);
  233. }
  234. }
  235. if (!CollectionUtils.isEmpty(addPiStatusList)) {
  236. piStatusService.batchAdd(addPiStatusList);
  237. }
  238. userIds.forEach(userId -> {
  239. cacheManager.batchEvict(Arrays.asList(CacheNameConstant.STAT_TASK_LINE), userId);
  240. cacheManager.batchEvictLike(Arrays.asList(CacheNameConstant.SETTLE_USER_HISTORY), String.valueOf(userId));
  241. });
  242. }
  243. /**
  244. * 获取用户ID-打卡结算数据关联
  245. *
  246. * @param userIds 设计的用户
  247. * @param punchInDate 打卡日期
  248. * @return
  249. */
  250. private List<SettleData> getSettleData(List<Long> userIds, LocalDate punchInDate) {
  251. // 获取多任务信息,用户ID-多任务关联
  252. // PiMultiTaskQuery piMultiTaskQuery = new PiMultiTaskQuery();
  253. // piMultiTaskQuery.setMultiTaskTaskStatus(VersionStatusEnum.ACTIVE);
  254. // piMultiTaskQuery.setUserIds(userIds);
  255. // List<PiMultiTask> piMultiTasks = piMultiTaskService.queryByCondition(piMultiTaskQuery);
  256. // Map<Long, PiMultiTask> piMultiTaskMap = piMultiTasks.stream()
  257. // .collect(Collectors.toMap(PiMultiTask::getUserId, Function.identity(), (key1, key2) -> key1));
  258. // 多任务ID
  259. // Set<Long> multiTaskIds = piMultiTasks.stream().map(PiMultiTask::getId).collect(Collectors.toSet());
  260. // 多任务唯一ID
  261. // Set<Long> multiTaskUniqueIds = piMultiTasks.stream().map(PiMultiTask::getUniqueId).collect(Collectors.toSet());
  262. // 获取多任务拓展信息,多任务ID-多任务拓展关联
  263. // PiMultiTaskExtQuery piMultiTaskExtQuery = new PiMultiTaskExtQuery();
  264. // piMultiTaskExtQuery.setMultiTaskIds(multiTaskIds);
  265. // List<PiMultiTaskExt> piMultiTaskExtList = piMultiTaskExtService.queryByCondition(piMultiTaskExtQuery);
  266. // Map<Long, List<PiMultiTaskExt>> piMultiTaskExtMap =
  267. // piMultiTaskExtList.stream().collect(Collectors.groupingBy(PiMultiTaskExt::getMultiTaskId));
  268. // 获取多任务打卡历史信息,多任务唯一ID-多任务打卡历史关联
  269. // PiMultiTaskHistoryQuery piMultiTaskHistoryQuery = new PiMultiTaskHistoryQuery();
  270. // piMultiTaskHistoryQuery.setPunchInMultiTaskUniqueIds(multiTaskUniqueIds);
  271. // piMultiTaskHistoryQuery.setPunchInDate(punchInDateStr);
  272. // List<PiMultiTaskHistory> piMultiTaskHistories =
  273. // piMultiTaskHistoryService.queryByCondition(piMultiTaskHistoryQuery);
  274. // Map<Long, PiMultiTaskHistory> piMultiTaskHistoryMap = piMultiTaskHistories.stream().collect(
  275. // Collectors.toMap(PiMultiTaskHistory::getMultiTaskUniqueId, Function.identity(), (key1, key2) -> key1));
  276. // 打卡任务状态
  277. PiStatusQuery piStatusQuery = new PiStatusQuery();
  278. piStatusQuery.setUserIds(userIds);
  279. piStatusQuery.setStatusDate(punchInDate.minusDays(1).toString());
  280. List<PiStatus> piStatusList = piStatusService.queryByCondition(piStatusQuery);
  281. // 打卡任务状态,多任务唯一ID-打卡状态关联
  282. // Map<Long, PiStatus> piStatusMapInMultiTask = piStatusList.stream().filter(v -> Objects.nonNull(v.getMultiTaskUniqueId())).collect(Collectors.toMap(PiStatus::getMultiTaskUniqueId, Function.identity(), (key1, key2) -> key1));
  283. // 打卡任务状态,任务唯一ID-打卡状态关联
  284. Map<Long, PiStatus> piStatusMapInTask = piStatusList.stream().filter(v -> Objects.nonNull(v.getTaskUniqueId())).collect(Collectors.toMap(PiStatus::getTaskUniqueId, Function.identity(), (key1, key2) -> key1));
  285. // 多任务关联打卡任务,多任务ID-多任务关联打卡任务关联
  286. // List<PiMultiTaskRela> piMultiTaskRelaList = piMultiTaskRelaService.queryByMultiTaskId(multiTaskIds);
  287. // Map<Long, List<PiMultiTaskRela>> piMultiTaskRelaMap =
  288. // piMultiTaskRelaList.stream().collect(Collectors.groupingBy(PiMultiTaskRela::getMultiTaskId));
  289. // 获取打卡任务信息
  290. PiTaskQuery piTaskQuery = new PiTaskQuery();
  291. piTaskQuery.setTaskStatus(VersionStatusEnum.ACTIVE);
  292. piTaskQuery.setUserIds(userIds);
  293. List<PiTask> piTasks = piTaskService.queryByCondition(piTaskQuery);
  294. // 处理归档数据,以防归档任务早于结算任务执行
  295. piTasks = piTasks.stream().filter(v -> {
  296. // 已归档(只有手动和自动两种可能)
  297. if (ArchiveStatusEnum.ARCHIVE.equals(v.getArchiveStatus())) {
  298. // 有手动归档日期,是主动归档 且 结算日期在手动归档日期前,则参与结算
  299. if (Objects.nonNull(v.getManualArchiveDate()) && punchInDate.isBefore(v.getManualArchiveDate())) {
  300. return true;
  301. }
  302. // 有自动归档日期,时自动归档 且 结算日期小于等于归档日期 参与结算
  303. if (Objects.nonNull(v.getAutoArchiveDate()) && punchInDate.compareTo(v.getAutoArchiveDate()) < 1) {
  304. return true;
  305. }
  306. // 其他情况应该不存在,不参与结算
  307. return false;
  308. }
  309. // 非已归档情况,参与结算
  310. return true;
  311. }).toList();
  312. // 打卡任务唯一ID-打卡任务关联
  313. Map<Long, List<PiTask>> piTaskMap =
  314. piTasks.stream().collect(Collectors.groupingBy(PiTask::getCreatedBy));
  315. // 获取打卡记录,任务唯一 ID-打卡记录关联
  316. PiTaskHistoryQuery piTaskHistoryQuery = new PiTaskHistoryQuery();
  317. piTaskHistoryQuery.setPunchInDate(punchInDate.toString());
  318. piTaskHistoryQuery.setUserIds(userIds);
  319. List<PiTaskHistory> punchInTaskHistories = piTaskHistoryService.queryByCondition(piTaskHistoryQuery);
  320. Map<Long, PiTaskHistory> piTaskHistoryMap =
  321. punchInTaskHistories.stream().collect(Collectors.toMap(PiTaskHistory::getTaskUniqueId, Function.identity(), (key1, key2) -> key1));
  322. // 打卡任务ID
  323. Set<Long> punchInTaskIds = piTasks.stream().map(PiTask::getId).collect(Collectors.toSet());
  324. // 获取打卡任务拓展表,打卡任务ID-打卡任务拓展关联
  325. PiTaskExtQuery piTaskExtQuery = new PiTaskExtQuery();
  326. piTaskExtQuery.setPunchInTaskIds(punchInTaskIds);
  327. List<PiTaskExt> piTaskExtList = piTaskExtService.queryByCondition(piTaskExtQuery);
  328. Map<Long, List<PiTaskExt>> piTaskExtGroupList =
  329. piTaskExtList.stream().collect(Collectors.groupingBy(PiTaskExt::getTaskId));
  330. return userIds.stream().filter(userId -> piTaskMap.containsKey(userId)).map(userId -> {
  331. SettleData settleData = new SettleData();
  332. // 设置用户ID
  333. settleData.setUserId(userId);
  334. // TODO 获取并设置多任务打卡信息,这个不可能为空,为空则用户初始注册时创建时有问题
  335. // PiMultiTask piMultiTask = piMultiTaskMap.get(userId);
  336. // settleData.setPiMultiTask(piMultiTask);
  337. //
  338. // // 获取并设置对应的拓展信息
  339. // List<PiMultiTaskExt> tempPiMultiTaskExtList = piMultiTaskExtMap.get(piMultiTask.getId());
  340. // settleData.setPiMultiTaskExtList(tempPiMultiTaskExtList);
  341. // 获取并设置对应的多任务打卡记录
  342. // PiMultiTaskHistory piMultiTaskHistory = piMultiTaskHistoryMap.get(piMultiTask.getUniqueId());
  343. // settleData.setPiMultiTaskHistory(piMultiTaskHistory);
  344. //
  345. // // 获取多任务与打卡任务的关联信息
  346. // List<PiMultiTaskRela> tempPiMultiTaskRelaList = piMultiTaskRelaMap.get(piMultiTask.getId());
  347. // Set<Long> relaContainTaskIdList =
  348. // tempPiMultiTaskRelaList.stream().map(PiMultiTaskRela::getTaskId).collect(Collectors.toSet());
  349. //
  350. // // 获取并设置多任务的状态信息
  351. // PiStatus piStatusInMultiTask = piStatusMapInMultiTask.get(piMultiTask.getUniqueId());
  352. // settleData.setPiStatus(piStatusInMultiTask);
  353. // 获取任务列表
  354. List<PiTask> piTasksList = piTaskMap.get(userId);
  355. // 打卡任务数据
  356. List<PiTaskData> piTaskDataList = new ArrayList<>(piTasksList.size());
  357. // 关联的打卡任务记录
  358. // List<PiTaskHistory> relaPunchInTaskHistories = new ArrayList<>(relaContainTaskIdList.size());
  359. for (PiTask piTask : piTasksList) {
  360. PiTaskData piTaskData = new PiTaskData();
  361. piTaskData.setPiTask(piTask);
  362. // 获取并设置打卡任务
  363. PiTaskHistory piTaskHistory = piTaskHistoryMap.get(piTask.getUniqueId());
  364. piTaskData.setPiTaskHistory(piTaskHistory);
  365. //设置多任务与打卡记录的关联信息
  366. // if (relaContainTaskIdList.contains(piTask.getId())) {
  367. // relaPunchInTaskHistories.add(piTaskHistory);
  368. // }
  369. // 获取并设置拓展信息
  370. List<PiTaskExt> tempPiTaskExtList = piTaskExtGroupList.get(piTask.getId());
  371. piTaskData.setPiTaskExtList(tempPiTaskExtList);
  372. // 获取并设置任务状态
  373. PiStatus piStatusInTask = piStatusMapInTask.get(piTask.getUniqueId());
  374. piTaskData.setPiStatus(piStatusInTask);
  375. piTaskDataList.add(piTaskData);
  376. }
  377. settleData.setPiTaskDataList(piTaskDataList);
  378. // settleData.setRelaPunchInTaskHistories(relaPunchInTaskHistories);
  379. return settleData;
  380. }).collect(Collectors.toList());
  381. }
  382. /**
  383. * 更新打卡任务状态
  384. * @param piStatus 打卡任务状态
  385. * @param piTask 打卡任务
  386. * @param piTaskHistory 打卡任务记录
  387. * @param punchInDate 打卡日期
  388. * @param isMonday 是否周一
  389. * @param isFirstDayOfMonth 是否本月第一天
  390. * @param yearWeek 周数
  391. * @param yearMonth 月份数
  392. */
  393. private void refreshPiStatus(PiStatus piStatus, PiTask piTask, PiTaskHistory piTaskHistory, LocalDate punchInDate, boolean isMonday, boolean isFirstDayOfMonth, String yearWeek, String yearMonth) {
  394. // 获取打卡结果
  395. PunchInResultEnum punchInResult = Objects.isNull(piTaskHistory) ? PunchInResultEnum.UNDONE : piTaskHistory.getPunchInResult();
  396. // 刷新打卡状态中的连续任务数据
  397. refreshContinueData(piStatus, punchInResult, piTask, punchInDate);
  398. // 周一或月初
  399. if (isMonday || isFirstDayOfMonth) {
  400. piStatus.setRepeatCategory(piTask.getRepeatCategory());
  401. piStatus.setRepeatCustomDay(piTask.getRepeatCustomDay());
  402. }
  403. // 周一
  404. if (isMonday) {
  405. piStatus.setStatTimeInWeek(yearWeek);
  406. // 设置本周总打卡次数
  407. int PunchInTotalCountInWeek = punchInCoreManager.getPunchInTotalCountInRange(piTask.getRepeatCategory(),
  408. piTask.getRepeatCustomDay(), DateUtils.getFirstDayOfWeek(punchInDate),
  409. DateUtils.getLastDayOfWeek(punchInDate));
  410. piStatus.setPunchInTotalCountInWeek(PunchInTotalCountInWeek);
  411. // 重置数据
  412. piStatus.setPunchInCountInWeek(0);
  413. piStatus.setPunchInDoneCountInWeek(0);
  414. piStatus.setRepeatPrevTotalCountInWeek(0);
  415. piStatus.setRepeatStartDateInWeek(punchInDate);
  416. }
  417. // 打卡日所在月的第一天
  418. if (isFirstDayOfMonth) {
  419. piStatus.setStatTimeInMonth(yearMonth);
  420. // 设置本月总打卡次数
  421. int PunchInTotalCountInMonth = punchInCoreManager.getPunchInTotalCountInRange(piTask.getRepeatCategory(),
  422. piTask.getRepeatCustomDay(), DateUtils.getFirstDayOfMonth(punchInDate),
  423. DateUtils.getLastDayOfMonth(punchInDate));
  424. piStatus.setPunchInTotalCountInMonth(PunchInTotalCountInMonth);
  425. // 重置数据
  426. piStatus.setPunchInCountInMonth(0);
  427. piStatus.setPunchInDoneCountInMonth(0);
  428. piStatus.setRepeatPrevTotalCountInMonth(0);
  429. piStatus.setRepeatStartDateInMonth(punchInDate);
  430. }
  431. // 重复类型发生变换,总打卡次数=历史真实发生的总打卡次数+变换前发生的总打卡次数+变换后可能的总打卡次数
  432. if (!piStatus.getRepeatCategory().equals(piTask.getRepeatCategory())) {
  433. // 历史真实发生的总打卡次数(周)
  434. Integer oldPrevTotalCountInWeek = Optional.ofNullable(piStatus.getRepeatPrevTotalCountInWeek()).orElse(0);
  435. // 变换前发生的总打卡次数(周)
  436. int prevTotalCountInWeek = punchInCoreManager.getPunchInTotalCountInRange(piStatus.getRepeatCategory(),
  437. piStatus.getRepeatCustomDay(), piStatus.getRepeatStartDateInWeek(),
  438. punchInDate.minusDays(1));
  439. // 变换后可能的总打卡次数(周)
  440. int punchInTotalCountInWeek = punchInCoreManager.getPunchInTotalCountInRange(piTask.getRepeatCategory(), piTask.getRepeatCustomDay(), punchInDate, DateUtils.getLastDayOfWeek(punchInDate));
  441. // 历史真实发生的总打卡次数(月)
  442. Integer oldPrevTotalCountInMonth = Optional.ofNullable(piStatus.getRepeatPrevTotalCountInMonth()).orElse(0);
  443. // 变换前发生的总打卡次数(月)
  444. int prevTotalCountInMonth = punchInCoreManager.getPunchInTotalCountInRange(piStatus.getRepeatCategory(),
  445. piStatus.getRepeatCustomDay(), piStatus.getRepeatStartDateInMonth(),
  446. punchInDate.minusDays(1));
  447. // 变换后可能的总打卡次数(月 )
  448. int punchInTotalCountInMonth = punchInCoreManager.getPunchInTotalCountInRange(piTask.getRepeatCategory(), piTask.getRepeatCustomDay(), punchInDate, DateUtils.getLastDayOfMonth(punchInDate));
  449. // 设置实时数据
  450. piStatus.setRepeatPrevTotalCountInWeek(prevTotalCountInWeek + oldPrevTotalCountInWeek);
  451. piStatus.setPunchInTotalCountInWeek(Optional.ofNullable(piStatus.getRepeatPrevTotalCountInWeek()).orElse(0) + punchInTotalCountInWeek);
  452. piStatus.setRepeatPrevTotalCountInMonth(prevTotalCountInMonth + oldPrevTotalCountInMonth);
  453. piStatus.setPunchInTotalCountInMonth(Optional.ofNullable(piStatus.getRepeatPrevTotalCountInMonth()).orElse(0) + punchInTotalCountInMonth);
  454. }
  455. // 存在打卡记录则已打卡数加1
  456. if (Objects.nonNull(piTaskHistory)) {
  457. piStatus.setPunchInCountInWeek(Optional.ofNullable(piStatus.getPunchInCountInWeek()).orElse(0) + 1);
  458. piStatus.setPunchInCountInMonth(Optional.ofNullable(piStatus.getPunchInCountInMonth()).orElse(0) + 1);
  459. }
  460. // 完成打卡则完成打卡数记录加一
  461. if (PunchInResultEnum.DONE.equals(punchInResult)) {
  462. piStatus.setPunchInDoneCountInWeek(Optional.ofNullable(piStatus.getPunchInDoneCountInWeek()).orElse(0) + 1);
  463. piStatus.setPunchInDoneCountInMonth(Optional.ofNullable(piStatus.getPunchInDoneCountInMonth()).orElse(0) + 1);
  464. }
  465. }
  466. /**
  467. * 刷新打卡状态中的连续任务数据
  468. * @param piStatus
  469. * @param punchInResult
  470. * @param continueTask
  471. * @param punchInDate
  472. */
  473. private void refreshContinueData(PiStatus piStatus, PunchInResultEnum punchInResult, ContinueTask continueTask, LocalDate punchInDate) {
  474. // 设置任务连续状态
  475. ContinueStatusEnum oldTaskContinueStatus = piStatus.getTaskContinueStatus();
  476. piStatus.setTaskContinueStatus(punchInResult.equals(PunchInResultEnum.DONE)
  477. ? ContinueStatusEnum.CONTINUE : ContinueStatusEnum.INTERRUPTED);
  478. piStatus.setTaskContinueDay(oldTaskContinueStatus.equals(piStatus.getTaskContinueStatus())
  479. ? piStatus.getTaskContinueDay() + 1 : 1);
  480. // 旧的连续阶段
  481. ContinueStageEnum oldContinueStage = piStatus.getContinueStage();
  482. // 判断当前处于的连续阶段
  483. ContinueStageEnum continueStageResult =
  484. punchInCoreManager.judgeContinueStage(continueTask, punchInResult, piStatus, punchInDate);
  485. piStatus.setContinueStage(continueStageResult);
  486. // 下面3种情况不处理:宽限期 变 宽限期;正常打卡期 变 正常打卡期;惩罚期 变 惩罚期;
  487. // 宽限期 变 正常打卡期,则设置阶段开始时间,重置中断次数
  488. if (ContinueStageEnum.GRACE_STAGE.equals(oldContinueStage)
  489. && ContinueStageEnum.NORMAL_STAGE.equals(continueStageResult)) {
  490. piStatus.setStageStartDate(punchInDate);
  491. piStatus.setContinueInterruptedCount(0);
  492. }
  493. // 如果正常打卡期 变 惩罚期,则设置阶段开始时间和阶段结束时间,增加中断次数
  494. if (ContinueStageEnum.NORMAL_STAGE.equals(oldContinueStage)
  495. && ContinueStageEnum.PENALTY_STAGE.equals(continueStageResult)) {
  496. piStatus.setStageStartDate(punchInDate);
  497. piStatus.setStageEndDate(punchInDate.plusDays(continueTask.getPenaltyDay()));
  498. piStatus.setContinueInterruptedCount(piStatus.getContinueInterruptedCount() + 1);
  499. }
  500. // 如果惩罚期 变 正常打卡期,则设置阶段开始时间
  501. if (ContinueStageEnum.PENALTY_STAGE.equals(oldContinueStage)
  502. && ContinueStageEnum.NORMAL_STAGE.equals(continueStageResult)) {
  503. piStatus.setStageStartDate(punchInDate);
  504. }
  505. }
  506. @Override
  507. @Transactional(rollbackFor = Exception.class)
  508. public void distributePoints(LocalDate settleDate) {
  509. // 查询结算记录
  510. SettleUserHistoryQuery settleUserHistoryQuery = new SettleUserHistoryQuery();
  511. settleUserHistoryQuery.setSettleDate(settleDate.toString());
  512. settleUserHistoryQuery.setDistributeStatus(PointsDistributeStatusEnum.NOT_DISTRIBUTE);
  513. List<SettleUserHistory> settleUserHistories = settleUserHistoryService.querySettleUserHistory(settleUserHistoryQuery);
  514. if (CollectionUtils.isEmpty(settleUserHistories)) {
  515. log.info("========== 积分分发,没有可分发的积分 结束执行 ==========");
  516. return;
  517. }
  518. // 零结算积分,直接修改结算状态节课
  519. List<SettleUserHistory> zeroSettleUserHistories = settleUserHistories.stream().filter(settleUserHistory -> Optional.ofNullable(settleUserHistory.getSettlePoints()).orElse(0).equals(0)).toList();
  520. zeroSettleUserHistories.forEach(v -> v.setDistributeStatus(PointsDistributeStatusEnum.DISTRIBUTE));
  521. // 非零结算积分,下发积分
  522. List<SettleUserHistory> nonZeroSettleUserHistories = settleUserHistories.stream().filter(settleUserHistory -> !Optional.ofNullable(settleUserHistory.getSettlePoints()).orElse(0).equals(0)).toList();
  523. // 用户ID-用户结算记录关联
  524. Map<Long, SettleUserHistory> settleUserHistoryMap = nonZeroSettleUserHistories.stream().collect(Collectors.toMap(SettleUserHistory::getUserId, Function.identity(), (key1, key2) -> key1));
  525. // 用户ID列表
  526. Set<Long> userIds = nonZeroSettleUserHistories.stream().map(SettleUserHistory::getUserId).collect(Collectors.toSet());
  527. // 用户信息, 用户ID-用户信息关联
  528. List<User> users = userService.listByIds(userIds);
  529. Map<Long, User> userMap = users.stream().collect(Collectors.toMap(User::getId, Function.identity(), (key1, key2) -> key1));
  530. // 获取账户信息,用户ID-账户信息关联
  531. AccountQuery accountQuery = new AccountQuery();
  532. accountQuery.setAccountCategory(AccountCategoryEnum.BASIC);
  533. accountQuery.setUserIds(userIds);
  534. List<Account> accounts = accountService.getAccountByCondition(accountQuery);
  535. Map<Long, Account> accountMap = accounts.stream().collect(Collectors.toMap(Account::getUserId, Function.identity(), (key1, key2) -> key1));
  536. // 用户信息 更新列表
  537. List<User> updateUserList = new ArrayList<>();
  538. // 账户信息 更新列表
  539. List<Account> updateAccountList = new ArrayList<>();
  540. // 转账记录 新增列表
  541. List<AccountTransferHistory> addAccountTransferHistories = new ArrayList<>();
  542. // 结算用户信息 更新列表
  543. List<SettleUserHistory> updateSettleUserHistories = new ArrayList<>();
  544. for (Long userId : userIds) {
  545. // 用户信息
  546. User user = userMap.get(userId);
  547. // 账户信息
  548. Account account = accountMap.get(userId);
  549. // 结算信息
  550. SettleUserHistory oldSettleUserHistory = settleUserHistoryMap.get(userId);
  551. // 结算积分
  552. Integer settlePoints = Optional.ofNullable(oldSettleUserHistory.getSettlePoints()).orElse(0);
  553. // 获取并设置用户信息
  554. Integer beforeTotalPoints = Optional.ofNullable(user.getTotalPoints()).orElse(0);
  555. Integer beforeUnusedPoints = Optional.ofNullable(user.getUnusedPoints()).orElse(0);
  556. User updateUser = new User();
  557. updateUser.setId(user.getId());
  558. updateUser.setTotalPoints(beforeTotalPoints + settlePoints);
  559. updateUser.setUnusedPoints(beforeUnusedPoints + settlePoints);
  560. updateUserList.add(updateUser);
  561. // 更新账户信息
  562. Integer beforeAccountPoints = Optional.ofNullable(account.getPoints()).orElse(0);
  563. Account updateAccount = new Account();
  564. updateAccount.setId(account.getId());
  565. updateAccount.setPoints(beforeAccountPoints + settlePoints);
  566. updateAccountList.add(updateAccount);
  567. // 增加账户转账记录
  568. AccountTransferHistory accountTransferHistory = new AccountTransferHistory();
  569. accountTransferHistory.setUserId(userId);
  570. accountTransferHistory.setTransferPoints(settlePoints);
  571. accountTransferHistory.setTransferCategory(TransferCategoryEnum.SETTLE);
  572. accountTransferHistory.setRecipientAccountId(account.getId());
  573. accountTransferHistory.setRaPointsBeforeTransfer(beforeAccountPoints);
  574. accountTransferHistory.setRaPointsAfterTransfer(account.getPoints());
  575. addAccountTransferHistories.add(accountTransferHistory);
  576. // 设置结算积分记录
  577. SettleUserHistory updateSettleUserHistory = new SettleUserHistory();
  578. updateSettleUserHistory.setId(oldSettleUserHistory.getId());
  579. updateSettleUserHistory.setBeforeSettlePoints(beforeTotalPoints);
  580. updateSettleUserHistory.setAfterSettlePoints(beforeTotalPoints + settlePoints);
  581. updateSettleUserHistory.setDistributeStatus(PointsDistributeStatusEnum.DISTRIBUTE);
  582. updateSettleUserHistories.add(updateSettleUserHistory);
  583. }
  584. if (!CollectionUtils.isEmpty(updateUserList)) {
  585. userService.batchUpdate(updateUserList);
  586. }
  587. if (!CollectionUtils.isEmpty(updateAccountList)) {
  588. accountService.batchUpdate(updateAccountList);
  589. }
  590. if (!CollectionUtils.isEmpty(addAccountTransferHistories)) {
  591. accountTransferHistoryService.insertList(addAccountTransferHistories);
  592. }
  593. if (!CollectionUtils.isEmpty(updateSettleUserHistories)) {
  594. settleUserHistoryService.batchUpdate(updateSettleUserHistories);
  595. }
  596. if (!CollectionUtils.isEmpty(zeroSettleUserHistories)) {
  597. settleUserHistoryService.batchUpdate(zeroSettleUserHistories);
  598. }
  599. userIds.forEach(userId -> {
  600. cacheManager.batchEvict(Arrays.asList(CacheNameConstant.USER, CacheNameConstant.USER_VO), userId);
  601. accountManager.clearCache(userId);
  602. });
  603. }
  604. }