1.仓储服务开发配置
1.1.加入到Nacos注册中心
spring:
application:
name: gmall-ware
cloud:
nacos:
discovery:
server-addr: 192.168.139.10:8848
namespace: 36854647-e68c-409b-9233-708a2d41702c
1.2.配置网关路由
spring:
cloud:
gateway:
routes:
- id: ware_route
uri: lb://gmall-ware
predicates:
- Path=/api/ware/**
filters:
- RewritePath=/api/(?<segment>.*), /$\{segment}
1.3.主启动类开启相关功能
package com.atguigu.gmall.ware;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class GmallWareApplication {
public static void main(String[] args) {
SpringApplication.run(GmallWareApplication.class, args);
}
}
1.4.MyBatisPlus分页插件配置
package com.atguigu.gmall.ware.config;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* MyBatisPlus 配置类 {@link MybatisPlusConfig}
* @author zhangwen
* @email: 1466787185@qq.com
*/
@Configuration
//开启事务
@EnableTransactionManagement
@MapperScan("com.atguigu.gmall.ware.dao")
public class MybatisPlusConfig {
/**
* 引入分页插件
* @return 分页插件拦截器实例
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求,默认false
paginationInterceptor.setOverflow(true);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
paginationInterceptor.setLimit(100);
// 开启 count 的 join 优化,只针对部分 left join
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
}
2.仓库维护CRUD
- 逆向工程已经实现了CRUD,只需要对查询进行修改
- 添加仓库信息
3.采购单维护
3.1.采购流程
- 创建采购需求
- 创建采购单
- 为采购单分配采购人员
- 领取采购单
- 完成采购单
- 商品入库
采购流程图如下:
3.2.采购需求
采购需求生成方式:
- 人工创建采购需求(人工)
- 库存预警自动创建采购需求(自动化)
3.2.1.采购需求-人工新增
3.2.2.采购需求-查询
GET /ware/purchasedetail/list
//请求参数
{
page: 1, // 当前页码
limit: 10, // 每页记录数
sidx: 'id', // 排序字段
order: 'asc/desc', // 排序方式
key: '华为', // 检索关键字
status: 0, // 状态
wareId: 1, // 仓库id
}
//响应数据
{
"msg": "success",
"code": 0,
"page": {
"totalCount": 0,
"pageSize": 10,
"totalPage": 0,
"currPage": 1,
"list": [{
"id": 2,
"purchaseId": 1,
"skuId": 1,
"skuNum": 2,
"skuPrice": 22.0000,
"wareId": 1,
"status": 1
}]
}
}
PurchaseDetailController
/**
* 采购需求列表
*/
@RequestMapping("/list")
public R list(@RequestParam Map<String, Object> params){
PageUtils page = purchaseDetailService.queryPage(params);
return R.ok().put("page", page);
}
PurchaseDetailServiceImpl
/**
* 采购需求列表查询
* @param params
* @return
*/
@Override
public PageUtils queryPage(Map<String, Object> params) {
QueryWrapper<PurchaseDetailEntity> queryWrapper = new QueryWrapper<>();
String key = (String) params.get("key");
if (!StringUtils.isEmpty(key)) {
queryWrapper.and(wrapper -> {
wrapper.eq("purchase_id", key).or().eq("sku_id", key);
});
}
String status = (String) params.get("status");
if (!StringUtils.isEmpty(status)) {
queryWrapper.eq("status", status);
}
String wareId = (String) params.get("wareId");
if (!StringUtils.isEmpty(wareId)) {
queryWrapper.eq("ware_id", wareId);
}
IPage<PurchaseDetailEntity> page = this.page(
new Query<PurchaseDetailEntity>().getPage(params),
queryWrapper
);
return new PageUtils(page);
}
3.2.3.合并采购单
合并采购单有两种方式
- 选择一个采购单
- 若没有选择一个采购单,系统自动创建一个新的采购单进行合并
3.2.4.查询未领取的采购单
采购单状态:
- CREATED(0, “新建”)
- ASSIGNED(1, “已分配”)
- RECEIVED(2, “已领取”)
- FINISHED(3, “已完成”)
- ERROR(4, “有异常”)
未领取的采购单:新建和已分配
GET /ware/purchase/unreceive/list
PurchaseController
/**
* 查询未领取的采购单
*/
@RequestMapping("/unreceive/list")
public R listUnReceive(@RequestParam Map<String, Object> params){
PageUtils page = purchaseService.queryPageUnReceivePurchase(params);
return R.ok().put("page", page);
}
PurchaseServiceImpl
/**
* 查询未领取的采购单
* @param params
* @return
*/
@Override
public PageUtils queryPageUnReceivePurchase(Map<String, Object> params) {
IPage<PurchaseEntity> page = this.page(
new Query<PurchaseEntity>().getPage(params),
new QueryWrapper<PurchaseEntity>()
.eq("status",
WareConstant.PurchaseStatusEnum.CREATED.getCode()).or()
.eq("status",
WareConstant.PurchaseStatusEnum.ASSIGNED.getCode())
);
return new PageUtils(page);
}
3.2.5.合并采购需求
POST /ware/purchase/merge
//请求参数
{
purchaseId: 1, // 整单id
items: [1,2,3] // 合并项集合
}
PurchaseController
/**
* 合并采购需求-采购单
* @return
*/
@PostMapping("/merge")
public R merge(@RequestBody MergeVO mergeVO) {
purchaseService.mergePurchase(mergeVO);
return R.ok();
}
purchaseServiceImpl
/**
* 合并采购需求-采购单
* @param mergeVO
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void mergePurchase(MergeVO mergeVO) {
Long purchaseId = mergeVO.getPurchaseId();
if (StringUtils.isEmpty(purchaseId)) {
// 新增
PurchaseEntity purchaseEntity = new PurchaseEntity();
purchaseEntity.setStatus(WareConstant.PurchaseStatusEnum.CREATED.getCode());
purchaseEntity.setCreateTime(new Date());
purchaseEntity.setUpdateTime(new Date());
this.save(purchaseEntity);
purchaseId = purchaseEntity.getId();
}
List<Long> items = mergeVO.getItems();
Long finalPurchaseId = purchaseId;
List<PurchaseDetailEntity> detailEntities = items.stream().map(item -> {
PurchaseDetailEntity purchaseDetailEntity = new PurchaseDetailEntity();
purchaseDetailEntity.setId(item);
purchaseDetailEntity.setPurchaseId(finalPurchaseId);
purchaseDetailEntity.setStatus(WareConstant.PurchaseDetailEnum.ASSIGNED.getCode());
return purchaseDetailEntity;
}).collect(Collectors.toList());
detailService.updateBatchById(detailEntities);
// 采购单更新时间
PurchaseEntity purchaseEntity = new PurchaseEntity();
purchaseEntity.setId(purchaseId);
purchaseEntity.setUpdateTime(new Date());
this.updateById(purchaseEntity);
}
4.采购单
菜单路径:库存系统 -> 采购单维护 -> 采购单
4.1.新建采购单-人工新增
4.2.查询采购单
4.3.分配采购人员
为采购单分配采购人员,采购人员从系统用户表中查询
4.4.领取采购单
4.4.1.API
POST /ware/purchase/received
//请求参数
[1,2,3,4] //采购单id
4.4.2.后台接口实现
PurchaseController
/**
* 领取采购单
* @param ids 采购单id集合
* @return
*/
@PostMapping("/received")
public R receive(@RequestBody List<Long> ids) {
purchaseService.receivePurchase(ids);
return R.ok();
}
PurchaseServiceImpl
/**
* 领取采购单
* @param ids 采购单id集合
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void receivePurchase(List<Long> ids) {
// 1.确认当前采购单是新建或已分配状态
List<PurchaseEntity> purchaseEntities = ids.stream().map(id -> {
PurchaseEntity purchaseEntity = this.getById(id);
return purchaseEntity;
}).filter(purchaseEntity -> {
if (purchaseEntity.getStatus() ==
WareConstant.PurchaseStatusEnum.CREATED.getCode() ||
purchaseEntity.getStatus() ==
WareConstant.PurchaseStatusEnum.ASSIGNED.getCode()) {
return true;
}
return false;
}).map(purchaseEntity -> {
// 设置采购单的状态为已领取
purchaseEntity.setStatus(WareConstant.PurchaseStatusEnum.RECEIVED.getCode());
purchaseEntity.setUpdateTime(new Date());
return purchaseEntity;
}).collect(Collectors.toList());
// 2.批量修改采购单的状态
this.updateBatchById(purchaseEntities);
// 3.修改采购项的状态
purchaseEntities.forEach(purchaseEntity -> {
// 根据采购单id获取采购项
List<PurchaseDetailEntity> detailEntities =
detailService.listDetailByPurchaseId(purchaseEntity.getId());
List<PurchaseDetailEntity> collect =
detailEntities.stream().map(detailEntity ->{
PurchaseDetailEntity entity = new PurchaseDetailEntity();
entity.setId(detailEntity.getId());
entity.setStatus(WareConstant.PurchaseDetailEnum.BUYING.getCode());
return entity;
}).collect(Collectors.toList());
// 批量修改采购项状态
detailService.updateBatchById(collect);
});
}
4.4.3.Postman模拟领取采购单
使用Postman发送领取采购单请求
POST /ware/purchase/received
//请求参数
[1,2,3,4] //采购单id
领取成功后,采购单状态更新为 已领取
采购需求状态更新为 正在采购
4.5.完成采购单
4.5.1.API
POST /ware/purchase/done
// 请求参数
{
"id":1, // 采购单id
// itemId 采购项id,status 采购状态,reason 采购情况说明
"items":[
{"itemId":1,"status":3,"reason":"完成"},
{"itemId":2,"status":3,"reason":"完成"},
{"itemId":3,"status":3,"reason":"完成"}
]
}
4.5.2.后台接口实现
PurchaseController
/**
* 完成采购单
* @param purchaseDoneVO
* @return
*/
@PostMapping("/done")
public R finished(@RequestBody PurchaseDoneVO purchaseDoneVO) {
purchaseService.done(purchaseDoneVO);
return R.ok();
}
PurchaseServiceImpl
/**
* 完成采购单
* @param purchaseDoneVO
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void done(PurchaseDoneVO purchaseDoneVO) {
// 1.修改采购项状态
List<PurchaseDetailEntity> updateList = new ArrayList<>();
boolean flag = true;
for (PurchaseItemDoneVO itemDoneVO : purchaseDoneVO.getItems()) {
PurchaseDetailEntity purchaseDetailEntity = new PurchaseDetailEntity();
if (itemDoneVO.getStatus() ==
WareConstant.PurchaseDetailEnum.FAILED.getCode()) {
flag = false;
purchaseDetailEntity.setStatus(itemDoneVO.getStatus());
} else {
purchaseDetailEntity.setStatus(WareConstant.PurchaseDetailEnum.FINISHED.getCode());
// 2.将成功采购的商品入库
PurchaseDetailEntity detailEntity =
detailService.getById(itemDoneVO.getItemId());
wareSkuService.addStock(detailEntity.getSkuId(),
detailEntity.getWareId(), detailEntity.getSkuNum());
}
purchaseDetailEntity.setId(itemDoneVO.getItemId());
updateList.add(purchaseDetailEntity);
}
detailService.updateBatchById(updateList);
// 3.修改采购单状态
PurchaseEntity purchaseEntity = new PurchaseEntity();
purchaseEntity.setId(purchaseDoneVO.getId());
purchaseEntity.setStatus(flag ?
WareConstant.PurchaseStatusEnum.FINISHED.getCode()
: WareConstant.PurchaseStatusEnum.ERROR.getCode());
purchaseEntity.setUpdateTime(new Date());
this.updateById(purchaseEntity);
}
4.5.3.Postman模拟完成采购单
使用Postman发送完成采购单请求
POST /ware/purchase/done
// 请求参数
{
"id":1, // 采购单id
"items": [
// itemId 采购项id,status 采购状态, reason 采购说明
{"itemId":1,"status":3,"reason":"完成"},
{"itemId":2,"status":3,"reason":"完成"}
]
}
完成采购单后
采购单状态更新为 已完成
采购商品状态更新为 已完成
商品库存更新
5.商品库存
5.1.入库方式
-
手动新增库存(不能直接新增,只能作为补偿手段)
-
采购入库(常规)
1、发起商品采购需求
2、创建采购单
3、采购人员领取采购单,进行商品采购(对接采购系统)
4、完成采购
5、商品入库
5.2.库存查询
5.2.1.API
GET /ware/waresku/list
// 请求参数
{
page: 1, // 当前页码
limit: 10, // 每页记录数
sidx: 'id', // 排序字段
order: 'asc/desc', // 排序方式
wareId: 123, // 仓库id
skuId: 123 // 商品id
}
//响应数据
{
"msg": "success",
"code": 0,
"page": {
"totalCount": 0,
"pageSize": 10,
"totalPage": 0,
"currPage": 1,
"list": [{
"id": 1,
"skuId": 1,
"wareId": 1,
"stock": 1,
"skuName": "dd",
"stockLocked": 1
}]
}
}
5.2.2.后台接口实现
WareSkuController
/**
* 商品库存查询
*/
@RequestMapping("/list")
public R list(@RequestParam Map<String, Object> params){
PageUtils page = wareSkuService.queryPage(params);
return R.ok().put("page", page);
}
WareSkuServiceImpl
/**
* 查询商品库存
* @param params
* @return
*/
@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(skuId)) {
queryWrapper.eq("ware_id", wareId);
}
IPage<WareSkuEntity> page = this.page(
new Query<WareSkuEntity>().getPage(params),
queryWrapper
);
return new PageUtils(page);
}
6.SPU规格维护
6.1.获取SPU规格
6.1.1.API
GET /product/attr/base/listforspu/{spuId}
//响应数据
{
"msg": "success",
"code": 0,
"data": [{
"id": 43,
"spuId": 11,
"attrId": 7,
"attrName": "入网型号",
"attrValue": "LIO-AL00",
"attrSort": null,
"quickShow": 1
}]
}
6.1.2.后台接口实现
AttrController
/**
* 获取SPU规格属性
* @param spuId
* @return
*/
@GetMapping("/base/listforspu/{spuId}")
public R listBaseAttrForSpu(@PathVariable("spuId") Long spuId) {
List<ProductAttrValueEntity> entities = productAttrValueService.listBaseAttrForSpu(spuId);
return R.ok().put("data", entities);
}
ProductAttrValueServiceImpl
/**
* 获取SPU规格属性
* @param spuId
* @return
*/
@Override
public List<ProductAttrValueEntity> listBaseAttrForSpu(Long spuId) {
List<ProductAttrValueEntity> attrValueEntities = this.list(
new QueryWrapper<ProductAttrValueEntity>().eq("spu_id", spuId));
return attrValueEntities;
}
6.2.修改SPU规格
6.2.1.API
POST /product/attr/update/{spuId}
// 请求参数
[{
"attrId": 7,
"attrName": "入网型号",
"attrValue": "LIO-AL00",
"quickShow": 1
}, {
"attrId": 14,
"attrName": "机身材质工艺",
"attrValue": "玻璃",
"quickShow": 0
}, {
"attrId": 16,
"attrName": "CPU型号",
"attrValue": "HUAWEI Kirin 980",
"quickShow": 1
}]
6.2.2.后台接口实现
AttrController
/**
* 修改SPU规格属性
* @param spuId
* @param entities
* @return
*/
@PostMapping("/update/{spuId}")
public R updateSpuAttr(@PathVariable("spuId") Long spuId, @RequestBody List<ProductAttrValueEntity> entities){
productAttrValueService.updateSpuAttr(spuId, entities);
return R.ok();
}
ProductAttrValueServiceImpl
/**
* 修改SPU规格属性
* @param spuId
* @param entities
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void updateSpuAttr(Long spuId, List<ProductAttrValueEntity> entities) {
// 删除spu之前对应的所有规格属性
this.remove(new QueryWrapper<ProductAttrValueEntity>().eq("spu_id",spuId));
//插入spu新的规格属性
List<ProductAttrValueEntity> ProductAttrValueEntities = entities.stream().map(entity -> {
entity.setSpuId(spuId);
return entity;
}).collect(Collectors.toList());
this.saveBatch(ProductAttrValueEntities);
}