谷粒商城-基础篇-仓储服务(P95-P99)


仓储服务

一、仓储服务-API

库存信息表:

wms_ware_info 包括仓库所在地区等仓库信息(与商品无关)
wms_ware_sku:具体商品的库存量和所在仓库
wms_purchase_detail:采购需求
wms_purchase:采购单
wms_ware_order_task:库存工作单
wms_ware_order_task_detail:库存工作单详情


1、整合ware服务

gulimall-ware:

  • 创建项目后nacos注册、网关重写等
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
		#ware服务路由
        - id: ware_route
          uri: lb://gulimall-ware
          predicates:
            - Path=/api/ware/**
          filters:
            # 把/api/* 去掉,剩下的留下来
            - RewritePath=/api/(?<segment>.*),/$\{segment}


2、仓库维护

提供模糊查询的仓库信息:
在这里插入图片描述

 @Override
    public PageUtils queryPage(Map<String, Object> params) {
        QueryWrapper<WareInfoEntity> wrapper = new QueryWrapper<>();

        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)) {
            wrapper.eq("id", key)
                    .or().like("name", key)
                    .or().like("address", key)
                    .or().like("areacode", key);
        }

        IPage<WareInfoEntity> page = this.page(
                new Query<WareInfoEntity>().getPage(params),
                wrapper
        );

        return new PageUtils(page);
    }


3、商品库存

功能:查询sku+库存id+库存数等信息

在这里插入图片描述

数据库表:wms_ware_sku 指明每个仓库有什么sku
在这里插入图片描述

手动新增库存:商品库存页面/新增,然后填写 sku_id+仓库+库存数 等信息
在这里插入图片描述

自动新增库存:需要通过采购完成


4、采购单维护


(1)采购需求

采购需求的生成方式可能有两种:

  • 人工新增
  • 系统检测到库存量低时自动创建

流程:
在这里插入图片描述


(2)合并采购需求

比如一个仓库的东西可以合并到一起,让采购人员一趟采购完

  1. 查询未领取的采购单:/ware/purchase/unreceive/list
  @Override
    public PageUtils queryPageUnreceive(Map<String, Object> params) {

        IPage<PurchaseEntity> page = this.page(
                new Query<PurchaseEntity>().getPage(params),
                new QueryWrapper<PurchaseEntity>().eq("status", 0).or().eq("status", 1)
        );

        return new PageUtils(page);
    }
  1. 采购单
  • wms_purchase采购单,里面有创建时间和分类人员等信息
  • wms_purchase_detail采购单详情表,指明采购单每项要采购的sku,可以自己新增采购单,然后让新的采购需求合并到已有采购单里。

采购单状态:只有新建、已分配的时候才能合并采购单

新建 0
已分配 1
已领取(正在采购) 2
已完成 3
有异常(采购失败) 4

  1. 合并采购需求:/ware/purchase/merge

请求数据:
{
purchaseId: 1, # 采购单id,没有携带就新建采购单
items: [1, 2] # 采购商品
}

注:如果不选择整单直接点击确定,将弹出提示。

在这里插入图片描述

流程:

  • 如果没有带过来采购单id,先新建采购单
  • 然后修改【采购需求】里对应的【采购单id、采购需求状态】,即purchase_detail
  • 采购需求是purchase_detail表、采购单是purchase表。采购单由多个采购需求组成
  • 采购单页面分配采购需求成功后应该刷新页面,或者说不能重复分配采购需求给不同的采购单(或者说是一个更新操作)

PurchaseServiceImpl

  /**
     * 合并采购需求
     *
     * @param mergeVo
     */
    @Transactional
    @Override
    public void mergePurchase(MergeVo mergeVo) {

        Long purchaseId = mergeVo.getPurchaseId();
        // 一、判断是否有采购单,没有的话新建一个
        if (purchaseId == null) {
            //1、新建一个
            PurchaseEntity purchaseEntity = new PurchaseEntity();
            //2、修改对应转态
            purchaseEntity.setStatus(WareConstant.PurchaseStatusEnum.CREATED.getCode());
            purchaseEntity.setCreateTime(new Date());
            purchaseEntity.setUpdateTime(new Date());

            this.save(purchaseEntity);
            purchaseId = purchaseEntity.getId();
        }

        //TODO 确认采购单状态是0,1才可以合并

        // 二、有采购单id,进行合并
        List<Long> items = mergeVo.getItems();
        Long finalPurchaseId = purchaseId;

        List<PurchaseDetailEntity> collect = items.stream().map(i -> {
            // 采购需求
            PurchaseDetailEntity detailEntity = new PurchaseDetailEntity();

            detailEntity.setId(i);
            // 合并到那个采购单
            detailEntity.setPurchaseId(finalPurchaseId);
            // 设置最新状态码为已分配
            detailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.ASSIGNED.getCode());
            return detailEntity;
        }).collect(Collectors.toList());
        // 保存修改
        detailService.updateBatchById(collect);

        // 三、分配完后更新时间
        PurchaseEntity purchaseEntity = new PurchaseEntity();
        purchaseEntity.setId(purchaseId);
        purchaseEntity.setUpdateTime(new Date());
        this.updateById(purchaseEntity);

    }

采购需求状态枚举:

public class WareConstant {

    /**
     * 采购单状态枚举
     */
    public enum PurchaseStatusEnum {

        CREATED(0, "新建"),
        ASSIGNED(1, "已分配"),
        RECEIVE(2, "已领取"),
        FINISH(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, "正在采购"),
        FINISH(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;
        }
    }
}


(3)领取采购单

请求地址:/ware/purchase/received

  • 某个人领取了采购单后,先看采购单是否处于未分配状态,只有采购单是新建或以领取状态时,才更新采购单的状态
  • 领取后确认采购单的状态、采购单人员等是否相符
  • 更改采购单状态、更改采购需求状态

后台系统里没有领取采购单这个功能,我们暂时通过postman手动领取采购单

  • http://localhost:88/api/ware/purchase/received
 /**
     * 领取采购单
     * ids:采购单id
     * 过滤采购需求,并同步采购需求的状态
     */
    @Override
    public void received(List<Long> ids) {

        //1、确认当前采购单是新建或者已分配状态
        List<PurchaseEntity> collect = ids.stream().map(id -> {
            // 1.1 查出采购单详细信息
            PurchaseEntity byId = this.getById(id);
            return byId;
        }).filter(item -> {
            // 1.2 过滤出新建过着已分配的采购单
            if (item.getStatus() == WareConstant.PurchaseStatusEnum.CREATED.getCode() || item.getStatus() == WareConstant.PurchaseStatusEnum.ASSIGNED.getCode()) {
                return true;
            }
            return false;
        }).map(item -> {
            // 1.3 设置最新状态
            item.setStatus(WareConstant.PurchaseStatusEnum.RECEIVE.getCode());
            item.setUpdateTime(new Date());
            return item;
        }).collect(Collectors.toList());

        //2、改变采购单的状态
        this.updateBatchById(collect);

        //3、改变采购需求的状态
        collect.forEach((item) -> {
            // 3.1 找到采购项(采购需求)
            List<PurchaseDetailEntity> entities = detailService.listDetailByPurchaseId(item.getId());

            List<PurchaseDetailEntity> detailEntities = entities.stream().map(entity -> {
                PurchaseDetailEntity entity1 = new PurchaseDetailEntity();

                entity1.setId(entity.getId());
                entity1.setStatus(WareConstant.PurchaseDetailStatusEnum.BUYING.getCode());
                return entity1;
            }).collect(Collectors.toList());
            // 3.2 批量更新状态
            detailService.updateBatchById(detailEntities);
        });
    }

(4)完成采购,添加到库存

在这里插入图片描述

可以多选采购单里哪些采购项(需求)完成了

  • 采购项都完成的时候采购单为完成,否则为有异常

在这里插入图片描述

  • 采购项完成时增加到库存
    在这里插入图片描述

  • 增加库存时要判断原来是否有库存以区分insert和update

API信息:同样相关页面也省略,通过POSTMAN发送,代表采购员采购回来了,提交信息

 /**
     * 完成采购
     *
     * @param doneVo
     */
    @Transactional
    @Override
    public void done(PurchaseDoneVo doneVo) {

        Long id = doneVo.getId();

        //2、改变采购项(需求)的状态
        Boolean flag = true;
        List<PurchaseItemDoneVo> items = doneVo.getItems();
        // 2.1 收集要更新的信息
        List<PurchaseDetailEntity> updates = new ArrayList<>();

        for (PurchaseItemDoneVo item : items) {
        	// 采购项(需求)
            PurchaseDetailEntity detailEntity = new PurchaseDetailEntity();
            // 若有一个采购不成功
            if (item.getStatus() == WareConstant.PurchaseDetailStatusEnum.HASERROR.getCode()) {
                flag = false;
                detailEntity.setStatus(item.getStatus());
            } else {
                // 设置成功状态
                detailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.FINISH.getCode());
                // 3、将成功采购的进行入库
                // 3.1 先查出采购项
                PurchaseDetailEntity entity = detailService.getById(item.getItemId());
                wareSkuService.addStock(entity.getSkuId(), entity.getWareId(), entity.getSkuNum());

            }
            detailEntity.setId(item.getItemId());
            // 更新信息
            updates.add(detailEntity);
        }

        // 2.2 更新信息
        detailService.updateBatchById(updates);

        //1、改变采购单状态
        PurchaseEntity purchaseEntity = new PurchaseEntity();
        purchaseEntity.setId(id);
        purchaseEntity.setStatus(flag ? WareConstant.PurchaseStatusEnum.FINISH.getCode() : WareConstant.PurchaseStatusEnum.HASERROR.getCode());
        purchaseEntity.setUpdateTime(new Date());
        this.updateById(purchaseEntity);

    }

完成采购增加库存时,需要涉及到设置SKU的name信息到仓库中,这是通过feign远程调用“gulimall-product”服务来实现根据sku_id查询得到sku_name的。

只要异常被捕获,事务是不会滚的(这里需要优化,是高级篇消息队列实现一致性事务的内容)

  @Override
    public void addStock(Long skuId, Long wareId, Integer skuNum) {
        //1、判断如果还没有这个库存记录是新增
        List<WareSkuEntity> entities = wareSkuDao.selectList(new QueryWrapper<WareSkuEntity>().eq("sku_id", skuId).eq("ware_id", wareId));
        if (entities == null || entities.size() == 0) {
            WareSkuEntity skuEntity = new WareSkuEntity();
            skuEntity.setSkuId(skuId);
            skuEntity.setStock(skuNum);
            skuEntity.setWareId(wareId);
            skuEntity.setStockLocked(0);
            //TODO 远程查询sku的名字,如果失败,整个事务无需回滚
            //1、自己catch异常
            //TODO 还可以用什么办法让异常出现以后不回滚?高级
            try {
                R info = productFeignService.info(skuId);
                Map<String, Object> data = (Map<String, Object>) info.get("skuInfo");

                if (info.getCode() == 0) {
                    skuEntity.setSkuName((String) data.get("skuName"));
                }
            } catch (Exception e) {

            }
            wareSkuDao.insert(skuEntity);
        } else {
            wareSkuDao.addStock(skuId, wareId, skuNum);
        }

    }

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

绿箭柠檬茶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值