谷粒商城笔记+踩坑(8)——仓库管理

简介: 采购单维护-采购需求、 采购单维护-采购单、 仓库维护、商品库存:

导航:

谷粒商城笔记+踩坑汇总篇

Java笔记汇总:

【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析-CSDN博客

目录

仓库管理

0、预览

1、数据表的说明

2、整合仓库服务

3、查询库存的模糊查询

4、采购需求的模糊查询

5、合并采购流程

6、查询未领取的采购单

7、合并采购需求

8、领取采购单

9、完成采购

10、获取spu规格

11、修改商品规格


仓库管理

0、预览

商家先在采购需求界面新增需求,新增时查询了商品、仓库等列表便于选择,然后根据需求新增采购单,采购完毕后将采购单和采购需求的状态字段设为“已完成”对应字典库的代码。

“仓库维护”界面展示仓库的名字、地址,“商品库存”界面展示sku和库存的关系,每个sku所在的每个仓库、以及该仓库下sku数量。

image.gif

采购单维护-采购需求:

image.gif

采购单维护-采购单:

image.gif

仓库维护:

image.gif

库存工作单:

商品库存:

image.gif

1、数据表的说明

gulimall_wms数据库

image.gif

表wms_ware_info,表示仓库信息

image.gif

wms_ware_sku,绑定仓库id和sku_id的关系

image.gif

2、整合仓库服务

1、要整合仓库服务,首先把仓库服务注册到nacos中

image.gif

2、配置网关

- id: ware_route
          uri: lb://gulimall-ware
          predicates:
            - Path=/api/ware/**
          filters:
            - RewritePath=/api/(?<segment>.*),/$\{segment}

image.gif

3、配置后测试仓库维护

image.gif

4、实现仓库模糊查询功能

点击查询,查看url

http://localhost:88/api/ware/wareinfo/list?t=1633696575331&page=1&limit=10&key=

image.gif

WareInfoController.java

@RequestMapping("/list")
    //@RequiresPermissions("ware:wareinfo:list")
    public R list(@RequestParam Map<String, Object> params){
        PageUtils page = wareInfoService.queryPageByCondition(params);
        return R.ok().put("page", page);
    }

image.gif

WareInfoServiceImpl.java

@Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        QueryWrapper<WareInfoEntity> wrapper = new QueryWrapper<>();
        String key = (String) params.get("key");
        if (!StringUtils.isNullOrEmpty(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);
    }

image.gif

设置日志输出级别,方便查看sql语句

logging:
  level:
    com.xmh: debug

image.gif

测试成功

image.gif

3、查询库存的模糊查询

1、库存系统02,url:/ware/waresku/list

2、实现库存模糊查询功能,WareSkuServiceImpl.java

@Override
    public PageUtils queryPage(Map<String, Object> params) {
        QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<>();
        String wareId = (String) params.get("wareId");
        if (!StringUtils.isNullOrEmpty(wareId)){
            wrapper.eq("ware_id", wareId);
        }
        String skuId = (String) params.get("skuId");
        if (!StringUtils.isNullOrEmpty(skuId)){
            wrapper.eq("sku_id", skuId);
        }
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                wrapper
        );
        return new PageUtils(page);
    }

image.gif

4、采购需求的模糊查询

1、库存系统03,url:/ware/purchasedetail/list

2、PurchaseDetailServiceImpl.java

@Override
    public PageUtils queryPage(Map<String, Object> params) {
        QueryWrapper<PurchaseDetailEntity> wrapper = new QueryWrapper<>();
        String key  = (String) params.get("key");
        if (!StringUtils.isNullOrEmpty(key)){
            wrapper.and(w -> {
               w.eq("sku_id", key).or().eq("purchase_id", key);
            });
        }
        String status  = (String) params.get("status");
        if (!StringUtils.isNullOrEmpty(status)){
            wrapper.eq("status", status);
        }
        String wareId  = (String) params.get("wareId");
        if (!StringUtils.isNullOrEmpty(wareId)){
            wrapper.eq("ware_id", wareId);
        }
        IPage<PurchaseDetailEntity> page = this.page(
                new Query<PurchaseDetailEntity>().getPage(params),
                wrapper
        );
        return new PageUtils(page);
    }

image.gif

5、合并采购流程

1、采购逻辑,新建采购需求后还要可以提供合并采购单,比如一个仓库的东西可以合并到一起,让采购人员一趟采购完

image.gif

新建采购需求后还要可以提供合并采购单,比如一个仓库的东西可以合并到一起,让采购人员一趟采购完

image.gif

新建采购单,可以在采购单后面分配给员工,员工可以在系统管理->管理员列表中新建

image.gif

6、查询未领取的采购单

1、库存系统05、url:/ware/purchase/unreceive/list, 查询未领取的采购单

image.gif

2、PurchaseController.java

@RequestMapping("/unreceive/list")
    //@RequiresPermissions("ware:purchase:list")
    public R unreceiveList(@RequestParam Map<String, Object> params){
        PageUtils page = purchaseService.queryPageUnreceive(params);
        return R.ok().put("page", page);
    }

image.gif

3、新建常量枚举类constant.WareConstant

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;
        }
    }
}

image.gif

4、queryPageUnreceive.java

@Override
    public PageUtils queryPageUnreceive(Map<String, Object> params) {
        QueryWrapper<PurchaseEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("status", WareConstant.PurchaseStatusEnum.CREATED.getCode()).or().eq("status", WareConstant.PurchaseStatusEnum.ASSIGNED.getCode());
        IPage<PurchaseEntity> page = this.page(
                new Query<PurchaseEntity>().getPage(params),
                wrapper
        );
        return new PageUtils(page);
    }

image.gif

5、测试成功

image.gif

7、合并采购需求

1、库存系统04,url:/ware/purchase/merge

选择要合并的采购需求,然后合并到整单

image.gif

如果不选择整单id,则自动创建新的采购单

image.gif

2、新建MergerVo.java

@Data
public class MergerVo {
    private Long purchaseId; //整单id
    private List<Long> items; //合并项集合
}

image.gif

3、分配,就是修改【采购需求】里对应的【采购单id、采购需求状态】,即purchase_detail表

并且不能重复分配采购需求给不同的采购单,如果还没去采购,或者采购失败,就可以修改

PurchaseController.java

@PostMapping("/merge")
    //@RequiresPermissions("ware:purchase:list")
    public R merge(@RequestBody MergeVo mergeVo){
        purchaseService.mergePurchase(mergeVo);
        return R.ok();
    }

image.gif

PurchaseServiceImpl.java

@Autowired
    private PurchaseDetailService detailService;
  @Transactional
    @Override
    public void mergePurchase(MergeVo mergeVo) {
        Long purchaseId = mergeVo.getPurchaseId();
        // 如果采购id为null 说明没选采购单
        if (purchaseId == null){
            //新建采购单
            PurchaseEntity purchaseEntity = new PurchaseEntity();
            purchaseEntity.setStatus(WareConstant.PurchaseStatusEnum.CREATED.getCode());
            this.save(purchaseEntity);
            purchaseId = purchaseEntity.getId();
        }
        //合并采购需求
        List<Long> items = mergeVo.getItems();
        Long finalPurchaseId = purchaseId;
        List<PurchaseDetailEntity> list = detailService.getBaseMapper().selectBatchIds(items).stream().filter(entity -> {
            //如果还没去采购,或者采购失败,就可以修改
            return entity.getStatus() < WareConstant.PurchaseDetailStatusEnum.BUYING.getCode()
                    || entity.getStatus() == WareConstant.PurchaseDetailStatusEnum.HASERROR.getCode();
        }).map(entity -> {
            //修改状态,以及采购单id
            entity.setStatus(WareConstant.PurchaseDetailStatusEnum.ASSIGNED.getCode());
            entity.setPurchaseId(finalPurchaseId);
            return entity;
        }).collect(Collectors.toList());
        detailService.updateBatchById(list);
    }

image.gif

对采购单的创建时间、更新时间进行自动填充

PurchaseEntity中添加注解

/**
   * 创建日期
   */
  @TableField(fill = FieldFill.INSERT)
  private Date createTime;
  /**
   * 更新日期
   */
  @TableField(fill = FieldFill.INSERT_UPDATE)
  private Date updateTime;

image.gif

新建MyMetaObjectHandler对注解进行处理

@Slf4j
@Component // 一定不要忘记把处理器加到IOC容器中!
public class MyMetaObjectHandler implements MetaObjectHandler {
    // 插入时的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill.....");
        // setFieldValByName(String fieldName, Object fieldVal, MetaObject
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
    // 更新时的填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill.....");
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

image.gif

在配置文件中对时间json进行格式化

jackson:
    date-format: yyyy-MM-dd HH:mm:ss

image.gif

测试成功

image.gif

image.gif

8、领取采购单

采购单分配给了采购人员,采购人员在手机端领取采购单,此时的采购单应该为新建已分配状态,在采购人员领取后采购单的状态变为已领取采购需求的状态变为正在采购

1、库存系统06、url:/ware/purchase/received

2、PurchaseController.java

/**
     * 领取采购单/ware/purchase/received
     */
    @PostMapping("/received")
    //@RequiresPermissions("ware:purchase:list")
    public R received(@RequestBody List<Long> ids){
        purchaseService.received(ids);
        return R.ok();
    }

image.gif

3、PurchaseServiceImpl.java

@Transactional
    @Override
    public void received(List<Long> ids) {
        // 没有采购需求直接返回,否则会破坏采购单
        if (ids == null || ids.size() == 0) {
            return;
        }
        List<PurchaseEntity> list = this.getBaseMapper().selectBatchIds(ids).stream().filter(entity -> {
            //确保采购单的状态是新建或者已分配
            return entity.getStatus() <= WareConstant.PurchaseStatusEnum.ASSIGNED.getCode();
        }).map(entity -> {
            //修改采购单的状态为已领取
            entity.setStatus(WareConstant.PurchaseStatusEnum.RECEIVE.getCode());
            return entity;
        }).collect(Collectors.toList());
        this.updateBatchById(list);
        //修改该采购单下的所有采购需求的状态为正在采购
        UpdateWrapper<PurchaseDetailEntity> updateWrapper = new UpdateWrapper<>();
        updateWrapper.in("purchase_id", ids);
        PurchaseDetailEntity purchaseDetailEntity = new PurchaseDetailEntity();
        purchaseDetailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.BUYING.getCode());
        detailService.update(purchaseDetailEntity, updateWrapper);
    }

image.gif

4、用idea自带的HTTP Client发送post请求,模拟采购人员领取采购单,进行测试

POST http://localhost:88/api//ware/purchase/received
Content-Type: application/json
[3]

image.gif

5、测试成功

image.gif

image.gif

image.gif

9、完成采购

完成采购的步骤:

  • 判断所有采购需求的状态,采购需求全部完成时,采购单状态才为完成
  • 采购项完成的时候,增加库存(调用远程获取skuName)
  • 加上分页插件

1、库存系统07,url:/ware/purchase/done

2、新建PurchaseItemDoneVo,PurchaseDoneVo

@Data
public class PurchaseItemDoneVo {
    private Long itemId;
    private Integer status;
    private String reason;
}

image.gif

@Data
public class PurchaseDoneVo {
    private Long id;
    private List<PurchaseItemDoneVo> items;
}

image.gif

3、PurchaseController.java

/**
 * 完成采购
 */
@PostMapping("/done")
//@RequiresPermissions("ware:purchase:list")
public R received(@RequestBody PurchaseDoneVo vo){
    purchaseService.done(vo);
    return R.ok();
}

image.gif

4、PurchaseServiceImpl.java

@Autowired
    private WareSkuService wareSkuService;
    @Autowired
    private ProductFeignService productFeignService;
@Override
public void done(PurchaseDoneVo vo) {
    //1、根据前端发过来的信息,更新采购需求的状态
    List<PurchaseItemDoneVo> items = vo.getItems();
    List<PurchaseDetailEntity> updateList = new ArrayList<>();
    boolean flag = true;
    for (PurchaseItemDoneVo item : items){
        Long detailId = item.getItemId();
        PurchaseDetailEntity detailEntity = detailService.getById(detailId);
        detailEntity.setStatus(item.getStatus());
        //采购需求失败
        if (item.getStatus() == WareConstant.PurchaseDetailStatusEnum.HASERROR.getCode()){
            flag = false;
        }else {
            //3、根据采购需求的状态,更新库存
            // sku_id, sku_num, ware_id
            // sku_id, ware_id, stock sku_name(调用远程服务获取), stock_locked(先获取已经有的库存,再加上新购买的数量)
            String skuName = "";
            try {
                R info = productFeignService.info(detailEntity.getSkuId());
                if(info.getCode() == 0){
                    Map<String,Object> data=(Map<String,Object>)info.get("skuInfo");
                    skuName = (String) data.get("skuName");
                }
            } catch (Exception e) {
            }
            //更新库存
            wareSkuService.addStock(detailEntity.getSkuId(), detailEntity.getWareId(), skuName, detailEntity.getSkuNum());
        }
        updateList.add(detailEntity);
    }
    //保存采购需求
    detailService.updateBatchById(updateList);
    //2、根据采购需求的状态,更新采购单的状态
    PurchaseEntity purchaseEntity = new PurchaseEntity();
    purchaseEntity.setId(vo.getId());
    purchaseEntity.setStatus(flag ? WareConstant.PurchaseStatusEnum.FINISH.getCode() : WareConstant.PurchaseStatusEnum.HASERROR.getCode());
    this.updateById(purchaseEntity);
}

image.gif

5、新建feign.ProductFeignService接口,用来远程获取skuName

ProductFeignService.java

@FeignClient("gulimall-product")
public interface ProductFeignService {
    @RequestMapping("/product/skuinfo/info/{skuId}")
    R info(@PathVariable("skuId") Long skuId);
}

image.gif

6、主启动类加上注解@EnableFeignClients

7、WareSkuServiceImpl.java 实现入库操作

@Override
    public void addStock(Long skuId, Long wareId, String skuName, Integer skuNum) {
        WareSkuEntity wareSkuEntity = this.baseMapper.selectOne(new QueryWrapper<WareSkuEntity>().eq("sku_id", skuId).eq("ware_id", wareId));
        if (wareSkuEntity == null){
            //新增
            wareSkuEntity = new WareSkuEntity();
            wareSkuEntity.setStock(skuNum);
        }else {
            wareSkuEntity.setStock(wareSkuEntity.getStock() + skuNum);
        }
        wareSkuEntity.setSkuName(skuName);
        wareSkuEntity.setWareId(wareId);
        wareSkuEntity.setSkuId(skuId);
        this.saveOrUpdate(wareSkuEntity);
    }

image.gif

8、添加分页插件,复制product服务中的即可

9、测试

POST http://localhost:88/api/ware/purchase/done
Content-Type: application/json
{
  "id": 7,
  "items": [
    {"itemId":6,"status":3,"reason":"完成"},
    {"itemId":7,"status":3,"reason":"完成"}
  ]
}

image.gif

测试成功

image.gif

image.gif

image.gif

10、获取spu规格

1、商品系统22、url:/product/attr/base/listforspu/{spuId}

2、AttrController.java

@Autowired
private ProductAttrValueService productAttrValueService;
@GetMapping("/base/listforspu/{spuId}")
public R baseListforspu(@PathVariable("spuId") Long spuId){
    List<ProductAttrValueEntity> entityList = productAttrValueService.baseAttrlistForSpu(spuId);
    return R.ok().put("data", entityList);
}

image.gif

3、ProductAttrValueServiceImpl.java

@Override
public List<ProductAttrValueEntity> baseAttrlistForSpu(Long spuId) {
    List<ProductAttrValueEntity> entities = this.baseMapper.selectList(new QueryWrapper<ProductAttrValueEntity>().eq("spu_id", spuId));
    return entities;
}

image.gif

测试,点击规格

image.gif

如果此时出现400页面,向gulimall_admin中的sys_menu表中添加一条数据即可

image.gif

11、修改商品规格

1、商品系统23,url:/product/attr/update/{spuId}

2、AttrController.java

@PostMapping("/update/{spuId}")
public R updateSpuAttr(@PathVariable("spuId") Long spuId, @RequestBody List<ProductAttrValueEntity> entities){
    productAttrValueService.updateSpuAttr(spuId, entities);
    return R.ok();
}

image.gif

3、ProductAttrValueServiceImpl.java

因为修改的时候,有新增有修改有删除。 所以就先把spuId对应的所有属性都删了,再新增

@Override
    public void updateSpuAttr(Long spuId, List<ProductAttrValueEntity> entities) {
        //1、删除这个spuId对应的所有属性
        this.baseMapper.delete(new QueryWrapper<ProductAttrValueEntity>().eq("spu_id", spuId));
        //2、新增回去
        for (ProductAttrValueEntity entity : entities){
            entity.setSpuId(spuId);
        }
        this.saveBatch(entities);
    }

image.gif

 

相关文章
|
6月前
|
安全 JavaScript 前端开发
多商户商城/多商家入驻系统开发指南教程/稳定版/功能需求/项目源码
Developing a multi merchant mall/multi merchant entry system involves multiple modules such as user management, merchant management, product management, and order management. Here is a simple development guide tutorial to help you build such a system
|
2月前
|
Java 数据库 Maven
谷粒商城笔记+踩坑(1)——架构、项目环境搭建、代码生成器
项目介绍、项目环境搭建、docker配置mysql,redis,jdk,maven、人人开源、快速开发、安装nodejs、逆向工程搭建,人人开源代码生成器
谷粒商城笔记+踩坑(1)——架构、项目环境搭建、代码生成器
|
2月前
|
存储 缓存 Java
谷粒商城笔记+踩坑汇总篇
环境的搭建、商品服务-三级分类、品牌服务、阿里云云存储+JSR303数字校验+统一异常处理、spu+sku、分页拦截器、商品服务、仓库服务、Nginx反向代理,thymeleaf+动态展示三级分类、缓存与分布式锁,Redisson+缓存数据一致性、ElasticSearch检索服务、异步和线程池、商品详情搭建+异步编排、认证服务、阿里云短信+验证码防刷+BCrypt加密、用户名密码登录+微博社交登录+SpringSession+xxl-sso单点登录、购物车、订单服务、幂等性、库存自动解锁。MQ延迟队列
谷粒商城笔记+踩坑汇总篇
|
2月前
|
存储 NoSQL 前端开发
谷粒商城笔记+踩坑(18)——购物车
业务流程:在执行目标方法之前,检测cookie里的userKey,如果没有则新建用户传输对象,userKey设为随机uuid将用户传输对象封装进ThreadLocal。在执行目标方法之后,创建cookie并,设置作用域和过期时间,让浏览器保存购物车模块/*** @Description: 在执行目标方法之前,判断用户的登录状态.并封装传递给controller目标请求**///创建ThreadLocal对象,同一个线程共享数据/**** 目标方法执行之前*/
谷粒商城笔记+踩坑(18)——购物车
|
2月前
|
存储 前端开发 Java
谷粒商城笔记+踩坑(19)——订单模块构建、登录拦截器
首先搭建页面环境,然后介绍整合Spring Session的相关内容,并将用户信息放到session里,多线程优化,完成订单模块的功能、登录拦截等功能的实现
谷粒商城笔记+踩坑(19)——订单模块构建、登录拦截器
|
2月前
|
SQL 前端开发 Java
谷粒商城笔记+踩坑(15)——商品详情搭建+异步编排
查询 pms_spu_info_desc@Autowired// 4、获取 spu 的介绍 pms_spu_info_desc获取线程池的属性值这里直接调用与配置文件相对应的属性配置类@Bean。
谷粒商城笔记+踩坑(15)——商品详情搭建+异步编排
|
3月前
|
运维 架构师 微服务
谷粒商城:如何通过笔记复盘实现事半功倍?
该博客文章讨论了如何通过笔记复盘来提高学习和工作效率。
谷粒商城:如何通过笔记复盘实现事半功倍?
|
6月前
毕业设计|springboot+h5的购物商城系统(二)
毕业设计|springboot+h5的购物商城系统
|
6月前
|
关系型数据库 MySQL 开发工具
谷粒商城--环境部署(2022/7/28最新)
谷粒商城--环境部署(2022/7/28最新)
164 0
谷粒商城--环境部署(2022/7/28最新)
|
6月前
|
前端开发 NoSQL Java
毕业设计|springboot+h5的购物商城系统(一)
毕业设计|springboot+h5的购物商城系统
162 2