package com.ruoyi.stock.service.impl;
|
|
import cn.hutool.core.bean.BeanUtil;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
|
import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
|
import com.ruoyi.common.utils.OrderUtils;
|
import com.ruoyi.framework.web.domain.R;
|
import com.ruoyi.procurementrecord.utils.StockUtils;
|
import com.ruoyi.project.system.domain.SysUser;
|
import com.ruoyi.project.system.mapper.SysUserMapper;
|
import com.ruoyi.stock.dto.*;
|
import com.ruoyi.stock.mapper.StockInventoryCheckItemMapper;
|
import com.ruoyi.stock.mapper.StockInventoryCheckPlanMapper;
|
import com.ruoyi.stock.mapper.StockInventoryCheckProductMapper;
|
import com.ruoyi.stock.mapper.WarehouseInfoMapper;
|
import com.ruoyi.stock.pojo.*;
|
import com.ruoyi.stock.service.*;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.math.BigDecimal;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
/**
|
* <p>
|
* 盘点计划表 服务实现类
|
* </p>
|
*
|
* @author 芯导软件(江苏)有限公司
|
* @since 2026-05-09 10:00:43
|
*/
|
@Service
|
@RequiredArgsConstructor
|
public class StockInventoryCheckPlanServiceImpl extends ServiceImpl<StockInventoryCheckPlanMapper, StockInventoryCheckPlan> implements StockInventoryCheckPlanService {
|
|
private final StockInventoryCheckPlanMapper stockInventoryCheckPlanMapper;
|
private final StockInventoryCheckProductMapper stockInventoryCheckProductMapper;
|
private final SysUserMapper sysUserMapper;
|
private final StockInventoryCheckMainService stockInventoryCheckMainService;
|
private final StockInventoryService stockInventoryService;
|
private final StockInventoryCheckItemMapper stockInventoryCheckItemMapper;
|
private final StockUtils stockUtils;
|
private final StockInRecordService stockInRecordService;
|
private final StockOutRecordService stockOutRecordService;
|
private final WarehouseInfoMapper warehouseInfoMapper;
|
|
@Override
|
public IPage<StockInventoryCheckPlanDto> listPage(Page page, StockInventoryCheckPlanDto stockInventoryCheckPlanDto) {
|
IPage<StockInventoryCheckPlanDto> stockInventoryCheckPlanDtoIPage = stockInventoryCheckPlanMapper.listPage(page, stockInventoryCheckPlanDto);
|
stockInventoryCheckPlanDtoIPage.getRecords().forEach(item -> {
|
List<StockInventoryCheckProduct> stockInventoryCheckProducts = stockInventoryCheckProductMapper.selectList(new LambdaQueryWrapper<StockInventoryCheckProduct>().eq(StockInventoryCheckProduct::getInventoryCheckPlanId, item.getId()));
|
item.setItems(stockInventoryCheckProducts);
|
});
|
return stockInventoryCheckPlanDtoIPage ;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public R start(Long id) {
|
StockInventoryCheckPlan stockInventoryCheckPlan = this.getById(id);
|
StockInventoryCheckPlanDto stockInventoryCheckPlanDto = new StockInventoryCheckPlanDto();
|
BeanUtil.copyProperties(stockInventoryCheckPlan, stockInventoryCheckPlanDto);
|
List<StockInventoryCheckProduct> stockInventoryCheckProducts = stockInventoryCheckProductMapper.selectList(new LambdaQueryWrapper<StockInventoryCheckProduct>().eq(StockInventoryCheckProduct::getInventoryCheckPlanId, id));
|
stockInventoryCheckPlanDto.setItems(stockInventoryCheckProducts);
|
BigDecimal totalQuantity = stockInventoryCheckPlanDto.getItems().stream()
|
.peek(item -> {
|
item.setInventoryCheckPlanId(stockInventoryCheckPlanDto.getId());
|
List<StockInventory> list = stockInventoryService.list(new LambdaQueryWrapper<StockInventory>().eq(StockInventory::getProductModelId, item.getProductModelId()));
|
BigDecimal systemQty = list.stream()
|
.map(StockInventory::getQualitity)
|
.filter(Objects::nonNull)
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
item.setSystemQuantity(systemQty);
|
})
|
.map(StockInventoryCheckProduct::getSystemQuantity)
|
.filter(Objects::nonNull)
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
//新增库存盘点
|
ArrayList<StockInventoryCheckItemDto> stockInventoryCheckItemDtos = new ArrayList<>();
|
StockInventoryCheckMainDto stockInventoryCheckMainDto = new StockInventoryCheckMainDto();
|
stockInventoryCheckMainDto.setCheckType("1");
|
stockInventoryCheckMainDto.setTotalQuantity(totalQuantity);
|
stockInventoryCheckMainDto.setSourceType("1");
|
stockInventoryCheckMainDto.setSourceId(stockInventoryCheckPlanDto.getId());
|
stockInventoryCheckMainDto.setStatus(0);
|
stockInventoryCheckPlanDto.getItems().forEach(item -> {
|
List<StockInventoryDto> list = stockInventoryService.selectStockInvenrory(item.getProductModelId());
|
//锁定库存
|
list.forEach(inventory -> {
|
inventory.setLocked(true);
|
stockInventoryService.updateById(inventory);
|
});
|
for (StockInventoryDto stockInventory : list) {
|
StockInventoryCheckItemDto stockInventoryCheckItemDto = new StockInventoryCheckItemDto();
|
stockInventoryCheckItemDto.setProductModelId(stockInventory.getProductModelId());
|
stockInventoryCheckItemDto.setBatchNo(stockInventory.getBatchNo());
|
stockInventoryCheckItemDto.setWarehouseInfoId(stockInventory.getWarehouseInfoId());
|
stockInventoryCheckItemDto.setSystemQuantity(stockInventory.getQualitity());
|
stockInventoryCheckItemDto.setModel(stockInventory.getModel());
|
stockInventoryCheckItemDto.setUnit(stockInventory.getUnit());
|
stockInventoryCheckItemDto.setProductName(stockInventory.getProductName());
|
stockInventoryCheckItemDtos.add(stockInventoryCheckItemDto);
|
}
|
});
|
stockInventoryCheckMainDto.setStockInventoryCheckItemDtos(stockInventoryCheckItemDtos);
|
stockInventoryCheckMainService.add(stockInventoryCheckMainDto);
|
stockInventoryCheckPlan.setStatus(1);
|
this.updateById(stockInventoryCheckPlan);
|
return R.ok();
|
}
|
|
@Override
|
public R end(StockInventoryCheckPlanDto stockInventoryCheckPlanDto) {
|
StockInventoryCheckPlan plan = this.getById(stockInventoryCheckPlanDto.getId());
|
if (plan == null) {
|
return R.fail("盘点单不存在");
|
}
|
for (StockInventoryCheckItem item : stockInventoryCheckPlanDto.getCheckItems()) {
|
//更新库存锁定状态
|
stockInventoryService.updateLocked(item.getProductModelId(),item.getBatchNo(), false);
|
if (item.getDifferenceQuantity() == null || item.getDifferenceQuantity().compareTo(BigDecimal.ZERO) == 0) {
|
continue;
|
}
|
StockInventoryDto stockInventoryDto = new StockInventoryDto();
|
stockInventoryDto.setProductModelId(item.getProductModelId());
|
stockInventoryDto.setBatchNo(item.getBatchNo());
|
stockInventoryDto.setQualitity(item.getDifferenceQuantity());
|
stockInventoryDto.setRecordId(stockInventoryCheckPlanDto.getId());
|
|
if (item.getDifferenceQuantity().compareTo(BigDecimal.ZERO) > 0) {
|
stockInventoryDto.setRecordType(StockInQualifiedRecordTypeEnum.INVENTORY_CHECK_STOCK_IN.getCode());
|
StockInRecordDto stockInRecordDto = stockUtils.addStockWithBatchNo(stockInventoryDto.getProductModelId(), item.getDifferenceQuantity().abs (), stockInventoryDto.getRecordType(), stockInventoryDto.getRecordId(), stockInventoryDto.getBatchNo(), resolveWarehouseInfoId(item.getProductModelId(), item.getBatchNo()));
|
//直接审核通过
|
stockInRecordService.batchApprove(Collections.singletonList(stockInRecordDto.getId()), 1, resolveWarehouseInfoId(item.getProductModelId(), item.getBatchNo()));
|
}else {
|
stockInventoryDto.setRecordType(StockOutQualifiedRecordTypeEnum.INVENTORY_CHECK_STOCK_OUT.getCode());
|
StockOutRecordDto stock = stockUtils.substractStock(stockInventoryDto.getProductModelId(), item.getDifferenceQuantity().abs(), stockInventoryDto.getRecordType(), stockInventoryDto.getRecordId(), stockInventoryDto.getBatchNo(), resolveWarehouseInfoId(item.getProductModelId(), item.getBatchNo()));
|
//直接审核通过
|
stockOutRecordService.batchApprove(Collections.singletonList(stock.getId()), 1,item.getWarehouseInfoId());
|
}
|
}
|
stockInventoryCheckItemMapper.updateById(stockInventoryCheckPlanDto.getCheckItems());
|
plan.setStatus(2);
|
this.updateById(plan);
|
return R.ok("盘点完成,库存已调整");
|
}
|
|
@Override
|
public StockInventoryCheckPlanDto detail(Long id) {
|
//查询仓库
|
List<WarehouseInfo> warehouseInfos = warehouseInfoMapper.selectList(null);
|
|
StockInventoryCheckPlan byId = this.getById(id);
|
if (byId == null) {
|
return null;
|
}
|
StockInventoryCheckPlanDto stockInventoryCheckPlanDto = new StockInventoryCheckPlanDto();
|
BeanUtil.copyProperties(byId, stockInventoryCheckPlanDto);
|
|
List<StockInventoryCheckProduct> items = stockInventoryCheckProductMapper.selectList(
|
new LambdaQueryWrapper<StockInventoryCheckProduct>()
|
.eq(StockInventoryCheckProduct::getInventoryCheckPlanId, id));
|
stockInventoryCheckPlanDto.setItems(items);
|
|
StockInventoryCheckMain checkMain = stockInventoryCheckMainService.getOne(
|
new LambdaQueryWrapper<StockInventoryCheckMain>()
|
.eq(StockInventoryCheckMain::getSourceId, id));
|
|
if (checkMain != null) {
|
List<StockInventoryCheckItem> checkItems = stockInventoryCheckItemMapper.selectList(
|
new LambdaQueryWrapper<StockInventoryCheckItem>()
|
.eq(StockInventoryCheckItem::getMainId, checkMain.getId()));
|
checkItems.stream().forEach(item -> {
|
item.setWarehouseName(warehouseInfos.stream().filter(warehouseInfo -> warehouseInfo.getId().equals(item.getWarehouseInfoId())).findFirst().get().getWarehouseName());
|
});
|
stockInventoryCheckPlanDto.setCheckItems(checkItems);
|
}
|
|
return stockInventoryCheckPlanDto;
|
}
|
|
@Override
|
public R add(StockInventoryCheckPlanDto stockInventoryCheckPlanDto) {
|
SysUser sysUser = sysUserMapper.selectUserById(stockInventoryCheckPlanDto.getCheckerId());
|
stockInventoryCheckPlanDto.setCheckerName(sysUser.getNickName());
|
//生成盘点计划编号
|
if (ObjectUtils.isEmpty(stockInventoryCheckPlanDto.getPlanNo())) {
|
stockInventoryCheckPlanDto.setPlanNo(OrderUtils.countTodayByCreateTime(
|
stockInventoryCheckPlanMapper, "PD", "plan_no"));
|
}
|
//新增计划
|
this.save(stockInventoryCheckPlanDto);
|
//设置盘点商品关联ID并查询系统库存
|
stockInventoryCheckPlanDto.getItems().forEach(item -> {
|
item.setInventoryCheckPlanId(stockInventoryCheckPlanDto.getId());
|
List<StockInventory> list = stockInventoryService.list(new LambdaQueryWrapper<StockInventory>().eq(StockInventory::getProductModelId, item.getProductModelId()));
|
BigDecimal systemQty = list.stream()
|
.map(StockInventory::getQualitity)
|
.filter(Objects::nonNull)
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
item.setSystemQuantity(systemQty);
|
});
|
//新增盘点商品
|
stockInventoryCheckProductMapper.insert(stockInventoryCheckPlanDto.getItems());
|
return R.ok();
|
}
|
|
@Override
|
public R edit(StockInventoryCheckPlanDto stockInventoryCheckPlanDto) {
|
SysUser sysUser = sysUserMapper.selectUserById(stockInventoryCheckPlanDto.getCheckerId());
|
stockInventoryCheckPlanDto.setCheckerName(sysUser.getNickName());
|
// 查询数据库中的旧数据
|
List<StockInventoryCheckProduct> oldItems = stockInventoryCheckProductMapper.selectList(
|
new LambdaQueryWrapper<StockInventoryCheckProduct>()
|
.eq(StockInventoryCheckProduct::getInventoryCheckPlanId, stockInventoryCheckPlanDto.getId()));
|
// 设置盘点商品关联 ID 并查询系统库存
|
stockInventoryCheckPlanDto.getItems().forEach(item -> {
|
item.setInventoryCheckPlanId(stockInventoryCheckPlanDto.getId());
|
// 查询并设置系统库存
|
List<StockInventory> list = stockInventoryService.list(
|
new LambdaQueryWrapper<StockInventory>().eq(StockInventory::getProductModelId, item.getProductModelId()));
|
BigDecimal systemQty = list.stream()
|
.map(StockInventory::getQualitity)
|
.filter(Objects::nonNull)
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
item.setSystemQuantity(systemQty);
|
// 如果旧数据中不存在该 ID,说明是新增,需要清空 ID 让数据库自动生成
|
boolean isExisting = oldItems.stream().anyMatch(old -> old.getId().equals(item.getId()));
|
if (!isExisting) {
|
item.setId(null);
|
}
|
});
|
// 使用 insertOrUpdate 批量处理,自动区分新增和更新
|
stockInventoryCheckProductMapper.insertOrUpdate(stockInventoryCheckPlanDto.getItems());
|
// 处理删除:旧数据中有但新数据中没有的项
|
Set<Long> newItemIds = stockInventoryCheckPlanDto.getItems().stream()
|
.map(StockInventoryCheckProduct::getId)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toSet());
|
List<Long> toDeleteIds = oldItems.stream()
|
.map(StockInventoryCheckProduct::getId)
|
.filter(id -> !newItemIds.contains(id))
|
.collect(Collectors.toList());
|
if (!toDeleteIds.isEmpty()) {
|
stockInventoryCheckProductMapper.deleteByIds(toDeleteIds);
|
}
|
return R.ok(this.updateById(stockInventoryCheckPlanDto));
|
}
|
|
@Override
|
public R delete(List<Long> ids) {
|
List<StockInventoryCheckPlan> list = this.list(new LambdaQueryWrapper<StockInventoryCheckPlan>().in(StockInventoryCheckPlan::getId, ids));
|
boolean hasNonZeroStatus = list.stream().anyMatch(plan -> plan.getStatus() != null && plan.getStatus() != 0);
|
if (hasNonZeroStatus) {
|
return R.fail("存在已执行或者正在执行的盘点计划,不允许删除");
|
}
|
return R.ok(this.removeByIds(ids));
|
}
|
|
|
private Long resolveWarehouseInfoId(Long productModelId, String batchNo) {
|
List<StockInventory> inventories = stockInventoryService.list(new LambdaQueryWrapper<StockInventory>()
|
.eq(StockInventory::getProductModelId, productModelId)
|
.eq(batchNo != null, StockInventory::getBatchNo, batchNo)
|
.isNull(batchNo == null, StockInventory::getBatchNo));
|
if (inventories.isEmpty() || inventories.get(0).getWarehouseInfoId() == null) {
|
return 1L;
|
}
|
return inventories.get(0).getWarehouseInfoId();
|
}
|
}
|