package com.ruoyi.production.service.impl;
|
|
import cn.hutool.core.bean.BeanUtil;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.ruoyi.common.exception.ServiceException;
|
import com.ruoyi.production.bean.dto.ProductionOrderDto;
|
import com.ruoyi.production.bean.vo.ProductionOrderVo;
|
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.ProductionOrderService;
|
import com.ruoyi.technology.mapper.TechnologyBomMapper;
|
import com.ruoyi.technology.mapper.TechnologyBomStructureMapper;
|
import com.ruoyi.technology.mapper.TechnologyRoutingMapper;
|
import com.ruoyi.technology.mapper.TechnologyRoutingOperationMapper;
|
import com.ruoyi.technology.mapper.TechnologyRoutingOperationParamMapper;
|
import com.ruoyi.technology.pojo.TechnologyBom;
|
import com.ruoyi.technology.pojo.TechnologyBomStructure;
|
import com.ruoyi.technology.pojo.TechnologyRouting;
|
import com.ruoyi.technology.pojo.TechnologyRoutingOperation;
|
import com.ruoyi.technology.pojo.TechnologyRoutingOperationParam;
|
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.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Objects;
|
import java.util.stream.Collectors;
|
|
@Service
|
@Transactional(rollbackFor = Exception.class)
|
@RequiredArgsConstructor
|
public class ProductionOrderServiceImpl extends ServiceImpl<ProductionOrderMapper, ProductionOrder> implements ProductionOrderService {
|
|
private final ProductionOrderRoutingMapper productionOrderRoutingMapper;
|
private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper;
|
private final ProductionOrderRoutingOperationParamMapper productionOrderRoutingOperationParamMapper;
|
private final ProductionOperationTaskMapper productionOperationTaskMapper;
|
private final ProductionOrderBomMapper productionOrderBomMapper;
|
private final ProductionBomStructureMapper productionBomStructureMapper;
|
private final ProductionProductMainMapper productionProductMainMapper;
|
private final TechnologyRoutingMapper technologyRoutingMapper;
|
private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
|
private final TechnologyRoutingOperationParamMapper technologyRoutingOperationParamMapper;
|
private final TechnologyBomMapper technologyBomMapper;
|
private final TechnologyBomStructureMapper technologyBomStructureMapper;
|
|
@Override
|
public com.baomidou.mybatisplus.core.metadata.IPage<ProductionOrderVo> pageProductionOrder(Page<ProductionOrderDto> page, ProductionOrderDto dto) {
|
Page<ProductionOrder> entityPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
|
return this.page(entityPage, buildQueryWrapper(dto)).convert(item -> BeanUtil.copyProperties(item, ProductionOrderVo.class));
|
}
|
|
@Override
|
public List<ProductionOrderVo> listProductionOrder(ProductionOrderDto dto) {
|
return BeanUtil.copyToList(this.list(buildQueryWrapper(dto)), ProductionOrderVo.class);
|
}
|
|
@Override
|
public ProductionOrderVo getProductionOrderInfo(Long id) {
|
ProductionOrder item = this.getById(id);
|
return item == null ? null : BeanUtil.copyProperties(item, ProductionOrderVo.class);
|
}
|
|
@Override
|
public boolean saveProductionOrder(ProductionOrder productionOrder) {
|
ProductionOrder oldOrder = productionOrder.getId() == null ? null : this.getById(productionOrder.getId());
|
if (productionOrder.getNpsNo() == null || productionOrder.getNpsNo().trim().isEmpty()) {
|
productionOrder.setNpsNo(generateNextOrderNo());
|
}
|
if (productionOrder.getCompleteQuantity() == null) {
|
productionOrder.setCompleteQuantity(BigDecimal.ZERO);
|
}
|
boolean saved = this.saveOrUpdate(productionOrder);
|
if (!saved) {
|
return false;
|
}
|
boolean needSync = productionOrder.getTechnologyRoutingId() != null
|
&& (oldOrder == null
|
|| !Objects.equals(oldOrder.getTechnologyRoutingId(), productionOrder.getTechnologyRoutingId())
|
|| productionOrderRoutingMapper.selectCount(Wrappers.<ProductionOrderRouting>lambdaQuery()
|
.eq(ProductionOrderRouting::getProductionOrderId, productionOrder.getId())) == 0);
|
if (needSync) {
|
syncProductionOrderSnapshot(productionOrder.getId());
|
}
|
return true;
|
}
|
|
@Override
|
public boolean removeProductionOrder(List<Long> ids) {
|
if (ids == null || ids.isEmpty()) {
|
return false;
|
}
|
for (Long id : ids) {
|
clearProductionSnapshot(id);
|
}
|
return this.removeByIds(ids);
|
}
|
|
@Override
|
public int syncProductionOrderSnapshot(Long productionOrderId) {
|
ProductionOrder productionOrder = this.getById(productionOrderId);
|
if (productionOrder == null) {
|
throw new ServiceException("Production order not found");
|
}
|
if (productionOrder.getTechnologyRoutingId() == null) {
|
throw new ServiceException("technologyRoutingId is required");
|
}
|
TechnologyRouting technologyRouting = technologyRoutingMapper.selectById(productionOrder.getTechnologyRoutingId());
|
if (technologyRouting == null) {
|
throw new ServiceException("Technology routing not found");
|
}
|
clearProductionSnapshot(productionOrderId);
|
|
ProductionOrderRouting orderRouting = new ProductionOrderRouting();
|
orderRouting.setProductionOrderId(productionOrder.getId());
|
orderRouting.setTechnologyRoutingId(technologyRouting.getId());
|
orderRouting.setProductModelId(technologyRouting.getProductModelId());
|
orderRouting.setProcessRouteCode(technologyRouting.getProcessRouteCode());
|
orderRouting.setDescription(technologyRouting.getDescription());
|
orderRouting.setBomId(technologyRouting.getBomId());
|
productionOrderRoutingMapper.insert(orderRouting);
|
|
int syncedParamCount = 0;
|
List<TechnologyRoutingOperation> routingOperations = technologyRoutingOperationMapper.selectList(
|
Wrappers.<TechnologyRoutingOperation>lambdaQuery()
|
.eq(TechnologyRoutingOperation::getTechnologyRoutingId, technologyRouting.getId())
|
.orderByAsc(TechnologyRoutingOperation::getDragSort)
|
.orderByAsc(TechnologyRoutingOperation::getId));
|
for (TechnologyRoutingOperation sourceOperation : routingOperations) {
|
ProductionOrderRoutingOperation targetOperation = new ProductionOrderRoutingOperation();
|
targetOperation.setProductionOrderId(productionOrder.getId());
|
targetOperation.setTechnologyRoutingOperationId(sourceOperation.getId());
|
targetOperation.setTechnologyRoutingId(orderRouting.getId());
|
targetOperation.setProductModelId(sourceOperation.getProductModelId());
|
targetOperation.setDragSort(sourceOperation.getDragSort());
|
targetOperation.setIsQuality(sourceOperation.getIsQuality());
|
productionOrderRoutingOperationMapper.insert(targetOperation);
|
|
ProductionOperationTask task = new ProductionOperationTask();
|
task.setTechnologyRoutingOperationId(targetOperation.getId());
|
task.setProductionOrderId(productionOrder.getId());
|
task.setPlanQuantity(defaultDecimal(productionOrder.getQuantity()));
|
task.setCompleteQuantity(BigDecimal.ZERO);
|
task.setWorkOrderNo(generateNextTaskNo());
|
task.setStatus(1);
|
productionOperationTaskMapper.insert(task);
|
|
List<TechnologyRoutingOperationParam> sourceParams = technologyRoutingOperationParamMapper.selectList(
|
Wrappers.<TechnologyRoutingOperationParam>lambdaQuery()
|
.eq(TechnologyRoutingOperationParam::getTechnologyRoutingOperationId, sourceOperation.getId())
|
.orderByAsc(TechnologyRoutingOperationParam::getId));
|
for (TechnologyRoutingOperationParam sourceParam : sourceParams) {
|
ProductionOrderRoutingOperationParam targetParam = new ProductionOrderRoutingOperationParam();
|
targetParam.setProductionOrderId(productionOrder.getId());
|
targetParam.setTechnologyRoutingOperationId(targetOperation.getId());
|
targetParam.setTechnologyRoutingOperationParamId(sourceParam.getId());
|
targetParam.setParamId(sourceParam.getParamId());
|
targetParam.setTechnologyOperationId(sourceParam.getTechnologyOperationId());
|
targetParam.setTechnologyOperationParamId(sourceParam.getTechnologyOperationParamId());
|
targetParam.setParamCode(sourceParam.getParamCode());
|
targetParam.setParamName(sourceParam.getParamName());
|
targetParam.setParamType(sourceParam.getParamType());
|
targetParam.setParamFormat(sourceParam.getParamFormat());
|
targetParam.setUnit(sourceParam.getUnit());
|
targetParam.setIsRequired(sourceParam.getIsRequired());
|
targetParam.setRemark(sourceParam.getRemark());
|
targetParam.setStandardValue(sourceParam.getStandardValue());
|
productionOrderRoutingOperationParamMapper.insert(targetParam);
|
syncedParamCount++;
|
}
|
}
|
|
syncProductionOrderBomSnapshot(productionOrder, technologyRouting);
|
return syncedParamCount;
|
}
|
|
private void syncProductionOrderBomSnapshot(ProductionOrder productionOrder, TechnologyRouting technologyRouting) {
|
if (technologyRouting.getBomId() == null) {
|
return;
|
}
|
TechnologyBom technologyBom = technologyBomMapper.selectById(technologyRouting.getBomId());
|
if (technologyBom == null) {
|
throw new ServiceException("Technology BOM not found");
|
}
|
List<TechnologyBomStructure> structureList = technologyBomStructureMapper.selectList(
|
Wrappers.<TechnologyBomStructure>lambdaQuery()
|
.eq(TechnologyBomStructure::getBomId, technologyBom.getId())
|
.orderByAsc(TechnologyBomStructure::getId));
|
TechnologyBomStructure root = structureList.stream().filter(item -> item.getParentId() == null).findFirst().orElse(null);
|
|
ProductionOrderBom orderBom = new ProductionOrderBom();
|
orderBom.setProductionOrderId(productionOrder.getId());
|
orderBom.setBomId(Long.valueOf(technologyBom.getId()));
|
orderBom.setProductModelId(root != null ? root.getProductModelId() : productionOrder.getProductModelId());
|
orderBom.setTechnologyOperationId(root == null ? null : root.getOperationId());
|
orderBom.setUnitQuantity(root != null && root.getUnitQuantity() != null ? root.getUnitQuantity() : BigDecimal.ONE);
|
orderBom.setDemandedQuantity(root != null && root.getDemandedQuantity() != null ? root.getDemandedQuantity() : defaultDecimal(productionOrder.getQuantity()));
|
orderBom.setUnit(root == null ? null : root.getUnit());
|
productionOrderBomMapper.insert(orderBom);
|
|
Map<Long, Long> idMap = new HashMap<>();
|
for (TechnologyBomStructure source : structureList) {
|
ProductionBomStructure target = new ProductionBomStructure();
|
target.setProductionOrderId(productionOrder.getId());
|
target.setProductionOrderBomId(orderBom.getId());
|
target.setParentId(source.getParentId() == null ? null : idMap.get(source.getParentId()));
|
target.setProductModelId(source.getProductModelId());
|
target.setTechnologyOperationId(source.getOperationId());
|
target.setUnitQuantity(source.getUnitQuantity());
|
target.setDemandedQuantity(source.getDemandedQuantity());
|
target.setUnit(source.getUnit());
|
productionBomStructureMapper.insert(target);
|
idMap.put(source.getId(), target.getId());
|
}
|
}
|
|
private void clearProductionSnapshot(Long productionOrderId) {
|
List<Long> taskIds = productionOperationTaskMapper.selectList(
|
Wrappers.<ProductionOperationTask>lambdaQuery()
|
.eq(ProductionOperationTask::getProductionOrderId, productionOrderId))
|
.stream().map(ProductionOperationTask::getId).collect(Collectors.toList());
|
if (!taskIds.isEmpty()) {
|
boolean started = productionProductMainMapper.selectCount(
|
Wrappers.<ProductionProductMain>lambdaQuery()
|
.in(ProductionProductMain::getProductionOperationTaskId, taskIds)) > 0;
|
if (started) {
|
throw new ServiceException("Production order already started, snapshot cannot be regenerated");
|
}
|
productionOperationTaskMapper.delete(Wrappers.<ProductionOperationTask>lambdaQuery()
|
.eq(ProductionOperationTask::getProductionOrderId, productionOrderId));
|
}
|
productionOrderRoutingOperationParamMapper.delete(Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
|
.eq(ProductionOrderRoutingOperationParam::getProductionOrderId, productionOrderId));
|
productionOrderRoutingOperationMapper.delete(Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
|
.eq(ProductionOrderRoutingOperation::getProductionOrderId, productionOrderId));
|
productionOrderRoutingMapper.delete(Wrappers.<ProductionOrderRouting>lambdaQuery()
|
.eq(ProductionOrderRouting::getProductionOrderId, productionOrderId));
|
productionBomStructureMapper.delete(Wrappers.<ProductionBomStructure>lambdaQuery()
|
.eq(ProductionBomStructure::getProductionOrderId, productionOrderId));
|
productionOrderBomMapper.delete(Wrappers.<ProductionOrderBom>lambdaQuery()
|
.eq(ProductionOrderBom::getProductionOrderId, productionOrderId));
|
}
|
|
private LambdaQueryWrapper<ProductionOrder> buildQueryWrapper(ProductionOrderDto dto) {
|
ProductionOrder query = dto == null ? new ProductionOrder() : dto;
|
return Wrappers.<ProductionOrder>lambdaQuery()
|
.eq(query.getId() != null, ProductionOrder::getId, query.getId())
|
.eq(query.getSalesLedgerId() != null, ProductionOrder::getSalesLedgerId, query.getSalesLedgerId())
|
.eq(query.getProductModelId() != null, ProductionOrder::getProductModelId, query.getProductModelId())
|
.eq(query.getTechnologyRoutingId() != null, ProductionOrder::getTechnologyRoutingId, query.getTechnologyRoutingId())
|
.like(query.getNpsNo() != null && !query.getNpsNo().trim().isEmpty(), ProductionOrder::getNpsNo, query.getNpsNo())
|
.orderByDesc(ProductionOrder::getId);
|
}
|
|
private String generateNextOrderNo() {
|
String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
|
String prefix = "SC" + datePrefix;
|
ProductionOrder latestOrder = this.getOne(Wrappers.<ProductionOrder>lambdaQuery()
|
.likeRight(ProductionOrder::getNpsNo, prefix)
|
.orderByDesc(ProductionOrder::getNpsNo)
|
.last("limit 1"));
|
int sequence = 1;
|
if (latestOrder != null && latestOrder.getNpsNo() != null && latestOrder.getNpsNo().startsWith(prefix)) {
|
try {
|
sequence = Integer.parseInt(latestOrder.getNpsNo().substring(prefix.length())) + 1;
|
} catch (NumberFormatException ignored) {
|
sequence = 1;
|
}
|
}
|
return prefix + String.format("%04d", sequence);
|
}
|
|
private String generateNextTaskNo() {
|
String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
|
String prefix = "GD" + datePrefix;
|
ProductionOperationTask lastTask = productionOperationTaskMapper.selectOne(
|
Wrappers.<ProductionOperationTask>lambdaQuery()
|
.likeRight(ProductionOperationTask::getWorkOrderNo, prefix)
|
.orderByDesc(ProductionOperationTask::getWorkOrderNo)
|
.last("limit 1"));
|
int sequence = 1;
|
if (lastTask != null && lastTask.getWorkOrderNo() != null && lastTask.getWorkOrderNo().startsWith(prefix)) {
|
try {
|
sequence = Integer.parseInt(lastTask.getWorkOrderNo().substring(prefix.length())) + 1;
|
} catch (NumberFormatException ignored) {
|
sequence = 1;
|
}
|
}
|
return prefix + String.format("%03d", sequence);
|
}
|
|
private BigDecimal defaultDecimal(BigDecimal value) {
|
return value == null ? BigDecimal.ZERO : value;
|
}
|
}
|