Commit c62f0e67fb80eb0a2540968b2ff0df706f2acdb5

Authored by YunaiV
1 parent aa5e1618

feat(mes): 支持盘点任务的动态时间过滤:

1. 新增动态盘点时间过滤功能
 2. 重构盘点任务流程
 3. 代码优化
 4. 前端适配
Showing 15 changed files with 723 additions and 36 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockListReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +
  8 +@Schema(description = "管理后台 - 物料库存查询 Request VO")
  9 +@Data
  10 +public class MesWmMaterialStockListReqVO {
  11 +
  12 + @Schema(description = "仓库编号")
  13 + private Long warehouseId;
  14 +
  15 + @Schema(description = "库区编号")
  16 + private Long locationId;
  17 +
  18 + @Schema(description = "库位编号")
  19 + private Long areaId;
  20 +
  21 + @Schema(description = "物料编号")
  22 + private Long itemId;
  23 +
  24 + @Schema(description = "批次编号")
  25 + private Long batchId;
  26 + // TODO @芋艿:后面看看,要不要 batchCode
  27 +
  28 + @Schema(description = "开始时间(动态盘点用)")
  29 + private LocalDateTime startTime;
  30 +
  31 + @Schema(description = "结束时间(动态盘点用)")
  32 + private LocalDateTime endTime;
  33 +
  34 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/stocktaking/task/MesWmStockTakingTaskController.java
@@ -98,9 +98,10 @@ public class MesWmStockTakingTaskController { @@ -98,9 +98,10 @@ public class MesWmStockTakingTaskController {
98 98
99 @PutMapping("/submit") 99 @PutMapping("/submit")
100 @Operation(summary = "提交盘点任务") 100 @Operation(summary = "提交盘点任务")
  101 + @Parameter(name = "id", description = "编号", required = true)
101 @PreAuthorize("@ss.hasPermission('mes:wm-stock-taking-task:update')") 102 @PreAuthorize("@ss.hasPermission('mes:wm-stock-taking-task:update')")
102 - public CommonResult<Boolean> submitStockTakingTask(@Valid @RequestBody MesWmStockTakingTaskSubmitReqVO reqVO) {  
103 - stockTakingTaskService.submitStockTakingTask(reqVO.getId()); 103 + public CommonResult<Boolean> submitStockTakingTask(@RequestParam("id") Long id) {
  104 + stockTakingTaskService.submitStockTakingTask(id);
104 return success(true); 105 return success(true);
105 } 106 }
106 107
@@ -136,14 +137,6 @@ public class MesWmStockTakingTaskController { @@ -136,14 +137,6 @@ public class MesWmStockTakingTaskController {
136 buildTaskRespVOList(pageResult.getList())); 137 buildTaskRespVOList(pageResult.getList()));
137 } 138 }
138 139
139 - @PutMapping("/start")  
140 - @Operation(summary = "开始盘点任务")  
141 - @PreAuthorize("@ss.hasPermission('mes:wm-stock-taking-task:update')")  
142 - public CommonResult<Boolean> startStockTakingTask(@Valid @RequestBody MesWmStockTakingTaskStartReqVO reqVO) {  
143 - stockTakingTaskService.startStockTakingTask(reqVO.getId());  
144 - return success(true);  
145 - }  
146 -  
147 @PutMapping("/finish") 140 @PutMapping("/finish")
148 @Operation(summary = "完成盘点任务") 141 @Operation(summary = "完成盘点任务")
149 @PreAuthorize("@ss.hasPermission('mes:wm-stock-taking-task:finish')") 142 @PreAuthorize("@ss.hasPermission('mes:wm-stock-taking-task:finish')")
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/stocktaking/task/vo/MesWmStockTakingTaskSaveReqVO.java
@@ -33,7 +33,8 @@ public class MesWmStockTakingTaskSaveReqVO { @@ -33,7 +33,8 @@ public class MesWmStockTakingTaskSaveReqVO {
33 @NotNull(message = "盘点人不能为空") 33 @NotNull(message = "盘点人不能为空")
34 private Long userId; 34 private Long userId;
35 35
36 - @Schema(description = "来源方案 ID", example = "1") 36 + @Schema(description = "来源方案 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  37 + @NotNull(message = "来源方案不能为空")
37 private Long planId; 38 private Long planId;
38 39
39 @Schema(description = "开始时间") 40 @Schema(description = "开始时间")
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java
@@ -3,15 +3,15 @@ package cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock; @@ -3,15 +3,15 @@ package cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockListReqVO;
6 import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO; 7 import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO;
7 -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;  
8 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; 8 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
  9 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
9 import org.apache.ibatis.annotations.Mapper; 10 import org.apache.ibatis.annotations.Mapper;
10 11
11 import java.math.BigDecimal; 12 import java.math.BigDecimal;
12 import java.util.Collection; 13 import java.util.Collection;
13 import java.util.List; 14 import java.util.List;
14 -import java.util.Set;  
15 15
16 /** 16 /**
17 * MES 库存台账 Mapper 17 * MES 库存台账 Mapper
@@ -65,17 +65,17 @@ public interface MesWmMaterialStockMapper extends BaseMapperX&lt;MesWmMaterialStock @@ -65,17 +65,17 @@ public interface MesWmMaterialStockMapper extends BaseMapperX&lt;MesWmMaterialStock
65 .eqIfPresent(MesWmMaterialStockDO::getBatchId, batchId)); 65 .eqIfPresent(MesWmMaterialStockDO::getBatchId, batchId));
66 } 66 }
67 67
68 - default List<MesWmMaterialStockDO> selectListForStockTaking(Set<Long> warehouseIds, Set<Long> locationIds,  
69 - Set<Long> areaIds, Set<Long> itemIds,  
70 - Set<Long> batchIds) { 68 + default List<MesWmMaterialStockDO> selectListForStockTaking(MesWmMaterialStockListReqVO reqVO) {
71 return selectList(new LambdaQueryWrapperX<MesWmMaterialStockDO>() 69 return selectList(new LambdaQueryWrapperX<MesWmMaterialStockDO>()
72 - .inIfPresent(MesWmMaterialStockDO::getWarehouseId, warehouseIds)  
73 - .inIfPresent(MesWmMaterialStockDO::getLocationId, locationIds)  
74 - .inIfPresent(MesWmMaterialStockDO::getAreaId, areaIds)  
75 - .inIfPresent(MesWmMaterialStockDO::getItemId, itemIds)  
76 - .inIfPresent(MesWmMaterialStockDO::getBatchId, batchIds)  
77 - .ne(MesWmMaterialStockDO::getQuantityOnhand, BigDecimal.ZERO)  
78 - .orderByAsc(MesWmMaterialStockDO::getId)); 70 + .eqIfPresent(MesWmMaterialStockDO::getWarehouseId, reqVO.getWarehouseId())
  71 + .eqIfPresent(MesWmMaterialStockDO::getLocationId, reqVO.getLocationId())
  72 + .eqIfPresent(MesWmMaterialStockDO::getAreaId, reqVO.getAreaId())
  73 + .eqIfPresent(MesWmMaterialStockDO::getItemId, reqVO.getItemId())
  74 + .eqIfPresent(MesWmMaterialStockDO::getBatchId, reqVO.getBatchId())
  75 + .geIfPresent(MesWmMaterialStockDO::getUpdateTime, reqVO.getStartTime())
  76 + .leIfPresent(MesWmMaterialStockDO::getUpdateTime, reqVO.getEndTime())
  77 + .ne(MesWmMaterialStockDO::getQuantityOnhand, BigDecimal.ZERO) // TODO @芋艿:需要在考虑下,要不要支持;
  78 + .orderByAsc(MesWmMaterialStockDO::getRecptDate));
79 } 79 }
80 80
81 } 81 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
@@ -484,6 +484,7 @@ public interface ErrorCodeConstants { @@ -484,6 +484,7 @@ public interface ErrorCodeConstants {
484 ErrorCode WM_STOCK_TAKING_TASK_NO_STOCK = new ErrorCode(1_040_714_115, "未找到符合条件的库存数据"); 484 ErrorCode WM_STOCK_TAKING_TASK_NO_STOCK = new ErrorCode(1_040_714_115, "未找到符合条件的库存数据");
485 ErrorCode WM_STOCK_TAKING_TASK_NO_LINE = new ErrorCode(1_040_714_116, "盘点任务至少需要一条任务行"); 485 ErrorCode WM_STOCK_TAKING_TASK_NO_LINE = new ErrorCode(1_040_714_116, "盘点任务至少需要一条任务行");
486 ErrorCode WM_STOCK_TAKING_TASK_LINE_NOT_EXISTS = new ErrorCode(1_040_714_117, "盘点任务行不存在"); 486 ErrorCode WM_STOCK_TAKING_TASK_LINE_NOT_EXISTS = new ErrorCode(1_040_714_117, "盘点任务行不存在");
  487 + ErrorCode WM_STOCK_TAKING_TASK_DYNAMIC_TIME_REQUIRED = new ErrorCode(1_040_714_118, "动态盘点必须选择开始时间和结束时间");
487 488
488 // ========== MES 仓库管理-销售出库单(1-040-714-000) ========== 489 // ========== MES 仓库管理-销售出库单(1-040-714-000) ==========
489 ErrorCode WM_PRODUCT_SALES_NOT_EXISTS = new ErrorCode(1_040_714_000, "销售出库单不存在"); 490 ErrorCode WM_PRODUCT_SALES_NOT_EXISTS = new ErrorCode(1_040_714_000, "销售出库单不存在");
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmStockTakingTaskLineStatusEnum.java
@@ -6,7 +6,6 @@ import lombok.Getter; @@ -6,7 +6,6 @@ import lombok.Getter;
6 6
7 import java.util.Arrays; 7 import java.util.Arrays;
8 8
9 -// TODO @AI:缺少注释;status + name 这种;  
10 /** 9 /**
11 * MES 盘点任务行状态枚举 10 * MES 盘点任务行状态枚举
12 */ 11 */
@@ -14,6 +13,7 @@ import java.util.Arrays; @@ -14,6 +13,7 @@ import java.util.Arrays;
14 @AllArgsConstructor 13 @AllArgsConstructor
15 public enum MesWmStockTakingTaskLineStatusEnum implements ArrayValuable<Integer> { 14 public enum MesWmStockTakingTaskLineStatusEnum implements ArrayValuable<Integer> {
16 15
  16 + // TODO @AI:UNCOUNTED 可以去掉!
17 UNCOUNTED(0, "未盘点"), 17 UNCOUNTED(0, "未盘点"),
18 NORMAL(1, "正常"), 18 NORMAL(1, "正常"),
19 GAIN(2, "盘盈"), 19 GAIN(2, "盘盈"),
@@ -22,7 +22,13 @@ public enum MesWmStockTakingTaskLineStatusEnum implements ArrayValuable&lt;Integer&gt; @@ -22,7 +22,13 @@ public enum MesWmStockTakingTaskLineStatusEnum implements ArrayValuable&lt;Integer&gt;
22 public static final Integer[] ARRAYS = Arrays.stream(values()) 22 public static final Integer[] ARRAYS = Arrays.stream(values())
23 .map(MesWmStockTakingTaskLineStatusEnum::getStatus).toArray(Integer[]::new); 23 .map(MesWmStockTakingTaskLineStatusEnum::getStatus).toArray(Integer[]::new);
24 24
  25 + /**
  26 + * 状态
  27 + */
25 private final Integer status; 28 private final Integer status;
  29 + /**
  30 + * 状态名称
  31 + */
26 private final String name; 32 private final String name;
27 33
28 @Override 34 @Override
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmStockTakingTaskStatusEnum.java
@@ -7,23 +7,50 @@ import lombok.Getter; @@ -7,23 +7,50 @@ import lombok.Getter;
7 7
8 import java.util.Arrays; 8 import java.util.Arrays;
9 9
10 -// TODO @AI:缺少注释;status + name 这种;  
11 /** 10 /**
12 * MES 盘点任务状态枚举 11 * MES 盘点任务状态枚举
  12 + *
  13 + * @author 芋道源码
13 */ 14 */
14 @Getter 15 @Getter
15 @AllArgsConstructor 16 @AllArgsConstructor
16 public enum MesWmStockTakingTaskStatusEnum implements ArrayValuable<Integer> { 17 public enum MesWmStockTakingTaskStatusEnum implements ArrayValuable<Integer> {
17 18
  19 + /**
  20 + * 草稿
  21 + *
  22 + * 对应方法:{@link cn.iocoder.yudao.module.mes.service.wm.stocktaking.task.MesWmStockTakingTaskService#createStockTakingTask}
  23 + */
18 PREPARE(MesOrderStatusConstants.PREPARE, "草稿"), 24 PREPARE(MesOrderStatusConstants.PREPARE, "草稿"),
  25 + /**
  26 + * 审批中
  27 + *
  28 + * 对应方法:{@link cn.iocoder.yudao.module.mes.service.wm.stocktaking.task.MesWmStockTakingTaskService#submitStockTakingTask}
  29 + */
19 APPROVING(MesOrderStatusConstants.APPROVING, "审批中"), 30 APPROVING(MesOrderStatusConstants.APPROVING, "审批中"),
  31 + /**
  32 + * 已完成
  33 + *
  34 + * 对应方法:{@link cn.iocoder.yudao.module.mes.service.wm.stocktaking.task.MesWmStockTakingTaskService#finishStockTakingTask}
  35 + */
20 FINISHED(MesOrderStatusConstants.FINISHED, "已完成"), 36 FINISHED(MesOrderStatusConstants.FINISHED, "已完成"),
  37 + /**
  38 + * 已取消
  39 + *
  40 + * 对应方法:{@link cn.iocoder.yudao.module.mes.service.wm.stocktaking.task.MesWmStockTakingTaskService#cancelStockTakingTask}
  41 + */
21 CANCELED(MesOrderStatusConstants.CANCELLED, "已取消"); 42 CANCELED(MesOrderStatusConstants.CANCELLED, "已取消");
22 43
23 public static final Integer[] ARRAYS = Arrays.stream(values()) 44 public static final Integer[] ARRAYS = Arrays.stream(values())
24 .map(MesWmStockTakingTaskStatusEnum::getStatus).toArray(Integer[]::new); 45 .map(MesWmStockTakingTaskStatusEnum::getStatus).toArray(Integer[]::new);
25 46
  47 + /**
  48 + * 状态
  49 + */
26 private final Integer status; 50 private final Integer status;
  51 + /**
  52 + * 状态名称
  53 + */
27 private final String name; 54 private final String name;
28 55
29 @Override 56 @Override
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java
1 package cn.iocoder.yudao.module.mes.service.wm.materialstock; 1 package cn.iocoder.yudao.module.mes.service.wm.materialstock;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 -import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO;  
5 import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockFreezeReqVO; 4 import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockFreezeReqVO;
  5 +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockListReqVO;
  6 +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO;
6 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; 7 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
7 import jakarta.validation.Valid; 8 import jakarta.validation.Valid;
8 9
@@ -11,7 +12,6 @@ import java.time.LocalDateTime; @@ -11,7 +12,6 @@ import java.time.LocalDateTime;
11 import java.util.Collection; 12 import java.util.Collection;
12 import java.util.List; 13 import java.util.List;
13 import java.util.Map; 14 import java.util.Map;
14 -import java.util.Set;  
15 15
16 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; 16 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
17 17
@@ -83,10 +83,13 @@ public interface MesWmMaterialStockService { @@ -83,10 +83,13 @@ public interface MesWmMaterialStockService {
83 */ 83 */
84 List<MesWmMaterialStockDO> getMaterialStockList(Collection<Long> ids); 84 List<MesWmMaterialStockDO> getMaterialStockList(Collection<Long> ids);
85 85
86 - // TODO @芋艿:不确定性;感觉就是一个查询接口,参数比较多;  
87 - List<MesWmMaterialStockDO> getMaterialStockListForStockTaking(Set<Long> warehouseIds, Set<Long> locationIds,  
88 - Set<Long> areaIds, Set<Long> itemIds,  
89 - Set<Long> batchIds); 86 + /**
  87 + * 获得物料库存列表(用于盘点等场景)
  88 + *
  89 + * @param reqVO 查询条件
  90 + * @return 物料库存列表
  91 + */
  92 + List<MesWmMaterialStockDO> getMaterialStockList(MesWmMaterialStockListReqVO reqVO);
90 93
91 default Map<Long, MesWmMaterialStockDO> getMaterialStockMap(Collection<Long> ids) { 94 default Map<Long, MesWmMaterialStockDO> getMaterialStockMap(Collection<Long> ids) {
92 return convertMap(getMaterialStockList(ids), MesWmMaterialStockDO::getId); 95 return convertMap(getMaterialStockList(ids), MesWmMaterialStockDO::getId);
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java
@@ -3,8 +3,9 @@ package cn.iocoder.yudao.module.mes.service.wm.materialstock; @@ -3,8 +3,9 @@ package cn.iocoder.yudao.module.mes.service.wm.materialstock;
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.collection.SetUtils; 5 import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
6 -import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO;  
7 import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockFreezeReqVO; 6 import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockFreezeReqVO;
  7 +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockListReqVO;
  8 +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO;
8 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; 9 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
9 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO; 10 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO;
10 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; 11 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
@@ -108,10 +109,8 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService @@ -108,10 +109,8 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService
108 } 109 }
109 110
110 @Override 111 @Override
111 - public List<MesWmMaterialStockDO> getMaterialStockListForStockTaking(Set<Long> warehouseIds, Set<Long> locationIds,  
112 - Set<Long> areaIds, Set<Long> itemIds,  
113 - Set<Long> batchIds) {  
114 - return materialStockMapper.selectListForStockTaking(warehouseIds, locationIds, areaIds, itemIds, batchIds); 112 + public List<MesWmMaterialStockDO> getMaterialStockList(MesWmMaterialStockListReqVO reqVO) {
  113 + return materialStockMapper.selectListForStockTaking(reqVO);
115 } 114 }
116 115
117 // TODO DONE @AI:increaseStock 方法命名合理,语义清晰 116 // TODO DONE @AI:increaseStock 方法命名合理,语义清晰
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/stocktaking/plan/MesWmStockTakingPlanService.java
@@ -74,6 +74,14 @@ public interface MesWmStockTakingPlanService { @@ -74,6 +74,14 @@ public interface MesWmStockTakingPlanService {
74 MesWmStockTakingPlanDO validateStockTakingPlanEditable(Long id); 74 MesWmStockTakingPlanDO validateStockTakingPlanEditable(Long id);
75 75
76 /** 76 /**
  77 + * 校验盘点方案存在且已启用
  78 + *
  79 + * @param id 盘点方案编号
  80 + * @return 盘点方案
  81 + */
  82 + MesWmStockTakingPlanDO validateStockTakingPlanEnabled(Long id);
  83 +
  84 + /**
77 * 获得盘点方案列表。 85 * 获得盘点方案列表。
78 * 86 *
79 * @param ids 盘点方案编号集合 87 * @param ids 盘点方案编号集合
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/stocktaking/plan/MesWmStockTakingPlanServiceImpl.java
@@ -135,6 +135,15 @@ public class MesWmStockTakingPlanServiceImpl implements MesWmStockTakingPlanServ @@ -135,6 +135,15 @@ public class MesWmStockTakingPlanServiceImpl implements MesWmStockTakingPlanServ
135 } 135 }
136 } 136 }
137 137
  138 + @Override
  139 + public MesWmStockTakingPlanDO validateStockTakingPlanEnabled(Long id) {
  140 + MesWmStockTakingPlanDO plan = validateStockTakingPlanExists(id);
  141 + if (!CommonStatusEnum.isEnable(plan.getStatus())) {
  142 + throw exception(WM_STOCK_TAKING_PLAN_NOT_ENABLED);
  143 + }
  144 + return plan;
  145 + }
  146 +
138 private MesWmStockTakingPlanDO validatePlanEditable(Long id) { 147 private MesWmStockTakingPlanDO validatePlanEditable(Long id) {
139 MesWmStockTakingPlanDO plan = validateStockTakingPlanExists(id); 148 MesWmStockTakingPlanDO plan = validateStockTakingPlanExists(id);
140 if (!CommonStatusEnum.isDisable(plan.getStatus())) { 149 if (!CommonStatusEnum.isDisable(plan.getStatus())) {
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/stocktaking/task/MesWmStockTakingTaskResultService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.stocktaking.task;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.mes.controller.admin.wm.stocktaking.task.vo.result.MesWmStockTakingTaskResultPageReqVO;
  5 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.stocktaking.task.MesWmStockTakingTaskResultDO;
  6 +
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * MES 盘点结果 Service 接口
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +public interface MesWmStockTakingTaskResultService {
  15 +
  16 + /**
  17 + * 分页查询盘点结果
  18 + *
  19 + * @param pageReqVO 分页查询条件
  20 + * @return 盘点结果分页结果
  21 + */
  22 + PageResult<MesWmStockTakingTaskResultDO> getStockTakingTaskResultPage(MesWmStockTakingTaskResultPageReqVO pageReqVO);
  23 +
  24 + /**
  25 + * 获得盘点结果
  26 + *
  27 + * @param id 盘点结果编号
  28 + * @return 盘点结果
  29 + */
  30 + MesWmStockTakingTaskResultDO getStockTakingTaskResult(Long id);
  31 +
  32 + /**
  33 + * 获得盘点结果列表
  34 + *
  35 + * @param taskId 盘点任务编号
  36 + * @return 盘点结果列表
  37 + */
  38 + List<MesWmStockTakingTaskResultDO> getStockTakingTaskResultList(Long taskId);
  39 +
  40 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/stocktaking/task/MesWmStockTakingTaskResultServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.stocktaking.task;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.mes.controller.admin.wm.stocktaking.task.vo.result.MesWmStockTakingTaskResultPageReqVO;
  5 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.stocktaking.task.MesWmStockTakingTaskResultDO;
  6 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.stocktaking.task.MesWmStockTakingTaskResultMapper;
  7 +import jakarta.annotation.Resource;
  8 +import org.springframework.stereotype.Service;
  9 +import org.springframework.validation.annotation.Validated;
  10 +
  11 +import java.util.List;
  12 +
  13 +/**
  14 + * MES 盘点结果 Service 实现类
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +@Service
  19 +@Validated
  20 +public class MesWmStockTakingTaskResultServiceImpl implements MesWmStockTakingTaskResultService {
  21 +
  22 + @Resource
  23 + private MesWmStockTakingTaskResultMapper stockTakingTaskResultMapper;
  24 +
  25 + @Override
  26 + public PageResult<MesWmStockTakingTaskResultDO> getStockTakingTaskResultPage(
  27 + MesWmStockTakingTaskResultPageReqVO pageReqVO) {
  28 + return stockTakingTaskResultMapper.selectPage(pageReqVO);
  29 + }
  30 +
  31 + @Override
  32 + public MesWmStockTakingTaskResultDO getStockTakingTaskResult(Long id) {
  33 + return stockTakingTaskResultMapper.selectById(id);
  34 + }
  35 +
  36 + @Override
  37 + public List<MesWmStockTakingTaskResultDO> getStockTakingTaskResultList(Long taskId) {
  38 + return stockTakingTaskResultMapper.selectListByTaskId(taskId);
  39 + }
  40 +
  41 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/stocktaking/task/MesWmStockTakingTaskService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.stocktaking.task;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.mes.controller.admin.wm.stocktaking.task.vo.line.MesWmStockTakingTaskLineBatchUpdateReqVO;
  5 +import cn.iocoder.yudao.module.mes.controller.admin.wm.stocktaking.task.vo.MesWmStockTakingTaskPageReqVO;
  6 +import cn.iocoder.yudao.module.mes.controller.admin.wm.stocktaking.task.vo.MesWmStockTakingTaskSaveReqVO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.stocktaking.task.MesWmStockTakingTaskDO;
  8 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.stocktaking.task.MesWmStockTakingTaskLineDO;
  9 +import jakarta.validation.Valid;
  10 +
  11 +import java.util.Collection;
  12 +import java.util.List;
  13 +import java.util.Map;
  14 +
  15 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  16 +
  17 +/**
  18 + * MES 盘点任务 Service 接口
  19 + *
  20 + * @author 芋道源码
  21 + */
  22 +public interface MesWmStockTakingTaskService {
  23 +
  24 + /**
  25 + * 创建盘点任务
  26 + *
  27 + * @param createReqVO 创建信息
  28 + * @return 盘点任务编号
  29 + */
  30 + Long createStockTakingTask(@Valid MesWmStockTakingTaskSaveReqVO createReqVO);
  31 +
  32 + /**
  33 + * 更新盘点任务
  34 + *
  35 + * @param updateReqVO 更新信息
  36 + */
  37 + void updateStockTakingTask(@Valid MesWmStockTakingTaskSaveReqVO updateReqVO);
  38 +
  39 + /**
  40 + * 删除盘点任务
  41 + *
  42 + * @param id 盘点任务编号
  43 + */
  44 + void deleteStockTakingTask(Long id);
  45 +
  46 + /**
  47 + * 提交盘点任务
  48 + *
  49 + * @param id 盘点任务编号
  50 + */
  51 + void submitStockTakingTask(Long id);
  52 +
  53 + /**
  54 + * 完成盘点任务
  55 + *
  56 + * @param id 盘点任务编号
  57 + */
  58 + void finishStockTakingTask(Long id);
  59 +
  60 + /**
  61 + * 取消盘点任务
  62 + *
  63 + * @param id 盘点任务编号
  64 + */
  65 + void cancelStockTakingTask(Long id);
  66 +
  67 + /**
  68 + * 批量更新盘点任务行
  69 + *
  70 + * @param updateReqVO 更新信息
  71 + */
  72 + void updateStockTakingTaskLines(@Valid MesWmStockTakingTaskLineBatchUpdateReqVO updateReqVO);
  73 +
  74 + /**
  75 + * 获得盘点任务
  76 + *
  77 + * @param id 盘点任务编号
  78 + * @return 盘点任务
  79 + */
  80 + MesWmStockTakingTaskDO getStockTakingTask(Long id);
  81 +
  82 + /**
  83 + * 校验盘点任务是否存在
  84 + *
  85 + * @param id 盘点任务编号
  86 + * @return 盘点任务
  87 + */
  88 + MesWmStockTakingTaskDO validateStockTakingTaskExists(Long id);
  89 +
  90 + /**
  91 + * 获得盘点任务列表
  92 + *
  93 + * @param ids 盘点任务编号集合
  94 + * @return 盘点任务列表
  95 + */
  96 + List<MesWmStockTakingTaskDO> getStockTakingTaskList(Collection<Long> ids);
  97 +
  98 + /**
  99 + * 获得盘点任务 Map
  100 + *
  101 + * @param ids 盘点任务编号集合
  102 + * @return 盘点任务 Map
  103 + */
  104 + default Map<Long, MesWmStockTakingTaskDO> getStockTakingTaskMap(Collection<Long> ids) {
  105 + return convertMap(getStockTakingTaskList(ids), MesWmStockTakingTaskDO::getId);
  106 + }
  107 +
  108 + /**
  109 + * 分页查询盘点任务
  110 + *
  111 + * @param pageReqVO 分页查询条件
  112 + * @return 盘点任务分页结果
  113 + */
  114 + PageResult<MesWmStockTakingTaskDO> getStockTakingTaskPage(MesWmStockTakingTaskPageReqVO pageReqVO);
  115 +
  116 + /**
  117 + * 获得盘点任务行列表
  118 + *
  119 + * @param taskId 盘点任务编号
  120 + * @return 盘点任务行列表
  121 + */
  122 + List<MesWmStockTakingTaskLineDO> getStockTakingTaskLineList(Long taskId);
  123 +
  124 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/stocktaking/task/MesWmStockTakingTaskServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.stocktaking.task;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.lang.Assert;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  7 +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockFreezeReqVO;
  8 +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockListReqVO;
  9 +import cn.iocoder.yudao.module.mes.controller.admin.wm.stocktaking.task.vo.MesWmStockTakingTaskPageReqVO;
  10 +import cn.iocoder.yudao.module.mes.controller.admin.wm.stocktaking.task.vo.MesWmStockTakingTaskSaveReqVO;
  11 +import cn.iocoder.yudao.module.mes.controller.admin.wm.stocktaking.task.vo.line.MesWmStockTakingTaskLineBatchUpdateReqVO;
  12 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
  13 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.stocktaking.plan.MesWmStockTakingPlanParamDO;
  14 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.stocktaking.task.MesWmStockTakingTaskDO;
  15 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.stocktaking.task.MesWmStockTakingTaskLineDO;
  16 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.stocktaking.task.MesWmStockTakingTaskResultDO;
  17 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.stocktaking.plan.MesWmStockTakingPlanMapper;
  18 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.stocktaking.plan.MesWmStockTakingPlanParamMapper;
  19 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.stocktaking.task.MesWmStockTakingTaskLineMapper;
  20 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.stocktaking.task.MesWmStockTakingTaskMapper;
  21 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.stocktaking.task.MesWmStockTakingTaskResultMapper;
  22 +import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockTakingPlanParamTypeEnum;
  23 +import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockTakingTaskLineStatusEnum;
  24 +import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockTakingTaskStatusEnum;
  25 +import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockTakingTypeEnum;
  26 +import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
  27 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  28 +import jakarta.annotation.Resource;
  29 +import org.springframework.stereotype.Service;
  30 +import org.springframework.transaction.annotation.Transactional;
  31 +import org.springframework.validation.annotation.Validated;
  32 +
  33 +import java.math.BigDecimal;
  34 +import java.time.LocalDateTime;
  35 +import java.util.*;
  36 +import java.util.stream.Collectors;
  37 +
  38 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  39 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  40 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
  41 +
  42 +/**
  43 + * MES 盘点任务 Service 实现类
  44 + *
  45 + * @author 芋道源码
  46 + */
  47 +@Service
  48 +@Validated
  49 +public class MesWmStockTakingTaskServiceImpl implements MesWmStockTakingTaskService {
  50 +
  51 + @Resource
  52 + private MesWmStockTakingTaskMapper stockTakingTaskMapper;
  53 + @Resource
  54 + private MesWmStockTakingTaskLineMapper stockTakingTaskLineMapper;
  55 + @Resource
  56 + private MesWmStockTakingTaskResultMapper stockTakingTaskResultMapper;
  57 + @Resource
  58 + private MesWmStockTakingPlanParamMapper stockTakingPlanParamMapper;
  59 + @Resource
  60 + private MesWmStockTakingPlanMapper stockTakingPlanMapper;
  61 + @Resource
  62 + private MesWmMaterialStockService materialStockService;
  63 + @Resource
  64 + private AdminUserApi adminUserApi;
  65 + @Resource
  66 + private cn.iocoder.yudao.module.mes.service.wm.stocktaking.plan.MesWmStockTakingPlanService stockTakingPlanService;
  67 +
  68 + @Override
  69 + @Transactional(rollbackFor = Exception.class)
  70 + public Long createStockTakingTask(MesWmStockTakingTaskSaveReqVO createReqVO) {
  71 + // 1.1 校验 code 唯一
  72 + validateTaskCodeUnique(null, createReqVO.getCode());
  73 + // 1.2 校验方案存在
  74 + adminUserApi.validateUser(createReqVO.getUserId());
  75 + // 1.3 校验方案可用
  76 + stockTakingPlanService.validateStockTakingPlanEnabled(createReqVO.getPlanId());
  77 +
  78 + // 2. 插入任务
  79 + MesWmStockTakingTaskDO task = BeanUtils.toBean(createReqVO, MesWmStockTakingTaskDO.class)
  80 + .setStatus(MesWmStockTakingTaskStatusEnum.PREPARE.getStatus());
  81 + stockTakingTaskMapper.insert(task);
  82 +
  83 + // 3. 根据方案生成盘点明细行
  84 + generateStockTakingLines(task);
  85 + return task.getId();
  86 + }
  87 +
  88 + @Override
  89 + @Transactional(rollbackFor = Exception.class)
  90 + public void updateStockTakingTask(MesWmStockTakingTaskSaveReqVO updateReqVO) {
  91 + // 1.1 校验任务存在且为草稿状态
  92 + validateTaskExistsAndPrepare(updateReqVO.getId());
  93 + // 1.2 校验 code 唯一
  94 + validateTaskCodeUnique(updateReqVO.getId(), updateReqVO.getCode());
  95 + // 1.3 校验方案存在
  96 + adminUserApi.validateUser(updateReqVO.getUserId());
  97 + // 1.4 校验方案可用
  98 + stockTakingPlanService.validateStockTakingPlanEnabled(updateReqVO.getPlanId());
  99 +
  100 + // 2. 更新任务
  101 + MesWmStockTakingTaskDO updateObj = BeanUtils.toBean(updateReqVO, MesWmStockTakingTaskDO.class);
  102 + stockTakingTaskMapper.updateById(updateObj);
  103 +
  104 + // 3. 删除老的明细,重新生成新的
  105 + stockTakingTaskLineMapper.deleteByTaskId(updateReqVO.getId());
  106 + generateStockTakingLines(updateObj);
  107 + }
  108 +
  109 + @Override
  110 + @Transactional(rollbackFor = Exception.class)
  111 + public void deleteStockTakingTask(Long id) {
  112 + // 1. 校验任务存在且为草稿状态
  113 + validateTaskExistsAndPrepare(id);
  114 +
  115 + // 2. 删除任务和明细
  116 + stockTakingTaskResultMapper.deleteByTaskId(id);
  117 + stockTakingTaskLineMapper.deleteByTaskId(id);
  118 + stockTakingTaskMapper.deleteById(id);
  119 + }
  120 +
  121 + @Override
  122 + @Transactional(rollbackFor = Exception.class)
  123 + public void submitStockTakingTask(Long id) {
  124 + // 1.1 校验任务存在且为草稿状态
  125 + MesWmStockTakingTaskDO task = validateTaskExistsAndPrepare(id);
  126 + // 1.2 检查要盘点的内容
  127 + List<MesWmStockTakingTaskLineDO> lines = stockTakingTaskLineMapper.selectListByTaskId(id);
  128 + if (CollUtil.isEmpty(lines)) {
  129 + throw exception(WM_STOCK_TAKING_TASK_NO_LINE);
  130 + }
  131 +
  132 + // 2. 更新任务状态为审批中
  133 + stockTakingTaskMapper.updateById(new MesWmStockTakingTaskDO().setId(id)
  134 + .setStatus(MesWmStockTakingTaskStatusEnum.APPROVING.getStatus()));
  135 +
  136 + // 3. 根据冻结标识,对物资进行冻结
  137 + // TODO @芋艿:后续跟进下!
  138 + if (Boolean.TRUE.equals(task.getFrozenFlag())) {
  139 + for (MesWmStockTakingTaskLineDO line : lines) {
  140 + if (line.getMaterialStockId() != null) {
  141 + updateFrozen(line.getMaterialStockId(), true);
  142 + }
  143 + }
  144 + }
  145 + }
  146 +
  147 + /**
  148 + * 根据盘点方案生成盘点明细行
  149 + *
  150 + * @param task 盘点任务
  151 + */
  152 + private void generateStockTakingLines(MesWmStockTakingTaskDO task) {
  153 + // 1.1 构建查询条件(包含动态盘点时间校验)
  154 + MesWmMaterialStockListReqVO reqVO = buildStockQueryReqVO(task);
  155 + // 1.2 查询物料库存
  156 + List<MesWmMaterialStockDO> stocks = materialStockService.getMaterialStockList(reqVO);
  157 + if (CollUtil.isEmpty(stocks)) {
  158 + throw exception(WM_STOCK_TAKING_TASK_NO_STOCK);
  159 + }
  160 +
  161 + // 2. 批量生成明细行
  162 + // TODO DONE @AI:把 stocks 作为参数,传递给 stocktakingTaskLineService,更收敛;(当前直接插入更简洁)
  163 + List<MesWmStockTakingTaskLineDO> lines = new ArrayList<>(stocks.size());
  164 + for (MesWmMaterialStockDO stock : stocks) {
  165 + MesWmStockTakingTaskLineDO line = MesWmStockTakingTaskLineDO.builder()
  166 + .taskId(task.getId())
  167 + .materialStockId(stock.getId())
  168 + .itemId(stock.getItemId())
  169 + .batchId(stock.getBatchId())
  170 + .quantity(defaultQuantity(stock.getQuantityOnhand()))
  171 + .warehouseId(stock.getWarehouseId())
  172 + .locationId(stock.getLocationId())
  173 + .areaId(stock.getAreaId())
  174 + .status(MesWmStockTakingTaskLineStatusEnum.LOSS.getStatus())
  175 + .build();
  176 + lines.add(line);
  177 + }
  178 + stockTakingTaskLineMapper.insertBatch(lines);
  179 + }
  180 +
  181 + /**
  182 + * 构建库存查询条件
  183 + *
  184 + * @param task 盘点任务
  185 + * @return 查询条件 VO
  186 + */
  187 + private MesWmMaterialStockListReqVO buildStockQueryReqVO(MesWmStockTakingTaskDO task) {
  188 + // 1. 从方案参数中提取过滤条件
  189 + List<MesWmStockTakingPlanParamDO> params = stockTakingPlanParamMapper.selectListByPlanId(task.getPlanId());
  190 + Assert.notEmpty(params, "盘点方案参数不能为空");
  191 +
  192 + // 2.1 拼接通用参数
  193 + MesWmMaterialStockListReqVO reqVO = new MesWmMaterialStockListReqVO()
  194 + .setWarehouseId(extractMesWmStockTakingPlanParamValueId(params, MesWmStockTakingPlanParamTypeEnum.WAREHOUSE.getType()))
  195 + .setLocationId(extractMesWmStockTakingPlanParamValueId(params, MesWmStockTakingPlanParamTypeEnum.LOCATION.getType()))
  196 + .setAreaId(extractMesWmStockTakingPlanParamValueId(params, MesWmStockTakingPlanParamTypeEnum.AREA.getType()))
  197 + .setItemId(extractMesWmStockTakingPlanParamValueId(params, MesWmStockTakingPlanParamTypeEnum.ITEM.getType()))
  198 + .setBatchId(extractMesWmStockTakingPlanParamValueId(params, MesWmStockTakingPlanParamTypeEnum.BATCH.getType()));
  199 + // 2.2 对于动态盘点,设置时间参数并校验
  200 + if (MesWmStockTakingTypeEnum.DYNAMIC.getType().equals(task.getType())) {
  201 + Assert.notNull(task.getStartTime(), "动态盘点开始时间不能为空");
  202 + Assert.notNull(task.getEndTime(), "动态盘点结束时间不能为空");
  203 + reqVO.setStartTime(task.getStartTime()).setEndTime(task.getEndTime());
  204 + }
  205 + return reqVO;
  206 + }
  207 +
  208 + /**
  209 + * 从参数列表中提取第一个匹配类型的参数 ID
  210 + *
  211 + * @param params 参数列表
  212 + * @param type 参数类型
  213 + * @return 参数 ID(如果有多个,取第一个)
  214 + */
  215 + private Long extractMesWmStockTakingPlanParamValueId(List<MesWmStockTakingPlanParamDO> params, Integer type) {
  216 + MesWmStockTakingPlanParamDO param = CollUtil.findOne(params,
  217 + item -> Objects.equals(item.getType(), type) && item.getValueId() != null);
  218 + return param != null ? param.getValueId() : null;
  219 + }
  220 +
  221 + @Override
  222 + @Transactional(rollbackFor = Exception.class)
  223 + public void finishStockTakingTask(Long id) {
  224 + // TODO @AI:补全下注释;
  225 + // TODO @AI:notEquals;
  226 + MesWmStockTakingTaskDO task = validateTaskExists(id);
  227 + if (!MesWmStockTakingTaskStatusEnum.APPROVING.getStatus().equals(task.getStatus())) {
  228 + throw exception(WM_STOCK_TAKING_TASK_NOT_APPROVING);
  229 + }
  230 + List<MesWmStockTakingTaskLineDO> lines = stockTakingTaskLineMapper.selectListByTaskId(id);
  231 + if (CollUtil.isEmpty(lines)) {
  232 + throw exception(WM_STOCK_TAKING_TASK_NO_LINE);
  233 + }
  234 +
  235 + stockTakingTaskResultMapper.deleteByTaskId(id);
  236 + for (MesWmStockTakingTaskLineDO line : lines) {
  237 + if (MesWmStockTakingTaskLineStatusEnum.NORMAL.getStatus().equals(line.getStatus())
  238 + || MesWmStockTakingTaskLineStatusEnum.UNCOUNTED.getStatus().equals(line.getStatus())) {
  239 + continue;
  240 + }
  241 + stockTakingTaskResultMapper.insert(MesWmStockTakingTaskResultDO.builder()
  242 + .taskId(id)
  243 + .lineId(line.getId())
  244 + .materialStockId(line.getMaterialStockId())
  245 + .itemId(line.getItemId())
  246 + .batchId(line.getBatchId())
  247 + .batchCode(line.getBatchCode())
  248 + .warehouseId(line.getWarehouseId())
  249 + .locationId(line.getLocationId())
  250 + .areaId(line.getAreaId())
  251 + .quantity(differenceQuantity(line))
  252 + .remark(line.getRemark())
  253 + .build());
  254 + }
  255 +
  256 + task.setEndTime(LocalDateTime.now());
  257 + task.setStatus(MesWmStockTakingTaskStatusEnum.FINISHED.getStatus());
  258 + stockTakingTaskMapper.updateById(task);
  259 + if (Boolean.TRUE.equals(task.getFrozenFlag())) {
  260 + unfreezeTaskStocks(lines);
  261 + }
  262 + }
  263 +
  264 + @Override
  265 + @Transactional(rollbackFor = Exception.class)
  266 + public void cancelStockTakingTask(Long id) {
  267 + MesWmStockTakingTaskDO task = validateTaskExists(id);
  268 + if (MesWmStockTakingTaskStatusEnum.FINISHED.getStatus().equals(task.getStatus())
  269 + || MesWmStockTakingTaskStatusEnum.CANCELED.getStatus().equals(task.getStatus())) {
  270 + throw exception(WM_STOCK_TAKING_TASK_CANNOT_CANCEL);
  271 + }
  272 + task.setStatus(MesWmStockTakingTaskStatusEnum.CANCELED.getStatus());
  273 + stockTakingTaskMapper.updateById(task);
  274 + if (Boolean.TRUE.equals(task.getFrozenFlag())) {
  275 + unfreezeTaskStocks(stockTakingTaskLineMapper.selectListByTaskId(id));
  276 + }
  277 + }
  278 +
  279 + @Override
  280 + @Transactional(rollbackFor = Exception.class)
  281 + public void updateStockTakingTaskLines(MesWmStockTakingTaskLineBatchUpdateReqVO updateReqVO) {
  282 + MesWmStockTakingTaskDO task = validateTaskExists(updateReqVO.getTaskId());
  283 + if (!MesWmStockTakingTaskStatusEnum.APPROVING.getStatus().equals(task.getStatus())) {
  284 + throw exception(WM_STOCK_TAKING_TASK_NOT_APPROVING);
  285 + }
  286 +
  287 + Set<Long> lineIds = convertSet(updateReqVO.getItems(), MesWmStockTakingTaskLineBatchUpdateReqVO.Item::getId);
  288 + List<MesWmStockTakingTaskLineDO> lines = stockTakingTaskLineMapper.selectListByTaskIdAndIds(updateReqVO.getTaskId(), lineIds);
  289 + if (lines.size() != updateReqVO.getItems().size()) {
  290 + throw exception(WM_STOCK_TAKING_TASK_LINE_NOT_EXISTS);
  291 + }
  292 + Map<Long, MesWmStockTakingTaskLineDO> lineMap = lines.stream()
  293 + .collect(Collectors.toMap(MesWmStockTakingTaskLineDO::getId, item -> item));
  294 + for (MesWmStockTakingTaskLineBatchUpdateReqVO.Item item : updateReqVO.getItems()) {
  295 + MesWmStockTakingTaskLineDO line = lineMap.get(item.getId());
  296 + line.setTakingQuantity(item.getTakingQuantity());
  297 + line.setRemark(item.getRemark());
  298 + line.setStatus(resolveLineStatus(line.getQuantity(), item.getTakingQuantity()));
  299 + stockTakingTaskLineMapper.updateById(line);
  300 + }
  301 + }
  302 +
  303 + @Override
  304 + public MesWmStockTakingTaskDO getStockTakingTask(Long id) {
  305 + return stockTakingTaskMapper.selectById(id);
  306 + }
  307 +
  308 + @Override
  309 + public MesWmStockTakingTaskDO validateStockTakingTaskExists(Long id) {
  310 + return validateTaskExists(id);
  311 + }
  312 +
  313 + @Override
  314 + public List<MesWmStockTakingTaskDO> getStockTakingTaskList(Collection<Long> ids) {
  315 + if (CollUtil.isEmpty(ids)) {
  316 + return Collections.emptyList();
  317 + }
  318 + return stockTakingTaskMapper.selectByIds(ids);
  319 + }
  320 +
  321 + @Override
  322 + public PageResult<MesWmStockTakingTaskDO> getStockTakingTaskPage(MesWmStockTakingTaskPageReqVO pageReqVO) {
  323 + return stockTakingTaskMapper.selectPage(pageReqVO);
  324 + }
  325 +
  326 + @Override
  327 + public List<MesWmStockTakingTaskLineDO> getStockTakingTaskLineList(Long taskId) {
  328 + return stockTakingTaskLineMapper.selectListByTaskId(taskId);
  329 + }
  330 +
  331 + private void updateFrozen(Long materialStockId, boolean frozen) {
  332 + MesWmMaterialStockFreezeReqVO reqVO = new MesWmMaterialStockFreezeReqVO();
  333 + reqVO.setId(materialStockId);
  334 + reqVO.setFrozen(frozen);
  335 + materialStockService.updateMaterialStockFrozen(reqVO);
  336 + }
  337 +
  338 + private void unfreezeTaskStocks(List<MesWmStockTakingTaskLineDO> lines) {
  339 + if (CollUtil.isEmpty(lines)) {
  340 + return;
  341 + }
  342 + for (MesWmStockTakingTaskLineDO line : lines) {
  343 + if (line.getMaterialStockId() != null) {
  344 + updateFrozen(line.getMaterialStockId(), false);
  345 + }
  346 + }
  347 + }
  348 +
  349 + private Integer resolveLineStatus(BigDecimal quantity, BigDecimal takingQuantity) {
  350 + if (takingQuantity == null) {
  351 + return MesWmStockTakingTaskLineStatusEnum.UNCOUNTED.getStatus();
  352 + }
  353 + int compare = takingQuantity.compareTo(defaultQuantity(quantity));
  354 + if (compare == 0) {
  355 + return MesWmStockTakingTaskLineStatusEnum.NORMAL.getStatus();
  356 + }
  357 + return compare > 0 ? MesWmStockTakingTaskLineStatusEnum.GAIN.getStatus()
  358 + : MesWmStockTakingTaskLineStatusEnum.LOSS.getStatus();
  359 + }
  360 +
  361 + private BigDecimal differenceQuantity(MesWmStockTakingTaskLineDO line) {
  362 + return defaultQuantity(line.getTakingQuantity()).subtract(defaultQuantity(line.getQuantity()));
  363 + }
  364 +
  365 + private BigDecimal defaultQuantity(BigDecimal quantity) {
  366 + return quantity == null ? BigDecimal.ZERO : quantity;
  367 + }
  368 +
  369 + private void validateTaskCodeUnique(Long id, String code) {
  370 + MesWmStockTakingTaskDO task = stockTakingTaskMapper.selectByCode(code);
  371 + if (task == null) {
  372 + return;
  373 + }
  374 + if (id == null || !Objects.equals(task.getId(), id)) {
  375 + throw exception(WM_STOCK_TAKING_TASK_CODE_DUPLICATE);
  376 + }
  377 + }
  378 +
  379 + private void validatePlanExists(Long id) {
  380 + if (stockTakingPlanMapper.selectById(id) == null) {
  381 + throw exception(WM_STOCK_TAKING_PLAN_NOT_EXISTS);
  382 + }
  383 + }
  384 +
  385 + private MesWmStockTakingTaskDO validateTaskExists(Long id) {
  386 + MesWmStockTakingTaskDO task = stockTakingTaskMapper.selectById(id);
  387 + if (task == null) {
  388 + throw exception(WM_STOCK_TAKING_TASK_NOT_EXISTS);
  389 + }
  390 + return task;
  391 + }
  392 +
  393 + private MesWmStockTakingTaskDO validateTaskExistsAndPrepare(Long id) {
  394 + MesWmStockTakingTaskDO task = validateTaskExists(id);
  395 + if (!MesWmStockTakingTaskStatusEnum.PREPARE.getStatus().equals(task.getStatus())) {
  396 + throw exception(WM_STOCK_TAKING_TASK_NOT_PREPARE);
  397 + }
  398 + return task;
  399 + }
  400 +
  401 +}