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.*;
|
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 totalQty = productOrder.getQuantity() == null ? BigDecimal.ZERO : productOrder.getQuantity();
|
// 剩余可报工数量
|
BigDecimal remainQty = totalQty.subtract(completeQty);
|
// 本次报工合格数量不能超过剩余数量(校验必须在累加前执行)
|
if (qualifiedQty.compareTo(remainQty) > 0) {
|
throw new ServiceException("报工失败,本次报工数量不能大于剩余可报工数量,剩余报工数量:[" + remainQty + "]");
|
}
|
// 历史已完成 + 本次合格数量
|
BigDecimal newCompleteQty = completeQty.add(qualifiedQty);
|
productOrder.setCompleteQuantity(newCompleteQty);
|
// 设置开始时间(第一次报工)
|
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(productionProductMainService.generateProductNo());
|
productionProductMain.setProductOrderId(dto.getProductOrderId());
|
productionProductMain.setSchedule(dto.getSchedule());
|
productionProductMain.setPostName(dto.getPostName());
|
productionProductMain.setReportingTime(LocalDateTime.now());
|
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());
|
paramEntity.setOrderItemParamId(productRouteItemParamDto.getId());
|
if (paramEntity.getProductId() == null) {
|
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());
|
}
|
}
|
}
|
}
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void deleteProductMain(Long productMainId) {
|
if (productMainId == null) {
|
throw new ServiceException("删除失败,报工ID不能为空");
|
}
|
|
// 校验报工主表是否存在
|
ProductionProductMain productMain = productionProductMainService.getById(productMainId);
|
if (productMain == null) {
|
throw new ServiceException("删除失败,报工记录不存在");
|
}
|
|
// 查询该报工下所有工序记录
|
List<ProductionProductRouteItem> routeItemList = productionProductRouteItemService.list(new LambdaQueryWrapper<ProductionProductRouteItem>()
|
.eq(ProductionProductRouteItem::getProductMainId, productMainId));
|
|
if (routeItemList != null && !routeItemList.isEmpty()) {
|
List<Long> routeItemIds = routeItemList.stream()
|
.map(ProductionProductRouteItem::getId)
|
.collect(Collectors.toList());
|
|
// 查询并删除每个工序下的附件
|
List<ProductionProductRouteItemFile> fileList = productionProductRouteItemFileService.list(new LambdaQueryWrapper<ProductionProductRouteItemFile>()
|
.in(ProductionProductRouteItemFile::getProductionProductRouteItemId, routeItemIds));
|
|
if (fileList != null && !fileList.isEmpty()) {
|
for (ProductionProductRouteItemFile file : fileList) {
|
if (StringUtils.hasText(file.getFileUrl())) {
|
try {
|
Files.deleteIfExists(Paths.get(file.getFileUrl()));
|
} catch (IOException e) {
|
log.warn("删除附件文件失败: {}", file.getFileUrl(), e);
|
}
|
}
|
}
|
productionProductRouteItemFileService.remove(new LambdaQueryWrapper<ProductionProductRouteItemFile>()
|
.in(ProductionProductRouteItemFile::getProductionProductRouteItemId, routeItemIds));
|
}
|
|
// 删除工序参数
|
productionProductRouteItemParamService.remove(new LambdaQueryWrapper<ProductionProductRouteItemParam>()
|
.in(ProductionProductRouteItemParam::getProductionProductRouteItemId, routeItemIds));
|
|
// 删除工序记录
|
productionProductRouteItemService.remove(new LambdaQueryWrapper<ProductionProductRouteItem>()
|
.eq(ProductionProductRouteItem::getProductMainId, productMainId));
|
}
|
|
// 删除投入表
|
productionProductInputService.remove(new LambdaQueryWrapper<ProductionProductInput>()
|
.eq(ProductionProductInput::getProductMainId, productMainId));
|
|
// 回滚生产订单完成数量
|
ProductionProductOutput output = productionProductOutputService.getOne(new LambdaQueryWrapper<ProductionProductOutput>()
|
.eq(ProductionProductOutput::getProductMainId, productMainId)
|
.last("LIMIT 1"));
|
|
ProductOrder productOrder = productOrderService.getById(productMain.getProductOrderId());
|
if (productOrder == null) {
|
throw new ServiceException("删除失败,关联的生产订单不存在");
|
}
|
|
BigDecimal qualifiedQty = (output != null && output.getQuantity() != null)
|
? output.getQuantity() : BigDecimal.ZERO;
|
BigDecimal currentCompleteQty = productOrder.getCompleteQuantity() == null
|
? BigDecimal.ZERO : productOrder.getCompleteQuantity();
|
BigDecimal totalQty = productOrder.getQuantity() == null ? BigDecimal.ZERO : productOrder.getQuantity();
|
|
// 扣减本条报工贡献的合格数量,不允许出现负数
|
BigDecimal updatedCompleteQty = currentCompleteQty.subtract(qualifiedQty).max(BigDecimal.ZERO);
|
productOrder.setCompleteQuantity(updatedCompleteQty);
|
|
// 重新判断订单状态
|
if (updatedCompleteQty.compareTo(totalQty) >= 0 && totalQty.compareTo(BigDecimal.ZERO) > 0) {
|
// 完成数 >= 需求数 → 已完成
|
productOrder.setStatus(ProductOrderStatusEnum.FINISHED.getCode());
|
} else if (updatedCompleteQty.compareTo(BigDecimal.ZERO) == 0) {
|
// 完成数归零 → 回到待开始,清空开始/结束时间
|
productOrder.setStatus(ProductOrderStatusEnum.WAIT.getCode());
|
productOrder.setStartTime(null);
|
productOrder.setEndTime(null);
|
} else {
|
// 完成数介于 0 ~ 需求数之间 → 进行中
|
productOrder.setStatus(ProductOrderStatusEnum.RUNNING.getCode());
|
productOrder.setEndTime(null);
|
}
|
productOrderService.updateById(productOrder);
|
|
// 删除产出表
|
productionProductOutputService.remove(new LambdaQueryWrapper<ProductionProductOutput>()
|
.eq(ProductionProductOutput::getProductMainId, productMainId));
|
|
// 删除报工主表
|
productionProductMainService.removeById(productMainId);
|
log.info("报工记录删除成功,productMainId={}", productMainId);
|
}
|
|
@Override
|
public ProductionRecordDto detailProductMain(Long productMainId) {
|
if (productMainId == null) {
|
throw new ServiceException("查询失败,报工ID不能为空");
|
}
|
|
// 查询报工主表
|
ProductionProductMain productMain = productionProductMainService.getById(productMainId);
|
if (productMain == null) {
|
throw new ServiceException("查询失败,报工记录不存在");
|
}
|
|
ProductionRecordDto dto = new ProductionRecordDto();
|
dto.setProductMainId(productMainId);
|
dto.setProductOrderId(productMain.getProductOrderId());
|
dto.setPostName(productMain.getPostName());
|
dto.setSchedule(productMain.getSchedule());
|
dto.setReportingTime(productMain.getReportingTime());
|
dto.setCreateTime(productMain.getCreateTime());
|
dto.setUpdateTime(productMain.getUpdateTime());
|
|
// 生产订单信息
|
ProductOrder productOrder = productOrderService.getById(productMain.getProductOrderId());
|
if (productOrder == null) {
|
throw new ServiceException("查询失败,未查询到生产订单信息");
|
}
|
dto.setNpsNo(productOrder.getNpsNo());
|
|
/// 产品信息
|
ProductMaterialSkuDto productMaterialSkuDto = productMaterialService.selectProductByProductMainId(productOrder.getId());
|
dto.setProductName(productMaterialSkuDto.getProductName());
|
dto.setMaterialCode(productMaterialSkuDto.getMaterialCode());
|
dto.setModel(productMaterialSkuDto.getModel());
|
|
// 查询投入表(获取产品ID和投入数量)
|
ProductionProductInput input = productionProductInputService.getOne(
|
new LambdaQueryWrapper<ProductionProductInput>()
|
.eq(ProductionProductInput::getProductMainId, productMainId)
|
.last("LIMIT 1"));
|
if (input != null) {
|
dto.setProductId(input.getProductModelId());
|
dto.setQuantity(input.getQuantity());
|
}
|
|
// 查询产出表(获取合格/不合格数量)
|
ProductionProductOutput output = productionProductOutputService.getOne(
|
new LambdaQueryWrapper<ProductionProductOutput>()
|
.eq(ProductionProductOutput::getProductMainId, productMainId)
|
.last("LIMIT 1"));
|
if (output != null) {
|
dto.setQualifiedQuantity(output.getQuantity());
|
dto.setUnqualifiedQuantity(output.getScrapQty());
|
}
|
|
// 查询工序列表
|
List<ProductionProductRouteItem> routeItemList = productionProductRouteItemService.list(
|
new LambdaQueryWrapper<ProductionProductRouteItem>()
|
.eq(ProductionProductRouteItem::getProductMainId, productMainId));
|
|
if (routeItemList != null && !routeItemList.isEmpty()) {
|
List<ProductionProductRouteItemDto> routeItemDtoList = routeItemList.stream().map(routeItem -> {
|
ProductionProductRouteItemDto routeItemDto = new ProductionProductRouteItemDto();
|
BeanUtils.copyProperties(routeItem, routeItemDto);
|
|
// 查询工序参数
|
List<ProductionProductRouteItemParam> paramList = productionProductRouteItemParamService.list(
|
new LambdaQueryWrapper<ProductionProductRouteItemParam>()
|
.eq(ProductionProductRouteItemParam::getProductionProductRouteItemId, routeItem.getId()));
|
if (paramList != null && !paramList.isEmpty()) {
|
List<ProductionProductRouteItemParamDto> paramDtoList = paramList.stream().map(param -> {
|
ProductionProductRouteItemParamDto paramDto = new ProductionProductRouteItemParamDto();
|
BeanUtils.copyProperties(param, paramDto);
|
if (paramDto.getProductId() != null) {
|
ProductMaterialSkuDto materialSkuDto = productMaterialService.selectProductByModelId(paramDto.getProductId());
|
productMaterialService.selectProductByModelId(paramDto.getProductId());
|
paramDto.setParamName(materialSkuDto.getProductName());
|
}
|
return paramDto;
|
}).collect(Collectors.toList());
|
routeItemDto.setProductionProductRouteItemParamDtoList(paramDtoList);
|
}
|
|
// 查询工序附件
|
List<ProductionProductRouteItemFile> fileRecordList = productionProductRouteItemFileService.list(
|
new LambdaQueryWrapper<ProductionProductRouteItemFile>()
|
.eq(ProductionProductRouteItemFile::getProductionProductRouteItemId, routeItem.getId()));
|
if (fileRecordList != null && !fileRecordList.isEmpty()) {
|
List<ProductionProductRouteItemFileDto> fileDtoList = fileRecordList.stream().map(file -> {
|
ProductionProductRouteItemFileDto fileDto = new ProductionProductRouteItemFileDto();
|
BeanUtils.copyProperties(file, fileDto);
|
return fileDto;
|
}).collect(Collectors.toList());
|
routeItemDto.setFileList(fileDtoList);
|
}
|
|
return routeItemDto;
|
}).collect(Collectors.toList());
|
|
dto.setProductionProductRouteItemDtoList(routeItemDtoList);
|
}
|
|
return dto;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void editProductMain(ProductionRecordDto dto) {
|
if (dto == null || dto.getProductMainId() == null) {
|
throw new ServiceException("编辑失败,报工ID不能为空");
|
}
|
if (dto.getProductId() == null) {
|
throw new ServiceException("编辑失败,产品信息不能为空");
|
}
|
if (StringUtils.isEmpty(dto.getPostName()) || StringUtils.isEmpty(dto.getSchedule())) {
|
throw new ServiceException("编辑失败,岗位人员/班次信息不能为空");
|
}
|
|
Long productMainId = dto.getProductMainId();
|
|
// 查询报工主表是否存在
|
ProductionProductMain productMain = productionProductMainService.getById(productMainId);
|
if (productMain == null) {
|
throw new ServiceException("编辑失败,报工记录不存在");
|
}
|
|
// 回滚生产订单的合格数量
|
ProductionProductOutput oldOutput = productionProductOutputService.getOne(new LambdaQueryWrapper<ProductionProductOutput>()
|
.eq(ProductionProductOutput::getProductMainId, productMainId)
|
.last("LIMIT 1"));
|
|
ProductOrder productOrder = productOrderService.getById(productMain.getProductOrderId());
|
if (productOrder == null) {
|
throw new ServiceException("编辑失败,关联的生产订单不存在");
|
}
|
|
BigDecimal oldQualifiedQty = (oldOutput != null && oldOutput.getQuantity() != null)
|
? oldOutput.getQuantity() : BigDecimal.ZERO;
|
BigDecimal newQualifiedQty = dto.getQualifiedQuantity() == null ? BigDecimal.ZERO : dto.getQualifiedQuantity();
|
BigDecimal currentCompleteQty = productOrder.getCompleteQuantity() == null
|
? BigDecimal.ZERO : productOrder.getCompleteQuantity();
|
BigDecimal totalQty = productOrder.getQuantity() == null ? BigDecimal.ZERO : productOrder.getQuantity();
|
|
// 回滚旧值,计算本次编辑后的新完成数量
|
BigDecimal baseQty = currentCompleteQty.subtract(oldQualifiedQty);
|
BigDecimal updatedCompleteQty = baseQty.add(newQualifiedQty);
|
|
// 新的合格数量不能超过(需求数量 - 报工总完成数量)
|
if (newQualifiedQty.compareTo(totalQty.subtract(baseQty)) > 0) {
|
throw new ServiceException("编辑失败,本次报工合格数量不能大于剩余可报工数量");
|
}
|
|
// 重新判断生产订单状态
|
productOrder.setCompleteQuantity(updatedCompleteQty);
|
if (updatedCompleteQty.compareTo(totalQty) >= 0 && totalQty.compareTo(BigDecimal.ZERO) > 0) {
|
productOrder.setStatus(ProductOrderStatusEnum.FINISHED.getCode());
|
productOrder.setEndTime(LocalDateTime.now());
|
} else {
|
productOrder.setStatus(ProductOrderStatusEnum.RUNNING.getCode());
|
productOrder.setEndTime(null);
|
}
|
productOrderService.updateById(productOrder);
|
|
// 更新报工主表
|
productMain.setPostName(dto.getPostName());
|
productMain.setSchedule(dto.getSchedule());
|
productMain.setReportingTime(dto.getReportingTime());
|
productionProductMainService.updateById(productMain);
|
|
// 更新投入表
|
ProductionProductInput input = productionProductInputService.getOne(new LambdaQueryWrapper<ProductionProductInput>()
|
.eq(ProductionProductInput::getProductMainId, productMainId)
|
.last("LIMIT 1"));
|
if (input != null) {
|
input.setProductModelId(dto.getProductId());
|
input.setQuantity(dto.getQuantity());
|
productionProductInputService.updateById(input);
|
}
|
|
// 更新产出表
|
if (oldOutput != null) {
|
oldOutput.setProductModelId(dto.getProductId());
|
oldOutput.setQuantity(dto.getQualifiedQuantity());
|
oldOutput.setScrapQty(dto.getUnqualifiedQuantity());
|
productionProductOutputService.updateById(oldOutput);
|
}
|
|
// 处理工序列表
|
List<ProductionProductRouteItemDto> routeItemDtoList = dto.getProductionProductRouteItemDtoList();
|
if (routeItemDtoList == null || routeItemDtoList.isEmpty()) {
|
throw new ServiceException("编辑失败,工序参数不能为空");
|
}
|
|
for (ProductionProductRouteItemDto routeItemDto : routeItemDtoList) {
|
// 更新已有工序
|
ProductionProductRouteItem routeItemEntity = productionProductRouteItemService.getById(routeItemDto.getId());
|
if (routeItemEntity == null) {
|
log.error("编辑失败,工序记录不存在,ID={}", routeItemDto.getId());
|
throw new ServiceException("编辑失败,工序记录不存在");
|
}
|
BeanUtils.copyProperties(routeItemDto, routeItemEntity, "id", "productMainId", "createTime", "tenantId");
|
productionProductRouteItemService.updateById(routeItemEntity);
|
|
final Long routeItemId = routeItemEntity.getId();
|
|
// 处理工序参数: 先删除该工序下所有旧参数,再重新插入传入的参数
|
productionProductRouteItemParamService.remove(new LambdaQueryWrapper<ProductionProductRouteItemParam>()
|
.eq(ProductionProductRouteItemParam::getProductionProductRouteItemId, routeItemId));
|
|
List<ProductionProductRouteItemParamDto> paramDtoList = routeItemDto.getProductionProductRouteItemParamDtoList();
|
if (paramDtoList != null && !paramDtoList.isEmpty()) {
|
for (ProductionProductRouteItemParamDto paramDto : paramDtoList) {
|
ProductionProductRouteItemParam paramEntity = new ProductionProductRouteItemParam();
|
BeanUtils.copyProperties(paramDto, paramEntity, "id");
|
paramEntity.setProductionProductRouteItemId(routeItemId);
|
if (paramEntity.getProductId() == null && paramDto.getId() != null) {
|
ProductionOrderRouteItemParam orderParam = productionOrderRouteItemParamService.getById(paramDto.getId());
|
if (orderParam != null) {
|
paramEntity.setOrderItemParamId(orderParam.getId());
|
paramEntity.setParamName(orderParam.getParamName());
|
paramEntity.setParamType(orderParam.getParamType());
|
paramEntity.setParamFormat(orderParam.getParamFormat());
|
paramEntity.setValueMode(orderParam.getValueMode());
|
}
|
}
|
productionProductRouteItemParamService.save(paramEntity);
|
}
|
}
|
|
// 处理新上传的临时附件
|
List<String> newFiles = routeItemDto.getFiles();
|
if (newFiles != null && !newFiles.isEmpty()) {
|
for (String tempId : newFiles) {
|
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 = routeItemId + "_"
|
+ 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(routeItemId);
|
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());
|
}
|
}
|
}
|
List<Long> delFileIds = routeItemDto.getDelFileIds();
|
if (delFileIds != null && !delFileIds.isEmpty()) {
|
delFileIds.forEach(productionProductRouteItemFileService::deleteFile);
|
}
|
}
|
log.info("报工记录编辑成功,productMainId={}", productMainId);
|
}
|
}
|