mirror of
http://192.168.1.205:9980/cf_devdept2/cf_imes_server.git
synced 2026-08-14 13:42:07 +08:00
新增贴皮优化结果保存接口
This commit is contained in:
+5
@@ -231,6 +231,11 @@ public class ErrorCodeConstants {
|
|||||||
public static final ErrorCode VENEER_OPTIMIZE_GOODS_EMPTY = new ErrorCode(1_003_009_062, "veneer.optimize.goods.empty");
|
public static final ErrorCode VENEER_OPTIMIZE_GOODS_EMPTY = new ErrorCode(1_003_009_062, "veneer.optimize.goods.empty");
|
||||||
public static final ErrorCode VENEER_OPTIMIZE_ORDERS_EMPTY = new ErrorCode(1_003_009_063, "veneer.optimize.orders.empty");
|
public static final ErrorCode VENEER_OPTIMIZE_ORDERS_EMPTY = new ErrorCode(1_003_009_063, "veneer.optimize.orders.empty");
|
||||||
public static final ErrorCode VENEER_OPTIMIZE_PLATE_MODEL_EMPTY = new ErrorCode(1_003_009_064, "veneer.optimize.plate.model.empty");
|
public static final ErrorCode VENEER_OPTIMIZE_PLATE_MODEL_EMPTY = new ErrorCode(1_003_009_064, "veneer.optimize.plate.model.empty");
|
||||||
|
public static final ErrorCode VENEER_OPTIMIZE_RESULT_REQUIRED = new ErrorCode(1_003_009_065, "veneer.optimize.result.required");
|
||||||
|
public static final ErrorCode VENEER_OPTIMIZE_PROCESS_STATUS_INVALID = new ErrorCode(1_003_009_066, "veneer.optimize.process.status.invalid");
|
||||||
|
public static final ErrorCode VENEER_OPTIMIZE_VENEER_NO_REQUIRED = new ErrorCode(1_003_009_067, "veneer.optimize.veneer.no.required");
|
||||||
|
public static final ErrorCode VENEER_OPTIMIZE_MATERIAL_MULTIPLE = new ErrorCode(1_003_009_068, "veneer.optimize.material.multiple");
|
||||||
|
public static final ErrorCode VENEER_OPTIMIZE_RESULT_STATUS_CHANGED = new ErrorCode(1_003_009_069, "veneer.optimize.result.status.changed");
|
||||||
|
|
||||||
//=========== 部件管理 1-003-010-000 ============
|
//=========== 部件管理 1-003-010-000 ============
|
||||||
public static final ErrorCode ORDER_COMPONENT_NOT_EXIST = new ErrorCode(1_003_010_000, "order.component.not.exist");
|
public static final ErrorCode ORDER_COMPONENT_NOT_EXIST = new ErrorCode(1_003_010_000, "order.component.not.exist");
|
||||||
|
|||||||
+16
@@ -3,6 +3,7 @@ package com.cf.imes.module.executor.controller.admin.veneer;
|
|||||||
import com.cf.imes.framework.common.pojo.CommonResult;
|
import com.cf.imes.framework.common.pojo.CommonResult;
|
||||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerOptimizePlanLockReqVO;
|
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerOptimizePlanLockReqVO;
|
||||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerOrderSource;
|
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerOrderSource;
|
||||||
|
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerOptimizationResultsReqVO;
|
||||||
import com.cf.imes.module.executor.service.veneer.VeneerOptimizePlanService;
|
import com.cf.imes.module.executor.service.veneer.VeneerOptimizePlanService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
@@ -79,4 +80,19 @@ public class VeneerOptimizePlanController {
|
|||||||
veneerOptimizePlanService.releasePlanLock(req);
|
veneerOptimizePlanService.releasePlanLock(req);
|
||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存组件回传的贴皮优化、开始开料或结束开料结果。
|
||||||
|
*
|
||||||
|
* @param req 贴皮排单及组件流程结果
|
||||||
|
* @return 是否保存成功
|
||||||
|
*/
|
||||||
|
@PostMapping("/optimize")
|
||||||
|
@Operation(summary = "保存贴皮优化及开料结果")
|
||||||
|
@PreAuthorize("@ss.hasPermission('veneerPlan:optimize')")
|
||||||
|
public CommonResult<Boolean> saveVeneerOptimizationResults(
|
||||||
|
@Valid @RequestBody VeneerOptimizationResultsReqVO req) {
|
||||||
|
veneerOptimizePlanService.saveOptimizationResults(req);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
package com.cf.imes.module.executor.controller.admin.veneer.vo;
|
||||||
|
|
||||||
|
import com.cf.imes.module.executor.controller.admin.plan.component.FlowSessionSavedContent;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 贴皮优化及开料结果保存参数。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "管理后台 - 贴皮优化及开料结果保存 Request VO")
|
||||||
|
public class VeneerOptimizationResultsReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "贴皮排单ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotNull(message = "{veneer.plan.id.required}")
|
||||||
|
private Long planId;
|
||||||
|
|
||||||
|
@Valid
|
||||||
|
@Schema(description = "组件优化流程保存结果", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotNull(message = "{veneer.optimize.result.required}")
|
||||||
|
private FlowSessionSavedContent flowSessionSavedContent;
|
||||||
|
}
|
||||||
+21
@@ -48,6 +48,27 @@ public class VeneerPlanPageRespVO {
|
|||||||
@Schema(description = "贴皮总面积,单位:平方米")
|
@Schema(description = "贴皮总面积,单位:平方米")
|
||||||
private BigDecimal veneerArea;
|
private BigDecimal veneerArea;
|
||||||
|
|
||||||
|
@Schema(description = "实际优化贴皮商品编号")
|
||||||
|
private String optimizeGoodsId;
|
||||||
|
|
||||||
|
@Schema(description = "最近优化时间")
|
||||||
|
private LocalDateTime optimizeTime;
|
||||||
|
|
||||||
|
@Schema(description = "已优化板件贴皮数量")
|
||||||
|
private Integer optimizedPlateNum;
|
||||||
|
|
||||||
|
@Schema(description = "未优化板件贴皮数量")
|
||||||
|
private Integer unOptimizedPlateNum;
|
||||||
|
|
||||||
|
@Schema(description = "已排贴皮库原料张数")
|
||||||
|
private Integer scheduledBoardNum;
|
||||||
|
|
||||||
|
@Schema(description = "已开料贴皮库原料张数")
|
||||||
|
private Integer cuttedBoardNum;
|
||||||
|
|
||||||
|
@Schema(description = "已切板件贴皮数量")
|
||||||
|
private Integer cuttedPlateNum;
|
||||||
|
|
||||||
@Schema(description = "创建时间")
|
@Schema(description = "创建时间")
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
|||||||
+18
@@ -76,6 +76,24 @@ public class OrderVeneerPlanDO extends BaseDO {
|
|||||||
*/
|
*/
|
||||||
private Long sourceVeneerId;
|
private Long sourceVeneerId;
|
||||||
|
|
||||||
|
/** 实际优化贴皮商品编号。 */
|
||||||
|
private String optimizeGoodsId;
|
||||||
|
|
||||||
|
/** 最近一次优化时间。 */
|
||||||
|
private LocalDateTime optimizeTime;
|
||||||
|
|
||||||
|
/** 已优化板件贴皮数量,A/B面分别计数。 */
|
||||||
|
private Integer optimizedPlateNum;
|
||||||
|
|
||||||
|
/** 已排贴皮库原料张数。 */
|
||||||
|
private Integer scheduledBoardNum;
|
||||||
|
|
||||||
|
/** 已开料贴皮库原料张数。 */
|
||||||
|
private Integer cuttedBoardNum;
|
||||||
|
|
||||||
|
/** 已切板件贴皮数量,A/B面分别计数。 */
|
||||||
|
private Integer cuttedPlateNum;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 排单关联的订单主键ID集合,使用 JSON 数组格式存储。
|
* 排单关联的订单主键ID集合,使用 JSON 数组格式存储。
|
||||||
*/
|
*/
|
||||||
|
|||||||
+41
-1
@@ -23,6 +23,14 @@ public interface VeneerOptimizePlanMapper extends BaseMapperX<OrderVeneerPlanDO>
|
|||||||
*/
|
*/
|
||||||
List<VeneerOptimizeGoodsRespVO> selectGoodsList(@Param("planId") Long planId);
|
List<VeneerOptimizeGoodsRespVO> selectGoodsList(@Param("planId") Long planId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询排单涉及的全部订单ID。
|
||||||
|
*
|
||||||
|
* @param planId 贴皮排单ID
|
||||||
|
* @return 订单ID列表
|
||||||
|
*/
|
||||||
|
List<Long> selectOrderIds(@Param("planId") Long planId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询排单贴皮及来源板件完整数据。
|
* 查询排单贴皮及来源板件完整数据。
|
||||||
* 同一贴皮可能因来源板件属于多个加工组返回多条记录,由 Service 层合并。
|
* 同一贴皮可能因来源板件属于多个加工组返回多条记录,由 Service 层合并。
|
||||||
@@ -30,7 +38,8 @@ public interface VeneerOptimizePlanMapper extends BaseMapperX<OrderVeneerPlanDO>
|
|||||||
* @param planId 贴皮排单ID
|
* @param planId 贴皮排单ID
|
||||||
* @return 贴皮及来源板件原始列表
|
* @return 贴皮及来源板件原始列表
|
||||||
*/
|
*/
|
||||||
List<VeneerOptimizePlateRespVO> selectPlateList(@Param("planId") Long planId);
|
List<VeneerOptimizePlateRespVO> selectPlateList(@Param("planId") Long planId,
|
||||||
|
@Param("optimized") boolean optimized);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询排单内已标记待删除的贴皮编号。
|
* 查询排单内已标记待删除的贴皮编号。
|
||||||
@@ -39,4 +48,35 @@ public interface VeneerOptimizePlanMapper extends BaseMapperX<OrderVeneerPlanDO>
|
|||||||
* @return 待删除贴皮编号列表
|
* @return 待删除贴皮编号列表
|
||||||
*/
|
*/
|
||||||
List<String> selectPendingDeleteVeneerNos(@Param("planId") Long planId);
|
List<String> selectPendingDeleteVeneerNos(@Param("planId") Long planId);
|
||||||
|
|
||||||
|
/** 重置当前排单中非待删除贴皮的已优化状态。 */
|
||||||
|
int resetOptimizedVeneerStatus(@Param("planId") Long planId,
|
||||||
|
@Param("optimizedStatus") Integer optimizedStatus,
|
||||||
|
@Param("notOptimizedStatus") Integer notOptimizedStatus);
|
||||||
|
|
||||||
|
/** 按贴皮短号批量更新加工状态。 */
|
||||||
|
int updateVeneerProcessStatus(@Param("planId") Long planId,
|
||||||
|
@Param("veneerNos") List<String> veneerNos,
|
||||||
|
@Param("sourceStatuses") List<Integer> sourceStatuses,
|
||||||
|
@Param("targetStatus") Integer targetStatus);
|
||||||
|
|
||||||
|
/** 保存优化排版统计并递增排单版本。 */
|
||||||
|
int updatePlanOptimized(@Param("planId") Long planId,
|
||||||
|
@Param("version") Integer version,
|
||||||
|
@Param("status") Integer status,
|
||||||
|
@Param("optimizeGoodsId") String optimizeGoodsId,
|
||||||
|
@Param("optimizedPlateNum") Integer optimizedPlateNum,
|
||||||
|
@Param("scheduledBoardNum") Integer scheduledBoardNum);
|
||||||
|
|
||||||
|
/** 更新排单为开料中并递增版本。 */
|
||||||
|
int updatePlanCutting(@Param("planId") Long planId,
|
||||||
|
@Param("version") Integer version,
|
||||||
|
@Param("status") Integer status);
|
||||||
|
|
||||||
|
/** 更新排单开料完成统计并递增版本。 */
|
||||||
|
int updatePlanCut(@Param("planId") Long planId,
|
||||||
|
@Param("version") Integer version,
|
||||||
|
@Param("status") Integer status,
|
||||||
|
@Param("cuttedBoardNum") Integer cuttedBoardNum,
|
||||||
|
@Param("cuttedPlateNum") Integer cuttedPlateNum);
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -2,6 +2,7 @@ package com.cf.imes.module.executor.service.veneer;
|
|||||||
|
|
||||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerOptimizePlanLockReqVO;
|
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerOptimizePlanLockReqVO;
|
||||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerOrderSource;
|
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerOrderSource;
|
||||||
|
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerOptimizationResultsReqVO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 贴皮排单优化 Service。
|
* 贴皮排单优化 Service。
|
||||||
@@ -30,4 +31,11 @@ public interface VeneerOptimizePlanService {
|
|||||||
* @param req 排单ID及锁持有者标识
|
* @param req 排单ID及锁持有者标识
|
||||||
*/
|
*/
|
||||||
void releasePlanLock(VeneerOptimizePlanLockReqVO req);
|
void releasePlanLock(VeneerOptimizePlanLockReqVO req);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存组件回传的贴皮优化及开料结果。
|
||||||
|
*
|
||||||
|
* @param req 贴皮排单及组件流程结果
|
||||||
|
*/
|
||||||
|
void saveOptimizationResults(VeneerOptimizationResultsReqVO req);
|
||||||
}
|
}
|
||||||
|
|||||||
+174
-13
@@ -9,15 +9,21 @@ import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerOptimizePlan
|
|||||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerOptimizePlateRespVO;
|
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerOptimizePlateRespVO;
|
||||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerOrderModelRespVO;
|
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerOrderModelRespVO;
|
||||||
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerOrderSource;
|
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerOrderSource;
|
||||||
|
import com.cf.imes.module.executor.controller.admin.veneer.vo.VeneerOptimizationResultsReqVO;
|
||||||
|
import com.cf.imes.module.executor.controller.admin.plan.component.BoardLayoutResultSummary;
|
||||||
import com.cf.imes.module.executor.dal.dataobject.order.OrderDO;
|
import com.cf.imes.module.executor.dal.dataobject.order.OrderDO;
|
||||||
import com.cf.imes.module.executor.dal.dataobject.veneer.OrderVeneerPlanDO;
|
import com.cf.imes.module.executor.dal.dataobject.veneer.OrderVeneerPlanDO;
|
||||||
import com.cf.imes.module.executor.dal.mysql.order.OrderMapper;
|
import com.cf.imes.module.executor.dal.mysql.order.OrderMapper;
|
||||||
import com.cf.imes.module.executor.dal.mysql.veneer.VeneerOptimizePlanMapper;
|
import com.cf.imes.module.executor.dal.mysql.veneer.VeneerOptimizePlanMapper;
|
||||||
|
import com.cf.imes.module.executor.enums.VeneerPlanStatusEnum;
|
||||||
|
import com.cf.imes.module.executor.enums.VeneerPlateProcessStatusEnum;
|
||||||
|
import com.cf.imes.module.executor.enums.plan.FlowProcessStatus;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -28,6 +34,7 @@ import java.util.LinkedHashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import static com.cf.imes.framework.redis.constants.RedisKeyConstants.ORDER_VENEER_PLAN_OPTIMIZE_KEY;
|
import static com.cf.imes.framework.redis.constants.RedisKeyConstants.ORDER_VENEER_PLAN_OPTIMIZE_KEY;
|
||||||
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_OPTIMIZE_GOODS_EMPTY;
|
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_OPTIMIZE_GOODS_EMPTY;
|
||||||
@@ -36,6 +43,11 @@ import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_OPTIMI
|
|||||||
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_OPTIMIZE_PLAN_LOCKED;
|
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_OPTIMIZE_PLAN_LOCKED;
|
||||||
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_OPTIMIZE_PLAN_NOT_EXIST;
|
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_OPTIMIZE_PLAN_NOT_EXIST;
|
||||||
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_OPTIMIZE_PLATE_EMPTY;
|
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_OPTIMIZE_PLATE_EMPTY;
|
||||||
|
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_OPTIMIZE_MATERIAL_MULTIPLE;
|
||||||
|
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_OPTIMIZE_PROCESS_STATUS_INVALID;
|
||||||
|
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_OPTIMIZE_RESULT_REQUIRED;
|
||||||
|
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_OPTIMIZE_RESULT_STATUS_CHANGED;
|
||||||
|
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.VENEER_OPTIMIZE_VENEER_NO_REQUIRED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 贴皮排单优化 Service 实现。
|
* 贴皮排单优化 Service 实现。
|
||||||
@@ -50,6 +62,9 @@ public class VeneerOptimizePlanServiceImpl implements VeneerOptimizePlanService
|
|||||||
/** 订单批量查询大小,避免生成过长的 IN 条件。 */
|
/** 订单批量查询大小,避免生成过长的 IN 条件。 */
|
||||||
private static final int ORDER_QUERY_BATCH_SIZE = 100;
|
private static final int ORDER_QUERY_BATCH_SIZE = 100;
|
||||||
|
|
||||||
|
/** 贴皮短号批量更新大小,避免生成过长的 IN 条件。 */
|
||||||
|
private static final int VENEER_UPDATE_BATCH_SIZE = 1000;
|
||||||
|
|
||||||
/** 原子校验锁归属并删除,避免误删其他请求重新获取的锁。 */
|
/** 原子校验锁归属并删除,避免误删其他请求重新获取的锁。 */
|
||||||
private static final DefaultRedisScript<Long> RELEASE_PLAN_LOCK_SCRIPT;
|
private static final DefaultRedisScript<Long> RELEASE_PLAN_LOCK_SCRIPT;
|
||||||
|
|
||||||
@@ -78,33 +93,37 @@ public class VeneerOptimizePlanServiceImpl implements VeneerOptimizePlanService
|
|||||||
VeneerOptimizePlanLockReqVO lockReq = new VeneerOptimizePlanLockReqVO();
|
VeneerOptimizePlanLockReqVO lockReq = new VeneerOptimizePlanLockReqVO();
|
||||||
lockReq.setPlanId(planId);
|
lockReq.setPlanId(planId);
|
||||||
lockReq.setVal(val);
|
lockReq.setVal(val);
|
||||||
acquirePlanLock(lockReq);
|
validateLockRequest(lockReq);
|
||||||
|
OrderVeneerPlanDO plan = validatePlanExists(planId);
|
||||||
|
acquirePlanLockValue(lockReq);
|
||||||
|
|
||||||
// 待删除贴皮仅向优化端下发短号,不重复传输此前已经发送的完整板件数据。
|
// optimize_time 是首次优化是否已经完成的持久标志,避免用可重算的数量字段判断。
|
||||||
List<String> pendingDeleteVeneerNos =
|
boolean optimized = plan.getOptimizeTime() != null;
|
||||||
veneerOptimizePlanMapper.selectPendingDeleteVeneerNos(planId);
|
|
||||||
|
|
||||||
// 只加载本次尚未优化且未标记待删除的贴皮,并合并多加工组造成的重复记录。
|
// 首次优化尚不存在历史排版,不下发待删除列表;再次优化才通知组件移除历史贴皮。
|
||||||
|
List<String> pendingDeleteVeneerNos = optimized
|
||||||
|
? veneerOptimizePlanMapper.selectPendingDeleteVeneerNos(planId) : List.of();
|
||||||
|
|
||||||
|
// 首次优化加载全部正常贴皮;再次优化只加载新增未优化贴皮,并合并多加工组重复记录。
|
||||||
List<VeneerOptimizePlateRespVO> plates = mergePlateDetails(
|
List<VeneerOptimizePlateRespVO> plates = mergePlateDetails(
|
||||||
veneerOptimizePlanMapper.selectPlateList(planId));
|
veneerOptimizePlanMapper.selectPlateList(planId, optimized));
|
||||||
if (CollUtil.isEmpty(plates) && CollUtil.isEmpty(pendingDeleteVeneerNos)) {
|
if (CollUtil.isEmpty(plates) && CollUtil.isEmpty(pendingDeleteVeneerNos)) {
|
||||||
throw new ServiceException(VENEER_OPTIMIZE_PLATE_EMPTY);
|
throw new ServiceException(VENEER_OPTIMIZE_PLATE_EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<VeneerOptimizeGoodsRespVO> goods = CollUtil.isEmpty(plates)
|
// 订单和贴皮商品属于排单基础上下文,始终返回全量,不随增量贴皮列表变空。
|
||||||
? List.of() : veneerOptimizePlanMapper.selectGoodsList(planId);
|
List<VeneerOptimizeGoodsRespVO> goods = veneerOptimizePlanMapper.selectGoodsList(planId);
|
||||||
if (CollUtil.isNotEmpty(plates) && CollUtil.isEmpty(goods)) {
|
if (CollUtil.isEmpty(goods)) {
|
||||||
throw new ServiceException(VENEER_OPTIMIZE_GOODS_EMPTY);
|
throw new ServiceException(VENEER_OPTIMIZE_GOODS_EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 订单范围以当前排单有效贴皮明细为准,不依赖排单冗余的 order_nos。
|
// 订单范围以整个排单有效贴皮明细为准,不依赖本次增量 plateList 或冗余 order_nos。
|
||||||
List<Long> orderIds = plates.stream().map(VeneerOptimizePlateRespVO::getOrderId)
|
List<Long> orderIds = veneerOptimizePlanMapper.selectOrderIds(planId);
|
||||||
.filter(java.util.Objects::nonNull).distinct().sorted().toList();
|
|
||||||
List<OrderDO> orders = new ArrayList<>();
|
List<OrderDO> orders = new ArrayList<>();
|
||||||
for (List<Long> batch : CollUtil.split(orderIds, ORDER_QUERY_BATCH_SIZE)) {
|
for (List<Long> batch : CollUtil.split(orderIds, ORDER_QUERY_BATCH_SIZE)) {
|
||||||
orders.addAll(orderMapper.selectBatchIds(batch));
|
orders.addAll(orderMapper.selectBatchIds(batch));
|
||||||
}
|
}
|
||||||
if (CollUtil.isNotEmpty(plates) && CollUtil.isEmpty(orders)) {
|
if (CollUtil.isEmpty(orders)) {
|
||||||
throw new ServiceException(VENEER_OPTIMIZE_ORDERS_EMPTY);
|
throw new ServiceException(VENEER_OPTIMIZE_ORDERS_EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,11 +148,153 @@ public class VeneerOptimizePlanServiceImpl implements VeneerOptimizePlanService
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void saveOptimizationResults(VeneerOptimizationResultsReqVO req) {
|
||||||
|
if (req == null || req.getFlowSessionSavedContent() == null
|
||||||
|
|| CollUtil.isEmpty(req.getFlowSessionSavedContent().getLayoutResultSummary())) {
|
||||||
|
throw new ServiceException(VENEER_OPTIMIZE_RESULT_REQUIRED);
|
||||||
|
}
|
||||||
|
OrderVeneerPlanDO plan = validatePlanExists(req.getPlanId());
|
||||||
|
Integer flowStatus = req.getFlowSessionSavedContent().getProcessStatus();
|
||||||
|
List<BoardLayoutResultSummary> summaries =
|
||||||
|
req.getFlowSessionSavedContent().getLayoutResultSummary();
|
||||||
|
|
||||||
|
if (FlowProcessStatus.NOT_STARTED.getStatus().equals(flowStatus)) {
|
||||||
|
saveOptimizedResult(plan, summaries);
|
||||||
|
} else if (FlowProcessStatus.IN_PROGRESS.getStatus().equals(flowStatus)) {
|
||||||
|
saveCuttingResult(plan, summaries);
|
||||||
|
} else if (FlowProcessStatus.COMPLETED.getStatus().equals(flowStatus)) {
|
||||||
|
saveCutResult(plan, summaries);
|
||||||
|
} else {
|
||||||
|
throw new ServiceException(VENEER_OPTIMIZE_PROCESS_STATUS_INVALID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 保存全量优化排版结果。 */
|
||||||
|
private void saveOptimizedResult(OrderVeneerPlanDO plan,
|
||||||
|
List<BoardLayoutResultSummary> summaries) {
|
||||||
|
List<String> veneerNos = collectVeneerNos(summaries, false);
|
||||||
|
String optimizeGoodsId = resolveOptimizeGoodsId(summaries);
|
||||||
|
|
||||||
|
// 与普通板件排单一致:先重置当前正常贴皮,再按本次全量结果重新标记已优化。
|
||||||
|
veneerOptimizePlanMapper.resetOptimizedVeneerStatus(
|
||||||
|
plan.getId(),
|
||||||
|
VeneerPlateProcessStatusEnum.OPTIMIZED.getStatus(),
|
||||||
|
VeneerPlateProcessStatusEnum.NOT_OPTIMIZED.getStatus());
|
||||||
|
updateVeneerStatusInBatches(
|
||||||
|
plan.getId(), veneerNos,
|
||||||
|
List.of(VeneerPlateProcessStatusEnum.NOT_OPTIMIZED.getStatus()),
|
||||||
|
VeneerPlateProcessStatusEnum.OPTIMIZED.getStatus());
|
||||||
|
|
||||||
|
int scheduledBoardNum = summaries.stream()
|
||||||
|
.map(BoardLayoutResultSummary::getBoardCount)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.mapToInt(Integer::intValue)
|
||||||
|
.sum();
|
||||||
|
int updated = veneerOptimizePlanMapper.updatePlanOptimized(
|
||||||
|
plan.getId(), plan.getVersion(), VeneerPlanStatusEnum.OPTIMIZED.getStatus(),
|
||||||
|
optimizeGoodsId, veneerNos.size(), scheduledBoardNum);
|
||||||
|
validateSinglePlanUpdated(updated);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 保存开始开料结果。 */
|
||||||
|
private void saveCuttingResult(OrderVeneerPlanDO plan,
|
||||||
|
List<BoardLayoutResultSummary> summaries) {
|
||||||
|
List<String> veneerNos = collectVeneerNos(summaries, false);
|
||||||
|
updateVeneerStatusInBatches(
|
||||||
|
plan.getId(), veneerNos,
|
||||||
|
List.of(VeneerPlateProcessStatusEnum.OPTIMIZED.getStatus()),
|
||||||
|
VeneerPlateProcessStatusEnum.CUTTING.getStatus());
|
||||||
|
int updated = veneerOptimizePlanMapper.updatePlanCutting(
|
||||||
|
plan.getId(), plan.getVersion(), VeneerPlanStatusEnum.OPENING.getStatus());
|
||||||
|
validateSinglePlanUpdated(updated);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 保存结束开料结果。 */
|
||||||
|
private void saveCutResult(OrderVeneerPlanDO plan,
|
||||||
|
List<BoardLayoutResultSummary> summaries) {
|
||||||
|
List<String> veneerNos = collectVeneerNos(summaries, true);
|
||||||
|
updateVeneerStatusInBatches(
|
||||||
|
plan.getId(), veneerNos,
|
||||||
|
List.of(VeneerPlateProcessStatusEnum.OPTIMIZED.getStatus(),
|
||||||
|
VeneerPlateProcessStatusEnum.CUTTING.getStatus()),
|
||||||
|
VeneerPlateProcessStatusEnum.CUT.getStatus());
|
||||||
|
|
||||||
|
int cuttedBoardNum = summaries.stream()
|
||||||
|
.map(BoardLayoutResultSummary::getEndCutBoardCount)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.mapToInt(Integer::intValue)
|
||||||
|
.sum();
|
||||||
|
int updated = veneerOptimizePlanMapper.updatePlanCut(
|
||||||
|
plan.getId(), plan.getVersion(), VeneerPlanStatusEnum.OPENED.getStatus(),
|
||||||
|
cuttedBoardNum, veneerNos.size());
|
||||||
|
validateSinglePlanUpdated(updated);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 汇总组件回传的贴皮短号并去重。 */
|
||||||
|
private List<String> collectVeneerNos(List<BoardLayoutResultSummary> summaries,
|
||||||
|
boolean completed) {
|
||||||
|
List<String> veneerNos = summaries.stream()
|
||||||
|
.map(completed
|
||||||
|
? BoardLayoutResultSummary::getCustomEndCutBlockNos
|
||||||
|
: BoardLayoutResultSummary::getCustomBlockNos)
|
||||||
|
.filter(CollUtil::isNotEmpty)
|
||||||
|
.flatMap(List::stream)
|
||||||
|
.filter(StrUtil::isNotBlank)
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
if (CollUtil.isEmpty(veneerNos)) {
|
||||||
|
throw new ServiceException(VENEER_OPTIMIZE_VENEER_NO_REQUIRED);
|
||||||
|
}
|
||||||
|
return veneerNos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取本次优化唯一的贴皮商品编号。 */
|
||||||
|
private String resolveOptimizeGoodsId(List<BoardLayoutResultSummary> summaries) {
|
||||||
|
List<String> goodsIds = summaries.stream()
|
||||||
|
.map(BoardLayoutResultSummary::getCustomMaterialNos)
|
||||||
|
.filter(CollUtil::isNotEmpty)
|
||||||
|
.flatMap(List::stream)
|
||||||
|
.filter(StrUtil::isNotBlank)
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
if (goodsIds.size() > 1) {
|
||||||
|
throw new ServiceException(VENEER_OPTIMIZE_MATERIAL_MULTIPLE);
|
||||||
|
}
|
||||||
|
return CollUtil.getFirst(goodsIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 分批更新贴皮加工状态,并以影响行数校验组件结果与数据库状态一致。 */
|
||||||
|
private void updateVeneerStatusInBatches(Long planId, List<String> veneerNos,
|
||||||
|
List<Integer> sourceStatuses,
|
||||||
|
Integer targetStatus) {
|
||||||
|
int updatedCount = 0;
|
||||||
|
for (List<String> batch : CollUtil.split(veneerNos, VENEER_UPDATE_BATCH_SIZE)) {
|
||||||
|
updatedCount += veneerOptimizePlanMapper.updateVeneerProcessStatus(
|
||||||
|
planId, batch, sourceStatuses, targetStatus);
|
||||||
|
}
|
||||||
|
if (updatedCount != veneerNos.size()) {
|
||||||
|
throw new ServiceException(VENEER_OPTIMIZE_RESULT_STATUS_CHANGED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 校验排单版本及状态更新结果。 */
|
||||||
|
private void validateSinglePlanUpdated(int updated) {
|
||||||
|
if (updated != 1) {
|
||||||
|
throw new ServiceException(VENEER_OPTIMIZE_RESULT_STATUS_CHANGED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void acquirePlanLock(VeneerOptimizePlanLockReqVO req) {
|
public void acquirePlanLock(VeneerOptimizePlanLockReqVO req) {
|
||||||
validateLockRequest(req);
|
validateLockRequest(req);
|
||||||
validatePlanExists(req.getPlanId());
|
validatePlanExists(req.getPlanId());
|
||||||
|
acquirePlanLockValue(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取锁值;调用前必须完成请求参数和排单存在性校验。 */
|
||||||
|
private void acquirePlanLockValue(VeneerOptimizePlanLockReqVO req) {
|
||||||
String lockKey = String.format(ORDER_VENEER_PLAN_OPTIMIZE_KEY, req.getPlanId());
|
String lockKey = String.format(ORDER_VENEER_PLAN_OPTIMIZE_KEY, req.getPlanId());
|
||||||
String lockVal = stringRedisTemplate.opsForValue().get(lockKey);
|
String lockVal = stringRedisTemplate.opsForValue().get(lockKey);
|
||||||
if (lockVal == null) {
|
if (lockVal == null) {
|
||||||
|
|||||||
+4
@@ -225,6 +225,10 @@ public class VeneerPlanServiceImpl implements VeneerPlanService {
|
|||||||
.orderNos(buildOrderNos(group))
|
.orderNos(buildOrderNos(group))
|
||||||
.veneerNum(group.size())
|
.veneerNum(group.size())
|
||||||
.veneerArea(calculateVeneerArea(group))
|
.veneerArea(calculateVeneerArea(group))
|
||||||
|
.optimizedPlateNum(0)
|
||||||
|
.scheduledBoardNum(0)
|
||||||
|
.cuttedBoardNum(0)
|
||||||
|
.cuttedPlateNum(0)
|
||||||
.operator(loginUser.getNickname())
|
.operator(loginUser.getNickname())
|
||||||
.version(0)
|
.version(0)
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
+79
-2
@@ -31,11 +31,17 @@
|
|||||||
AND ovg.deleted = false
|
AND ovg.deleted = false
|
||||||
WHERE opv.deleted = false
|
WHERE opv.deleted = false
|
||||||
AND opv.plan_id = #{planId}
|
AND opv.plan_id = #{planId}
|
||||||
AND opv.process_status = 0
|
|
||||||
AND opv.pending_delete = false
|
|
||||||
ORDER BY ovg.goods_id
|
ORDER BY ovg.goods_id
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectOrderIds" resultType="java.lang.Long">
|
||||||
|
SELECT DISTINCT opv.order_id
|
||||||
|
FROM order_plate_veneer opv
|
||||||
|
WHERE opv.deleted = false
|
||||||
|
AND opv.plan_id = #{planId}
|
||||||
|
ORDER BY opv.order_id
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="selectPlateList" resultMap="OptimizePlateMap">
|
<select id="selectPlateList" resultMap="OptimizePlateMap">
|
||||||
SELECT opv.id AS veneerId,
|
SELECT opv.id AS veneerId,
|
||||||
ovg.id,
|
ovg.id,
|
||||||
@@ -121,7 +127,9 @@
|
|||||||
AND opg.id = oi.group_id
|
AND opg.id = oi.group_id
|
||||||
WHERE opv.deleted = false
|
WHERE opv.deleted = false
|
||||||
AND opv.plan_id = #{planId}
|
AND opv.plan_id = #{planId}
|
||||||
|
<if test="optimized">
|
||||||
AND opv.process_status = 0
|
AND opv.process_status = 0
|
||||||
|
</if>
|
||||||
AND opv.pending_delete = false
|
AND opv.pending_delete = false
|
||||||
ORDER BY opv.id, oi.group_id
|
ORDER BY opv.id, oi.group_id
|
||||||
</select>
|
</select>
|
||||||
@@ -134,4 +142,73 @@
|
|||||||
AND opv.pending_delete = true
|
AND opv.pending_delete = true
|
||||||
ORDER BY opv.id
|
ORDER BY opv.id
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<update id="resetOptimizedVeneerStatus">
|
||||||
|
UPDATE order_plate_veneer
|
||||||
|
SET process_status = #{notOptimizedStatus},
|
||||||
|
update_time = CURRENT_TIMESTAMP
|
||||||
|
WHERE deleted = false
|
||||||
|
AND plan_id = #{planId}
|
||||||
|
AND pending_delete = false
|
||||||
|
AND process_status = #{optimizedStatus}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<update id="updateVeneerProcessStatus">
|
||||||
|
UPDATE order_plate_veneer
|
||||||
|
SET process_status = #{targetStatus},
|
||||||
|
update_time = CURRENT_TIMESTAMP
|
||||||
|
WHERE deleted = false
|
||||||
|
AND plan_id = #{planId}
|
||||||
|
AND pending_delete = false
|
||||||
|
AND process_status IN
|
||||||
|
<foreach collection="sourceStatuses" item="status" open="(" close=")" separator=",">
|
||||||
|
#{status}
|
||||||
|
</foreach>
|
||||||
|
AND veneer_no IN
|
||||||
|
<foreach collection="veneerNos" item="veneerNo" open="(" close=")" separator=",">
|
||||||
|
#{veneerNo}
|
||||||
|
</foreach>
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<update id="updatePlanOptimized">
|
||||||
|
UPDATE order_veneer_plan
|
||||||
|
SET status = #{status},
|
||||||
|
optimize_goods_id = #{optimizeGoodsId},
|
||||||
|
optimize_time = CURRENT_TIMESTAMP,
|
||||||
|
optimized_plate_num = #{optimizedPlateNum},
|
||||||
|
scheduled_board_num = #{scheduledBoardNum},
|
||||||
|
version = version + 1,
|
||||||
|
update_time = CURRENT_TIMESTAMP
|
||||||
|
WHERE deleted = false
|
||||||
|
AND id = #{planId}
|
||||||
|
AND version = #{version}
|
||||||
|
AND status IN (0, 1)
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<update id="updatePlanCutting">
|
||||||
|
UPDATE order_veneer_plan
|
||||||
|
SET status = #{status},
|
||||||
|
produce_time = NULL,
|
||||||
|
version = version + 1,
|
||||||
|
update_time = CURRENT_TIMESTAMP
|
||||||
|
WHERE deleted = false
|
||||||
|
AND id = #{planId}
|
||||||
|
AND version = #{version}
|
||||||
|
AND status IN (0, 1)
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<update id="updatePlanCut">
|
||||||
|
UPDATE order_veneer_plan
|
||||||
|
SET status = #{status},
|
||||||
|
cutted_board_num = #{cuttedBoardNum},
|
||||||
|
cutted_plate_num = #{cuttedPlateNum},
|
||||||
|
produce_time = CURRENT_TIMESTAMP,
|
||||||
|
finish_time = CURRENT_TIMESTAMP,
|
||||||
|
version = version + 1,
|
||||||
|
update_time = CURRENT_TIMESTAMP
|
||||||
|
WHERE deleted = false
|
||||||
|
AND id = #{planId}
|
||||||
|
AND version = #{version}
|
||||||
|
AND status != 3
|
||||||
|
</update>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
+7
@@ -24,6 +24,13 @@
|
|||||||
ovp.is_scheduled AS isScheduled,
|
ovp.is_scheduled AS isScheduled,
|
||||||
ovp.veneer_num AS veneerNum,
|
ovp.veneer_num AS veneerNum,
|
||||||
ovp.veneer_area AS veneerArea,
|
ovp.veneer_area AS veneerArea,
|
||||||
|
ovp.optimize_goods_id AS optimizeGoodsId,
|
||||||
|
ovp.optimize_time AS optimizeTime,
|
||||||
|
ovp.optimized_plate_num AS optimizedPlateNum,
|
||||||
|
GREATEST(ovp.veneer_num - ovp.optimized_plate_num, 0) AS unOptimizedPlateNum,
|
||||||
|
ovp.scheduled_board_num AS scheduledBoardNum,
|
||||||
|
ovp.cutted_board_num AS cuttedBoardNum,
|
||||||
|
ovp.cutted_plate_num AS cuttedPlateNum,
|
||||||
ovp.create_time AS createTime,
|
ovp.create_time AS createTime,
|
||||||
ovp.produce_time AS produceTime
|
ovp.produce_time AS produceTime
|
||||||
FROM order_veneer_plan ovp
|
FROM order_veneer_plan ovp
|
||||||
|
|||||||
+5
@@ -173,3 +173,8 @@ veneer.optimize.plate.empty=貼皮排單下沒有有效貼皮數據
|
|||||||
veneer.optimize.goods.empty=貼皮排單商品數據異常
|
veneer.optimize.goods.empty=貼皮排單商品數據異常
|
||||||
veneer.optimize.orders.empty=貼皮排單關聯訂單為空
|
veneer.optimize.orders.empty=貼皮排單關聯訂單為空
|
||||||
veneer.optimize.plate.model.empty=貼皮排單板件造型數據異常
|
veneer.optimize.plate.model.empty=貼皮排單板件造型數據異常
|
||||||
|
veneer.optimize.result.required=貼皮優化結果不能為空
|
||||||
|
veneer.optimize.process.status.invalid=貼皮優化流程狀態不正確
|
||||||
|
veneer.optimize.veneer.no.required=貼皮優化結果中的貼皮編號不能為空
|
||||||
|
veneer.optimize.material.multiple=同一貼皮排單只能包含一個貼皮商品編號
|
||||||
|
veneer.optimize.result.status.changed=貼皮排單或貼皮加工狀態已發生變化,請刷新後重試
|
||||||
|
|||||||
+5
@@ -174,3 +174,8 @@ veneer.optimize.plate.empty=No valid veneer records exist in the veneer plan
|
|||||||
veneer.optimize.goods.empty=The veneer plan goods data is invalid
|
veneer.optimize.goods.empty=The veneer plan goods data is invalid
|
||||||
veneer.optimize.orders.empty=The veneer plan has no associated orders
|
veneer.optimize.orders.empty=The veneer plan has no associated orders
|
||||||
veneer.optimize.plate.model.empty=The veneer plan plate model data is invalid
|
veneer.optimize.plate.model.empty=The veneer plan plate model data is invalid
|
||||||
|
veneer.optimize.result.required=The veneer optimization result is required
|
||||||
|
veneer.optimize.process.status.invalid=The veneer optimization process status is invalid
|
||||||
|
veneer.optimize.veneer.no.required=The veneer number in the optimization result is required
|
||||||
|
veneer.optimize.material.multiple=Only one veneer goods number is allowed in a veneer plan
|
||||||
|
veneer.optimize.result.status.changed=The veneer plan or veneer process status has changed. Please refresh and try again
|
||||||
|
|||||||
+5
@@ -174,3 +174,8 @@ veneer.optimize.plate.empty=贴皮排单下没有有效贴皮数据
|
|||||||
veneer.optimize.goods.empty=贴皮排单商品数据异常
|
veneer.optimize.goods.empty=贴皮排单商品数据异常
|
||||||
veneer.optimize.orders.empty=贴皮排单关联订单为空
|
veneer.optimize.orders.empty=贴皮排单关联订单为空
|
||||||
veneer.optimize.plate.model.empty=贴皮排单板件造型数据异常
|
veneer.optimize.plate.model.empty=贴皮排单板件造型数据异常
|
||||||
|
veneer.optimize.result.required=贴皮优化结果不能为空
|
||||||
|
veneer.optimize.process.status.invalid=贴皮优化流程状态不正确
|
||||||
|
veneer.optimize.veneer.no.required=贴皮优化结果中的贴皮编号不能为空
|
||||||
|
veneer.optimize.material.multiple=同一贴皮排单只能包含一个贴皮商品编号
|
||||||
|
veneer.optimize.result.status.changed=贴皮排单或贴皮加工状态已发生变化,请刷新后重试
|
||||||
|
|||||||
Reference in New Issue
Block a user