SettleManagerImpl.java 33 KB

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