库存系统

首先了解一下库存系统的数据库设计:

73.jpg


一、仓库管理

仓库管理的代码,我们得逆向工程已经全部自动完成了:

74.jpg

测试可用,新增2个仓库,以供后用!

完善一下,搜索时的模糊查询功能,略!


二、查询库存&创建采购需求

  GET  /ware/waresku/list  

{
   page: 1,//当前页码
   limit: 10,//每页记录数
   sidx: 'id',//排序字段
   order: 'asc/desc',//排序方式
   wareId: 123,//仓库id
   skuId: 123//商品id
}

1、实现过程代码:略;效果如下:(从商品管理的具体Sku上点击 更多——库存管理,可以直接携带查询条件跳转到库存管理的页面)

75.jpg

直接跳转:

76.jpg

2、上面的过程很简单,但是需要注意的是:

实际使用过程中,新增库存的工作,我们并不会通过:此新增按钮直接新增,因为不严谨,可能实际并没有库存;

而是通过:采购单全流程 实现库存的增加;大概过程如下:

  • 新建采购需求:来源:人工后台创建 + 系统自动发出低库存预警并创建采购需求;

  • 创建采购单:采购单由一个或多个采购需求构成(一个大订单中其实包含多个商品的采购需求);人工合并或系统定时合并;

  • 分配到采购人员

  • 采购人员接单并进行采购工作;

  • 采购完成后,采购单入库;

  • 成功采购的商品自动添加库存;

3、新增采购需求:新增了两个:

77.jpg

完善一下条件搜索功能:略!

  GET  /ware/purchasedetail/list  

{
   page: 1,//当前页码
   limit: 10,//每页记录数
   sidx: 'id',//排序字段
   order: 'asc/desc',//排序方式
   key: '华为',//检索关键字
   status: 0,//状态    
   wareId: 1,//仓库id
}

三、合并采购需求

采购的简要流程大致如下:文字描述上节已经描述;

78.jpg

1、新增采购单:

79.jpg

2、合并采购需求到整单:注意:“已分配但是未领取”的采购单也是可以继续被合并的;

80.jpg

  GET   /ware/purchase/unreceive/list  

无传参,略!

81.jpg

3、点击确认合并采购需求:

  POST  /ware/purchase/merge  

{
  purchaseId: 1, //整单id
  items:[1,2,3,4] //合并项集合
}

此处要满足一个设计:当提交的数据中没有purchaseId的时候,我们需要快速地创建一个采购单,并合并到它;

我们现在common中为库存模块定义一个常量枚举类:

public class WareConstant {
    public enum PurchaseStatusEnum {
        CREATED(0, "新建"), ASSIGNED(1, "已分配"),
        RECEIVED(2, "已领取"), FINISHED(3, "已完成"),
        HASERROR(4, "有异常");
        private int code;
        private String msg;

        PurchaseStatusEnum(int code, String msg){
            this.code = code;
            this.msg = msg;
        }

        public int getCode(){
            return code;
        }

        public String getMsg(){
            return msg;
        }
    }

    public enum PurchaseDetailStatusEnum {
        CREATED(0, "新建"), ASSIGNED(1, "已分配"),
        BUYING(2, "正在采购"), FINISHED(3, "已完成"),
        HASERROR(4, "采购失败");
        private int code;
        private String msg;

        PurchaseDetailStatusEnum(int code, String msg){
            this.code = code;
            this.msg = msg;
        }

        public int getCode(){
            return code;
        }

        public String getMsg(){
            return msg;
        }
    }
}

PurchaseServiceImpl.java:

@Transactional
@Override
public void mergePurchase(MergeVo mergeVo) {
    Long purchaseId = mergeVo.getPurchaseId();   //如果purchaseId存在,则合并到它,如果不存在则新建后再合并
    if (purchaseId == null){
        PurchaseEntity purchaseEntity = new PurchaseEntity();
        purchaseEntity.setCreateTime(new Date());
        purchaseEntity.setUpdateTime(new Date());
        purchaseEntity.setStatus(WareConstant.PurchaseStatusEnum.CREATED.getCode());
        this.save(purchaseEntity);
        purchaseId = purchaseEntity.getId();
    }

    Long finalPurchaseId = purchaseId;
    List<PurchaseDetailEntity> collect = mergeVo.getItems().stream().map(i -> {
        PurchaseDetailEntity detailEntity = new PurchaseDetailEntity();
        detailEntity.setId(i);
        detailEntity.setPurchaseId(finalPurchaseId);
        detailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.ASSIGNED.getCode());
        return detailEntity;
    }).collect(Collectors.toList());
    //批量修改
    purchaseDetailService.updateBatchById(collect);

    //更新采购单的最后更新时间
    PurchaseEntity purchase = new PurchaseEntity();
    purchase.setId(finalPurchaseId);
    purchase.setUpdateTime(new Date());
    this.updateById(purchase);
}

合并成功后的效果如下:

82.jpg

同时,对应的采购单的最后更新时间也会发生改变:

83.jpg

这样,合并采购需求的操作就完成了!


四、采购人员领取采购单

但是领取操作,不是由采购人员在我们后台进行操作的,正常情况下是采购人员有自己的App,在App上点击领取,调用我们得接口,完成领取操作;

所以,领取操作,我们使用 postman 模拟App操作;

注意,已经被领取的采购单,新的采购需求就不可以再被分配过去了,与上面合并环节相呼应了!

且采购单并领取后,除了采购单状态变为“已领取”,对应的采购需求状态将被置为“正在采购”!

  POST   /ware/purchase/received  

[1,2,3,4]//采购单id

测试领取1号采购单:

84.jpg

成功后,检查采购单状态:

85.jpg

同时,对应的采购需求的状态也变为了“正在采购”:

86.jpg


五、完成采购

1、完成采购的功能也应该是由采购人员通过App点击完成,调用的接口为:

  POST   /ware/purchase/done  

{
   id: 123,//采购单id
   items: [{itemId:1,status:4,reason:""}]//完成/失败的需求详情
}

PurchaseServiceImpl.java:

@Transactional
@Override
public void done(PurchaseDoneVo vo) {
    //1、改变采购项状态;
    Boolean flag = true;  //只有有任何一个采购项没有采购成功,都将被置为false
    List<PurchaseDetailEntity> updates = new ArrayList<>();
    for (PurchaseDoneVo.ItemVo item: vo.getItems()){
        PurchaseDetailEntity detailEntity = new PurchaseDetailEntity();
        if (item.getStatus() == WareConstant.PurchaseDetailStatusEnum.HASERROR.getCode()){
            flag = false;
            detailEntity.setStatus(item.getStatus());
        }else {
            detailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.FINISHED.getCode());
            //2、将成功采购的sku进行入库;
            PurchaseDetailEntity detail = purchaseDetailService.getById(item.getItemId());
            wareSkuService.addStock(detail.getSkuId(), detail.getWareId(), detail.getSkuNum());
        }
        detailEntity.setId(item.getItemId());
        updates.add(detailEntity);
    }
    purchaseDetailService.updateBatchById(updates);

    //3、改变采购单状态;
    PurchaseEntity purchaseEntity = new PurchaseEntity();
    purchaseEntity.setId(vo.getId());
    purchaseEntity.setStatus(flag?WareConstant.PurchaseStatusEnum.FINISHED.getCode():WareConstant.PurchaseStatusEnum.HASERROR.getCode());
    purchaseEntity.setUpdateTime(new Date());
    this.updateById(purchaseEntity);
}

WareSkuServiceImpl.java:

@Override
public void addStock(Long skuId, Long wareId, Integer skuNum) {
    List<WareSkuEntity> list = this.list(new QueryWrapper<WareSkuEntity>().eq("sku_id", skuId).eq("ware_id", wareId));
    if (CollectionUtils.isEmpty(list)){
        WareSkuEntity entity = new WareSkuEntity();
        entity.setSkuId(skuId);
        //远程调用zidanmall-product服务,查询skuName
        try {   //如果失败,整个事务不需要回滚,因为只是name
            R info = productFeignService.info(skuId);
            if (info.getCode() == 0){
                Map<String, Object> map = (Map<String, Object>) info.get("skuInfo");
                entity.setSkuName((String) map.get("skuName"));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        entity.setWareId(wareId);
        entity.setStock(skuNum);
        entity.setStockLocked(0);
        this.save(entity);
    }else {
        this.baseMapper.addStock(skuId, wareId, skuNum);
    }
}

2、测试——接口调用:

93.jpg

3、测试——对比:

采购完成前:

库存:

87.jpg

采购单信息:

89.jpg

采购需求:

88.jpg

采购完成后:

采购需求:

92.jpg

采购单:

91.jpg

商品库存:

90.jpg

jiguiquan@163.com

文章作者信息...

留下你的评论

*评论支持代码高亮<pre class="prettyprint linenums">代码</pre>

相关推荐