package com.chinaztt.mes.production.state.productout;
|
|
import cn.hutool.core.collection.CollectionUtil;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.chinaztt.mes.basic.entity.Part;
|
import com.chinaztt.mes.basic.entity.Workstation;
|
import com.chinaztt.mes.basic.entity.WorkstationLocation;
|
import com.chinaztt.mes.basic.mapper.PartMapper;
|
import com.chinaztt.mes.basic.mapper.WorkstationLocationMapper;
|
import com.chinaztt.mes.basic.mapper.WorkstationMapper;
|
import com.chinaztt.mes.common.handler.StateMachineHandler;
|
import com.chinaztt.mes.plan.entity.MoRoutingOperation;
|
import com.chinaztt.mes.plan.mapper.MoRoutingOperationMapper;
|
import com.chinaztt.mes.production.dto.OperationTaskDTO;
|
import com.chinaztt.mes.production.dto.OperationTaskMaterialDTO;
|
import com.chinaztt.mes.production.entity.OperationTask;
|
import com.chinaztt.mes.production.entity.OperationTaskMaterial;
|
import com.chinaztt.mes.production.entity.ProductMain;
|
import com.chinaztt.mes.production.entity.ProductOutput;
|
import com.chinaztt.mes.production.mapper.OperationTaskMapper;
|
import com.chinaztt.mes.production.mapper.OperationTaskMaterialMapper;
|
import com.chinaztt.mes.production.mapper.ProductMainMapper;
|
import com.chinaztt.mes.production.mapper.ProductOutputMapper;
|
import com.chinaztt.mes.production.state.productmain.constant.ProductMainStateStringValues;
|
import com.chinaztt.mes.production.state.productout.constant.ProductOutEvents;
|
import com.chinaztt.mes.production.state.productout.constant.ProductOutStateStringValues;
|
import com.chinaztt.mes.quality.dto.ApplyDTO;
|
import com.chinaztt.mes.quality.dto.ApplyPartDTO;
|
import com.chinaztt.mes.quality.entity.Apply;
|
import com.chinaztt.mes.quality.entity.ApplyPart;
|
import com.chinaztt.mes.quality.entity.Result;
|
import com.chinaztt.mes.quality.entity.TestRule;
|
import com.chinaztt.mes.quality.mapper.ApplyMapper;
|
import com.chinaztt.mes.quality.mapper.ApplyPartMapper;
|
import com.chinaztt.mes.quality.mapper.ResultMapper;
|
import com.chinaztt.mes.quality.mapper.TestRuleMapper;
|
import com.chinaztt.mes.quality.service.ApplyPartService;
|
import com.chinaztt.mes.quality.service.ApplyService;
|
import com.chinaztt.mes.quality.state.result.constant.ResultStateStringValues;
|
import com.chinaztt.mes.quality.utils.ResultUtils;
|
import com.chinaztt.mes.quality.utils.TestApplyRuleUtils;
|
import com.chinaztt.mes.technology.entity.RoutingOperation;
|
import com.chinaztt.mes.technology.mapper.RoutingOperationMapper;
|
import com.chinaztt.mes.warehouse.dto.StockAddDTO;
|
import com.chinaztt.mes.warehouse.entity.Stock;
|
import com.chinaztt.mes.warehouse.mapper.StockMapper;
|
import com.chinaztt.mes.warehouse.service.impl.JoinStockOrderServiceImpl;
|
import com.chinaztt.mes.warehouse.util.StockUtils;
|
import com.chinaztt.mes.warehouse.util.TransactionType;
|
import com.google.common.collect.Lists;
|
import lombok.AllArgsConstructor;
|
import org.springframework.messaging.Message;
|
import org.springframework.statemachine.StateMachine;
|
import org.springframework.statemachine.annotation.OnTransition;
|
import org.springframework.statemachine.annotation.WithStateMachine;
|
import org.springframework.stereotype.Component;
|
import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
import org.springframework.util.CollectionUtils;
|
|
import java.math.BigDecimal;
|
import java.time.LocalDateTime;
|
import java.util.ArrayList;
|
import java.util.List;
|
import java.util.stream.Collectors;
|
|
|
/**
|
* @Author: zhangxy
|
* @Date: 2020-08-24 9:51
|
*/
|
@AllArgsConstructor
|
@Component
|
@WithStateMachine(id = "productOutStateMachine")
|
public class ProductOutStateListener {
|
|
private ProductOutputMapper productOutputMapper;
|
private RoutingOperationMapper routingOperationMapper;
|
private ProductMainMapper productMainMapper;
|
private WorkstationLocationMapper workstationLocationMapper;
|
private StockUtils stockUtils;
|
private ResultUtils resultUtils;
|
private PartMapper partMapper;
|
private TestRuleMapper testRuleMapper;
|
private ResultMapper resultMapper;
|
private WorkstationMapper workstationMapper;
|
private ApplyService applyService;
|
private OperationTaskMaterialMapper operationTaskMaterialMapper;
|
private OperationTaskMapper operationTaskMapper;
|
private JoinStockOrderServiceImpl joinStockOrderService;
|
private StockMapper stockMapper;
|
private ApplyPartMapper applyPartMapper;
|
private ApplyMapper applyMapper;
|
private MoRoutingOperationMapper moRoutingOperationMapper;
|
private TestApplyRuleUtils testApplyRuleUtils;
|
|
/**
|
* 提交到草稿
|
*
|
* @param stateMachine
|
* @param msg
|
* @return
|
*/
|
@OnTransition(source = ProductOutStateStringValues.SUBMITTED, target = ProductOutStateStringValues.DRAFT)
|
public boolean start(StateMachine stateMachine, Message<ProductOutEvents> msg) {
|
ProductOutput productOutput = (ProductOutput) msg.getHeaders().get("productOutput");
|
ProductMain productMain = productMainMapper.selectById(productOutput.getProductMainId());
|
//判断报工主表的状态
|
if (ProductMainStateStringValues.SUBMITTED.equals(productMain.getState())) {
|
stateMachine.getExtendedState().getVariables().put(StateMachineHandler.ERROR_KEY, "报工已提交不可撤回");
|
return false;
|
}
|
//判断是否检测
|
Integer resultNum = resultMapper.selectCount(Wrappers.<Result>lambdaQuery()
|
.eq(Result::getSystemNo, productOutput.getSystemNo())
|
//.eq(Result::getApplyType, Apply.OUTPUT_APPLY)//解除工作台提交时与尾检的琐定【2022-09-20】
|
.eq(Result::getApplyType, testApplyRuleUtils.getApplyTypeBySystemNo(productOutput.getSystemNo()))
|
.isNotNull(Result::getIsQualified));
|
if (resultNum > 0) {
|
stateMachine.getExtendedState().getVariables().put(StateMachineHandler.ERROR_KEY, "已检测不可撤回");
|
return false;
|
}
|
//工作台报工数据删除时需要先校验,是否已经进行了检测汇报
|
List<ApplyPart> applyPartList = applyPartMapper.selectApplyApertByInspState(productOutput.getOutBatchNo(), Apply.OUTPUT_APPLY);//这里的检测类型传参无效,无需解锁
|
if (!CollectionUtils.isEmpty(applyPartList)) {
|
List<ApplyPart> applyPartListChecked = applyPartList.stream().filter(e -> null != e.getReportId()).collect(Collectors.toList());
|
if (CollectionUtils.isEmpty(applyPartListChecked)) {
|
//没有进行检测汇报,先删除检测申请数据,再删除报工数据
|
List<Long> applyIds = applyPartList.stream().map(ApplyPart::getApplyId).collect(Collectors.toList());
|
List<Long> applyPartIds = applyPartList.stream().map(ApplyPart::getId).collect(Collectors.toList());
|
if (!CollectionUtils.isEmpty(applyIds)) {
|
applyMapper.deleteBatchIds(applyIds);
|
}
|
if (!CollectionUtils.isEmpty(applyPartIds)) {
|
applyPartMapper.deleteBatchIds(applyPartIds);
|
}
|
//删除检测结果
|
resultMapper.deleteBySystemNo(productOutput.getSystemNo());
|
} else {
|
stateMachine.getExtendedState().getVariables().put(StateMachineHandler.ERROR_KEY, "已经检测汇报,请先删除检测汇报");
|
return false;
|
}
|
}
|
//修改状态
|
productOutput.setState(ProductOutStateStringValues.DRAFT);
|
productOutputMapper.updateById(productOutput);
|
try {
|
//自动反向报检
|
autoInspection(productOutput, true);
|
} catch (RuntimeException e) {
|
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
|
stateMachine.getExtendedState().getVariables().put(StateMachineHandler.ERROR_KEY, e.getMessage());
|
return false;
|
}
|
return true;
|
}
|
|
/**
|
* 草稿到提交
|
*
|
* @param stateMachine
|
* @param msg
|
* @return
|
*/
|
@OnTransition(source = ProductOutStateStringValues.DRAFT, target = ProductOutStateStringValues.SUBMITTED)
|
public boolean complete(StateMachine stateMachine, Message<ProductOutEvents> msg) {
|
ProductOutput productOutput = (ProductOutput) msg.getHeaders().get("productOutput");
|
//修改状态
|
productOutput.setState(ProductOutStateStringValues.SUBMITTED);
|
productOutputMapper.updateById(productOutput);
|
// 自动报检和自动移库
|
try {
|
autoInspection(productOutput, false);
|
} catch (RuntimeException e) {
|
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
|
stateMachine.getExtendedState().getVariables().put(StateMachineHandler.ERROR_KEY, e.getMessage());
|
return false;
|
}
|
return true;
|
}
|
|
/**
|
* 草稿到交班
|
*
|
* @param stateMachine
|
* @param msg
|
* @return
|
*/
|
@OnTransition(source = ProductOutStateStringValues.DRAFT, target = ProductOutStateStringValues.CHANGESHIFT)
|
public boolean draftToChangeShift(StateMachine stateMachine, Message<ProductOutEvents> msg) {
|
ProductOutput productOutput = (ProductOutput) msg.getHeaders().get("productOutput");
|
//修改状态
|
productOutput.setState(ProductOutStateStringValues.CHANGESHIFT);
|
productOutputMapper.updateById(productOutput);
|
return true;
|
}
|
|
/**
|
* 交班到草稿
|
*
|
* @param stateMachine
|
* @param msg
|
* @return
|
*/
|
@OnTransition(source = ProductOutStateStringValues.CHANGESHIFT, target = ProductOutStateStringValues.DRAFT)
|
public boolean ChangeShiftTodraft(StateMachine stateMachine, Message<ProductOutEvents> msg) {
|
ProductOutput productOutput = (ProductOutput) msg.getHeaders().get("productOutput");
|
Integer shiftedNumber = productOutputMapper.getShiftedNumberByOutputIds(Lists.newArrayList(productOutput.getId()));
|
if (shiftedNumber > 0) {
|
stateMachine.getExtendedState().getVariables().put(StateMachineHandler.ERROR_KEY, "交班后产出已提交无法撤销");
|
return false;
|
}
|
// 清空交班id数据
|
productOutputMapper.clearShiftOutputId(productOutput.getId());
|
|
//修改状态
|
productOutput.setState(ProductOutStateStringValues.DRAFT);
|
productOutputMapper.updateById(productOutput);
|
return true;
|
}
|
|
/**
|
* 自动报检
|
*
|
* @param productOutput
|
* @param revoke
|
*/
|
private void autoInspection(ProductOutput productOutput, boolean revoke) {
|
//1.根据产出查工单-制造订单-工艺工序的配置(检验/自动报检)
|
MoRoutingOperation routingOperation = moRoutingOperationMapper.findByProductMainId(productOutput.getProductMainId());
|
ProductMain productMain = productMainMapper.selectById(productOutput.getProductMainId());
|
if (routingOperation != null) {
|
if (routingOperation.getInspection() == null || routingOperation.getInspection() == false) {
|
//不检测进行的操作
|
addStock(productMain, WorkstationLocation.QUALIFIED_LOCATION, productOutput, revoke, routingOperation.getIsLast());
|
//解除工作台提交时与尾检的琐定【2022-09-20】
|
//resultUtils.addOrUpdateResult(productOutput.getSystemNo(), productOutput.getOutBatchNo(), ResultStateStringValues.NOTEST, null, null, true, null, productOutput.getPartId(), null, Apply.OUTPUT_APPLY);
|
if(!revoke){
|
//撤销产出时不去创建检测结果【2022-09-20】
|
resultUtils.addOrUpdateResult(productOutput.getSystemNo(), productOutput.getOutBatchNo(), ResultStateStringValues.NOTEST, null, null, true, null, productOutput.getPartId(), null, testApplyRuleUtils.getApplyTypeBySystemNo(productOutput.getSystemNo()));
|
}
|
} else {
|
//自动报检进行的操作
|
addStock(productMain, WorkstationLocation.INSPECTION_LOCATION, productOutput, revoke, routingOperation.getIsLast());
|
if (routingOperation.getAutoInspection() == null || !routingOperation.getAutoInspection()) {
|
//3.检验,手动报检:不做处理,手动报检时生成检测记录(防止首检这种的,还没产出就要检验)
|
} else {
|
//4.检验,自动报检:
|
//解除工作台提交时与尾检的琐定【2022-09-20】
|
//resultUtils.addOrUpdateResult(productOutput.getSystemNo(), productOutput.getOutBatchNo(), null, null, null, null, productMain.getWorkstationId(), productOutput.getPartId(), null, Apply.OUTPUT_APPLY);
|
if(!revoke){
|
//撤销产出时不去创建检测结果【2022-09-20】
|
resultUtils.addOrUpdateResult(productOutput.getSystemNo(), productOutput.getOutBatchNo(), null, null, null, null, productMain.getWorkstationId(), productOutput.getPartId(), null, testApplyRuleUtils.getApplyTypeBySystemNo(productOutput.getSystemNo()));
|
}
|
// 查零件对应的检验规则
|
int inspectQuantity = 1;
|
Long partId = productOutput.getPartId();
|
Part part = partMapper.selectById(partId);
|
if (part != null && part.getTestRuleId() != null) {
|
//查询报检数量
|
TestRule testRule = testRuleMapper.selectById(part.getTestRuleId());
|
if (testRule != null) {
|
inspectQuantity = testRule.getInspectQuantity().intValue();
|
}
|
}
|
//解除工作台提交时与尾检的琐定【2022-09-20】
|
//resultUtils.addOrUpdateResult(productOutput.getSystemNo(), productOutput.getOutBatchNo(), null, null, null, null, productMain.getWorkstationId(), partId, null, Apply.OUTPUT_APPLY);
|
if(!revoke){
|
//撤销产出时不去创建检测结果【2022-09-20】
|
resultUtils.addOrUpdateResult(productOutput.getSystemNo(), productOutput.getOutBatchNo(), null, null, null, null, productMain.getWorkstationId(), partId, null, testApplyRuleUtils.getApplyTypeBySystemNo(productOutput.getSystemNo()));
|
}
|
//查询当前机台未报检的零件,按报检数量分组自动生成质检申请
|
if (!revoke) {
|
List<Result> resultList = resultMapper.selectList(Wrappers.<Result>query().lambda()
|
.eq(Result::getPartId, partId)
|
.eq(Result::getWorkstationId, productMain.getWorkstationId())
|
//.eq(Result::getApplyType, Apply.OUTPUT_APPLY)//解除工作台提交时与尾检的琐定【2022-09-20】
|
.eq(Result::getApplyType, testApplyRuleUtils.getApplyTypeBySystemNo(productOutput.getSystemNo()))
|
.eq(Result::getIsErp, false)
|
.eq(Result::getSystemNo,productOutput.getSystemNo())//通过锁定产出系统编号暂时使原有的抽检规则失效【2022-09-20】
|
.isNull(Result::getCheckStatus)
|
.orderByAsc(Result::getId));
|
if (CollectionUtil.isNotEmpty(resultList)) {
|
Workstation workstation = workstationMapper.selectById(productMain.getWorkstationId());
|
int count = 0;
|
List<Result> group = new ArrayList<Result>();
|
for (Result result : resultList) {
|
group.add(result);
|
count += 1;
|
if (count == inspectQuantity) {
|
// 创建质检申请
|
ApplyDTO applyDTO = new ApplyDTO();
|
//applyDTO.setApplyType(Apply.OUTPUT_APPLY);//解除工作台提交时与尾检的琐定【2022-09-20】
|
applyDTO.setApplyType(testApplyRuleUtils.getApplyTypeBySystemNo(productOutput.getSystemNo()));
|
applyDTO.setRemark("自动报检:" + workstation.getName());
|
List<ApplyPartDTO> applyPartList = new ArrayList<ApplyPartDTO>();
|
group.stream().forEach(e -> {
|
ApplyPartDTO applyPartDTO = new ApplyPartDTO();
|
applyPartDTO.setSystemNo(e.getSystemNo());
|
applyPartList.add(applyPartDTO);
|
});
|
applyDTO.setApplyPartList(applyPartList);
|
if(applyService.saveDto(applyDTO)){
|
group.stream().forEach(e -> {
|
e.setApplyId(applyDTO.getId());
|
resultMapper.updateById(e);
|
});
|
}
|
group.clear();
|
count = 0;
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
/**
|
* 产出自动进库(不检验进合格,其他进待检)
|
*
|
* @param productMain
|
* @param locationType
|
* @param revoke
|
*/
|
private void addStock(ProductMain productMain, Long locationType, ProductOutput productOutput, boolean revoke, Boolean isLast) {
|
WorkstationLocation workstationLocation = workstationLocationMapper.selectOne(Wrappers.<WorkstationLocation>query().lambda()
|
.eq(WorkstationLocation::getWorkstationId, productMain.getWorkstationId())
|
.eq(WorkstationLocation::getLocationType, locationType));
|
if (workstationLocation == null) {
|
throw new RuntimeException("机台未配置库位,请配置库位后再操作");
|
}
|
OperationTaskDTO operationInfo = operationTaskMapper.getOperationInfoById(productMain.getOperationTaskId());
|
BigDecimal stockQuantityIncrement = productOutput.getProductQty();
|
BigDecimal sstockQuantityIncrement = productOutput.getSproductQty();
|
// 判断是否存在交班产出,叠加交班产出
|
if (productOutput.getShiftOutputId() != null) {
|
List<ProductOutput> shifts = productOutputMapper.selectList(Wrappers.<ProductOutput>lambdaQuery()
|
.eq(ProductOutput::getOutBatchNo, productOutput.getOutBatchNo())
|
.eq(ProductOutput::getState, ProductOutStateStringValues.CHANGESHIFT));
|
stockQuantityIncrement = stockQuantityIncrement.add(shifts.stream().map(ProductOutput::getProductQty).reduce(BigDecimal.ZERO, BigDecimal::add));
|
sstockQuantityIncrement = sstockQuantityIncrement.add(shifts.stream().map(ProductOutput::getSproductQty).reduce(BigDecimal.ZERO, BigDecimal::add));
|
}
|
if (revoke) {
|
stockQuantityIncrement = stockQuantityIncrement.negate();
|
sstockQuantityIncrement = sstockQuantityIncrement.negate();
|
}
|
// 合格库位增加/删除产出
|
if (workstationLocation != null && workstationLocation.getLocationId() != null) {
|
StockAddDTO stockAdd = new StockAddDTO();
|
stockAdd.setPartsId(productOutput.getPartId());
|
stockAdd.setNewLocationId(workstationLocation.getLocationId());
|
stockAdd.setNewPartBatchNo(productOutput.getOutBatchNo());
|
stockAdd.setNewSystemNo(productOutput.getSystemNo());
|
stockAdd.setReelNumber(productOutput.getReelNumber());
|
stockAdd.setCustomerOrderNo(operationInfo.getCustomerOrderNo());
|
stockAdd.setMpsNo(operationInfo.getMpsNo());
|
stockAdd.setOuterColor(operationInfo.getOuterColor());
|
stockAdd.setInsulationColor(operationInfo.getInsulationColor());
|
|
Stock stock = stockUtils.query(stockAdd);
|
|
//将实时库存中的ifs批次号更新成与产出记录中的ifs批次号一致
|
stock.setIfsBatchNo(productOutput.getIfsBatchNo());
|
stockMapper.updateById(stock);
|
|
stockUtils.updateById(stock.getId(), stockQuantityIncrement, BigDecimal.ZERO, sstockQuantityIncrement, BigDecimal.ZERO, null, TransactionType.PRODUCT_SUBMIT.getValue());
|
// 设置是否工序库存
|
setOperationStockStatus(stock, isLast);
|
List<OperationTask> operationTaskList = operationTaskMapper.getLastOperationTask(productMain.getOperationTaskId());
|
if (CollectionUtil.isNotEmpty(operationTaskList)) {
|
for (OperationTask operationTask : operationTaskList) {
|
//如果触发自动预留,实时库存需要预留的数量
|
BigDecimal number = BigDecimal.ZERO;
|
Stock newStock = stockMapper.selectById(stock.getId());
|
RoutingOperation routingOperation = routingOperationMapper.selectById(operationTask.getRoutingOperationId());
|
if (routingOperation != null) {
|
//如果当前工单绑定的工艺路线配置了自动预留并且是提交的时候,计算出预留的数量
|
if (routingOperation.getReserved() && !revoke) {
|
QueryWrapper<OperationTaskMaterialDTO> wrapper = new QueryWrapper<>();
|
OperationTaskMaterialDTO operationTaskMaterial =
|
operationTaskMaterialMapper.getMaterial(wrapper.lambda()
|
.eq(OperationTaskMaterialDTO::getOperationTaskId, operationTask.getId())
|
.eq(OperationTaskMaterialDTO::getPartId, productOutput.getPartId())).get(0);
|
if (operationTaskMaterial != null) { //需求数量 //已预留
|
BigDecimal needNumber = operationTaskMaterial.getQuantityRequired().subtract(operationTaskMaterial.getReservedQuantity());
|
if (needNumber.compareTo(BigDecimal.ZERO) > 0) {
|
if (needNumber.compareTo(newStock.getAvailableStockQuantity()) < 0) {//可用库存数量
|
number = needNumber;
|
} else {
|
number = newStock.getAvailableStockQuantity();
|
}
|
}
|
}
|
}
|
}
|
//如果当前工单绑定的工艺路线配置了自动预留并且是提交的时候,新增工单预留
|
if (routingOperation.getReserved() && !revoke) {
|
joinStockOrderService.addJoinStock(operationTask.getId(), stock, number);
|
}
|
}
|
}
|
}
|
}
|
|
|
private void setOperationStockStatus(Stock stock, Boolean isLast) {
|
if (stock.getOperationStockStatus() == null) {
|
Stock update = new Stock();
|
update.setId(stock.getId());
|
if (isLast != null) {
|
update.setOperationStockStatus(!isLast);
|
} else {
|
update.setOperationStockStatus(true);
|
}
|
stockMapper.updateById(update);
|
}
|
}
|
}
|