电商项目10:商品管理、仓库管理
1、商品管理
1.1、spu检索
1.1.1、后端
SpuInfoController
/**
* 列表
*/
@RequestMapping("/list")
// @RequiresPermissions("product:spuinfo:list")
public R list(@RequestParam Map<String, Object> params){
PageUtils page = spuInfoService.queryPageCondition(params);
return R.ok().put("page", page);
}
SpuInfoService
PageUtils queryPageCondition(Map<String, Object> params);
SpuInfoServiceImpl
@Override
public PageUtils queryPageCondition(Map<String, Object> params) {
QueryWrapper<SpuInfoEntity> wrapper = new QueryWrapper<>();
// 关键字检索
Object key = params.get("key");
// 三级分类id
Object catalogId = params.get("catalogId");
// 品牌id
Object brandId = params.get("brandId");
// 状态 0-新建 1-上架 2-下架
Object status = params.get("status");
if (!StringUtils.isEmpty(key)){
wrapper.and((w) -> {
w.eq("id",key).or().like("spu_name",key);
});
}
if (!StringUtils.isEmpty(catalogId)){
wrapper.eq("catalog_id",catalogId);
}
if (!StringUtils.isEmpty(brandId)){
wrapper.eq("brand_id",brandId);
}
if (!StringUtils.isEmpty(status)){
wrapper.eq("publish_status",status);
}
IPage<SpuInfoEntity> page = this.page(
new Query<SpuInfoEntity>().getPage(params),
wrapper
);
return new PageUtils(page);
}
查询时创建时间不是年月日时分秒类型。可以在全局配置文件中配置:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
后端代码修改:
SpuInfoServiceImpl
if (!StringUtils.isEmpty(catalogId) && !"0".equals(catalogId)){
wrapper.eq("catalog_id",catalogId);
}
if (!StringUtils.isEmpty(brandId) && !"0".equals(brandId)){
wrapper.eq("brand_id",brandId);
}
1.1.2、前端
前端调用时出现第一次进入页面。搜索时输入框条件未置空,且为0.是因为业务规则,传0就查全部。后端需要改代码。
1.2、sku检索
1.2.1、后端
sku检索
SkuInfoController
/**
* 列表
*/
@RequestMapping("/list")
// @RequiresPermissions("product:skuinfo:list")
public R list(@RequestParam Map<String, Object> params){
PageUtils page = skuInfoService.queryPageByCondition(params);
return R.ok().put("page", page);
}
SkuInfoService
PageUtils queryPageByCondition(Map<String, Object> params);
SkuInfoServiceImpl
@Override
public PageUtils queryPageByCondition(Map<String, Object> params) {
QueryWrapper<SkuInfoEntity> wrapper = new QueryWrapper<>();
Object key = params.get("key");
Object catelogId = params.get("catelogId");
Object brandId = params.get("brandId");
Object min = params.get("min");
Object max = params.get("max");
if (!StringUtils.isEmpty(key)){
wrapper.and((w) -> {
w.eq("sku_id",key).or().like("sku_name",key);
});
}
if (!StringUtils.isEmpty(catelogId) && !"0".equals(catelogId)){
wrapper.eq("catalog_id",catelogId);
}
if (!StringUtils.isEmpty(brandId) && !"0".equals(brandId)){
wrapper.eq("brand_id",brandId);
}
if (!StringUtils.isEmpty(min)){
wrapper.ge("price",min);
}
if (!StringUtils.isEmpty(max)){
BigDecimal bigDecimal = new BigDecimal((String) max);
if (bigDecimal.compareTo(new BigDecimal("0")) > 0){
// 当价格区间的最大值大于0才去拼接
wrapper.le("price",max);
}
}
IPage<SkuInfoEntity> page = this.page(
new Query<SkuInfoEntity>().getPage(params),
wrapper
);
return new PageUtils(page);
}
1.3、查询spu规格
点击规格。会跑到404.页面。
解决方案如下:
spu管理规格404问题修复方案
注意和parent_id绑定,建议以菜单按钮新增方式
1.3.1、后端
AttrController
/**
* 获取spu规格
*/
@RequestMapping("/base/listforspu/{spuId}")
// @RequiresPermissions("product:attr:list")
public R getListForspu(@PathVariable Long spuId){
List<ProductAttrValueEntity> list = attrService.getListForspu(spuId);
return R.ok().put("data", list);
}
AttrService
List<ProductAttrValueEntity> getListForspu(Long spuId);
AttrServiceImpl
@Override
public List<ProductAttrValueEntity> getListForspu(Long spuId) {
return productAttrValueService.getBaseMapper().selectList(new QueryWrapper<ProductAttrValueEntity>().eq("spu_id",spuId));
}
1.3.2、前端
接口有返回数据。但前端未正常回显
解决方案如下:
前端+后端此接口修改方式
根据此文档修改以后
重新新增一个商品
可以正常回显了。但是多次点击又不能正常回显。
第二、第三次进来又为空
因为延迟加载问题。使用延迟函数即可修复此问题
1.4、修改spu规格
AttrController
/**
* 获取spu规格
*/
@PostMapping("/update/{spuId}")
// @RequiresPermissions("product:attr:list")
public R updateProductSpu(@PathVariable Long spuId,@RequestBody List<ProductAttrValueEntity> entityList){
attrService.updateProductSpu(spuId,entityList);
return R.ok();
}
AttrService
void updateProductSpu(Long spuId, List<ProductAttrValueEntity> entityList);
AttrServiceImpl
@Transactional
@Override
public void updateProductSpu(Long spuId, List<ProductAttrValueEntity> entityList) {
// 删除后新增
// 1、根据spuId删除spu属性值表
productAttrValueService.getBaseMapper().delete(new QueryWrapper<ProductAttrValueEntity>().eq("spu_id",spuId));
// 2、批量新增
entityList = entityList.stream().map(entity -> {
entity.setSpuId(spuId);
return entity;
}).collect(Collectors.toList());
productAttrValueService.saveBatch(entityList);
}
2、库存管理
2.1、启动ware后端微服务
application.yml
application:
name: gulimall-ware
GulimallWareApplication
@SpringBootApplication
@EnableDiscoveryClient
@EnableTransactionManagement
@MapperScan("com.ljs.gulimall.ware.dao")
public class GulimallWareApplication {
public static void main(String[] args) {
SpringApplication.run(GulimallWareApplication.class, args);
}
}
启动ware服务。登录nacos
代表已经注册成功
gulimall-gateway配置路由规则
application.yml
- id: ware_route
#负载均衡到member服务
uri: lb://gulimall-ware
predicates:
- Path=/api/ware/**
#网关重写
filters:
- RewritePath=/api/(?<segment>.*),/$\{segment}
2.2、仓库维护查询
仓库列表
WareInfoServiceImpl
@Override
public PageUtils queryPage(Map<String, Object> params) {
QueryWrapper<WareInfoEntity> wrapper = new QueryWrapper<>();
Object key = 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);
}
2.3、查询商品库存
查询商品库存
WareSkuServiceImpl
@Override
public PageUtils queryPage(Map<String, Object> params) {
QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<>();
Object skuId = params.get("skuId");
if (!StringUtils.isEmpty(skuId)){
wrapper.eq("sku_id",skuId);
}
Object wareId = params.get("wareId");
if (!StringUtils.isEmpty(wareId)){
wrapper.eq("ware_id",wareId);
}
IPage<WareSkuEntity> page = this.page(
new Query<WareSkuEntity>().getPage(params),
wrapper
);
return new PageUtils(page);
}
2.4、查询采购需求
PurchaseDetailServiceImpl
@Override
public PageUtils queryPage(Map<String, Object> params) {
QueryWrapper<PurchaseDetailEntity> wrapper = new QueryWrapper<>();
Object key = params.get("key");
if (!StringUtils.isEmpty(key)){
wrapper.and((w) -> {
w.eq("id",key).or().eq("sku_id",key).or().eq("sku_num",key);
});
}
Object status = params.get("status");
if (!StringUtils.isEmpty(status)){
wrapper.eq("status",status);
}
Object wareId = params.get("wareId");
if (!StringUtils.isEmpty(wareId)){
wrapper.eq("ware_id",wareId);
}
IPage<PurchaseDetailEntity> page = this.page(
new Query<PurchaseDetailEntity>().getPage(params),
wrapper
);
return new PageUtils(page);
}
2.5、合并采购单
PurchaseController
/**
* 列表
*/
@RequestMapping("/unreceive/list")
// @RequiresPermissions("ware:purchase:list")
public R unreceiveList(@RequestParam Map<String, Object> params){
PageUtils page = purchaseService.queryUnReceivePage(params);
return R.ok().put("page", page);
}
PurchaseService
PageUtils queryUnReceivePage(Map<String, Object> params);
PurchaseServiceImpl
@Override
public PageUtils queryUnReceivePage(Map<String, Object> params) {
QueryWrapper<PurchaseEntity> wrapper = new QueryWrapper<>();
wrapper.and(item -> {item.eq("status",1).or().eq("status",0);});
IPage<PurchaseEntity> page = this.page(
new Query<PurchaseEntity>().getPage(params),
wrapper
);
return new PageUtils(page);
}
这里显示有问题是因为没有绑定好采购人员信息
分配好以后再点击合并采购单
就能正常显示了
需要编写此接口
##合并采购单有两种方式
1、选择到采购单
会传采购单id
2、不选择采购单,它会自己创建一个采购单进行合并
PurchaseController
/**
* 合并采购需求
*/
@RequestMapping("/merge")
// @RequiresPermissions("ware:purchase:list")
public R merge(@RequestBody PurchaseMergeEntity mergeEntity){
purchaseService.merge(mergeEntity);
return R.ok();
}
PurchaseService
void merge(PurchaseMergeEntity mergeEntity);
PurchaseServiceImpl
@Transactional
@Override
public void merge(PurchaseMergeEntity mergeEntity) {
Long purchaseId = mergeEntity.getPurchaseId();
if (purchaseId == null){
// 新建合并单
PurchaseEntity purchaseEntity = new PurchaseEntity();
purchaseEntity.setStatus(PurchaseEnum.CREATED.getCode());
this.save(purchaseEntity);
purchaseId = purchaseEntity.getId();
}
// 修改合并项信息
List<Long> items = mergeEntity.getItems();
Long finalPurchaseId = purchaseId;
List<PurchaseDetailEntity> collect = items.stream().map(
(id) -> {
PurchaseDetailEntity purchaseDetailEntity = new PurchaseDetailEntity();
purchaseDetailEntity.setId(id);
purchaseDetailEntity.setPurchaseId(finalPurchaseId);
purchaseDetailEntity.setStatus(PurchaseDetailEnum.ASSIGNED.getCode());
return purchaseDetailEntity;
}
).collect(Collectors.toList());
purchaseDetailService.updateBatchById(collect);
// 更新采购单更新时间
PurchaseEntity purchaseEntity = new PurchaseEntity();
purchaseEntity.setId(purchaseId);
purchaseEntity.setUpdateTime(new Date());
this.updateById(purchaseEntity);
}
合并采购单id
不选择采购单id会新增采购单
2.6、领取采购单
PurchaseController
/**
* 领取采购单
*/
@PostMapping("/received")
// @RequiresPermissions("ware:purchase:list")
public R merge(@RequestBody List<Long> ids){
purchaseService.received(ids);
return R.ok();
}
PurchaseServiceImpl
@Transactional
@Override
public void received(List<Long> ids) {
// 1、确认当前采购单是否新建或已分配状态
List<PurchaseEntity> collect = ids.stream().map(this::getById).
filter(item -> {
if (PurchaseEnum.CREATED.getCode().equals(item.getStatus()) || PurchaseEnum.ASSIGNED.getCode().equals(item.getStatus())) {
return true;
}
return false;
}).map(item -> {
item.setUpdateTime(new Date());
item.setStatus(PurchaseEnum.RECEIVED.getCode());
return item;
}).collect(Collectors.toList());
// 2、改变采购单状态
if (collect.size() == 0){
return;
}
this.updateBatchById(collect);
// 3、改变采购单详情状态
collect.forEach(item -> {
List<PurchaseDetailEntity> list = purchaseDetailService.list(new QueryWrapper<PurchaseDetailEntity>().eq("purchase_id", item.getId()));
List<PurchaseDetailEntity> collect1 = list.stream().map(updateItem -> {
PurchaseDetailEntity detailEntity = new PurchaseDetailEntity();
detailEntity.setId(updateItem.getId());
detailEntity.setStatus(PurchaseDetailEnum.RECEIVED.getCode());
return detailEntity;
}).collect(Collectors.toList());
if (collect1.size() > 0){
purchaseDetailService.updateBatchById(collect1);
}
});
}
@Transactional
@Override
public void merge(PurchaseMergeEntity mergeEntity) {
Long purchaseId = mergeEntity.getPurchaseId();
if (purchaseId == null){
// 新建合并单
PurchaseEntity purchaseEntity = new PurchaseEntity();
purchaseEntity.setStatus(PurchaseEnum.CREATED.getCode());
this.save(purchaseEntity);
purchaseId = purchaseEntity.getId();
}
// 合并采购需求时判断合并单新建和已分配状态。其他状态不给合并
PurchaseEntity entity = this.getById(purchaseId);
if (entity != null && (!PurchaseEnum.CREATED.getCode().equals(entity.getStatus()) && !PurchaseEnum.ASSIGNED.getCode().equals(entity.getStatus()))){
throw new RuntimeException("有合并单:" + purchaseId + "不是新建或已分配状态,不允许合并");
}
// 修改合并项信息
List<Long> items = mergeEntity.getItems();
Long finalPurchaseId = purchaseId;
List<PurchaseDetailEntity> collect = items.stream().map(
(id) -> {
PurchaseDetailEntity purchaseDetailEntity = new PurchaseDetailEntity();
purchaseDetailEntity.setId(id);
purchaseDetailEntity.setPurchaseId(finalPurchaseId);
purchaseDetailEntity.setStatus(PurchaseDetailEnum.ASSIGNED.getCode());
return purchaseDetailEntity;
}
).collect(Collectors.toList());
purchaseDetailService.updateBatchById(collect);
// 更新采购单更新时间
PurchaseEntity purchaseEntity = new PurchaseEntity();
purchaseEntity.setId(purchaseId);
purchaseEntity.setUpdateTime(new Date());
this.updateById(purchaseEntity);
}
2.7、完成采购
PurchaseController
/**
* 完成采购
*/
@PostMapping("/done")
// @RequiresPermissions("ware:purchase:list")
public R done(@RequestBody PurchaseDoneVO purchaseDoneVO){
purchaseService.done(purchaseDoneVO);
return R.ok();
}
PurchaseService
void done(PurchaseDoneVO purchaseDoneVO);
PurchaseServiceImpl
@Transactional
@Override
public void done(PurchaseDoneVO purchaseDoneVO) {
// 1、改变采购项状态
List<PurchaseItemDoneVO> items = purchaseDoneVO.getItems();
items.forEach(item -> {
PurchaseDetailEntity entity = new PurchaseDetailEntity();
BeanUtils.copyProperties(item,entity);
purchaseDetailService.updateById(entity);
});
// 2、根据采购项状态改变采购单状态
boolean flag = true;
for (PurchaseItemDoneVO item : items) {
PurchaseDetailEntity entity = new PurchaseDetailEntity();
entity.setId(item.getItemId());
if (!PurchaseDetailEnum.FINISHED.getCode().equals(item.getStatus())) {
flag = false;
entity.setStatus(PurchaseDetailEnum.HASERROR.getCode());
purchaseDetailService.updateById(entity);
} else {
entity.setStatus(PurchaseDetailEnum.FINISHED.getCode());
purchaseDetailService.updateById(entity);
// 3、新增或修改库存
Long itemId = item.getItemId();
PurchaseDetailEntity detailEntity = purchaseDetailService.getBaseMapper().selectById(itemId);
if (detailEntity != null){
Long skuId = detailEntity.getSkuId();
Integer skuNum = detailEntity.getSkuNum();
Long wareId = detailEntity.getWareId();
QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<WareSkuEntity>().eq("sku_id", skuId).eq("ware_id", wareId);
List<WareSkuEntity> list = wareSkuService.list(wrapper);
WareSkuEntity wareSkuEntity = new WareSkuEntity();
BeanUtils.copyProperties(detailEntity,wareSkuEntity);
wareSkuEntity.setStock(skuNum);
if (list == null || list.size() == 0){
// 新增
wareSkuEntity.setStockLocked(0);
// 调用远程接口获取skuName。并且保证事务不回滚
try{
R info = productFeignService.info(skuId);
if (info.getCode() == 0){
Map<String,Object> data = (Map<String, Object>) info.get("skuInfo");
wareSkuEntity.setSkuName((String)data.get("skuName"));
}
}catch (Exception e){
}
wareSkuEntity.setStock(skuNum);
wareSkuService.addStock(wareSkuEntity);
} else {
// 修改
wareSkuService.updateStock(wareSkuEntity);
}
}
}
}
Long id = purchaseDoneVO.getId();
PurchaseEntity entity = new PurchaseEntity();
entity.setId(id);
entity.setStatus(flag ? PurchaseEnum.FINISHED.getCode() : PurchaseEnum.HASERROR.getCode());
this.updateById(entity);
}
ProductFeignService
package com.ljs.gulimall.ware.feign;
import com.ljs.gulimall.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient("gulimall-product")
public interface ProductFeignService {
/**
* 根据skuId获取sku信息
*
* @param skuId skuId
* @return R
*/
@RequestMapping("/product/skuinfo/info/{skuId}")
R info(@PathVariable("skuId") Long skuId);
}
GulimallWareApplication
@EnableFeignClients
WareSkuService
void addStock(WareSkuEntity wareSkuEntity);
void updateStock(WareSkuEntity wareSkuEntity);
WareSkuServiceImpl
@Override
public void addStock(WareSkuEntity wareSkuEntity) {
wareSkuDao.addStock(wareSkuEntity);
}
@Override
public void updateStock(WareSkuEntity wareSkuEntity) {
wareSkuDao.updateStock(wareSkuEntity);
}
WareSkuDao
void addStock(WareSkuEntity wareSkuEntity);
void updateStock(WareSkuEntity wareSkuEntity);
WareSkuDao.xml
<insert id="addStock">
insert into
wms_ware_sku
(`sku_id`,`ware_id`,`stock`,`sku_name`,`stock_locked`)
values
(#{skuId},#{wareId},#{stock},#{skuName},#{stockLocked})
</insert>
<update id="updateStock">
update
wms_ware_sku
set
stock = stock + #{stock}
where sku_id = #{skuId}
and ware_id = #{wareId}
</update>