谷粒商城基础篇完结

谷粒商城总结71-100(基础篇完结)

1.保存商品

1.1.后端

首先我们根据前端返回给我的json数据,我们可以使用网上人家写好的一个方法,就是根据给的json数据生成java对象,这样就会方便很多的事情。

最终的生成:

下面就是实现我们的业务逻辑的代码:

1.业务逻辑分析

// 11多张表数据的保存

// 1.保存spu基本信息  pms_spu_info

// 2.保存spu的描述  pms_spu_info_desc

// 3.保存spu的图片集  pms_spu_images

// 4.保存spu的规格参数  pms_sku_sale_attr_value

// 4.1. spu的积分表  送积分 和 增长值   gulimall_sms -> sms_spu_bounds

// 5. 下面就是sku  保存spu对应的sku的信息

// 5.1)、保存sku的基本信息   pms_sku_info

// 5.2)、 sku的图片信息  pms_sku_images

// 5.3)、 sku的销售属性值  pms_sku_sale_attr_value

// 5.4)、sku的优惠信息和满减信息 gulimall_sms -> sms_sku_ladder  这个是打折表几件打几折

// 5.5)、sku的满减表  满多少钱减多少  gulimall_sms -> sms_sku_full_reduction

// 5.6)、sku对应会员等级所购买的价格 gulimall_sms -> sms_member_price

注意:

​ BeanUtils.copyProerties() 这个的使用 注意 如果我们有对应的字段 但是我们的属性名字不相同,那么就无法使用这个方法进行拷贝, 就只能用set() get() 方法来进行赋值

1.1.1.spu的保存

spu的基本信息的保存

// 1.保存spu基本信息  pms_spu_info
        SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
        BeanUtils.copyProperties(spuSaveVo, spuInfoEntity);
        spuInfoEntity.setCreateTime(new Date());
        spuInfoEntity.setUpdateTime(new Date());
		// 进行保存
        this.saveBaseSpuInfo(spuInfoEntity);

spu的图片保存

我们图片的id是spuId因此需要保存后才能获取到spuId

List<String> images = spuSaveVo.getImages();

// 还要传递我们的spuId
spuImagesService.saveImages(spuInfoEntity.getId(), images);

// saveImages写在spuImagesService的saveImages然后进行实现 虽然我们可以都写在这个原本的方法里面,但是写在这里面喃就进行了分块,这样看起来更为的简介。

spu的描述保存

List<String> decript = spuSaveVo.getDecript();
        SpuInfoDescEntity spuInfoDescEntity = new SpuInfoDescEntity();
        // mp误以为你是自增的 所以导致错误了  所以表示自己设置
		// 在我们SpuInfoDescEntity的id字段上面加上注解
		// @TableId(type =  IdType.INPUT) // 这个就是自己填写
        spuInfoDescEntity.setSpuId(spuInfoEntity.getId());

        // 变成以,结束的字符串
        String join = String.join(",", decript);

        spuInfoDescEntity.setDecript(join);

        spuInfoDescService.saveSpuInfoDesc(spuInfoDescEntity);

保存spu的规格参数 pms_sku_sale_attr_value

		// 基本属性
        List<BaseAttrs> baseAttrs = spuSaveVo.getBaseAttrs();
		// 对每一个BaseAttrs进行stream操作 生成 ProductAttrValueEntity
        List<ProductAttrValueEntity> collect = baseAttrs.stream().map((item) -> {
            
            ProductAttrValueEntity valueEntity = new ProductAttrValueEntity();
            
            // 设置spuId
            valueEntity.setSpuId(spuInfoEntity.getId());

            // 查询属性名字 根据 attrId进行查询  attrId是从前台获取过来的
            // 得到我们attrName 进行庸于字段保存
            AttrEntity attrEntity = attrService.getById(item.getAttrId());

            // 得到属性名字
            String attrName = attrEntity.getAttrName();
			
            // 进行设置valueEntity其他属性
            valueEntity.setAttrName(attrName);
            valueEntity.setAttrValue(item.getAttrValues());
            valueEntity.setQuickShow(item.getShowDesc());
            valueEntity.setAttrId(item.getAttrId());

            return valueEntity;
            
        }).collect(Collectors.toList());

        // 进行批量保存
        productAttrValueService.saveBatch(collect);

1.1.2.sku的保存

现在就是对sku的信息进行保存的, 注意我们下面所有的都是在sku的stream里面进行循环保存的

sku的基本信息保存

因为我们的数据库保存sku的时候要保存我们默认的图片 defalut_img

// 得到sku的基本信息
List<Skus> skus = spuSaveVo.getSkus();

// 因此我们要先遍历每一个sku然后进行defalut_img的保存
// 先进行判断是否为空 为空就不执行了
if(sku != null &&sku.size() >0) {
    sku.forEach((sku) -> {
        // 这个就是获取我们的默认图片的
    	String defalutImg = "";
        for(Images image: sku.getImages()) {
            // 表示是默认的图片
            if(image.getDefaultImg() == 1) {
                defalutImg = image.getImgUrl();
			}
        }
        // 下面就进行sku的基本信息的保存
        /*
                    只能拷贝这四个 因为其他的都要自己进行赋值
                    private String skuName;
                    private BigDecimal price;
                    private String skuTitle;
                    private String skuSubtitle;
        */
        SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
        BeanUtils.copyProperties(item, skuInfoEntity);
        skuInfoEntity.setBrandId(spuInfoEntity.getBrandId());
        skuInfoEntity.setCatalogId(spuInfoEntity.getCatalogId());
        skuInfoEntity.setSaleCount(0L);
        skuInfoEntity.setSpuId(spuId);
        skuInfoEntity.setSkuDefaultImg(defaultImg);
        // 下面就是进行保存
        skuInfoService.saveSkuInfo(skuInfoEntity);
        
        // 获取我们的sku的id 只有保存后才有的
        Long skuId = skuInfoEntity.getSkuId();
        
       	// 下面就是保存图片
        // 得到每一个sku的全部图片
        List<SkuImagesEntity> images = sku.getImages();
        // 收集成SkuImagesEntity的集合 进行批量保存
        List<SkuImagesEntity> imagesEntity = images.stream().map((img) -> {
            
            SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
            skuImagesEntity.setDefaultImg(img.getDefaultImg());
            skuImagesEntity.setSkuId(skuId);
            skuImagesEntity.setImgUrl(img.getImgUrl());
            return skuImagesEntity
        }).filter((enitity) -> {
            // 我们的图片为空 为空的话我们就不进行保存了
            return !StringUtils.isEmity(enitity.getImgUrl());
        }).collect(Collectors.toList()); // 收集成为我们的集合
        // 进行批量的保存
        SkuImagesService.saveBatch(imagesEntity);
        
        /*
        attr的属性
        	public class Attr {
                private Long attrId;
                private String attrName;
                private String attrValue;
            }
        */
        
        // 下面就是保存我们sku的销售属性(不是规格参数参数那些了)
        List<Attr> attrs = sku.getAttr();
        List<SkuSaleAttrValueEntity> skuSal = attrs.stream().map((attr.getAttrId()); -> {
            SkuSaleAttrValueEntity skuSaleAttrValueEntity = new SkuSaleAttrValueEntity();
        	skuSaleAttrValueEntity.setSkuId(skuId);
            skuSaleAttrValueEntity.setAttrId(attr.getAttrId());
            skuSaleAttrValueEntity.setAttrValue(attr.getAttrValue());
            skuSaleAttrValueEntity.setAttrName(attr.getAttrName());
            return skuSaleAttrValueEntity;
        }).collect(Collectors.toList());
        
        // 进行批量的保存
        skuSaleAttrValueService.saleAttrValue(saleAttrValueEntities);
        
        
        // 下面就是操作我们远程的服务
        // 我们首先要在gulimall-common里面创建我们两个不同服务都用调用的实体类
        /*
        	@Data
            public class SkuReductionTo {

                // 这个skuId才是最重要的
                private Long skuId;
                private int fullCount;
                private BigDecimal discount;
                private int countStatus;
                private BigDecimal fullPrice;
                private BigDecimal reducePrice;
                private int priceStatus;
                // 会员价格
                private List<MemberPrice> memberPrice;
            }
        */
        
        // 5.4)、sku的优惠信息  gulimall_sms -> sms_sku_ladder  这个是打折表几件打几折

        // 5.5)、sku的满减表  满多少钱减多少  gulimall_sms -> sms_sku_full_reduction

        // 5.6)、sku对应会员等级所购买的价格 gulimall_sms -> sms_member_price
        // 我们直接全部传递过去然后我们在另外一个服务里面来进行这三个操作
        // 就要使用到我们的SkuReductionTo实体类 然后我们的BeanUtils
        SkuReductionTo skuReductionTo = new SkuReductionTo();
        BeanUtils.copyProperties(item,skuReductionTo);
        // 好像我们的集合是浅拷贝的 为了严谨我们可以在单独进行set一下
        List<MemberPrice> memberPrice = item.getMemberPrice();
        List<com.atguigu.common.to.MemberPrice> collect1 = memberPrice.stream().map((memberPrice1) -> {
             com.atguigu.common.to.MemberPrice memberPrice2 = new com.atguigu.common.to.MemberPrice();
             memberPrice2.setPrice(memberPrice1.getPrice());
             // 这个是一定要设置的 因为是前端发送给我们的他的id是多少 
             memberPrice2.setId(memberPrice1.getId());
             memberPrice2.setName(memberPrice1.getName());
             return memberPrice2;
         }).collect(Collectors.toList());
         // 进行的循环拷贝的环节
         skuReductionTo.setMemberPrice(collect1);

         // 再来设置一下skuId就可以了
         skuReductionTo.setSkuId(skuId);

     // TODO 我们也可以在传递过去后进行判断 因为如果这里有一个不成立的话其他的满减信息也不会进行保存 所以
 // 这里为什么使用或 因为我们在另外那边做了分别的判断 这里就相当于 如果那两个优惠都没有的话我们才不进行保存
       // 如果其中有一个是有一种优惠的那么我们就传递过去后进行判断
       // 为了保险起见我们还是可以进行传递过去够针对每一个不同的表进行判断
       // 要有满减多少件 并且 满多少元也是要大于0 因为既然你说了满... 那么肯定就是有优惠的
         if(skuReductionTo.getFullCount() > 0 
            || 	            
            (skuReductionTo.getFullPrice().compareTo(new BigDecimal("0")) == 1) 
            || 
            skuReductionTo.getMemberPrice() != null 
            || 
            skuReductionTo.getMemberPrice().size() > 0) {
            // 发起远程调用
            R r1 = couponFeignService.saveSkuReduction(skuReductionTo);
              if(r1.getCode() != 0) {
                  
                  log.error("远程保存sku优惠信息失败");
              }
          }
         
        
	})
}

下面就是我们调用的那个微服务里面的多个表之间的插入数据

//    保存我们保存商品的时候全部的优惠信息 以及 会员价格等等
    @Transactional // 这个也要操作多张表
    @Override
    public void saveSkuReduction(SkuReductionTo skuReductionTo) {
        // 必须要大于0才进行保存
        if(skuReductionTo.getFullCount() > 0) {
            // 5.4)、sku的优惠信息和满减信息 gulimall_sms -> sms_sku_ladder  这个是打折表几件打几折
            SkuLadderEntity skuLadderEntity = new SkuLadderEntity();
            skuLadderEntity.setSkuId(skuReductionTo.getSkuId());
            skuLadderEntity.setFullCount(skuReductionTo.getFullCount());
            // 打几折
            skuLadderEntity.setDiscount(skuReductionTo.getDiscount());
            // 状态是否参与其他优惠
            skuLadderEntity.setAddOther(skuReductionTo.getCountStatus());

            // 最终打折后是多少钱
            //        skuLadderEntity.setPrice(skuReductionTo);
            skuLadderService.save(skuLadderEntity);
        }
		
        // 满多少钱也要大于0才行
        // 这里也单独进行判断
        if ((skuReductionTo.getFullPrice().compareTo(new BigDecimal("0")) == 1)) {
            // 5.5)、sku的满减表  满多少钱减多少  gulimall_sms -> sms_sku_full_reduction
            SkuFullReductionEntity skuFullReductionEntity = new SkuFullReductionEntity();
            skuFullReductionEntity.setSkuId(skuReductionTo.getSkuId());
            // 满多少
            skuFullReductionEntity.setFullPrice(skuReductionTo.getFullPrice());
            // 减多少钱
            skuFullReductionEntity.setReducePrice(skuReductionTo.getReducePrice());
            // 建了是否叠加
            skuFullReductionEntity.setAddOther(skuReductionTo.getPriceStatus());
            save(skuFullReductionEntity);

        }

		// 会员价钱也必须要进行设置才行 
        // 5.6)、sku对应会员等级所购买的价格 gulimall_sms -> sms_member_price
        List<MemberPrice> memberPrice = skuReductionTo.getMemberPrice();

        if(memberPrice != null && memberPrice.size() > 0) {


            List<MemberPriceEntity> priceEntities = memberPrice.stream().map((item) -> {
                MemberPriceEntity memberPriceEntity = new MemberPriceEntity();
                memberPriceEntity.setSkuId(skuReductionTo.getSkuId());
                memberPriceEntity.setMemberLevelId(item.getId());
                memberPriceEntity.setMemberLevelName(item.getName());
                memberPriceEntity.setMemberPrice(item.getPrice());
                memberPriceEntity.setAddOther(1); // 默认就是叠加优惠
                return memberPriceEntity;
            }).filter((entity) -> {
                // 只留下我们设置了会员价钱的数据  
                return (entity.getMemberPrice().compareTo(new BigDecimal("0")) == 1);
            }).collect(Collectors.toList());

            // 最终进行批量保存
            memberPriceService.saveBatch(priceEntities);
        }
    }

sku的图片保存(有默认图片的单独保存)

sku的销售属性(不是规格参数参数那些了)

1.1.3.gulimall-coupon的跨库保存

对某个sku的会员价钱进行保存

对某个sku的商品满减信息的保存

对某个sku的商品进行打折优惠

1.2.前端(页面展示)

这些页面就是我们不需要考虑怎么实现了,我们注重的是后端的业务逻辑的实现

这些都是组件我们注重后端。

2.进行关联分类逻辑业务

2.1.后端

// 进行分析
// 1.根据brandId 和 categroyId进行查询 我们数据库看是否已经存在了 这个了 如果存在了就不添加我们的这个了直接进行返回

// 2. 如果不存在我们根据brandId 查询出 brandName  根据catelogId查询出catelogName

// 3. 进行保存 就是我们的业务代码 其实也很简单

2.2.前端(页面展示)

注意我们的方法调用的时机是什么时候

当我们点击上面那个确定的时候就会进行执行这个方法, 所以不是点击下面这个确定在来确定这个方法

并且我们只传递2个参数回去

brandId

categoryId

这两个参数

3.获取当前分组没有关联的所里有属性

3.1.前端(页面展示)

3.2.后端

前端的样式是这样的:

首先是前端给我们的参数就是这个分组的id 还有就是我们的key因为我们点击新建关联的时候可以进行搜索的

public PageUtils getNoRealtion(Long attrgroupId, Map<String, Object> params) {
    // 首先我们是根据attrgroupId查询我们的查询到他的分类id
    // 1、我们只能关联我们这个分类下面的分组id
    AttrGroupEntity attrGroup = attrGroupService.getById(attrgroupId);
    
    // 得到分类的id
    Long catelogId = attrGroup.getCatelogId();
    
    // 我们根据这个分类id查询我们关联表里面的所有的分组id
    // 因为其他分组选了的话 我们就不能再显示了
    LambdaQueryWrapper<AttrGroupEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    lambdaQueryWrapper.eq(AttrGroupEntity::getCatelogId,catelogId);
    
    // 得到这个分类下面的所有分组对象
    List<AttrGroupEntity> groupEntities = attrGroupService.list(lambdaQueryWrapper);
    
    // 从分组对象里面获取我们的分组id  要去分组属性关联表里面去查询的
    List<Long> groupIds = groupEntities.stream().map((item) -> {
        Long groupId = item.getGroupId();
        return groupId;
    }).collect(Collectors.toList());
    
    
    // 2. 去我们的 pms_attr_attrgroup_relation里面出找出attr与groupId进行关联了的
    LambdaQueryWrapper<AttrAttrgroupRelationEntity> lambdaQueryWrapper1 = new LambdaQueryWrapper<>();
    lambdaQueryWrapper1.in(AttrAttrgroupRelationEntity::getAttrGroupId,groupIds);
    // 查询出已经关联了的attrId
    List<AttrAttrgroupRelationEntity> isReadlyReation = attrAttrgroupRelationService.list(lambdaQueryWrapper1);
    
    // 从对象里面得到attrIds
    Lsit<Long> attrIds = isReadlyReation.stream().map((item) -> {
        Long attrId = item.getAttrId();
        return attrId;
    }).collect(Collectors.toList());
    
    // 3.查询我们的attr表 除去上面那些id 并且还要是同一个 catelogId
    LambdaQueryWrapper<AttrEntity> lambdaQueryWrapper2 = new LambdaQueryWrapper<>();
    
    // 3.1分类要是同一个
    lambdaQueryWrapper2.eq(AttrEntity::getCatelogId);
    // 3.2必须还要是属于规格参数的才行  我们写了一个常量里面有我们专门的code
    lambdaQueryWrapper2.eq(AttrEntity::getAttrType,ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode());
    // 这个就是去重就是什么意思喃 不属于我们的上面的attrIds 注意我们要进行判断是否有attrIds 不然要报错的
    lambdaQueryWrapper2.notIn(attrIds != null && attrIds.size() > 0, AttrEntity::getAttrId,attrIds);
    
    // 经过上面的步骤我们最终就实现了我们的 获取同一分类下 其他分组没有引用的规格参数
    
    
    // 下面就是处理我们的key了
    
    String key = (String) params.get("key");
    
    if(!StringUtils.isEmpity(key)) {
        // 注意我们要使用lambdaQueryWrapper2 因为这个是最终的判断条件
        lambdaQueryWrapper2.and((obj) -> {
            obj.eq(AttrEntity::getAttrId,key).or()
                        .like(AttrEntity::getAttrName,key);
        });
    }
    
    // 下面就是返回分页的数据
    IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
        		// 注意这里还是使用的是lambdaQueryWrapper2 因为这个是我们最终的判断条件
                lambdaQueryWrapper2
    );
    
    return page;
    
    
}

4.回显我们分组修改里面的所属分类

4.1后端(无前端)

这个喃也是使用递归的形式进行实现的,我们要返回他一级二级三级分类的分类id 这样才能进行回显。

1.我们的当时写的实体类是不规范的直接在原本的实体类上面加上我们的新的字段

当然你也是可以使用vo类 规范写法就是使用一个vo来实现的。

我们根据传过去的最终三级分类的cateLogId进行查询他的二级分类的一级分类的id等等…

注意我们这个是只有有三级分类的才有属性分组那些等等

递归的结束条件就是我们的parent_cid等于0 那么就不用再找了。

下面就是递归的过程

public List<Long> findParentPath(Long catlogId, List<Long> paths) {
    // 一进来我们就先加入
    paths.add(catlogId);
    CategoryEntity byId = getById(catlogId);
    if(byId.getParentId() != 0) {
        // 表示还能往上走
        findParentPath(byId.getParentId(), paths);
    }
    // 最后返回我们的paths
    return paths;
}

注意我们最终显示的是反过来的 但是我们的页面需要的是 爷/爸/子 才行

所以要进行反转才可以

Collections.reverse(parentPath);

最终就能正确。

5.采购单等业务逻辑

5.1.后端

5.1.1.合并整单

新创建了一个采购单并且那个采购单进行了人员的分配的 并且是没有合并我们的采购需求的,

但是你要注意这里有一个严重的问题,就是

当我们进行合并整单的时候,我们一旦完成了合并整单,我们有一个员工的手机app他就可以看到有采购单,然后进行接单,就是人员的分配,进行领取后,然后进行采购,最后在进行判断你时候完成,没完成是因为什么,就是采购异常。然后进行反馈,虽然数据库是没有这些字段的 但是你可以进自己去数据库添加,这个就是作为一个拓展的功能。

mergeVo类

/**
 * 合并采购单得vo类
 */
@Data
public class MergeVo {

    // 采购单id
    private Long purchaseId;

    // 合并项id
    private List<Long> items;
}
// 这个合并整单有两种情况
// 1.情况1:就是我们这个整单是没有整合已经存在的采购单的,如果没有选择会新创建一个采购单
// 2.情况2:这个就是我们创建了采购单,但是没有想好买什么,先放在那,然后我们后面要买的东西就记录在上面,
// 最主要的就是这两个情况的判断
@Transactional // 事务因为你可以能你的PurchaseEntity是没有创建的
    @Override
    public String purchaseMerge(MergeVo mergeVo) {

        List<Long> items = mergeVo.getItems();
        // TODO 首先我们要判断一下我们选择整单的他的状态是新建还是已领取,只有这两种情况才能整单,你想要重复买这个东西就重新加一个采购项出来
        // 只要你选择有不是这两种情况的就重新选择(当然你也可以说符合两种情况的就加入进去,对都不是进行特殊的判断)
        // 批量查询出来
        List<PurchaseDetailEntity> purchaseDetailEntities = (List<PurchaseDetailEntity>) purchaseDetailService.listByIds(items);

        for (PurchaseDetailEntity purchaseDetailEntity : purchaseDetailEntities) {
            if (purchaseDetailEntity.getStatus() == WareConstant.PurchaseDetailStatusEnum.HASERROR.getCode()
                    || purchaseDetailEntity.getStatus() == WareConstant.PurchaseDetailStatusEnum.FINISH.getCode()
                    || purchaseDetailEntity.getStatus() == WareConstant.PurchaseDetailStatusEnum.BUYING.getCode()) {
//                throw new RRException("");
                return "chongfu";
            }
        }
        
        // 上面的操作就是看是否有选错状态的情况


        Long purchaseId = mergeVo.getPurchaseId();
        // 新建一个采购单
        if (purchaseId == null) {
            // 新建过来的
            PurchaseEntity purchaseEntity = new PurchaseEntity();
            purchaseEntity.setCreateTime(new Date());
            purchaseEntity.setUpdateTime(new Date());

            // 新建的时候默认是0 新建状态
            purchaseEntity.setStatus(WareConstant.PurchaseStatusEnum.CREATED.getCode());
            save(purchaseEntity);

            // 得到采购单id
            purchaseId = purchaseEntity.getId();
        }

        // TODO 确认采购单的状态是0还是1  不判断每一个采购项因为我们同一个东西要分配给多个人才行
//        LambdaQueryWrapper<PurchaseDetailEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//        lambdaQueryWrapper.eq(PurchaseDetailEntity::getPurchaseId, purchaseId);
//
//        // 判断采购单id
        PurchaseEntity byId = getById(purchaseId);

        // 如我们这个采购单的状态也有错误的话也是有问题的
        if(byId.getStatus() == WareConstant.PurchaseStatusEnum.FINISH.getCode() || byId.getStatus() == WareConstant.PurchaseStatusEnum.RECEIVE.getCode() || byId.getStatus() == WareConstant.PurchaseStatusEnum.HASERROR.getCode()) {
            return "";
        }
//
        purchaseDetailService.list();
//        if(byId.getStatus() != WareConstant.PurchaseStatusEnum.CREATED.getCode() || byId.getStatus() != WareConstant.PurchaseStatusEnum.ASSIGNED.getCode()) {
//            return;
//        }


        // 还要修改采购单detial的状态 并且设置他的采购单id就可以了
        Long finalPurchaseId = purchaseId;
        // 这个items就是我们采购项的全部id
        List<PurchaseDetailEntity> collect = items.stream().map((purchaseDetailId) -> {
            // 修改采购需求
            PurchaseDetailEntity purchaseDetailEntity = new PurchaseDetailEntity();
            purchaseDetailEntity.setPurchaseId(finalPurchaseId);
            // 设置主键根据主键进行修改
            purchaseDetailEntity.setId(purchaseDetailId);
            purchaseDetailEntity.setStatus
                (WareConstant.PurchaseDetailStatusEnum.ASSIGNED.getCode());	
            
            // 返回我们的结果
            return purchaseDetailEntity;
        }).collect(Collectors.toList());

        // 批量修改
        purchaseDetailService.updateBatchById(collect);

        // 还要修改我们日期还要进行修改
        // 创建采购单根据采购单id修改采购单的修改时间
        PurchaseEntity purchaseEntity = new PurchaseEntity();
        purchaseEntity.setId(purchaseId);
        purchaseEntity.setUpdateTime(new Date());
        updateById(purchaseEntity);

        return "";
    }

对前端页面也进行了修改

如果我们选择采购项中有状态不是我们所说的两个状态的那么就提示他说状态选择有错误

5.1.2.领取采购单(使用apipost代替app)

@Transactional // 开启我们的
public void purchaseReceived(List<Long> ids) {
    
    // 将每一个id取出来获得这个采购单的每一个实体类
    // 1.并且这个采购单必须是新建或者是已经分配了的
    List<PurchaseEntity> purchaseEntityList = ids.stream().map((id) -> {
        
        // 得到采购单的实体类
        PurchaseEntity purchaseEntity = getById(id);
        return purchaseEntity;
    }).filter((item) -> {
        // 收集我们的状态必须是新建还有就是必须就是已分配的才行
        // 这状态必须是新建或者是已领取的才能进行我们的出来采购的标志
        return item.getStatus() == WareConstant.PurchaseStatusEnum.CREATED.getCode() || item.getStatus() == WareConstant.PurchaseStatusEnum.ASSIGNED.getCode();
    }).map((item) -> {
        
        // 改为什么 就是状态修改了2
        item.setStatus(WareConstant.PurchaseStatusEnum.RECEIVE.getCode());
        // 设置当时这个领取人员领取的时间
        item.setUpdateTime(new Date());
        return item;
    }).collect(Collectors.toList());

    // 2.修改我们采购单的状态改为我们的已领取的状态
    // 使用批量修改
    updateBatchById(purchaseEntityList);
    
    // 下面就是修改每一个采购项的状态就可以了
    // 我们就是对这个采购单进行循环,取出每一个采购单的实体类,然后去我们的wms_purchase_detail 表里面	根据我们的purchaseId进行这个采购单的全部采购项
    purchaseEntityList.forEach((item) -> {
        // 调用service查询出这个采购单下面的全部采购项
        List<PurchaseDetailEntity> purchaseDetailEntities = 
                              purchaseDetailService.listDetialBypurchaseId(item.getId());
        
        // 对每一个采购项进行设置状态
        List<PurchaseDetailEntity> collect = purchaseDetailEntities.stream().map((entity) 		  -> {
            // enity表示每一个采购项
                PurchaseDetailEntity purchaseDetailEntity = new PurchaseDetailEntity();

                // 设置主键id 我们只修改状态 没有时间就不进行修改
                purchaseDetailEntity.setId(entity.getId());
            	
                // 修改状态
        purchaseDetailEntity.setStatus
                                (WareConstant.PurchaseDetailStatusEnum.BUYING.getCode());
                		 
                return purchaseDetailEntity; // 进行收集
            }).collect(Collectors.toList());
        
        // 下面进行批量的修改
        purchaseDetailService.updateBatchById(collect);
    })
    
}

使用我们的apiPost进行测试,

5.1.3.完成采购(使用apipost代替app)

分析:

1.首先我们最终要看采购单是否有异常,那么我们就要根据采购的每一项是否有问题,如果都没有问题那么肯定是没有问题的,如果有一个有问题的那么就是异常的

2.我们修改完状态后还要进行库存的增加,我们有一个庸于字段,就是skuName,实现微服务的调用,如果我们的微服务宕机了我们怎样才能让他不回滚,就是使用try…catch()

PurchaseItemVo实体类

public class PurchaseItemVo {
	private Long itemId;  // 这个采购项的id
    
    private String reason; // 购买异常的原因
    
    private Integer status; // 状态
    
    private Intger realNum; // 实际购买的数量
}

PurchaseDoneVo实体类

@Data
public class PurchaseDoneVo {
    @NotNull
    private Long id; // 采购单id

    private List<PurchaseItemVo> items; // 每一个采购项
}
@Transactional
@Override
public void purchaseDone(PurchaseDoneVo purchaseDoneVo) {
    // 1、修改我们采购单的状态
    Long purchaseId = purchaseDoneVo.getId();
    
    // 2、修改我们每一个采购项的状态
    Boolean flag = true; // 这个就是判断我们所有的采购项里面有没有购买异常的
    // 来对我们采购单进行状态的修改
    List<PurchaseItemVo> items = purchaseDoneVo.getItems();
    
    // 进行批量状态更新的
    List<PurchaseDetailEntity> updates = new ArrayList<>();
    
    for(PurchaseItemVo item :items) {
        // 创建每一个采购项的实体类 进行状态的修改的
        PurchaseDetailEntity purchaseDetailEntity = new PurchaseDetailEntity();

            // 这个就是失败
            if (item.getStatus() ==      		
                     WareConstant.PurchaseDetailStatusEnum.HASERROR.getCode()) {
				// 给上标识
                flag = false;
                purchaseDetailEntity.setStatus(item.getStatus());
            } else {
                // 这个就是状态是没有问题的
                purchaseDetailEntity.setStatus(
                    WareConstant.PurchaseDetailStatusEnum.FINISH.getCode());
                
                // 3.增加库存(仓库id,skuId,入几个库)  每一个采购项的id
                PurchaseDetailEntity entity = 
                    purchaseDetailService.getById(item.getItemId());
                
				// 得到这个采购项目的基本信息  微服务的调用
                wareSkuService.addStock(entity.getSkuId(), entity.getWareId(), entity.getSkuNum());
            }
            purchaseDetailEntity.setId(item.getItemId());
            updates.add(purchaseDetailEntity);
    }
    // 3.将成功采购的进行入库
    purchaseDetailService.updateBatchById(updates);
    
    // 1.1.获取采购单的id
    Long id = purchaseDoneVo.getId();
    
    // 4.修改我们采购单的状态根据flag来修改
    PurchaseEntity purchaseEntity = new PurchaseEntity();
    // 这是我们的采购单id
    purchaseEntity.setId(id);
    //设置状态
            purchaseEntity.setStatus(
                flag ? 	WareConstant.PurchaseStatusEnum.FINISH.getCode() : 
				        WareConstant.PurchaseStatusEnum.HASERROR.getCode());
    
    // 进行采购单状态的更新
    updateById(purchaseEntity);
    
}

微服务的调用(增加库存) 就是进行了多表之间的查询

/**
     * 完成采购后进行入库的操作
     * @param skuId
     * @param wareId
     * @param skuNum
     */
    @Override
    public void addStock(Long skuId, Long wareId, Integer skuNum) {
        // 进行检查
        // 1.如果还没有这个库存记录的话就是新增操作
        LambdaQueryWrapper<WareSkuEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(WareSkuEntity::getSkuId,skuId).eq(WareSkuEntity::getWareId,wareId);
        List<WareSkuEntity> list = list(lambdaQueryWrapper);
        
        // 根据仓库id 和 skuId 进行查询 如果没有则新增一个进去

        if(list == null || list.size() == 0) {
            // 进行新增的操作
            WareSkuEntity wareSkuEntity = new WareSkuEntity();
            wareSkuEntity.setSkuId(skuId);
            wareSkuEntity.setWareId(wareId);
            wareSkuEntity.setStock(skuNum);
            wareSkuEntity.setStockLocked(0);
            
            // 远程查询sku的名字 feign的调用(根据skuId查询sku的全部信息)
            R info = productFeignService.info(skuId);
            // TODO 远程查询sku名字,如果失败,整个事务无需要回滚
            // 自己catch掉异常
            // TODO 让异常出现以后不回滚?
            try {
                if(info.getCode() == 0) {
                    // 根据我们product的代码来进行实现的
                    Map<String, Object> data = (Map<String, Object>) info.get("skuInfo");
                    // System.out.println(data.toString());
                    // System.out.println((String) data.get("skuName"));
					// 获取里面的名字 进行打印
                    wareSkuEntity.setSkuName((String) data.get("skuName"));
                }
                
            } catch (Exception e) {
                // 如果发生了异常就打印这个语句 并且我们不让我们的事务进行回滚
                log.error("第一次添加库存服务调用查询skuName失败{}",e);
            }
            // 进行添加
            baseMapper.insert(wareSkuEntity);

        } else {
            // 就表示这个商品不是第一次库存了 直接添加就可以了
            baseMapper.addStock(skuId,wareId,skuNum);
        }
    }

5.2.前端(页面展示)

采购需求展示

采购单展示

注意:

当我们分配人员后他没有确定,我们还可以后台进行修改,或者说送货人员有一个app可以看到我们创建的采购单,去抢单,然后进行领取,如果你一直没有去购买,那么我们后台就可以进行修改然后去换新的人去,分配新的人员去。

6.添加商品

这个与谷粒学院不同的是,这个只会是最终的数据才进行保存,不会说下一步我们就不进行存储到数据库,就不会产生没用的字段,这个就是全部数据先存储到前端里面,最终一起提交到上面。

即使是进行回显也是根据前端存储的信息进行回显,就不会去读取数据库,除非就是你这商品已经提交上去了,最终进行保存,然后进行上架,我们点击规格等操作,就会操作数据库。

基础篇重要的地方

最主要的还是要理清楚我们的数据库的表与表之间的结构

虽然大部分都是crud但是对逻辑是要很清楚的查的是哪张表

后面我会把数据的表与表之间的关系,会根据业务进行一一分析,理解后对这个业务基本上没有什么问题了

0.一直都在写的一个map的根据key查询

// 这个object就是根据你自己的来的
public PageUtils queryPage(Map<String, Object> params) {
    // 这个key一般根据id查询和name查询的
    String key = (String) params.get("key");
    LambdaQueryWrapper<Object> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    if(!StringUtils.isEmpity(key)) {
        lambdaQueryWrapper.and((obj) -> {
            // 这里根据实际情况来修改
            obj.eq(Object::getId,key).or().like(Object::getName,key);
        });
    }
    // 上面就是根据我们的所选的来实现的
    
    IPage<Object> page = this.page(
        new Query<Object>().getPage(params),
        lambdaQueryWrapper
    );
    // 分页返回数据
    return new PageUtils(page);
 }

1.拖拽功能的实现

后端都还好,就是前端那个递归 根据不同的type进行不同的判断

并且是根据前端element-ui组件里面实时封装的数据来劲判断的是否能放入这个位置…

2.保存商品

最主要的还是后端 使用到我们的dto,然后就是操作了10多张表然后就行边界条件的判断 比如没有图片就不存,没有会员价钱就不存入数据库等等,边界条件的判断

3.属性分组关联同一分类下没有被其他分组的选中的规格参数

1.后端,主要就是根据我们的groupId,查询 pms_attr_group

  1. 这个分组下面的categoryId 然后在根据categoryId在查询pms_attr_group, 得到我们的这个分类下面的全部分组id
  2. 然后根据我们的分组id去查询我们pms_attr_attrgroup_relation 里面的所有的分组id 就可以查询到被关联了的attrIds,
  3. 最终查询pms_attr 根据catelogId 还有就是 就是不在上面的attrIds里面的attrId就是我们可以进行关联的

4.采购单那一块

1、最主要的还是我们对数据库的了解,首先是创建了采购项了我们要进行整单,然后就有两种情况,一个是创建新的采购单,还有一个是用我们新建或者已分配的采购单,就两种情况来进行判断,

2、领取采购单,传递我们采购单id的集合,然后修改每一个采购项的状态,并且合成采购单的时候要判断采购项的状态,必须是新建或者是已分配,如果其中掺杂有其他状态的就直接异常,进行提示,必须重新选择采购项,或者重新创建一个新的采购项。

3、完成采购,就是根据我们每一个采购项是否完成,如果没有完成的话,就会给出原因,并且给出实际买的数量是多少,,来根据这些来进行添加库存,并且还有一个skuPrice这个字段还没有被填充,因为我们不知道他的成本价格是多少,我们只有售卖这个商品时候的价格,因此我们这个如果想要设置,我们可以以为是,比原本的产品少个500元左右,所以我们可以根据,这样来进行完善,因为我们的

TODO 这个就留到后面在说把

TODO

自己添加的模块

最主要的就是采购项前端那一个板块

最终效果图

采购项的界面

都变成了标签格式这样才能进行上面显示内容

// 这个就是添加的商品名称
<el-table-column prop="skuName" header-align="center" align="center" label="采购商品名称">
    
    <template slot-scope="scope">
		
        <el-tooltip placement="top">
            <div slot="content">
                <span>{{scope.row.skuName}}</span>
            </div>
        	<el-tag>{{scope.row.skuName.substring(0,5) + "..."}}</el-tag>
        </el-tooltip>
    </template>
</el-table-column>

// 这个就是添加的失败的原因的代码 根据字数的不同还要做不同的判断
<el-table-column prop="reason" header-align="center" align="center" label="异常原因">

        <template slot-scope="scope">
          <el-tooltip placement="top">
            <el-tag type="success" v-if="scope.row.reason === null"></el-tag>
          
            <div slot="content">
              <span v-if="scope.row.reason !== null">{{scope.row.reason}}</span>
              <span v-if="scope.row.reason === null"></span>
            </div>
            <el-tag v-if="scope.row.reason !== null && scope.row.reason.length > 4" type="danger">{{scope.row.reason.substring(0,4) + "..."}}</el-tag>
            <el-tag v-if="scope.row.reason !== null && scope.row.reason.length <= 4" type="danger">{{scope.row.reason}}</el-tag>
          </el-tooltip>
          
        </template>
          
      </el-table-column>

后端代码:

	// 这个就是根据三级分类的id进行查询到这个三级分类下有哪些sku品牌进行返回
	@Override
    public PageUtils listForSkuInfo(Map<String, Object> params, Long catlogId) {

        // 根据key查询
        String key = (String) params.get("key");
        LambdaQueryWrapper<SkuInfoEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();


        if (catlogId != 0) {
            lambdaQueryWrapper.eq(SkuInfoEntity::getCatelogId, catlogId);
        }

        // 获取所有的三级分类的sku_id

        if(!StringUtils.isEmpty(key)) {
            lambdaQueryWrapper.and((obj) -> {
                obj.eq(SkuInfoEntity::getSkuId,key).or().like(SkuInfoEntity::getSkuName,key);
            });
        }

        IPage<SkuInfoEntity> page = page(new Query<SkuInfoEntity>().getPage(params), 		                                                                       lambdaQueryWrapper);

        return new PageUtils(page);
    }

添加采购项的界面

代码:

// 这个
<el-form-item label="采购商品id" prop="skuId">
        <el-select
          ref="groupSelect"
          v-model="dataForm.skuId"   // 绑定的是skuId这个很重要
          placeholder="请选择"
        >
          <el-option
            v-for="item in attrSkuInfos"   // 循环遍历这个集合
            :key="item.skuId"
            :label="item.skuName"
            :value="item.skuId"
          ></el-option>
        </el-select>

</el-form-item>

//  下面就是javascript代码
// 这个就是监听器
catelogPath(path) {
      // 监听到路径变化需要查出这个三级分类的分组信息
      console.log("路径变了", path);
      this.attrSkuInfos = [];  // 进行初始化
      this.dataForm.skuId = "";  // 我们的skuId
      this.catelogId = path[path.length - 1]; // 得到这个三级分类
      if (path && path.length == 3) {  // 这个必须是三级分类才会进行显示
        this.$http({
          url: this.$http.adornUrl(
              // 获取我们的puchaseDetialVo的实体类 里面包含到skuName
            `/product/skuinfo/list/skuinfo/${path[path.length - 1]}`
          ),
          method: "get",  // get请求
          params: this.$http.adornParams({ page: 1, limit: 10000000 }),
        }).then(({ data }) => {
          if (data && data.code === 0) {
              //得到我们所有的skuInfo的信息
            this.attrSkuInfos = data.page.list;
            // 这个就包含了所有 有我们的skuIds
            console.log(this.attrSkuInfos)
          } else {
            this.$message.error(data.msg);
          }
        });
      } else if (path.length == 0) {
        this.catelogId = "";
      } else {
        this.$message.error("请选择正确的分类");
        this.catelogId = "";
      }
    },
  },

后端代码(部分代码):

		
		// 新建一个
		IPage<PurchaseDetailVo> page1 = new Page<>();
        BeanUtils.copyProperties(page,page1);
		// 用我们原来查询到的弄成我们的vo实体类  因为本来的实体类是不满足我们的skuName的
        List<PurchaseDetailEntity> records = page.getRecords();
        List<PurchaseDetailVo> collect = records.stream().map((item) -> {
            PurchaseDetailVo purchaseDetailVo = new PurchaseDetailVo();
            BeanUtils.copyProperties(item, purchaseDetailVo);
            // 根据sku进行查询
            Long skuId = item.getSkuId();

            // 进行微服务的调用 我们这个也是不进行回滚的 如果发生了异常就不查询名字了 
            R info = productFeignService.info(skuId);
            try {
                if (info.getCode() == 0) {
                    Map<String, Object> data = (Map<String, Object>) info.get("skuInfo");

                    purchaseDetailVo.setSkuName((String) data.get("skuName"));
                }
            } catch (Exception e) {
                log.error("第一次添加采购项时候查询skuName服务调用查询skuName失败{}", e);
            }
            return purchaseDetailVo;
        }).collect(Collectors.toList());
        // 最终返回
        page1.setRecords(collect);

        return new PageUtils(page1);
    

TODO

1.首先是下架的功能,需要删除多个表里面的数据,

进行规格回显的时候还要进行判断,只能说有一些才进行回显,有一些是不能进行回显的

2.删除级联分类的时候要判断是有有商品在这个类里面,如果在就要进行业务代码的处理

最终就完成基础篇全部内容

柠檬加油,你已经完成了基础篇了,接下来要继续努力,朝着你的目标继续前行!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值