Browse Source

全量进货接口

zhangwl 1 month ago
parent
commit
9c9dc8eb65
27 changed files with 1373 additions and 7 deletions
  1. 34 0
      src/main/java/zs/payment/controller/EweiShopGoodsController.java
  2. 27 0
      src/main/java/zs/payment/dto/yunmall/CategoryResolveResult.java
  3. 16 0
      src/main/java/zs/payment/dto/yunmall/CloudMallAttr.java
  4. 13 0
      src/main/java/zs/payment/dto/yunmall/CloudMallAttrValue.java
  5. 24 0
      src/main/java/zs/payment/dto/yunmall/CloudMallGoods.java
  6. 19 0
      src/main/java/zs/payment/dto/yunmall/CloudMallGoodsBody.java
  7. 13 0
      src/main/java/zs/payment/dto/yunmall/CloudMallHead.java
  8. 12 0
      src/main/java/zs/payment/dto/yunmall/CloudMallImg.java
  9. 13 0
      src/main/java/zs/payment/dto/yunmall/CloudMallNormalAttr.java
  10. 13 0
      src/main/java/zs/payment/dto/yunmall/CloudMallResponse.java
  11. 13 0
      src/main/java/zs/payment/dto/yunmall/CloudMallShop.java
  12. 21 0
      src/main/java/zs/payment/dto/yunmall/CloudMallSku.java
  13. 15 1
      src/main/java/zs/payment/entity/mongodb/yunmall/Sku.java
  14. 244 0
      src/main/java/zs/payment/entity/mysql/ImsEweiShopApply.java
  15. 37 0
      src/main/java/zs/payment/entity/mysql/ImsEweiShopGoodsParam.java
  16. 9 0
      src/main/java/zs/payment/mapper/primary/ImsEweiShopApplyMapper.java
  17. 5 0
      src/main/java/zs/payment/mapper/primary/ImsEweiShopGoodsMapper.java
  18. 9 0
      src/main/java/zs/payment/mapper/primary/ImsEweiShopGoodsParamMapper.java
  19. 37 6
      src/main/java/zs/payment/messages/KafkaConsumer.java
  20. 36 0
      src/main/java/zs/payment/req/CommodityProcureReq.java
  21. 5 0
      src/main/java/zs/payment/service/Imseweishopgoods/ImsEweiShopGoodsService.java
  22. 10 0
      src/main/java/zs/payment/service/Imseweishopgoods/impl/ImsEweiShopGoodsServiceImpl.java
  23. 25 0
      src/main/java/zs/payment/service/commodity/CommodityProcureService.java
  24. 696 0
      src/main/java/zs/payment/service/commodity/impl/CommodityProcureServiceImpl.java
  25. 7 0
      src/main/java/zs/payment/service/imseweishopgoodsparam/ImsEweiShopGoodsParamService.java
  26. 12 0
      src/main/java/zs/payment/service/imseweishopgoodsparam/impl/ImsEweiShopGoodsParamServiceImpl.java
  27. 8 0
      src/main/resources/mapper/primary/ImsEweiShopGoodsMapper.xml

+ 34 - 0
src/main/java/zs/payment/controller/EweiShopGoodsController.java

@@ -0,0 +1,34 @@
+package zs.payment.controller;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import zs.payment.exception.ApiException;
+import zs.payment.req.CommodityProcureReq;
+import zs.payment.resp.Result;
+import zs.payment.service.commodity.CommodityProcureService;
+
+import javax.validation.Valid;
+
+@Slf4j
+@RestController
+@RequestMapping("/shopgoods")
+public class EweiShopGoodsController {
+
+    @Autowired
+    private CommodityProcureService commodityProcureService;
+
+    /**
+     * 进货:把云商城(悦店管理)里的商品全进货到本地
+     *
+     */
+    @PostMapping("/fullAdd")
+    public Result fullAdd(@Valid @RequestBody CommodityProcureReq req) {
+        try {
+            return commodityProcureService.procureGoods(req);
+        } catch (ApiException e) {
+            return Result.fail(e.getMsg());
+        }
+    }
+
+}

+ 27 - 0
src/main/java/zs/payment/dto/yunmall/CategoryResolveResult.java

@@ -0,0 +1,27 @@
+package zs.payment.dto.yunmall;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.List;
+
+@Setter
+@Getter
+@NoArgsConstructor
+public class CategoryResolveResult {
+    /** 第一个分类的一级分类ID */
+    private Long pcate;
+    /** 第一个分类的二级分类ID */
+    private Long ccate;
+    /** 第一个分类的三级分类ID */
+    private Long tcate;
+    /** 所有选中的分类ID */
+    private List<Long> cates;
+    /** 所有一级分类ID */
+    private List<Long> pcates;
+    /** 所有二级分类ID */
+    private List<Long> ccates;
+    /** 所有三级分类ID */
+    private List<Long> tcates;
+}

+ 16 - 0
src/main/java/zs/payment/dto/yunmall/CloudMallAttr.java

@@ -0,0 +1,16 @@
+package zs.payment.dto.yunmall;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.List;
+
+@Setter
+@Getter
+@NoArgsConstructor
+public class CloudMallAttr {
+    private Integer attr_id;
+    private String attr_name;
+    private List<CloudMallAttrValue> values;
+}

+ 13 - 0
src/main/java/zs/payment/dto/yunmall/CloudMallAttrValue.java

@@ -0,0 +1,13 @@
+package zs.payment.dto.yunmall;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Setter
+@Getter
+@NoArgsConstructor
+public class CloudMallAttrValue {
+    private Integer attr_val_id;
+    private String attr_val_name;
+}

+ 24 - 0
src/main/java/zs/payment/dto/yunmall/CloudMallGoods.java

@@ -0,0 +1,24 @@
+package zs.payment.dto.yunmall;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+@Setter
+@Getter
+@NoArgsConstructor
+public class CloudMallGoods {
+    private String gd_name;
+    private String unit;
+    private BigDecimal weight;
+    private String desc;
+    /** 分佣比例(%) */
+    private BigDecimal statement_rate;
+    /** 推广分佣比例(%) */
+    private BigDecimal tg_statement_rate;
+    private List<CloudMallImg> imgsInfo;
+    private CloudMallShop shop;
+}

+ 19 - 0
src/main/java/zs/payment/dto/yunmall/CloudMallGoodsBody.java

@@ -0,0 +1,19 @@
+package zs.payment.dto.yunmall;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.List;
+import java.util.Map;
+
+@Setter
+@Getter
+@NoArgsConstructor
+public class CloudMallGoodsBody {
+    private CloudMallGoods goods;
+    private List<CloudMallAttr> attrList;
+    private List<CloudMallNormalAttr> nomalattrList;
+    /** key: 规格项ID组合(如 "123_456_sku"), value: SKU详情 */
+    private Map<String, CloudMallSku> skuList;
+}

+ 13 - 0
src/main/java/zs/payment/dto/yunmall/CloudMallHead.java

@@ -0,0 +1,13 @@
+package zs.payment.dto.yunmall;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Setter
+@Getter
+@NoArgsConstructor
+public class CloudMallHead {
+    private Integer status;
+    private String message;
+}

+ 12 - 0
src/main/java/zs/payment/dto/yunmall/CloudMallImg.java

@@ -0,0 +1,12 @@
+package zs.payment.dto.yunmall;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Setter
+@Getter
+@NoArgsConstructor
+public class CloudMallImg {
+    private String imgUrl;
+}

+ 13 - 0
src/main/java/zs/payment/dto/yunmall/CloudMallNormalAttr.java

@@ -0,0 +1,13 @@
+package zs.payment.dto.yunmall;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Setter
+@Getter
+@NoArgsConstructor
+public class CloudMallNormalAttr {
+    private String attr_name;
+    private String attr_val_name;
+}

+ 13 - 0
src/main/java/zs/payment/dto/yunmall/CloudMallResponse.java

@@ -0,0 +1,13 @@
+package zs.payment.dto.yunmall;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Setter
+@Getter
+@NoArgsConstructor
+public class CloudMallResponse {
+    private CloudMallHead head;
+    private CloudMallGoodsBody body;
+}

+ 13 - 0
src/main/java/zs/payment/dto/yunmall/CloudMallShop.java

@@ -0,0 +1,13 @@
+package zs.payment.dto.yunmall;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Setter
+@Getter
+@NoArgsConstructor
+public class CloudMallShop {
+    private Integer shop_id;
+    private String shop_name;
+}

+ 21 - 0
src/main/java/zs/payment/dto/yunmall/CloudMallSku.java

@@ -0,0 +1,21 @@
+package zs.payment.dto.yunmall;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+@Setter
+@Getter
+@NoArgsConstructor
+public class CloudMallSku {
+    private Integer sku_id;
+    private BigDecimal sku_price;
+    private BigDecimal mk_price;
+    /** 供货价,可能为null */
+    private BigDecimal cost_price;
+    private Integer stock;
+    private String sku_img;
+    private String attr_val_name_str;
+}

+ 15 - 1
src/main/java/zs/payment/entity/mongodb/yunmall/Sku.java

@@ -6,6 +6,8 @@ import lombok.Setter;
 import lombok.experimental.Accessors;
 import lombok.experimental.Accessors;
 import zs.payment.entity.mysql.flymall.B2cGoodsSkuInOnline;
 import zs.payment.entity.mysql.flymall.B2cGoodsSkuInOnline;
 
 
+import java.util.List;
+
 @Setter
 @Setter
 @Getter
 @Getter
 @NoArgsConstructor
 @NoArgsConstructor
@@ -13,9 +15,21 @@ import zs.payment.entity.mysql.flymall.B2cGoodsSkuInOnline;
 public class Sku {
 public class Sku {
     Integer sku_id;
     Integer sku_id;
     String sku_img;
     String sku_img;
+    List<SkuAttr> attrs;
 
 
 
 
-    public static Sku ofArticle(B2cGoodsSkuInOnline goodsSku,String sku_img){
+    public static Sku ofArticle(B2cGoodsSkuInOnline goodsSku, String sku_img){
         return new Sku().setSku_id(goodsSku.getSkuId()).setSku_img(sku_img);
         return new Sku().setSku_id(goodsSku.getSkuId()).setSku_img(sku_img);
     }
     }
+
+    @Setter
+    @Getter
+    @NoArgsConstructor
+    @Accessors(chain = true)
+    public static class SkuAttr {
+        Integer attr_id;
+        String attr_name;
+        Integer attr_val_id;
+        String attr_val_name;
+    }
 }
 }

+ 244 - 0
src/main/java/zs/payment/entity/mysql/ImsEweiShopApply.java

@@ -0,0 +1,244 @@
+package zs.payment.entity.mysql;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * 商城资质申请
+ */
+@Setter
+@Getter
+@NoArgsConstructor
+@TableName("ims_ewei_shop_apply")
+public class ImsEweiShopApply {
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    // 所属账号id
+    @TableField("uniacid")
+    private Integer uniacid;
+
+    // 所属多商户id
+    @TableField("merchid")
+    private Integer merchid;
+
+    // 创建时间
+    @TableField("createtime")
+    private Integer createtime;
+
+    // 卖场id
+    @TableField("mallid")
+    private Integer mallid;
+
+    // 店铺id
+    @TableField("storeid")
+    private Integer storeid;
+
+    // 卖场审核状态:0待审核 1通过 2未通过
+    @TableField("mall_status")
+    private Integer mallStatus;
+
+    // 店铺审核状态:0待审核 1通过 2未通过
+    @TableField("shop_status")
+    private Integer shopStatus;
+
+    // 卖场审核未通过的原因
+    @TableField("mall_note")
+    private String mallNote;
+
+    // 店铺审核未通过原因
+    @TableField("shop_note")
+    private String shopNote;
+
+    // 主营分类1
+    @TableField("select_1")
+    private String select1;
+
+    // 主营分类2
+    @TableField("select_2")
+    private String select2;
+
+    // 主营分类3
+    @TableField("select_3")
+    private String select3;
+
+    // merchants_id
+    @TableField("merchants_id")
+    private Integer merchantsId;
+
+    // 招商人员姓名
+    @TableField("merchants_username")
+    private String merchantsUsername;
+
+    // 公司名称
+    @TableField("company")
+    private String company;
+
+    // 营业执照号
+    @TableField("business")
+    private String business;
+
+    // 经营者QQ
+    @TableField("operator")
+    private String operator;
+
+    // 法人姓名
+    @TableField("legal")
+    private String legal;
+
+    // 法人身份证号
+    @TableField("idcard")
+    private String idcard;
+
+    // 经营者邮箱
+    @TableField("email")
+    private String email;
+
+    // 订单提醒手机号
+    @TableField("ordermobile")
+    private String ordermobile;
+
+    // 卖场搜悦号
+    @TableField("mall_souyue")
+    private String mallSouyue;
+
+    // 店铺搜悦号(结算账户)
+    @TableField("settlement_souyue")
+    private String settlementSouyue;
+
+    // 开户银行及支行名称
+    @TableField("bank")
+    private String bank;
+
+    // 开户银行行号
+    @TableField("number")
+    private String number;
+
+    // 开户银行账号
+    @TableField("account")
+    private String account;
+
+    // 联系人
+    @TableField("contact")
+    private String contact;
+
+    // 联系电话
+    @TableField("linkmobile")
+    private String linkmobile;
+
+    // 客服电话
+    @TableField("tel")
+    private String tel;
+
+    // 客服地址
+    @TableField("service")
+    private String service;
+
+    // 客服搜悦号
+    @TableField("servicesouyue")
+    private String servicesouyue;
+
+    // 店铺名称
+    @TableField("storename")
+    private String storename;
+
+    // 店铺宣传语
+    @TableField("slogan")
+    private String slogan;
+
+    // 店铺描述
+    @TableField("`desc`")
+    private String desc;
+
+    // 店铺有效期
+    @TableField("beginstarttime")
+    private Date beginstarttime;
+
+    // 店铺有效期
+    @TableField("beginendtime")
+    private Date beginendtime;
+
+    // 店铺主页背景图片
+    @TableField("bgimg")
+    private String bgimg;
+
+    // 店铺主页logo
+    @TableField("storelogo")
+    private String storelogo;
+
+    // 上传证照图片
+    @TableField("cardimg")
+    private String cardimg;
+
+    // 是否供货 1是 0否
+    @TableField("issupply")
+    private Integer issupply;
+
+    // 押金
+    @TableField("deposit")
+    private Integer deposit;
+
+    // 押金状态 0未交 1已交
+    @TableField("isdeposit")
+    private Integer isdeposit;
+
+    // 供货联系人
+    @TableField("supplyname")
+    private String supplyname;
+
+    // 供货联系手机号
+    @TableField("supplymobile")
+    private String supplymobile;
+
+    // 供货联系邮箱
+    @TableField("supplyemail")
+    private String supplyemail;
+
+    // 供货状态 0待审核 1通过 2不通过
+    @TableField("supplystatus")
+    private Integer supplystatus;
+
+    // 供货审核未通过原因
+    @TableField("supplynote")
+    private String supplynote;
+
+    // 是否进货 0否1是
+    @TableField("isstock")
+    private Integer isstock;
+
+    // 预付款
+    @TableField("money")
+    private Integer money;
+
+    // 预付款状态 0未交1已交
+    @TableField("ismoney")
+    private Integer ismoney;
+
+    // 进货联系人
+    @TableField("stockname")
+    private String stockname;
+
+    // 进货联系手机号
+    @TableField("stockmobile")
+    private String stockmobile;
+
+    // 进货联系人邮箱
+    @TableField("stockemail")
+    private String stockemail;
+
+    // 进货状态 0待审核 1通过 2不通过
+    @TableField("stockstatus")
+    private Integer stockstatus;
+
+    // 进货审核未通过原因
+    @TableField("stocknote")
+    private String stocknote;
+}

+ 37 - 0
src/main/java/zs/payment/entity/mysql/ImsEweiShopGoodsParam.java

@@ -0,0 +1,37 @@
+package zs.payment.entity.mysql;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * 商品参数
+ */
+@Setter
+@Getter
+@NoArgsConstructor
+@TableName("ims_ewei_shop_goods_param")
+public class ImsEweiShopGoodsParam {
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    @TableField("uniacid")
+    private Integer uniacid;
+
+    @TableField("goodsid")
+    private Integer goodsid;
+
+    @TableField("title")
+    private String title;
+
+    @TableField("`value`")
+    private String value;
+
+    @TableField("displayorder")
+    private Integer displayorder;
+}

+ 9 - 0
src/main/java/zs/payment/mapper/primary/ImsEweiShopApplyMapper.java

@@ -0,0 +1,9 @@
+package zs.payment.mapper.primary;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import zs.payment.entity.mysql.ImsEweiShopApply;
+
+@Mapper
+public interface ImsEweiShopApplyMapper extends BaseMapper<ImsEweiShopApply> {
+}

+ 5 - 0
src/main/java/zs/payment/mapper/primary/ImsEweiShopGoodsMapper.java

@@ -25,4 +25,9 @@ public interface ImsEweiShopGoodsMapper extends BaseMapper<ImsEweiShopGoods> {
      * @return
      * @return
      */
      */
     AddressInfo findAddressByOrdersn(@Param("ordersn")String ordersn);
     AddressInfo findAddressByOrdersn(@Param("ordersn")String ordersn);
+
+    /**
+     * 多规格商品:从option子查询更新goods的价格字段
+     */
+    void updateGoodsPriceByOption(@Param("goodsId") Long goodsId);
 }
 }

+ 9 - 0
src/main/java/zs/payment/mapper/primary/ImsEweiShopGoodsParamMapper.java

@@ -0,0 +1,9 @@
+package zs.payment.mapper.primary;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import zs.payment.entity.mysql.ImsEweiShopGoodsParam;
+
+@Mapper
+public interface ImsEweiShopGoodsParamMapper extends BaseMapper<ImsEweiShopGoodsParam> {
+}

+ 37 - 6
src/main/java/zs/payment/messages/KafkaConsumer.java

@@ -66,7 +66,7 @@ public class KafkaConsumer {
      * @param messsage
      * @param messsage
      */
      */
     @KafkaListener(
     @KafkaListener(
-        topics = "goods.undercarriage",
+        topics = "goods.undercarriage2",
         groupId = "pay2-group"
         groupId = "pay2-group"
     )
     )
     public void goodsUndercarriage(String messsage) {
     public void goodsUndercarriage(String messsage) {
@@ -90,7 +90,7 @@ public class KafkaConsumer {
      * @param messsage
      * @param messsage
      */
      */
     @KafkaListener(
     @KafkaListener(
-        topics = "goods.on.sale",
+        topics = "goods.on.sale2",
         groupId = "pay2-group"
         groupId = "pay2-group"
     )
     )
     public void goodsOnSale(String messsage) {
     public void goodsOnSale(String messsage) {
@@ -114,7 +114,7 @@ public class KafkaConsumer {
      * @param messsage
      * @param messsage
      */
      */
     @KafkaListener(
     @KafkaListener(
-        topics = "goods.delete",
+        topics = "goods.delete2",
         groupId = "pay2-group"
         groupId = "pay2-group"
     )
     )
     public void goodsDelete(String messsage) {
     public void goodsDelete(String messsage) {
@@ -142,7 +142,7 @@ public class KafkaConsumer {
      * @param messsage
      * @param messsage
      */
      */
     @KafkaListener(
     @KafkaListener(
-        topics = "goods.sync",
+        topics = "goods.sync2",
         groupId = "pay2-group"
         groupId = "pay2-group"
     )
     )
     @Transactional(rollbackFor = Exception.class)
     @Transactional(rollbackFor = Exception.class)
@@ -168,7 +168,7 @@ public class KafkaConsumer {
                 if (!b) {
                 if (!b) {
                     //不存在,则需要添加
                     //不存在,则需要添加
 
 
-                    Integer uniacid = 465;
+                    Integer uniacid = 463;//463-云悦生活  465-云享生态
 
 
                     //第一级
                     //第一级
                     Long pcate = 0L;
                     Long pcate = 0L;
@@ -364,7 +364,7 @@ public class KafkaConsumer {
      * @param messsage
      * @param messsage
      */
      */
     @KafkaListener(
     @KafkaListener(
-        topics = "order.delivery",
+        topics = "order.delivery2",
         groupId = "pay2-group"
         groupId = "pay2-group"
     )
     )
     public void goodsDelivery(String orderSn) {
     public void goodsDelivery(String orderSn) {
@@ -373,5 +373,36 @@ public class KafkaConsumer {
         log.info("=======订单发货-第三方订单编号:{} =======", orderSn);
         log.info("=======订单发货-第三方订单编号:{} =======", orderSn);
     }
     }
 
 
+    @Autowired
+    private zs.payment.service.commodity.CommodityProcureService commodityProcureService;
+
+    /**
+     * 商品进货消费
+     * 消息格式:{"uniacid":1, "gdId":123456, "mallid":100, "cates":[1,2,3]}
+     */
+    @KafkaListener(
+        topics = "commodity.procure",
+        groupId = "pay2-group"
+    )
+    public void commodityProcure(String message) {
+        JSONObject jsonObject = JSONObject.parseObject(message);
+        Integer uniacid = jsonObject.getIntValue("uniacid");
+        Integer gdId = jsonObject.getIntValue("gdId");
+        Integer mallid = jsonObject.getIntValue("mallid");
+        List<Long> cates = jsonObject.getJSONArray("cates").toJavaList(Long.class);
+
+        try {
+            // 查重
+            ImsEweiShopGoods existing = imsEweiShopGoodsService.getByGdId(gdId, uniacid);
+            if (existing != null) {
+                log.info("商品已进货,跳过 gdId={}, goodsId={}", gdId, existing.getId());
+                return;
+            }
+            commodityProcureService.procureSingleGoods(uniacid, gdId, mallid, cates);
+        } catch (Exception e) {
+            log.error("商品进货失败 uniacid={}, gdId={}, error={}", uniacid, gdId, e.getMessage(), e);
+        }
+    }
+
 
 
 }
 }

+ 36 - 0
src/main/java/zs/payment/req/CommodityProcureReq.java

@@ -0,0 +1,36 @@
+package zs.payment.req;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.util.List;
+
+@Setter
+@Getter
+@NoArgsConstructor
+public class CommodityProcureReq implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /** 品类ID列表,用于从MongoDB搜索商品 */
+//    @NotEmpty(message = "品类ID不能为空")
+    private List<Long> ptIds;
+
+    /** 排除的店铺ID(当前商家店铺,搜索时排除) */
+    private Long shopId;
+
+    /** 搜索关键字(可选) */
+    private String keyWord;
+
+    /** 分类ID数组 */
+    @NotEmpty(message = "请选择分类")
+    private List<Long> cates;
+
+    /** 公众号ID */
+    @NotNull(message = "公众号ID不能为空")
+    private Integer uniacid;
+}

+ 5 - 0
src/main/java/zs/payment/service/Imseweishopgoods/ImsEweiShopGoodsService.java

@@ -13,4 +13,9 @@ public interface ImsEweiShopGoodsService extends IService<ImsEweiShopGoods> {
 
 
     Boolean deleteBySupplyId(String supplyId,String supplySource);
     Boolean deleteBySupplyId(String supplyId,String supplySource);
 
 
+    /**
+     * 根据云商城商品ID查询是否已进货
+     */
+    ImsEweiShopGoods getByGdId(Integer gdId, Integer uniacid);
+
 }
 }

+ 10 - 0
src/main/java/zs/payment/service/Imseweishopgoods/impl/ImsEweiShopGoodsServiceImpl.java

@@ -36,4 +36,14 @@ public class ImsEweiShopGoodsServiceImpl  extends ServiceImpl<ImsEweiShopGoodsMa
             .eq(ImsEweiShopGoods::getSupply_source, supplySource)
             .eq(ImsEweiShopGoods::getSupply_source, supplySource)
             .eq(ImsEweiShopGoods::getSupply_id, supplyId).update();
             .eq(ImsEweiShopGoods::getSupply_id, supplyId).update();
     }
     }
+
+    @Override
+    public ImsEweiShopGoods getByGdId(Integer gdId, Integer uniacid) {
+        return lambdaQuery()
+            .eq(ImsEweiShopGoods::getGd_id, gdId)
+            .eq(ImsEweiShopGoods::getDeleted, 0)
+            .eq(ImsEweiShopGoods::getCommoditytype, 1)
+            .eq(ImsEweiShopGoods::getUniacid, uniacid)
+            .one();
+    }
 }
 }

+ 25 - 0
src/main/java/zs/payment/service/commodity/CommodityProcureService.java

@@ -0,0 +1,25 @@
+package zs.payment.service.commodity;
+
+import zs.payment.req.CommodityProcureReq;
+import zs.payment.resp.Result;
+
+import java.util.List;
+
+public interface CommodityProcureService {
+
+    /**
+     * 进货:从云商城拉取商品数据写入本地
+     */
+    Result procureGoods(CommodityProcureReq req);
+
+    /**
+     * 单商品进货(独立事务)
+     */
+    Result procureSingleGoods(Integer uniacid, Integer gdId, Integer mallid,
+                              zs.payment.dto.yunmall.CategoryResolveResult categoryResult);
+
+    /**
+     * 单商品进货(独立事务),传入cates列表自动解析分类
+     */
+    Result procureSingleGoods(Integer uniacid, Integer gdId, Integer mallid, List<Long> cates);
+}

+ 696 - 0
src/main/java/zs/payment/service/commodity/impl/CommodityProcureServiceImpl.java

@@ -0,0 +1,696 @@
+package zs.payment.service.commodity.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import zs.payment.dao.yunmall.GoodsDao;
+import zs.payment.dto.yunmall.*;
+import zs.payment.entity.mongodb.yunmall.Goods;
+import zs.payment.entity.mongodb.yunmall.Sku;
+import zs.payment.entity.mysql.*;
+import zs.payment.entity.mysql.flymall.B2cGoodsImgInOnline;
+import zs.payment.entity.mysql.flymall.B2cGoodsSkuInOnline;
+import zs.payment.entity.mysql.flymall.B2cGoodsSpuInOnline;
+import zs.payment.entity.mysql.flymall.B2cShop;
+import zs.payment.exception.ApiException;
+import zs.payment.mapper.primary.ImsEweiShopApplyMapper;
+import zs.payment.mapper.primary.ImsEweiShopGoodsMapper;
+import zs.payment.req.CommodityProcureReq;
+import zs.payment.resp.Result;
+import zs.payment.service.Imseweishopgoods.ImsEweiShopGoodsService;
+import zs.payment.service.imseweishopcategory.ImsEweiShopCategoryService;
+import zs.payment.service.imseweishopgoodsoption.ImsEweiShopGoodsOptionService;
+import zs.payment.service.imseweishopgoodsparam.ImsEweiShopGoodsParamService;
+import zs.payment.service.imseweishopgoodsspec.ImsEweiShopGoodsSpecService;
+import zs.payment.service.imseweishopgoodsspecitem.ImsEweiShopGoodsSpecItemService;
+import zs.payment.service.commodity.CommodityProcureService;
+import zs.payment.service.flymall.b2cgoodsimginonline.B2cGoodsImgInOnlineService;
+import zs.payment.service.flymall.b2cgoodsskuinonline.B2cGoodsSkuInOnlineService;
+import zs.payment.service.flymall.b2cgoodsspuinonline.B2cGoodsSpuInOnlineService;
+import zs.payment.service.flymall.b2cshop.B2cShopService;
+
+import zs.payment.messages.KafkaProducer;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+@Slf4j
+public class CommodityProcureServiceImpl implements CommodityProcureService {
+
+    private static final String TOPIC_COMMODITY_PROCURE = "commodity.procure";
+
+    @Autowired
+    private ImsEweiShopGoodsService goodsService;
+    @Autowired
+    private ImsEweiShopGoodsSpecService specService;
+    @Autowired
+    private ImsEweiShopGoodsSpecItemService specItemService;
+    @Autowired
+    private ImsEweiShopGoodsOptionService optionService;
+    @Autowired
+    private ImsEweiShopGoodsParamService paramService;
+    @Autowired
+    private ImsEweiShopApplyMapper applyMapper;
+    @Autowired
+    private ImsEweiShopGoodsMapper goodsMapper;
+    @Autowired
+    private ImsEweiShopCategoryService categoryService;
+
+    @Autowired
+    private GoodsDao goodsDao;
+    @Autowired
+    private B2cGoodsSpuInOnlineService b2cGoodsSpuInOnlineService;
+    @Autowired
+    private B2cGoodsSkuInOnlineService b2cGoodsSkuInOnlineService;
+    @Autowired
+    private B2cGoodsImgInOnlineService b2cGoodsImgInOnlineService;
+    @Autowired
+    private B2cShopService b2cShopService;
+
+    @Autowired
+    private KafkaProducer kafkaProducer;
+
+    @Lazy
+    @Autowired
+    private CommodityProcureService self;
+
+    private static final BigDecimal HUNDRED = new BigDecimal("100");
+    private static final BigDecimal COMMISSION_DEFAULT_RATE = new BigDecimal("0.01");
+    private static final Integer JD_SHOP_ID = 11507;
+
+    @Override
+    public Result procureGoods(CommodityProcureReq req) {
+        Integer uniacid = req.getUniacid();
+        List<Long> cates = req.getCates();
+
+        // 1. 从MongoDB goods表查询符合条件的gdIds
+        List<Long> gdIds = searchGdIdsFromMongo(req.getPtIds(), req.getShopId(), req.getKeyWord());
+        if (gdIds.isEmpty()) {
+            return Result.fail("未搜索到符合条件的商品");
+        }
+
+        // 2. 查询资质
+        ImsEweiShopApply apply = applyMapper.selectOne(new LambdaQueryWrapper<ImsEweiShopApply>()
+                .eq(ImsEweiShopApply::getUniacid, uniacid)
+                .eq(ImsEweiShopApply::getMerchid, 0)
+                .eq(ImsEweiShopApply::getMallStatus, 1)
+                .eq(ImsEweiShopApply::getShopStatus, 1)
+                .eq(ImsEweiShopApply::getStockstatus, 1)
+                .last("LIMIT 1"));
+        if (apply == null || apply.getMallid() == null) {
+            throw new ApiException("资质审核未通过,无法进货");
+        }
+
+        // 3. 异步发送Kafka消息,逐条进货
+        for (Long gdId : gdIds) {
+            JSONObject msg = new JSONObject();
+            msg.put("uniacid", uniacid);
+            msg.put("gdId", gdId);
+            msg.put("mallid", apply.getMallid());
+            msg.put("cates", cates);
+            kafkaProducer.sendMessage(TOPIC_COMMODITY_PROCURE, msg.toJSONString());
+        }
+
+        log.info("进货任务已提交,共{}个商品待处理", gdIds.size());
+        return Result.success("进货任务已提交,共" + gdIds.size() + "个商品将异步处理");
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Result procureSingleGoods(Integer uniacid, Integer gdId, Integer mallid, List<Long> cates) {
+        CategoryResolveResult categoryResult = resolveCategories(cates);
+        return procureSingleGoods(uniacid, gdId, mallid, categoryResult);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Result procureSingleGoods(Integer uniacid, Integer gdId, Integer mallid,
+                                     CategoryResolveResult categoryResult) {
+        // 1. 从MongoDB查询商品基本信息(含shop、skus含attrs、gd_imgs)
+        Query mongoQuery = new Query(Criteria.where("gd_id").is(gdId));
+        Goods mongoGoods = goodsDao.queryOne(mongoQuery);
+
+        // 2. 从MySQL flymall查询商品详细信息
+        B2cGoodsSpuInOnline spu = b2cGoodsSpuInOnlineService.getById(gdId);
+        if (spu == null) {
+            throw new ApiException("云商城商品数据为空: gdId=" + gdId);
+        }
+        List<B2cGoodsSkuInOnline> dbSkuList = b2cGoodsSkuInOnlineService.findByGdId(String.valueOf(gdId));
+        List<B2cGoodsImgInOnline> dbImgList = b2cGoodsImgInOnlineService.findByGdId(String.valueOf(gdId));
+        B2cShop b2cShop = b2cShopService.getById(spu.getShopId());
+
+        // 3. 构建CloudMallGoods(保持下游逻辑不变)
+        CloudMallGoods yunGoods = buildCloudMallGoods(spu, b2cShop, dbImgList, mongoGoods);
+
+        // 4. 构建attrList(从MongoDB skus的attrs聚合)
+        boolean hasSpec = mongoGoods != null && mongoGoods.getSkus() != null
+                && mongoGoods.getSkus().stream().anyMatch(s -> s.getAttrs() != null && !s.getAttrs().isEmpty());
+        List<CloudMallAttr> attrList = hasSpec ? buildAttrList(mongoGoods.getSkus()) : new ArrayList<>();
+
+        // 5. 构建skuList map
+        Map<String, CloudMallSku> skuMap = buildSkuMap(mongoGoods, dbSkuList);
+
+        // 6. 构建nomalattrList(从spu.normal_attrs解析)
+        List<CloudMallNormalAttr> nomalattrList = parseNormalAttrs(spu.getNormalAttrs());
+
+        // 7. 组装CloudMallGoodsBody
+        CloudMallGoodsBody body = new CloudMallGoodsBody();
+        body.setGoods(yunGoods);
+        body.setAttrList(attrList);
+        body.setNomalattrList(nomalattrList);
+        body.setSkuList(skuMap);
+
+        // 8. 构建商品实体
+        ImsEweiShopGoods goods = buildGoodsEntity(uniacid, gdId, yunGoods, categoryResult, hasSpec);
+
+        // 9. 插入商品
+        goodsService.save(goods);
+        Long goodsId = goods.getId();
+        log.info("进货商品插入成功 gdId={}, goodsId={}", gdId, goodsId);
+
+        // 10. 处理规格和SKU
+        if (!hasSpec) {
+            handleNoSpec(goodsId, uniacid, body, yunGoods);
+        } else {
+            Map<Integer, Long> yunSpecItemIdMap = handleSpecs(goodsId, uniacid, body);
+            handleOptions(goodsId, uniacid, body, yunGoods, yunSpecItemIdMap);
+        }
+
+        // 11. 计算生态分佣
+        recalculateFenyonglmb(goodsId);
+
+        // 12. 插入商品参数
+        if (body.getNomalattrList() != null) {
+            for (int k = 0; k < body.getNomalattrList().size(); k++) {
+                CloudMallNormalAttr attr = body.getNomalattrList().get(k);
+                ImsEweiShopGoodsParam param = new ImsEweiShopGoodsParam();
+                param.setUniacid(uniacid);
+                param.setTitle(attr.getAttr_name());
+                param.setValue(attr.getAttr_val_name());
+                param.setDisplayorder(k);
+                param.setGoodsid(goodsId.intValue());
+                paramService.save(param);
+            }
+        }
+
+        return Result.success();
+    }
+
+    // ==================== 私有方法 ====================
+
+    /**
+     * 从MongoDB goods表搜索符合条件的gdIds(参考qiyueGoodsSearch逻辑)
+     */
+    private List<Long> searchGdIdsFromMongo(List<Long> ptIds, Long shopId, String keyWord) {
+        Criteria criteria = new Criteria();
+        // pt_id in ptIds
+        if (ptIds != null && !ptIds.isEmpty()) {
+            criteria.and("pt_id").in(ptIds);
+        }
+        // 排除自身店铺
+        if (shopId != null) {
+            criteria.and("shop.shop_id").ne(shopId);
+        }
+        // 排除自主结算型店铺(shop_type=4)
+        criteria.and("shop.shop_type").ne(4);
+        // 必须有有效SKU
+        criteria.and("skus.sku_id").gt(0);
+        // 关键字搜索(商品名称模糊匹配)
+        if (keyWord != null && !keyWord.trim().isEmpty()) {
+            criteria.and("gd_name").regex(".*" + keyWord.trim() + ".*", "i");
+        }
+
+        Query query = new Query(criteria);
+        // 只查gd_id字段,提高查询效率
+        query.fields().include("gd_id");
+//        query.limit(1);
+        List<Goods> goodsList = goodsDao.queryList(query);
+        return goodsList.stream().map(Goods::getGdId).collect(Collectors.toList());
+    }
+
+    /**
+     * 构建CloudMallGoods(从MySQL+MongoDB数据组装,替代原HTTP接口返回)
+     */
+    private CloudMallGoods buildCloudMallGoods(B2cGoodsSpuInOnline spu, B2cShop b2cShop,
+                                                List<B2cGoodsImgInOnline> dbImgList, Goods mongoGoods) {
+        CloudMallGoods yunGoods = new CloudMallGoods();
+        yunGoods.setGd_name(spu.getGdName());
+        yunGoods.setUnit(spu.getGdUnit());
+        yunGoods.setWeight(spu.getGdWeight() != null ? BigDecimal.valueOf(spu.getGdWeight()) : BigDecimal.ZERO);
+        yunGoods.setDesc(spu.getGdDesc());
+        yunGoods.setStatement_rate(spu.getCommissionRatio());
+        yunGoods.setTg_statement_rate(spu.getTgCommissionRatio());
+
+        // Shop
+        CloudMallShop shop = new CloudMallShop();
+        if (b2cShop != null) {
+            shop.setShop_id(b2cShop.getShopId());
+            shop.setShop_name(b2cShop.getShopName());
+        } else if (mongoGoods != null && mongoGoods.getShop() != null) {
+            shop.setShop_id(mongoGoods.getShop().getShop_id());
+            shop.setShop_name(mongoGoods.getShop().getShop_name());
+        }
+        yunGoods.setShop(shop);
+
+        // Images
+        List<CloudMallImg> imgsInfo = new ArrayList<>();
+        for (B2cGoodsImgInOnline img : dbImgList) {
+            CloudMallImg ci = new CloudMallImg();
+            ci.setImgUrl(img.getGdImg());
+            imgsInfo.add(ci);
+        }
+        yunGoods.setImgsInfo(imgsInfo);
+
+        return yunGoods;
+    }
+
+    /**
+     * 从MongoDB skus的attrs聚合构建attrList(参考Groovy goodsDetail逻辑)
+     */
+    private List<CloudMallAttr> buildAttrList(List<Sku> skus) {
+        Map<Integer, CloudMallAttr> attrMap = new LinkedHashMap<>();
+        for (Sku sku : skus) {
+            if (sku.getAttrs() == null) continue;
+            for (Sku.SkuAttr attr : sku.getAttrs()) {
+                CloudMallAttr existing = attrMap.get(attr.getAttr_id());
+                if (existing == null) {
+                    existing = new CloudMallAttr();
+                    existing.setAttr_id(attr.getAttr_id());
+                    existing.setAttr_name(attr.getAttr_name());
+                    existing.setValues(new ArrayList<>());
+                    attrMap.put(attr.getAttr_id(), existing);
+                }
+                // 去重添加attr_val
+                boolean valExists = existing.getValues().stream()
+                        .anyMatch(v -> v.getAttr_val_id().equals(attr.getAttr_val_id()));
+                if (!valExists) {
+                    CloudMallAttrValue val = new CloudMallAttrValue();
+                    val.setAttr_val_id(attr.getAttr_val_id());
+                    val.setAttr_val_name(attr.getAttr_val_name());
+                    existing.getValues().add(val);
+                }
+            }
+        }
+        return new ArrayList<>(attrMap.values());
+    }
+
+    /**
+     * 构建skuList map(MongoDB结构数据 + MySQL价格/库存)
+     */
+    private Map<String, CloudMallSku> buildSkuMap(Goods mongoGoods, List<B2cGoodsSkuInOnline> dbSkuList) {
+        Map<String, CloudMallSku> skuMap = new LinkedHashMap<>();
+        if (mongoGoods == null || mongoGoods.getSkus() == null || mongoGoods.getSkus().isEmpty()) {
+            // 无MongoDB数据时,直接用MySQL SKU构建
+            for (B2cGoodsSkuInOnline dbSku : dbSkuList) {
+                CloudMallSku cloudSku = new CloudMallSku();
+                cloudSku.setSku_id(dbSku.getSkuId());
+                cloudSku.setSku_price(dbSku.getGdPrice());
+                cloudSku.setCost_price(dbSku.getCostPrice());
+                cloudSku.setMk_price(dbSku.getMkPrice());
+                cloudSku.setStock(dbSku.getGdStock());
+                skuMap.put("sku_" + dbSku.getSkuId(), cloudSku);
+            }
+            return skuMap;
+        }
+
+        // MySQL skuId -> B2cGoodsSkuInOnline 映射
+        Map<Integer, B2cGoodsSkuInOnline> dbSkuMap = dbSkuList.stream()
+                .collect(Collectors.toMap(B2cGoodsSkuInOnline::getSkuId, s -> s, (a, b) -> a));
+
+        for (Sku mongoSku : mongoGoods.getSkus()) {
+            B2cGoodsSkuInOnline dbSku = dbSkuMap.get(mongoSku.getSku_id());
+            if (dbSku == null) continue;
+
+            String skuKey;
+            String attrValNameStr = "";
+            if (mongoSku.getAttrs() != null && !mongoSku.getAttrs().isEmpty()) {
+                skuKey = "sku_" + mongoSku.getAttrs().stream()
+                        .map(a -> String.valueOf(a.getAttr_val_id()))
+                        .sorted()
+                        .collect(Collectors.joining("_"));
+                attrValNameStr = mongoSku.getAttrs().stream()
+                        .map(Sku.SkuAttr::getAttr_val_name)
+                        .collect(Collectors.joining("+"));
+            } else {
+                skuKey = "sku_" + mongoSku.getSku_id();
+            }
+
+            CloudMallSku cloudSku = new CloudMallSku();
+            cloudSku.setSku_id(dbSku.getSkuId());
+            cloudSku.setSku_price(dbSku.getGdPrice());
+            cloudSku.setCost_price(dbSku.getCostPrice());
+            cloudSku.setMk_price(dbSku.getMkPrice());
+            cloudSku.setStock(dbSku.getGdStock());
+            cloudSku.setSku_img(mongoSku.getSku_img());
+            cloudSku.setAttr_val_name_str(attrValNameStr);
+
+            skuMap.put(skuKey, cloudSku);
+        }
+        return skuMap;
+    }
+
+    /**
+     * 解析normal_attrs为CloudMallNormalAttr列表
+     * normal_attrs格式:{"attr_id":["val1","val2"],...}
+     * 注:完整的attr_name需要查询ptmall的attr表,此处使用attr_id作为降级
+     */
+    private List<CloudMallNormalAttr> parseNormalAttrs(String normalAttrs) {
+        List<CloudMallNormalAttr> result = new ArrayList<>();
+        if (normalAttrs == null || normalAttrs.trim().isEmpty()) {
+            return result;
+        }
+        try {
+            JSONObject attrsJson = JSONObject.parseObject(normalAttrs);
+            for (String attrIdKey : attrsJson.keySet()) {
+                CloudMallNormalAttr attr = new CloudMallNormalAttr();
+                attr.setAttr_name(attrIdKey);
+                List<Object> valList = attrsJson.getJSONArray(attrIdKey).toJavaList(Object.class);
+                String valStr = valList.stream().map(Object::toString).sorted().collect(Collectors.joining(","));
+                attr.setAttr_val_name(valStr);
+                result.add(attr);
+            }
+        } catch (Exception e) {
+            log.warn("解析normal_attrs失败: {}", normalAttrs, e);
+        }
+        return result;
+    }
+
+    /**
+     * 构建商品实体
+     */
+    private ImsEweiShopGoods buildGoodsEntity(Integer uniacid, Integer gdId, CloudMallGoods yunGoods,
+                                               CategoryResolveResult categoryResult, boolean hasSpec) {
+        ImsEweiShopGoods goods = new ImsEweiShopGoods();
+        goods.setCommoditytype(1);
+        goods.setGd_id(gdId);
+        goods.setUniacid(uniacid);
+        goods.setTitle(yunGoods.getGd_name());
+        goods.setUnit(yunGoods.getUnit());
+        goods.setType(1);
+        goods.setStatus(1);
+        goods.setWeight(yunGoods.getWeight());
+        goods.setHasoption(hasSpec ? 1 : 0);
+        goods.setContent(yunGoods.getDesc());
+        goods.setCreatetime(System.currentTimeMillis() / 1000);
+        goods.setInvoice(1);
+        goods.setThumb_first(1);
+        goods.setIssendfree(1);
+
+        // 京东判断
+        boolean isJd = yunGoods.getShop() != null && JD_SHOP_ID.equals(yunGoods.getShop().getShop_id());
+        goods.setIsjingdong(isJd ? 1 : 0);
+        if (yunGoods.getShop() != null) {
+            goods.setMerchid(isJd ? -JD_SHOP_ID : -yunGoods.getShop().getShop_id());
+            goods.setYsh_merchname(yunGoods.getShop().getShop_name());
+        }
+
+        // 分类
+        if (categoryResult != null) {
+            goods.setCates(joinList(categoryResult.getCates()));
+            goods.setPcates(joinList(categoryResult.getPcates()));
+            goods.setCcates(joinList(categoryResult.getCcates()));
+            goods.setTcates(joinList(categoryResult.getTcates()));
+            goods.setPcate(categoryResult.getPcate());
+            goods.setCcate(categoryResult.getCcate());
+            goods.setTcate(categoryResult.getTcate());
+        }
+
+        // 折扣
+        JSONObject discounts = new JSONObject();
+        discounts.put("type", 0);
+        discounts.put("default", "");
+        discounts.put("default_pay", "");
+        goods.setDiscounts(discounts.toJSONString());
+
+        // 图片
+        if (yunGoods.getImgsInfo() != null && !yunGoods.getImgsInfo().isEmpty()) {
+            goods.setThumb(yunGoods.getImgsInfo().get(0).getImgUrl());
+            if (yunGoods.getImgsInfo().size() > 1) {
+                List<String> imgUrlList = yunGoods.getImgsInfo().stream()
+                        .skip(1)
+                        .map(CloudMallImg::getImgUrl)
+                        .collect(Collectors.toList());
+                goods.setThumb_url(JSON.toJSONString(imgUrlList));
+            }
+        }
+
+        return goods;
+    }
+
+    /**
+     * 无规格商品处理
+     */
+    private void handleNoSpec(Long goodsId, Integer uniacid, CloudMallGoodsBody body, CloudMallGoods yunGoods) {
+        Map<String, CloudMallSku> skuList = body.getSkuList();
+        if (skuList == null || skuList.isEmpty()) {
+            return;
+        }
+
+        // 取唯一SKU
+        CloudMallSku sku = skuList.values().iterator().next();
+
+        BigDecimal costprice = calculateCostPrice(sku.getSku_price(), sku.getCost_price(),
+                yunGoods.getStatement_rate(), yunGoods.getTg_statement_rate());
+        BigDecimal fenyonglmb = sku.getSku_price().multiply(COMMISSION_DEFAULT_RATE)
+                .setScale(2, RoundingMode.HALF_UP);
+
+        ImsEweiShopGoods update = new ImsEweiShopGoods();
+        update.setId(goodsId);
+        update.setProductprice(sku.getMk_price());
+        update.setCostprice(costprice);
+        update.setMarketprice(sku.getSku_price());
+        update.setTotal(sku.getStock());
+        update.setWeight(yunGoods.getWeight());
+        update.setThumb(sku.getSku_img());
+        update.setHasoption(0);
+        update.setMinprice(sku.getSku_price());
+        update.setMaxprice(sku.getSku_price());
+        update.setFenyonglmb(fenyonglmb);
+        goodsService.updateById(update);
+    }
+
+    /**
+     * 有规格商品处理:插入规格和规格项
+     *
+     * @return yunspecitemid -> 本地spec_item_id 的映射
+     */
+    private Map<Integer, Long> handleSpecs(Long goodsId, Integer uniacid, CloudMallGoodsBody body) {
+        Map<Integer, Long> yunSpecItemIdMap = new HashMap<>();
+        List<CloudMallAttr> attrList = body.getAttrList();
+
+        for (int k = 0; k < attrList.size(); k++) {
+            CloudMallAttr attr = attrList.get(k);
+
+            // 插入规格
+            ImsEweiShopGoodsSpec spec = new ImsEweiShopGoodsSpec();
+            spec.setUniacid(uniacid);
+            spec.setGoodsid(goodsId.intValue());
+            spec.setDisplayorder(k);
+            spec.setTitle(attr.getAttr_name());
+            spec.setYunspecid(attr.getAttr_id());
+            specService.save(spec);
+            Long specId = spec.getId();
+
+            // 插入规格项
+            if (attr.getValues() != null) {
+                for (int n = 0; n < attr.getValues().size(); n++) {
+                    CloudMallAttrValue attrVal = attr.getValues().get(n);
+                    ImsEweiShopGoodsSpecItem specItem = new ImsEweiShopGoodsSpecItem();
+                    specItem.setUniacid(uniacid);
+                    specItem.setSpecid(specId.intValue());
+                    specItem.setDisplayorder(n);
+                    specItem.setTitle(attrVal.getAttr_val_name());
+                    specItem.setShowVar(1);
+                    specItem.setThumb("");
+                    specItem.setVirtualVar(0);
+                    specItem.setYunspecitemid(attrVal.getAttr_val_id());
+                    specItemService.save(specItem);
+
+                    // 建立映射
+                    yunSpecItemIdMap.put(attrVal.getAttr_val_id(), specItem.getId());
+                }
+            }
+        }
+
+        return yunSpecItemIdMap;
+    }
+
+    /**
+     * 有规格商品处理:插入SKU选项
+     */
+    private void handleOptions(Long goodsId, Integer uniacid, CloudMallGoodsBody body,
+                               CloudMallGoods yunGoods, Map<Integer, Long> yunSpecItemIdMap) {
+        Map<String, CloudMallSku> skuList = body.getSkuList();
+        if (skuList == null || skuList.isEmpty()) {
+            return;
+        }
+
+        int totalStocks = 0;
+        for (Map.Entry<String, CloudMallSku> entry : skuList.entrySet()) {
+            String key = entry.getKey();
+            CloudMallSku sku = entry.getValue();
+
+            // 解析规格key(如 "123_456_sku")
+            String[] parts = key.split("_");
+            List<Long> localSpecIds = new ArrayList<>();
+            for (String part : parts) {
+                if (part.isEmpty() || "sku".equals(part)) {
+                    continue;
+                }
+                try {
+                    Integer yunSpecItemId = Integer.valueOf(part);
+                    Long localId = yunSpecItemIdMap.get(yunSpecItemId);
+                    if (localId != null) {
+                        localSpecIds.add(localId);
+                    }
+                } catch (NumberFormatException e) {
+                    // 忽略非数字部分
+                }
+            }
+            String specs = localSpecIds.stream().map(String::valueOf).collect(Collectors.joining("_"));
+
+            BigDecimal costprice = calculateCostPrice(sku.getSku_price(), sku.getCost_price(),
+                    yunGoods.getStatement_rate(), yunGoods.getTg_statement_rate());
+
+            ImsEweiShopGoodsOption option = new ImsEweiShopGoodsOption();
+            option.setUniacid(uniacid);
+            option.setTitle(sku.getAttr_val_name_str());
+            option.setProductprice(sku.getMk_price());
+            option.setCostprice(costprice);
+            option.setMarketprice(sku.getSku_price());
+            option.setStock(sku.getStock());
+            option.setWeight(yunGoods.getWeight());
+            option.setGoodsid(goodsId.intValue());
+            option.setSpecs(specs);
+            option.setVirtual(0);
+            option.setSku_id(sku.getSku_id());
+            option.setThumb(sku.getSku_img());
+            optionService.save(option);
+
+            totalStocks += sku.getStock();
+        }
+
+        // 从option子查询更新goods价格
+        goodsMapper.updateGoodsPriceByOption(goodsId);
+
+        // 更新总库存
+        ImsEweiShopGoods updateStock = new ImsEweiShopGoods();
+        updateStock.setId(goodsId);
+        updateStock.setTotal(totalStocks);
+        goodsService.updateById(updateStock);
+    }
+
+    /**
+     * 计算并更新生态分佣金额
+     */
+    private void recalculateFenyonglmb(Long goodsId) {
+        ImsEweiShopGoods goods = goodsService.getById(goodsId);
+        if (goods != null && goods.getMinprice() != null) {
+            BigDecimal fenyonglmb = goods.getMinprice().multiply(COMMISSION_DEFAULT_RATE)
+                    .setScale(2, RoundingMode.HALF_UP);
+            ImsEweiShopGoods update = new ImsEweiShopGoods();
+            update.setId(goodsId);
+            update.setFenyonglmb(fenyonglmb);
+            goodsService.updateById(update);
+        }
+    }
+
+    /**
+     * 解析分类(对应PHP reust_cates方法)
+     */
+    private CategoryResolveResult resolveCategories(List<Long> cates) {
+        CategoryResolveResult result = new CategoryResolveResult();
+        List<Long> pcates = new ArrayList<>();
+        List<Long> ccates = new ArrayList<>();
+        List<Long> tcates = new ArrayList<>();
+        long pcateid = 0, ccateid = 0, tcateid = 0;
+
+        for (int i = 0; i < cates.size(); i++) {
+            Long cid = cates.get(i);
+            ImsEweiShopCategory category = categoryService.getById(cid);
+            if (category == null || category.getLevel() == null) {
+                continue;
+            }
+            int level = category.getLevel();
+
+            if (level == 1) {
+                pcates.add(cid);
+            } else if (level == 2) {
+                ccates.add(cid);
+            } else if (level == 3) {
+                tcates.add(cid);
+            }
+
+            // 第一个分类特殊处理(1.x兼容)
+            if (i == 0) {
+                if (level == 1) {
+                    pcateid = cid;
+                } else if (level == 2) {
+                    ccateid = cid;
+                    if (category.getParentId() != null) {
+                        pcateid = category.getParentId().longValue();
+                    }
+                } else if (level == 3) {
+                    tcateid = cid;
+                    if (category.getParentId() != null) {
+                        ImsEweiShopCategory parent = categoryService.getById(category.getParentId().longValue());
+                        if (parent != null) {
+                            ccateid = parent.getId();
+                            if (parent.getParentId() != null) {
+                                pcateid = parent.getParentId().longValue();
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        result.setPcate(pcateid);
+        result.setCcate(ccateid);
+        result.setTcate(tcateid);
+        result.setCates(cates);
+        result.setPcates(pcates);
+        result.setCcates(ccates);
+        result.setTcates(tcates);
+        return result;
+    }
+
+    /**
+     * 计算成本价
+     * 公式:cost_price有值则取cost_price,否则 sku_price * (100 - statement_rate - tg_statement_rate) / 100
+     */
+    private BigDecimal calculateCostPrice(BigDecimal skuPrice, BigDecimal costPrice,
+                                          BigDecimal statementRate, BigDecimal tgStatementRate) {
+        if (costPrice != null && costPrice.compareTo(BigDecimal.ZERO) > 0) {
+            return costPrice.setScale(2, RoundingMode.HALF_UP);
+        }
+        if (statementRate == null) {
+            statementRate = BigDecimal.ZERO;
+        }
+        if (tgStatementRate == null) {
+            tgStatementRate = BigDecimal.ZERO;
+        }
+        return skuPrice.multiply(HUNDRED.subtract(statementRate).subtract(tgStatementRate))
+                .divide(HUNDRED, 2, RoundingMode.HALF_UP);
+    }
+
+    /**
+     * List<Long> 逗号拼接
+     */
+    private String joinList(List<Long> list) {
+        if (list == null || list.isEmpty()) {
+            return "";
+        }
+        return list.stream().map(String::valueOf).collect(Collectors.joining(","));
+    }
+}

+ 7 - 0
src/main/java/zs/payment/service/imseweishopgoodsparam/ImsEweiShopGoodsParamService.java

@@ -0,0 +1,7 @@
+package zs.payment.service.imseweishopgoodsparam;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import zs.payment.entity.mysql.ImsEweiShopGoodsParam;
+
+public interface ImsEweiShopGoodsParamService extends IService<ImsEweiShopGoodsParam> {
+}

+ 12 - 0
src/main/java/zs/payment/service/imseweishopgoodsparam/impl/ImsEweiShopGoodsParamServiceImpl.java

@@ -0,0 +1,12 @@
+package zs.payment.service.imseweishopgoodsparam.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+import zs.payment.entity.mysql.ImsEweiShopGoodsParam;
+import zs.payment.mapper.primary.ImsEweiShopGoodsParamMapper;
+import zs.payment.service.imseweishopgoodsparam.ImsEweiShopGoodsParamService;
+
+@Service
+public class ImsEweiShopGoodsParamServiceImpl extends ServiceImpl<ImsEweiShopGoodsParamMapper, ImsEweiShopGoodsParam>
+        implements ImsEweiShopGoodsParamService {
+}

+ 8 - 0
src/main/resources/mapper/primary/ImsEweiShopGoodsMapper.xml

@@ -28,4 +28,12 @@
         WHERE o.ordersn = #{ordersn}
         WHERE o.ordersn = #{ordersn}
     </select>
     </select>
 
 
+    <update id="updateGoodsPriceByOption">
+        UPDATE ims_ewei_shop_goods g SET
+            g.costprice = (SELECT MAX(costprice) FROM ims_ewei_shop_goods_option WHERE goodsid = #{goodsId}),
+            g.minprice = (SELECT MIN(marketprice) FROM ims_ewei_shop_goods_option WHERE goodsid = #{goodsId}),
+            g.maxprice = (SELECT MAX(marketprice) FROM ims_ewei_shop_goods_option WHERE goodsid = #{goodsId})
+        WHERE g.id = #{goodsId} AND g.hasoption = 1
+    </update>
+
 </mapper>
 </mapper>