package com.ruoyi.production.service.impl;
|
|
import com.alibaba.fastjson2.JSON;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
|
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.basic.mapper.ProductMapper;
|
import com.ruoyi.basic.mapper.ProductModelMapper;
|
import com.ruoyi.basic.pojo.Product;
|
import com.ruoyi.basic.pojo.ProductModel;
|
import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
|
import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
|
import com.ruoyi.common.exception.ServiceException;
|
import com.ruoyi.common.utils.SecurityUtils;
|
import com.ruoyi.common.utils.bean.BeanUtils;
|
import com.ruoyi.procurementrecord.utils.StockUtils;
|
import com.ruoyi.production.bean.dto.ProductionProductMainDto;
|
import com.ruoyi.production.enums.ProductOrderStatusEnum;
|
import com.ruoyi.production.mapper.*;
|
import com.ruoyi.production.pojo.*;
|
import com.ruoyi.production.service.ProductionProductMainService;
|
import com.ruoyi.project.system.domain.SysUser;
|
import com.ruoyi.project.system.mapper.SysUserMapper;
|
import com.ruoyi.quality.mapper.*;
|
import com.ruoyi.quality.pojo.*;
|
import com.ruoyi.stock.pojo.StockInRecord;
|
import com.ruoyi.stock.service.StockInRecordService;
|
import com.ruoyi.stock.dto.StockInventoryDto;
|
import com.ruoyi.stock.service.StockInventoryService;
|
import com.ruoyi.technology.mapper.TechnologyOperationMapper;
|
import com.ruoyi.technology.mapper.TechnologyRoutingOperationMapper;
|
import com.ruoyi.technology.pojo.TechnologyOperation;
|
import com.ruoyi.technology.pojo.TechnologyRoutingOperation;
|
import lombok.AllArgsConstructor;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.time.Duration;
|
import java.time.LocalDate;
|
import java.time.LocalDateTime;
|
import java.time.format.DateTimeFormatter;
|
import java.util.ArrayList;
|
import java.util.Collections;
|
import java.util.HashMap;
|
import java.util.LinkedHashSet;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Objects;
|
import java.util.Set;
|
import java.util.stream.Collectors;
|
|
@Service
|
@AllArgsConstructor
|
@Transactional(rollbackFor = Exception.class)
|
public class ProductionProductMainServiceImpl extends ServiceImpl<ProductionProductMainMapper, ProductionProductMain> implements ProductionProductMainService {
|
|
private final ProductionProductMainMapper productionProductMainMapper;
|
private final SysUserMapper userMapper;
|
private final ProductionProductOutputMapper productionProductOutputMapper;
|
private final ProductModelMapper productModelMapper;
|
private final QualityInspectMapper qualityInspectMapper;
|
private final QualityUnqualifiedMapper qualityUnqualifiedMapper;
|
private final ProductMapper productMapper;
|
private final QualityTestStandardParamMapper qualityTestStandardParamMapper;
|
private final QualityTestStandardMapper qualityTestStandardMapper;
|
private final QualityInspectParamMapper qualityInspectParamMapper;
|
private final ProductionProductInputMapper productionProductInputMapper;
|
private final ProductionAccountMapper productionAccountMapper;
|
private final ProductionOperationTaskMapper productionOperationTaskMapper;
|
private final ProductionOrderMapper productionOrderMapper;
|
private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper;
|
private final ProductionOrderRoutingOperationParamMapper productionOrderRoutingOperationParamMapper;
|
private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
|
private final TechnologyOperationMapper technologyOperationMapper;
|
private final StockUtils stockUtils;
|
private final StockInRecordService stockInRecordService;
|
private final StockInventoryService stockInventoryService;
|
|
@Override
|
public IPage<ProductionProductMainDto> listPageProductionProductMainDto(Page page, ProductionProductMainDto productionProductMainDto) {
|
// 分页查询生产报工主表
|
IPage<ProductionProductMainDto> result = productionProductMainMapper.listPageProductionProductMainDto(page, productionProductMainDto);
|
fillOperationParamList(result.getRecords());
|
return result;
|
}
|
|
@Override
|
public IPage<ProductionProductMainDto> pageProductionProductMain(Page page, ProductionProductMainDto productionProductMainDto) {
|
// 分页查询生产报工主表
|
return listPageProductionProductMainDto(page, productionProductMainDto);
|
}
|
|
@Override
|
public ProductionProductMainDto getProductionProductMainInfo(Long id) {
|
// 获取生产产品主表详情
|
return listPageProductionProductMainDto(new Page<>(1, 1), new ProductionProductMainDto() {{
|
setId(id);
|
}}).getRecords().stream().findFirst().orElse(null);
|
}
|
|
private void fillOperationParamList(List<ProductionProductMainDto> recordList) {
|
// 填充工序参数列表
|
if (recordList == null || recordList.isEmpty()) {
|
return;
|
}
|
// 遍历处理数据并组装结果
|
Set<Long> mainIdSet = recordList.stream()
|
.map(ProductionProductMainDto::getId)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
if (mainIdSet.isEmpty()) {
|
recordList.forEach(item -> item.setProductionOperationParamList(Collections.emptyList()));
|
return;
|
}
|
|
// 查询并准备业务数据
|
List<ProductionOrderRoutingOperationParam> paramList = productionOrderRoutingOperationParamMapper.selectList(
|
Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
|
.in(ProductionOrderRoutingOperationParam::getProductionProductMainId, mainIdSet)
|
.orderByAsc(ProductionOrderRoutingOperationParam::getId));
|
Map<Long, List<ProductionOrderRoutingOperationParam>> paramGroupMap = new HashMap<>();
|
for (ProductionOrderRoutingOperationParam param : paramList) {
|
if (param == null || param.getProductionProductMainId() == null) {
|
continue;
|
}
|
paramGroupMap.computeIfAbsent(param.getProductionProductMainId(), key -> new ArrayList<>()).add(param);
|
}
|
|
Set<Long> missingMainIdSet = new LinkedHashSet<>();
|
for (ProductionProductMainDto item : recordList) {
|
Long mainId = item.getId();
|
if (mainId == null) {
|
item.setProductionOperationParamList(Collections.emptyList());
|
continue;
|
}
|
List<ProductionOrderRoutingOperationParam> params = paramGroupMap.get(mainId);
|
if (params != null && !params.isEmpty()) {
|
item.setProductionOperationParamList(params);
|
continue;
|
}
|
missingMainIdSet.add(mainId);
|
}
|
if (missingMainIdSet.isEmpty()) {
|
return;
|
}
|
|
// 兼容历史数据:旧报工记录没有按报工ID落参数快照时,回退展示工序模板参数。
|
List<ProductionProductMain> mainList = productionProductMainMapper.selectBatchIds(missingMainIdSet);
|
Map<Long, Long> mainIdToTaskIdMap = mainList.stream()
|
.filter(Objects::nonNull)
|
.filter(item -> item.getId() != null)
|
.collect(Collectors.toMap(ProductionProductMain::getId,
|
ProductionProductMain::getProductionOperationTaskId, (left, right) -> left));
|
Set<Long> taskIdSet = mainIdToTaskIdMap.values().stream()
|
.filter(Objects::nonNull)
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
if (taskIdSet.isEmpty()) {
|
for (ProductionProductMainDto item : recordList) {
|
if (item.getId() != null && missingMainIdSet.contains(item.getId())) {
|
item.setProductionOperationParamList(Collections.emptyList());
|
}
|
}
|
return;
|
}
|
|
List<ProductionOperationTask> taskList = productionOperationTaskMapper.selectList(
|
Wrappers.<ProductionOperationTask>lambdaQuery()
|
.in(ProductionOperationTask::getId, taskIdSet));
|
Map<Long, Long> taskIdToRoutingOperationIdMap = taskList.stream()
|
.filter(Objects::nonNull)
|
.filter(item -> item.getId() != null)
|
.collect(Collectors.toMap(ProductionOperationTask::getId,
|
ProductionOperationTask::getProductionOrderRoutingOperationId, (left, right) -> left));
|
Set<Long> routingOperationIdSet = taskIdToRoutingOperationIdMap.values().stream()
|
.filter(Objects::nonNull)
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
if (routingOperationIdSet.isEmpty()) {
|
for (ProductionProductMainDto item : recordList) {
|
if (item.getId() != null && missingMainIdSet.contains(item.getId())) {
|
item.setProductionOperationParamList(Collections.emptyList());
|
}
|
}
|
return;
|
}
|
|
List<ProductionOrderRoutingOperationParam> fallbackParamList = productionOrderRoutingOperationParamMapper.selectList(
|
Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
|
.in(ProductionOrderRoutingOperationParam::getProductionOrderRoutingOperationId, routingOperationIdSet)
|
.isNull(ProductionOrderRoutingOperationParam::getProductionProductMainId)
|
.orderByAsc(ProductionOrderRoutingOperationParam::getId));
|
Map<Long, List<ProductionOrderRoutingOperationParam>> fallbackGroupMap = new HashMap<>();
|
for (ProductionOrderRoutingOperationParam param : fallbackParamList) {
|
if (param == null || param.getProductionOrderRoutingOperationId() == null) {
|
continue;
|
}
|
fallbackGroupMap.computeIfAbsent(param.getProductionOrderRoutingOperationId(), key -> new ArrayList<>()).add(param);
|
}
|
|
for (ProductionProductMainDto item : recordList) {
|
Long mainId = item.getId();
|
if (mainId == null || !missingMainIdSet.contains(mainId)) {
|
continue;
|
}
|
Long taskId = mainIdToTaskIdMap.get(mainId);
|
Long routingOperationId = taskId == null ? null : taskIdToRoutingOperationIdMap.get(taskId);
|
if (routingOperationId == null) {
|
item.setProductionOperationParamList(Collections.emptyList());
|
continue;
|
}
|
item.setProductionOperationParamList(fallbackGroupMap.getOrDefault(routingOperationId, Collections.emptyList()));
|
}
|
}
|
|
@Override
|
public Boolean addProductMain(ProductionProductMainDto dto) {
|
// 兼容旧流程:如果没有开始报工记录ID,走一步报工(自动创建+结束)
|
Long startRecordId = dto.resolveStartRecordId();
|
if (startRecordId == null) {
|
return oneStepWork(dto);
|
}
|
dto.setId(startRecordId);
|
return finishWork(dto);
|
}
|
|
@Override
|
public Boolean startWork(ProductionProductMainDto dto) {
|
// 开始报工:创建报工记录,标记实际开始时间
|
Long taskId = resolveTaskId(dto);
|
if (taskId == null) {
|
throw new ServiceException("请传入生产工单ID");
|
}
|
ProductionOperationTask task = productionOperationTaskMapper.selectById(taskId);
|
if (task == null) {
|
throw new ServiceException("生产工单不存在");
|
}
|
// 权限校验:已指派时仅被指派人可操作
|
validateWorkerPermission(task);
|
|
if (task.getStatus() != null && task.getStatus() != 2 && task.getStatus() != 3) {
|
throw new ServiceException("当前工单状态不允许开始报工,仅待生产或生产中状态的工单可操作");
|
}
|
SysUser user = userMapper.selectUserById(dto.getUserId());
|
ProductionProductMain main = new ProductionProductMain();
|
main.setProductNo(generateProductNo());
|
main.setUserId(user == null ? dto.getUserId() : user.getUserId());
|
main.setUserName(user == null ? dto.getUserName() : user.getNickName());
|
main.setProductionOperationTaskId(taskId);
|
main.setStatus(0);
|
main.setActualStartTime(LocalDateTime.now());
|
productionProductMainMapper.insert(main);
|
|
// 工单状态 -> 生产中
|
task.setStatus(3);
|
if (task.getActualStartTime() == null) {
|
task.setActualStartTime(LocalDateTime.now());
|
}
|
productionOperationTaskMapper.updateById(task);
|
|
// 生产订单 -> 生产进行中
|
ProductionOrder productionOrder = productionOrderMapper.selectById(task.getProductionOrderId());
|
if (productionOrder != null && productionOrder.getStartTime() == null) {
|
productionOrder.setStartTime(LocalDateTime.now());
|
productionOrder.setStatus(ProductOrderStatusEnum.RUNNING.getCode());
|
productionOrderMapper.updateById(productionOrder);
|
}
|
return true;
|
}
|
|
private Boolean oneStepWork(ProductionProductMainDto dto) {
|
// 兼容旧一步报工流程:自动创建开始记录并立即结束
|
Long taskId = resolveTaskId(dto);
|
if (taskId == null) {
|
throw new ServiceException("请传入生产工单ID");
|
}
|
ProductionOperationTask task = productionOperationTaskMapper.selectById(taskId);
|
if (task == null) {
|
throw new ServiceException("生产工单不存在");
|
}
|
validateWorkerPermission(task);
|
if (task.getStatus() != null && task.getStatus() != 2 && task.getStatus() != 3) {
|
throw new ServiceException("当前工单状态不允许报工");
|
}
|
SysUser user = userMapper.selectUserById(dto.getUserId());
|
ProductionProductMain main = new ProductionProductMain();
|
main.setProductNo(generateProductNo());
|
main.setUserId(user == null ? dto.getUserId() : user.getUserId());
|
main.setUserName(user == null ? dto.getUserName() : user.getNickName());
|
main.setProductionOperationTaskId(taskId);
|
main.setStatus(0);
|
main.setActualStartTime(LocalDateTime.now());
|
productionProductMainMapper.insert(main);
|
|
if (task.getActualStartTime() == null) {
|
task.setActualStartTime(LocalDateTime.now());
|
}
|
task.setStatus(3);
|
productionOperationTaskMapper.updateById(task);
|
|
ProductionOrder productionOrder = productionOrderMapper.selectById(task.getProductionOrderId());
|
if (productionOrder != null && productionOrder.getStartTime() == null) {
|
productionOrder.setStartTime(LocalDateTime.now());
|
productionOrder.setStatus(ProductOrderStatusEnum.RUNNING.getCode());
|
productionOrderMapper.updateById(productionOrder);
|
}
|
|
dto.setId(main.getId());
|
return finishWork(dto);
|
}
|
|
private Boolean finishWork(ProductionProductMainDto dto) {
|
// 结束报工:更新开始报工记录,创建产出、投入品、核算记录
|
ProductionProductMain currentMain = productionProductMainMapper.selectById(dto.getId());
|
if (currentMain == null) {
|
throw new ServiceException("开始报工记录不存在");
|
}
|
if (currentMain.getStatus() == null || currentMain.getStatus() != 0) {
|
throw new ServiceException("该报工记录已结束或状态异常");
|
}
|
Long taskId = currentMain.getProductionOperationTaskId();
|
ProductionOperationTask task = productionOperationTaskMapper.selectById(taskId);
|
if (task == null) {
|
throw new ServiceException("生产工单不存在");
|
}
|
validateWorkerPermission(task);
|
|
// 更新报工记录为已结束,记录结束时间
|
currentMain.setActualEndTime(LocalDateTime.now());
|
currentMain.setStatus(1);
|
if (dto.getWorkHour() != null) {
|
currentMain.setWorkHour(dto.getWorkHour());
|
} else if (currentMain.getActualStartTime() != null) {
|
// 根据开始/结束时间计算实际工时(小时)
|
long seconds = Duration.between(currentMain.getActualStartTime(), currentMain.getActualEndTime()).getSeconds();
|
currentMain.setWorkHour(BigDecimal.valueOf(seconds).divide(BigDecimal.valueOf(3600), 4, RoundingMode.HALF_UP));
|
}
|
productionProductMainMapper.updateById(currentMain);
|
|
// 同步工序参数
|
ProductionOrderRoutingOperation routingOperation = productionOrderRoutingOperationMapper.selectById(task.getProductionOrderRoutingOperationId());
|
if (routingOperation != null) {
|
syncOperationParamInputValue(dto, routingOperation.getId(), currentMain.getId());
|
}
|
|
// 获取产品规格
|
ProductModel productModel = null;
|
if (routingOperation != null) {
|
productModel = productModelMapper.selectById(
|
routingOperation.getProductModelId() != null ? routingOperation.getProductModelId() : getProductionOrderProductModelId(task));
|
}
|
if (productModel == null) {
|
throw new ServiceException("产品规格不存在");
|
}
|
|
// 投入品
|
ProductionProductInput productionProductInput = new ProductionProductInput();
|
productionProductInput.setProductionProductMainId(currentMain.getId());
|
productionProductInput.setProductModelId(productModel.getId());
|
productionProductInput.setInputQuantity(defaultDecimal(dto.getQuantity()));
|
productionProductInput.setQuantity(productionProductInput.getInputQuantity());
|
productionProductInputMapper.insert(productionProductInput);
|
|
// 产出品
|
ProductionProductOutput productionProductOutput = new ProductionProductOutput();
|
productionProductOutput.setProductionProductMainId(currentMain.getId());
|
productionProductOutput.setProductModelId(productModel.getId());
|
productionProductOutput.setQuantity(defaultDecimal(dto.getQuantity()));
|
productionProductOutput.setScrapQty(defaultDecimal(dto.getScrapQty()));
|
productionProductOutputMapper.insert(productionProductOutput);
|
|
BigDecimal reportQty = defaultDecimal(productionProductOutput.getQuantity());
|
BigDecimal scrapQty = defaultDecimal(productionProductOutput.getScrapQty());
|
BigDecimal productQty = reportQty;
|
String qualifiedBatchNo = null;
|
|
TechnologyRoutingOperation technologyRoutingOperation = routingOperation != null
|
? technologyRoutingOperationMapper.selectById(routingOperation.getTechnologyRoutingOperationId()) : null;
|
TechnologyOperation technologyOperation = technologyRoutingOperation == null ? null
|
: technologyOperationMapper.selectById(technologyRoutingOperation.getTechnologyOperationId());
|
|
List<ProductionOrderRoutingOperation> routingOperationList = routingOperation != null ? productionOrderRoutingOperationMapper.selectList(
|
Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
|
.eq(ProductionOrderRoutingOperation::getOrderRoutingId, routingOperation.getOrderRoutingId())
|
.eq(ProductionOrderRoutingOperation::getProductionOrderId, routingOperation.getProductionOrderId())) : new ArrayList<>();
|
boolean isLastOperation = routingOperation != null && routingOperation.getDragSort() != null
|
&& routingOperation.getDragSort().equals(routingOperationList.size());
|
|
if (productQty.compareTo(BigDecimal.ZERO) > 0) {
|
if (routingOperation != null && Boolean.TRUE.equals(routingOperation.getIsQuality())) {
|
int inspectType = isLastOperation ? 2 : 1;
|
String process = isLastOperation ? null : technologyOperation == null ? null : technologyOperation.getName();
|
Product product = productMapper.selectById(productModel.getProductId());
|
QualityInspect qualityInspect = new QualityInspect();
|
qualityInspect.setProductId(product.getId());
|
qualityInspect.setProductName(product.getProductName());
|
qualityInspect.setModel(productModel.getModel());
|
qualityInspect.setUnit(productModel.getUnit());
|
qualityInspect.setQuantity(productQty);
|
qualityInspect.setProcess(process);
|
qualityInspect.setInspectState(0);
|
qualityInspect.setInspectType(inspectType);
|
qualityInspect.setProductMainId(currentMain.getId());
|
qualityInspect.setProductModelId(productModel.getId());
|
qualityInspectMapper.insert(qualityInspect);
|
List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(product.getId(), inspectType, process);
|
if (!qualityTestStandard.isEmpty()) {
|
qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId());
|
qualityInspectMapper.updateById(qualityInspect);
|
qualityTestStandardParamMapper.selectList(Wrappers.<QualityTestStandardParam>lambdaQuery()
|
.eq(QualityTestStandardParam::getTestStandardId, qualityTestStandard.get(0).getId()))
|
.forEach(qualityTestStandardParam -> {
|
QualityInspectParam param = new QualityInspectParam();
|
BeanUtils.copyProperties(qualityTestStandardParam, param);
|
param.setId(null);
|
param.setInspectId(qualityInspect.getId());
|
qualityInspectParamMapper.insert(param);
|
});
|
}
|
} else {
|
StockInventoryDto stockInventoryDto = new StockInventoryDto();
|
stockInventoryDto.setRecordId(currentMain.getId());
|
stockInventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode()));
|
stockInventoryDto.setQualitity(productQty);
|
stockInventoryDto.setProductModelId(productModel.getId());
|
stockInventoryService.addStockInRecordOnly(stockInventoryDto);
|
qualifiedBatchNo = resolveLatestStockInBatchNo(
|
currentMain.getId(),
|
StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(),
|
productModel.getId(),
|
"0");
|
}
|
|
task.setCompleteQuantity(defaultDecimal(task.getCompleteQuantity()).add(productQty));
|
if (task.getActualStartTime() == null) {
|
task.setActualStartTime(LocalDateTime.now());
|
}
|
task.setStatus(3);
|
if (task.getPlanQuantity() != null
|
&& task.getCompleteQuantity().compareTo(task.getPlanQuantity()) >= 0) {
|
task.setActualEndTime(LocalDateTime.now());
|
task.setStatus(4);
|
}
|
productionOperationTaskMapper.updateById(task);
|
|
ProductionOrder productionOrder = productionOrderMapper.selectById(task.getProductionOrderId());
|
if (productionOrder != null) {
|
if (productionOrder.getStartTime() == null) {
|
productionOrder.setStartTime(LocalDateTime.now());
|
}
|
productionOrder.setStatus(ProductOrderStatusEnum.RUNNING.getCode());
|
if (isLastOperation) {
|
productionOrder.setCompleteQuantity(defaultDecimal(productionOrder.getCompleteQuantity()).add(productQty));
|
if (productionOrder.getQuantity() != null
|
&& productionOrder.getCompleteQuantity().compareTo(productionOrder.getQuantity()) >= 0) {
|
productionOrder.setEndTime(LocalDateTime.now());
|
productionOrder.setStatus(ProductOrderStatusEnum.FINISHED.getCode());
|
}
|
}
|
productionOrderMapper.updateById(productionOrder);
|
}
|
|
BigDecimal workHours = BigDecimal.ZERO;
|
if (technologyOperation != null && technologyOperation.getSalaryQuota() != null) {
|
workHours = Integer.valueOf(1).equals(technologyOperation.getType())
|
? technologyOperation.getSalaryQuota().multiply(productQty)
|
: technologyOperation.getSalaryQuota();
|
}
|
ProductionAccount productionAccount = new ProductionAccount();
|
productionAccount.setProductionProductMainId(currentMain.getId());
|
SysUser user = userMapper.selectUserById(dto.getUserId());
|
productionAccount.setSchedulingUserId(user == null ? currentMain.getUserId() : user.getUserId());
|
productionAccount.setSchedulingUserName(user == null ? currentMain.getUserName() : user.getNickName());
|
productionAccount.setFinishedNum(productQty);
|
productionAccount.setWorkHours(technologyOperation != null ? technologyOperation.getSalaryQuota() : null);
|
productionAccount.setTechnologyOperationName(technologyOperation == null ? null : technologyOperation.getName());
|
productionAccount.setSchedulingDate(currentMain.getActualEndTime() != null ? currentMain.getActualEndTime() : LocalDateTime.now());
|
productionAccountMapper.insert(productionAccount);
|
}
|
if (scrapQty.compareTo(BigDecimal.ZERO) > 0) {
|
stockUtils.addUnStockWithBatchNo(
|
productModel.getId(),
|
scrapQty,
|
StockInQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode(),
|
currentMain.getId(),
|
qualifiedBatchNo);
|
}
|
return true;
|
}
|
|
private Long getProductionOrderProductModelId(ProductionOperationTask task) {
|
// 从生产订单获取产品规格ID
|
if (task == null || task.getProductionOrderId() == null) {
|
return null;
|
}
|
ProductionOrder order = productionOrderMapper.selectById(task.getProductionOrderId());
|
return order == null ? null : order.getProductModelId();
|
}
|
|
private void validateWorkerPermission(ProductionOperationTask task) {
|
// 校验当前用户是否有权操作此工单:未指派时人人可操作,已指派时仅被指派人可操作
|
if (task == null) {
|
return;
|
}
|
String userIds = task.getUserIds();
|
if (userIds == null || userIds.isEmpty() || "[]".equals(userIds.trim())) {
|
return;
|
}
|
Long currentUserId = SecurityUtils.getUserId();
|
if (currentUserId == null) {
|
return;
|
}
|
List<Long> assignedIds = JSON.parseArray(userIds, Long.class);
|
if (assignedIds == null || !assignedIds.contains(currentUserId)) {
|
throw new ServiceException("您未被指派到此工单,无法操作");
|
}
|
}
|
|
@Override
|
public Boolean saveProductionProductMain(ProductionProductMainDto productionProductMainDto) {
|
// 保存生产报工主记录
|
return addProductMain(productionProductMainDto);
|
}
|
|
@Override
|
public Boolean removeProductMain(Long id) {
|
// 删除生产报工主记录
|
ProductionProductMain currentMain = productionProductMainMapper.selectById(id);
|
if (currentMain == null) {
|
return true;
|
}
|
return removeProductMainByProductionTask(currentMain);
|
}
|
|
private String resolveLatestStockInBatchNo(Long recordId,
|
String recordType,
|
Long productModelId,
|
String stockType) {
|
if (recordId == null || productModelId == null) {
|
return null;
|
}
|
StockInRecord stockInRecord = stockInRecordService.getOne(
|
Wrappers.<StockInRecord>lambdaQuery()
|
.eq(StockInRecord::getRecordId, recordId)
|
.eq(StockInRecord::getRecordType, recordType)
|
.eq(StockInRecord::getProductModelId, productModelId)
|
.eq(StockInRecord::getType, stockType)
|
.orderByDesc(StockInRecord::getId)
|
.last("limit 1"),
|
false);
|
if (stockInRecord == null) {
|
throw new ServiceException("未找到对应的入库申请记录");
|
}
|
return stockInRecord.getBatchNo();
|
}
|
|
private void syncOperationParamInputValue(ProductionProductMainDto dto,
|
Long productionOrderRoutingOperationId,
|
Long productionProductMainId) {
|
if (dto == null || productionOrderRoutingOperationId == null || productionProductMainId == null) {
|
return;
|
}
|
List<ProductionOrderRoutingOperationParam> paramList = dto.getProductionOperationParamList();
|
if (paramList == null || paramList.isEmpty()) {
|
return;
|
}
|
Set<Long> sourceParamIdSet = paramList.stream()
|
.filter(Objects::nonNull)
|
.map(ProductionOrderRoutingOperationParam::getId)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
if (sourceParamIdSet.isEmpty()) {
|
return;
|
}
|
|
List<ProductionOrderRoutingOperationParam> dbParamList = productionOrderRoutingOperationParamMapper.selectList(
|
Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
|
.in(ProductionOrderRoutingOperationParam::getId, sourceParamIdSet)
|
.eq(ProductionOrderRoutingOperationParam::getProductionOrderRoutingOperationId, productionOrderRoutingOperationId));
|
if (dbParamList == null || dbParamList.isEmpty()) {
|
return;
|
}
|
|
Map<Long, ProductionOrderRoutingOperationParam> dbParamMap = dbParamList.stream()
|
.filter(item -> item != null && item.getId() != null)
|
.collect(Collectors.toMap(ProductionOrderRoutingOperationParam::getId, item -> item, (left, right) -> left));
|
for (ProductionOrderRoutingOperationParam param : paramList) {
|
if (param == null || param.getId() == null) {
|
continue;
|
}
|
ProductionOrderRoutingOperationParam dbParam = dbParamMap.get(param.getId());
|
if (dbParam == null) {
|
throw new ServiceException("工序参数不存在或不属于当前工单工序,ID=" + param.getId());
|
}
|
productionOrderRoutingOperationParamMapper.insert(buildReportParamSnapshot(dbParam, param.getInputValue(), productionProductMainId));
|
}
|
}
|
|
private ProductionOrderRoutingOperationParam buildReportParamSnapshot(ProductionOrderRoutingOperationParam source,
|
String inputValue,
|
Long productionProductMainId) {
|
ProductionOrderRoutingOperationParam target = new ProductionOrderRoutingOperationParam();
|
target.setProductionOrderId(source.getProductionOrderId());
|
target.setTechnologyRoutingOperationParamId(source.getTechnologyRoutingOperationParamId());
|
target.setParamCode(source.getParamCode());
|
target.setParamName(source.getParamName());
|
target.setParamType(source.getParamType());
|
target.setParamFormat(source.getParamFormat());
|
target.setUnit(source.getUnit());
|
target.setIsRequired(source.getIsRequired());
|
target.setRemark(source.getRemark());
|
target.setParamId(source.getParamId());
|
target.setTechnologyOperationId(source.getTechnologyOperationId());
|
target.setTechnologyOperationParamId(source.getTechnologyOperationParamId());
|
target.setStandardValue(source.getStandardValue());
|
target.setInputValue(inputValue);
|
target.setProductionOrderRoutingOperationId(source.getProductionOrderRoutingOperationId());
|
target.setProductionProductMainId(productionProductMainId);
|
return target;
|
}
|
|
private Boolean removeProductMainByProductionTask(ProductionProductMain productionProductMain) {
|
// 按生产任务回滚并删除报工主记录
|
List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(
|
Wrappers.<QualityInspect>lambdaQuery().eq(QualityInspect::getProductMainId, productionProductMain.getId()));
|
// 参数与前置条件校验
|
if (qualityInspects.size() > 0) {
|
List<QualityUnqualified> qualityUnqualifieds = qualityUnqualifiedMapper.selectList(
|
Wrappers.<QualityUnqualified>lambdaQuery()
|
// 遍历处理数据并组装结果
|
.in(QualityUnqualified::getInspectId, qualityInspects.stream().map(QualityInspect::getId).collect(Collectors.toList())));
|
if (qualityUnqualifieds.size() > 0 && qualityUnqualifieds.get(0).getInspectState() == 1) {
|
throw new ServiceException("该条报工已经不合格处理了,不允许删除");
|
}
|
}
|
ProductionProductOutput productionProductOutput = productionProductOutputMapper.selectList(
|
Wrappers.<ProductionProductOutput>lambdaQuery()
|
.eq(ProductionProductOutput::getProductionProductMainId, productionProductMain.getId()))
|
.stream().findFirst().orElse(null);
|
productionAccountMapper.delete(new LambdaQueryWrapper<ProductionAccount>()
|
.eq(ProductionAccount::getProductionProductMainId, productionProductMain.getId()));
|
|
ProductionOperationTask productionOperationTask = productionOperationTaskMapper.selectById(productionProductMain.getProductionOperationTaskId());
|
if (productionOperationTask != null && productionProductOutput != null) {
|
BigDecimal reportQuantity = defaultDecimal(productionProductOutput.getQuantity());
|
productionOperationTask.setCompleteQuantity(defaultDecimal(productionOperationTask.getCompleteQuantity()).subtract(reportQuantity));
|
productionOperationTask.setActualEndTime(null);
|
if (defaultDecimal(productionOperationTask.getCompleteQuantity()).compareTo(BigDecimal.ZERO) <= 0) {
|
productionOperationTask.setCompleteQuantity(BigDecimal.ZERO);
|
productionOperationTask.setActualStartTime(null);
|
productionOperationTask.setStatus(2);
|
} else {
|
productionOperationTask.setStatus(3);
|
}
|
// 持久化或输出处理结果
|
productionOperationTaskMapper.updateById(productionOperationTask);
|
|
ProductionOrder productionOrder = productionOrderMapper.selectById(productionOperationTask.getProductionOrderId());
|
ProductionOrderRoutingOperation routingOperation = productionOrderRoutingOperationMapper.selectById(productionOperationTask.getProductionOrderRoutingOperationId());
|
if (productionOrder != null && routingOperation != null) {
|
// 只有最后一道工序的报工才会影响生产订单完工数量。
|
List<ProductionOrderRoutingOperation> routingOperationList = productionOrderRoutingOperationMapper.selectList(
|
Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
|
.eq(ProductionOrderRoutingOperation::getOrderRoutingId, routingOperation.getOrderRoutingId())
|
.eq(ProductionOrderRoutingOperation::getProductionOrderId, routingOperation.getProductionOrderId()));
|
boolean isLastOperation = routingOperation.getDragSort() != null && routingOperation.getDragSort().equals(routingOperationList.size());
|
if (isLastOperation) {
|
BigDecimal newCompleteQty = defaultDecimal(productionOrder.getCompleteQuantity()).subtract(reportQuantity);
|
productionOrder.setCompleteQuantity(newCompleteQty.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : newCompleteQty);
|
productionOrder.setEndTime(null);
|
}
|
if (defaultDecimal(productionOrder.getCompleteQuantity()).compareTo(BigDecimal.ZERO) <= 0) {
|
productionOrder.setStartTime(null);
|
productionOrder.setStatus(ProductOrderStatusEnum.WAIT.getCode());
|
} else {
|
productionOrder.setStatus(ProductOrderStatusEnum.RUNNING.getCode());
|
}
|
productionOrderMapper.updateById(productionOrder);
|
}
|
}
|
|
qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
|
.eq(QualityInspect::getProductMainId, productionProductMain.getId())).forEach(q -> {
|
qualityInspectParamMapper.delete(new LambdaQueryWrapper<QualityInspectParam>()
|
.eq(QualityInspectParam::getInspectId, q.getId()));
|
qualityInspectMapper.deleteById(q.getId());
|
stockUtils.deleteStockInRecord(q.getId(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode());
|
});
|
productionProductOutputMapper.delete(new LambdaQueryWrapper<ProductionProductOutput>()
|
.eq(ProductionProductOutput::getProductionProductMainId, productionProductMain.getId()));
|
productionProductInputMapper.delete(new LambdaQueryWrapper<ProductionProductInput>()
|
.eq(ProductionProductInput::getProductionProductMainId, productionProductMain.getId()));
|
productionOrderRoutingOperationParamMapper.delete(
|
Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
|
.eq(ProductionOrderRoutingOperationParam::getProductionProductMainId, productionProductMain.getId()));
|
stockUtils.deleteStockInRecord(productionProductMain.getId(), StockInQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode());
|
stockUtils.deleteStockInRecord(productionProductMain.getId(), StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode());
|
stockUtils.deleteStockOutRecord(productionProductMain.getId(), StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode());
|
productionProductMainMapper.deleteById(productionProductMain.getId());
|
return true;
|
}
|
|
private String generateProductNo() {
|
// 生成下一个生产产品编号
|
String datePrefix = "BG" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyMMdd"));
|
QueryWrapper<ProductionProductMain> queryWrapper = new QueryWrapper<>();
|
queryWrapper.select("MAX(product_no) as maxNo").likeRight("product_no", datePrefix);
|
List<Map<String, Object>> resultList = productionProductMainMapper.selectMaps(queryWrapper);
|
int sequenceNumber = 1;
|
if (resultList != null && !resultList.isEmpty()) {
|
Map<String, Object> result = resultList.get(0);
|
if (result != null && result.get("maxNo") != null) {
|
String lastNo = result.get("maxNo").toString();
|
if (lastNo.startsWith(datePrefix)) {
|
try {
|
sequenceNumber = Integer.parseInt(lastNo.substring(datePrefix.length())) + 1;
|
} catch (NumberFormatException e) {
|
sequenceNumber = 1;
|
}
|
}
|
}
|
}
|
return String.format("%s%03d", datePrefix, sequenceNumber);
|
}
|
|
private BigDecimal defaultDecimal(BigDecimal value) {
|
// 将空数量兜底为0,避免空指针异常
|
return value == null ? BigDecimal.ZERO : value;
|
}
|
|
private Long resolveTaskId(ProductionProductMainDto dto) {
|
// 从入参中解析生产工单ID并校验
|
if (dto == null) {
|
return null;
|
}
|
return dto.getProductionOperationTaskId();
|
}
|
|
@Override
|
public ArrayList<Long> listMain(List<Long> idList) {
|
// 查询主表ID集合
|
return productionProductMainMapper.listMain(idList);
|
}
|
}
|