TaskStocktakingServiceImpl.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. package com.jsh.erp.service.impl;
  2. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  3. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  4. import com.jsh.erp.datasource.dto.TaskStocktakingDTO;
  5. import com.jsh.erp.datasource.dto.TaskStocktakingItemQueryDTO;
  6. import com.jsh.erp.datasource.dto.TaskStocktakingQueryDTO;
  7. import com.jsh.erp.datasource.entities.*;
  8. import com.jsh.erp.datasource.mappers.*;
  9. import com.jsh.erp.datasource.pda.dto.PDATaskStocktakingItemDTO;
  10. import com.jsh.erp.datasource.pda.vo.PDATaskStocktakingItemVO;
  11. import com.jsh.erp.datasource.pda.vo.PDATaskStocktakingVO;
  12. import com.jsh.erp.datasource.vo.TaskStocktakingItemVO;
  13. import com.jsh.erp.datasource.vo.TaskStocktakingVO;
  14. import com.jsh.erp.query.LambdaQueryWrapperX;
  15. import com.jsh.erp.service.*;
  16. import com.jsh.erp.utils.PageUtils;
  17. import com.jsh.erp.utils.StringUtil;
  18. import lombok.RequiredArgsConstructor;
  19. import lombok.extern.slf4j.Slf4j;
  20. import org.springframework.beans.BeanUtils;
  21. import org.springframework.stereotype.Service;
  22. import org.springframework.transaction.annotation.Transactional;
  23. import javax.annotation.Resource;
  24. import java.math.BigDecimal;
  25. import java.math.RoundingMode;
  26. import java.util.ArrayList;
  27. import java.util.Collections;
  28. import java.util.Date;
  29. import java.util.List;
  30. import java.util.stream.Collectors;
  31. @Service
  32. @RequiredArgsConstructor
  33. @Slf4j
  34. public class TaskStocktakingServiceImpl extends ServiceImpl<TaskStocktakingMapper, TaskStocktaking> implements TaskStocktakingService {
  35. private final UserMapper userMapper;
  36. private final DepotMapper depotMapper;
  37. private final TaskStocktakingItemMapper taskStocktakingItemMapper;
  38. private final TaskStocktakingMapper taskStocktakingMapper;
  39. private final MaterialMapper materialMapper;
  40. private final UserService userService;
  41. private final SequenceService sequenceService;
  42. private final MaterialBatchMapper materialBatchMapper;
  43. private final MaterialUpcMapper materialUpcMapper;
  44. @Resource
  45. private AuditService auditService;
  46. @Override
  47. public List<TaskStocktakingVO> listBy(TaskStocktakingQueryDTO taskStocktakingQueryDTO) {
  48. return taskStocktakingMapper.listBy(taskStocktakingQueryDTO);
  49. }
  50. /**
  51. * 创建盘点任务
  52. * @param taskStocktakingDTO
  53. * @return
  54. */
  55. @Override
  56. @Transactional(value = "transactionManager", rollbackFor = Exception.class)
  57. public boolean add(TaskStocktakingDTO taskStocktakingDTO) {
  58. try {
  59. List<String> collect;
  60. List<MaterialBatch> materialBatchList;
  61. //全盘,抽盘,处理任务明细
  62. if (taskStocktakingDTO.getTaskType() == 1) {
  63. materialBatchList = materialBatchMapper.selectList(new LambdaQueryWrapper<MaterialBatch>().ne(MaterialBatch::getInventory, BigDecimal.ZERO).isNotNull(MaterialBatch::getInventory).eq(MaterialBatch::getDepotId,taskStocktakingDTO.getDepotId()));
  64. collect = materialBatchList
  65. .stream()
  66. .map(MaterialBatch::getPosition)
  67. .collect(Collectors.toList());
  68. List<Long> materialIdList = materialBatchList.stream().map(MaterialBatch::getMaterialId).distinct().collect(Collectors.toList());
  69. List<Material> materialList = materialMapper.selectList(new LambdaQueryWrapperX<Material>().in(Material::getId, materialIdList));
  70. List<Long> categoryIdList = materialList.stream().map(Material::getCategoryId).distinct().collect(Collectors.toList());
  71. taskStocktakingDTO.setCategoryCount(categoryIdList.size());
  72. taskStocktakingDTO.setMaterialCount(materialBatchList.size());
  73. } else {
  74. materialBatchList = materialBatchMapper.selectList(new LambdaQueryWrapper<MaterialBatch>().in(MaterialBatch::getBatchNumber, taskStocktakingDTO.getMaterialExtendIdList()));
  75. collect = materialBatchList.stream().map(MaterialBatch::getPosition).collect(Collectors.toList());
  76. List<Long> materialIdList = materialBatchList.stream().map(MaterialBatch::getMaterialId).collect(Collectors.toList());
  77. List<Material> materialList = materialMapper.selectList(new LambdaQueryWrapperX<Material>().in(Material::getId, materialIdList));
  78. List<Long> categoryIdList = materialList.stream().map(Material::getCategoryId).distinct().collect(Collectors.toList());
  79. taskStocktakingDTO.setCategoryCount(categoryIdList.size());
  80. taskStocktakingDTO.setMaterialCount(materialBatchList.size());
  81. }
  82. //处理商品库位范围处理
  83. String positionRange = extractRangePair(collect);
  84. taskStocktakingDTO.setPositionRange(positionRange);
  85. User currentUser = userService.getCurrentUser();
  86. taskStocktakingDTO.setCreateBy(currentUser.getId());
  87. taskStocktakingDTO.setCreateTime(new Date());
  88. //生成单据编号
  89. taskStocktakingDTO.setNumber("PDRW" + sequenceService.buildOnlyNumber());
  90. //生成任务
  91. this.save(taskStocktakingDTO);
  92. //生成任务明细
  93. List<TaskStocktakingItem> taskStocktakingItemList = new ArrayList<>();
  94. materialBatchList.forEach(item -> {
  95. TaskStocktakingItem taskStocktakingItem = new TaskStocktakingItem();
  96. taskStocktakingItem.setTaskStocktakingId(taskStocktakingDTO.getId());
  97. taskStocktakingItem.setMaterialItemId(item.getId());
  98. taskStocktakingItemList.add(taskStocktakingItem);
  99. });
  100. taskStocktakingItemMapper.insertBatch(taskStocktakingItemList);
  101. if (taskStocktakingDTO.getTaskStatus().equals(9)){
  102. auditService.generateAuditByItemId(taskStocktakingDTO.getNumber(),"盘点任务");
  103. }
  104. } catch (Exception e) {
  105. log.error("创建盘点任务失败", e);
  106. return false;
  107. }
  108. return true;
  109. }
  110. /**
  111. * 任务-详情
  112. * @param id 任务ID
  113. * @return
  114. * @throws Exception
  115. */
  116. @Override
  117. public TaskStocktakingVO detail(Long id) throws Exception{
  118. TaskStocktaking one = getOne(new LambdaQueryWrapperX<TaskStocktaking>().eq(TaskStocktaking::getId, id));
  119. TaskStocktakingVO taskStocktakingVO = new TaskStocktakingVO();
  120. BeanUtils.copyProperties(one, taskStocktakingVO);
  121. //获取负责人名称
  122. User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getId, one.getCreator()));
  123. if (user != null) {
  124. taskStocktakingVO.setCreatorName(user.getUsername());
  125. }
  126. //获取创建人名称
  127. User user1 = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getId, one.getCreateBy()));
  128. if (user1 != null) {
  129. taskStocktakingVO.setCreateByName(user1.getUsername());
  130. }
  131. //获取盘点人名称
  132. User user2 = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getId, one.getOperBy()));
  133. if (user2 != null) {
  134. taskStocktakingVO.setOperByName(user2.getUsername());
  135. }
  136. //获取仓库名称
  137. Depot depot = depotMapper.selectById(one.getDepotId());
  138. taskStocktakingVO.setDepotName(depot.getName());
  139. //当任务类型是抽盘时,返回商品盘点信息
  140. return taskStocktakingVO;
  141. }
  142. /**
  143. * 任务-详情
  144. * @param number 任务编号
  145. */
  146. @Override
  147. public TaskStocktakingVO detail(String number) {
  148. TaskStocktaking one = getOne(new LambdaQueryWrapperX<TaskStocktaking>().eq(TaskStocktaking::getNumber, number));
  149. TaskStocktakingVO taskStocktakingVO = new TaskStocktakingVO();
  150. BeanUtils.copyProperties(one, taskStocktakingVO);
  151. //获取负责人名称
  152. User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getId, one.getCreator()));
  153. if (user != null) {
  154. taskStocktakingVO.setCreatorName(user.getUsername());
  155. }
  156. //获取创建人名称
  157. User user1 = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getId, one.getCreateBy()));
  158. if (user1 != null) {
  159. taskStocktakingVO.setCreateByName(user1.getUsername());
  160. }
  161. //获取盘点人名称
  162. User user2 = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getId, one.getOperBy()));
  163. if (user2 != null) {
  164. taskStocktakingVO.setOperByName(user2.getUsername());
  165. }
  166. //获取仓库名称
  167. Depot depot = depotMapper.selectById(one.getDepotId());
  168. taskStocktakingVO.setDepotName(depot.getName());
  169. //当任务类型是抽盘时,返回商品盘点信息
  170. return taskStocktakingVO;
  171. }
  172. /**
  173. * 任务详情-修改
  174. * @param taskStocktakingDTO
  175. * @return
  176. */
  177. @Override
  178. @Transactional(value = "transactionManager", rollbackFor = Exception.class)
  179. public boolean detailUpdate(TaskStocktakingDTO taskStocktakingDTO) {
  180. try {
  181. List<String> collect;
  182. List<MaterialBatch> materialExtendList;
  183. //全盘,抽盘,处理任务明细
  184. if (taskStocktakingDTO.getTaskType() == 1) {
  185. materialExtendList = materialBatchMapper.selectList(new LambdaQueryWrapper<MaterialBatch>().ne(MaterialBatch::getInventory, BigDecimal.ZERO).isNotNull(MaterialBatch::getInventory).eq(MaterialBatch::getDepotId,taskStocktakingDTO.getDepotId()));
  186. collect = materialExtendList
  187. .stream()
  188. .map(MaterialBatch::getPosition)
  189. .collect(Collectors.toList());
  190. List<Long> materialIdList = materialExtendList.stream().map(MaterialBatch::getMaterialId).distinct().collect(Collectors.toList());
  191. List<Material> materialList = materialMapper.selectList(new LambdaQueryWrapperX<Material>().eq(Material::getId, materialIdList));
  192. List<Long> categoryIdList = materialList.stream().map(Material::getCategoryId).distinct().collect(Collectors.toList());
  193. taskStocktakingDTO.setCategoryCount(categoryIdList.size());
  194. taskStocktakingDTO.setMaterialCount(materialExtendList.size());
  195. } else {
  196. materialExtendList = materialBatchMapper.selectList(new LambdaQueryWrapper<MaterialBatch>().in(MaterialBatch::getBatchNumber, taskStocktakingDTO.getMaterialExtendIdList()));
  197. collect = materialExtendList.stream().map(MaterialBatch::getPosition).collect(Collectors.toList());
  198. List<Long> materialIdList = materialExtendList.stream().map(MaterialBatch::getMaterialId).collect(Collectors.toList());
  199. List<Material> materialList = materialMapper.selectList(new LambdaQueryWrapperX<Material>().in(Material::getId, materialIdList));
  200. List<Long> categoryIdList = materialList.stream().map(Material::getCategoryId).distinct().collect(Collectors.toList());
  201. taskStocktakingDTO.setCategoryCount(categoryIdList.size());
  202. taskStocktakingDTO.setMaterialCount(materialExtendList.size());
  203. }
  204. //处理商品库位范围处理
  205. String positionRange = extractRangePair(collect);
  206. taskStocktakingDTO.setPositionRange(positionRange);
  207. User currentUser = userService.getCurrentUser();
  208. taskStocktakingDTO.setCreateBy(currentUser.getId());
  209. taskStocktakingDTO.setCreateTime(new Date());
  210. //生成任务
  211. this.updateById(taskStocktakingDTO);
  212. List<Long> taskStocktakingItemIdList = taskStocktakingItemMapper.selectList(new LambdaQueryWrapperX<TaskStocktakingItem>().eq(TaskStocktakingItem::getTaskStocktakingId, taskStocktakingDTO.getId())).stream().map(TaskStocktakingItem::getId).collect(Collectors.toList());
  213. //生成任务明细
  214. List<TaskStocktakingItem> addTaskStocktakingItemList = new ArrayList<>();
  215. materialExtendList.forEach(item -> {
  216. if (!taskStocktakingItemIdList.contains(item.getId())) {
  217. TaskStocktakingItem taskStocktakingItem = new TaskStocktakingItem();
  218. taskStocktakingItem.setTaskStocktakingId(taskStocktakingDTO.getId());
  219. taskStocktakingItem.setMaterialItemId(item.getId());
  220. addTaskStocktakingItemList.add(taskStocktakingItem);
  221. }
  222. });
  223. List<Long> materialExtendIdList = materialExtendList.stream().map(MaterialBatch::getId).collect(Collectors.toList());
  224. taskStocktakingItemIdList.forEach(item -> {
  225. if (!materialExtendIdList.contains(item)) {
  226. TaskStocktakingItem taskStocktakingItem = new TaskStocktakingItem();
  227. taskStocktakingItem.setId(item);
  228. taskStocktakingItem.setDeleteFlag(true);
  229. taskStocktakingItemMapper.updateById(taskStocktakingItem);
  230. }
  231. });
  232. if (addTaskStocktakingItemList.size() > 0) {
  233. taskStocktakingItemMapper.insertBatch(addTaskStocktakingItemList);
  234. }
  235. if (taskStocktakingDTO.getTaskStatus().equals(9)){
  236. auditService.generateAuditByItemId(taskStocktakingDTO.getNumber(),"盘点任务");
  237. }
  238. } catch (Exception e) {
  239. log.error("修改盘点任务失败", e);
  240. return false;
  241. }
  242. return true;
  243. }
  244. /**
  245. * 任务详情-商品明细
  246. * @param taskStocktakingItemQueryDTO 筛选参数
  247. * @return
  248. */
  249. @Override
  250. public List<TaskStocktakingItemVO> listByTaskStocktakingId(TaskStocktakingItemQueryDTO taskStocktakingItemQueryDTO) {
  251. return taskStocktakingItemMapper.listByTaskStocktakingId(taskStocktakingItemQueryDTO);
  252. }
  253. /**
  254. * PDA-盘点任务列表
  255. * @param number 盘点单号或者任务名称
  256. * @param taskStatus 盘点任务状态
  257. * @return
  258. */
  259. @Override
  260. public List<PDATaskStocktakingVO> pdaList(String number , Integer taskStatus, Long depotId) {
  261. return taskStocktakingMapper.pdaList(number , taskStatus, depotId);
  262. }
  263. /**
  264. * PDA-盘点任务详情
  265. * @param id 盘点任务ID
  266. * @return
  267. * @throws Exception
  268. */
  269. @Override
  270. public TaskStocktakingVO pdaDetail(Long id) throws Exception{
  271. TaskStocktakingVO detail = detail(id);
  272. List<TaskStocktakingItem> itemList = taskStocktakingItemMapper.selectList(new LambdaQueryWrapper<TaskStocktakingItem>().eq(TaskStocktakingItem::getTaskStocktakingId, id));
  273. //已操作数量
  274. long finishCount = itemList.stream().filter(item -> item.getCreator() != null).count();
  275. //操作人数
  276. long operCount = itemList.stream().filter(item -> item.getCreator() != null).map(TaskStocktakingItem::getCreator).distinct().count();
  277. //商品总数量
  278. long itemCount = itemList.size();
  279. //商品差异条数
  280. long itemDifferenceCount = itemList.stream().filter(item -> item.getCreator() != null
  281. && item.getDifferenceCount() != null
  282. && item.getDifferenceCount() > 0).count();
  283. //差异率
  284. double differenceRate = 0;
  285. //准确率
  286. double accuracyRate = 100;
  287. if (itemDifferenceCount > 0) {
  288. //差异率 = 商品差异条数/商品总数量*100%
  289. differenceRate = BigDecimal.valueOf(itemDifferenceCount)
  290. .divide(BigDecimal.valueOf(itemCount), 4, RoundingMode.HALF_UP)
  291. .multiply(BigDecimal.valueOf(100))
  292. .doubleValue();
  293. //准确数 = 已操作数量-商品差异条数
  294. BigDecimal subtract = BigDecimal.valueOf(finishCount).subtract(BigDecimal.valueOf(itemDifferenceCount));
  295. //准确率 = 准确数/商品总数量*100%
  296. if (!subtract.equals(BigDecimal.ZERO)) {
  297. accuracyRate = subtract.divide(BigDecimal.valueOf(itemCount), 4, RoundingMode.HALF_UP)
  298. .multiply(BigDecimal.valueOf(100))
  299. .doubleValue();
  300. }
  301. }
  302. detail.setItemCount(itemCount);
  303. detail.setDifferenceRate(differenceRate);
  304. detail.setAccuracyRate(accuracyRate);
  305. detail.setFinishCount(finishCount);
  306. detail.setOperCount(operCount);
  307. return detail;
  308. }
  309. @Override
  310. public List<PDATaskStocktakingItemVO> pdaItemList(PDATaskStocktakingItemDTO pdaTaskStocktakingItemDTO) {
  311. if (StringUtil.isNotEmpty(pdaTaskStocktakingItemDTO.getNumber())){
  312. MaterialUpc upc = materialUpcMapper.selectOne(new LambdaQueryWrapperX<MaterialUpc>()
  313. .eq(MaterialUpc::getUpc,pdaTaskStocktakingItemDTO.getNumber())
  314. .eq(MaterialUpc::getDeleteFlag,false));
  315. if (upc != null && upc.getMaterialExtendId() != null){
  316. pdaTaskStocktakingItemDTO.setMaterialExtendId(upc.getMaterialExtendId());
  317. }
  318. }
  319. PageUtils.startPage();
  320. return taskStocktakingItemMapper.pdaList(pdaTaskStocktakingItemDTO);
  321. }
  322. /**
  323. * 计算库位范围
  324. * @param data 库位集合
  325. * @return
  326. */
  327. public static String extractRangePair(List<String> data) {
  328. // 用于存储提取的前两部分
  329. List<String> rangeParts = new ArrayList<>();
  330. for (String item : data) {
  331. if (item != null){
  332. // 提取前两部分(假设格式固定,以 "-" 分割,取前两部分)
  333. String[] parts = item.split("-");
  334. if (parts.length >= 2) {
  335. String rangePart = parts[0] + "-" + parts[1];
  336. rangeParts.add(rangePart); // 添加到列表
  337. }
  338. }
  339. }
  340. // 如果范围为空,直接返回空字符串
  341. if (rangeParts.isEmpty()) {
  342. return "";
  343. }
  344. // 找到最小和最大范围
  345. String minRange = Collections.min(rangeParts); // 字典序最小
  346. String maxRange = Collections.max(rangeParts); // 字典序最大
  347. // 返回范围对
  348. return minRange + "——" + maxRange;
  349. }
  350. }