找回密码
 立即注册
首页 业界区 业界 商品中心—1.B端建品和C端缓存的技术文档 ...

商品中心—1.B端建品和C端缓存的技术文档

硫辨姥 2025-6-10 09:03:20
大纲
1.商品中心的专业术语
2.商品中心的基本业务系统
3.商品中心整体架构设计以及运行流程
4.商品B端—商品编码生成逻辑
5.商品B端—商品核心数据模型
6.商品B端—转换建品请求数据为商品模型数据
7.商品B端—商品建品时商品编号补全与审核配置
8.商品B端—商品审核前的草稿数据保存逻辑
9.商品B端—不需审核的建品流程持久化逻辑
10.商品B端—审核工单分页列表和商品草稿查询
11.商品B端—商品审核时的敏感字段diff计算逻辑
12.商品B端—对草稿中的商品进行审核的逻辑
13.商品B端—商品属性+买手+品类的数据维护
14.商品C端—通用缓存读写组件的实现逻辑
15.商品C端—接口代码实现逻辑
 
1.商品中心的专业术语
一.ITEM
商品售卖展示单位,仅⽤于销售时展示使⽤。
 
二.SKU
SKU是Stock Keeping Unit(库存单位),即库存进出计量的单位。可以是以件、盒、托盘等为单位,如:iPhoneX + ⿊⾊ + 256G。
 
三.SPU
SPU是Standard Product Unit标准化产品单元,是对某一类标准产品的共同特征属性的描述。SPU是商品信息聚合的最⼩单位,如:iPhoneX就是SPU。SPU的出现是为了满足在叶子类目下对商品进行进一步抽象的需求。比如手机就是叶子类目,虽然可以添加苹果手机或者华为手机这样的类目,但这样添加就比较麻烦了,可能会导致类目树就会变得非常庞大。所以SPU是一个介于叶子类目和商品之间的概念,是对类目的细化。因此SPU通常由"后台类目 + 关键属性"唯一确定。
 
四.CSPU
CSPU也就是子标准化产品单元,即SPU的细分,Child SPU。CSPU通常由"后台类目 + 关键属性 + 销售属性"唯一确定。比如手机类型下,品牌和型号这两个属性可以确定一个SPU,但还不能确定一个CSPU,需要额外的销售属性才能确定一个CSPU。以苹果手机为例,品牌是iPhone、型号是X、颜色为黑色、存储为256G,两个关键属性是品牌和型号,两个销售属性为颜色和存储。
 
1.png
五.运营品类
运营品类是⼀种抽象的概念,例如:运动裤、⼿机。每一个商品都会有所属的品类,比如iPhone X这个SPU会属于手机这个品类。不同的电商平台会对品类进行不同的划分,手机品类在有的平台是一级品类,在有的平台是电子产品品类的子品类。
 
六.前台类⽬
多级品类可以构成前台类⽬,例如:男T恤 + 男短裤可归属到男装类⽬。电商网站首页里,左侧都会有一颗类目树,这个类目树就是前台类目。
 
七.SKU规格
⽤来区分单品的主要指标。例如⼿机商品由颜⾊、内存两种规格区分单品,每个规格有多个可选值。从每个规格选出一个值,拼凑起来的组合就可以唯一确定一款商品SKU。颜色规格:白色、黑色、粉色、天蓝色;内存:128G、256G、512G。
 
八.原料商品
只采购不销售的商品,只有采购属性如包材或原材料,例如:吸管、开瓶器。
 
九.普通商品
⼜采购⼜销售的商品,有库存和销售属性。
 
十.组套商品
不采购只销售的商品,共享库存和销售属性,例如:原料商品 + 普通商品组合为⼀个商品。开瓶器是原料商品,红酒是普通商品,开瓶器 + 红酒就是一个组套商品。开瓶器不能单卖但需要采购,用户购买红酒时不用关注开瓶器,开瓶器会和红酒打包在一起进行展示和售卖。
 
十一.虚拟商品
不采购只销售,只有虚拟库存,只有销售属性,例如:会员卡、虚拟卡、购物卡、游戏点卡。这些虚拟商品没有必要去进行采购,用户支付后也不需要履约签收。用户完成对虚拟商品的支付后,商品直接可以展示在用户的会员中心里。
 
十二.售卖区
商品可以在哪⾥卖,售卖范围配置:按城市配置、按卖家组配置。有的商品只能在部分城市可以售卖,部分城市是没法售卖的。在某些区域里,商品的库存不好发货,可能会显示该区域无货。
 
仓库会分成两种:微仓和大仓,微仓就是微型的小仓库,大仓就是大型的大仓库。大仓可以辐射很大一片区域的发货,仓库容量很大,里面可以放很多商品。微仓也叫前置仓,在一个城市里,可以设置微仓。可以将该城市经常购买的,库存量消耗比较大的商品,放到多个微仓里。这样距离消费者就会更近一些,发货也可以更快一些。
 
十三.卖家类型
类型一:⾃营,类型二:POP。自营就是商品是由平台自己来采购、入仓、售卖,POP(Platform Open Plan)意思是平台开放计划,POP就是第三方卖家入驻平台开店售卖自己的商品。
 
十四.商品状态
可售:商品配置了售卖区并且状态为可售
可补:商品可售且微仓可补货状态
可采:商品可售且⼤仓可采货状态
准备上架:建品后为此状态,表示可采和可补
试销上架:上架状态,表示处于试销阶段
上架:正式上架售卖
预下架:售完不展示商品,表示不可采和可补
下架:不可采和不可补
停售:永久下架,已淘汰
 
十五.商品价格
商城价:⾮会员⽤户购买商品的价格
会员价:会员⽤户购买的价格
营销价:促销活动价
秒杀价:秒杀活动价格,⼀⼝价
 
2.商品中心的基本业务系统
(1)商品基础服务
(2)商品类型与采购销售之间的关系
(3)商品中心的业务系统
 
(1)商品基础服务
服务一:提供从建品到下架期间可采可补可售管理的商品全流程服务
 
服务二:对商品基本信息、品牌信息、运营品类、前台类⽬、仓配信息、标签信息、品控信息、销售信息、推⼴信息等进⾏精细化管理与运营
 
服务三:通过权限收敛,可以很好把控并记录⽤户操作⾏为,使流程更加规范
 
服务四:通过提效⼯具,业务⽅可以批量处理商品相关⼯作,降低⼈⼒成本
 
(2)商品类型与采购销售之间的关系
2.png
(3)商品中心的业务系统
商品中心的系统主要会分为两类:一个是面向B端,一个是面向C端。面向B端的系统,主要由公司运营来使用,对商品进行精细化管理。面向C端的系统,则会对C端用户提供各种商品浏览和查询的接口。
 
一.价格中心系统
商品价格管理,提供全流程价格管控和分析。⽀持功能:价格查询、价格设置、审核流程、历史价格查询与趋势分析等。
 
二.商品卖家系统
商品售卖⽅,这⾥将卖家定义为卖家树,⽤户可以定位到多个卖家。商品基于卖家售卖,⽤户在当前覆盖的区域内可浏览到相应卖家的商品。将多个卖家合并为⼀个⼤的卖家称为卖家组,也称为售卖区,售卖区之间的逻辑处理称为售卖区管理(可售区域)。
 
三.商品⽣命周期系统
商品的状态分为:准备上架、试销上架、上架、预下架、下架、停售。为了更好的管理商品,需要对商品进⾏⼀套⽣命周期管理。⽤于考核商品,降低滞销率、资⾦成本以及影响商品的可采可补逻辑。
 
四.商品库存系统
商品库存需要分卖家设置,卖家 + 商品 + 库存关系定位具体商品库存数量。
 
五.商品标签系统
需要打上特殊标签的商品,例如:爆款,后台进⾏标签 + 标签组 + 商品管理。
 
六.属性库系统
商品关联的属性,涉及四种属性:关键属性、销售属性、⾮关键属性、导购属性。
 
七.商品品控系统
把控商品质量,在商品⼊库前进⾏取样检测,给出质检报告。合格商品允许⼊库,不合格商品不允许⼊库。将可售卖商品关联上质检报告,展示给⽤户。
 
3.商品中心整体架构设计以及运行流程
(1)商品中心整体架构
(2)商品新建编辑流程
 
(1)商品中心整体架构
3.png
(2)商品新建编辑流程
4.png
  1. //商品服务
  2. @DubboService(version = "1.0.0", interfaceClass = ProductApi.class, retries = 0)
  3. public class ProductApiImpl implements ProductApi {
  4.     @Autowired
  5.     private ProductService productService;
  6.     //建品/编辑商品接口
  7.     @Override
  8.     public JsonResult<ProductDTO> product(ProductRequest request) {
  9.         try {
  10.             ProductDTO productDTO = productService.product(request);
  11.             return JsonResult.buildSuccess(productDTO);
  12.         } catch (ProductBizException e) {
  13.             log.error("biz error: request={}", JSON.toJSONString(request), e);
  14.             return JsonResult.buildError(e.getErrorCode(), e.getErrorMsg());
  15.         } catch (Exception e) {
  16.             log.error("system error: request={}", JSON.toJSONString(request), e);
  17.             return JsonResult.buildError(e.getMessage());
  18.         }
  19.     }
  20.     ...
  21. }
复制代码
 
4.商品B端—商品编码生成逻辑
  1. //商品编码
  2. @Service
  3. public class ProductNoManagerImpl implements ProductNoManager {
  4.     //6位序列号
  5.     private static final int width = 6;
  6.     @Autowired
  7.     private ProductAutoNoMapper productAutoNoMapper;
  8.     //生成商品编码
  9.     @Override
  10.     public String generateProductNo(Integer sourceType) {
  11.         ProductTypeEnum productTypeEnum = ProductTypeEnum.getByCode(sourceType);
  12.         if (productTypeEnum == null) {
  13.             throw new ProductBizException(ProductErrorCodeEnum.PARAM_ERROR);
  14.         }
  15.         return getProductNo(productTypeEnum.getValue());
  16.     }
  17.     //获取组装后的商品编码,商品的prefixNo是100000
  18.     private String getProductNo(String prefixNo) {
  19.         //有一张ProductAutoNo表专门用于生成商品ID
  20.         //分库分表也可以利用此来实现基于数据库的内存缓存分段的发号器
  21.         ProductAutoNoDO productAutoNoDO = new ProductAutoNoDO();
  22.         productAutoNoMapper.insert(productAutoNoDO);
  23.         Long autoNo = productAutoNoDO.getId();//获取自增ID
  24.         return prefixNo + IDUtils.genId(autoNo, width);//数字混淆算法
  25.     }
  26. }
复制代码
 
5.商品B端—商品核心数据模型
  1. //建品/编辑商品请求入参
  2. @Data
  3. public class ProductRequest implements Serializable {
  4.     //商品基本信息
  5.     private ItemBaseRequest itemBaseRequest;
  6.     //存储信息
  7.     private ItemStorageRequest itemStorageRequest;
  8.     //品控信息
  9.     private ShelfLifeRequest shelfLifeRequest;
  10.     //图文信息
  11.     private List<ItemVideoImgRequest> itemVideoImgRequestList;
  12.     //销售信息
  13.     private ItemSaleRequest itemSaleRequest;
  14.     //推广信息
  15.     private ItemPopularizeRequest itemPopularizeRequest;
  16.     //操作人
  17.     @NotNull(message = "操作人[operateUser]不能为空")
  18.     private Integer operatorUser;
  19.     //商品基本信息
  20.     @Data
  21.     public static class ItemBaseRequest implements Serializable {
  22.         //商品ID
  23.         private String itemId;
  24.         //商品名称
  25.         private String itemName;
  26.         //渠道(1-每日生鲜、2-美团、3-饿了么、4-淘鲜达、5-招商银行)
  27.         private Integer channel;
  28.         //卖家类型(1-自营、2-POP)
  29.         private Integer sellerType;
  30.         //商品状态
  31.         private Integer itemStatus;
  32.         //商品类型
  33.         private Integer itemType;
  34.         //品牌ID
  35.         private Integer brandId;
  36.         //产地ID
  37.         private Integer producingAreaId;
  38.         //成本价(单位:分)
  39.         private Integer basePrice;
  40.         //末级品类ID
  41.         private Integer lastCategoryId;
  42.         //一级品类ID
  43.         private Integer oneCategoryId;
  44.         //二级品类ID
  45.         private Integer twoCategoryId;
  46.         //三级品类ID
  47.         private Integer threeCategoryId;
  48.     }
  49.     //存储信息
  50.     @Data
  51.     public static class ItemStorageRequest implements Serializable {
  52.         //存储条件
  53.         private Integer storeConditionType;
  54.         //ITEM维度规格值(多个规格集合):key=颜色,value=蓝色;key=颜色,value=红色;key=内存,value=128g;key=内存,value=256g
  55.         private List<ProductSpcesValue> productSpcesValueList;
  56.     }
  57.     //规格信息
  58.     @Data
  59.     public static class ProductSpcesValue implements Serializable {
  60.         //规格关键字
  61.         private String key;
  62.         //规格值
  63.         private String value;
  64.         //排序
  65.         private Integer sort;
  66.     }
  67.     //品控信息
  68.     @Data
  69.     public static class ShelfLifeRequest implements Serializable {
  70.     //保质期(单位:小时)
  71.     private Integer shelfLife;
  72.         //Map<key=保质期类型,value=保质期时间(单位:小时)>:acceptLife 允收期,shelfLife 货架期
  73.         private Map<String, Integer> shelfLifeMap;
  74.     }
  75.     //图文信息
  76.     @Data
  77.     public static class ItemVideoImgRequest implements Serializable {
  78.         //内容类型(1-主图,2-轮播图、3-详情图、4-视频)
  79.         private Integer contentType;
  80.         //链接地址
  81.         private String contentUrl;
  82.         //排序(正整数,数字越小越靠前)
  83.         private Integer contentSort;
  84.     }
  85.     //销售信息
  86.     @Data
  87.     public static class ItemSaleRequest implements Serializable {
  88.         //sku信息
  89.         private List<SkuInfoRequest> skuInfoRequestList;
  90.     }
  91.     //sku信息
  92.     @Data
  93.     public static class SkuInfoRequest implements Serializable {
  94.         //商品itemId
  95.         private String itemId;
  96.         //商品skuId
  97.         private String skuId;
  98.         //商品SKU名称
  99.         private String skuName;
  100.         //商城价
  101.         private Integer basePrice;
  102.         //会员价
  103.         private Integer vipPrice;
  104.         //商品分级(ABC标签,运营归类处理)
  105.         private Integer skuGrade;
  106.         //69码,条形码
  107.         private String barCode;
  108.         //SKU维度规格值(单个):key=颜色,value=蓝色;key=内存,value=128g
  109.         private List<ProductSpcesValue> productSpcesValueList;
  110.         //sku匹配的spu信息
  111.         private Long cspuId;
  112.     }
  113.     //推广信息
  114.     @Data
  115.     public static class ItemPopularizeRequest implements Serializable {
  116.         //推荐语
  117.         private String recommend;
  118.         //亮点
  119.         private List<HighlightsRequest> highlightsRequestList;
  120.         //卖点
  121.         private List<SellingPointRequest> sellingPointRequestList;
  122.         //质检报告
  123.         private List<QualityControlRequest> qualityControlRequestList;
  124.     }
  125.     //亮点
  126.     @Data
  127.     public static class HighlightsRequest implements Serializable {
  128.         //亮点文案
  129.         private String highlights;
  130.         //排序(正整数,数字越小越靠前)
  131.         private Integer sort;
  132.     }
  133.     //卖点
  134.     @Data
  135.     public static class SellingPointRequest implements Serializable {
  136.         //卖点文案
  137.         private String sellingPoint;
  138.         //排序(正整数,数字越小越靠前)
  139.         private Integer sort;
  140.     }
  141.     //质检报告
  142.     @Data
  143.     public static class QualityControlRequest implements Serializable {
  144.         //商品skuId
  145.         private String skuId;
  146.         //质检报告名称
  147.         private String qcName;
  148.         //材料图片链接
  149.         private String qcImgUrl;
  150.         //排序(正整数,数字越小越靠前)
  151.         private Integer qcSort;
  152.     }
  153. }
复制代码
 
6.商品B端—转换建品请求数据为商品模型数据
前端的建品请求数据比较复杂,需要和后端的商品模型数据匹配起来,所以需要进行数据转换。这种数据转换,通常会用Builder模式来实现。
  1. @Service
  2. public class ProductServiceImpl implements ProductService {
  3.     ...
  4.     //建品/编辑商品
  5.     @Transactional(rollbackFor = Exception.class)
  6.     @Override
  7.     @ParamsValidate
  8.     public ProductDTO product(ProductRequest productRequest) {
  9.         //入参检查
  10.         checkProductRequestParam(productRequest);
  11.         //商品数据处理
  12.         ProductDTO productDTO = handleProduct(productRequest);
  13.         //返回商品信息
  14.         return productDTO;
  15.     }
  16.     //建品/编辑商品入参检查
  17.     private void checkProductRequestParam(ProductRequest productRequest) {
  18.         ParamCheckUtil.checkObjectNonNull(productRequest);
  19.         //商品基本信息
  20.         ProductRequest.ItemBaseRequest itemBaseRequest = productRequest.getItemBaseRequest();
  21.         ParamCheckUtil.checkObjectNonNull(itemBaseRequest);
  22.         //存储信息
  23.         ProductRequest.ItemStorageRequest itemStorageRequest = productRequest.getItemStorageRequest();
  24.         ParamCheckUtil.checkObjectNonNull(itemStorageRequest);
  25.         //品控信息
  26.         ProductRequest.ShelfLifeRequest shelfLifeRequest = productRequest.getShelfLifeRequest();
  27.         ParamCheckUtil.checkObjectNonNull(shelfLifeRequest);
  28.         //图文信息
  29.         List<ProductRequest.ItemVideoImgRequest> itemVideoImgRequestList = productRequest.getItemVideoImgRequestList();
  30.         ParamCheckUtil.checkObjectNonNull(itemVideoImgRequestList);
  31.         //销售信息
  32.         ProductRequest.ItemSaleRequest itemSaleRequest = productRequest.getItemSaleRequest();
  33.         ParamCheckUtil.checkObjectNonNull(itemSaleRequest);
  34.         //推广信息
  35.         ProductRequest.ItemPopularizeRequest itemPopularizeRequest = productRequest.getItemPopularizeRequest();
  36.         ParamCheckUtil.checkObjectNonNull(itemPopularizeRequest);
  37.     }
  38.     //商品数据处理
  39.     private ProductDTO handleProduct(ProductRequest productRequest) {
  40.         //构建商品的全量信息
  41.         FullProductData fullProductData = buildProduct(productRequest);
  42.         //是否构建填充 itemId
  43.         Boolean createFlag = whetherBuildProductItemId(fullProductData);
  44.         //判断是否需要审核,根据配置的sku或者item或者品类信息,如果需要审核,只处理草稿表中的数据,正式表中的数据不动
  45.         if (productAuditRepository.needAudit(fullProductData, createFlag)) {
  46.             //需要审核,则正式表中的数据不变更,只新增草稿表记录
  47.             FullDraftData fullDraftData = buildDraft(fullProductData, AuditTypeEnum.GOODS.getCode());
  48.             //保存草稿信息
  49.             productAuditRepository.saveDraft(fullDraftData);
  50.             return new ProductDTO(null, null);
  51.         }
  52.         //如果不需要审核,则保存商品信息
  53.         this.saveOrUpdateDBProduct(fullProductData, createFlag);
  54.         //发送消息通知订阅方
  55.         sendUpdateProductMessage(fullProductData);
  56.         //返回商品返回结果
  57.         return new ProductDTO(fullProductData.getItemInfoDO().getItemId(), buildProductSkuIds(fullProductData));
  58.     }
  59.     //前端建品请求数据到后端商品数据模型的转换
  60.     private FullProductData buildProduct(ProductRequest productRequest) {
  61.         ProductBuilder productBuilder = new ProductBuilder(productRequest);
  62.         FullProductData fullProductData = productBuilder.buildItemInfo()
  63.             .buildItemShelfLife()
  64.             .buildItemVideoImgList()
  65.             .buildSkuInfoList()
  66.             .buildSkuBarCodeRelationList()
  67.             .buildCspuSkuRelation()
  68.             .buildAttributeExtend()
  69.             .buildQualityControl()
  70.             .build();
  71.         return fullProductData;
  72.     }
  73.     ...
  74. }
  75. //全量商品数据
  76. @Data
  77. @NoArgsConstructor
  78. @AllArgsConstructor
  79. public class FullProductData {
  80.     //ITEM信息
  81.     private ItemInfoDO itemInfoDO;
  82.     //保质期信息
  83.     private ItemShelfLifeDO itemShelfLifeDO;
  84.     //视频图片信息
  85.     private List<ItemVideoImgDO> itemVideoImgDOList;
  86.     //SKU信息
  87.     private List<SkuInfoDO> skuInfoDOList;
  88.     //69码关系
  89.     private List<SkuBarCodeRelationDO> skuBarCodeRelationDOList;
  90.     //CSPU与SKU关系
  91.     private List<CspuSkuRelationDO> cspuSkuRelationDOList;
  92.     //ITEM或SKU扩展属性
  93.     private AttributeExtendDO attributeExtendDO;
  94.     //品控信息
  95.     private List<QualityControlDO> qualityControlDOList;
  96.     public FullProductData(ItemInfoDO itemInfoDO, List<SkuInfoDO> skuInfoDOList) {
  97.         this.itemInfoDO = itemInfoDO;
  98.         this.skuInfoDOList = skuInfoDOList;
  99.     }
  100. }
  101. //全量商品数据
  102. public class ProductBuilder {
  103.     //商品入参
  104.     private ProductRequest productRequest;
  105.     //全量商品数据
  106.     private FullProductData fullProductData;
  107.     public ProductBuilder(ProductRequest productRequest) {
  108.         this.productRequest = productRequest;
  109.         this.fullProductData = new FullProductData();
  110.     }
  111.     public ProductBuilder buildItemInfo() {
  112.         ItemInfoDO itemInfoDO = new ItemInfoDO();
  113.         ProductRequest.ItemBaseRequest itemBaseRequest = productRequest.getItemBaseRequest();
  114.         itemInfoDO.setItemId(itemBaseRequest.getItemId());
  115.         itemInfoDO.setItemName(itemBaseRequest.getItemName());
  116.         ...
  117.         fullProductData.setItemInfoDO(itemInfoDO);
  118.         return this;
  119.     }
  120.     public ProductBuilder buildItemShelfLife() {
  121.         ItemShelfLifeDO itemShelfLifeDO = new ItemShelfLifeDO();
  122.         ProductRequest.ItemBaseRequest itemBaseRequest = productRequest.getItemBaseRequest();
  123.         ProductRequest.ShelfLifeRequest shelfLifeRequest = productRequest.getShelfLifeRequest();
  124.         itemShelfLifeDO.setItemId(itemBaseRequest.getItemId());
  125.         itemShelfLifeDO.setShelfLifeContent(JSON.toJSONString(shelfLifeRequest.getShelfLife()));
  126.         itemShelfLifeDO.setDelFlag(DelFlagEnum.EFFECTIVE.getCode());
  127.         ...
  128.         fullProductData.setItemShelfLifeDO(itemShelfLifeDO);
  129.         return this;
  130.     }
  131.     public ProductBuilder buildItemVideoImgList() {
  132.         List<ItemVideoImgDO> itemVideoImgDOList = new ArrayList<>(16);
  133.         ProductRequest.ItemBaseRequest itemBaseRequest = productRequest.getItemBaseRequest();
  134.         List<ProductRequest.ItemVideoImgRequest> itemVideoImgRequestList = productRequest.getItemVideoImgRequestList();
  135.         for (ProductRequest.ItemVideoImgRequest itemVideoImgRequest : itemVideoImgRequestList) {
  136.             ItemVideoImgDO itemVideoImgDO = new ItemVideoImgDO();
  137.             itemVideoImgDO.setItemId(itemBaseRequest.getItemId());
  138.             ...
  139.             itemVideoImgDOList.add(itemVideoImgDO);
  140.         }
  141.         fullProductData.setItemVideoImgDOList(itemVideoImgDOList);
  142.         return this;
  143.     }
  144.     public ProductBuilder buildSkuInfoList() {
  145.         List<SkuInfoDO> skuInfoDOList = new ArrayList<>(16);
  146.         ProductRequest.ItemBaseRequest itemBaseRequest = productRequest.getItemBaseRequest();
  147.         List<ProductRequest.SkuInfoRequest> skuInfoRequestList = productRequest.getItemSaleRequest().getSkuInfoRequestList();
  148.         for (ProductRequest.SkuInfoRequest skuInfoRequest : skuInfoRequestList) {
  149.             SkuInfoDO skuInfoDO = new SkuInfoDO();
  150.             skuInfoDO.setItemId(skuInfoRequest.getItemId());
  151.             skuInfoDO.setSkuId(skuInfoRequest.getSkuId());
  152.             skuInfoDO.setSkuName(skuInfoRequest.getSkuName());
  153.             ...
  154.             skuInfoDOList.add(skuInfoDO);
  155.         }
  156.         fullProductData.setSkuInfoDOList(skuInfoDOList);
  157.         return this;
  158.     }
  159.     public ProductBuilder buildSkuBarCodeRelationList() {
  160.         List<SkuBarCodeRelationDO> skuBarCodeRelationDOList = new ArrayList<>(16);
  161.         List<ProductRequest.SkuInfoRequest> skuInfoRequestList = productRequest.getItemSaleRequest().getSkuInfoRequestList();
  162.         for (ProductRequest.SkuInfoRequest skuInfoRequest : skuInfoRequestList) {
  163.             SkuBarCodeRelationDO skuBarCodeRelationDO = new SkuBarCodeRelationDO();
  164.             skuBarCodeRelationDO.setSkuId(skuInfoRequest.getSkuId());
  165.             skuBarCodeRelationDO.setBarCode(skuInfoRequest.getBarCode());
  166.             ...
  167.             skuBarCodeRelationDOList.add(skuBarCodeRelationDO);
  168.         }
  169.         fullProductData.setSkuBarCodeRelationDOList(skuBarCodeRelationDOList);
  170.         return this;
  171.     }
  172.     public ProductBuilder buildCspuSkuRelation() {
  173.         List<CspuSkuRelationDO> cspuSkuRelationDOList = new ArrayList<>(16);
  174.         ProductRequest.ItemBaseRequest itemBaseRequest = productRequest.getItemBaseRequest();
  175.         List<ProductRequest.SkuInfoRequest> skuInfoRequestList = productRequest.getItemSaleRequest().getSkuInfoRequestList();
  176.         for (ProductRequest.SkuInfoRequest skuInfoRequest : skuInfoRequestList) {
  177.             CspuSkuRelationDO cspuSkuRelationDO = new CspuSkuRelationDO();
  178.             cspuSkuRelationDO.setSkuId(skuInfoRequest.getSkuId());
  179.             cspuSkuRelationDO.setCspuId(skuInfoRequest.getCspuId());
  180.             ...
  181.             cspuSkuRelationDOList.add(cspuSkuRelationDO);
  182.         }
  183.         fullProductData.setCspuSkuRelationDOList(cspuSkuRelationDOList);
  184.         return this;
  185.     }
  186.     public ProductBuilder buildAttributeExtend() {
  187.         AttributeExtendDO attributeExtendDO = new AttributeExtendDO();
  188.         ProductRequest.ItemBaseRequest itemBaseRequest = productRequest.getItemBaseRequest();
  189.         ProductRequest.ItemPopularizeRequest itemPopularizeRequest = productRequest.getItemPopularizeRequest();
  190.         attributeExtendDO.setParticipateId(itemBaseRequest.getItemId());
  191.         ...
  192.         fullProductData.setAttributeExtendDO(attributeExtendDO);
  193.         return this;
  194.     }
  195.     public ProductBuilder buildQualityControl() {
  196.         List<QualityControlDO> qualityControlDOList = new ArrayList<>(16);
  197.         ProductRequest.ItemBaseRequest itemBaseRequest = productRequest.getItemBaseRequest();
  198.         ProductRequest.ItemPopularizeRequest itemPopularizeRequest = productRequest.getItemPopularizeRequest();
  199.         List<ProductRequest.QualityControlRequest> qualityControlRequestList = itemPopularizeRequest.getQualityControlRequestList();
  200.         for (ProductRequest.QualityControlRequest qualityControlRequest : qualityControlRequestList) {
  201.             QualityControlDO qualityControlDO = new QualityControlDO();
  202.             qualityControlDO.setItemId(itemBaseRequest.getItemId());
  203.             qualityControlDO.setSkuId(qualityControlRequest.getSkuId());
  204.             ...
  205.             qualityControlDOList.add(qualityControlDO);
  206.         }
  207.         fullProductData.setQualityControlDOList(qualityControlDOList);
  208.         return this;
  209.     }
  210.     public FullProductData build() {
  211.         return this.fullProductData;
  212.     }
  213. }
复制代码
 
7.商品B端—商品建品时商品编号补全与审核配置
  1. @Service
  2. public class ProductServiceImpl implements ProductService {
  3.     ...
  4.     //建品/编辑商品
  5.     @Transactional(rollbackFor = Exception.class)
  6.     @Override
  7.     @ParamsValidate
  8.     public ProductDTO product(ProductRequest productRequest) {
  9.         //入参检查
  10.         checkProductRequestParam(productRequest);
  11.         //商品数据处理
  12.         ProductDTO productDTO = handleProduct(productRequest);
  13.         //返回商品信息
  14.         return productDTO;
  15.     }
  16.     ...
  17.     //商品数据处理
  18.     private ProductDTO handleProduct(ProductRequest productRequest) {
  19.         //构建商品的全量信息
  20.         FullProductData fullProductData = buildProduct(productRequest);
  21.         //是否构建填充itemId
  22.         Boolean createFlag = whetherBuildProductItemId(fullProductData);
  23.         //判断是否需要审核,根据配置的sku或者item或者品类信息,如果需要审核,只处理草稿表中的数据,正式表中的数据不动
  24.         if (productAuditRepository.needAudit(fullProductData, createFlag)) {
  25.             //需要审核,则正式表中的数据不变更,只新增草稿表记录
  26.             FullDraftData fullDraftData = buildDraft(fullProductData, AuditTypeEnum.GOODS.getCode());
  27.             //保存草稿信息
  28.             productAuditRepository.saveDraft(fullDraftData);
  29.             return new ProductDTO(null, null);
  30.         }
  31.         //如果不需要审核,则保存商品信息
  32.         this.saveOrUpdateDBProduct(fullProductData, createFlag);
  33.         //发送消息通知订阅方
  34.         sendUpdateProductMessage(fullProductData);
  35.         //返回商品返回结果
  36.         return new ProductDTO(fullProductData.getItemInfoDO().getItemId(), buildProductSkuIds(fullProductData));
  37.     }
  38.     //是否需要构建商品的ItemId
  39.     private Boolean whetherBuildProductItemId(FullProductData fullProductData) {
  40.         //ITEM信息
  41.         ItemInfoDO itemInfoDO = fullProductData.getItemInfoDO();
  42.         //新增
  43.         if (StringUtils.isEmpty(itemInfoDO.getItemId())) {
  44.             //保质期
  45.             ItemShelfLifeDO itemShelfLifeDO = fullProductData.getItemShelfLifeDO();
  46.             //生成Item的Id
  47.             String itemId = createItemId();
  48.             //赋值itemId
  49.             itemInfoDO.setItemId(itemId);
  50.             itemShelfLifeDO.setItemId(itemId);
  51.             //SKU信息
  52.             List<SkuInfoDO> skuInfoDOList = fullProductData.getSkuInfoDOList();
  53.             for (SkuInfoDO skuInfoDO : skuInfoDOList) {
  54.                 //对每个SKU也生成ID
  55.                 String skuId = productNoManager.generateProductNo(ProductTypeEnum.SKU.getCode());
  56.                 skuInfoDO.setSkuId(skuId);
  57.                 skuInfoDO.setItemId(itemId);
  58.             }
  59.             //视频图片
  60.             List<ItemVideoImgDO> itemVideoImgDOList = fullProductData.getItemVideoImgDOList();
  61.             for (ItemVideoImgDO itemVideoImgDO : itemVideoImgDOList) {
  62.                 itemVideoImgDO.setItemId(itemId);
  63.             }
  64.             //属性扩展
  65.             AttributeExtendDO attributeExtendDO = fullProductData.getAttributeExtendDO();
  66.             attributeExtendDO.setParticipateId(itemInfoDO.getItemId());
  67.             attributeExtendDO.setParticipateType(ProductTypeEnum.ITEM.getCode());
  68.             return true;
  69.         }
  70.         return false;
  71.     }
  72.     //创建ItemId
  73.     private String createItemId() {
  74.         String itemId = productNoManager.generateProductNo(ProductTypeEnum.ITEM.getCode());
  75.         return itemId;
  76.     }
  77.     ...
  78. }
  79. //商品审核 资源管理
  80. @Repository
  81. public class ProductAuditRepository {
  82.     ...
  83.     //验证是否需要审核
  84.     public Boolean needAudit(FullProductData fullProductData, Boolean createFlag) {
  85.         ItemInfoDO itemInfoDO = fullProductData.getItemInfoDO();
  86.         Integer count = 0;
  87.         if (!createFlag) {
  88.             //1.首先判断 商品审核内容配置表 中是否有对应的skuId
  89.             List<String> skuIds = fullProductData.getSkuInfoDOList().stream().map(SkuInfoDO::getSkuId).collect(Collectors.toList());
  90.             count = countByCustomIds(skuIds, AuditCustomTypeEnum.SKU);
  91.             if (count > 0) {
  92.                 return true;
  93.             }
  94.             //2.是否有对应的item
  95.             count = countByCustomIds(Collections.singletonList(itemInfoDO.getItemId()), AuditCustomTypeEnum.ITEM);
  96.             if (count > 0) {
  97.                 return true;
  98.             }
  99.         }
  100.         //3.验证是否有对应的categoryId
  101.         List<Integer> categoryIds = Arrays.asList(itemInfoDO.getFirstCategoryId(), itemInfoDO.getSecondCategoryId(), itemInfoDO.getThirdCategoryId());
  102.         count = countByCustomIds(categoryIds, AuditCustomTypeEnum.CATEGORY);
  103.         //当商品审核内容配置表中有相应的品类数据,则需要审核,否则不需要审核
  104.         return count > 0;
  105.     }
  106.     ...
  107. }
复制代码
 
8.商品B端—商品审核前的草稿数据保存逻辑
[code]@Servicepublic class ProductServiceImpl implements ProductService {    ...    //建品/编辑商品    @Transactional(rollbackFor = Exception.class)    @Override    @ParamsValidate    public ProductDTO product(ProductRequest productRequest) {        //入参检查        checkProductRequestParam(productRequest);        //商品数据处理        ProductDTO productDTO = handleProduct(productRequest);        //返回商品信息        return productDTO;    }    ...    //商品数据处理    private ProductDTO handleProduct(ProductRequest productRequest) {        //构建商品的全量信息        FullProductData fullProductData = buildProduct(productRequest);        //是否构建填充itemId        Boolean createFlag = whetherBuildProductItemId(fullProductData);        //判断是否需要审核,根据配置的sku或者item或者品类信息,如果需要审核,只处理草稿表中的数据,正式表中的数据不动        if (productAuditRepository.needAudit(fullProductData, createFlag)) {            //需要审核,则正式表中的数据不变更,只新增草稿表记录            FullDraftData fullDraftData = buildDraft(fullProductData, AuditTypeEnum.GOODS.getCode());            //保存草稿信息            productAuditRepository.saveDraft(fullDraftData);            return new ProductDTO(null, null);        }        //如果不需要审核,则保存商品信息        this.saveOrUpdateDBProduct(fullProductData, createFlag);        //发送消息通知订阅方        sendUpdateProductMessage(fullProductData);        //返回商品返回结果        return new ProductDTO(fullProductData.getItemInfoDO().getItemId(), buildProductSkuIds(fullProductData));    }    ...    //根据商品数据构建商品草稿数据    private FullDraftData buildDraft(FullProductData fullProductData, Integer auditType) {        ProductDraftBuilder productDraftBuilder = new ProductDraftBuilder(fullProductData);        FullDraftData fullDraftData = productDraftBuilder.buildDraftMain(auditType)            .buildDraftImgList()            .build();        return fullDraftData;    }    ...}//商品审核 资源管理@Repositorypublic class ProductAuditRepository {    ...    //保存草稿信息    public void saveDraft(FullDraftData fullDraftData) {        //1.保存工单信息        AuditInfoDO auditInfoDO = saveAudit(fullDraftData);        //2.保存工单审核历史信息        saveAuditHistory(auditInfoDO);        //3.保存草稿信息        saveDraftMain(fullDraftData, auditInfoDO.getId());        //4.保存草稿图片信息        saveDraftImgBatch(fullDraftData);    }    //保存工单信息    private AuditInfoDO saveAudit(FullDraftData fullDraftData) {        AuditInfoDO auditInfoDO = auditConverter.converterDO(fullDraftData.getDraftMainDO());        auditInfoDO.initCommon();        int count = auditInfoMapper.insert(auditInfoDO);        if (count
您需要登录后才可以回帖 登录 | 立即注册