package com.ruoyi.production.service.impl; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; 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.deepoove.poi.XWPFTemplate; import com.deepoove.poi.data.PictureRenderData; import com.deepoove.poi.data.Pictures; import com.ruoyi.common.utils.MatrixToImageWriter; import com.ruoyi.production.dto.ProductWorkOrderDto; import com.ruoyi.production.dto.ProductStructureDto; import com.ruoyi.production.mapper.*; import com.ruoyi.production.pojo.*; import com.ruoyi.production.service.ProductWorkOrderService; import com.ruoyi.quality.mapper.QualityInspectMapper; import com.ruoyi.quality.mapper.QualityUnqualifiedMapper; import com.ruoyi.quality.pojo.QualityInspect; import com.ruoyi.quality.pojo.QualityUnqualified; 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 javax.servlet.http.HttpServletResponse; import java.io.InputStream; import java.io.OutputStream; import java.math.BigDecimal; import java.math.RoundingMode; import java.net.URLEncoder; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @Service @Transactional(rollbackFor = Exception.class) public class ProductWorkOrderServiceImpl extends ServiceImpl implements ProductWorkOrderService { @Autowired private ProductWorkOrderMapper productWorkOrdermapper; @Autowired private ProductWorkOrderFileMapper productWorkOrderFileMapper; @Autowired private ProductProcessRouteItemMapper productProcessRouteItemMapper; @Autowired private ProductProcessMapper productProcessMapper; @Autowired private ProductProcessRouteMapper productProcessRouteMapper; @Autowired private ProductStructureMapper productStructureMapper; @Autowired private ProductionProductMainMapper productionProductMainMapper; @Autowired private ProductionProductOutputMapper productionProductOutputMapper; @Autowired private ProductionProductInputMapper productionProductInputMapper; @Autowired private QualityUnqualifiedMapper qualityUnqualifiedMapper; @Autowired private QualityInspectMapper qualityInspectMapper; @Value("${file.temp-dir}") private String tempDir; @Override public IPage listPage(Page page, ProductWorkOrderDto productWorkOrder) { IPage productWorkOrderDtoIPage = productWorkOrdermapper.pageProductWorkOrder(page, productWorkOrder); Map bomInputQtyCache = new HashMap<>(); productWorkOrderDtoIPage.getRecords().forEach(record -> { // 是否能报工: 1. 第一个工序能报工 2. 上一个工序已报工 3. 之前的工序未被隔离 Integer currentDragSort = record.getDragSort(); if (currentDragSort == null || currentDragSort == 1) { record.setIsCanReport(true); } else { // 上一个工序是否已报工 boolean isPreviousReported = productionProductMainMapper.checkPreviousProcessReported( record.getId(), currentDragSort ); record.setIsCanReport(isPreviousReported); // 之前的工序是否被隔离 if (record.getIsCanReport()) { // 查询所有之前的工序(排序号小于当前工序) List previousItems = productProcessRouteItemMapper.selectList( Wrappers.lambdaQuery() .eq(ProductProcessRouteItem::getProductRouteId, record.getProductRouteId()) .lt(ProductProcessRouteItem::getDragSort, currentDragSort) ); if (CollectionUtils.isNotEmpty(previousItems)) { // 提取之前工序的名称列表 List previousProcessNames = new ArrayList<>(); for (ProductProcessRouteItem item : previousItems) { ProductProcess process = productProcessMapper.selectById(item.getProcessId()); if (process != null) { previousProcessNames.add(process.getName()); } } // 检查之前的工序是否有被隔离的不合格记录 List unqualifiedList = Collections.emptyList(); if (CollectionUtils.isNotEmpty(previousProcessNames)) { unqualifiedList = qualityUnqualifiedMapper.selectUnqualifiedByProductOrderAndProcessNames( record.getProductOrderId(), previousProcessNames ); } if (CollectionUtils.isNotEmpty(unqualifiedList)) { record.setIsCanReport(false); } } } } // 查询当前实际的合格率 // 查询关联产出表数据 List productionProductMains = productionProductMainMapper.selectList(Wrappers.lambdaQuery().eq(ProductionProductMain::getWorkOrderId, record.getId())); BigDecimal totalScrapQty = BigDecimal.ZERO; if (CollectionUtils.isNotEmpty(productionProductMains)) { // 计算报废数量 List mainIds = productionProductMains.stream().map(ProductionProductMain::getId).collect(Collectors.toList()); List productionProductOutputs = productionProductOutputMapper.selectList(Wrappers.lambdaQuery().in(ProductionProductOutput::getProductMainId, mainIds)); totalScrapQty = productionProductOutputs.stream().map(ProductionProductOutput::getScrapQty).reduce(BigDecimal.ZERO, BigDecimal::add); } if (record.getCompleteQuantity().compareTo(BigDecimal.ZERO) > 0) { record.setActualQualifiedRate((record.getCompleteQuantity().subtract(totalScrapQty)) .divide(record.getCompleteQuantity(), 2, RoundingMode.HALF_UP) .multiply(new BigDecimal("100")) ); } else { record.setActualQualifiedRate((record.getCompleteQuantity().subtract(totalScrapQty)).multiply(BigDecimal.valueOf(100))); } // 查询当前工单对应产品结构中的标准投入数量 String bomInputQtyCacheKey = record.getProductRouteId() + "_" + record.getProcessId() + "_" + record.getPlanQuantity(); BigDecimal bomInputQty = bomInputQtyCache.get(bomInputQtyCacheKey); if (bomInputQty == null) { bomInputQty = BigDecimal.ZERO; ProductProcessRoute productProcessRoute = productProcessRouteMapper.selectById(record.getProductRouteId()); if (productProcessRoute != null && productProcessRoute.getBomId() != null && record.getProcessId() != null) { List productStructureDtos = productStructureMapper.listBybomAndProcess( productProcessRoute.getBomId(), record.getProcessId() ); if (CollectionUtils.isEmpty(productStructureDtos)) { bomInputQty = record.getPlanQuantity() == null ? BigDecimal.ZERO : record.getPlanQuantity(); } else { Set parentIds = productStructureDtos.stream() .map(ProductStructureDto::getParentId) .filter(Objects::nonNull) .collect(Collectors.toSet()); Map parentMap = new HashMap<>(); if (CollectionUtils.isNotEmpty(parentIds)) { parentMap = productStructureMapper.selectByIds(parentIds) .stream() .collect(Collectors.toMap(ProductStructureDto::getId, Function.identity(), (a, b) -> a)); } BigDecimal planQty = record.getPlanQuantity() == null ? BigDecimal.ZERO : record.getPlanQuantity(); for (ProductStructureDto productStructureDto : productStructureDtos) { BigDecimal childQty = productStructureDto.getUnitQuantity(); if (childQty == null || childQty.compareTo(BigDecimal.ZERO) <= 0) { continue; } BigDecimal parentQty = BigDecimal.ONE; if (productStructureDto.getParentId() != null) { ProductStructureDto parent = parentMap.get(productStructureDto.getParentId()); if (parent != null && parent.getUnitQuantity() != null && parent.getUnitQuantity().compareTo(BigDecimal.ZERO) > 0) { parentQty = parent.getUnitQuantity(); } } if (parentQty.compareTo(BigDecimal.ZERO) <= 0) { continue; } bomInputQty = bomInputQty.add( childQty.divide(parentQty, 6, RoundingMode.HALF_UP).multiply(planQty) ); } } } bomInputQtyCache.put(bomInputQtyCacheKey, bomInputQty); } record.setBomInputQty(bomInputQty); }); return productWorkOrderDtoIPage; } @Override public int updateProductWorkOrder(ProductWorkOrderDto productWorkOrderDto) { return productWorkOrdermapper.updateById(productWorkOrderDto); } @Override public void down(HttpServletResponse response, ProductWorkOrder productWorkOrder) { ProductWorkOrderDto productWorkOrderDto = productWorkOrdermapper.getProductWorkOrderFlowCard(productWorkOrder.getId()); String codePath; try { codePath = new MatrixToImageWriter().code(productWorkOrderDto.getId().toString(), tempDir); } catch (Exception e) { throw new RuntimeException(e); } /*获取附件图片类型*/ List> images = new ArrayList<>(); List productWorkOrderFiles = productWorkOrderFileMapper.selectList(Wrappers.lambdaQuery().eq(ProductWorkOrderFile::getWorkOrderId, productWorkOrder.getId())); if (CollectionUtils.isNotEmpty(productWorkOrderFiles)) { productWorkOrderFiles.forEach(productWorkOrderFile -> { Map image = new HashMap<>(); PictureRenderData pictureRenderData = Pictures.ofLocal( productWorkOrderFile.getUrl()).sizeInCm(17, 20).create(); image.put("url", pictureRenderData); images.add(image); }); } InputStream inputStream = this.getClass().getResourceAsStream("/static/work-order-template.docx"); XWPFTemplate template = XWPFTemplate.compile(inputStream).render( new HashMap() {{ put("process", productWorkOrderDto.getProcessName()); put("workOrderNo", productWorkOrderDto.getWorkOrderNo()); put("productOrderNpsNo", productWorkOrderDto.getProductOrderNpsNo()); put("productName", productWorkOrderDto.getProductName()); put("planQuantity", productWorkOrderDto.getPlanQuantity()); put("model", productWorkOrderDto.getModel()); put("unit", productWorkOrderDto.getUnit()); put("completeQuantity", productWorkOrderDto.getCompleteQuantity()); put("scrapQty", productWorkOrderDto.getScrapQty()); put("planStartTime", productWorkOrderDto.getPlanStartTime()); put("planEndTime", productWorkOrderDto.getPlanEndTime()); put("actualStartTime", productWorkOrderDto.getActualStartTime()); put("actualEndTime", productWorkOrderDto.getActualEndTime()); put("twoCode", Pictures.ofLocal(codePath).create()); put("images", images.isEmpty()?null:images); }}); try { response.setContentType("application/msword"); String fileName = URLEncoder.encode( "流转卡", "UTF-8"); response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".docx"); OutputStream os = response.getOutputStream(); template.write(os); os.flush(); os.close(); inputStream.close(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("导出失败"); } } @Override public List getByProductOrderId(Long productOrderId) { List productWorkOrderDtos = productWorkOrdermapper.getByProductOrderId(productOrderId); if (CollectionUtils.isNotEmpty(productWorkOrderDtos)) { productWorkOrderDtos.forEach(productWorkOrderDto -> { // 查询关联产出表数据 List productionProductMains = productionProductMainMapper.selectList(Wrappers.lambdaQuery().eq(ProductionProductMain::getWorkOrderId, productWorkOrderDto.getId())); // 查询报废数量 BigDecimal scrapQty = BigDecimal.ZERO; // 查询不良数量 BigDecimal defectiveQuantity = BigDecimal.ZERO; // 查询投入数量 BigDecimal inputQty = BigDecimal.ZERO; if (CollectionUtils.isNotEmpty(productionProductMains)) { // 计算报废数量 List mainIds = productionProductMains.stream().map(ProductionProductMain::getId).collect(Collectors.toList()); List productionProductOutputs = productionProductOutputMapper.selectList(Wrappers.lambdaQuery().in(ProductionProductOutput::getProductMainId, mainIds)); List qualityInspects = qualityInspectMapper.selectList(Wrappers.lambdaQuery().in(QualityInspect::getProductMainId, mainIds)); if (CollectionUtils.isNotEmpty(productionProductOutputs)) { scrapQty = productionProductOutputs.stream().map(ProductionProductOutput::getScrapQty).reduce(BigDecimal.ZERO, BigDecimal::add); } List productionProductInputs = productionProductInputMapper.selectList(Wrappers.lambdaQuery().in(ProductionProductInput::getProductMainId, mainIds)); if (CollectionUtils.isNotEmpty(productionProductInputs)) { inputQty = productionProductInputs.stream().map(ProductionProductInput::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add); } if (CollectionUtils.isNotEmpty(qualityInspects)) { defectiveQuantity = qualityInspects.stream().map(QualityInspect::getDefectiveQuantity).reduce(BigDecimal.ZERO, BigDecimal::add); } } BigDecimal totalQuantity = productWorkOrderDto.getCompleteQuantity().add(scrapQty); if (totalQuantity.compareTo(BigDecimal.ZERO) > 0) { productWorkOrderDto.setDefectiveRate(defectiveQuantity.divide(productWorkOrderDto.getCompleteQuantity(), 4, RoundingMode.HALF_UP)); } else { productWorkOrderDto.setDefectiveRate(defectiveQuantity.multiply(BigDecimal.valueOf(100))); } productWorkOrderDto.setInputQty(inputQty); productWorkOrderDto.setScrapQty(scrapQty); productWorkOrderDto.setTotalQty(totalQuantity); productWorkOrderDto.setDefectiveQuantity(defectiveQuantity); productWorkOrderDto.setCompleteQty(productWorkOrderDto.getCompleteQuantity().subtract(defectiveQuantity)); }); } return productWorkOrderDtos; } }