src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java
@@ -13,7 +13,6 @@ import com.ruoyi.approve.service.IApproveNodeService; import com.ruoyi.common.enums.FileNameType; import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.device.mapper.DeviceRepairMapper; import com.ruoyi.device.pojo.DeviceRepair; @@ -25,7 +24,10 @@ import com.ruoyi.purchase.mapper.PurchaseLedgerMapper; import com.ruoyi.purchase.pojo.PurchaseLedger; import com.ruoyi.purchase.service.impl.PurchaseLedgerServiceImpl; import com.ruoyi.sales.mapper.*; import com.ruoyi.sales.mapper.CommonFileMapper; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; import com.ruoyi.sales.mapper.SalesQuotationMapper; import com.ruoyi.sales.mapper.ShippingInfoMapper; import com.ruoyi.sales.pojo.CommonFile; import com.ruoyi.sales.pojo.SalesLedgerProduct; import com.ruoyi.sales.pojo.SalesQuotation; @@ -204,7 +206,8 @@ purchaseLedgerServiceImpl.addQualityInspect(purchaseLedger, salesLedgerProduct); }else { //直接入库 stockUtils.addStock(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(), purchaseLedger.getId()); stockUtils.addStock(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(), purchaseLedger.getId(),salesLedgerProduct.getBatchNo(),salesLedgerProduct.getCustomer()); } } } else if (status.equals(3)) { src/main/java/com/ruoyi/basic/controller/ProductController.java
@@ -17,8 +17,6 @@ import com.ruoyi.framework.web.domain.AjaxResult; import com.ruoyi.sales.pojo.SalesLedgerProduct; import com.ruoyi.sales.service.ISalesLedgerProductService; import com.ruoyi.sales.service.ISalesLedgerService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.AllArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; src/main/java/com/ruoyi/basic/dto/ProductTreeDto.java
@@ -9,6 +9,13 @@ private Long id; private Long parentId; private String productName; private String model; private String batchNo; private String customer; private String uidNo; private String unit; private Long productModelId; private String label; // 用于树形结构的显示名称 private List<ProductTreeDto> children; private String nodeType; } src/main/java/com/ruoyi/basic/pojo/Product.java
@@ -4,9 +4,11 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.io.Serializable; @Data @TableName("product") public class Product { public class Product implements Serializable { private static final long serialVersionUID = 1L; src/main/java/com/ruoyi/basic/pojo/ProductModel.java
@@ -83,4 +83,7 @@ */ @Excel(name = "UID码") private String uidNo; @TableField(exist = false) private String parentName; } src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java
@@ -4,7 +4,6 @@ import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper; import com.ruoyi.procurementrecord.mapper.ProcurementRecordOutMapper; import com.ruoyi.stock.dto.StockInRecordDto; import com.ruoyi.stock.dto.StockInventoryDto; import com.ruoyi.stock.dto.StockUninventoryDto; import com.ruoyi.stock.pojo.StockInRecord; @@ -13,15 +12,11 @@ import com.ruoyi.stock.service.StockInventoryService; import com.ruoyi.stock.service.StockOutRecordService; import com.ruoyi.stock.service.StockUninventoryService; import com.ruoyi.stock.service.impl.StockInRecordServiceImpl; import com.ruoyi.stock.service.impl.StockOutRecordServiceImpl; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.util.Collections; import java.util.HashMap; import java.util.Map; @Component @RequiredArgsConstructor @@ -40,7 +35,7 @@ * @param recordType * @param recordId */ public void addUnStock(Long productModelId, BigDecimal quantity, String recordType,Long recordId) { public void addUnStock(Long productModelId, BigDecimal quantity, String recordType, Long recordId) { StockUninventoryDto stockUninventoryDto = new StockUninventoryDto(); stockUninventoryDto.setRecordId(recordId); stockUninventoryDto.setRecordType(String.valueOf(recordType)); @@ -56,7 +51,7 @@ * @param recordType * @param recordId */ public void subtractUnStock(Long productModelId, BigDecimal quantity, Integer recordType,Long recordId) { public void subtractUnStock(Long productModelId, BigDecimal quantity, Integer recordType, Long recordId) { StockUninventoryDto stockUninventoryDto = new StockUninventoryDto(); stockUninventoryDto.setRecordId(recordId); stockUninventoryDto.setRecordType(String.valueOf(recordType)); @@ -72,12 +67,16 @@ * @param recordType * @param recordId */ public void addStock(Long productModelId, BigDecimal quantity, String recordType,Long recordId) { public void addStock(Long productModelId, BigDecimal quantity, String recordType, Long recordId,String batchNo,String customer) { StockInventoryDto stockInventoryDto = new StockInventoryDto(); stockInventoryDto.setRecordId(recordId); stockInventoryDto.setRecordType(String.valueOf(recordType)); if (recordType != null) { stockInventoryDto.setRecordType(recordType); } stockInventoryDto.setQualitity(quantity); stockInventoryDto.setProductModelId(productModelId); stockInventoryDto.setBatchNo(batchNo); stockInventoryDto.setCustomer(customer); stockInventoryService.addstockInventory(stockInventoryDto); } @@ -88,12 +87,16 @@ * @param recordType * @param recordId */ public void substractStock(Long productModelId, BigDecimal quantity, String recordType,Long recordId) { public void substractStock(Long productModelId, BigDecimal quantity, String recordType, Long recordId,String batchNo,String customer) { StockInventoryDto stockInventoryDto = new StockInventoryDto(); stockInventoryDto.setRecordId(recordId); stockInventoryDto.setRecordType(String.valueOf(recordType)); if (recordType != null) { stockInventoryDto.setRecordType(recordType); } stockInventoryDto.setQualitity(quantity); stockInventoryDto.setProductModelId(productModelId); stockInventoryDto.setBatchNo(batchNo); stockInventoryDto.setCustomer(customer); stockInventoryService.subtractStockInventory(stockInventoryDto); } @@ -106,6 +109,7 @@ stockInRecordService.batchDelete(Collections.singletonList(one.getId())); } } public void deleteStockOutRecord(Long recordId, String recordType) { StockOutRecord one = stockOutRecordService.getOne(new QueryWrapper<StockOutRecord>() .lambda().eq(StockOutRecord::getRecordId, recordId) src/main/java/com/ruoyi/production/controller/ProductOrderController.java
@@ -91,12 +91,6 @@ return R.ok(productOrderService.getProductOrderBatchNo()); } @ApiOperation("查询生产订单对应的BOM的原材料") @GetMapping("/getByBomId") public R getByBomId(Long bomId) { return R.ok(productOrderService.getByBomId(bomId)); } @ApiOperation("生产订单领料更新") @PostMapping("/drawMaterials") public R drawMaterials(@RequestBody ProductOrderDto productOrderDto) { src/main/java/com/ruoyi/production/controller/ProductWorkOrderController.java
@@ -5,7 +5,6 @@ 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.*; src/main/java/com/ruoyi/production/dto/DrawMaterialDto.java
@@ -1,17 +1,44 @@ package com.ruoyi.production.dto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; @Data @ApiModel("领料单DTO") public class DrawMaterialDto { @ApiModelProperty("订单ID") private Long id; @ApiModelProperty("型号ID") private Long productModelId; @ApiModelProperty("库存数量") private BigDecimal qualitity; @ApiModelProperty("领用数量") private BigDecimal requisitionQty; @ApiModelProperty("产品名称") private String productName; @ApiModelProperty("产品型号") private String model; @ApiModelProperty("产品单位") private String unit; } @ApiModelProperty("报工领用数量") private BigDecimal reportQty; @ApiModelProperty("备注") private String remark; @ApiModelProperty("批号") private String batchNo; @ApiModelProperty("供应商名称") private String customer; } src/main/java/com/ruoyi/production/dto/ProductionProductMainDto.java
@@ -10,6 +10,7 @@ import java.math.BigDecimal; import java.time.LocalDate; import java.util.List; @Data @ExcelIgnoreUnannotated @@ -72,4 +73,7 @@ private String otherData; // 工序id private Long processId; //原料 private List<DrawMaterialDto> drawMaterialList; } src/main/java/com/ruoyi/production/pojo/ProductionProductInput.java
@@ -30,4 +30,13 @@ @ApiModelProperty(value = "租户ID") @TableField(fill = FieldFill.INSERT) private Long tenantId; @ApiModelProperty(value = "备注") private String remark; @ApiModelProperty("批号") private String batchNo; @ApiModelProperty("供应商名称") private String customer; } src/main/java/com/ruoyi/production/service/ProductOrderService.java
@@ -33,7 +33,5 @@ List<SelectOptionDTO<String>> getProductOrderBatchNo(); List getByBomId(Long bomId); int drawMaterials(ProductOrderDto productOrderDto); } src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java
@@ -23,8 +23,8 @@ import com.ruoyi.production.pojo.*; import com.ruoyi.production.service.ProductOrderService; import com.ruoyi.quality.mapper.QualityInspectMapper; import com.ruoyi.stock.dto.StockInventoryDto; import com.ruoyi.stock.mapper.StockInventoryMapper; import com.ruoyi.stock.pojo.StockInventory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -32,7 +32,8 @@ import java.math.BigDecimal; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Service @@ -247,43 +248,9 @@ @Override public List<SelectOptionDTO<String>> getProductOrderBatchNo() { List<ProductOrder> productOrders = productOrderMapper.selectList(null); return productOrders.stream().map(productOrder -> new SelectOptionDTO<>(productOrder.getBatchNo(), productOrder.getBatchNo())).collect(Collectors.toList()); } @Override public List<StockInventoryDto> getByBomId(Long bomId) { List<ProductStructureDto> structureList = productStructureMapper.listBybomId(bomId); if (CollectionUtils.isEmpty(structureList)) { return Collections.emptyList(); } Set<Long> allNodeIds = structureList.stream() .map(ProductStructureDto::getId) .collect(Collectors.toSet()); Set<Long> parentIds = structureList.stream() .filter(node -> node.getParentId() != null && node.getParentId() != 0) .map(ProductStructureDto::getParentId) .collect(Collectors.toSet()); Set<Long> leafNodeIds = new HashSet<>(allNodeIds); leafNodeIds.removeAll(parentIds); // 获取叶子节点的 productModelId List<Long> productModelIds = structureList.stream() .filter(node -> leafNodeIds.contains(node.getId())) .map(ProductStructureDto::getProductModelId) .filter(Objects::nonNull) .distinct() .collect(Collectors.toList()); if (productModelIds.isEmpty()) { return Collections.emptyList(); } return stockInventoryMapper.getStockInventory(productModelIds); //查询库存批号 List<StockInventory> stockInventoryList = stockInventoryMapper.selectList(null); return stockInventoryList.stream().map(stockInventory -> new SelectOptionDTO<>(stockInventory.getBatchNo(), stockInventory.getBatchNo())).collect(Collectors.toList()); } @Override @@ -308,6 +275,16 @@ if (CollectionUtils.isEmpty(drawMaterialsList)) { throw new RuntimeException("领料明细不能为空"); } // 如果有数据先加库存 ProductOrder productOrder = productOrderMapper.selectById(productOrderDto.getId()); if (productOrder != null) { List<DrawMaterialDto> materialDtoList = JSON.parseArray(productOrder.getDrawMaterials(), DrawMaterialDto.class); for (DrawMaterialDto drawMaterialDto : materialDtoList) { stockUtils.addStock(drawMaterialDto.getProductModelId(), drawMaterialDto.getRequisitionQty(), null, productOrderDto.getId(), drawMaterialDto.getBatchNo(), drawMaterialDto.getCustomer() ); } } // 处理领料(扣减库存) try { @@ -315,7 +292,9 @@ if (drawMaterialDto.getProductModelId() == null) { throw new RuntimeException("产品型号ID不能为空"); } stockUtils.substractStock(drawMaterialDto.getProductModelId(), drawMaterialDto.getRequisitionQty(), StockOutQualifiedRecordTypeEnum.DRAW_MATERIALS_STOCK_OUT.getCode(), productOrderDto.getId()); stockUtils.substractStock(drawMaterialDto.getProductModelId(), drawMaterialDto.getRequisitionQty(), StockOutQualifiedRecordTypeEnum.DRAW_MATERIALS_STOCK_OUT.getCode(), productOrderDto.getId(), drawMaterialDto.getBatchNo(),drawMaterialDto.getCustomer()); } } catch (Exception e) { throw new RuntimeException("领料失败:" + e.getMessage()); src/main/java/com/ruoyi/production/service/impl/ProductWorkOrderServiceImpl.java
@@ -7,10 +7,8 @@ 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; @@ -18,8 +16,6 @@ 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; src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -1,8 +1,10 @@ package com.ruoyi.production.service.impl; import com.alibaba.fastjson2.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -12,12 +14,12 @@ import com.ruoyi.basic.pojo.Product; import com.ruoyi.basic.pojo.ProductModel; import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.bean.BeanUtils; import com.ruoyi.procurementrecord.utils.StockUtils; import com.ruoyi.production.dto.ProductStructureDto; import com.ruoyi.production.dto.DrawMaterialDto; import com.ruoyi.production.dto.ProductionProductMainDto; import com.ruoyi.production.mapper.*; import com.ruoyi.production.pojo.*; @@ -30,7 +32,6 @@ import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.ruoyi.production.mapper.ProductionProductMainMapper; import java.math.BigDecimal; import java.time.LocalDate; @@ -39,6 +40,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; @Service @@ -140,22 +142,80 @@ productionProductMain.setStatus(0); productionProductMain.setDeviceId(dto.getDeviceId()); productionProductMainMapper.insert(productionProductMain); /*新增报工投入表*/ List<ProductStructureDto> productStructureDtos = productStructureMapper.listBybomAndProcess(productProcessRoute.getBomId(), productProcess.getId()); if (productStructureDtos.isEmpty()) { //如果该工序没有产品结构的投入品,那这个投入品和产出品是同一个 ProductStructureDto productStructureDto = new ProductStructureDto(); productStructureDto.setProductModelId(productProcessRouteItem.getProductModelId()); productStructureDto.setUnitQuantity(BigDecimal.ONE); productStructureDtos.add(productStructureDto); /* 新增报工投入表 */ ProductWorkOrder WorkOrder = productWorkOrderMapper.selectById(dto.getWorkOrderId()); if (WorkOrder == null) { throw new RuntimeException("工单不存在"); } for (ProductStructureDto productStructureDto : productStructureDtos) { ProductionProductInput productionProductInput = new ProductionProductInput(); productionProductInput.setProductModelId(productStructureDto.getProductModelId()); productionProductInput.setQuantity(productStructureDto.getUnitQuantity().multiply(dto.getQuantity())); productionProductInput.setProductMainId(productionProductMain.getId()); productionProductInputMapper.insert(productionProductInput); ProductOrder order = productOrderMapper.selectById(WorkOrder.getProductOrderId()); if (order == null) { throw new RuntimeException("产品订单不存在"); } List<DrawMaterialDto> drawMaterialList = dto.getDrawMaterialList(); if (!CollectionUtils.isEmpty(drawMaterialList)) { // 物料Map List<DrawMaterialDto> existingMaterialList = JSON.parseArray(order.getDrawMaterials(), DrawMaterialDto.class); if (CollectionUtils.isEmpty(existingMaterialList)) { throw new RuntimeException("可领用物料列表为空"); } Map<String, DrawMaterialDto> materialMap = existingMaterialList.stream() .collect(Collectors.toMap( materialDto -> materialDto.getProductModelId() + "_" + (materialDto.getBatchNo() == null ? "" : materialDto.getBatchNo()) + "_" + (materialDto.getCustomer() == null ? "" : materialDto.getCustomer()), Function.identity(), (existing, replacement) -> existing )); // 处理报工物料 List<ProductionProductInput> inputList = new ArrayList<>(); for (DrawMaterialDto drawMaterial : drawMaterialList) { Long modelId = drawMaterial.getProductModelId(); BigDecimal reportQty = drawMaterial.getReportQty(); String key = drawMaterial.getProductModelId() + "_" + (drawMaterial.getBatchNo() == null ? "" : drawMaterial.getBatchNo()) + "_" + (drawMaterial.getCustomer() == null ? "" : drawMaterial.getCustomer()); DrawMaterialDto material = materialMap.get(key); if (material == null) { throw new RuntimeException("物料不存在: 产品型号ID=" + modelId + ", 批次号=" + drawMaterial.getBatchNo() + ", 客户=" + drawMaterial.getCustomer()); } // 验证库存 BigDecimal availableQty = material.getRequisitionQty().subtract(reportQty); if (availableQty.compareTo(BigDecimal.valueOf(0)) < 0) { throw new RuntimeException(String.format("物料%s库存不足,可用:%s,需领:%s", modelId, availableQty, reportQty)); } // 更新可领用 material.setRequisitionQty(availableQty); // 构建投入记录 ProductionProductInput input = new ProductionProductInput(); input.setProductModelId(modelId); input.setQuantity(reportQty); input.setProductMainId(productionProductMain.getId()); input.setRemark(drawMaterial.getRemark()); input.setBatchNo(drawMaterial.getBatchNo()); input.setCustomer(drawMaterial.getCustomer()); inputList.add(input); } if (!inputList.isEmpty()) { for (ProductionProductInput productionProductInput : inputList) { productionProductInputMapper.insert(productionProductInput); } order.setDrawMaterials(JSON.toJSONString(existingMaterialList)); productOrderMapper.updateById(order); } } /*新增报工产出表*/ ProductionProductOutput productionProductOutput = new ProductionProductOutput(); @@ -193,14 +253,13 @@ qualityInspect.setProductName(product.getProductName()); qualityInspect.setModel(productModel.getModel()); qualityInspect.setUnit(productModel.getUnit()); qualityInspect.setQuantity(productQty); qualityInspect.setQuantity(productionProductOutput.getQuantity().subtract(productionProductOutput.getScrapQty())); qualityInspect.setProcess(process); qualityInspect.setInspectState(0); qualityInspect.setInspectType(inspectType); qualityInspect.setProductMainId(productionProductMain.getId()); qualityInspect.setProductModelId(productModel.getId()); qualityInspect.setBatchNo(productOrder.getBatchNo()); qualityInspect.setInspectedQuantity(dto.getInspectedQuantity()); qualityInspect.setManufacturingTeam(productOrder.getManufacturingTeam()); qualityInspectMapper.insert(qualityInspect); List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(product.getId(), inspectType, process); @@ -217,9 +276,12 @@ qualityInspectParamMapper.insert(param); }); } }else { } else { //直接入库 stockUtils.addStock(productProcessRouteItem.getProductModelId(), productQty, StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(), productionProductMain.getId()); String customer = "长治市轴承制造有限公司"; stockUtils.addStock(productProcessRouteItem.getProductModelId(), productionProductOutput.getQuantity().subtract(productionProductOutput.getScrapQty()), StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(), productionProductMain.getId(),order.getBatchNo(),customer ); } /*更新工单和生产订单*/ ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(dto.getWorkOrderId()); @@ -275,10 +337,10 @@ public Boolean removeProductMain(Long id) { //判断该条报工是否不合格处理,如果不合格处理了,则不允许删除 List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(Wrappers.<QualityInspect>lambdaQuery().eq(QualityInspect::getProductMainId, id)); if (qualityInspects.size() > 0){ if (qualityInspects.size() > 0) { List<QualityUnqualified> qualityUnqualifieds = qualityUnqualifiedMapper.selectList(Wrappers.<QualityUnqualified>lambdaQuery() .in(QualityUnqualified::getInspectId, qualityInspects.stream().map(QualityInspect::getId).collect(Collectors.toList()))); if (qualityUnqualifieds.size() > 0 && qualityUnqualifieds.get(0).getInspectState()==1) { if (qualityUnqualifieds.size() > 0 && qualityUnqualifieds.get(0).getInspectState() == 1) { throw new ServiceException("该条报工已经不合格处理了,不允许删除"); } } @@ -332,9 +394,37 @@ new LambdaQueryWrapper<QualityInspectParam>() .eq(QualityInspectParam::getInspectId, q.getId())); qualityInspectMapper.deleteById(q.getId()); stockUtils.deleteStockInRecord(q.getId(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode()); stockUtils.deleteStockInRecord(q.getId(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode()); }); ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId()); List<DrawMaterialDto> materialDtoList = JSON.parseArray(productOrder.getDrawMaterials(), DrawMaterialDto.class); // 批量查询并构建Map Map<Long, BigDecimal> usedQuantityMap = productionProductInputMapper.selectList( new LambdaQueryWrapper<ProductionProductInput>() .eq(ProductionProductInput::getProductMainId, productionProductMain.getId()) .in(ProductionProductInput::getProductModelId, materialDtoList.stream() .map(DrawMaterialDto::getProductModelId) .collect(Collectors.toList())) ).stream() .collect(Collectors.groupingBy( ProductionProductInput::getProductModelId, Collectors.reducing(BigDecimal.ZERO, ProductionProductInput::getQuantity, BigDecimal::add) )); // 更新所有物料 materialDtoList.forEach(dto -> { BigDecimal usedQty = usedQuantityMap.getOrDefault(dto.getProductModelId(), BigDecimal.ZERO); dto.setRequisitionQty(dto.getRequisitionQty().add(usedQty)); }); // 更新订单 productOrder.setDrawMaterials(JSON.toJSONString(materialDtoList)); productOrderMapper.updateById(productOrder); // 删除产出记录 productionProductOutputMapper.delete(new LambdaQueryWrapper<ProductionProductOutput>() .eq(ProductionProductOutput::getProductMainId, productionProductMain.getId())); src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -1,29 +1,23 @@ package com.ruoyi.purchase.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.account.pojo.AccountExpense; import com.ruoyi.account.pojo.AccountIncome; import com.ruoyi.account.service.AccountExpenseService; import com.ruoyi.account.service.AccountIncomeService; import com.ruoyi.approve.pojo.ApproveProcess; import com.ruoyi.approve.service.impl.ApproveProcessServiceImpl; import com.ruoyi.approve.vo.ApproveProcessVO; import com.ruoyi.basic.mapper.ProductMapper; import com.ruoyi.basic.mapper.ProductModelMapper; import com.ruoyi.basic.mapper.SupplierManageMapper; import com.ruoyi.basic.pojo.Customer; import com.ruoyi.basic.pojo.Product; import com.ruoyi.basic.pojo.ProductModel; import com.ruoyi.basic.pojo.SupplierManage; import com.ruoyi.common.enums.FileNameType; import com.ruoyi.common.exception.base.BaseException; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; @@ -39,19 +33,25 @@ import com.ruoyi.purchase.dto.PurchaseLedgerImportDto; import com.ruoyi.purchase.dto.PurchaseLedgerProductImportDto; import com.ruoyi.purchase.mapper.*; import com.ruoyi.purchase.pojo.*; import com.ruoyi.purchase.pojo.PaymentRegistration; import com.ruoyi.purchase.pojo.ProductRecord; import com.ruoyi.purchase.pojo.PurchaseLedger; import com.ruoyi.purchase.pojo.TicketRegistration; import com.ruoyi.purchase.service.IPurchaseLedgerService; import com.ruoyi.quality.mapper.*; import com.ruoyi.quality.pojo.*; import com.ruoyi.sales.dto.SalesLedgerImportDto; import com.ruoyi.sales.dto.SalesLedgerProductImportDto; import com.ruoyi.sales.mapper.*; import com.ruoyi.quality.pojo.QualityInspect; import com.ruoyi.quality.pojo.QualityInspectParam; import com.ruoyi.quality.pojo.QualityTestStandard; import com.ruoyi.quality.pojo.QualityTestStandardParam; import com.ruoyi.sales.mapper.CommonFileMapper; import com.ruoyi.sales.mapper.InvoiceRegistrationProductMapper; import com.ruoyi.sales.mapper.SalesLedgerMapper; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; import com.ruoyi.sales.pojo.CommonFile; import com.ruoyi.sales.pojo.InvoiceRegistrationProduct; import com.ruoyi.sales.pojo.SalesLedger; import com.ruoyi.sales.pojo.SalesLedgerProduct; import com.ruoyi.sales.service.impl.CommonFileServiceImpl; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FilenameUtils; import org.springframework.beans.BeanUtils; @@ -207,7 +207,7 @@ // 4. 处理子表数据 List<SalesLedgerProduct> productList = purchaseLedgerDto.getProductData(); if (productList != null && !productList.isEmpty()) { handleSalesLedgerProducts(purchaseLedger.getId(), productList, purchaseLedgerDto.getType()); handleSalesLedgerProducts(purchaseLedger.getId(), productList, purchaseLedgerDto.getType(),supplierManage); } //新增原材料检验 审批之后才生成检验 // if (productList != null) { @@ -230,6 +230,7 @@ QualityInspect qualityInspect = new QualityInspect(); qualityInspect.setInspectType(0); qualityInspect.setSupplier(purchaseLedger.getSupplierName()); qualityInspect.setBatchNo(saleProduct.getBatchNo()); qualityInspect.setPurchaseLedgerId(purchaseLedger.getId()); qualityInspect.setProductId(saleProduct.getProductId()); qualityInspect.setProductName(saleProduct.getProductCategory()); @@ -254,7 +255,7 @@ } } private void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, Integer type) { private void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, Integer type,SupplierManage supplierManage) { if (products == null || products.isEmpty()) { throw new BaseException("产品信息不存在"); } @@ -324,6 +325,8 @@ salesLedgerProduct.setFutureTickets(salesLedgerProduct.getQuantity()); salesLedgerProduct.setFutureTicketsAmount(salesLedgerProduct.getTaxInclusiveTotalPrice()); salesLedgerProduct.setPendingTicketsTotal(salesLedgerProduct.getTaxInclusiveTotalPrice()); salesLedgerProduct.setCustomer(supplierManage.getSupplierName()); salesLedgerProduct.setBatchNo(salesLedgerProduct.getBatchNo()); salesLedgerProductMapper.insert(salesLedgerProduct); } } @@ -511,6 +514,15 @@ productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId()) .eq(SalesLedgerProduct::getType, purchaseLedgerDto.getType()); List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper); // 查询关联产品的UID for (SalesLedgerProduct product : products) { if (product.getProductModelId() != null) { ProductModel productModel = productModelMapper.selectById(product.getProductModelId()); if (productModel != null) { product.setUidNo(productModel.getUidNo()); } } } // 3.查询上传文件 LambdaQueryWrapper<CommonFile> salesLedgerFileWrapper = new LambdaQueryWrapper<>(); src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java
@@ -4,11 +4,11 @@ import com.ruoyi.framework.web.domain.AjaxResult; import com.ruoyi.quality.pojo.QualityUnqualified; import com.ruoyi.quality.service.IQualityUnqualifiedService; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; /** @@ -24,6 +24,7 @@ /** * 新增不合格管理 * * @param qualityUnqualified * @return */ @@ -35,21 +36,23 @@ /** * 删除不合格管理 * * @param ids * @return */ @DeleteMapping("/del") public AjaxResult delQualityUnqualified(@RequestBody List<Integer> ids) { qualityUnqualifiedService.listByIds(ids).stream().forEach(qualityUnqualified -> { if (qualityUnqualified.getInspectState()==1){ throw new RuntimeException("该不合格数据已经处理无法删除!"); } }); qualityUnqualifiedService.listByIds(ids).stream().forEach(qualityUnqualified -> { if (qualityUnqualified.getInspectState() == 1) { throw new RuntimeException("该不合格数据已经处理无法删除!"); } }); return AjaxResult.success(qualityUnqualifiedService.removeBatchByIds(ids)); } /** * 不合格管理详情 * * @param id * @return */ @@ -60,6 +63,7 @@ /** * 不合格管理修改 * * @param qualityUnqualified * @return */ @@ -69,7 +73,8 @@ } /** *不合格管理分页查询 * 不合格管理分页查询 * * @param page * @param qualityUnqualified * @return @@ -81,16 +86,18 @@ /** * 不合格管理导出 * * @param response * @param qualityUnqualified */ @PostMapping("/export") public void qualityUnqualifiedExport(HttpServletResponse response,QualityUnqualified qualityUnqualified) { public void qualityUnqualifiedExport(HttpServletResponse response, QualityUnqualified qualityUnqualified) { qualityUnqualifiedService.qualityUnqualifiedExport(response, qualityUnqualified); } /** * 不合格管理处理 * * @param qualityUnqualified * @return */ @@ -99,5 +106,8 @@ return AjaxResult.success(qualityUnqualifiedService.deal(qualityUnqualified)); } @GetMapping("/downloadReturnRecord") public void downloadReturnRecord(@RequestParam("id") Long id,HttpServletResponse response) throws IOException { qualityUnqualifiedService.downloadReturnRecord(id,response); } } src/main/java/com/ruoyi/quality/service/IQualityUnqualifiedService.java
@@ -3,10 +3,10 @@ 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.quality.pojo.QualityInspect; import com.ruoyi.quality.pojo.QualityUnqualified; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public interface IQualityUnqualifiedService extends IService<QualityUnqualified> { @@ -18,4 +18,6 @@ int deal(QualityUnqualified qualityUnqualified); QualityUnqualified getUnqualified(Integer id); void downloadReturnRecord(Long id, HttpServletResponse response) throws IOException; } src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
@@ -15,6 +15,12 @@ import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.procurementrecord.service.ProcurementRecordService; import com.ruoyi.procurementrecord.utils.StockUtils; import com.ruoyi.production.mapper.ProductOrderMapper; import com.ruoyi.production.mapper.ProductWorkOrderMapper; import com.ruoyi.production.mapper.ProductionProductMainMapper; import com.ruoyi.production.pojo.ProductOrder; import com.ruoyi.production.pojo.ProductWorkOrder; import com.ruoyi.production.pojo.ProductionProductMain; import com.ruoyi.quality.dto.QualityInspectDto; import com.ruoyi.quality.mapper.QualityInspectMapper; import com.ruoyi.quality.mapper.QualityTestStandardMapper; @@ -61,6 +67,13 @@ private ProductModelMapper productModelMapper; private ProductionProductMainMapper productionProductMainMapper; private ProductWorkOrderMapper productWorkOrderMapper; private ProductOrderMapper productOrderMapper; @Override public int add(QualityInspectDto qualityInspectDto) { QualityInspect qualityInspect = new QualityInspect(); @@ -88,6 +101,20 @@ @Override public int submit(QualityInspect inspect) { QualityInspect qualityInspect = qualityInspectMapper.selectById(inspect.getId()); ProductionProductMain productionProductMain = productionProductMainMapper.selectById(qualityInspect.getProductMainId()); String batchNo; String customer; if (productionProductMain != null) { ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(productionProductMain.getWorkOrderId()); ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId()); batchNo = productOrder.getBatchNo(); customer = "长治市轴承制造有限公司"; } else { batchNo = qualityInspect.getBatchNo(); customer = qualityInspect.getSupplier(); } //提交前必须判断是否合格 if (ObjectUtils.isNull(qualityInspect.getCheckResult())) { throw new RuntimeException("请先判断是否合格"); @@ -104,7 +131,9 @@ qualityUnqualifiedMapper.insert(qualityUnqualified); } else { //合格直接入库 stockUtils.addStock(qualityInspect.getProductModelId(), qualityInspect.getQuantity(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode(), qualityInspect.getId()); stockUtils.addStock(qualityInspect.getProductModelId(), qualityInspect.getQuantity(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode(), qualityInspect.getId(), batchNo, customer ); } qualityInspect.setInspectState(1);//已提交 return qualityInspectMapper.updateById(qualityInspect); src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java
@@ -7,16 +7,13 @@ 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.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum; import com.ruoyi.common.utils.bean.BeanUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.procurementrecord.utils.StockUtils; import com.ruoyi.production.mapper.ProductProcessRouteItemMapper; import com.ruoyi.production.mapper.ProductProcessRouteMapper; import com.ruoyi.production.mapper.ProductWorkOrderMapper; import com.ruoyi.production.mapper.ProductionProductMainMapper; import com.ruoyi.production.mapper.*; import com.ruoyi.production.pojo.*; import com.ruoyi.production.service.ProductOrderService; import com.ruoyi.quality.mapper.QualityUnqualifiedMapper; @@ -29,10 +26,14 @@ import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletResponse; import java.io.InputStream; import java.io.OutputStream; import java.math.BigDecimal; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.List; import java.util.Map; @AllArgsConstructor @Service @@ -47,6 +48,7 @@ private ProductProcessRouteItemMapper productProcessRouteItemMapper; private ProductWorkOrderMapper productWorkOrderMapper; private StockUninventoryService stockUninventoryService; private ProductOrderMapper productOrderMapper; @Override public IPage<QualityUnqualified> qualityUnqualifiedListPage(Page page, QualityUnqualified qualityUnqualified) { @@ -64,10 +66,12 @@ public int deal(QualityUnqualified qualityUnqualified) { QualityUnqualified unqualified = qualityUnqualifiedMapper.selectById(qualityUnqualified.getId()); QualityInspect qualityInspect = qualityInspectService.getById(unqualified.getInspectId()); ProductionProductMain productionProductMain = productionProductMainMapper.selectById(qualityInspect.getProductMainId()); ProductWorkOrder workOrder = productWorkOrderMapper.selectById(productionProductMain.getWorkOrderId()); ProductOrder orders = productOrderMapper.selectById(workOrder.getProductOrderId()); if (ObjectUtils.isNotNull(qualityInspect) && qualityInspect.getInspectType() != 0) { switch (qualityUnqualified.getDealResult()) { case "返修": case "返工": //判断质检表是否有相关的报工id,如果有报工id,那么返工需要重新创建生产订单重新生产 if (ObjectUtils.isNotNull(qualityInspect.getProductMainId())) { //返工需要重新创建生产订单重新生产 @@ -131,8 +135,12 @@ break; case "让步放行": //调用提交合格的接口 stockUtils.addStock(qualityInspect.getProductModelId(), unqualified.getQuantity(), StockInQualifiedRecordTypeEnum.DEFECTIVE_PASS.getCode(), unqualified.getId()); String customer = "长治市轴承制造有限公司"; stockUtils.addStock(qualityInspect.getProductModelId(), unqualified.getQuantity(), StockInQualifiedRecordTypeEnum.DEFECTIVE_PASS.getCode(), unqualified.getId(), orders.getBatchNo(), customer ); break; case "返工": default: break; } @@ -146,7 +154,8 @@ break; case "让步放行": //调用提交合格的接口 stockUtils.addStock(modelId, unqualified.getQuantity(), StockInQualifiedRecordTypeEnum.DEFECTIVE_PASS.getCode(), unqualified.getId()); String customer = "长治市轴承制造有限公司"; stockUtils.addStock(modelId, unqualified.getQuantity(), StockInQualifiedRecordTypeEnum.DEFECTIVE_PASS.getCode(), unqualified.getId(), orders.getBatchNo(), customer); break; default: break; @@ -161,4 +170,60 @@ public QualityUnqualified getUnqualified(Integer id) { return qualityUnqualifiedMapper.getUnqualified(id); } @Override public void downloadReturnRecord(Long id, HttpServletResponse response) { XWPFTemplate template = null; InputStream inputStream = null; OutputStream out = null; try { // 1. 查询数据 QualityUnqualified info = qualityUnqualifiedMapper.selectById(id); Map<String, Object> data = new HashMap<>(); data.put("productName", info.getProductName()); data.put("model", info.getModel()); // 加载模板 inputStream = getClass().getResourceAsStream("/static/return-record.docx"); if (inputStream == null) { throw new RuntimeException("模板文件不存在,请检查路径:/static/return-record.docx"); } // 渲染模板 template = XWPFTemplate.compile(inputStream).render(data); // 设置响应头 response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document"); response.setHeader("Content-Disposition", "attachment; filename=rework_record_" + id + ".docx"); response.setContentLengthLong(-1); out = response.getOutputStream(); template.write(out); out.flush(); } catch (Exception e) { throw new RuntimeException("下载失败", e); } finally { if (template != null) { try { template.close(); } catch (Exception e) { log.error("关闭模板失败", e); } } if (inputStream != null) { try { inputStream.close(); } catch (Exception e) { log.error("关闭输入流失败", e); } } if (out != null) { try { out.close(); } catch (Exception e) { log.error("关闭输出流失败", e); } } } } } src/main/java/com/ruoyi/sales/controller/ShipmentApprovalController.java
@@ -87,7 +87,7 @@ //出库 stockUtils.addStock(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), req.getId()); stockUtils.addStock(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), req.getId(),null,null); } return AjaxResult.success(); src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
@@ -241,4 +241,7 @@ @ApiModelProperty(value = "批号") private String batchNo; @ApiModelProperty(value = "供应商") private String customer; } src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -194,6 +194,9 @@ product.setTempnoInvoiceAmount(product.getNoInvoiceAmount()); product.setTempNoInvoiceNum(product.getNoInvoiceNum()); product.setRegister(SecurityUtils.getLoginUser().getUser().getNickName()); product.setUidNo(product.getUidNo()); product.setUnit(product.getUnit()); product.setBatchNo(product.getBatchNo()); product.setRegisterDate(LocalDateTime.now()); // 发货信息 ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>() @@ -202,6 +205,13 @@ .last("limit 1")); if (shippingInfo != null) { product.setShippingStatus(shippingInfo.getStatus()); } // 查询关联产品的UID if (product.getProductModelId() != null) { ProductModel productModel = productModelMapper.selectById(product.getProductModelId()); if (productModel != null) { product.setUidNo(productModel.getUidNo()); } } } @@ -911,6 +921,7 @@ map.put("taxInclusiveUnitPrice", product.getTaxInclusiveUnitPrice().setScale(2, RoundingMode.HALF_UP).toString()); map.put("taxInclusiveTotalPrice", product.getTaxInclusiveTotalPrice().setScale(2, RoundingMode.HALF_UP).toString()); map.put("batchNo", product.getBatchNo()); map.put("uidNo", product.getUidNo()); // 查询凭证 ProductModel productModel = productModelMapper.selectById(product.getProductModelId()); if (productModel != null) { src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java
@@ -67,7 +67,9 @@ //扣减库存 if(!"已发货".equals(byId.getStatus())){ SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(byId.getSalesLedgerProductId()); stockUtils.substractStock(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), req.getId()); stockUtils.substractStock(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), req.getId(),null,null ); } byId.setExpressNumber(req.getExpressNumber()); byId.setExpressCompany(req.getExpressCompany()); src/main/java/com/ruoyi/stock/controller/StockInventoryController.java
@@ -2,6 +2,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.basic.dto.ProductDto; import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.common.utils.poi.ExcelUtil; @@ -105,4 +106,16 @@ public R thawStock(@RequestBody StockInventoryDto stockInventoryDto) { return R.ok(stockInventoryService.thawStock(stockInventoryDto)); } @ApiOperation("查询库存原材料") @GetMapping("/getMaterials") public R getMaterials(StockInventoryDto stockInventoryDto) { return R.ok(stockInventoryService.getMaterials(stockInventoryDto)); } @ApiOperation("查询库存产品") @GetMapping("/getStockInventoryAll") public R getStockInventoryAll(ProductDto productDto) { return R.ok(stockInventoryService.getStockInventoryAll(productDto)); } } src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java
@@ -42,4 +42,7 @@ private BigDecimal currentStock; private BigDecimal unLockedQuantity; private Long productId; // 产品ID private Long parentId; // 父级产品ID private Long productModelId; // 产品型号ID } src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java
@@ -3,6 +3,7 @@ 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.basic.dto.ProductDto; import com.ruoyi.stock.dto.StockInRecordDto; import com.ruoyi.stock.dto.StockInventoryDto; import com.ruoyi.stock.execl.StockInventoryExportData; @@ -51,4 +52,8 @@ BigDecimal selectTotalByDate(@Param("now") LocalDate now); List<StockInventoryDto> getStockInventory(@Param("ids") List<Long> ids); List<StockInventoryDto> getMaterials(@Param("ew")StockInventoryDto stockInventoryDto); List<StockInventoryDto> getStockInventoryAll(@Param("ew") ProductDto productDto); } src/main/java/com/ruoyi/stock/pojo/StockInRecord.java
@@ -63,4 +63,10 @@ @ApiModelProperty(value = "修改用户") @TableField(fill = FieldFill.INSERT_UPDATE) private Integer updateUser; @ApiModelProperty("批号") private String batchNo; @ApiModelProperty("供应商名称") private String customer; } src/main/java/com/ruoyi/stock/pojo/StockInventory.java
@@ -63,4 +63,10 @@ @ApiModelProperty("备注") private String remark; @ApiModelProperty("批号") private String batchNo; @ApiModelProperty("供应商名称") private String customer; } src/main/java/com/ruoyi/stock/pojo/StockOutRecord.java
@@ -71,4 +71,11 @@ @ApiModelProperty(value = "类型 0合格入库 1不合格入库") private String type; @ApiModelProperty("批号") private String batchNo; @ApiModelProperty("供应商名称") private String customer; } src/main/java/com/ruoyi/stock/pojo/StockUninventory.java
@@ -59,4 +59,10 @@ @ApiModelProperty("被订单锁定数量") private BigDecimal lockedQuantity; @ApiModelProperty("批号") private String batchNo; @ApiModelProperty("供应商名称") private String customer; } src/main/java/com/ruoyi/stock/service/StockInventoryService.java
@@ -3,6 +3,8 @@ 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.basic.dto.ProductDto; import com.ruoyi.basic.dto.ProductTreeDto; import com.ruoyi.framework.web.domain.R; import com.ruoyi.stock.dto.StockInRecordDto; import com.ruoyi.stock.dto.StockInventoryDto; @@ -10,6 +12,7 @@ import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import java.util.List; /** * <p> @@ -38,4 +41,8 @@ Boolean frozenStock(StockInventoryDto stockInventoryDto); Boolean thawStock(StockInventoryDto stockInventoryDto); List<StockInventoryDto> getMaterials(StockInventoryDto stockInventoryDto); List<ProductTreeDto> getStockInventoryAll(ProductDto productDto); } src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
@@ -1,11 +1,19 @@ package com.ruoyi.stock.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; 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.dto.ProductDto; import com.ruoyi.basic.dto.ProductTreeDto; import com.ruoyi.basic.mapper.ProductMapper; import com.ruoyi.basic.mapper.ProductModelMapper; import com.ruoyi.basic.pojo.Product; import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.web.domain.R; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; @@ -19,15 +27,14 @@ import com.ruoyi.stock.service.StockInRecordService; import com.ruoyi.stock.service.StockInventoryService; import com.ruoyi.stock.service.StockOutRecordService; import lombok.AllArgsConstructor; 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.ArrayList; import java.util.List; import java.util.*; /** * <p> @@ -38,13 +45,22 @@ * @since 2026-01-21 04:16:36 */ @Service @AllArgsConstructor public class StockInventoryServiceImpl extends ServiceImpl<StockInventoryMapper, StockInventory> implements StockInventoryService { @Autowired private StockInventoryMapper stockInventoryMapper; @Autowired private StockInRecordService stockInRecordService; @Autowired private StockOutRecordService stockOutRecordService; @Autowired private SalesLedgerProductMapper salesLedgerProductMapper; @Autowired private ProductMapper productMapper; @Autowired private ProductModelMapper productModelMapper; @Override public IPage<StockInventoryDto> pagestockInventory(Page page, StockInventoryDto stockInventoryDto) { return stockInventoryMapper.pagestockInventory(page, stockInventoryDto); @@ -55,16 +71,24 @@ @Transactional(rollbackFor = Exception.class) public Boolean addstockInventory(StockInventoryDto stockInventoryDto) { //新增入库记录再添加库存 StockInRecordDto stockInRecordDto = new StockInRecordDto(); stockInRecordDto.setRecordId(stockInventoryDto.getRecordId()); stockInRecordDto.setRecordType(stockInventoryDto.getRecordType()); stockInRecordDto.setStockInNum(stockInventoryDto.getQualitity()); stockInRecordDto.setProductModelId(stockInventoryDto.getProductModelId()); stockInRecordDto.setType("0"); stockInRecordService.add(stockInRecordDto); if (stockInventoryDto.getRecordType() != null) { StockInRecordDto stockInRecordDto = new StockInRecordDto(); stockInRecordDto.setRecordId(stockInventoryDto.getRecordId()); stockInRecordDto.setRecordType(stockInventoryDto.getRecordType()); stockInRecordDto.setStockInNum(stockInventoryDto.getQualitity()); stockInRecordDto.setProductModelId(stockInventoryDto.getProductModelId()); stockInRecordDto.setType("0"); stockInRecordDto.setBatchNo(stockInventoryDto.getBatchNo()); stockInRecordDto.setCustomer(stockInventoryDto.getCustomer()); stockInRecordService.add(stockInRecordDto); } //再进行新增库存数量库存 //先查询库存表中的产品是否存在,不存在新增,存在更新 StockInventory oldStockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda().eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId())); StockInventory oldStockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda() .eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId()) .eq(StockInventory::getBatchNo, stockInventoryDto.getBatchNo()) .eq(StockInventory::getCustomer, stockInventoryDto.getCustomer()) ); if (ObjectUtils.isEmpty(oldStockInventory)) { StockInventory newStockInventory = new StockInventory(); newStockInventory.setProductModelId(stockInventoryDto.getProductModelId()); @@ -73,6 +97,8 @@ newStockInventory.setRemark(stockInventoryDto.getRemark()); newStockInventory.setLockedQuantity(stockInventoryDto.getLockedQuantity()); newStockInventory.setWarnNum(stockInventoryDto.getWarnNum()); newStockInventory.setBatchNo(stockInventoryDto.getBatchNo()); newStockInventory.setCustomer(stockInventoryDto.getCustomer()); stockInventoryMapper.insert(newStockInventory); }else { stockInventoryMapper.updateAddStockInventory(stockInventoryDto); @@ -85,14 +111,22 @@ @Transactional(rollbackFor = Exception.class) public Boolean subtractStockInventory(StockInventoryDto stockInventoryDto) { // 新增出库记录 StockOutRecordDto stockOutRecordDto = new StockOutRecordDto(); stockOutRecordDto.setRecordId(stockInventoryDto.getRecordId()); stockOutRecordDto.setRecordType(stockInventoryDto.getRecordType()); stockOutRecordDto.setStockOutNum(stockInventoryDto.getQualitity()); stockOutRecordDto.setProductModelId(stockInventoryDto.getProductModelId()); stockOutRecordDto.setType("0"); stockOutRecordService.add(stockOutRecordDto); StockInventory oldStockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda().eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId())); if (stockInventoryDto.getRecordType() != null) { StockOutRecordDto stockOutRecordDto = new StockOutRecordDto(); stockOutRecordDto.setRecordId(stockInventoryDto.getRecordId()); stockOutRecordDto.setRecordType(stockInventoryDto.getRecordType()); stockOutRecordDto.setStockOutNum(stockInventoryDto.getQualitity()); stockOutRecordDto.setProductModelId(stockInventoryDto.getProductModelId()); stockOutRecordDto.setBatchNo(stockInventoryDto.getBatchNo()); stockOutRecordDto.setCustomer(stockInventoryDto.getCustomer()); stockOutRecordDto.setType("0"); stockOutRecordService.add(stockOutRecordDto); } StockInventory oldStockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda() .eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId()) .eq(StockInventory::getBatchNo, stockInventoryDto.getBatchNo()) .eq(StockInventory::getCustomer, stockInventoryDto.getCustomer()) ); if (ObjectUtils.isEmpty(oldStockInventory)) { throw new RuntimeException("产品库存不存在"); } @@ -206,4 +240,216 @@ stockInventory.setLockedQuantity(stockInventory.getLockedQuantity().subtract(stockInventoryDto.getLockedQuantity())); return this.updateById(stockInventory); } @Override public List<StockInventoryDto> getMaterials(StockInventoryDto stockInventoryDto) { return stockInventoryMapper.getMaterials(stockInventoryDto); } @Override public List<ProductTreeDto> getStockInventoryAll(ProductDto productDto) { // 查询库存列表 List<StockInventoryDto> stockList = stockInventoryMapper.getStockInventoryAll(productDto); if (CollectionUtils.isEmpty(stockList)) { return new ArrayList<>(); } // 构建产品树(基于产品表的父子关系) Map<Long, ProductTreeDto> productNodeMap = buildProductTree(stockList); // 将库存数据(型号->批次->客户)挂载到对应的产品节点下 attachStockDataToProduct(productNodeMap, stockList); // 返回根节点 List<ProductTreeDto> tree = new ArrayList<>(); for (ProductTreeDto node : productNodeMap.values()) { if (node.getParentId() == null || node.getParentId() == 0) { tree.add(node); } } return tree; } /** * 构建产品树(自动递归查询所有父级,包含根节点) */ private Map<Long, ProductTreeDto> buildProductTree(List<StockInventoryDto> stockList) { // 1. 收集所有需要加载的产品ID Set<Long> needQueryIds = new HashSet<>(); for (StockInventoryDto stock : stockList) { if (stock.getProductId() != null) { needQueryIds.add(stock.getProductId()); } } // 递归查询所有节点(直到根节点) Set<Long> allAncestors = getAllAncestorIds(needQueryIds); needQueryIds.addAll(allAncestors); // 批量查询所有产品(包含完整层级) LambdaQueryWrapper<Product> wrapper = new LambdaQueryWrapper<>(); wrapper.in(Product::getId, needQueryIds); List<Product> products = productMapper.selectList(wrapper); // 构建节点Map Map<Long, ProductTreeDto> nodeMap = new HashMap<>(); for (Product product : products) { ProductTreeDto node = new ProductTreeDto(); node.setId(product.getId()); node.setParentId(product.getParentId()); node.setProductName(product.getProductName()); node.setLabel(product.getProductName()); node.setNodeType("product"); node.setChildren(new ArrayList<>()); nodeMap.put(product.getId(), node); } // 构建父子关系 for (ProductTreeDto node : nodeMap.values()) { Long parentId = node.getParentId(); if (parentId != null && parentId != 0 && nodeMap.containsKey(parentId)) { nodeMap.get(parentId).getChildren().add(node); } } return nodeMap; } /** * 递归查询所有产品的祖先ID(直到根节点) */ private Set<Long> getAllAncestorIds(Set<Long> productIds) { Set<Long> ancestorIds = new HashSet<>(); Queue<Long> queue = new LinkedList<>(productIds); while (!queue.isEmpty()) { Long currentId = queue.poll(); Product product = productMapper.selectById(currentId); if (product == null) continue; Long parentId = product.getParentId(); if (parentId != null && parentId != 0 && !ancestorIds.contains(parentId)) { ancestorIds.add(parentId); queue.add(parentId); } } return ancestorIds; } /** * 将库存数据(型号->批次->客户)挂载到产品节点下 */ private void attachStockDataToProduct(Map<Long, ProductTreeDto> productNodeMap, List<StockInventoryDto> stockList) { for (StockInventoryDto stock : stockList) { Long productId = stock.getProductId(); if (productId == null || !productNodeMap.containsKey(productId)) { continue; } ProductTreeDto productNode = productNodeMap.get(productId); // 构建该产品的库存树(型号 -> 批次 -> 客户) ProductTreeDto stockTree = buildStockTree(stock); // 合并到产品节点的 children 中 mergeStockTree(productNode.getChildren(), stockTree); } } /** * 构建单个库存的树结构(型号 -> 批次 -> 客户) */ private ProductTreeDto buildStockTree(StockInventoryDto stock) { // 型号节点 ProductTreeDto modelNode = new ProductTreeDto(); modelNode.setModel(stock.getModel()); modelNode.setUidNo(stock.getUidNo()); modelNode.setUnit(stock.getUnit()); modelNode.setProductModelId(stock.getProductModelId()); modelNode.setLabel(stock.getModel()); modelNode.setNodeType("model"); modelNode.setChildren(new ArrayList<>()); // 批次节点 ProductTreeDto batchNode = new ProductTreeDto(); String batchNo = StringUtils.isBlank(stock.getBatchNo()) ? "无批次" : stock.getBatchNo(); batchNode.setBatchNo(batchNo); batchNode.setLabel("批次: " + batchNo); batchNode.setNodeType("batch"); batchNode.setChildren(new ArrayList<>()); // 客户节点 ProductTreeDto customerNode = new ProductTreeDto(); String customer = StringUtils.isBlank(stock.getCustomer()) ? "无客户" : stock.getCustomer(); customerNode.setCustomer(customer); customerNode.setLabel(customer); customerNode.setNodeType("customer"); customerNode.setChildren(new ArrayList<>()); batchNode.getChildren().add(customerNode); modelNode.getChildren().add(batchNode); return modelNode; } /** * 合并库存树到产品节点的 children 中 */ private void mergeStockTree(List<ProductTreeDto> children, ProductTreeDto newStockTree) { if (children == null) { return; } // 查找是否已有相同型号的节点 ProductTreeDto existingModelNode = null; for (ProductTreeDto child : children) { if (child.getNodeType().equals("model") && child.getModel() != null && child.getModel().equals(newStockTree.getModel())) { existingModelNode = child; break; } } if (existingModelNode == null) { // 没有相同型号,直接添加 children.add(newStockTree); } else { // 有相同型号,合并批次节点 ProductTreeDto newBatchNode = newStockTree.getChildren().get(0); // 查找是否已有相同批次 ProductTreeDto existingBatchNode = null; for (ProductTreeDto batchChild : existingModelNode.getChildren()) { if (batchChild.getNodeType().equals("batch") && batchChild.getBatchNo() != null && batchChild.getBatchNo().equals(newBatchNode.getBatchNo())) { existingBatchNode = batchChild; break; } } if (existingBatchNode == null) { existingModelNode.getChildren().add(newBatchNode); } else { // 合并客户节点 ProductTreeDto newCustomerNode = newBatchNode.getChildren().get(0); boolean customerExists = false; for (ProductTreeDto customerChild : existingBatchNode.getChildren()) { if (customerChild.getNodeType().equals("customer") && customerChild.getCustomer() != null && customerChild.getCustomer().equals(newCustomerNode.getCustomer())) { customerExists = true; break; } } if (!customerExists) { existingBatchNode.getChildren().add(newCustomerNode); } } } } } src/main/resources/mapper/basic/ProductModelMapper.xml
@@ -16,11 +16,13 @@ <result column="validity_period" property="validityPeriod" /> <result column="filing_certificate_no" property="filingCertificateNo" /> <result column="uid_no" property="uidNo" /> <result column="parent_name" property="parentName" /> </resultMap> <select id="listPageProductModel" resultType="com.ruoyi.basic.pojo.ProductModel"> select pm.*,p.product_name select pm.*,p.product_name, parent_p.product_name as parent_name from product_model pm left join product p on pm.product_id = p.id left join product parent_p on p.parent_id = parent_p.id <where> <if test="c.model != null and c.model != ''"> and pm.model like concat('%',#{c.model},'%') src/main/resources/mapper/purchase/PaymentRegistrationMapper.xml
@@ -189,7 +189,7 @@ T1.supplier_name, SUM(contract_amount) AS invoiceAmount, IFNULL( SUM(T2.current_payment_amount) , 0 ) AS paymentAmount, IFNULL((IFNULL(SUM(contract_amount),0) - IFNULL(SUM(T2.current_payment_amount),0)),0) AS payableAmount IFNULL((IFNULL(SUM(contract_amount),0) - IFNULL(SUM(T2.current_payment_amount),0)),0) AS payableAmount FROM purchase_ledger T1 LEFT JOIN payment_registration T2 ON T1.id = T2.purchase_ledger_id <where> @@ -197,7 +197,7 @@ T1.supplier_name LIKE CONCAT ('%',#{req.supplierName},'%') </if> </where> GROUP BY T1.supplier_name GROUP BY T1.supplier_id, T1.supplier_name </select> <select id="supplierNameListPageDetails" resultType="com.ruoyi.purchase.dto.PaymentRegistrationDto"> src/main/resources/mapper/stock/StockInventoryMapper.xml
@@ -65,7 +65,9 @@ si.remark, pm.unit, pm.uid_no as uidNo, p.product_name p.product_name, si.batch_no, si.customer from stock_inventory si left join product_model pm on si.product_model_id = pm.id left join product p on pm.product_id = p.id @@ -257,4 +259,73 @@ ORDER BY pm.id </select> <select id="getMaterials" resultType="com.ruoyi.stock.dto.StockInventoryDto"> SELECT si.id, si.qualitity, COALESCE(si.locked_quantity, 0) AS locked_quantity, si.product_model_id, si.create_time, si.update_time, COALESCE(si.warn_num, 0) AS warn_num, si.version, (si.qualitity - COALESCE(si.locked_quantity, 0)) AS un_locked_quantity, pm.model, si.remark, pm.unit, pm.uid_no AS uidNo, p.product_name, p1.product_name AS parentName, si.batch_no, si.customer FROM stock_inventory si LEFT JOIN product_model pm ON si.product_model_id = pm.id LEFT JOIN product p ON pm.product_id = p.id LEFT JOIN product p1 ON p1.id = p.parent_id WHERE p1.product_name = '原材料'; <if test="ew.batchNo != null and ew.batchNo !=''"> and si.batch_no like concat('%',#{ew.batchNo},'%') </if> <if test="ew.customer != null and ew.customer !=''"> and si.customer like concat('%',#{ew.customer},'%') </if> </select> <select id="getStockInventoryAll" resultType="com.ruoyi.stock.dto.StockInventoryDto"> SELECT si.id, si.qualitity, COALESCE(si.locked_quantity, 0) AS locked_quantity, si.product_model_id, si.create_time, si.update_time, COALESCE(si.warn_num, 0) AS warn_num, si.version, (si.qualitity - COALESCE(si.locked_quantity, 0)) AS un_locked_quantity, pm.id as productModelId, pm.model, si.remark, pm.unit, pm.uid_no AS uidNo, p.id AS product_id, p.product_name, p.parent_id AS parent_id, p1.product_name AS parentName, si.batch_no, si.customer FROM stock_inventory si LEFT JOIN product_model pm ON si.product_model_id = pm.id LEFT JOIN product p ON pm.product_id = p.id LEFT JOIN product p1 ON p1.id = p.parent_id <where> <if test="ew.productName != null and ew.productName != ''"> AND p.product_name LIKE CONCAT('%', #{ew.productName}, '%') </if> </where> </select> </mapper> src/main/resources/static/return-record.docxBinary files differ
src/main/resources/static/sale-outbound.docxBinary files differ