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 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.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 applyPartList = applyPartMapper.selectApplyApertByInspState(productOutput.getOutBatchNo(), Apply.OUTPUT_APPLY);//这里的检测类型传参无效,无需解锁 if (!CollectionUtils.isEmpty(applyPartList)) { List applyPartListChecked = applyPartList.stream().filter(e -> null != e.getReportId()).collect(Collectors.toList()); if (CollectionUtils.isEmpty(applyPartListChecked)) { //没有进行检测汇报,先删除检测申请数据,再删除报工数据 List applyIds = applyPartList.stream().map(ApplyPart::getApplyId).collect(Collectors.toList()); List 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 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 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 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 resultList = resultMapper.selectList(Wrappers.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 group = new ArrayList(); 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 applyPartList = new ArrayList(); 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.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 shifts = productOutputMapper.selectList(Wrappers.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 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 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); } } }