wwh 2 тижнів тому
батько
коміт
a5c4cecccd

+ 2 - 0
baqing-shop/src/main/java/com/ruoyi/web/modules/goods/constant/GoodsConstants.java

@@ -51,6 +51,8 @@ public final class GoodsConstants
51 51
 
52 52
     public static final String MSG_SHOP_CATEGORY_INVALID = "请选择本店店铺商品二级分类";
53 53
 
54
+    public static final String MSG_ATTR_TEMPLATE_INVALID = "请选择本店有效属性模版";
55
+
54 56
     public static final String MSG_DELETE_INVALID = "当前状态不可删除";
55 57
 
56 58
     public static final String MSG_UNFINISHED_ORDER = "该商品存在未完成订单,无法下架";

+ 12 - 0
baqing-shop/src/main/java/com/ruoyi/web/modules/goods/domain/BizGoods.java

@@ -19,6 +19,8 @@ public class BizGoods extends BaseEntity
19 19
 
20 20
     private Long shopCategoryId;
21 21
 
22
+    private Long attrTemplateId;
23
+
22 24
     private String goodsSn;
23 25
 
24 26
     private String goodsName;
@@ -92,6 +94,16 @@ public class BizGoods extends BaseEntity
92 94
         this.shopCategoryId = shopCategoryId;
93 95
     }
94 96
 
97
+    public Long getAttrTemplateId()
98
+    {
99
+        return attrTemplateId;
100
+    }
101
+
102
+    public void setAttrTemplateId(Long attrTemplateId)
103
+    {
104
+        this.attrTemplateId = attrTemplateId;
105
+    }
106
+
95 107
     public String getGoodsSn()
96 108
     {
97 109
         return goodsSn;

+ 13 - 0
baqing-shop/src/main/java/com/ruoyi/web/modules/goods/dto/GoodsSaveDTO.java

@@ -15,6 +15,9 @@ public class GoodsSaveDTO
15 15
     /** 店铺商品分类(本店二级,可选) */
16 16
     private Long shopCategoryId;
17 17
 
18
+    /** 属性模版(可选,用于删模版校验与编辑回显) */
19
+    private Long attrTemplateId;
20
+
18 21
     private String goodsName;
19 22
 
20 23
     private String mainPic;
@@ -60,6 +63,16 @@ public class GoodsSaveDTO
60 63
         this.shopCategoryId = shopCategoryId;
61 64
     }
62 65
 
66
+    public Long getAttrTemplateId()
67
+    {
68
+        return attrTemplateId;
69
+    }
70
+
71
+    public void setAttrTemplateId(Long attrTemplateId)
72
+    {
73
+        this.attrTemplateId = attrTemplateId;
74
+    }
75
+
63 76
     public String getGoodsName()
64 77
     {
65 78
         return goodsName;

+ 30 - 0
baqing-shop/src/main/java/com/ruoyi/web/modules/goods/service/impl/GoodsServiceImpl.java

@@ -45,6 +45,8 @@ import com.ruoyi.web.modules.store.constant.ShopConstants;
45 45
 import com.ruoyi.web.modules.store.domain.BizShop;
46 46
 import com.ruoyi.web.modules.store.facade.IShopGlobalConfigFacade;
47 47
 import com.ruoyi.web.modules.store.mapper.BizShopMapper;
48
+import com.ruoyi.web.modules.template.domain.BizGoodsAttrTemplate;
49
+import com.ruoyi.web.modules.template.mapper.BizGoodsAttrTemplateMapper;
48 50
 
49 51
 @Service
50 52
 public class GoodsServiceImpl implements IGoodsService
@@ -82,6 +84,9 @@ public class GoodsServiceImpl implements IGoodsService
82 84
     @Autowired
83 85
     private IGoodsOrderFacade goodsOrderFacade;
84 86
 
87
+    @Autowired
88
+    private BizGoodsAttrTemplateMapper attrTemplateMapper;
89
+
85 90
     @Override
86 91
     public List<GoodsListVO> selectPlatformList(BizGoods query)
87 92
     {
@@ -135,6 +140,7 @@ public class GoodsServiceImpl implements IGoodsService
135 140
         validateSaveFields(dto, true);
136 141
         assertPlatformCategoryLevel2(dto.getCategoryId());
137 142
         assertShopCategoryIfPresent(shopId, dto.getShopCategoryId());
143
+        assertAttrTemplateIfPresent(shopId, dto.getAttrTemplateId());
138 144
         BizGoods goods = buildGoodsFromDto(dto);
139 145
         goods.setShopId(shopId);
140 146
         goods.setGoodsSn(goodsSnGenerator.nextSn());
@@ -164,6 +170,7 @@ public class GoodsServiceImpl implements IGoodsService
164 170
             assertPlatformCategoryLevel2(dto.getCategoryId());
165 171
         }
166 172
         assertShopCategoryIfPresent(shopId, dto.getShopCategoryId());
173
+        assertAttrTemplateIfPresent(shopId, dto.getAttrTemplateId());
167 174
         BizGoods update = buildGoodsFromDto(dto);
168 175
         update.setGoodsId(dto.getGoodsId());
169 176
         update.setUpdateBy(operator);
@@ -403,6 +410,7 @@ public class GoodsServiceImpl implements IGoodsService
403 410
         vo.setShopId(goods.getShopId());
404 411
         vo.setCategoryId(goods.getCategoryId());
405 412
         vo.setShopCategoryId(goods.getShopCategoryId());
413
+        vo.setAttrTemplateId(goods.getAttrTemplateId());
406 414
         vo.setGoodsSn(goods.getGoodsSn());
407 415
         vo.setGoodsName(goods.getGoodsName());
408 416
         vo.setMainPic(goods.getMainPic());
@@ -421,6 +429,14 @@ public class GoodsServiceImpl implements IGoodsService
421 429
         {
422 430
             vo.setShopCategoryPath(categoryFacade.getCategoryPath(goods.getShopCategoryId()));
423 431
         }
432
+        if (goods.getAttrTemplateId() != null)
433
+        {
434
+            BizGoodsAttrTemplate template = attrTemplateMapper.selectById(goods.getAttrTemplateId(), goods.getShopId());
435
+            if (template != null)
436
+            {
437
+                vo.setAttrTemplateName(template.getTemplateName());
438
+            }
439
+        }
424 440
         vo.setCanAudit(GoodsConstants.STATUS_PENDING.equals(goods.getGoodsStatus()));
425 441
         vo.setCanOffShelf(GoodsConstants.STATUS_ON_SALE.equals(goods.getGoodsStatus()));
426 442
         vo.setCanSubmit(canSubmitStatus(goods.getGoodsStatus()));
@@ -513,6 +529,7 @@ public class GoodsServiceImpl implements IGoodsService
513 529
         BizGoods goods = new BizGoods();
514 530
         goods.setCategoryId(dto.getCategoryId());
515 531
         goods.setShopCategoryId(dto.getShopCategoryId());
532
+        goods.setAttrTemplateId(dto.getAttrTemplateId());
516 533
         goods.setGoodsName(dto.getGoodsName());
517 534
         goods.setMainPic(dto.getMainPic());
518 535
         goods.setDetailContent(dto.getDetailContent());
@@ -589,6 +606,19 @@ public class GoodsServiceImpl implements IGoodsService
589 606
         }
590 607
     }
591 608
 
609
+    private void assertAttrTemplateIfPresent(Long shopId, Long attrTemplateId)
610
+    {
611
+        if (attrTemplateId == null)
612
+        {
613
+            return;
614
+        }
615
+        BizGoodsAttrTemplate template = attrTemplateMapper.selectById(attrTemplateId, shopId);
616
+        if (template == null)
617
+        {
618
+            throw new ServiceException(GoodsConstants.MSG_ATTR_TEMPLATE_INVALID);
619
+        }
620
+    }
621
+
592 622
     private boolean canSubmitStatus(String status)
593 623
     {
594 624
         return GoodsConstants.STATUS_DRAFT.equals(status)

+ 24 - 0
baqing-shop/src/main/java/com/ruoyi/web/modules/goods/vo/GoodsDetailVO.java

@@ -18,6 +18,10 @@ public class GoodsDetailVO extends GoodsListVO
18 18
 
19 19
     private String shopCategoryPath;
20 20
 
21
+    private Long attrTemplateId;
22
+
23
+    private String attrTemplateName;
24
+
21 25
     private String detailContent;
22 26
 
23 27
     private String rejectReason;
@@ -80,6 +84,26 @@ public class GoodsDetailVO extends GoodsListVO
80 84
         this.shopCategoryPath = shopCategoryPath;
81 85
     }
82 86
 
87
+    public Long getAttrTemplateId()
88
+    {
89
+        return attrTemplateId;
90
+    }
91
+
92
+    public void setAttrTemplateId(Long attrTemplateId)
93
+    {
94
+        this.attrTemplateId = attrTemplateId;
95
+    }
96
+
97
+    public String getAttrTemplateName()
98
+    {
99
+        return attrTemplateName;
100
+    }
101
+
102
+    public void setAttrTemplateName(String attrTemplateName)
103
+    {
104
+        this.attrTemplateName = attrTemplateName;
105
+    }
106
+
83 107
     public String getDetailContent()
84 108
     {
85 109
         return detailContent;

+ 5 - 3
baqing-shop/src/main/resources/mapper/goods/BizGoodsMapper.xml

@@ -7,6 +7,7 @@
7 7
         <result property="shopId" column="shop_id"/>
8 8
         <result property="categoryId" column="category_id"/>
9 9
         <result property="shopCategoryId" column="shop_category_id"/>
10
+        <result property="attrTemplateId" column="attr_template_id"/>
10 11
         <result property="goodsSn" column="goods_sn"/>
11 12
         <result property="goodsName" column="goods_name"/>
12 13
         <result property="mainPic" column="main_pic"/>
@@ -28,7 +29,7 @@
28 29
     </resultMap>
29 30
 
30 31
     <sql id="selectGoodsVo">
31
-        select goods_id, shop_id, category_id, shop_category_id, goods_sn, goods_name, main_pic, detail_content,
32
+        select goods_id, shop_id, category_id, shop_category_id, attr_template_id, goods_sn, goods_name, main_pic, detail_content,
32 33
                sale_price, stock, sales_count, goods_status, reject_reason, submit_time, audit_time,
33 34
                off_shelf_time, del_flag, create_by, create_time, update_by, update_time, remark
34 35
         from biz_goods
@@ -149,10 +150,10 @@
149 150
 
150 151
     <insert id="insert" useGeneratedKeys="true" keyProperty="goodsId">
151 152
         insert into biz_goods (
152
-            shop_id, category_id, shop_category_id, goods_sn, goods_name, main_pic, detail_content,
153
+            shop_id, category_id, shop_category_id, attr_template_id, goods_sn, goods_name, main_pic, detail_content,
153 154
             sale_price, stock, sales_count, goods_status, del_flag, create_by, create_time
154 155
         ) values (
155
-            #{shopId}, #{categoryId}, #{shopCategoryId}, #{goodsSn}, #{goodsName}, #{mainPic}, #{detailContent},
156
+            #{shopId}, #{categoryId}, #{shopCategoryId}, #{attrTemplateId}, #{goodsSn}, #{goodsName}, #{mainPic}, #{detailContent},
156 157
             #{salePrice}, #{stock}, #{salesCount}, #{goodsStatus}, #{delFlag}, #{createBy}, sysdate()
157 158
         )
158 159
     </insert>
@@ -162,6 +163,7 @@
162 163
         <set>
163 164
             <if test="categoryId != null">category_id = #{categoryId},</if>
164 165
             <if test="shopCategoryId != null">shop_category_id = #{shopCategoryId},</if>
166
+            <if test="attrTemplateId != null">attr_template_id = #{attrTemplateId},</if>
165 167
             <if test="goodsName != null">goods_name = #{goodsName},</if>
166 168
             <if test="mainPic != null">main_pic = #{mainPic},</if>
167 169
             <if test="detailContent != null">detail_content = #{detailContent},</if>

+ 61 - 0
baqing-shop/src/test/java/com/ruoyi/web/modules/goods/service/GoodsServiceImplTest.java

@@ -8,6 +8,7 @@ import static org.mockito.ArgumentMatchers.eq;
8 8
 import static org.mockito.Mockito.never;
9 9
 import static org.mockito.Mockito.verify;
10 10
 import static org.mockito.Mockito.when;
11
+import org.mockito.ArgumentCaptor;
11 12
 import java.math.BigDecimal;
12 13
 import java.util.Arrays;
13 14
 import java.util.Collections;
@@ -42,6 +43,8 @@ import com.ruoyi.web.modules.store.constant.ShopConstants;
42 43
 import com.ruoyi.web.modules.store.domain.BizShop;
43 44
 import com.ruoyi.web.modules.store.facade.IShopGlobalConfigFacade;
44 45
 import com.ruoyi.web.modules.store.mapper.BizShopMapper;
46
+import com.ruoyi.web.modules.template.domain.BizGoodsAttrTemplate;
47
+import com.ruoyi.web.modules.template.mapper.BizGoodsAttrTemplateMapper;
45 48
 
46 49
 @ExtendWith(MockitoExtension.class)
47 50
 class GoodsServiceImplTest
@@ -79,6 +82,9 @@ class GoodsServiceImplTest
79 82
     @Mock
80 83
     private IGoodsOrderFacade goodsOrderFacade;
81 84
 
85
+    @Mock
86
+    private BizGoodsAttrTemplateMapper attrTemplateMapper;
87
+
82 88
     @InjectMocks
83 89
     private GoodsServiceImpl goodsService;
84 90
 
@@ -378,6 +384,61 @@ class GoodsServiceImplTest
378 384
         assertTrue(ex.getMessage().contains("店铺商品二级分类"));
379 385
     }
380 386
 
387
+    @Test
388
+    void insert_withAttrTemplate_persistsTemplateId()
389
+    {
390
+        when(goodsSnGenerator.nextSn()).thenReturn("G20260526000003");
391
+        BizGoodsCategory platformCat = new BizGoodsCategory();
392
+        platformCat.setCategoryLevel(CategoryConstants.LEVEL_TWO);
393
+        when(categoryMapper.selectById(100L, null)).thenReturn(platformCat);
394
+        BizGoodsAttrTemplate template = new BizGoodsAttrTemplate();
395
+        template.setTemplateId(4L);
396
+        when(attrTemplateMapper.selectById(4L, 10L)).thenReturn(template);
397
+        when(goodsMapper.insert(any())).thenAnswer(inv -> {
398
+            BizGoods g = inv.getArgument(0);
399
+            g.setGoodsId(101L);
400
+            return 1;
401
+        });
402
+
403
+        GoodsSaveDTO dto = new GoodsSaveDTO();
404
+        dto.setCategoryId(100L);
405
+        dto.setAttrTemplateId(4L);
406
+        dto.setGoodsName("复合肥");
407
+        dto.setMainPic("/a.jpg");
408
+        dto.setDetailContent("detail");
409
+        dto.setSalePrice(new BigDecimal("10"));
410
+        dto.setStock(5);
411
+
412
+        goodsService.insertSellerGoods(10L, dto, "seller");
413
+
414
+        ArgumentCaptor<BizGoods> captor = ArgumentCaptor.forClass(BizGoods.class);
415
+        verify(goodsMapper).insert(captor.capture());
416
+        assertEquals(4L, captor.getValue().getAttrTemplateId());
417
+    }
418
+
419
+    @Test
420
+    void insert_invalidAttrTemplate_fails()
421
+    {
422
+        BizGoodsCategory platformCat = new BizGoodsCategory();
423
+        platformCat.setCategoryLevel(CategoryConstants.LEVEL_TWO);
424
+        when(categoryMapper.selectById(100L, null)).thenReturn(platformCat);
425
+        when(attrTemplateMapper.selectById(999L, 10L)).thenReturn(null);
426
+
427
+        GoodsSaveDTO dto = new GoodsSaveDTO();
428
+        dto.setCategoryId(100L);
429
+        dto.setAttrTemplateId(999L);
430
+        dto.setGoodsName("复合肥");
431
+        dto.setMainPic("/a.jpg");
432
+        dto.setDetailContent("detail");
433
+        dto.setSalePrice(new BigDecimal("10"));
434
+        dto.setStock(5);
435
+
436
+        ServiceException ex = assertThrows(ServiceException.class,
437
+                () -> goodsService.insertSellerGoods(10L, dto, "seller"));
438
+        assertTrue(ex.getMessage().contains("属性模版"));
439
+        verify(goodsMapper, never()).insert(any());
440
+    }
441
+
381 442
     @Test
382 443
     void delete_draft_success()
383 444
     {

+ 2 - 0
sql/biz_goods.sql

@@ -4,6 +4,7 @@ CREATE TABLE IF NOT EXISTS `biz_goods` (
4 4
   `shop_id` bigint(20) NOT NULL COMMENT '店铺ID',
5 5
   `category_id` bigint(20) NOT NULL COMMENT '平台端二级分类ID',
6 6
   `shop_category_id` bigint(20) DEFAULT NULL COMMENT '店铺商品分类ID(本店二级)',
7
+  `attr_template_id` bigint(20) DEFAULT NULL COMMENT '属性模版ID',
7 8
   `goods_sn` varchar(32) NOT NULL COMMENT '商品编号',
8 9
   `goods_name` varchar(200) NOT NULL COMMENT '商品名称',
9 10
   `main_pic` varchar(512) NOT NULL COMMENT '主图',
@@ -27,6 +28,7 @@ CREATE TABLE IF NOT EXISTS `biz_goods` (
27 28
   KEY `idx_shop_status` (`shop_id`,`goods_status`,`del_flag`),
28 29
   KEY `idx_category_id` (`category_id`,`del_flag`),
29 30
   KEY `idx_shop_category_id` (`shop_category_id`,`del_flag`),
31
+  KEY `idx_attr_template_id` (`attr_template_id`,`del_flag`),
30 32
   KEY `idx_submit_time` (`submit_time`)
31 33
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品';
32 34