src/main/java/com/ruoyi/basic/utils/FileUtil.java
@@ -55,9 +55,6 @@ * @param storageBlobDTOS 文件信息 */ public void saveStorageAttachment(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId, List<StorageBlobDTO> storageBlobDTOS) { if (CollectionUtils.isEmpty(storageBlobDTOS)) { throw new RuntimeException("文件信息不能为空"); } if (application == null) { throw new RuntimeException("文件用途不能为空"); } @@ -69,6 +66,9 @@ } // 删除旧附件信息 deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordId(application, recordType, recordId); if (CollectionUtils.isEmpty(storageBlobDTOS)) { return; } List<StorageAttachment> storageAttachments = new ArrayList<>(); for (StorageBlobDTO storageBlobDTO : storageBlobDTOS) { StorageAttachment storageAttachment = new StorageAttachment(); src/main/java/com/ruoyi/stock/controller/StockInRecordController.java
@@ -43,10 +43,31 @@ return AjaxResult.success(stockInRecordService.batchDelete(ids)); } @DeleteMapping("/pending") @Log(title = "入库管理-删除待审批入库", businessType = BusinessType.DELETE) @Operation(summary = "删除待审批的入库记录") public AjaxResult deletePending(@RequestBody List<Long> ids) { if(CollectionUtils.isEmpty(ids)){ return AjaxResult.error("请选择至少一条数据"); } return AjaxResult.success(stockInRecordService.batchDeletePending(ids)); } @PostMapping("/exportStockInRecord") @Operation(summary = "导出入库记录") public void exportStockInRecord(HttpServletResponse response, StockInRecordDto stockInRecordDto) { stockInRecordService.exportStockInRecord(response,stockInRecordDto); } @PostMapping("/approve") @Log(title = "入库管理-审批入库", businessType = BusinessType.UPDATE) @Operation(summary = "批量审批入库记录") public AjaxResult approve(@RequestBody StockInRecordDto approveDto) { if(CollectionUtils.isEmpty(approveDto.getIds())){ return AjaxResult.error("请选择至少一条数据"); } stockInRecordService.batchApprove(approveDto.getIds(), approveDto.getApprovalStatus()); return AjaxResult.success(); } } src/main/java/com/ruoyi/stock/controller/StockInventoryController.java
@@ -68,6 +68,22 @@ return R.ok(stockInventoryService.subtractStockInventory(stockInventoryDto)); } @PostMapping("/addStockInRecordOnly") @Operation(summary = "新增入库记录(仅创建记录,不调整库存)") public R addStockInRecordOnly(@RequestBody StockInventoryDto stockInventoryDto) { stockInventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.CUSTOMIZATION_STOCK_IN.getCode())); stockInventoryDto.setRecordId(0L); return R.ok(stockInventoryService.addStockInRecordOnly(stockInventoryDto)); } @PostMapping("/addStockOutRecordOnly") @Operation(summary = "新增出库记录(仅创建记录,不调整库存)") public R addStockOutRecordOnly(@RequestBody StockInventoryDto stockInventoryDto) { stockInventoryDto.setRecordType(String.valueOf(StockOutQualifiedRecordTypeEnum.CUSTOMIZATION_STOCK_OUT.getCode())); stockInventoryDto.setRecordId(0L); return R.ok(stockInventoryService.addStockOutRecordOnly(stockInventoryDto)); } @PostMapping("importStockInventory") @Operation(summary = "导入库存") src/main/java/com/ruoyi/stock/controller/StockOutRecordController.java
@@ -10,7 +10,6 @@ import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Operation; import lombok.AllArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; @@ -61,10 +60,31 @@ return AjaxResult.success(stockOutRecordService.batchDelete(ids)); } @DeleteMapping("/pending") @Log(title = "出库管理-删除待审批出库", businessType = BusinessType.DELETE) @Operation(summary = "删除待审批的出库记录") public AjaxResult deletePending(@RequestBody List<Long> ids) { if(CollectionUtils.isEmpty(ids)){ return AjaxResult.error("请选择至少一条数据"); } return AjaxResult.success(stockOutRecordService.batchDeletePending(ids)); } @PostMapping("/exportStockOutRecord") @Operation(summary = "导出出库记录") public void exportStockOutRecord(HttpServletResponse response, StockOutRecordDto stockOutRecordDto) { stockOutRecordService.exportStockOutRecord(response,stockOutRecordDto); } @PostMapping("/approve") @Log(title = "出库管理-审批出库", businessType = BusinessType.UPDATE) @Operation(summary = "批量审批出库记录") public AjaxResult approve(@RequestBody StockOutRecordDto approveDto) { if(CollectionUtils.isEmpty(approveDto.getIds())){ return AjaxResult.error("请选择至少一条数据"); } stockOutRecordService.batchApprove(approveDto.getIds(), approveDto.getApprovalStatus()); return AjaxResult.success(); } } src/main/java/com/ruoyi/stock/controller/StockUninventoryController.java
@@ -51,6 +51,22 @@ return R.ok(stockUninventoryService.subtractStockUninventory(stockUninventoryDto)); } @PostMapping("/addStockInRecordOnly") @Operation(summary = "新增入库记录(仅创建记录,不调整库存)") public R addStockInRecordOnly(@RequestBody StockUninventoryDto stockUninventoryDto) { stockUninventoryDto.setRecordType(String.valueOf(StockInUnQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_IN.getCode())); stockUninventoryDto.setRecordId(0L); return R.ok(stockUninventoryService.addStockInRecordOnly(stockUninventoryDto)); } @PostMapping("/addStockOutRecordOnly") @Operation(summary = "新增出库记录(仅创建记录,不调整库存)") public R addStockOutRecordOnly(@RequestBody StockUninventoryDto stockUninventoryDto) { stockUninventoryDto.setRecordType(String.valueOf(StockOutUnQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_OUT.getCode())); stockUninventoryDto.setRecordId(0L); return R.ok(stockUninventoryService.addStockOutRecordOnly(stockUninventoryDto)); } @PostMapping("/exportStockUninventory") @Operation(summary = "导出库存") public void exportStockUninventory(HttpServletResponse response, StockUninventoryDto stockUninventoryDto) { src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java
@@ -4,6 +4,8 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.List; @Data public class StockInRecordDto extends StockInRecord { @@ -30,4 +32,7 @@ @Schema(description = "顶部父产品id") private Long topParentProductId; @Schema(description = "记录ID列表") private List<Long> ids; } src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java
@@ -43,31 +43,37 @@ @Schema(description = "顶部父产品id") private Long topParentProductId; @Schema(description = "库存类型:qualified(合格)、unqualified(不合格)") private String stockType; @Schema(description = "合格库存数量") private BigDecimal qualifiedQuantity; @Schema(description = "不合格库存数量") private BigDecimal unQualifiedQuantity; @Schema(description = "合格库存冻结数量") private BigDecimal qualifiedLockedQuantity; @Schema(description = "不合格库存冻结数量") private BigDecimal unQualifiedLockedQuantity; @Schema(description = "合格库存未冻结数量") private BigDecimal qualifiedUnLockedQuantity; @Schema(description = "不合格库存未冻结数量") private BigDecimal unQualifiedUnLockedQuantity; @Schema(description = "合格库存待审核出库数量(不占用库存但已申请出库)") private BigDecimal qualifiedPendingOutQuantity; @Schema(description = "不合格库存待审核出库数量") private BigDecimal unQualifiedPendingOutQuantity; @Schema(description = "合格库存ID") private Long qualifiedId; @Schema(description = "不合格库存ID") private Long unQualifiedId; } } src/main/java/com/ruoyi/stock/dto/StockOutRecordDto.java
@@ -6,6 +6,8 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; @Data @AllArgsConstructor @NoArgsConstructor @@ -29,4 +31,7 @@ @Schema(description = "顶部父产品id") private Long topParentProductId; @Schema(description = "记录ID列表") private List<Long> ids; } src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java
@@ -50,4 +50,6 @@ List<Map<String, Object>> selectDailyStockOutCounts(@Param("rootCategoryId") Long rootCategoryId, @Param("startDate") String startDate, @Param("endDate") String endDate); BigDecimal selectTotalByDate(@Param("now") LocalDate now); BigDecimal selectPendingOutQuantity(@Param("productModelId") Long productModelId, @Param("batchNo") String batchNo, @Param("type") String type); } src/main/java/com/ruoyi/stock/mapper/StockUninventoryMapper.java
@@ -9,6 +9,7 @@ import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import java.math.BigDecimal; import java.util.List; /** @@ -26,6 +27,8 @@ int updateSubtractStockUnInventory(@Param("ew") StockUninventoryDto stockUninventoryDto); BigDecimal selectPendingOutQuantity(@Param("productModelId") Long productModelId, @Param("batchNo") String batchNo, @Param("type") String type); int updateAddStockUnInventory(@Param("ew") StockUninventoryDto stockUninventoryDto); List<StockUnInventoryExportData> listStockInventoryExportData(@Param("ew") StockUninventoryDto stockUninventoryDto); src/main/java/com/ruoyi/stock/pojo/StockInRecord.java
@@ -2,6 +2,7 @@ import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.JsonFormat; import com.ruoyi.common.enums.ReviewStatusEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; @@ -65,6 +66,9 @@ @TableField(fill = FieldFill.INSERT_UPDATE) private Integer updateUser; @Schema(description = "审批状态 0-待审批 1-通过 2-驳回", implementation = ReviewStatusEnum.class) private Integer approvalStatus; @TableField(fill = FieldFill.INSERT) private Long deptId; } src/main/java/com/ruoyi/stock/pojo/StockOutRecord.java
@@ -2,6 +2,7 @@ import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.JsonFormat; import com.ruoyi.common.enums.ReviewStatusEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; @@ -74,6 +75,9 @@ @Schema(description = "类型 0合格入库 1不合格入库") private String type; @Schema(description = "审批状态 0-待审批 1-通过 2-驳回", implementation = ReviewStatusEnum.class) private Integer approvalStatus; @TableField(fill = FieldFill.INSERT) private Long deptId; } src/main/java/com/ruoyi/stock/service/StockInRecordService.java
@@ -18,5 +18,9 @@ int batchDelete(List<Long> ids); int batchDeletePending(List<Long> ids); void exportStockInRecord(HttpServletResponse response, StockInRecordDto stockInRecordDto); int batchApprove(List<Long> ids, Integer approvalStatus); } src/main/java/com/ruoyi/stock/service/StockInventoryService.java
@@ -29,6 +29,10 @@ Boolean subtractStockInventory(StockInventoryDto stockInventoryDto); Boolean addStockInRecordOnly(StockInventoryDto stockInventoryDto); Boolean addStockOutRecordOnly(StockInventoryDto stockInventoryDto); R importStockInventory(MultipartFile file); void exportStockInventory(HttpServletResponse response, StockInventoryDto stockInventoryDto); src/main/java/com/ruoyi/stock/service/StockOutRecordService.java
@@ -26,5 +26,9 @@ int batchDelete(List<Long> ids); int batchDeletePending(List<Long> ids); void exportStockOutRecord(HttpServletResponse response, StockOutRecordDto stockOutRecordDto); int batchApprove(List<Long> ids, Integer approvalStatus); } src/main/java/com/ruoyi/stock/service/StockUninventoryService.java
@@ -25,6 +25,10 @@ Integer subtractStockUninventory(StockUninventoryDto stockUninventoryDto); Integer addStockInRecordOnly(StockUninventoryDto stockUninventoryDto); Integer addStockOutRecordOnly(StockUninventoryDto stockUninventoryDto); void exportStockUninventory(HttpServletResponse response, StockUninventoryDto stockUninventoryDto); Boolean frozenStock(StockInventoryDto stockInventoryDto); src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java
@@ -4,6 +4,7 @@ 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.common.enums.ReviewStatusEnum; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum; import com.ruoyi.common.exception.base.BaseException; @@ -26,6 +27,7 @@ import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import jakarta.servlet.http.HttpServletResponse; import java.util.List; @@ -127,4 +129,106 @@ ExcelUtil<StockInRecordExportData> util = new ExcelUtil<>(StockInRecordExportData.class); util.exportExcel(response,list, "入库记录信息"); } private StockInventory getStockInventory(Long productModelId, String batchNo) { LambdaQueryWrapper<StockInventory> eq = new LambdaQueryWrapper<>(); eq.eq(StockInventory::getProductModelId, productModelId); if (StringUtils.isEmpty(batchNo)) { eq.isNull(StockInventory::getBatchNo); } else { eq.eq(StockInventory::getBatchNo, batchNo); } return stockInventoryMapper.selectOne(eq); } private StockUninventory getStockUninventory(Long productModelId, String batchNo) { LambdaQueryWrapper<StockUninventory> eq = new LambdaQueryWrapper<>(); eq.eq(StockUninventory::getProductModelId, productModelId); if (StringUtils.isEmpty(batchNo)) { eq.isNull(StockUninventory::getBatchNo); } else { eq.eq(StockUninventory::getBatchNo, batchNo); } return stockUninventoryMapper.selectOne(eq); } @Override @Transactional(rollbackFor = Exception.class) public int batchDeletePending(List<Long> ids) { for (Long id : ids) { StockInRecord stockInRecord = stockInRecordMapper.selectById(id); if (stockInRecord == null) { throw new BaseException("入库记录不存在,无法删除!!!"); } if (stockInRecord.getApprovalStatus() != null && !ReviewStatusEnum.PENDING_REVIEW.getCode().equals(stockInRecord.getApprovalStatus())) { throw new BaseException("只有待审批状态的记录才能删除,入库批次:" + stockInRecord.getInboundBatches()); } } return stockInRecordMapper.deleteBatchIds(ids); } @Override @Transactional(rollbackFor = Exception.class) public int batchApprove(List<Long> ids, Integer approvalStatus) { if (CollectionUtils.isEmpty(ids)) { throw new BaseException("请选择至少一条数据"); } if (approvalStatus == null || (!ReviewStatusEnum.APPROVED.getCode().equals(approvalStatus) && !ReviewStatusEnum.REJECTED.getCode().equals(approvalStatus))) { throw new BaseException("审批状态值无效"); } for (Long id : ids) { StockInRecord stockInRecord = stockInRecordMapper.selectById(id); if (stockInRecord == null) { throw new BaseException("入库记录不存在,无法审批!!!"); } if (stockInRecord.getApprovalStatus() != null && !ReviewStatusEnum.PENDING_REVIEW.getCode().equals(stockInRecord.getApprovalStatus())) { throw new BaseException("只有待审批状态的记录才能审批,入库批次:" + stockInRecord.getInboundBatches()); } stockInRecord.setApprovalStatus(approvalStatus); stockInRecordMapper.updateById(stockInRecord); // 审批通过时,库存增加 if (ReviewStatusEnum.APPROVED.getCode().equals(approvalStatus)) { if ("0".equals(stockInRecord.getType())) { // 合格入库 -> 先查库存,存在则更新,不存在则新增 StockInventory stockInventory = getStockInventory(stockInRecord.getProductModelId(), stockInRecord.getBatchNo()); StockInventoryDto stockInventoryDto = new StockInventoryDto(); stockInventoryDto.setProductModelId(stockInRecord.getProductModelId()); stockInventoryDto.setBatchNo(stockInRecord.getBatchNo()); stockInventoryDto.setQualitity(stockInRecord.getStockInNum()); stockInventoryDto.setRemark(stockInRecord.getRemark()); if (stockInventory == null) { stockInventoryMapper.insert(new StockInventory() {{ setProductModelId(stockInRecord.getProductModelId()); setQualitity(stockInRecord.getStockInNum()); setBatchNo(stockInRecord.getBatchNo()); setRemark(stockInRecord.getRemark()); setVersion(1); }}); } else { stockInventoryMapper.updateAddStockInventory(stockInventoryDto); } } else if ("1".equals(stockInRecord.getType())) { // 不合格入库 -> 先查库存,存在则更新,不存在则新增 StockUninventory stockUninventory = getStockUninventory(stockInRecord.getProductModelId(), stockInRecord.getBatchNo()); StockUninventoryDto stockUninventoryDto = new StockUninventoryDto(); stockUninventoryDto.setProductModelId(stockInRecord.getProductModelId()); stockUninventoryDto.setBatchNo(stockInRecord.getBatchNo()); stockUninventoryDto.setQualitity(stockInRecord.getStockInNum()); stockUninventoryDto.setRemark(stockInRecord.getRemark()); if (stockUninventory == null) { stockUninventoryMapper.insert(new StockUninventory() {{ setProductModelId(stockInRecord.getProductModelId()); setQualitity(stockInRecord.getStockInNum()); setBatchNo(stockInRecord.getBatchNo()); setRemark(stockInRecord.getRemark()); setVersion(1); }}); } else { stockUninventoryMapper.updateAddStockUnInventory(stockUninventoryDto); } } } } return ids.size(); } } src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
@@ -8,7 +8,8 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.base.BaseException; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.web.domain.R; @@ -145,6 +146,63 @@ @Override @Transactional(rollbackFor = Exception.class) public Boolean addStockInRecordOnly(StockInventoryDto stockInventoryDto) { StockInRecordDto stockInRecordDto = new StockInRecordDto(); stockInRecordDto.setRecordId(stockInventoryDto.getRecordId()); stockInRecordDto.setRecordType(stockInventoryDto.getRecordType()); stockInRecordDto.setStockInNum(stockInventoryDto.getQualitity()); stockInRecordDto.setBatchNo(stockInventoryDto.getBatchNo()); stockInRecordDto.setProductModelId(stockInventoryDto.getProductModelId()); stockInRecordDto.setType("0"); stockInRecordDto.setRemark(stockInventoryDto.getRemark()); stockInRecordService.add(stockInRecordDto); return true; } @Override @Transactional(rollbackFor = Exception.class) public Boolean addStockOutRecordOnly(StockInventoryDto stockInventoryDto) { LambdaQueryWrapper<StockInventory> eq = new LambdaQueryWrapper<>(); eq.eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId()); if (StringUtils.isEmpty(stockInventoryDto.getBatchNo())) { eq.isNull(StockInventory::getBatchNo); } else { eq.eq(StockInventory::getBatchNo, stockInventoryDto.getBatchNo()); } StockInventory stockInventory = stockInventoryMapper.selectOne(eq); if (stockInventory == null) { throw new ServiceException("库存记录不存在"); } BigDecimal lockedQty = stockInventory.getLockedQuantity(); if (lockedQty == null) { lockedQty = BigDecimal.ZERO; } BigDecimal pendingOut = stockInventoryMapper.selectPendingOutQuantity( stockInventoryDto.getProductModelId(), stockInventoryDto.getBatchNo(), "0" ); if (pendingOut == null) { pendingOut = BigDecimal.ZERO; } BigDecimal availableQty = stockInventory.getQualitity().subtract(lockedQty).subtract(pendingOut); if (stockInventoryDto.getQualitity().compareTo(availableQty) > 0) { throw new ServiceException("申请数量超过可用库存,当前可用库存为:" + availableQty); } StockOutRecordDto stockOutRecordDto = new StockOutRecordDto(); stockOutRecordDto.setRecordId(stockInventoryDto.getRecordId()); stockOutRecordDto.setRecordType(stockInventoryDto.getRecordType()); stockOutRecordDto.setStockOutNum(stockInventoryDto.getQualitity()); stockOutRecordDto.setBatchNo(stockInventoryDto.getBatchNo()); stockOutRecordDto.setProductModelId(stockInventoryDto.getProductModelId()); stockOutRecordDto.setType("0"); stockOutRecordDto.setRemark(stockInventoryDto.getRemark()); stockOutRecordService.add(stockOutRecordDto); return true; } @Override @Transactional(rollbackFor = Exception.class) public R importStockInventory(MultipartFile file) { try { // 查询所有的产品并构建映射,提高查找效率 src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java
@@ -4,6 +4,7 @@ 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.common.enums.ReviewStatusEnum; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum; import com.ruoyi.common.exception.base.BaseException; @@ -26,6 +27,8 @@ import com.ruoyi.stock.service.StockOutRecordService; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import jakarta.servlet.http.HttpServletResponse; import java.util.List; @@ -130,4 +133,90 @@ ExcelUtil<StockOutRecordExportData> util = new ExcelUtil<>(StockOutRecordExportData.class); util.exportExcel(response,list, "出库记录信息"); } @Override @Transactional(rollbackFor = Exception.class) public int batchDeletePending(List<Long> ids) { for (Long id : ids) { StockOutRecord stockOutRecord = stockOutRecordMapper.selectById(id); if (stockOutRecord == null) { throw new BaseException("出库记录不存在,无法删除!!!"); } if (stockOutRecord.getApprovalStatus() != null && !ReviewStatusEnum.PENDING_REVIEW.getCode().equals(stockOutRecord.getApprovalStatus())) { throw new BaseException("只有待审批状态的记录才能删除,出库批次:" + stockOutRecord.getOutboundBatches()); } } return stockOutRecordMapper.deleteBatchIds(ids); } @Override @Transactional(rollbackFor = Exception.class) public int batchApprove(List<Long> ids, Integer approvalStatus) { if (CollectionUtils.isEmpty(ids)) { throw new BaseException("请选择至少一条数据"); } if (approvalStatus == null || (!ReviewStatusEnum.APPROVED.getCode().equals(approvalStatus) && !ReviewStatusEnum.REJECTED.getCode().equals(approvalStatus))) { throw new BaseException("审批状态值无效"); } for (Long id : ids) { StockOutRecord stockOutRecord = stockOutRecordMapper.selectById(id); if (stockOutRecord == null) { throw new BaseException("出库记录不存在,无法审批!!!"); } if (stockOutRecord.getApprovalStatus() != null && !ReviewStatusEnum.PENDING_REVIEW.getCode().equals(stockOutRecord.getApprovalStatus())) { throw new BaseException("只有待审批状态的记录才能审批,出库批次:" + stockOutRecord.getOutboundBatches()); } stockOutRecord.setApprovalStatus(approvalStatus); stockOutRecordMapper.updateById(stockOutRecord); // 审批通过时,扣减库存 if (ReviewStatusEnum.APPROVED.getCode().equals(approvalStatus)) { if ("0".equals(stockOutRecord.getType())) { // 合格出库 -> 先查库存是否存在,存在才扣减 StockInventory stockInventory = getStockInventory(stockOutRecord.getProductModelId(), stockOutRecord.getBatchNo()); if (stockInventory == null) { throw new BaseException("合格库存记录不存在,出库批次:" + stockOutRecord.getOutboundBatches()); } StockInventoryDto stockInventoryDto = new StockInventoryDto(); stockInventoryDto.setProductModelId(stockOutRecord.getProductModelId()); stockInventoryDto.setBatchNo(stockOutRecord.getBatchNo()); stockInventoryDto.setQualitity(stockOutRecord.getStockOutNum()); stockInventoryMapper.updateSubtractStockInventory(stockInventoryDto); } else if ("1".equals(stockOutRecord.getType())) { // 不合格出库 -> 先查库存是否存在,存在才扣减 StockUninventory stockUninventory = getStockUninventory(stockOutRecord.getProductModelId(), stockOutRecord.getBatchNo()); if (stockUninventory == null) { throw new BaseException("不合格库存记录不存在,出库批次:" + stockOutRecord.getOutboundBatches()); } StockUninventoryDto stockUninventoryDto = new StockUninventoryDto(); stockUninventoryDto.setProductModelId(stockOutRecord.getProductModelId()); stockUninventoryDto.setBatchNo(stockOutRecord.getBatchNo()); stockUninventoryDto.setQualitity(stockOutRecord.getStockOutNum()); stockUninventoryMapper.updateSubtractStockUnInventory(stockUninventoryDto); } } } return ids.size(); } private StockInventory getStockInventory(Long productModelId, String batchNo) { LambdaQueryWrapper<StockInventory> eq = new LambdaQueryWrapper<>(); eq.eq(StockInventory::getProductModelId, productModelId); if (StringUtils.isEmpty(batchNo)) { eq.isNull(StockInventory::getBatchNo); } else { eq.eq(StockInventory::getBatchNo, batchNo); } return stockInventoryMapper.selectOne(eq); } private StockUninventory getStockUninventory(Long productModelId, String batchNo) { LambdaQueryWrapper<StockUninventory> eq = new LambdaQueryWrapper<>(); eq.eq(StockUninventory::getProductModelId, productModelId); if (StringUtils.isEmpty(batchNo)) { eq.isNull(StockUninventory::getBatchNo); } else { eq.eq(StockUninventory::getBatchNo, batchNo); } return stockUninventoryMapper.selectOne(eq); } } src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java
@@ -6,6 +6,7 @@ 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.common.exception.base.BaseException; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.stock.dto.StockInRecordDto; @@ -24,6 +25,8 @@ import org.springframework.transaction.annotation.Transactional; import jakarta.servlet.http.HttpServletResponse; import java.math.BigDecimal; import java.util.List; /** @@ -95,6 +98,7 @@ stockOutRecordDto.setRecordType(stockUninventoryDto.getRecordType()); stockOutRecordDto.setStockOutNum(stockUninventoryDto.getQualitity()); stockOutRecordDto.setProductModelId(stockUninventoryDto.getProductModelId()); stockOutRecordDto.setBatchNo(stockUninventoryDto.getBatchNo()); stockOutRecordDto.setType("1"); stockOutRecordService.add(stockOutRecordDto); StockUninventory oldStockInventory = stockUninventoryMapper.selectOne(new QueryWrapper<StockUninventory>().lambda().eq(StockUninventory::getProductModelId, stockUninventoryDto.getProductModelId())); @@ -107,6 +111,63 @@ } @Override @Transactional(rollbackFor = Exception.class) public Integer addStockInRecordOnly(StockUninventoryDto stockUninventoryDto) { StockInRecordDto stockInRecordDto = new StockInRecordDto(); stockInRecordDto.setRecordId(stockUninventoryDto.getRecordId()); stockInRecordDto.setRecordType(stockUninventoryDto.getRecordType()); stockInRecordDto.setStockInNum(stockUninventoryDto.getQualitity()); stockInRecordDto.setBatchNo(stockUninventoryDto.getBatchNo()); stockInRecordDto.setProductModelId(stockUninventoryDto.getProductModelId()); stockInRecordDto.setType("1"); stockInRecordDto.setRemark(stockUninventoryDto.getRemark()); stockInRecordService.add(stockInRecordDto); return 1; } @Override @Transactional(rollbackFor = Exception.class) public Integer addStockOutRecordOnly(StockUninventoryDto stockUninventoryDto) { LambdaQueryWrapper<StockUninventory> eq = new LambdaQueryWrapper<>(); eq.eq(StockUninventory::getProductModelId, stockUninventoryDto.getProductModelId()); if (StringUtils.isEmpty(stockUninventoryDto.getBatchNo())) { eq.isNull(StockUninventory::getBatchNo); } else { eq.eq(StockUninventory::getBatchNo, stockUninventoryDto.getBatchNo()); } StockUninventory stockUninventory = stockUninventoryMapper.selectOne(eq); if (stockUninventory == null) { throw new BaseException("库存记录不存在"); } BigDecimal lockedQty = stockUninventory.getLockedQuantity(); if (lockedQty == null) { lockedQty = BigDecimal.ZERO; } BigDecimal pendingOut = stockUninventoryMapper.selectPendingOutQuantity( stockUninventoryDto.getProductModelId(), stockUninventoryDto.getBatchNo(), "1" ); if (pendingOut == null) { pendingOut = BigDecimal.ZERO; } BigDecimal availableQty = stockUninventory.getQualitity().subtract(lockedQty).subtract(pendingOut); if (stockUninventoryDto.getQualitity().compareTo(availableQty) > 0) { throw new BaseException("申请数量超过可用库存,当前可用库存为:" + availableQty); } StockOutRecordDto stockOutRecordDto = new StockOutRecordDto(); stockOutRecordDto.setRecordId(stockUninventoryDto.getRecordId()); stockOutRecordDto.setRecordType(stockUninventoryDto.getRecordType()); stockOutRecordDto.setStockOutNum(stockUninventoryDto.getQualitity()); stockOutRecordDto.setBatchNo(stockUninventoryDto.getBatchNo()); stockOutRecordDto.setProductModelId(stockUninventoryDto.getProductModelId()); stockOutRecordDto.setType("1"); stockOutRecordDto.setRemark(stockUninventoryDto.getRemark()); stockOutRecordService.add(stockOutRecordDto); return 1; } @Override public void exportStockUninventory(HttpServletResponse response, StockUninventoryDto stockUninventoryDto) { List<StockUnInventoryExportData> list = stockUninventoryMapper.listStockInventoryExportData(stockUninventoryDto); ExcelUtil<StockUnInventoryExportData> util = new ExcelUtil<>(StockUnInventoryExportData.class); src/main/resources/mapper/stock/StockInventoryMapper.xml
@@ -106,8 +106,10 @@ SUM(unQualifiedQuantity) as unQualifiedQuantity, SUM(qualifiedLockedQuantity) as qualifiedLockedQuantity, SUM(unQualifiedLockedQuantity) as unQualifiedLockedQuantity, SUM(qualifiedQuantity - qualifiedLockedQuantity) as qualifiedUnLockedQuantity, SUM(unQualifiedQuantity - unQualifiedLockedQuantity) as unQualifiedUnLockedQuantity, SUM(qualifiedQuantity - qualifiedLockedQuantity - IFNULL(qualifiedPendingOut, 0)) as qualifiedUnLockedQuantity, SUM(unQualifiedQuantity - unQualifiedLockedQuantity - IFNULL(unQualifiedPendingOut, 0)) as unQualifiedUnLockedQuantity, SUM(IFNULL(qualifiedPendingOut, 0)) as qualifiedPendingOutQuantity, SUM(IFNULL(unQualifiedPendingOut, 0)) as unQualifiedPendingOutQuantity, product_model_id, MAX(create_time) as create_time, MAX(update_time) as update_time, @@ -139,7 +141,16 @@ si.remark, pm.unit, p.product_name, p.id as product_id p.id as product_id, ( select IFNULL(SUM(sor.stock_out_num), 0) from stock_out_record sor where sor.product_model_id = si.product_model_id and (si.batch_no is null and sor.batch_no is null or si.batch_no = sor.batch_no) and sor.type = '0' and sor.approval_status = 0 ) as qualifiedPendingOut, 0 as unqualifiedPendingOut 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 @@ -165,7 +176,16 @@ su.remark, pm.unit, p.product_name, p.id as product_id p.id as product_id, 0 as qualifiedPendingOut, ( select IFNULL(SUM(sor.stock_out_num), 0) from stock_out_record sor where sor.product_model_id = su.product_model_id and (su.batch_no is null and sor.batch_no is null or su.batch_no = sor.batch_no) and sor.type = '1' and sor.approval_status = 0 ) as unqualifiedPendingOut from stock_uninventory su left join product_model pm on su.product_model_id = pm.id left join product p on pm.product_id = p.id @@ -410,4 +430,13 @@ ORDER BY DATE(sor.create_time) ASC </select> <select id="selectPendingOutQuantity" resultType="java.math.BigDecimal"> SELECT IFNULL(SUM(sor.stock_out_num), 0) FROM stock_out_record sor WHERE sor.product_model_id = #{productModelId} AND (sor.batch_no = #{batchNo} OR (#{batchNo} IS NULL AND sor.batch_no IS NULL)) AND sor.type = #{type} AND sor.approval_status = 0 </select> </mapper> src/main/resources/mapper/stock/StockUninventoryMapper.xml
@@ -95,4 +95,13 @@ </if> </select> <select id="selectPendingOutQuantity" resultType="java.math.BigDecimal"> SELECT IFNULL(SUM(sor.stock_out_num), 0) FROM stock_out_record sor WHERE sor.product_model_id = #{productModelId} AND (sor.batch_no = #{batchNo} OR (#{batchNo} IS NULL AND sor.batch_no IS NULL)) AND sor.type = #{type} AND sor.approval_status = 0 </select> </mapper>