Commit 10ef807472085608648cb12a5006318bd148d637

Authored by YunaiV
1 parent 9ff3593f

feat(wms):库存增加列表接口

yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/WmsInventoryController.java
... ... @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
7 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  8 +import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryListReqVO;
8 9 import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryPageReqVO;
9 10 import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryRespVO;
10 11 import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDO;
... ... @@ -55,6 +56,14 @@ public class WmsInventoryController {
55 56 return success(new PageResult<>(buildInventoryRespVOList(pageResult.getList()), pageResult.getTotal()));
56 57 }
57 58  
  59 + @GetMapping("/list")
  60 + @Operation(summary = "获得库存统计列表")
  61 + @PreAuthorize("@ss.hasPermission('wms:inventory:query')")
  62 + public CommonResult<List<WmsInventoryRespVO>> getInventoryList(@Valid WmsInventoryListReqVO listReqVO) {
  63 + List<WmsInventoryDO> list = inventoryService.getInventoryList(listReqVO);
  64 + return success(buildInventoryRespVOList(list));
  65 + }
  66 +
58 67 // ==================== 拼接 VO ====================
59 68  
60 69 private List<WmsInventoryRespVO> buildInventoryRespVOList(List<WmsInventoryDO> list) {
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/WmsInventoryListReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.inventory.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.NotNull;
  5 +import lombok.Data;
  6 +
  7 +@Schema(description = "管理后台 - WMS 库存统计列表 Request VO")
  8 +@Data
  9 +public class WmsInventoryListReqVO {
  10 +
  11 + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
  12 + @NotNull(message = "仓库编号不能为空")
  13 + private Long warehouseId;
  14 +
  15 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/inventory/WmsInventoryMapper.java
... ... @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
7 7 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
8 8 import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
  9 +import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryListReqVO;
9 10 import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryPageReqVO;
10 11 import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDO;
11 12 import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
... ... @@ -48,11 +49,24 @@ public interface WmsInventoryMapper extends BaseMapperX&lt;WmsInventoryDO&gt; {
48 49 return selectCount(WmsInventoryDO::getSkuId, skuId);
49 50 }
50 51  
  52 + default List<WmsInventoryDO> selectList(WmsInventoryListReqVO reqVO) {
  53 + return selectList(new LambdaQueryWrapperX<WmsInventoryDO>()
  54 + .eq(WmsInventoryDO::getWarehouseId, reqVO.getWarehouseId())
  55 + .orderByAsc(WmsInventoryDO::getSkuId)
  56 + .orderByAsc(WmsInventoryDO::getId));
  57 + }
  58 +
51 59 default WmsInventoryDO selectBySkuIdAndWarehouseId(Long skuId, Long warehouseId) {
52 60 return selectOne(WmsInventoryDO::getSkuId, skuId,
53 61 WmsInventoryDO::getWarehouseId, warehouseId);
54 62 }
55 63  
  64 + default WmsInventoryDO selectByIdForUpdate(Long id) {
  65 + return selectOne(new LambdaQueryWrapperX<WmsInventoryDO>()
  66 + .eq(WmsInventoryDO::getId, id)
  67 + .last("FOR UPDATE"));
  68 + }
  69 +
56 70 /**
57 71 * 根据多个唯一键,批量查询库存列表
58 72 *
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryService.java
1 1 package cn.iocoder.yudao.module.wms.service.inventory;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryListReqVO;
4 5 import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryPageReqVO;
5 6 import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDO;
6 7 import cn.iocoder.yudao.module.wms.service.inventory.dto.WmsInventoryChangeReqDTO;
  8 +import cn.iocoder.yudao.module.wms.service.inventory.dto.WmsInventoryCheckReqDTO;
  9 +
  10 +import java.util.List;
7 11  
8 12 /**
9 13 * WMS 库存 Service 接口
... ... @@ -21,6 +25,14 @@ public interface WmsInventoryService {
21 25 PageResult<WmsInventoryDO> getInventoryPage(WmsInventoryPageReqVO pageReqVO);
22 26  
23 27 /**
  28 + * 获得库存余额列表
  29 + *
  30 + * @param listReqVO 列表查询
  31 + * @return 库存余额列表
  32 + */
  33 + List<WmsInventoryDO> getInventoryList(WmsInventoryListReqVO listReqVO);
  34 +
  35 + /**
24 36 * 获得指定 SKU 的库存数量
25 37 *
26 38 * @param skuId SKU 编号
... ... @@ -29,6 +41,13 @@ public interface WmsInventoryService {
29 41 long getInventoryCountBySkuId(Long skuId);
30 42  
31 43 /**
  44 + * 盘点库存
  45 + *
  46 + * @param reqDTO 盘点库存请求
  47 + */
  48 + void checkInventory(WmsInventoryCheckReqDTO reqDTO);
  49 +
  50 + /**
32 51 * 变更库存
33 52 *
34 53 * @param reqDTO 库存变更请求
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryServiceImpl.java
... ... @@ -5,6 +5,7 @@ import cn.hutool.core.lang.Tuple;
5 5 import cn.hutool.core.util.ObjectUtil;
6 6 import cn.iocoder.yudao.framework.common.exception.ServiceException;
7 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  8 +import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryListReqVO;
8 9 import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryPageReqVO;
9 10 import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDO;
10 11 import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryHistoryDO;
... ... @@ -12,6 +13,7 @@ import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
12 13 import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
13 14 import cn.iocoder.yudao.module.wms.dal.mysql.inventory.WmsInventoryMapper;
14 15 import cn.iocoder.yudao.module.wms.service.inventory.dto.WmsInventoryChangeReqDTO;
  16 +import cn.iocoder.yudao.module.wms.service.inventory.dto.WmsInventoryCheckReqDTO;
15 17 import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
16 18 import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
17 19 import jakarta.annotation.Resource;
... ... @@ -59,12 +61,44 @@ public class WmsInventoryServiceImpl implements WmsInventoryService {
59 61 }
60 62  
61 63 @Override
  64 + public List<WmsInventoryDO> getInventoryList(WmsInventoryListReqVO listReqVO) {
  65 + return inventoryMapper.selectList(listReqVO);
  66 + }
  67 +
  68 + @Override
62 69 public long getInventoryCountBySkuId(Long skuId) {
63 70 return inventoryMapper.selectCountBySkuId(skuId);
64 71 }
65 72  
66 73 @Override
67 74 @Transactional(rollbackFor = Exception.class)
  75 + public void checkInventory(WmsInventoryCheckReqDTO reqDTO) {
  76 + if (reqDTO == null || CollUtil.isEmpty(reqDTO.getItems())) {
  77 + return;
  78 + }
  79 +
  80 + List<WmsInventoryDO> updateInventories = new ArrayList<>(reqDTO.getItems().size());
  81 + List<WmsInventoryHistoryDO> histories = new ArrayList<>(reqDTO.getItems().size());
  82 + for (WmsInventoryCheckReqDTO.Item item : reqDTO.getItems()) {
  83 + WmsInventoryDO inventory = getOrCreateCheckInventory(item);
  84 + BigDecimal beforeQuantity = inventory.getQuantity();
  85 + BigDecimal afterQuantity = item.getCheckQuantity();
  86 + if (beforeQuantity.compareTo(afterQuantity) == 0) {
  87 + continue;
  88 + }
  89 + updateInventories.add(new WmsInventoryDO().setId(inventory.getId()).setQuantity(afterQuantity));
  90 + histories.add(buildInventoryHistory(reqDTO, item, beforeQuantity, afterQuantity));
  91 + }
  92 + if (CollUtil.isNotEmpty(updateInventories)) {
  93 + inventoryMapper.updateBatch(updateInventories);
  94 + }
  95 + if (CollUtil.isNotEmpty(histories)) {
  96 + inventoryHistoryService.createInventoryHistoryList(histories);
  97 + }
  98 + }
  99 +
  100 + @Override
  101 + @Transactional(rollbackFor = Exception.class)
68 102 public void changeInventory(WmsInventoryChangeReqDTO reqDTO) {
69 103 if (reqDTO == null || CollUtil.isEmpty(reqDTO.getItems())) {
70 104 return;
... ... @@ -179,6 +213,43 @@ public class WmsInventoryServiceImpl implements WmsInventoryService {
179 213 .setOrderId(reqDTO.getOrderId()).setOrderNo(reqDTO.getOrderNo()).setOrderType(reqDTO.getOrderType());
180 214 }
181 215  
  216 + private WmsInventoryHistoryDO buildInventoryHistory(WmsInventoryCheckReqDTO reqDTO,
  217 + WmsInventoryCheckReqDTO.Item item,
  218 + BigDecimal beforeQuantity,
  219 + BigDecimal afterQuantity) {
  220 + return new WmsInventoryHistoryDO()
  221 + .setWarehouseId(item.getWarehouseId()).setSkuId(item.getSkuId())
  222 + .setQuantity(afterQuantity.subtract(beforeQuantity))
  223 + .setBeforeQuantity(beforeQuantity).setAfterQuantity(afterQuantity)
  224 + .setPrice(item.getPrice()).setRemark(item.getRemark())
  225 + .setOrderId(reqDTO.getOrderId()).setOrderNo(reqDTO.getOrderNo()).setOrderType(reqDTO.getOrderType());
  226 + }
  227 +
  228 + private WmsInventoryDO getOrCreateCheckInventory(WmsInventoryCheckReqDTO.Item item) {
  229 + if (item.getInventoryId() == null) {
  230 + return createCheckInventory(item);
  231 + }
  232 + WmsInventoryDO inventory = inventoryMapper.selectByIdForUpdate(item.getInventoryId());
  233 + if (inventory == null || !isSameInventory(inventory, item)
  234 + || inventory.getQuantity().compareTo(item.getQuantity()) != 0) {
  235 + throw exception(CHECK_ORDER_INVENTORY_CHANGED);
  236 + }
  237 + return inventory;
  238 + }
  239 +
  240 + private WmsInventoryDO createCheckInventory(WmsInventoryCheckReqDTO.Item item) {
  241 + WmsInventoryDO inventory = new WmsInventoryDO()
  242 + .setSkuId(item.getSkuId()).setWarehouseId(item.getWarehouseId())
  243 + .setQuantity(item.getCheckQuantity());
  244 + try {
  245 + inventoryMapper.insert(inventory);
  246 + } catch (DuplicateKeyException ex) {
  247 + throw exception(CHECK_ORDER_INVENTORY_CHANGED);
  248 + }
  249 + inventory.setQuantity(BigDecimal.ZERO);
  250 + return inventory;
  251 + }
  252 +
182 253 private static WmsInventoryDO findInventory(List<WmsInventoryDO> inventories, WmsInventoryChangeReqDTO.Item item) {
183 254 return CollUtil.findOne(inventories, inventory -> isSameInventory(inventory, item));
184 255 }
... ... @@ -192,6 +263,11 @@ public class WmsInventoryServiceImpl implements WmsInventoryService {
192 263 && ObjectUtil.equal(inventory.getWarehouseId(), item.getWarehouseId());
193 264 }
194 265  
  266 + private static boolean isSameInventory(WmsInventoryDO inventory, WmsInventoryCheckReqDTO.Item item) {
  267 + return ObjectUtil.equal(inventory.getSkuId(), item.getSkuId())
  268 + && ObjectUtil.equal(inventory.getWarehouseId(), item.getWarehouseId());
  269 + }
  270 +
195 271 private static boolean isSameInventory(WmsInventoryDO inventory, WmsInventoryDO key) {
196 272 return ObjectUtil.equal(inventory.getSkuId(), key.getSkuId())
197 273 && ObjectUtil.equal(inventory.getWarehouseId(), key.getWarehouseId());
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuServiceImpl.java
... ... @@ -21,6 +21,7 @@ import org.springframework.validation.annotation.Validated;
21 21 import java.util.Collection;
22 22 import java.util.HashSet;
23 23 import java.util.List;
  24 +import java.util.Objects;
24 25 import java.util.Set;
25 26  
26 27 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
... ... @@ -58,10 +59,8 @@ public class WmsItemSkuServiceImpl implements WmsItemSkuService {
58 59 @Transactional(rollbackFor = Exception.class)
59 60 public void createItemSkuList(Long itemId, List<WmsItemSkuSaveReqVO> skus) {
60 61 validateItemSkuList(skus);
61   - List<WmsItemSkuDO> list = BeanUtils.toBean(skus, WmsItemSkuDO.class, sku -> sku.setItemId(itemId));
62   - if (CollUtil.isNotEmpty(convertList(list, WmsItemSkuDO::getId))) {
63   - throw exception(ITEM_SKU_NOT_EXISTS);
64   - }
  62 + List<WmsItemSkuDO> list = BeanUtils.toBean(skus, WmsItemSkuDO.class, sku ->
  63 + sku.setItemId(itemId).setId(null)); // id 由数据库自增分配,避免前端误操作
65 64 itemSkuMapper.insertBatch(list);
66 65 }
67 66  
... ... @@ -74,7 +73,7 @@ public class WmsItemSkuServiceImpl implements WmsItemSkuService {
74 73 List<WmsItemSkuDO> oldList = itemSkuMapper.selectListByItemId(itemId);
75 74 List<WmsItemSkuDO> newList = BeanUtils.toBean(skus, WmsItemSkuDO.class);
76 75 List<List<WmsItemSkuDO>> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录
77   - (oldVal, newVal) -> oldVal.getId().equals(newVal.getId()));
  76 + (oldVal, newVal) -> Objects.equals(oldVal.getId(), newVal.getId()));
78 77  
79 78 // 第二步,批量添加、修改、删除
80 79 if (CollUtil.isNotEmpty(diffList.get(2))) {
... ... @@ -85,10 +84,11 @@ public class WmsItemSkuServiceImpl implements WmsItemSkuService {
85 84 itemSkuMapper.deleteByIds(deleteSkuIds);
86 85 }
87 86 if (CollUtil.isNotEmpty(diffList.get(0))) {
88   - if (CollUtil.isNotEmpty(convertList(diffList.get(0), WmsItemSkuDO::getId))) {
89   - throw exception(ITEM_SKU_NOT_EXISTS);
90   - }
91   - diffList.get(0).forEach(sku -> sku.setItemId(itemId));
  87 + // 新增场景下忽略前端误传的 SKU id:统一置 null,由数据库自增分配
  88 + diffList.get(0).forEach(sku -> {
  89 + sku.setItemId(itemId);
  90 + sku.setId(null);
  91 + });
92 92 itemSkuMapper.insertBatch(diffList.get(0));
93 93 }
94 94 if (CollUtil.isNotEmpty(diffList.get(1))) {
... ...