package com.ruoyi.production.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.production.bean.dto.ProductionBomStructureDto;
import com.ruoyi.production.bean.vo.ProductionBomStructureVo;
import com.ruoyi.production.mapper.ProductionBomStructureMapper;
import com.ruoyi.production.mapper.ProductionOperationTaskMapper;
import com.ruoyi.production.mapper.ProductionOrderBomMapper;
import com.ruoyi.production.mapper.ProductionOrderMapper;
import com.ruoyi.production.mapper.ProductionOrderRoutingMapper;
import com.ruoyi.production.mapper.ProductionOrderRoutingOperationMapper;
import com.ruoyi.production.mapper.ProductionOrderRoutingOperationParamMapper;
import com.ruoyi.production.mapper.ProductionProductMainMapper;
import com.ruoyi.production.pojo.ProductionBomStructure;
import com.ruoyi.production.pojo.ProductionOperationTask;
import com.ruoyi.production.pojo.ProductionOrder;
import com.ruoyi.production.pojo.ProductionOrderBom;
import com.ruoyi.production.pojo.ProductionOrderRouting;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam;
import com.ruoyi.production.pojo.ProductionProductMain;
import com.ruoyi.production.service.ProductionBomStructureService;
import com.ruoyi.production.util.TaskPlanQuantityUtil;
import com.ruoyi.technology.mapper.TechnologyOperationMapper;
import com.ruoyi.technology.mapper.TechnologyOperationParamMapper;
import com.ruoyi.technology.mapper.TechnologyParamMapper;
import com.ruoyi.technology.pojo.TechnologyOperation;
import com.ruoyi.technology.pojo.TechnologyOperationParam;
import com.ruoyi.technology.pojo.TechnologyParam;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
/**
*
* 生产订单BOM产品结构 服务实现类
*
*
* @author 芯导软件(江苏)有限公司
* @since 2026-04-21 03:55:52
*/
@Service
@RequiredArgsConstructor()
public class ProductionBomStructureServiceImpl extends ServiceImpl implements ProductionBomStructureService {
private final ProductionBomStructureMapper productionBomStructureMapper;
private final ProductionOrderBomMapper productionOrderBomMapper;
private final ProductionOrderMapper productionOrderMapper;
private final ProductionOrderRoutingMapper productionOrderRoutingMapper;
private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper;
private final ProductionOrderRoutingOperationParamMapper productionOrderRoutingOperationParamMapper;
private final ProductionOperationTaskMapper productionOperationTaskMapper;
private final ProductionProductMainMapper productionProductMainMapper;
private final ProductModelMapper productModelMapper;
private final TechnologyOperationMapper technologyOperationMapper;
private final TechnologyOperationParamMapper technologyOperationParamMapper;
private final TechnologyParamMapper technologyParamMapper;
/**
* 按订单BOM查询扁平物料明细。
*/
@Override
public List listByBomId(Long bomId) {
if (bomId == null) {
return new ArrayList<>();
}
return productionBomStructureMapper.listByBomId(bomId);
}
/**
* 按生产订单查询订单BOM快照的扁平物料明细。
*/
@Override
public List listByOrderId(Long productionOrderId) {
if (productionOrderId == null) {
return new ArrayList<>();
}
ProductionOrderBom orderBom = productionOrderBomMapper.selectOne(
Wrappers.lambdaQuery()
.eq(ProductionOrderBom::getProductionOrderId, productionOrderId)
.orderByDesc(ProductionOrderBom::getId)
.last("limit 1"));
if (orderBom == null || orderBom.getId() == null) {
return new ArrayList<>();
}
return listByBomId(orderBom.getId());
}
/**
* 全量同步订单BOM快照的扁平物料明细,并按其中的工序重建订单工艺路线快照与工单。
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean addProductionBomStructure(ProductionBomStructureDto dto) {
Long orderBomId = dto.getProductionOrderBomId();
if (orderBomId == null) {
throw new ServiceException("订单BOM ID不能为空");
}
ProductionOrderBom orderBom = productionOrderBomMapper.selectById(orderBomId);
if (orderBom == null) {
throw new ServiceException("订单BOM不存在");
}
Long productionOrderId = dto.getProductionOrderId() != null
? dto.getProductionOrderId()
: orderBom.getProductionOrderId();
List detailList = dto.getDetailList() == null
? Collections.emptyList()
: dto.getDetailList();
List dbList = this.list(new LambdaQueryWrapper()
.eq(ProductionBomStructure::getProductionOrderBomId, orderBomId));
Set dbIds = dbList.stream().map(ProductionBomStructure::getId).collect(Collectors.toSet());
Set submittedIds = new HashSet<>();
Set relationKeys = new HashSet<>();
List insertList = new ArrayList<>();
List updateList = new ArrayList<>();
for (ProductionBomStructureDto item : detailList) {
Long productModelId = item.getProductModelId();
Long technologyOperationId = item.getTechnologyOperationId();
if (productModelId == null) {
throw new ServiceException("请选择物料规格");
}
if (productModelMapper.selectById(productModelId) == null) {
throw new ServiceException("物料规格不存在");
}
if (technologyOperationId == null) {
throw new ServiceException("请选择消耗工序");
}
if (technologyOperationMapper.selectById(technologyOperationId) == null) {
throw new ServiceException("消耗工序不存在");
}
if (productModelId.equals(orderBom.getProductModelId())) {
throw new ServiceException("成品规格不能作为自身的物料");
}
if (!relationKeys.add(productModelId + "#" + technologyOperationId)) {
throw new ServiceException("同一物料规格在同一工序下不能重复配置");
}
ProductionBomStructure entity = new ProductionBomStructure();
entity.setProductionOrderBomId(orderBomId);
entity.setProductionOrderId(productionOrderId);
entity.setProductModelId(productModelId);
entity.setTechnologyOperationId(technologyOperationId);
// 扁平快照不再使用层级与数量语义
entity.setParentId(null);
entity.setUnitQuantity(null);
entity.setDemandedQuantity(null);
entity.setUnit(null);
if (item.getId() == null) {
insertList.add(entity);
} else {
if (!dbIds.contains(item.getId())) {
throw new ServiceException("订单BOM物料明细不存在或不属于当前订单BOM");
}
entity.setId(item.getId());
submittedIds.add(item.getId());
updateList.add(entity);
}
}
Set deleteIds = new HashSet<>(dbIds);
deleteIds.removeAll(submittedIds);
if (!deleteIds.isEmpty()) {
this.removeByIds(deleteIds);
}
if (!updateList.isEmpty()) {
this.updateBatchById(updateList);
}
if (!insertList.isEmpty()) {
this.saveBatch(insertList);
}
syncRoutingAndTaskByStructure(orderBomId, productionOrderId);
return true;
}
/**
* 订单BOM物料变化后,按其工序集合重建订单工艺路线工序快照与工单计划数量。
*/
private void syncRoutingAndTaskByStructure(Long orderBomId, Long productionOrderId) {
if (orderBomId == null) {
return;
}
ProductionOrderBom orderBom = productionOrderBomMapper.selectById(orderBomId);
if (orderBom == null) {
return;
}
Long currentProductionOrderId = productionOrderId != null ? productionOrderId : orderBom.getProductionOrderId();
if (currentProductionOrderId == null) {
return;
}
ProductionOrder productionOrder = productionOrderMapper.selectById(currentProductionOrderId);
if (productionOrder == null) {
return;
}
List structureList = this.list(
Wrappers.lambdaQuery()
.eq(ProductionBomStructure::getProductionOrderBomId, orderBomId)
.orderByAsc(ProductionBomStructure::getId));
Long rootProductModelId = orderBom.getProductModelId() != null
? orderBom.getProductModelId()
: productionOrder.getProductModelId();
// 同步生产工艺路线快照
syncRoutingOperationsByBom(currentProductionOrderId, productionOrder, orderBom, structureList, rootProductModelId);
// 同步工单计划数量:扁平BOM无数量配置,计划数量统一取订单数量
syncTaskPlanQuantity(currentProductionOrderId, TaskPlanQuantityUtil.resolveTaskPlanQuantity(productionOrder));
}
private void syncTaskPlanQuantity(Long productionOrderId, BigDecimal planQuantity) {
List taskList = productionOperationTaskMapper.selectList(
Wrappers.lambdaQuery()
.eq(ProductionOperationTask::getProductionOrderId, productionOrderId)
.orderByAsc(ProductionOperationTask::getId));
if (taskList == null || taskList.isEmpty()) {
return;
}
for (ProductionOperationTask task : taskList) {
if (task == null || task.getId() == null) {
continue;
}
if (compareDecimal(task.getPlanQuantity(), planQuantity) == 0) {
continue;
}
ProductionOperationTask update = new ProductionOperationTask();
update.setId(task.getId());
update.setPlanQuantity(planQuantity);
productionOperationTaskMapper.updateById(update);
}
}
private void syncRoutingOperationsByBom(Long productionOrderId,
ProductionOrder productionOrder,
ProductionOrderBom orderBom,
List structureList,
Long rootProductModelId) {
ProductionOrderRouting orderRouting = getOrCreateOrderRoutingSnapshot(productionOrderId, productionOrder, orderBom, rootProductModelId);
List desiredOperationList = buildDesiredRoutingOperationList(structureList, rootProductModelId);
List existingOperationList = productionOrderRoutingOperationMapper.selectList(
Wrappers.lambdaQuery()
.eq(ProductionOrderRoutingOperation::getOrderRoutingId, orderRouting.getId())
.eq(ProductionOrderRoutingOperation::getProductionOrderId, productionOrderId)
.orderByAsc(ProductionOrderRoutingOperation::getDragSort)
.orderByAsc(ProductionOrderRoutingOperation::getId));
Map> existingBucketMap = buildExistingRoutingOperationBucketMap(existingOperationList);
List finalOperationList = new ArrayList<>();
for (ProductionOrderRoutingOperation desiredOperation : desiredOperationList) {
String bucketKey = buildRoutingOperationBucketKey(
desiredOperation.getTechnologyOperationId(),
desiredOperation.getProductModelId());
Deque matchedQueue = existingBucketMap.get(bucketKey);
ProductionOrderRoutingOperation matchedOperation = matchedQueue == null ? null : matchedQueue.pollFirst();
if (matchedOperation == null) {
matchedOperation = insertRoutingOperationSnapshot(orderRouting.getId(), productionOrderId, desiredOperation);
} else {
updateRoutingOperationSnapshotIfNecessary(matchedOperation, orderRouting.getId(), productionOrderId, desiredOperation);
}
finalOperationList.add(matchedOperation);
}
for (Deque queue : existingBucketMap.values()) {
while (queue != null && !queue.isEmpty()) {
removeRoutingOperationSnapshot(queue.pollFirst());
}
}
syncRoutingOperationTasks(productionOrderId, finalOperationList);
}
private ProductionOrderRouting getOrCreateOrderRoutingSnapshot(Long productionOrderId,
ProductionOrder productionOrder,
ProductionOrderBom orderBom,
Long rootProductModelId) {
ProductionOrderRouting orderRouting = productionOrderRoutingMapper.selectOne(
Wrappers.lambdaQuery()
.eq(ProductionOrderRouting::getProductionOrderId, productionOrderId)
.orderByDesc(ProductionOrderRouting::getId)
.last("limit 1"));
if (orderRouting == null) {
orderRouting = new ProductionOrderRouting();
orderRouting.setProductionOrderId(productionOrderId);
orderRouting.setProductModelId(rootProductModelId);
orderRouting.setTechnologyRoutingId(productionOrder == null ? null : productionOrder.getTechnologyRoutingId());
orderRouting.setBomId(orderBom == null ? null : orderBom.getBomId());
orderRouting.setOrderBomId(orderBom == null ? null : orderBom.getId());
productionOrderRoutingMapper.insert(orderRouting);
return orderRouting;
}
ProductionOrderRouting update = new ProductionOrderRouting();
update.setId(orderRouting.getId());
boolean changed = false;
if (!Objects.equals(orderRouting.getProductModelId(), rootProductModelId)) {
update.setProductModelId(rootProductModelId);
orderRouting.setProductModelId(rootProductModelId);
changed = true;
}
Long technologyRoutingId = productionOrder == null ? null : productionOrder.getTechnologyRoutingId();
if (!Objects.equals(orderRouting.getTechnologyRoutingId(), technologyRoutingId)) {
update.setTechnologyRoutingId(technologyRoutingId);
orderRouting.setTechnologyRoutingId(technologyRoutingId);
changed = true;
}
Long bomId = orderBom == null ? null : orderBom.getBomId();
if (!Objects.equals(orderRouting.getBomId(), bomId)) {
update.setBomId(bomId);
orderRouting.setBomId(bomId);
changed = true;
}
Long orderBomId = orderBom == null ? null : orderBom.getId();
if (!Objects.equals(orderRouting.getOrderBomId(), orderBomId)) {
update.setOrderBomId(orderBomId);
orderRouting.setOrderBomId(orderBomId);
changed = true;
}
if (changed) {
productionOrderRoutingMapper.updateById(update);
}
return orderRouting;
}
/**
* 扁平BOM按工序去重生成期望的订单工序列表,
* 顺序取物料明细中工序首次出现的顺序,产出规格固定为订单成品规格。
*/
private List buildDesiredRoutingOperationList(List structureList,
Long rootProductModelId) {
if (structureList == null || structureList.isEmpty()) {
return Collections.emptyList();
}
Set uniqueOperationIdList = new LinkedHashSet<>();
for (ProductionBomStructure structure : structureList) {
if (structure == null || structure.getTechnologyOperationId() == null) {
continue;
}
uniqueOperationIdList.add(structure.getTechnologyOperationId());
}
List desiredOperationList = new ArrayList<>(uniqueOperationIdList.size());
int dragSort = 1;
for (Long operationId : uniqueOperationIdList) {
TechnologyOperation technologyOperation = getTechnologyOperation(operationId);
ProductionOrderRoutingOperation routingOperation = new ProductionOrderRoutingOperation();
routingOperation.setProductModelId(rootProductModelId);
routingOperation.setTechnologyOperationId(operationId);
routingOperation.setOperationName(technologyOperation == null ? null : technologyOperation.getName());
routingOperation.setIsQuality(technologyOperation == null ? null : technologyOperation.getIsQuality());
routingOperation.setIsProduction(technologyOperation == null ? null : technologyOperation.getIsProduction());
routingOperation.setType(technologyOperation == null ? null : technologyOperation.getType());
routingOperation.setDragSort(dragSort++);
desiredOperationList.add(routingOperation);
}
return desiredOperationList;
}
private Map> buildExistingRoutingOperationBucketMap(List existingOperationList) {
Map> existingBucketMap = new LinkedHashMap<>();
if (existingOperationList == null || existingOperationList.isEmpty()) {
return existingBucketMap;
}
for (ProductionOrderRoutingOperation routingOperation : existingOperationList) {
String bucketKey = buildRoutingOperationBucketKey(
routingOperation.getTechnologyOperationId(),
routingOperation.getProductModelId());
existingBucketMap.computeIfAbsent(bucketKey, key -> new ArrayDeque<>()).addLast(routingOperation);
}
return existingBucketMap;
}
private ProductionOrderRoutingOperation insertRoutingOperationSnapshot(Long orderRoutingId,
Long productionOrderId,
ProductionOrderRoutingOperation desiredOperation) {
ProductionOrderRoutingOperation insert = new ProductionOrderRoutingOperation();
insert.setOrderRoutingId(orderRoutingId);
insert.setProductionOrderId(productionOrderId);
insert.setProductModelId(desiredOperation.getProductModelId());
insert.setTechnologyOperationId(desiredOperation.getTechnologyOperationId());
insert.setOperationName(desiredOperation.getOperationName());
insert.setIsQuality(desiredOperation.getIsQuality());
insert.setIsProduction(desiredOperation.getIsProduction());
insert.setType(desiredOperation.getType());
insert.setDragSort(desiredOperation.getDragSort());
productionOrderRoutingOperationMapper.insert(insert);
syncRoutingOperationParams(insert.getId(), productionOrderId, insert.getTechnologyOperationId());
return insert;
}
private void updateRoutingOperationSnapshotIfNecessary(ProductionOrderRoutingOperation currentOperation,
Long orderRoutingId,
Long productionOrderId,
ProductionOrderRoutingOperation desiredOperation) {
if (currentOperation == null || currentOperation.getId() == null) {
return;
}
ProductionOrderRoutingOperation update = new ProductionOrderRoutingOperation();
update.setId(currentOperation.getId());
boolean changed = false;
if (!Objects.equals(currentOperation.getOrderRoutingId(), orderRoutingId)) {
update.setOrderRoutingId(orderRoutingId);
currentOperation.setOrderRoutingId(orderRoutingId);
changed = true;
}
if (!Objects.equals(currentOperation.getProductionOrderId(), productionOrderId)) {
update.setProductionOrderId(productionOrderId);
currentOperation.setProductionOrderId(productionOrderId);
changed = true;
}
if (!Objects.equals(currentOperation.getProductModelId(), desiredOperation.getProductModelId())) {
update.setProductModelId(desiredOperation.getProductModelId());
currentOperation.setProductModelId(desiredOperation.getProductModelId());
changed = true;
}
if (!Objects.equals(currentOperation.getTechnologyOperationId(), desiredOperation.getTechnologyOperationId())) {
update.setTechnologyOperationId(desiredOperation.getTechnologyOperationId());
currentOperation.setTechnologyOperationId(desiredOperation.getTechnologyOperationId());
changed = true;
}
if (!Objects.equals(currentOperation.getOperationName(), desiredOperation.getOperationName())) {
update.setOperationName(desiredOperation.getOperationName());
currentOperation.setOperationName(desiredOperation.getOperationName());
changed = true;
}
if (!Objects.equals(currentOperation.getIsQuality(), desiredOperation.getIsQuality())) {
update.setIsQuality(desiredOperation.getIsQuality());
currentOperation.setIsQuality(desiredOperation.getIsQuality());
changed = true;
}
if (!Objects.equals(currentOperation.getIsProduction(), desiredOperation.getIsProduction())) {
update.setIsProduction(desiredOperation.getIsProduction());
currentOperation.setIsProduction(desiredOperation.getIsProduction());
changed = true;
}
if (!Objects.equals(currentOperation.getType(), desiredOperation.getType())) {
update.setType(desiredOperation.getType());
currentOperation.setType(desiredOperation.getType());
changed = true;
}
if (!Objects.equals(currentOperation.getDragSort(), desiredOperation.getDragSort())) {
update.setDragSort(desiredOperation.getDragSort());
currentOperation.setDragSort(desiredOperation.getDragSort());
changed = true;
}
if (changed) {
productionOrderRoutingOperationMapper.updateById(update);
}
}
private void removeRoutingOperationSnapshot(ProductionOrderRoutingOperation routingOperation) {
if (routingOperation == null || routingOperation.getId() == null) {
return;
}
ProductionOperationTask task = productionOperationTaskMapper.selectOne(
Wrappers.lambdaQuery()
.eq(ProductionOperationTask::getProductionOrderRoutingOperationId, routingOperation.getId())
.last("limit 1"));
if (task != null) {
validateTaskCanRemove(task);
productionOperationTaskMapper.deleteById(task.getId());
}
productionOrderRoutingOperationParamMapper.delete(
Wrappers.lambdaQuery()
.eq(ProductionOrderRoutingOperationParam::getProductionOrderRoutingOperationId, routingOperation.getId()));
productionOrderRoutingOperationMapper.deleteById(routingOperation.getId());
}
private void syncRoutingOperationTasks(Long productionOrderId, List routingOperationList) {
if (routingOperationList == null || routingOperationList.isEmpty()) {
return;
}
List routingOperationIdList = routingOperationList.stream()
.map(ProductionOrderRoutingOperation::getId)
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (routingOperationIdList.isEmpty()) {
return;
}
Map taskByRoutingOperationId = productionOperationTaskMapper.selectList(
Wrappers.lambdaQuery()
.in(ProductionOperationTask::getProductionOrderRoutingOperationId, routingOperationIdList)
.orderByAsc(ProductionOperationTask::getId))
.stream()
.filter(item -> item != null && item.getProductionOrderRoutingOperationId() != null)
.collect(Collectors.toMap(
ProductionOperationTask::getProductionOrderRoutingOperationId,
item -> item,
(left, right) -> left,
LinkedHashMap::new));
for (int i = 0; i < routingOperationList.size(); i++) {
ProductionOrderRoutingOperation routingOperation = routingOperationList.get(i);
if (routingOperation == null || routingOperation.getId() == null) {
continue;
}
boolean shouldHaveTask = i == routingOperationList.size() - 1 || Boolean.TRUE.equals(routingOperation.getIsProduction());
ProductionOperationTask existingTask = taskByRoutingOperationId.get(routingOperation.getId());
if (shouldHaveTask) {
if (existingTask == null) {
ProductionOperationTask task = new ProductionOperationTask();
task.setProductionOrderId(productionOrderId);
task.setProductionOrderRoutingOperationId(routingOperation.getId());
task.setPlanQuantity(BigDecimal.ZERO);
task.setCompleteQuantity(BigDecimal.ZERO);
task.setWorkOrderNo(generateNextTaskNo());
task.setStatus(2);
productionOperationTaskMapper.insert(task);
}
continue;
}
if (existingTask != null) {
validateTaskCanRemove(existingTask);
productionOperationTaskMapper.deleteById(existingTask.getId());
}
}
}
private void validateTaskCanRemove(ProductionOperationTask task) {
if (task == null || task.getId() == null) {
return;
}
if (defaultDecimal(task.getCompleteQuantity()).compareTo(BigDecimal.ZERO) > 0) {
throw new ServiceException("工序已产生报工记录,无法根据 BOM 变更删除对应工序快照" + task.getWorkOrderNo());
}
long reportCount = productionProductMainMapper.selectCount(
Wrappers.lambdaQuery()
.eq(ProductionProductMain::getProductionOperationTaskId, task.getId()));
if (reportCount > 0) {
throw new ServiceException("工序已产生报工记录,无法根据 BOM 变更删除对应工单");
}
}
private void syncRoutingOperationParams(Long routingOperationId, Long productionOrderId, Long technologyOperationId) {
if (routingOperationId == null || technologyOperationId == null) {
return;
}
List operationParamList = technologyOperationParamMapper.selectList(
Wrappers.lambdaQuery()
.eq(TechnologyOperationParam::getTechnologyOperationId, technologyOperationId)
.orderByAsc(TechnologyOperationParam::getId));
for (TechnologyOperationParam operationParam : operationParamList) {
TechnologyParam technologyParam = technologyParamMapper.selectById(operationParam.getTechnologyParamId());
if (technologyParam == null) {
continue;
}
ProductionOrderRoutingOperationParam snapshot = new ProductionOrderRoutingOperationParam();
snapshot.setProductionOrderId(productionOrderId);
snapshot.setProductionOrderRoutingOperationId(routingOperationId);
snapshot.setTechnologyOperationId(operationParam.getTechnologyOperationId());
snapshot.setTechnologyOperationParamId(operationParam.getId());
snapshot.setParamId(technologyParam.getId());
snapshot.setParamCode(technologyParam.getParamCode());
snapshot.setParamName(technologyParam.getParamName());
snapshot.setParamType(technologyParam.getParamType());
snapshot.setParamFormat(technologyParam.getParamFormat());
snapshot.setUnit(technologyParam.getUnit());
snapshot.setIsRequired(technologyParam.getIsRequired());
snapshot.setRemark(technologyParam.getRemark());
snapshot.setStandardValue(operationParam.getStandardValue());
productionOrderRoutingOperationParamMapper.insert(snapshot);
}
}
private String buildRoutingOperationBucketKey(Long operationId, Long outputProductModelId) {
return String.valueOf(operationId) + "#" + String.valueOf(outputProductModelId);
}
private TechnologyOperation getTechnologyOperation(Long technologyOperationId) {
if (technologyOperationId == null) {
return null;
}
return technologyOperationMapper.selectById(technologyOperationId);
}
private String generateNextTaskNo() {
String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
ProductionOperationTask latestTask = productionOperationTaskMapper.selectOne(
Wrappers.lambdaQuery()
.likeRight(ProductionOperationTask::getWorkOrderNo, "GD" + datePrefix)
.orderByDesc(ProductionOperationTask::getWorkOrderNo)
.last("limit 1"));
int sequenceNumber = 1;
if (latestTask != null && latestTask.getWorkOrderNo() != null && latestTask.getWorkOrderNo().startsWith("GD" + datePrefix)) {
try {
sequenceNumber = Integer.parseInt(latestTask.getWorkOrderNo().substring(("GD" + datePrefix).length())) + 1;
} catch (NumberFormatException ignored) {
sequenceNumber = 1;
}
}
return "GD" + String.format("%s%03d", datePrefix, sequenceNumber);
}
private BigDecimal defaultDecimal(BigDecimal value) {
return value == null ? BigDecimal.ZERO : value;
}
private int compareDecimal(BigDecimal left, BigDecimal right) {
return defaultDecimal(left).compareTo(defaultDecimal(right));
}
}