package com.ruoyi.production.service.impl;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.ruoyi.common.exception.ServiceException;
|
import com.ruoyi.common.utils.DateUtils;
|
import com.ruoyi.common.utils.SecurityUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.other.mapper.TempFileMapper;
|
import com.ruoyi.other.pojo.TempFile;
|
import com.ruoyi.production.dto.ProductionProductRouteItemDto;
|
import com.ruoyi.production.dto.ProductionProductRouteItemParamDto;
|
import com.ruoyi.production.dto.ProductionRecordDto;
|
import com.ruoyi.production.enums.ProductOrderStatusEnum;
|
import com.ruoyi.production.pojo.*;
|
import com.ruoyi.production.service.*;
|
import com.ruoyi.production.vo.ProductionOrderRouteItemParamVo;
|
import com.ruoyi.production.vo.ProductionOrderRouteItemVo;
|
import com.ruoyi.production.vo.ProductionOrderStructureVo;
|
import com.ruoyi.production.vo.ProductionRecordVo;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.io.FilenameUtils;
|
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.io.IOException;
|
import java.math.BigDecimal;
|
import java.nio.file.Files;
|
import java.nio.file.Path;
|
import java.nio.file.Paths;
|
import java.nio.file.StandardCopyOption;
|
import java.time.LocalDate;
|
import java.time.LocalDateTime;
|
import java.time.format.DateTimeFormatter;
|
import java.util.ArrayList;
|
import java.util.List;
|
import java.util.UUID;
|
import java.util.stream.Collectors;
|
|
/**
|
* <br>
|
* 生产报工记录Service实现类
|
* </br>
|
*
|
* @author deslrey
|
* @version 1.0
|
* @since 2026/03/23 10:23
|
*/
|
@Slf4j
|
@Service
|
public class ProductionRecordServiceImpl implements ProductionRecordService {
|
|
@Value("${file.upload-dir}")
|
private String uploadDir;
|
|
@Autowired
|
private ProductionProductMainService productionProductMainService;
|
|
@Autowired
|
private ProductionProductInputService productionProductInputService;
|
|
@Autowired
|
private ProductionProductOutputService productionProductOutputService;
|
|
@Autowired
|
private IProductionProductRouteItemService productionProductRouteItemService;
|
|
@Autowired
|
private IProductionProductRouteItemParamService productionProductRouteItemParamService;
|
|
@Autowired
|
private IProductionProductRouteItemFileService productionProductRouteItemFileService;
|
|
@Autowired
|
private ProductOrderService productOrderService;
|
|
@Autowired
|
private IProductionOrderRouteItemService productionOrderRouteItemService;
|
|
@Autowired
|
private IProductionOrderRouteItemParamService productionOrderRouteItemParamService;
|
|
@Autowired
|
private IProductionOrderStructureService productionOrderStructureService;
|
|
@Autowired
|
private ProductProcessService productProcessService;
|
|
@Autowired
|
private ProductMaterialSkuService productMaterialSkuService;
|
|
@Autowired
|
private ProductMaterialService productMaterialService;
|
|
@Autowired
|
private TempFileMapper tempFileMapper;
|
|
@Override
|
public ProductionRecordVo productRouteItem(Long productOrderId) {
|
if (productOrderId == null) {
|
throw new ServiceException("请选择生产订单再新增报工");
|
}
|
|
// 查询出生产订单绑定的工艺路线
|
ProductOrder productOrder = productOrderService.getById(productOrderId);
|
if (productOrder == null) {
|
throw new ServiceException("未查询到该生产订单的信息");
|
}
|
// 通过工艺路线查询出绑定的工序及参数
|
List<ProductionOrderRouteItem> productionOrderRouteItemList = productionOrderRouteItemService.list(new LambdaQueryWrapper<ProductionOrderRouteItem>()
|
.eq(ProductionOrderRouteItem::getOrderId, productOrderId)
|
.eq(ProductionOrderRouteItem::getRouteId, productOrder.getRouteId()));
|
|
if (productionOrderRouteItemList == null || productionOrderRouteItemList.isEmpty()) {
|
throw new ServiceException("该生产订单绑定的工艺路线无工序");
|
}
|
|
ProductionRecordVo productionRecordVo = new ProductionRecordVo();
|
productionRecordVo.setProductOrderId(productOrderId);
|
productionRecordVo.setProductRouteId(productOrder.getRouteId());
|
|
List<ProductionOrderRouteItemVo> productionOrderRouteItemVoList = new ArrayList<>();
|
|
// 根据绑定的工序查询出工序参数及BOM需要消耗的产品
|
for (ProductionOrderRouteItem orderRouteItem : productionOrderRouteItemList) {
|
ProductionOrderRouteItemVo productionOrderRouteItemVo = new ProductionOrderRouteItemVo();
|
productionOrderRouteItemVo.setProcessId(orderRouteItem.getProcessId());
|
|
if (orderRouteItem.getProcessId() != null) {
|
ProductProcess process = productProcessService.getById(orderRouteItem.getProcessId());
|
if (process != null) {
|
productionOrderRouteItemVo.setProcessName(process.getName());
|
}
|
}
|
|
List<ProductionOrderRouteItemParam> orderRouteItemParamList = productionOrderRouteItemParamService.list(new LambdaQueryWrapper<ProductionOrderRouteItemParam>()
|
.eq(ProductionOrderRouteItemParam::getOrderId, productOrderId)
|
.eq(ProductionOrderRouteItemParam::getRouteItemId, orderRouteItem.getId()));
|
|
if (orderRouteItemParamList != null && !orderRouteItemParamList.isEmpty()) {
|
List<ProductionOrderRouteItemParamVo> paraVoList = orderRouteItemParamList.stream().map(param -> {
|
ProductionOrderRouteItemParamVo paraVo = new ProductionOrderRouteItemParamVo();
|
BeanUtils.copyProperties(param, paraVo);
|
paraVo.setParamFormat(DateUtils.toUpperCasePattern(paraVo.getParamFormat()));
|
return paraVo;
|
}).collect(Collectors.toList());
|
productionOrderRouteItemVo.setOrderRouteItemParaVos(paraVoList);
|
}
|
|
List<ProductionOrderStructure> orderStructureList = productionOrderStructureService.list(new LambdaQueryWrapper<ProductionOrderStructure>()
|
.eq(ProductionOrderStructure::getOrderId, productOrderId)
|
.eq(ProductionOrderStructure::getProcessId, orderRouteItem.getProcessId()));
|
|
if (orderStructureList != null && !orderStructureList.isEmpty()) {
|
List<ProductionOrderStructureVo> structureVoList = orderStructureList.stream().map(struct -> {
|
ProductionOrderStructureVo structureVo = new ProductionOrderStructureVo();
|
BeanUtils.copyProperties(struct, structureVo);
|
// 查询出产品的名称/模型
|
ProductMaterialSku productMaterialSku = productMaterialSkuService.getById(structureVo.getProductModelId());
|
ProductMaterial productMaterial = productMaterialService.getById(productMaterialSku.getProductId());
|
structureVo.setProductName(productMaterial.getProductName());
|
structureVo.setModel(productMaterialSku.getModel());
|
return structureVo;
|
}).collect(Collectors.toList());
|
productionOrderRouteItemVo.setOrderStructureVos(structureVoList);
|
}
|
|
// 每一个工序的参数、BOM消耗产品
|
productionOrderRouteItemVoList.add(productionOrderRouteItemVo);
|
}
|
|
productionRecordVo.setProductionOrderRouteItemVos(productionOrderRouteItemVoList);
|
return productionRecordVo;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void addProductionRecordService(ProductionRecordDto dto) {
|
if (dto == null) {
|
throw new ServiceException("报工失败,数据不能为空");
|
}
|
if (dto.getProductOrderId() == null) {
|
throw new ServiceException("报工失败,生产订单ID不能为空");
|
}
|
if (dto.getProductId() == null) {
|
throw new ServiceException("报工失败,产品信息不能为空");
|
}
|
if (StringUtils.isEmpty(dto.getPostName()) || StringUtils.isEmpty(dto.getSchedule())) {
|
throw new ServiceException("报工失败,岗位人员/班次信息不能为空");
|
}
|
|
// 更新生产订单数据
|
ProductOrder productOrder = productOrderService.getById(dto.getProductOrderId());
|
if (productOrder == null) {
|
throw new ServiceException("报工失败,生产订单不存在");
|
}
|
|
// 当前报工合格数量
|
BigDecimal qualifiedQty = dto.getQualifiedQuantity() == null ? BigDecimal.ZERO : dto.getQualifiedQuantity();
|
// 已完成数量
|
BigDecimal completeQty = productOrder.getCompleteQuantity() == null ? BigDecimal.ZERO : productOrder.getCompleteQuantity();
|
// 累加(只算合格)
|
BigDecimal newCompleteQty = completeQty.add(qualifiedQty);
|
productOrder.setCompleteQuantity(newCompleteQty);
|
// 需求数量
|
BigDecimal totalQty = productOrder.getQuantity() == null ? BigDecimal.ZERO : productOrder.getQuantity();
|
// 剩余可报工数量
|
BigDecimal remainQty = totalQty.subtract(completeQty);
|
// 本次报工不能超过剩余数量
|
if (qualifiedQty.compareTo(remainQty) > 0) {
|
throw new ServiceException("报工失败,本次报工数量不能大于剩余可报工数量");
|
}
|
// 设置开始时间(第一次报工)
|
if (productOrder.getStartTime() == null) {
|
productOrder.setStartTime(LocalDateTime.now());
|
}
|
// 状态判断
|
if (newCompleteQty.compareTo(totalQty) >= 0 && totalQty.compareTo(BigDecimal.ZERO) > 0) {
|
productOrder.setStatus(ProductOrderStatusEnum.FINISHED.getCode());
|
productOrder.setEndTime(LocalDateTime.now());
|
} else {
|
productOrder.setStatus(ProductOrderStatusEnum.RUNNING.getCode());
|
}
|
boolean update = productOrderService.updateById(productOrder);
|
if (!update) {
|
throw new ServiceException("报工失败,生产订单更新失败");
|
}
|
|
// 完成报工主表-投入表-产出表数据
|
ProductionProductMain productionProductMain = new ProductionProductMain();
|
productionProductMain.setProductNo("BG" + UUID.randomUUID());
|
productionProductMain.setProductOrderId(dto.getProductOrderId());
|
productionProductMain.setSchedule(dto.getSchedule());
|
boolean result = productionProductMainService.save(productionProductMain);
|
if (!result) {
|
throw new ServiceException("报工失败,数据存储失败");
|
}
|
|
ProductionProductInput productionProductInput = new ProductionProductInput();
|
productionProductInput.setProductMainId(productionProductMain.getId());
|
productionProductInput.setProductModelId(dto.getProductId());
|
productionProductInput.setQuantity(dto.getQuantity());
|
result = productionProductInputService.save(productionProductInput);
|
if (!result) {
|
throw new ServiceException("报工失败,生产投入存储失败");
|
}
|
|
ProductionProductOutput productionProductOutput = new ProductionProductOutput();
|
productionProductOutput.setProductMainId(productionProductMain.getId());
|
productionProductOutput.setProductModelId(dto.getProductId());
|
productionProductOutput.setQuantity(dto.getQualifiedQuantity());
|
productionProductOutput.setScrapQty(dto.getUnqualifiedQuantity());
|
result = productionProductOutputService.save(productionProductOutput);
|
if (!result) {
|
throw new ServiceException("报工失败,生产产出存储失败");
|
}
|
|
// 处理工序
|
List<ProductionProductRouteItemDto> productionProductRouteItemDtoList = dto.getProductionProductRouteItemDtoList();
|
if (productionProductRouteItemDtoList == null || productionProductRouteItemDtoList.isEmpty()) {
|
throw new ServiceException("报工失败,工序参数不能为空");
|
}
|
for (ProductionProductRouteItemDto productRouteItemDto : productionProductRouteItemDtoList) {
|
// 处理工序主表
|
ProductionProductRouteItem productRouteItemEntity = new ProductionProductRouteItem();
|
BeanUtils.copyProperties(productRouteItemDto, productRouteItemEntity, "id");
|
productRouteItemEntity.setProductMainId(productionProductMain.getId());
|
productionProductRouteItemService.save(productRouteItemEntity);
|
|
// 处理参数及消耗产品
|
List<ProductionProductRouteItemParamDto> productionProductRouteItemParamDtoList = productRouteItemDto.getProductionProductRouteItemParamDtoList();
|
if (productionProductRouteItemParamDtoList != null && !productionProductRouteItemParamDtoList.isEmpty()) {
|
for (ProductionProductRouteItemParamDto productRouteItemParamDto : productionProductRouteItemParamDtoList) {
|
ProductionProductRouteItemParam paramEntity = new ProductionProductRouteItemParam();
|
BeanUtils.copyProperties(productRouteItemParamDto, paramEntity, "id");
|
paramEntity.setProductionProductRouteItemId(productRouteItemEntity.getId());
|
if (paramEntity.getProductId() != null) {
|
} else {
|
ProductionOrderRouteItemParam productionOrderRouteItemParam = productionOrderRouteItemParamService.getById(productRouteItemParamDto.getId());
|
paramEntity.setParamName(productionOrderRouteItemParam.getParamName());
|
paramEntity.setParamType(productionOrderRouteItemParam.getParamType());
|
paramEntity.setParamFormat(productionOrderRouteItemParam.getParamFormat());
|
paramEntity.setValueMode(productionOrderRouteItemParam.getValueMode());
|
}
|
|
productionProductRouteItemParamService.save(paramEntity);
|
}
|
}
|
|
// 处理工序上传的附件
|
List<String> files = productRouteItemDto.getFiles();
|
if (files != null && !files.isEmpty()) {
|
for (String tempId : files) {
|
TempFile tempFile = tempFileMapper.selectById(tempId);
|
if (tempFile == null) {
|
log.warn("未找到临时文件记录: {}", tempId);
|
continue;
|
}
|
|
try {
|
// 正式目录路径(按日期分组)
|
String formalDir = uploadDir + LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE);
|
Path formalDirPath = Paths.get(formalDir);
|
if (!Files.exists(formalDirPath)) {
|
Files.createDirectories(formalDirPath);
|
}
|
|
// 正式文件名
|
String originalFilename = tempFile.getOriginalName();
|
String fileExtension = FilenameUtils.getExtension(originalFilename);
|
String formalFilename = productRouteItemEntity.getId() + "_" +
|
System.currentTimeMillis() + "_" +
|
UUID.randomUUID().toString().substring(0, 8) +
|
(StringUtils.hasText(fileExtension) ? "." + fileExtension : "");
|
|
Path formalFilePath = formalDirPath.resolve(formalFilename);
|
|
// 文件迁移 (复制+删除)
|
Files.copy(Paths.get(tempFile.getTempPath()), formalFilePath, StandardCopyOption.REPLACE_EXISTING);
|
Files.deleteIfExists(Paths.get(tempFile.getTempPath()));
|
|
// 保存报工附件记录
|
ProductionProductRouteItemFile fileEntity = new ProductionProductRouteItemFile();
|
fileEntity.setProductionProductRouteItemId(productRouteItemEntity.getId());
|
fileEntity.setFileName(originalFilename);
|
fileEntity.setFileUrl(formalFilePath.toString());
|
fileEntity.setFileSuffix(fileExtension);
|
fileEntity.setFileSize(Files.size(formalFilePath));
|
fileEntity.setCreateTime(LocalDateTime.now());
|
fileEntity.setTenantId(SecurityUtils.getLoginUser().getTenantId());
|
productionProductRouteItemFileService.save(fileEntity);
|
|
// 删除临时文件记录
|
tempFileMapper.deleteById(tempId);
|
log.info("工序附件迁移成功: {} -> {}", tempFile.getTempPath(), formalFilePath);
|
|
} catch (IOException e) {
|
log.error("工序附件迁移失败: {}", tempFile.getTempPath(), e);
|
throw new ServiceException("工序附件处理异常: " + e.getMessage());
|
}
|
}
|
}
|
}
|
}
|
|
}
|