已添加3个文件
已修改29个文件
908 ■■■■ 文件已修改
pom.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/pojo/ProductModel.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/utils/MatrixToImageWriter.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordController.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/dto/ProcurementPageDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/dto/ProcurementPageDtoCopy.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/pojo/ProcurementRecordStorage.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordServiceImpl.java 230 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductBomController.java 48 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductOrderController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductStructureController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductWorkOrderController.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/BomImportDto.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProductWorkOrderDto.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductStructureMapper.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductWorkOrderMapper.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProcessRoute.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductProcessRoute.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductStructure.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductBomService.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductOrderService.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductStructureService.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductWorkOrderService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductBomServiceImpl.java 248 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductStructureServiceImpl.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductWorkOrderServiceImpl.java 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/basic/ProductModelMapper.xml 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/procurementrecord/ProcurementRecordMapper.xml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductWorkOrderMapper.xml 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/static/work-order-template.docx 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -301,6 +301,12 @@
            <artifactId>easyexcel</artifactId>
            <version>4.0.3</version>
        </dependency>
         <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.3.3</version>
        </dependency>
    </dependencies>
src/main/java/com/ruoyi/basic/pojo/ProductModel.java
@@ -63,4 +63,8 @@
    @TableField(exist = false)
    private LocalDateTime createTime;
    @TableField(exist = false)
    private Boolean  isFrozen;
}
src/main/java/com/ruoyi/common/utils/MatrixToImageWriter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,67 @@
package com.ruoyi.common.utils;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
/**
 * é…ç½®å›¾åƒå†™å…¥å™¨
 *
 * @author z1292
 *
 */
public class MatrixToImageWriter {
    private final int BLACK = 0xFF000000;
    private final int WHITE = 0xFFFFFFFF;
    private BufferedImage toBufferedImage(BitMatrix matrix) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
            }
        }
        return image;
    }
    private void writeToFile(BitMatrix matrix, String format, File file) throws IOException {
        BufferedImage image = toBufferedImage(matrix);
        if (!ImageIO.write(image, format, file)) {
            throw new RuntimeException("Could not write an image of format " + format + " to " + file);
        }
    }
    public String code(String content, String path) {
        try {
            String codeName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yy_MM_dd&HH_mm_ss"));// äºŒç»´ç çš„图片名
            String imageType = "jpg";// å›¾ç‰‡ç±»åž‹
            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            hints.put(EncodeHintType.MARGIN, 0);
            BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, 400, 400, hints);
            File file1 = new File(path, codeName + "." + imageType);
            writeToFile(bitMatrix, imageType, file1);
            return file1.getPath();
        } catch (WriterException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        throw new RuntimeException("二维码生成失败");
    }
}
src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordController.java
@@ -156,6 +156,48 @@
        return AjaxResult.success(result);
    }
    @PostMapping("frozenStorageQuality")
    @Log(title = "采购入库-库存管理-冻结不合格产品", businessType = BusinessType.UPDATE)
    public AjaxResult frozenStorageQuality(@RequestBody List<Integer> frozenIds) {
        boolean result = procurementRecordService.frozenStorageQuality(frozenIds);
        if (result) {
            return AjaxResult.success();
        }
        return AjaxResult.error();
    }
    @PostMapping("thawStorageQuality")
    @Log(title = "采购入库-库存管理-解冻不合格产品", businessType = BusinessType.UPDATE)
    public AjaxResult thawStorageQuality(@RequestBody List<Integer> thawIds) {
        boolean result = procurementRecordService.thawStorageQuality(thawIds);
        if (result) {
            return AjaxResult.success();
        }
        return AjaxResult.error();
    }
    @PostMapping("frozenFinishedQuality")
    @Log(title = "采购入库-库存管理-冻结不合格产品", businessType = BusinessType.UPDATE)
    public AjaxResult frozenFinishedQuality(@RequestBody List<Integer> frozenIds) {
        boolean result = procurementRecordService.frozenFinishedQuality(frozenIds);
        if (result) {
            return AjaxResult.success();
        }
        return AjaxResult.error();
    }
    @PostMapping("thawFinishedQuality")
    @Log(title = "采购入库-库存管理-解冻不合格产品", businessType = BusinessType.UPDATE)
    public AjaxResult thawFinishedQuality(@RequestBody List<Integer> thawIds) {
        boolean result = procurementRecordService.thawFinishedQuality(thawIds);
        if (result) {
            return AjaxResult.success();
        }
        return AjaxResult.error();
    }
    @GetMapping("/listPageCopyByProduction")
    @Log(title = "生产入库-库存管理-分页查询", businessType = BusinessType.OTHER)
    public AjaxResult listPageCopyByProduction(Page page, ProcurementPageDto procurementDto) {
src/main/java/com/ruoyi/procurementrecord/dto/ProcurementPageDto.java
@@ -194,4 +194,8 @@
    private Long productModelId;
    @ApiModelProperty(value = "是否冻结(0:未冻结 1:已冻结)")
    @Excel(name = "是否冻结")
    private Boolean isFrozen;
}
src/main/java/com/ruoyi/procurementrecord/dto/ProcurementPageDtoCopy.java
@@ -203,4 +203,7 @@
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    private LocalDate endDate;
    @Excel(name = "是否冻结")
    private Boolean isFrozen;
}
src/main/java/com/ruoyi/procurementrecord/pojo/ProcurementRecordStorage.java
@@ -102,4 +102,9 @@
    private Long productModelId;
    private Long qualityInspectId;
    /**
     * æ˜¯å¦å†»ç»“(0:未冻结 1:已冻结)
     */
    private Boolean isFrozen;
}
src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordService.java
@@ -63,4 +63,12 @@
    IPage<ProductModel> listPageProductionStock(Page page, ProcurementPageDto procurementDto);
    IPage<ProcurementPageDto> listPageByProductProduction(Page page, ProcurementPageDto procurementDto);
    boolean frozenStorageQuality(List<Integer> frozenIds);
    boolean thawStorageQuality(List<Integer> thawIds);
    boolean frozenFinishedQuality(List<Integer> frozenIds);
    boolean thawFinishedQuality(List<Integer> thawIds);
}
src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordServiceImpl.java
@@ -1,12 +1,14 @@
package com.ruoyi.procurementrecord.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.basic.service.IProductModelService;
import com.ruoyi.common.utils.OrderUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -55,19 +57,21 @@
    private final StockUtils stockUtils;
    private final ProductModelMapper productModelMapper;
    private final IProductModelService productModelService;
    @Override
    public List<ProcurementDto> listProcurementBySalesLedgerId(ProcurementDto procurementDto) {
        List<ProcurementDto> procurementDtos = procurementRecordMapper.listProcurementBySalesLedgerId(procurementDto);
        // è®¡ç®—待入库数量
        // æŸ¥è¯¢é‡‡è´­è®°å½•已入库数量
        List<Integer> collect = procurementDtos.stream().map(ProcurementDto::getId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty( collect)){
        if (CollectionUtils.isEmpty(collect)) {
            return procurementDtos;
        }
        LambdaQueryWrapper<ProcurementRecordStorage> procurementRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        procurementRecordLambdaQueryWrapper.in(ProcurementRecordStorage::getSalesLedgerProductId, collect);
        List<ProcurementRecordStorage> procurementRecordStorages = procurementRecordMapper.selectList(procurementRecordLambdaQueryWrapper);
        if(CollectionUtils.isEmpty(procurementRecordStorages)){
        if (CollectionUtils.isEmpty(procurementRecordStorages)) {
            return procurementDtos;
        }
        for (ProcurementDto dto : procurementDtos) {
@@ -77,7 +81,7 @@
                    .collect(Collectors.toList());
            // å¦‚果没有相关的入库记录,跳过该条数据
            if(CollectionUtils.isEmpty(collect1)){
            if (CollectionUtils.isEmpty(collect1)) {
                dto.setQuantity0(dto.getQuantity());
                continue;
            }
@@ -93,17 +97,17 @@
        return procurementDtos;
    }
    public ProcurementRecordStorage getProcurementRecordById(Integer id){
    public ProcurementRecordStorage getProcurementRecordById(Integer id) {
        ProcurementRecordStorage procurementRecordStorage = procurementRecordMapper.selectById(id);
        if(procurementRecordStorage == null) {
        if (procurementRecordStorage == null) {
            throw new RuntimeException("未找到该采购入库记录");
        }
        return procurementRecordStorage;
    }
    public List<ProcurementRecordStorage> getProcurementRecordByIds(List<Integer> id){
    public List<ProcurementRecordStorage> getProcurementRecordByIds(List<Integer> id) {
        List<ProcurementRecordStorage> procurementRecordStorage = procurementRecordMapper.selectBatchIds(id);
        if(procurementRecordStorage == null) {
        if (procurementRecordStorage == null) {
            throw new RuntimeException("未找到该采购入库记录");
        }
        return procurementRecordStorage;
@@ -128,26 +132,26 @@
        // åˆ é™¤æ‰€æœ‰å¯¹åº”的出库记录
        LambdaQueryWrapper<ProcurementRecordOut> procurementRecordOutLambdaQueryWrapper = new LambdaQueryWrapper<>();
        procurementRecordOutLambdaQueryWrapper.in(ProcurementRecordOut::getProcurementRecordStorageId, procurementDto.getIds())
                .eq(ProcurementRecordOut::getType,procurementDto.getType());
                .eq(ProcurementRecordOut::getType, procurementDto.getType());
        List<ProcurementRecordOut> procurementRecordOuts = procurementRecordOutMapper.selectList(procurementRecordOutLambdaQueryWrapper);
        if(!CollectionUtils.isEmpty(procurementRecordOuts)){
        if (!CollectionUtils.isEmpty(procurementRecordOuts)) {
            procurementRecordOutMapper.deleteBatchIds(procurementRecordOuts.stream().map(ProcurementRecordOut::getId).collect(Collectors.toList()));
        }
        return 0;
    }
    @Override
    public void export(HttpServletResponse response,Integer type) {
    public void export(HttpServletResponse response, Integer type) {
        List<ProcurementPageDto> list = new ArrayList<>();
        if(type == 1){
        if (type == 1) {
            list = procurementRecordMapper.list();
        }else{
        } else {
            list = procurementRecordMapper.listOne();
        }
        // è®¡ç®—待入库数量
        // æŸ¥è¯¢é‡‡è´­è®°å½•已入库数量
        List<Integer> collect = list.stream().map(ProcurementPageDto::getId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty( collect)){
        if (CollectionUtils.isEmpty(collect)) {
            ExcelUtil<ProcurementPageDto> util = new ExcelUtil<ProcurementPageDto>(ProcurementPageDto.class);
            util.exportExcel(response, list, "入库台账");
            return;
@@ -156,7 +160,7 @@
        procurementRecordLambdaQueryWrapper.in(ProcurementRecordOut::getProcurementRecordStorageId, collect);
        procurementRecordLambdaQueryWrapper.eq(ProcurementRecordOut::getType, type);
        List<ProcurementRecordOut> procurementRecords = procurementRecordOutMapper.selectList(procurementRecordLambdaQueryWrapper);
        if(CollectionUtils.isEmpty( procurementRecords)){
        if (CollectionUtils.isEmpty(procurementRecords)) {
            ExcelUtil<ProcurementPageDto> util = new ExcelUtil<ProcurementPageDto>(ProcurementPageDto.class);
            util.exportExcel(response, list, "入库台账");
            return;
@@ -168,7 +172,7 @@
                    .collect(Collectors.toList());
            // å¦‚果没有相关的出库记录,跳过该条数据
            if(CollectionUtils.isEmpty(collect1)){
            if (CollectionUtils.isEmpty(collect1)) {
                dto.setInboundNum0(dto.getInboundNum());
                continue;
            }
@@ -191,14 +195,14 @@
    public int updateManagement(ProcurementManagementUpdateDto procurementDto) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser sysUser = sysUserMapper.selectUserById(procurementDto.getCreateUser());
        if(sysUser == null){
        if (sysUser == null) {
            throw new RuntimeException("入库人不存在");
        }
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String entryDateStr = procurementDto.getEntryDate() + " 00:00:00";
        String createTimeStr = procurementDto.getCreateTime() + " 00:00:00";
        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(procurementDto.getSalesLedgerProductId());
        if(salesLedgerProduct == null){
        if (salesLedgerProduct == null) {
            throw new RuntimeException("销售台账产品不存在");
        }
        // æ ¹æ®å¤§ç±»ï¼Œè§„格查询所有产品id
@@ -207,7 +211,7 @@
                .eq(SalesLedgerProduct::getSpecificationModel, salesLedgerProduct.getSpecificationModel())
                .eq(SalesLedgerProduct::getType, 1);
        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(salesLedgerProductLambdaQueryWrapper);
        if(CollectionUtils.isEmpty(salesLedgerProducts)){
        if (CollectionUtils.isEmpty(salesLedgerProducts)) {
            throw new RuntimeException("没有找到对应的产品");
        }
        salesLedgerProduct.setMinStock(procurementDto.getMinStock());
@@ -219,25 +223,25 @@
        procurementRecordStorage.setTotalPrice(procurementDto.getTotalPrice());
        procurementRecordStorage.setCreateBy(sysUser.getNickName());
        procurementRecordStorage.setCreateUser(sysUser.getUserId());
        procurementRecordStorage.setUpdateTime(LocalDateTime.parse(entryDateStr,df));
        procurementRecordStorage.setUpdateTime(LocalDateTime.parse(entryDateStr, df));
        procurementRecordStorage.setUpdateUser(loginUser.getUserId());
        procurementRecordStorage.setCreateTime(LocalDateTime.parse(createTimeStr,df));
        procurementRecordMapper.update(procurementRecordStorage,procurementRecordStorageLambdaQueryWrapper);
        procurementRecordStorage.setCreateTime(LocalDateTime.parse(createTimeStr, df));
        procurementRecordMapper.update(procurementRecordStorage, procurementRecordStorageLambdaQueryWrapper);
        return 0;
    }
    @Override
    public void exportCopy(HttpServletResponse response,Integer type) {
    public void exportCopy(HttpServletResponse response, Integer type) {
        List<ProcurementPageDtoCopy> list = new ArrayList<>();
        if(type == 1){
        if (type == 1) {
            list = procurementRecordMapper.listCopy();
        }else{
        } else {
            list = procurementRecordMapper.listCopyOne();
        }
        // è®¡ç®—待入库数量
        // æŸ¥è¯¢é‡‡è´­è®°å½•已入库数量
        List<Integer> collect = list.stream().map(ProcurementPageDtoCopy::getId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty( collect)){
        if (CollectionUtils.isEmpty(collect)) {
            ExcelUtil<ProcurementPageDtoCopy> util = new ExcelUtil<ProcurementPageDtoCopy>(ProcurementPageDtoCopy.class);
            util.exportExcel(response, list, "库存管理");
            return;
@@ -246,7 +250,7 @@
        procurementRecordLambdaQueryWrapper.in(ProcurementRecordOut::getProcurementRecordStorageId, collect);
        procurementRecordLambdaQueryWrapper.eq(ProcurementRecordOut::getType, type);
        List<ProcurementRecordOut> procurementRecords = procurementRecordOutMapper.selectList(procurementRecordLambdaQueryWrapper);
        if(CollectionUtils.isEmpty( procurementRecords)){
        if (CollectionUtils.isEmpty(procurementRecords)) {
            ExcelUtil<ProcurementPageDtoCopy> util = new ExcelUtil<ProcurementPageDtoCopy>(ProcurementPageDtoCopy.class);
            util.exportExcel(response, list, "库存管理");
            return;
@@ -258,7 +262,7 @@
                    .collect(Collectors.toList());
            // å¦‚果没有相关的出库记录,跳过该条数据
            if(CollectionUtils.isEmpty(collect1)){
            if (CollectionUtils.isEmpty(collect1)) {
                dto.setInboundNum0(dto.getInboundNum());
                continue;
            }
@@ -276,14 +280,14 @@
    }
    @Override
    public void exportCopyTwo(HttpServletResponse response,Integer type) {
    public void exportCopyTwo(HttpServletResponse response, Integer type) {
        LambdaQueryWrapper<CustomStorage> customStorageLambdaQueryWrapper = new LambdaQueryWrapper<>();
        customStorageLambdaQueryWrapper.groupBy(CustomStorage::getSupplierName, CustomStorage::getProductCategory, CustomStorage::getSpecificationModel);
        List<CustomStorage> list = customStorageMapper.selectList(customStorageLambdaQueryWrapper);
        // è®¡ç®—待入库数量
        // æŸ¥è¯¢é‡‡è´­è®°å½•已入库数量
        List<Integer> collect = list.stream().map(CustomStorage::getId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty( collect)){
        if (CollectionUtils.isEmpty(collect)) {
            ExcelUtil<CustomStorage> util = new ExcelUtil<CustomStorage>(CustomStorage.class);
            util.exportExcel(response, list, "库存管理");
            return;
@@ -293,7 +297,7 @@
        procurementRecordLambdaQueryWrapper.eq(ProcurementRecordOut::getType, type);
        procurementRecordLambdaQueryWrapper.eq(ProcurementRecordOut::getType, type);
        List<ProcurementRecordOut> procurementRecords = procurementRecordOutMapper.selectList(procurementRecordLambdaQueryWrapper);
        if(CollectionUtils.isEmpty( procurementRecords)){
        if (CollectionUtils.isEmpty(procurementRecords)) {
            ExcelUtil<CustomStorage> util = new ExcelUtil<CustomStorage>(CustomStorage.class);
            util.exportExcel(response, list, "库存管理");
            return;
@@ -305,7 +309,7 @@
                    .collect(Collectors.toList());
            // å¦‚果没有相关的出库记录,跳过该条数据
            if(CollectionUtils.isEmpty(collect1)){
            if (CollectionUtils.isEmpty(collect1)) {
                dto.setInboundNum0(dto.getInboundNum());
                continue;
            }
@@ -335,19 +339,19 @@
        reportData.put("tableData", procurementPageDtoCopyList);
        // æŸ¥è¯¢é‡‡è´­è®°å½•已入库数量
        List<Integer> collect = procurementPageDtoCopyList.stream().map(ProcurementPageDtoCopy::getId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(collect)){
             return reportData;
        if (CollectionUtils.isEmpty(collect)) {
            return reportData;
        }
        LambdaQueryWrapper<ProcurementRecordOut> procurementRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        procurementRecordLambdaQueryWrapper.in(ProcurementRecordOut::getProcurementRecordStorageId, collect);
        List<ProcurementRecordOut> procurementRecords = procurementRecordOutMapper.selectList(procurementRecordLambdaQueryWrapper);
        if(CollectionUtils.isEmpty( procurementRecords)){
             return reportData;
        if (CollectionUtils.isEmpty(procurementRecords)) {
            return reportData;
        }
        int totalIn =0;
        int totalOut =0;
        int currentStock =0;
        int turnoverRate =0;
        int totalIn = 0;
        int totalOut = 0;
        int currentStock = 0;
        int turnoverRate = 0;
        List<String> dates = new ArrayList<>();
        List<Integer> values = new ArrayList<>();
        List<String> comparisonDates = new ArrayList<>();
@@ -365,7 +369,7 @@
                    .collect(Collectors.toList());
            // å¦‚果没有相关的出库记录,跳过该条数据
            if(CollectionUtils.isEmpty(collect1)){
            if (CollectionUtils.isEmpty(collect1)) {
                dto.setInboundNum0(dto.getInboundNum());
                continue;
            }
@@ -388,7 +392,7 @@
            currentStock += dto.getInboundNum().intValue() - totalInboundNum.intValue();
            values.add(currentStock);
            // è®¡ç®—周转率
            if(totalIn > 0){
            if (totalIn > 0) {
                turnoverRate = totalOut * 100 / totalIn;
            }
        }
@@ -424,7 +428,7 @@
    public InventoryInformationDto getReportList() {
        InventoryInformationDto inventoryInformationDto = new InventoryInformationDto();
        IPage<ProcurementPageDto> procurementPageDtoIPage = this.listPage(new Page<>(1, -1), new ProcurementPageDto());
        if(CollectionUtils.isEmpty(procurementPageDtoIPage.getRecords())){
        if (CollectionUtils.isEmpty(procurementPageDtoIPage.getRecords())) {
            return inventoryInformationDto;
        }
        // è®¡ç®—总库存数量
@@ -482,6 +486,7 @@
        inventoryInformationDto.setInventoryChangeValue(inventoryChangeValue.subtract(totalInventoryValue));
        return inventoryInformationDto;
    }
    @Override
    public IPage<ProcurementPageDto> listPageByProduction(Page page, ProcurementPageDto procurementDto) {
        IPage<ProcurementPageDto> procurementPageDtoIPage = procurementRecordMapper.listPageByProduction(page, procurementDto);
@@ -489,14 +494,14 @@
        // è®¡ç®—待入库数量
        // æŸ¥è¯¢é‡‡è´­è®°å½•已入库数量
        List<Integer> collect = procurementPageDtos.stream().map(ProcurementPageDto::getId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty( collect)){
        if (CollectionUtils.isEmpty(collect)) {
            return procurementPageDtoIPage;
        }
        LambdaQueryWrapper<ProcurementRecordOut> procurementRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        procurementRecordLambdaQueryWrapper.in(ProcurementRecordOut::getProcurementRecordStorageId, collect)
                .eq(ProcurementRecordOut::getType,2);
                .eq(ProcurementRecordOut::getType, 2);
        List<ProcurementRecordOut> procurementRecords = procurementRecordOutMapper.selectList(procurementRecordLambdaQueryWrapper);
        if(CollectionUtils.isEmpty( procurementRecords)){
        if (CollectionUtils.isEmpty(procurementRecords)) {
            return procurementPageDtoIPage;
        }
        for (ProcurementPageDto dto : procurementPageDtos) {
@@ -506,7 +511,7 @@
                    .collect(Collectors.toList());
            // å¦‚果没有相关的出库记录,跳过该条数据
            if(CollectionUtils.isEmpty(collect1)){
            if (CollectionUtils.isEmpty(collect1)) {
                dto.setInboundNum0(dto.getInboundNum());
                continue;
            }
@@ -527,13 +532,13 @@
    @Override
    public AjaxResult addCustom(List<CustomStorage> customStorage) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if(CollectionUtils.isEmpty(customStorage)){
        if (CollectionUtils.isEmpty(customStorage)) {
            return AjaxResult.error("数据不能为空");
        }
        customStorage.forEach(item -> {
            // æŸ¥è¯¢é‡‡è´­å…¥åº“数量
            Long aLong = customStorageMapper.selectCount(null);
            item.setInboundBatches(aLong.equals(0L) ? "第1批次(自定义入库)" : "第"+ (aLong + 1) + "批次(自定义入库)" );
            item.setInboundBatches(aLong.equals(0L) ? "第1批次(自定义入库)" : "第" + (aLong + 1) + "批次(自定义入库)");
            item.setCreateBy(loginUser.getNickName());
            item.setCode(OrderUtils.countTodayByCreateTime(customStorageMapper, ""));
            customStorageMapper.insert(item);
@@ -544,15 +549,15 @@
    @Override
    public IPage<CustomStorage> listPageByCustom(Page page, CustomStorage customStorage) {
        LambdaQueryWrapper<CustomStorage> customStorageLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if(customStorage != null){
            if(!StringUtils.isEmpty(customStorage.getSupplierName())){
        if (customStorage != null) {
            if (!StringUtils.isEmpty(customStorage.getSupplierName())) {
                customStorageLambdaQueryWrapper.like(CustomStorage::getSupplierName, customStorage.getSupplierName());
            }
            // ç­›é€‰å…¥åº“æ—¶é—´
            if(customStorage.getTimeStr() != null){
            if (customStorage.getTimeStr() != null) {
                customStorageLambdaQueryWrapper.eq(CustomStorage::getInboundDate, customStorage.getTimeStr());
            }
            if(!StringUtils.isEmpty(customStorage.getProductCategory())){
            if (!StringUtils.isEmpty(customStorage.getProductCategory())) {
                customStorageLambdaQueryWrapper.like(CustomStorage::getProductCategory, customStorage.getProductCategory());
            }
        }
@@ -563,14 +568,14 @@
        // è®¡ç®—待入库数量
        // æŸ¥è¯¢é‡‡è´­è®°å½•已入库数量
        List<Integer> collect = procurementPageDtos.stream().map(CustomStorage::getId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty( collect)){
        if (CollectionUtils.isEmpty(collect)) {
            return procurementPageDtoIPage;
        }
        LambdaQueryWrapper<ProcurementRecordOut> procurementRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        procurementRecordLambdaQueryWrapper.in(ProcurementRecordOut::getProcurementRecordStorageId, collect)
                .eq(ProcurementRecordOut::getType, 3);
        List<ProcurementRecordOut> procurementRecords = procurementRecordOutMapper.selectList(procurementRecordLambdaQueryWrapper);
        if(CollectionUtils.isEmpty( procurementRecords)){
        if (CollectionUtils.isEmpty(procurementRecords)) {
            return procurementPageDtoIPage;
        }
        for (CustomStorage dto : procurementPageDtos) {
@@ -580,7 +585,7 @@
                    .collect(Collectors.toList());
            // å¦‚果没有相关的出库记录,跳过该条数据
            if(CollectionUtils.isEmpty(collect1)){
            if (CollectionUtils.isEmpty(collect1)) {
                dto.setInboundNum0(dto.getInboundNum());
                continue;
            }
@@ -603,7 +608,7 @@
        // è®¡ç®—待入库数量
        // æŸ¥è¯¢é‡‡è´­è®°å½•已入库数量
        List<Integer> collect = procurementPageDtoCopyList.stream().map(ProcurementPageDtoCopy::getId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty( collect)){
        if (CollectionUtils.isEmpty(collect)) {
            return procurementPageDtoCopyIPage;
        }
        // 1. æŸ¥è¯¢é‡‡è´­è®°å½•已入库的出库记录(按storageId分组)
@@ -675,14 +680,14 @@
        // è®¡ç®—待入库数量
        // æŸ¥è¯¢é‡‡è´­è®°å½•已入库数量
        List<Integer> collect = procurementPageDtoCopyList.stream().map(CustomStorage::getId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty( collect)){
        if (CollectionUtils.isEmpty(collect)) {
            return pageList;
        }
        LambdaQueryWrapper<ProcurementRecordOut> procurementRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        procurementRecordLambdaQueryWrapper.in(ProcurementRecordOut::getProcurementRecordStorageId, collect);
        procurementRecordLambdaQueryWrapper.eq(ProcurementRecordOut::getType, 3);
        List<ProcurementRecordOut> procurementRecords = procurementRecordOutMapper.selectList(procurementRecordLambdaQueryWrapper);
        if(CollectionUtils.isEmpty( procurementRecords)){
        if (CollectionUtils.isEmpty(procurementRecords)) {
            return pageList;
        }
        for (CustomStorage dto : procurementPageDtoCopyList) {
@@ -692,7 +697,7 @@
                    .collect(Collectors.toList());
            // å¦‚果没有相关的出库记录,跳过该条数据
            if(CollectionUtils.isEmpty(collect1)){
            if (CollectionUtils.isEmpty(collect1)) {
                dto.setInboundNum0(dto.getInboundNum());
                dto.setTotalInboundNum(BigDecimal.ZERO);
                continue;
@@ -707,7 +712,7 @@
            // å¾…出库数量 = æ€»æ•°é‡ - å·²å‡ºåº“数量
            dto.setInboundNum0(dto.getInboundNum().subtract(totalInboundNum));
            // åº“存价值
            if(dto.getTaxInclusiveUnitPrice() != null){
            if (dto.getTaxInclusiveUnitPrice() != null) {
                dto.setTaxInclusiveTotalPrice(dto.getInboundNum0().multiply(dto.getTaxInclusiveUnitPrice()));
            }
        }
@@ -728,7 +733,7 @@
    @Override
    public int updateManagementByCustom(ProcurementManagementUpdateDto procurementDto) {
        CustomStorage customStorage = customStorageMapper.selectById(procurementDto.getId());
        if(customStorage == null){
        if (customStorage == null) {
            throw new RuntimeException("材料库存不存在");
        }
        LambdaQueryWrapper<CustomStorage> customStorageLambdaQueryWrapper = new LambdaQueryWrapper<>();
@@ -737,7 +742,7 @@
        CustomStorage one = new CustomStorage();
        one.setTaxInclusiveUnitPrice(procurementDto.getTaxInclusiveUnitPrice());
        one.setTaxInclusiveTotalPrice(procurementDto.getTaxInclusiveTotalPrice());
        return customStorageMapper.update(one,customStorageLambdaQueryWrapper);
        return customStorageMapper.update(one, customStorageLambdaQueryWrapper);
    }
    @Override
@@ -746,7 +751,7 @@
        procurementRecordStorageLambdaQueryWrapper.eq(ProcurementRecordStorage::getSalesLedgerProductId, salesProductId)
                .eq(ProcurementRecordStorage::getType, 2);
        List<ProcurementRecordStorage> procurementRecordStorages = procurementRecordMapper.selectList(procurementRecordStorageLambdaQueryWrapper);
        if(CollectionUtils.isEmpty( procurementRecordStorages)){
        if (CollectionUtils.isEmpty(procurementRecordStorages)) {
            return BigDecimal.ZERO;
        }
        return procurementRecordStorages.stream()
@@ -765,12 +770,12 @@
                    .eq(ProcurementRecordStorage::getType, procurementDto.getType());
            Long aLong = procurementRecordMapper.selectCount(procurementRecordLambdaQueryWrapper);
            SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(detail.getId());
            if (ObjectUtils.isNull(detail.getProductModelId())){
            if (ObjectUtils.isNull(detail.getProductModelId())) {
                detail.setProductModelId(salesLedgerProduct.getProductModelId());
            }
            ProcurementRecordStorage.ProcurementRecordStorageBuilder procurementRecordBuilder = ProcurementRecordStorage.builder()
                    .salesLedgerProductId(detail.getId())
                    .inboundBatches(aLong.equals(0L) ? "第1批次("+ procurementDto.getTypeName() +")" : "第"+ (aLong + 1) + "批次(" + procurementDto.getTypeName() + ")" )
                    .inboundBatches(aLong.equals(0L) ? "第1批次(" + procurementDto.getTypeName() + ")" : "第" + (aLong + 1) + "批次(" + procurementDto.getTypeName() + ")")
                    .inboundNum(detail.getInboundQuantity())
                    .type(procurementDto.getType())
                    .warnNum(detail.getWarnNum())
@@ -782,7 +787,7 @@
                    .updateUser(loginUser.getUserId())
                    .createBy(procurementDto.getNickName())
                    .productModelId(detail.getProductModelId())
                    .qualityInspectId(ObjectUtils.isNotNull(procurementDto.getQualityInspectId())?procurementDto.getQualityInspectId():0L);
                    .qualityInspectId(ObjectUtils.isNotNull(procurementDto.getQualityInspectId()) ? procurementDto.getQualityInspectId() : 0L);
            this.save(procurementRecordBuilder.build());
            // å…¥åº“成功减掉采购数量
//            LambdaQueryWrapper<SalesLedgerProduct> salesLedgerProductLambdaQueryWrapper = new LambdaQueryWrapper<>();
@@ -804,14 +809,14 @@
        // è®¡ç®—待入库数量
        // æŸ¥è¯¢é‡‡è´­è®°å½•已入库数量
        List<Integer> collect = procurementPageDtos.stream().map(ProcurementPageDto::getId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty( collect)){
        if (CollectionUtils.isEmpty(collect)) {
            return procurementPageDtoIPage;
        }
        LambdaQueryWrapper<ProcurementRecordOut> procurementRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        procurementRecordLambdaQueryWrapper.in(ProcurementRecordOut::getProcurementRecordStorageId, collect)
                .eq(ProcurementRecordOut::getType, 1);
        List<ProcurementRecordOut> procurementRecords = procurementRecordOutMapper.selectList(procurementRecordLambdaQueryWrapper);
        if(CollectionUtils.isEmpty( procurementRecords)){
        if (CollectionUtils.isEmpty(procurementRecords)) {
            return procurementPageDtoIPage;
        }
        for (ProcurementPageDto dto : procurementPageDtos) {
@@ -821,7 +826,7 @@
                    .collect(Collectors.toList());
            // å¦‚果没有相关的出库记录,跳过该条数据
            if(CollectionUtils.isEmpty(collect1)){
            if (CollectionUtils.isEmpty(collect1)) {
                dto.setInboundNum0(dto.getInboundNum());
                continue;
            }
@@ -844,14 +849,14 @@
        // è®¡ç®—待入库数量
        // æŸ¥è¯¢é‡‡è´­è®°å½•已入库数量
        List<Integer> collect = procurementPageDtoCopyList.stream().map(ProcurementPageDtoCopy::getId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty( collect)){
        if (CollectionUtils.isEmpty(collect)) {
            return procurementPageDtoCopyIPage;
        }
        LambdaQueryWrapper<ProcurementRecordOut> procurementRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        procurementRecordLambdaQueryWrapper.in(ProcurementRecordOut::getProcurementRecordStorageId, collect);
        procurementRecordLambdaQueryWrapper.eq(ProcurementRecordOut::getType,1);
        procurementRecordLambdaQueryWrapper.eq(ProcurementRecordOut::getType, 1);
        List<ProcurementRecordOut> procurementRecords = procurementRecordOutMapper.selectList(procurementRecordLambdaQueryWrapper);
        if(CollectionUtils.isEmpty( procurementRecords)){
        if (CollectionUtils.isEmpty(procurementRecords)) {
            return procurementPageDtoCopyIPage;
        }
        for (ProcurementPageDtoCopy dto : procurementPageDtoCopyList) {
@@ -861,7 +866,7 @@
                    .collect(Collectors.toList());
            // å¦‚果没有相关的出库记录,跳过该条数据
            if(CollectionUtils.isEmpty(collect1)){
            if (CollectionUtils.isEmpty(collect1)) {
                dto.setInboundNum0(dto.getInboundNum());
                dto.setTotalInboundNum(BigDecimal.ZERO);
                continue;
@@ -876,7 +881,7 @@
            // å¾…出库数量 = æ€»æ•°é‡ - å·²å‡ºåº“数量
            dto.setInboundNum0(dto.getInboundNum().subtract(totalInboundNum));
            // åº“存价值
            if(dto.getUnitPrice() != null){
            if (dto.getUnitPrice() != null) {
                dto.setTotalPrice(dto.getInboundNum0().multiply(dto.getUnitPrice()));
            }
        }
@@ -897,14 +902,14 @@
        // è®¡ç®—待入库数量
        // æŸ¥è¯¢é‡‡è´­è®°å½•已入库数量
        List<Integer> collect = procurementPageDtos.stream().map(ProcurementPageDto::getId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty( collect)){
        if (CollectionUtils.isEmpty(collect)) {
            return procurementPageDtoIPage;
        }
        LambdaQueryWrapper<ProcurementRecordOut> procurementRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        procurementRecordLambdaQueryWrapper.in(ProcurementRecordOut::getProcurementRecordStorageId, collect)
                .eq(ProcurementRecordOut::getType, 4);
        List<ProcurementRecordOut> procurementRecords = procurementRecordOutMapper.selectList(procurementRecordLambdaQueryWrapper);
        if(CollectionUtils.isEmpty( procurementRecords)){
        if (CollectionUtils.isEmpty(procurementRecords)) {
            return procurementPageDtoIPage;
        }
        for (ProcurementPageDto dto : procurementPageDtos) {
@@ -914,7 +919,7 @@
                    .collect(Collectors.toList());
            // å¦‚果没有相关的出库记录,跳过该条数据
            if(CollectionUtils.isEmpty(collect1)){
            if (CollectionUtils.isEmpty(collect1)) {
                dto.setInboundNum0(dto.getInboundNum());
                continue;
            }
@@ -930,4 +935,75 @@
        return procurementPageDtoIPage;
    }
    @Override
    public boolean frozenStorageQuality(List<Integer> frozenIds) {
        if (frozenIds == null || frozenIds.isEmpty()) {
            return true;
        }
        LambdaUpdateWrapper<ProcurementRecordStorage> storageLambdaUpdateWrapper = new LambdaUpdateWrapper<ProcurementRecordStorage>()
                .set(ProcurementRecordStorage::getIsFrozen, true)
                .in(ProcurementRecordStorage::getSalesLedgerProductId, frozenIds)
                .eq(ProcurementRecordStorage::getIsFrozen, false);
        return update(storageLambdaUpdateWrapper);
    }
    @Override
    public boolean thawStorageQuality(List<Integer> thawIds) {
        if (thawIds == null || thawIds.isEmpty()) {
            return true;
        }
        LambdaUpdateWrapper<ProcurementRecordStorage> storageLambdaUpdateWrapper = new LambdaUpdateWrapper<ProcurementRecordStorage>()
                .set(ProcurementRecordStorage::getIsFrozen, false)
                .in(ProcurementRecordStorage::getSalesLedgerProductId, thawIds)
                .eq(ProcurementRecordStorage::getIsFrozen, true);
        return update(storageLambdaUpdateWrapper);
    }
    @Override
    public boolean frozenFinishedQuality(List<Integer> frozenIds) {
        if (frozenIds == null || frozenIds.isEmpty()) {
            return true;
        }
        List<ProductModel> modelList = productModelService.list(new LambdaQueryWrapper<ProductModel>().in(ProductModel::getProductId, frozenIds));
        List<Long> productModelIds = modelList.stream()
                .map(ProductModel::getId)
                .collect(Collectors.toList());
        if (productModelIds.isEmpty()) {
            return true;
        }
        LambdaUpdateWrapper<ProcurementRecordStorage> updateWrapper = new LambdaUpdateWrapper<ProcurementRecordStorage>()
                .in(ProcurementRecordStorage::getProductModelId, productModelIds).set(ProcurementRecordStorage::getIsFrozen, 1);
        return update(updateWrapper);
    }
    @Override
    public boolean thawFinishedQuality(List<Integer> thawIds) {
        if (thawIds == null || thawIds.isEmpty()) {
            return true;
        }
        List<ProductModel> modelList = productModelService.list(new LambdaQueryWrapper<ProductModel>().in(ProductModel::getProductId, thawIds));
        List<Long> productModelIds = modelList.stream()
                .map(ProductModel::getId)
                .collect(Collectors.toList());
        if (productModelIds.isEmpty()) {
            return true;
        }
        LambdaUpdateWrapper<ProcurementRecordStorage> updateWrapper = new LambdaUpdateWrapper<ProcurementRecordStorage>()
                .in(ProcurementRecordStorage::getProductModelId, productModelIds).set(ProcurementRecordStorage::getIsFrozen, 0);
        return update(updateWrapper);
    }
}
src/main/java/com/ruoyi/production/controller/ProductBomController.java
@@ -3,20 +3,30 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.production.dto.BomImportDto;
import com.ruoyi.production.dto.ProductBomDto;
import com.ruoyi.production.dto.ProductProcessDto;
import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.*;
import com.ruoyi.production.pojo.ProcessRoute;
import com.ruoyi.production.pojo.ProductBom;
import com.ruoyi.production.pojo.ProductProcessRoute;
import com.ruoyi.production.pojo.ProductStructure;
import com.ruoyi.production.service.ProcessRouteService;
import com.ruoyi.production.service.ProductBomService;
import com.ruoyi.production.service.ProductProcessRouteService;
import com.ruoyi.production.service.ProductStructureService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
@@ -55,7 +65,7 @@
    @ApiModelProperty("新增BOM")
    @PostMapping("/add")
    @Log(title = "新增", businessType = BusinessType.INSERT)
    public AjaxResult add( @RequestBody ProductBom productBom) {
    public AjaxResult add(@RequestBody ProductBom productBom) {
        return productBomService.add(productBom);
    }
@@ -72,14 +82,14 @@
    public AjaxResult batchDelete(@RequestBody List<Integer> ids) {
        List<ProcessRoute> list = processRouteService.list(Wrappers.<ProcessRoute>lambdaQuery().in(ProcessRoute::getBomId, ids));
        List<ProductProcessRoute> list2 = productProcessRouteService.list(Wrappers.<ProductProcessRoute>lambdaQuery().in(ProductProcessRoute::getBomId, ids));
        if (list.size()>0 || list2.size()>0){
        if (list.size() > 0 || list2.size() > 0) {
            return AjaxResult.error("该BOM已经存在对应的工艺路线,无法进行删除");
        }
        if(CollectionUtils.isEmpty(ids)){
        if (CollectionUtils.isEmpty(ids)) {
            return AjaxResult.error("请选择至少一条数据");
        }
        //删除bom子表
        productStructureService.remove(Wrappers.<ProductStructure>lambdaQuery().in(ProductStructure::getBomId,ids));
        productStructureService.remove(Wrappers.<ProductStructure>lambdaQuery().in(ProductStructure::getBomId, ids));
        return AjaxResult.success(productBomService.removeBatchByIds(ids));
    }
@@ -91,4 +101,28 @@
        return AjaxResult.success(productBoms);
    }
    @PostMapping("uploadBom")
    @PreAuthorize("@ss.hasPermi('product:bom:import')")
    @Log(title = "根据Excel导入BOM", businessType = BusinessType.IMPORT)
    @ApiOperation("根据Excel导入BOM")
    public AjaxResult uploadBom(@RequestParam("file") MultipartFile file) {
        return productBomService.uploadBom(file);
    }
    @PostMapping("exportBom")
    @PreAuthorize("@ss.hasPermi('product:bom:export')")
    @ApiOperation("导出BOM文件")
    @Log(title = "导出BOM文件", businessType = BusinessType.EXPORT)
    public void exportBom(HttpServletResponse response, @RequestParam Integer bomId) {
        productBomService.exportBom(response, bomId);
    }
    @GetMapping("/downloadTemplate")
    @Log(title = "下载BOM导入模板", businessType = BusinessType.EXPORT)
    @ApiOperation("下载BOM导入模板")
    public void importTemplate(HttpServletResponse response) {
        ExcelUtil<BomImportDto> excelUtil = new ExcelUtil<>(BomImportDto.class);
        excelUtil.importTemplateExcel(response, "BOM导入模板");
    }
}
src/main/java/com/ruoyi/production/controller/ProductOrderController.java
@@ -62,6 +62,4 @@
    public R listProcessBom(Long orderId) {
        return R.ok(productOrderService.listProcessBom(orderId));
    }
}
src/main/java/com/ruoyi/production/controller/ProductStructureController.java
@@ -34,7 +34,7 @@
    @ApiOperation("BOM查看子集详情")
    @GetMapping("/listBybomId/{bomId}")
    public R listBybomId( @PathVariable("bomId") Long bomId){
    public R listBybomId( @PathVariable("bomId") Integer bomId){
        return R.ok(productStructureService.listBybomId(bomId));
    }
}
src/main/java/com/ruoyi/production/controller/ProductWorkOrderController.java
@@ -3,10 +3,14 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.dto.ProductWorkOrderDto;
import com.ruoyi.production.pojo.ProductWorkOrder;
import com.ruoyi.production.service.ProductWorkOrderService;
import com.ruoyi.quality.pojo.QualityInspect;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
@RestController
@AllArgsConstructor
@@ -43,4 +47,14 @@
        return R.ok(productWorkOrderservice.getById(id));
    }
    /**
     * å·¥å•流转卡下载
     * @param response
     * @param productWorkOrder
     */
    @PostMapping("/down")
    public void down(HttpServletResponse response, @RequestBody ProductWorkOrder productWorkOrder) {
        productWorkOrderservice.down(response, productWorkOrder);
    }
}
src/main/java/com/ruoyi/production/dto/BomImportDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
package com.ruoyi.production.dto;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class BomImportDto {
    @Excel(name = "父项产品编号")
    private String parentCode;
    @Excel(name = "父项产品名称")
    private String parentName;
    @Excel(name = "父项产品规格")
    private String parentSpec;
    @Excel(name = "子项产品编号")
    private String childCode;
    @Excel(name = "子项产品名称")
    private String childName;
    @Excel(name = "子项产品规格")
    private String childSpec;
    @Excel(name = "单位用量")
    private BigDecimal unitQty;
    @Excel(name = "投料工序")
    private String process;
    @Excel(name = "备注")
    private String remark;
}
src/main/java/com/ruoyi/production/dto/ProductWorkOrderDto.java
@@ -2,11 +2,13 @@
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import com.ruoyi.production.pojo.ProductWorkOrder;
import com.ruoyi.production.pojo.ProductWorkOrderFile;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
@@ -35,4 +37,7 @@
    @ApiModelProperty(value = "完成进度")
    private BigDecimal completionStatus;
    @ApiModelProperty(value = "报废数量")
    private BigDecimal scrapQty;
}
src/main/java/com/ruoyi/production/mapper/ProductStructureMapper.java
@@ -1,8 +1,6 @@
package com.ruoyi.production.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.pojo.ProductStructure;
import org.apache.ibatis.annotations.Mapper;
@@ -13,7 +11,7 @@
@Mapper
public interface ProductStructureMapper  extends BaseMapper<ProductStructure> {
    List<ProductStructureDto> listBybomId(@Param("bomId") Long bomId);
    List<ProductStructureDto> listBybomId(@Param("bomId") Integer bomId);
    List<ProductStructureDto> listBybomAndProcess(@Param("bomId") Long bomId, @Param("processId") Long processId);
    List<ProductStructureDto> listBybomAndProcess(@Param("bomId") Integer bomId, @Param("processId") Long processId);
}
src/main/java/com/ruoyi/production/mapper/ProductWorkOrderMapper.java
@@ -17,4 +17,5 @@
    IPage<ProductWorkOrderDto> pageProductWorkOrder(Page<ProductWorkOrderDto> page, @Param("c") ProductWorkOrderDto productWorkOrder);
    ProductWorkOrderDto getProductWorkOrderFlowCard(@Param("id") Long id);
}
src/main/java/com/ruoyi/production/pojo/ProcessRoute.java
@@ -40,5 +40,5 @@
    private String processRouteCode;
    @ApiModelProperty(value = "BOM的ID")
    private Long bomId;
    private Integer bomId;
}
src/main/java/com/ruoyi/production/pojo/ProductProcessRoute.java
@@ -5,8 +5,10 @@
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
@@ -51,7 +53,7 @@
    private LocalDateTime updateTime;
    @ApiModelProperty("关联bom的id")
    private Long bomId;
    private Integer bomId;
    @ApiModelProperty("工艺路线编码")
    private String processRouteCode;
src/main/java/com/ruoyi/production/pojo/ProductStructure.java
@@ -50,7 +50,7 @@
    /**
     * å…³è”BOMid
     */
    private Long bomId;
    private Integer bomId;
    /**
     * çˆ¶èŠ‚ç‚¹ID
src/main/java/com/ruoyi/production/service/ProductBomService.java
@@ -2,11 +2,13 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.production.dto.ProductBomDto;
import com.ruoyi.production.dto.ProductProcessDto;
import com.ruoyi.production.pojo.ProductBom;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
/**
 * <p>
@@ -21,4 +23,9 @@
    IPage<ProductBomDto> listPage(Page page, ProductBomDto productBomDto);
    AjaxResult add(ProductBom productBom);
    AjaxResult uploadBom(MultipartFile file);
    void exportBom(HttpServletResponse response, Integer bomId);
}
src/main/java/com/ruoyi/production/service/ProductOrderService.java
@@ -6,6 +6,7 @@
import com.ruoyi.production.dto.ProductBomDto;
import com.ruoyi.production.dto.ProductOrderDto;
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.dto.ProductWorkOrderDto;
import com.ruoyi.production.pojo.ProcessRoute;
import com.ruoyi.production.pojo.ProductOrder;
src/main/java/com/ruoyi/production/service/ProductStructureService.java
@@ -1,7 +1,6 @@
package com.ruoyi.production.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.basic.dto.ProductModelDto;
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.pojo.ProductStructure;
@@ -12,6 +11,6 @@
    Boolean addProductStructureDto(ProductStructureDto productStructureDto);
    List<ProductStructureDto> listBybomId(Long bomId);
    List<ProductStructureDto> listBybomId(Integer bomId);
}
src/main/java/com/ruoyi/production/service/ProductWorkOrderService.java
@@ -6,10 +6,13 @@
import com.ruoyi.production.dto.ProductWorkOrderDto;
import com.ruoyi.production.pojo.ProductWorkOrder;
import javax.servlet.http.HttpServletResponse;
public interface ProductWorkOrderService extends IService<ProductWorkOrder>{
    IPage<ProductWorkOrderDto> listPage(Page<ProductWorkOrderDto> page, ProductWorkOrderDto productWorkOrder);
    int updateProductWorkOrder(ProductWorkOrderDto productWorkOrderDto);
    void down(HttpServletResponse response, ProductWorkOrder productWorkOrder);
}
src/main/java/com/ruoyi/production/service/impl/ProductBomServiceImpl.java
@@ -1,23 +1,36 @@
package com.ruoyi.production.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.pojo.Product;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.basic.service.IProductModelService;
import com.ruoyi.basic.service.IProductService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.production.dto.BomImportDto;
import com.ruoyi.production.dto.ProductBomDto;
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.mapper.ProductBomMapper;
import com.ruoyi.production.mapper.ProductStructureMapper;
import com.ruoyi.production.pojo.ProductBom;
import com.ruoyi.production.pojo.ProductProcess;
import com.ruoyi.production.pojo.ProductStructure;
import com.ruoyi.production.service.ProductBomService;
import com.ruoyi.production.service.ProductProcessService;
import com.ruoyi.production.service.ProductStructureService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
/**
 * <p>
@@ -31,13 +44,20 @@
public class ProductBomServiceImpl extends ServiceImpl<ProductBomMapper, ProductBom> implements ProductBomService {
    @Autowired
    private IProductService productService;
    @Autowired
    private ProductBomMapper productBomMapper;
    @Autowired
    private IProductModelService productModelService;
    @Autowired
    private ProductStructureMapper productStructureMapper;
    private ProductStructureService productStructureService;
    @Autowired
    private ProductProcessService productProcessService;
    @Override
    public IPage<ProductBomDto> listPage(Page page, ProductBomDto productBomDto) {
@@ -49,7 +69,6 @@
    public AjaxResult add(ProductBom productBom) {
        boolean save = productBomMapper.insert(productBom) > 0;
        if (save) {
            // æ ¹æ®id生成no字段:GX + 8位数字(不足8位前面补0)
            String no = "BM." + String.format("%05d", productBom.getId());
            productBom.setBomNo(no);
            productBomMapper.updateById(productBom);
@@ -69,12 +88,229 @@
            productStructure.setProductModelId(productBom.getProductModelId());
            productStructure.setUnit(productModel.getUnit());
            productStructure.setUnitQuantity(BigDecimal.valueOf(1));
            productStructure.setBomId(Long.valueOf(productBom.getId()));
            productStructure.setBomId(productBom.getId());
            productStructureMapper.insert(productStructure);
            productStructureService.save(productStructure);
            return AjaxResult.success();
        }
        return AjaxResult.error();
    }
}
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult uploadBom(MultipartFile file) {
        ExcelUtil<BomImportDto> util = new ExcelUtil<>(BomImportDto.class);
        List<BomImportDto> list;
        try {
            list = util.importExcel(file.getInputStream());
        } catch (Exception e) {
            return AjaxResult.error("Excel解析失败");
        }
        if (list == null || list.isEmpty()) return AjaxResult.error("数据为空");
        //  å¤„理工序
        list.forEach(dto -> {
            dto.setParentName(clean(dto.getParentName()));
            dto.setParentSpec(clean(dto.getParentSpec()));
            dto.setChildName(clean(dto.getChildName()));
            dto.setChildSpec(clean(dto.getChildSpec()));
        });
        handleProcess(list);
        Map<String, Long> processMap = productProcessService.list().stream()
                .collect(Collectors.toMap(ProductProcess::getName, ProductProcess::getId, (k1, k2) -> k1));
        //  åˆ›å»º BOM æ•°æ®
        BomImportDto first = list.get(0);
        ProductModel rootModel = findModel(first.getParentName(), first.getParentSpec());
        ProductBom bom = new ProductBom();
        bom.setProductModelId(rootModel.getId());
        bom.setVersion("1.0");
        productBomMapper.insert(bom);
        bom.setBomNo("BM." + String.format("%05d", bom.getId()));
        productBomMapper.updateById(bom);
        // è®°å½•已经插入结构的节点:Key = "名称+规格", Value = structure_id
        Map<String, Long> treePathMap = new HashMap<>();
        for (int i = 0; i < list.size(); i++) {
            BomImportDto dto = list.get(i);
            String parentKey = dto.getParentName() + "|" + dto.getParentSpec();
            String childKey = dto.getChildName() + "|" + dto.getChildSpec();
            //处理根节点,第一行且子项为空
            if (i == 0 && StringUtils.isBlank(dto.getChildName())) {
                ProductStructure rootNode = new ProductStructure();
                rootNode.setBomId(bom.getId());
                rootNode.setParentId(null); // é¡¶å±‚没有父节点
                rootNode.setProductModelId(rootModel.getId());
                rootNode.setUnitQuantity(BigDecimal.ONE);
                rootNode.setUnit(rootModel.getUnit());
                productStructureService.save(rootNode);
                treePathMap.put(parentKey, rootNode.getId());
                continue;
            }
            //  å¤„理子层级节点
            //  æ‰¾åˆ°çˆ¶èŠ‚ç‚¹åœ¨æ•°æ®åº“é‡Œçš„ ID
            Long parentStructureId = treePathMap.get(parentKey);
            if (parentStructureId == null) {
                // å¦‚æžœ Map é‡Œæ‰¾ä¸åˆ°ï¼Œè¯´æ˜Ž Excel é¡ºåºä¹±äº†æˆ–者数据有误
                throw new ServiceException("导入失败: çˆ¶é¡¹[" + dto.getParentName() + "]必须在其子项之前定义");
            }
            //  èŽ·å–å­é¡¹æ¨¡åž‹ä¿¡æ¯
            ProductModel childModel = findModel(dto.getChildName(), dto.getChildSpec());
            //  æ’入结构表
            ProductStructure node = new ProductStructure();
            node.setBomId(bom.getId());
            node.setParentId(parentStructureId); // çˆ¶èŠ‚ç‚¹ID
            node.setProductModelId(childModel.getId());
            node.setUnitQuantity(dto.getUnitQty());
            node.setUnit(childModel.getUnit());
            if (processMap.containsKey(dto.getProcess())) {
                node.setProcessId(processMap.get(dto.getProcess()));
            }
            productStructureService.save(node);
            //  æŠŠå½“前子项记录到 Map,作为以后更深层级的父项查找依据
            //  åŒä¸€çˆ¶é¡¹ä¸‹çš„同名子项不需要重复记录
            treePathMap.put(childKey, node.getId());
        }
        return AjaxResult.success("BOM导入成功");
    }
    @Override
    public void exportBom(HttpServletResponse response, Integer bomId) {
        if (bomId == null) {
            return;
        }
        List<ProductStructureDto> treeData = productStructureService.listBybomId(bomId);
        if (treeData == null || treeData.isEmpty()) {
            return;
        }
        //  å°†æ ‘形结构扁平化 ä½¿ç”¨ BFS算法 å¯¼å‡º,按层级顺序
        List<BomImportDto> exportList = new ArrayList<>();
        // Map<ID, Node> idMap ç”¨äºŽæŸ¥æ‰¾çˆ¶èŠ‚ç‚¹
        Map<Long, ProductStructureDto> idMap = new HashMap<>();
        populateMap(treeData, idMap);
        //  treeData çš„第一个是根节点
        for (ProductStructureDto root : treeData) {
            //  æ·»åŠ æ ¹èŠ‚ç‚¹
            BomImportDto rootRow = new BomImportDto();
            rootRow.setParentName(root.getProductName());
            rootRow.setParentSpec(root.getModel());
            rootRow.setUnitQty(root.getUnitQuantity());
            rootRow.setRemark("");
            exportList.add(rootRow);
            //  BFS éåކ-队列
            Queue<ProductStructureDto> queue = new LinkedList<>();
            if (root.getChildren() != null) {
                queue.addAll(root.getChildren());
            }
            while (!queue.isEmpty()) {
                ProductStructureDto child = queue.poll();
                // æŸ¥æ‰¾çˆ¶èŠ‚ç‚¹
                ProductStructureDto parent = idMap.get(child.getParentId());
                if (parent == null) {
                    // é™¤äº†æœ€å¤–层节点,其他节点的父类肯定是不会为空的
                    continue;
                }
                BomImportDto row = new BomImportDto();
                // çˆ¶ç±»ä¿¡æ¯
                row.setParentName(parent.getProductName());
                row.setParentSpec(parent.getModel());
                // å­ç±»ä¿¡æ¯
                row.setChildName(child.getProductName());
                row.setChildSpec(child.getModel());
                row.setUnitQty(child.getUnitQuantity());
                row.setProcess(child.getProcessName());
                exportList.add(row);
                //  å°†å­èŠ‚ç‚¹çš„å­èŠ‚ç‚¹åŠ å…¥é˜Ÿåˆ—-下一层
                if (child.getChildren() != null && !child.getChildren().isEmpty()) {
                    queue.addAll(child.getChildren());
                }
            }
        }
        ExcelUtil<BomImportDto> util = new ExcelUtil<>(BomImportDto.class);
        util.exportExcel(response, exportList, "BOM结构导出");
    }
    private void populateMap(List<ProductStructureDto> nodes, Map<Long, ProductStructureDto> map) {
        if (nodes == null || nodes.isEmpty()) {
            return;
        }
        for (ProductStructureDto node : nodes) {
            map.put(node.getId(), node);
            populateMap(node.getChildren(), map);
        }
    }
    private ProductModel findModel(String name, String spec) {
        Product product = productService.getOne(new LambdaQueryWrapper<Product>()
                .eq(Product::getProductName, name).last("limit 1"));
        if (product == null) throw new ServiceException("产品未维护:" + name);
        ProductModel model = productModelService.getOne(new LambdaQueryWrapper<ProductModel>()
                .eq(ProductModel::getProductId, product.getId())
                .eq(ProductModel::getModel, spec).last("limit 1"));
        if (model == null) throw new ServiceException("规格未维护:" + name + "[" + spec + "]");
        return model;
    }
    private void handleProcess(List<BomImportDto> list) {
        Set<String> processNames = list.stream()
                .map(BomImportDto::getProcess)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toSet());
        if (processNames.isEmpty()) {
            return;
        }
        List<ProductProcess> exists = productProcessService.list(
                new LambdaQueryWrapper<ProductProcess>().in(ProductProcess::getName, processNames)
        );
        Set<String> existNames = exists.stream()
                .map(ProductProcess::getName)
                .collect(Collectors.toSet());
        List<ProductProcess> needSave = processNames.stream()
                .filter(n -> !existNames.contains(n))
                .map(n -> {
                    ProductProcess p = new ProductProcess();
                    p.setName(n);
                    return p;
                })
                .collect(Collectors.toList());
        if (!needSave.isEmpty()) {
            productProcessService.saveBatch(needSave);
            needSave.forEach(p -> p.setNo("GX" + String.format("%08d", p.getId())));
            productProcessService.updateBatchById(needSave);
        }
    }
    private String clean(String s) {
        if (s == null) return null;
        return s.replaceAll("[\\u00A0\\u3000]", "").trim();
    }
}
src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java
@@ -2,11 +2,13 @@
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
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.production.dto.ProductBomDto;
import com.ruoyi.production.dto.ProductOrderDto;
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.dto.ProductWorkOrderDto;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.ProcessRouteService;
@@ -17,6 +19,7 @@
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class ProductOrderServiceImpl extends ServiceImpl<ProductOrderMapper, ProductOrder> implements ProductOrderService {
src/main/java/com/ruoyi/production/service/impl/ProductStructureServiceImpl.java
@@ -29,7 +29,7 @@
    @Transactional
    public Boolean addProductStructureDto(ProductStructureDto dto) {
        Long bomId = dto.getBomId();
        Integer bomId = dto.getBomId();
        //  å°†æ ‘扁平化
        List<ProductStructureDto> flatDtoList = new ArrayList<>();
@@ -132,7 +132,7 @@
    @Override
    public List<ProductStructureDto> listBybomId(Long bomId) {
    public List<ProductStructureDto> listBybomId(Integer bomId) {
        List<ProductStructureDto> list = productStructureMapper.listBybomId(bomId);
        Map<Long, ProductStructureDto> map = new HashMap<>();
src/main/java/com/ruoyi/production/service/impl/ProductWorkOrderServiceImpl.java
@@ -2,22 +2,49 @@
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.config.Configure;
import com.deepoove.poi.data.PictureRenderData;
import com.deepoove.poi.data.Pictures;
import com.ruoyi.common.utils.HackLoopTableRenderPolicy;
import com.ruoyi.common.utils.MatrixToImageWriter;
import com.ruoyi.production.dto.ProductWorkOrderDto;
import com.ruoyi.production.mapper.ProductWorkOrderFileMapper;
import com.ruoyi.production.mapper.ProductWorkOrderMapper;
import com.ruoyi.production.pojo.ProductWorkOrder;
import com.ruoyi.production.pojo.ProductWorkOrderFile;
import com.ruoyi.production.service.ProductWorkOrderService;
import com.ruoyi.quality.pojo.QualityInspectParam;
import lombok.AllArgsConstructor;
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.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
@AllArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class ProductWorkOrderServiceImpl extends ServiceImpl<ProductWorkOrderMapper, ProductWorkOrder> implements ProductWorkOrderService {
    @Autowired
    private ProductWorkOrderMapper productWorkOrdermapper;
    @Autowired
    private ProductWorkOrderFileMapper productWorkOrderFileMapper;
    @Value("${file.temp-dir}")
    private String tempDir;
    @Override
    public IPage<ProductWorkOrderDto> listPage(Page<ProductWorkOrderDto> page, ProductWorkOrderDto productWorkOrder) {
@@ -29,4 +56,61 @@
        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<Map<String, Object>> images = new ArrayList<>();
        List<ProductWorkOrderFile> productWorkOrderFiles = productWorkOrderFileMapper.selectList(Wrappers.<ProductWorkOrderFile>lambdaQuery().eq(ProductWorkOrderFile::getWorkOrderId, productWorkOrder.getId()));
        if (CollectionUtils.isNotEmpty(productWorkOrderFiles)) {
            productWorkOrderFiles.forEach(productWorkOrderFile -> {
                Map<String, Object> 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<String, Object>() {{
                    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("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("导出失败");
        }
    }
}
src/main/resources/mapper/basic/ProductModelMapper.xml
@@ -41,10 +41,12 @@
        pm.model,
        pm.unit,
        p.product_name,
        GREATEST(s.last_in_time, o.last_out_time) AS create_time,
        COALESCE(s.inboundNum, 0) AS inboundNum,
        COALESCE(o.outboundNum, 0) AS outboundNum,
        COALESCE(s.inboundNum, 0) - COALESCE(o.outboundNum, 0) AS stockQuantity
        COALESCE(s.inboundNum, 0) - COALESCE(o.outboundNum, 0) AS stockQuantity,
        COALESCE(s.is_frozen, 0) AS is_frozen
        FROM product_model pm
        LEFT JOIN product p ON pm.product_id = p.id
@@ -53,7 +55,8 @@
        SELECT
        product_model_id,
        SUM(inbound_num) AS inboundNum,
        MAX(create_time) AS last_in_time
        MAX(create_time) AS last_in_time,
        MAX(is_frozen) AS is_frozen
        FROM procurement_record_storage
        <where>
            <if test="req.timeStr != null and req.timeStr != ''">
src/main/resources/mapper/procurementrecord/ProcurementRecordMapper.xml
@@ -50,7 +50,8 @@
        t1.create_time,
        t1.update_time,
        t1.create_by,
        t2.warn_num
        t2.warn_num,
        t1.is_frozen
        from  procurement_record_storage t1
                  left join sales_ledger_product t2 on t2.id = t1.sales_ledger_product_id and t2.type = 2
                  left join purchase_ledger t3 on t3.id = t2.sales_ledger_id
@@ -141,7 +142,8 @@
        t1.create_time,
        t1.update_time,
        t1.create_by,
        t2.warn_num
        t2.warn_num,
        t1.is_frozen
        from  procurement_record_storage t1
        left join sales_ledger_product t2 on t2.id = t1.sales_ledger_product_id and t2.type = 2
        left join purchase_ledger t3 on t3.id = t2.sales_ledger_id
@@ -256,7 +258,8 @@
        t1.update_time,
        t1.create_by,
        t2.warn_num,
        t2.product_id
        t2.product_id,
        t1.is_frozen
        from  procurement_record_storage t1
        left join sales_ledger_product t2 on t2.id = t1.sales_ledger_product_id and t2.type = 1
        left join sales_ledger t3 on t3.id = t2.sales_ledger_id
@@ -353,11 +356,13 @@
              </if>
          </where>
    </select>
    <select id="getSumQuantity" resultType="BigDecimal">
    <select id="getSumQuantity" resultType="java.math.BigDecimal">
        select COALESCE(sum(inbound_num), 0)
        from procurement_record_storage
        where product_model_id = #{productModelId}
        where product_model_id = #{productModelId} and is_frozen = false
    </select>
    <select id="listPageByProductProduction" resultType="com.ruoyi.procurementrecord.dto.ProcurementPageDto">
        select
        t1.*,
src/main/resources/mapper/production/ProductWorkOrderMapper.xml
@@ -34,13 +34,42 @@
        LEFT JOIN product_process pp ON pp.id = ppri.process_id
        LEFT JOIN product_model pm ON pm.id = ppri.product_model_id
        LEFT JOIN product p ON p.id = pm.product_id
        <where>
        where 1=1
            <if test="c.workOrderNo != null and c.workOrderNo != ''">
                pwo.work_order_no like concat('%',#{c.workOrderNo},'%')
               and pwo.work_order_no like concat('%',#{c.workOrderNo},'%')
            </if>
            <if test="c.planStartTime != null and c.planEndTime != null">
                and DATE(pwo.create_time) between #{c.planStartTime} and #{c.planEndTime}
            </if>
        </where>
            <if test="c.productOrderId != null and c.productOrderId != ''">
               and pwo.product_order_id = #{c.productOrderId}
            </if>
    </select>
    <select id="getProductWorkOrderFlowCard" resultType="com.ruoyi.production.dto.ProductWorkOrderDto">
        SELECT
        pwo.*,
        pp.NAME as processName,
        pm.model,
        pm.unit,
        p.product_name AS productName,
        po.nps_no AS productOrderNpsNo,
        ROUND(pwo.complete_quantity / pwo.plan_quantity * 100, 2) AS completionStatus,
        sum(ppo.scrap_qty) scrapQty
        FROM
        product_work_order pwo
        LEFT JOIN product_process_route_item ppri ON ppri.id = pwo.product_process_route_item_id
        LEFT JOIN production_product_main ppm ON ppm.work_order_id = pwo.id
        LEFT JOIN production_product_output ppo ON ppo.product_main_id = ppm.id
        LEFT JOIN product_order po ON po.id = pwo.product_order_id
        LEFT JOIN product_process pp ON pp.id = ppri.process_id
        LEFT JOIN product_model pm ON pm.id = ppri.product_model_id
        LEFT JOIN product p ON p.id = pm.product_id
        WHERE pwo.id = #{id}
        GROUP BY pwo.id, pwo.product_process_route_item_id, pwo.create_time, pwo.update_time, pwo.work_order_no, pwo.plan_start_time, pwo.plan_end_time, pwo.actual_start_time, pwo.actual_end_time, pwo.status, pwo.tenant_id, pwo.plan_quantity, pwo.product_order_id, pwo.complete_quantity,
                 pp.NAME ,
                pm.model,
                pm.unit,
                p.product_name,
                po.nps_no
    </select>
</mapper>
src/main/resources/static/work-order-template.docx
Binary files differ