package com.ruoyi.stock.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.stock.dto.ProductBorrowDto; import com.ruoyi.stock.dto.StockInventoryDto; import com.ruoyi.stock.mapper.ProductBorrowMapper; import com.ruoyi.stock.pojo.ProductBorrow; import com.ruoyi.stock.service.ProductBorrowService; import com.ruoyi.stock.service.StockInventoryService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; /** * 产品领用 Service 实现类 * * @author ruoyi */ @Slf4j @Service @RequiredArgsConstructor public class ProductBorrowServiceImpl extends ServiceImpl implements ProductBorrowService { private final ProductBorrowMapper productBorrowMapper; private final StockInventoryService stockInventoryService; @Override public IPage listPage(Page page, ProductBorrowDto dto) { IPage result = productBorrowMapper.listPage(page, dto); // 填充状态名称 result.getRecords().forEach(this::fillStatusName); return result; } @Override @Transactional(rollbackFor = Exception.class) public Boolean add(ProductBorrowDto dto) { // 生成领用单号 String borrowNo = generateBorrowNo(); dto.setBorrowNo(borrowNo); // 设置初始状态 - 直接设为已通过(取消审批流程) dto.setApprovalStatus(1); // 已通过 dto.setStatus(0); // 未归还 dto.setReturnedQuantity(BigDecimal.ZERO); dto.setBorrowTime(LocalDateTime.now()); // 保存领用记录 save(dto); // 领用时直接做出库操作,自动审核通过 doBorrowStockOut(dto); return true; } /** * 执行领用出库操作(自动审核通过) */ private void doBorrowStockOut(ProductBorrow borrow) { // 构建库存扣减参数 StockInventoryDto stockInventoryDto = new StockInventoryDto(); stockInventoryDto.setProductModelId(borrow.getProductModelId()); stockInventoryDto.setBatchNo(borrow.getBatchNo()); stockInventoryDto.setQualitity(borrow.getBorrowQuantity()); stockInventoryDto.setRecordType(String.valueOf(StockOutQualifiedRecordTypeEnum.PRODUCT_BORROW.getCode())); stockInventoryDto.setRecordId(borrow.getId()); stockInventoryDto.setRemark("产品领用出库,领用单号:" + borrow.getBorrowNo()); // 设置审批状态为已通过,自动审核 stockInventoryDto.setApprovalStatus(1); // 调用库存服务扣减库存 stockInventoryService.subtractStockInventory(stockInventoryDto); log.info("产品领用出库成功,领用单号:{},数量:{}", borrow.getBorrowNo(), borrow.getBorrowQuantity()); } @Override @Transactional(rollbackFor = Exception.class) public Boolean update(ProductBorrowDto dto) { ProductBorrow existing = getById(dto.getId()); if (existing == null) { throw new ServiceException("领用记录不存在"); } // 只有未通过审批状态才能修改(但现在默认已通过,所以不允许修改) if (existing.getApprovalStatus() != 0) { throw new ServiceException("领用记录已完成出库,不能修改"); } return updateById(dto); } @Override @Transactional(rollbackFor = Exception.class) public Boolean delete(List ids) { for (Long id : ids) { ProductBorrow borrow = getById(id); if (borrow != null && borrow.getApprovalStatus() != 0) { throw new ServiceException("领用记录已完成出库,不能删除"); } } return removeByIds(ids); } @Override @Transactional(rollbackFor = Exception.class) public Boolean batchApprove(List ids, Integer approvalStatus) { for (Long id : ids) { ProductBorrow borrow = getById(id); if (borrow == null) { throw new ServiceException("领用记录不存在: " + id); } if (borrow.getApprovalStatus() != 0) { throw new ServiceException("只有待审批状态的记录才能审批"); } borrow.setApprovalStatus(approvalStatus); updateById(borrow); // 审批通过后扣减库存 if (approvalStatus == 1) { onApprovePass(borrow); } } return true; } @Override @Transactional(rollbackFor = Exception.class) public void onApprovePass(ProductBorrow borrow) { // 构建库存扣减参数,设置审批状态为已通过 StockInventoryDto stockInventoryDto = new StockInventoryDto(); stockInventoryDto.setProductModelId(borrow.getProductModelId()); stockInventoryDto.setBatchNo(borrow.getBatchNo()); stockInventoryDto.setQualitity(borrow.getBorrowQuantity()); stockInventoryDto.setRecordType(String.valueOf(StockOutQualifiedRecordTypeEnum.PRODUCT_BORROW.getCode())); stockInventoryDto.setRecordId(borrow.getId()); stockInventoryDto.setRemark("产品领用出库,领用单号:" + borrow.getBorrowNo()); stockInventoryDto.setApprovalStatus(1); stockInventoryService.subtractStockInventory(stockInventoryDto); log.info("产品领用审批通过,扣减库存成功,领用单号:{},数量:{}", borrow.getBorrowNo(), borrow.getBorrowQuantity()); } @Override public ProductBorrowDto getDetailById(Long id) { ProductBorrowDto dto = productBorrowMapper.selectDetailById(id); if (dto != null) { fillStatusName(dto); // 计算剩余可归还数量 if (dto.getBorrowQuantity() != null && dto.getReturnedQuantity() != null) { dto.setRemainingQuantity(dto.getBorrowQuantity().subtract(dto.getReturnedQuantity())); } } return dto; } /** * 生成领用单号 * 格式:LY + 年月日 + 4位序号 */ private String generateBorrowNo() { String dateStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.likeRight(ProductBorrow::getBorrowNo, "LY" + dateStr) .orderByDesc(ProductBorrow::getBorrowNo) .last("LIMIT 1"); ProductBorrow lastBorrow = getOne(wrapper); int sequence = 1; if (lastBorrow != null && lastBorrow.getBorrowNo() != null) { String lastNo = lastBorrow.getBorrowNo(); if (lastNo.length() >= 14) { try { sequence = Integer.parseInt(lastNo.substring(10)) + 1; } catch (NumberFormatException ignored) { } } } return "LY" + dateStr + String.format("%04d", sequence); } /** * 填充状态名称 */ private void fillStatusName(ProductBorrowDto dto) { // 审批状态名称 if (dto.getApprovalStatus() != null) { switch (dto.getApprovalStatus()) { case 0: dto.setApprovalStatusName("待审批"); break; case 1: dto.setApprovalStatusName("已通过"); break; case 2: dto.setApprovalStatusName("已驳回"); break; } } // 归还状态名称 if (dto.getStatus() != null) { switch (dto.getStatus()) { case 0: dto.setStatusName("未归还"); break; case 1: dto.setStatusName("部分归还"); break; case 2: dto.setStatusName("已全部归还"); break; } } } }