十四、仓储服务&仓库管理
上一级页面:index-la
十四、仓储服务&仓库管理
14.1 整合ware服务&获取仓库列表
14.1.1整合 ware 服务
1、首先服务需要先注册到 Nacos 中,需要自己配置文件 配置对应的 nacos注册地址,
2、启动类需要开启 服务注册发现,开启远程服务调用
@EnableFeignClients // 开启openfeign 远程服务调用
@EnableTransactionManagement //开启事务
@MapperScan("com.atguigu.gulimall.ware.dao") //mapper包扫描
@EnableDiscoveryClient //服务注册发现
14.1.2 获取仓库列表
具体需求:
根据参数名查询出 仓库相关的记录 ,具体对于操作的是wms_ware_info
表
Controller
/**
* 列表
*/
@RequestMapping("/list")
//@RequiresPermissions("ware:wareinfo:list")
public R list(@RequestParam Map<String, Object> params){
PageUtils page = wareInfoService.queryPage(params);
return R.ok().put("page", page);
}
Service
@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)
.eq("address",key)
.eq("areacode",key);
}
IPage<WareInfoEntity> page = this.page(
new Query<WareInfoEntity>().getPage(params),
wrapper
);
return new PageUtils(page);
}
总结业务流程
仓库维护对应的是 wms_ware_info
根据前端传递过来的参数进行拼接然后进行查询
14.2 查询库存&创建采购需求
14.2.1 查询库存
具体需求:
根据 仓库、skuId 进行查询对应的表是 wms_ware_sku
Controller
/**
* 列表
*/
@RequestMapping("/list")
//@RequiresPermissions("ware:waresku:list")
public R list(@RequestParam Map<String, Object> params){
PageUtils page = wareSkuService.queryPage(params);
return R.ok().put("page", page);
}
Service
@Override
public PageUtils queryPage(Map<String, Object> params) {
QueryWrapper<WareSkuEntity> queryWrapper = new QueryWrapper<>();
// 取出请求的参数 组装条件进行查询
String skuId = (String) params.get("skuId");
if (!StringUtils.isEmpty(skuId)) {
queryWrapper.eq("sku_id",skuId);
}
String wareId = (String) params.get("wareId");
if (!StringUtils.isEmpty(wareId)) {
queryWrapper.eq("ware_id",wareId);
}
IPage<WareSkuEntity> page = this.page(
new Query<WareSkuEntity>().getPage(params),
queryWrapper
);
return new PageUtils(page);
}
总结业务流程:
wms_ware_sku
主要的操作的就是该表 一样的封装条件,然后进行查询
14.2.2 创建采购需求
具体需求:
选择 仓库、状态、 以及其他关键字 查询出对应的数据 那么查询的是哪张表? wms_purchase_detail
Controller
如往常一样 调用 Service
返回结果 组装 返回~~~
/**
* 列表
*/
@RequestMapping("/list")
//@RequiresPermissions("ware:purchasedetail:list")
public R list(@RequestParam Map<String, Object> params){
PageUtils page = purchaseDetailService.queryPage(params);
return R.ok().put("page", page);
}
Service
/**
* // status: 0,//状态
* // wareId: 1,//仓库id
* @param params
* @return
*/
@Override
public PageUtils queryPage(Map<String, Object> params) {
QueryWrapper<PurchaseDetailEntity> wrapper = new QueryWrapper<>();
// 取出key
String key = (String) params.get("key");
// key 主要查询条件
if (!StringUtils.isEmpty(key)) {
wrapper.and((w) ->{
w.eq("purchase_id",key).or().eq("sku_id",key);
});
}
String status = (String) params.get("status");
if (!StringUtils.isEmpty(status)) {
wrapper.and((w) ->{
w.eq("status",status);
});
}
String wareId = (String) params.get("wareId");
if (!StringUtils.isEmpty(wareId)) {
wrapper.and((w) ->{
w.eq("ware_id",wareId);
});
}
IPage<PurchaseDetailEntity> page = this.page(
new Query<PurchaseDetailEntity>().getPage(params),
wrapper
);
return new PageUtils(page);
}
总结业务流程:
对 wms_purchase_detail
表进行操作 拼装条件 查询 嗯 就这样~~~
14.3 合并采购需求&领取采购单&完成采购&Spu规格维护
14.3.1 合并采购需求
具体需求:
选中 点击批量操作
请求参数分享
{
purchaseId: 1, //整单id
items:[1,2,3,4] //合并项集合
}
那就建立对应的 Vo 用来接收请求参数
Controller
/**
* 合并采购
* @param mergeVo
* @return
*/
///ware/purchase/merge
@PostMapping("/merge")
public R merge(@RequestBody MergeVo mergeVo) {
purchaseService.mrgePurchase(mergeVo);
return R.ok();
}
Service
/**
* 合并采购需求
* @param mergeVo
*/
@Transactional
@Override
public void mrgePurchase(MergeVo mergeVo) {
// 拿到采购单id
Long purchaseId = mergeVo.getPurchaseId();
// 采购单 id为空 新建
if (purchaseId == null ) {
PurchaseEntity purchaseEntity = new PurchaseEntity();
// 状态设置为新建
purchaseEntity.setStatus(WareConstant.PurchaseStatusEnum.CREATED.getCode());
purchaseEntity.setCreateTime(new Date());
purchaseEntity.setUpdateTime(new Date());
this.save(purchaseEntity);
// 拿到最新的采购单id
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();
// 通过采购单id 查询到 采购信息对象
PurchaseEntity byId = this.getById(finalPurchaseId);
// 状态如果是正在采购
if (! (byId.getStatus() == WareConstant.PurchaseDetailStatusEnum.BUYING.getCode())) {
// 设置为已分配
detailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.HASERROR.getCode());
}
detailEntity.setId(i);
// 设置采购单id
detailEntity.setPurchaseId(finalPurchaseId);
return detailEntity;
}).collect(Collectors.toList());
// id批量更新
purchaseDetailService.updateBatchById(collect);
// 再次合并的话 更新修改时间
PurchaseEntity purchaseEntity = new PurchaseEntity();
purchaseEntity.setId(purchaseId);
purchaseEntity.setUpdateTime(new Date());
this.updateById(purchaseEntity);
}
总结业务流程:
- 从 参数 mergeVo中取出 purchaseId 和 items 进行相关操作
- 主要是用来操作两张表
wms_purchase
和wms_purchase_detail
wms_purchase
表是 采购信息wms_purchase_detail
表是 采购需求- 我的理解是将
wms_purchase
的id插入到wms_purchase_detail
表中 也就是 purchase_id 字段,中间通过这个字段关联起来,同时wms_purchase
表对 status 状态有比较多的选择,视频里面也是定义了两个常量
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 void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = 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 void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
}
将常量抽取出来,修改更加方便
14.3.2 领取采购单
具体需求:
合并采购需求成功后,具体这个功能有啥用啊? 你总得需要有人去采购吧? 所以就会有一个采购APP 工作人员点击采购,然后就去采购,这里就没有实现采购 APP 就用接口来实现,通过 JSON 的参数 来请求
Controller
/**
*
* @param ids
* @return
*/
@PostMapping("/received")
public R received(@RequestBody List<Long> ids) {
purchaseService.received(ids);
return R.ok();
}
Service
@Override
public void received(List<Long> ids) {
// 1、确认当前采购单是 新建或者 已分配状态 才能进行采购
List<PurchaseEntity> collect = ids.stream().map(id -> {
// 根据采购id查询出采购信息
PurchaseEntity byId = this.getById(id);
return byId;
}).filter(item -> {
// 新建或者已分配留下
if (item.getStatus() == WareConstant.PurchaseStatusEnum.CREATED.getCode() ||
item.getStatus() == WareConstant.PurchaseStatusEnum.ASSIGNED.getCode()) {
return true;
}
return false;
}).map(item -> {
// 设置为已领取
item.setStatus(WareConstant.PurchaseStatusEnum.RECEIVE.getCode());
item.setUpdateTime(new Date());
return item;
}).collect(Collectors.toList());
// 2、改变采购单状态
this.updateBatchById(collect);
// 3、改变采购项的状态
collect.forEach((item) -> {
// 根据 purchase_id 查询出采购需求
List<PurchaseDetailEntity> entities = purchaseDetailService.listDetailByPurchaseId(item.getId());
//
List<PurchaseDetailEntity> detailEntites = entities.stream().map(entity -> {
PurchaseDetailEntity detailEntity = new PurchaseDetailEntity();
detailEntity.setId(entity.getId());
// 设置状态正在采购
detailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.BUYING.getCode());
return detailEntity;
}).collect(Collectors.toList());
// id批量更新
purchaseDetailService.updateBatchById(detailEntites);
});
}
总结业务流程:
业务分析
- 采购人员通过 APP 点击采购 完成对应的采购需求,这里使用的是 PostMan 来发送请求,发送请求 带的参数是什么? 参数就是 采购Id
- 通过采购 Id 查询出采购相关信息,然后设置采购表的状态,设置成采购成功,同时通过这个 id 在
wms_purchase_detail
表中 对应的是 purchase_id 查询采购需求表的数据, 查询到后将他的状态设置成 “正在采购“
14.3.3 完成采购
具体需求:
采购人员参与采购后,采购就会有他的结果,采购成功、采购失败,
有了请求参数,如果比较多,那么底考虑设计一个 VO 哦
@PostMapping("/done")
public R finish(@RequestBody PurchaseDoneVo doneVo) {
purchaseService.done(doneVo);
return R.ok();
}
Vo
@Data
public class PurchaseDoneVo {
/**
* 采购单id
*/
@NotNull
private Long id;
public List<PurchaseItemDoneVo> items;
}
@Data
public class PurchaseItemDoneVo {
/**
* 完成/失败的需求详情
*/
private Long itemId;
/**
* 状态
*/
private Integer status;
private String reason;
}
Service
@Transactional
@Override
public void done(PurchaseDoneVo doneVo) {
// 采购单id
Long id = doneVo.getId();
// 2、改变采购项目的状态
Boolean flag = true;
List<PurchaseItemDoneVo> items = doneVo.getItems();
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 {
// 3、将成功采购的进行入库
PurchaseDetailEntity entity = purchaseDetailService.getById(item.getItemId());
wareSkuService.addStock(entity.getSkuId(),entity.getWareId(),entity.getSkuNum());
detailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.FINISH.getCode());
}
detailEntity.setId(item.getItemId());
updates.add(detailEntity);
}
// 批量更新
purchaseDetailService.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);
}
addStock方法
@Override
public void addStock(Long skuId, Long wareId, Integer skuNum) {
// 先根据 skuId 和 ware_id 查询 是否拥有这个用户
List<WareSkuEntity> wareSkuEntities = wareSkuDao.selectList(new QueryWrapper<WareSkuEntity>().eq("sku_id", skuId).eq("ware_id", wareId));
//没有这个用户 那就新增
if(wareSkuEntities == null || wareSkuEntities.size() == 0) {
WareSkuEntity wareSkuEntity = new WareSkuEntity();
// 根据属性值设置
wareSkuEntity.setSkuId(skuId);
wareSkuEntity.setStock(skuNum);
wareSkuEntity.setWareId(wareId);
wareSkuEntity.setStockLocked(0);
// TODO 远程查询sku的名字 如果失败整个事务不需要回滚
try {
// 远程调用 根据 skuid进行查询
R info = productFeignService.info(skuId);
Map<String,Object> map = (Map<String, Object>) info.get("skuInfo");
if (info.getCode() == 0) {
wareSkuEntity.setSkuName((String) map.get("skuName"));
}
} catch (Exception e) {
e.printStackTrace();
}
wareSkuDao.insert(wareSkuEntity);
}else {
// 有该记录那就进行更新
wareSkuDao.addStock(skuId,wareId,skuNum);
}
}
addStock 具体实现
<insert id="addStock">
UPDATE `wms_ware_sku` SET stock=stock+#{skuNum} WHERE sku_id=#{skuId} AND ware_id=#{wareId}
</insert>
14.3.4 Spu规格维护
具体需求:
前端项目遇到的问题: 需要自己去 router目录下找到 index.js 增加改行配置,主要是配置规格维护的路径
在 Spu管理上 点击规格后查询出相关规格信息
Controller
@GetMapping("/base/listforspu/{spuId}")
public R baseAttrListforspu(@PathVariable("spuId") Long spuId) {
List<ProductAttrValueEntity> productAttrValueEntity = productAttrValueService.baseAttrListforspu(spuId);
return R.ok().put("data",productAttrValueEntity);
}
Service
@Override
public List<ProductAttrValueEntity> baseAttrListforspu(Long spuId) {
// 1、根据spuid进行查询
List<ProductAttrValueEntity> attrValueEntities = this.baseMapper.selectList(new QueryWrapper<ProductAttrValueEntity>().eq("spu_id", spuId));
return attrValueEntities;
}
总结业务流程:
单表操作,根据 spu_id 查询出 pms_product_attr_value
表的信息
14.3.5 Spu更新操作
具体需求:
根据spu_id 查询出规格信息后 ,修改对应信息 提交后会发送一个post请求,并同时带上请求参数
[{
"attrId": 7,
"attrName": "入网型号",
"attrValue": "LIO-AL00",
"quickShow": 1
}, {
"attrId": 14,
"attrName": "机身材质工艺",
"attrValue": "玻璃",
"quickShow": 0
}, {
"attrId": 16,
"attrName": "CPU型号",
"attrValue": "HUAWEI Kirin 980",
"quickShow": 1
}]
刚好这四个参数和实体类的一致,就不需要创建 Vo来接收
Controller
@RequestMapping("/update/{spuId}")
//@RequiresPermissions("product:attr:update")
public R updateSpuAttr(@PathVariable("spuId") Long spuId,
@RequestBody List<ProductAttrValueEntity> productAttrValueEntityList){
productAttrValueService.updateSpuAttr(spuId,productAttrValueEntityList);
return R.ok();
}
Service
/**
* 先删除 后更新
* @param spuId
* @param productAttrValueEntityList
*/
@Override
public void updateSpuAttr(Long spuId, List<ProductAttrValueEntity> productAttrValueEntityList) {
// 1、根据spuid删除记录
this.baseMapper.delete(new QueryWrapper<ProductAttrValueEntity>().eq("spu_id",spuId));
// 2、遍历传递过来的记录 设置 spuId
List<ProductAttrValueEntity> collect = productAttrValueEntityList.stream().map(item -> {
item.setSpuId(spuId);
return item;
}).collect(Collectors.toList());
// 3、批量保存
this.saveBatch(collect);
}
总结业务流程:
- 更新操作,根据前端传递过来的参数来进行更新,前端传递了一个
spu_id
和多个 spu属性值 一个spu_id
对多个 spu 属性值 - 先根据
spu_id
删除存在 pms_product_attr_value 表的记录 - 然后对多个 ProductAttrValueEntity 对象设置 sup_id ,最后进行批量保存