Browse Source

1、增加自动发货商品的一些逻辑

rayson 6 months ago
parent
commit
7f85ab5d97
34 changed files with 458 additions and 43 deletions
  1. 14 0
      citu-module-mall/citu-module-product-api/src/main/java/com/citu/module/product/api/sku/dto/ProductSkuExtendRespDTO.java
  2. 3 0
      citu-module-mall/citu-module-product-api/src/main/java/com/citu/module/product/api/sku/dto/ProductSkuRespDTO.java
  3. 5 0
      citu-module-mall/citu-module-product-api/src/main/java/com/citu/module/product/api/spu/dto/ProductSpuRespDTO.java
  4. 5 3
      citu-module-mall/citu-module-product-api/src/main/java/com/citu/module/product/enums/spu/ProductSpuTypeEnum.java
  5. 4 0
      citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/controller/admin/spu/vo/ProductSkuRespVO.java
  6. 4 0
      citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/controller/admin/spu/vo/ProductSkuSaveReqVO.java
  7. 5 1
      citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java
  8. 20 1
      citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/dal/dataobject/sku/ProductSkuDO.java
  9. 2 0
      citu-module-mall/citu-module-trade-api/src/main/java/com/citu/module/trade/enums/MessageTemplateConstants.java
  10. 6 0
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/admin/order/vo/TradeOrderBaseVO.java
  11. 6 0
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/admin/order/vo/TradeOrderDeliveryReqVO.java
  12. 3 0
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/admin/order/vo/TradeOrderItemBaseVO.java
  13. 4 0
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/admin/order/vo/TradeOrderUpdateAddressReqVO.java
  14. 1 1
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/app/order/vo/AppTradeOrderCreateReqVO.java
  15. 4 0
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/app/order/vo/AppTradeOrderDetailRespVO.java
  16. 7 0
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java
  17. 6 0
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/app/order/vo/AppTradeOrderSettlementRespVO.java
  18. 8 0
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/app/order/vo/item/AppTradeOrderItemRespVO.java
  19. 30 0
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/dal/dataobject/order/TradeOrderDO.java
  20. 27 0
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/dal/dataobject/order/TradeOrderItemDO.java
  21. 2 1
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/framework/rpc/config/RpcConfiguration.java
  22. 7 0
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/order/TradeOrderUpdateService.java
  23. 43 8
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/order/TradeOrderUpdateServiceImpl.java
  24. 117 0
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/order/handler/TradeAutomaticDeliveryOrderHandler.java
  25. 11 0
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/price/bo/TradePriceCalculateRespBO.java
  26. 1 1
      citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
  27. 3 0
      citu-module-system/citu-module-system-api/src/main/java/com/citu/module/system/api/mail/MailSendApi.java
  28. 4 0
      citu-module-system/citu-module-system-api/src/main/java/com/citu/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java
  29. 6 0
      citu-module-system/citu-module-system-biz/src/main/java/com/citu/module/system/api/mail/MailSendApiImpl.java
  30. 6 0
      citu-module-system/citu-module-system-biz/src/main/java/com/citu/module/system/mq/message/mail/MailSendMessage.java
  31. 3 2
      citu-module-system/citu-module-system-biz/src/main/java/com/citu/module/system/mq/producer/mail/MailProducer.java
  32. 3 1
      citu-module-system/citu-module-system-biz/src/main/java/com/citu/module/system/service/mail/MailSendService.java
  33. 72 8
      citu-module-system/citu-module-system-biz/src/main/java/com/citu/module/system/service/mail/MailSendServiceImpl.java
  34. 16 16
      citu-module-system/citu-module-system-biz/src/test/java/com/citu/module/system/service/mail/MailSendServiceImplTest.java

+ 14 - 0
citu-module-mall/citu-module-product-api/src/main/java/com/citu/module/product/api/sku/dto/ProductSkuExtendRespDTO.java

@@ -0,0 +1,14 @@
+package com.citu.module.product.api.sku.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "RPC 服务 - 商品属性项扩展 Response DTO")
+@Data
+public class ProductSkuExtendRespDTO {
+
+    @Schema(description = "文件地址")
+    private List<String> fileUrls;
+}

+ 3 - 0
citu-module-mall/citu-module-product-api/src/main/java/com/citu/module/product/api/sku/dto/ProductSkuRespDTO.java

@@ -36,6 +36,9 @@ public class ProductSkuRespDTO {
     @Schema(description = "商品体积,单位:m^3 平米", requiredMode = Schema.RequiredMode.REQUIRED, example = "3.0")
     private Double volume;
 
+    @Schema(description = "商品属性项扩展 Response DTO")
+    private ProductSkuExtendRespDTO extend;
+
     @Schema(description = "一级分销的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "550")
     private Integer firstBrokeragePrice;
     @Schema(description = "二级分销的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "250")

+ 5 - 0
citu-module-mall/citu-module-product-api/src/main/java/com/citu/module/product/api/spu/dto/ProductSpuRespDTO.java

@@ -27,6 +27,11 @@ public class ProductSpuRespDTO {
      * 商品名称
      */
     private String name;
+    /**
+     * 商品类型
+     *
+     */
+    private String type;
     /**
      * 单位
      *

+ 5 - 3
citu-module-mall/citu-module-product-api/src/main/java/com/citu/module/product/enums/spu/ProductSpuTypeEnum.java

@@ -5,15 +5,17 @@ import lombok.Getter;
 
 /**
  * 商品 SPU 类型
- * 0 普通商品 | 1 虚拟商品
+ * 0 普通商品 | 1 卡密/网盘 | 2 优惠券 | 3 虚拟商品 | 99文件资料
  * @author Rayson
  */
 @Getter
 @AllArgsConstructor
 public enum ProductSpuTypeEnum {
     NORMAL("0", "普通商品"),
-    VIRTUAL("1", "虚拟商品");
-
+    CARD("1", "卡密/网盘"),
+    COUPON("2", "优惠券"),
+    VIRTUAL("3", "虚拟商品"),
+    FILE("99", "文件");
     private final String type;
     private final String name;
 }

+ 4 - 0
citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/controller/admin/spu/vo/ProductSkuRespVO.java

@@ -1,5 +1,6 @@
 package com.citu.module.product.controller.admin.spu.vo;
 
+import com.citu.module.product.dal.dataobject.sku.ProductSkuDO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
@@ -39,6 +40,9 @@ public class ProductSkuRespVO {
     @Schema(description = "商品体积,单位:m^3 平米", example = "2.5")
     private Double volume;
 
+    @Schema(description = "扩展信息")
+    private ProductSkuDO.Extend extend;
+
     @Schema(description = "一级分销的佣金,单位:分", example = "199")
     private Integer firstBrokeragePrice;
 

+ 4 - 0
citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/controller/admin/spu/vo/ProductSkuSaveReqVO.java

@@ -1,5 +1,6 @@
 package com.citu.module.product.controller.admin.spu.vo;
 
+import com.citu.module.product.dal.dataobject.sku.ProductSkuDO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.AllArgsConstructor;
 import lombok.Data;
@@ -44,6 +45,9 @@ public class ProductSkuSaveReqVO {
     @Schema(description = "商品体积,单位:m^3 平米", example = "2.5")
     private Double volume;
 
+    @Schema(description = "扩展信息")
+    private ProductSkuDO.Extend extend;
+
     @Schema(description = "一级分销的佣金,单位:分", example = "199")
     private Integer firstBrokeragePrice;
 

+ 5 - 1
citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java

@@ -1,6 +1,7 @@
 package com.citu.module.product.controller.app.spu.vo;
 
 import com.citu.module.product.controller.app.property.vo.value.AppProductPropertyValueDetailRespVO;
+import com.citu.module.product.dal.dataobject.sku.ProductSkuDO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
@@ -80,7 +81,8 @@ public class AppProductSpuDetailRespVO {
         @Schema(description = "市场价,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
         private Integer marketPrice;
 
-        @Schema(description = "VIP 价格,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "968") // 通过会员等级,计算出折扣后价格
+        @Schema(description = "VIP 价格,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "968")
+        // 通过会员等级,计算出折扣后价格
         private Integer vipPrice;
 
         @Schema(description = "图片地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png")
@@ -95,6 +97,8 @@ public class AppProductSpuDetailRespVO {
         @Schema(description = "商品体积", example = "1024") // 单位:m^3 平米
         private Double volume;
 
+        @Schema(description = "扩展信息")
+        private ProductSkuDO.Extend extend;
     }
 
 }

+ 20 - 1
citu-module-mall/citu-module-product-biz/src/main/java/com/citu/module/product/dal/dataobject/sku/ProductSkuDO.java

@@ -76,7 +76,11 @@ public class ProductSkuDO extends BaseDO {
      * 商品体积,单位:m^3 平米
      */
     private Double volume;
-
+    /**
+     * 扩展信息
+     */
+    @TableField(typeHandler = JacksonTypeHandler.class)
+    private Extend extend;
     /**
      * 一级分销的佣金,单位:分
      */
@@ -129,5 +133,20 @@ public class ProductSkuDO extends BaseDO {
         private String valueName;
 
     }
+
+    /**
+     * SKU信息扩展
+     */
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Extend {
+
+        /**
+         * 文件地址
+         */
+        private List<String> fileUrls;
+
+    }
 }
 

+ 2 - 0
citu-module-mall/citu-module-trade-api/src/main/java/com/citu/module/trade/enums/MessageTemplateConstants.java

@@ -15,4 +15,6 @@ public interface MessageTemplateConstants {
 
     String WXA_ORDER_DELIVERY = "订单发货通知";
 
+    // ======================= 自动发货-邮件接收 =======================
+    String EMAIL_ORDER_DELIVERY = "trade-automatic-delivery-order";
 }

+ 6 - 0
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/admin/order/vo/TradeOrderBaseVO.java

@@ -1,5 +1,8 @@
 package com.citu.module.trade.controller.admin.order.vo;
 
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import com.citu.module.trade.dal.dataobject.order.TradeOrderDO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
@@ -123,6 +126,9 @@ public class TradeOrderBaseVO {
     @Schema(description = "收件人详细地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "中关村大街 1 号")
     private String receiverDetailAddress;
 
+    @Schema(description = "收货信息扩展")
+    private TradeOrderDO.ReceiverExtend receiverExtend;
+
     // ========== 售后基本信息 ==========
 
     @Schema(description = "售后状态", example = "1")

+ 6 - 0
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/admin/order/vo/TradeOrderDeliveryReqVO.java

@@ -1,12 +1,18 @@
 package com.citu.module.trade.controller.admin.order.vo;
 
 import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 
 import javax.validation.constraints.NotNull;
 
 @Schema(description = "管理后台 - 订单发货 Request VO")
 @Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
 public class TradeOrderDeliveryReqVO {
 
     @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")

+ 3 - 0
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/admin/order/vo/TradeOrderItemBaseVO.java

@@ -29,6 +29,9 @@ public class TradeOrderItemBaseVO {
     @Schema(description = "商品 SPU 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
     private String spuName;
 
+    @Schema(description = "商品 SPU 类型")
+    private String spuType;
+
     @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     private Long skuId;
 

+ 4 - 0
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/admin/order/vo/TradeOrderUpdateAddressReqVO.java

@@ -1,5 +1,6 @@
 package com.citu.module.trade.controller.admin.order.vo;
 
+import com.citu.module.trade.dal.dataobject.order.TradeOrderDO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
@@ -30,4 +31,7 @@ public class TradeOrderUpdateAddressReqVO {
     @NotEmpty(message = "收件人详细地址不能为空")
     private String receiverDetailAddress;
 
+    @Schema(description = "收货信息扩展")
+    private TradeOrderDO.ReceiverExtend receiverExtend;
+
 }

+ 1 - 1
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/app/order/vo/AppTradeOrderCreateReqVO.java

@@ -13,7 +13,7 @@ public class AppTradeOrderCreateReqVO extends AppTradeOrderSettlementReqVO {
     @Schema(description = "备注", example = "这个是我的订单哟")
     private String remark;
 
-    @AssertTrue(message = "配送方式不能为空")
+//    @AssertTrue(message = "配送方式不能为空")
     @JsonIgnore
     public boolean isDeliveryTypeNotNull() {
         return getDeliveryType() != null;

+ 4 - 0
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/app/order/vo/AppTradeOrderDetailRespVO.java

@@ -1,6 +1,7 @@
 package com.citu.module.trade.controller.app.order.vo;
 
 import com.citu.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO;
+import com.citu.module.trade.dal.dataobject.order.TradeOrderDO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
@@ -112,6 +113,9 @@ public class AppTradeOrderDetailRespVO {
     @Schema(description = "收件人详细地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "中关村大街 1 号")
     private String receiverDetailAddress;
 
+    @Schema(description = "收货信息扩展")
+    private TradeOrderDO.ReceiverExtend receiverExtend;
+
     @Schema(description = "自提门店编号", example = "1088")
     private Long pickUpStoreId;
 

+ 7 - 0
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java

@@ -1,8 +1,11 @@
 package com.citu.module.trade.controller.app.order.vo;
 
 import cn.hutool.core.util.ObjUtil;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
 import com.citu.framework.common.validation.InEnum;
 import com.citu.framework.common.validation.Mobile;
+import com.citu.module.trade.dal.dataobject.order.TradeOrderDO;
 import com.citu.module.trade.enums.delivery.DeliveryTypeEnum;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -47,6 +50,10 @@ public class AppTradeOrderSettlementReqVO {
     @Mobile(message = "收件人手机格式不正确")
     private String receiverMobile;
 
+    @Schema(description = "收货信息扩展,兼容自动发货虚拟商品等的场景")
+    private TradeOrderDO.ReceiverExtend receiverExtend;
+
+
     // ========== 秒杀活动相关字段 ==========
     @Schema(description = "秒杀活动编号", example = "1024")
     private Long seckillActivityId;

+ 6 - 0
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/app/order/vo/AppTradeOrderSettlementRespVO.java

@@ -1,6 +1,7 @@
 package com.citu.module.trade.controller.app.order.vo;
 
 import com.citu.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO;
+import com.citu.module.trade.dal.dataobject.order.TradeOrderItemDO;
 import com.citu.module.trade.service.price.bo.TradePriceCalculateRespBO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.AllArgsConstructor;
@@ -54,6 +55,8 @@ public class AppTradeOrderSettlementRespVO {
         private Long spuId;
         @Schema(description = "SPU 名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "Apple iPhone 12")
         private String spuName;
+        @Schema(description = "商品 SPU 类型")
+        private String spuType;
 
         // ========== SKU 信息 ==========
 
@@ -67,6 +70,9 @@ public class AppTradeOrderSettlementRespVO {
         @Schema(description = "属性数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
         private List<AppProductPropertyValueDetailRespVO> properties;
 
+        @Schema(description = "扩展信息")
+        private TradeOrderItemDO.Extend extend;
+
         // ========== 购物车信息 ==========
 
         @Schema(description = "购物车编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")

+ 8 - 0
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/controller/app/order/vo/item/AppTradeOrderItemRespVO.java

@@ -1,6 +1,9 @@
 package com.citu.module.trade.controller.app.order.vo.item;
 
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
 import com.citu.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO;
+import com.citu.module.trade.dal.dataobject.order.TradeOrderItemDO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
@@ -20,6 +23,8 @@ public class AppTradeOrderItemRespVO {
     private Long spuId;
     @Schema(description = "商品 SPU 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
     private String spuName;
+    @Schema(description = "商品 SPU 类型")
+    private String spuType;
 
     @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     private Long skuId;
@@ -29,6 +34,9 @@ public class AppTradeOrderItemRespVO {
      */
     private List<AppProductPropertyValueDetailRespVO> properties;
 
+    @Schema(description = "扩展信息")
+    private TradeOrderItemDO.Extend extend;
+
     @Schema(description = "商品图片", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
     private String picUrl;
 

+ 30 - 0
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/dal/dataobject/order/TradeOrderDO.java

@@ -18,6 +18,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
 import lombok.*;
 
+import java.io.Serializable;
 import java.time.LocalDateTime;
 import java.util.List;
 import java.util.Map;
@@ -107,6 +108,7 @@ public class TradeOrderDO extends BaseDO {
      * 商家备注
      */
     private String remark;
+
     /**
      * 是否评价
      *
@@ -236,6 +238,12 @@ public class TradeOrderDO extends BaseDO {
      */
     private String receiverDetailAddress;
 
+    /**
+     * 收货信息扩展,兼容自动发货虚拟商品等的场景
+     */
+    @TableField(typeHandler = JacksonTypeHandler.class)
+    private ReceiverExtend receiverExtend;
+
     /**
      * 自提门店编号
      *
@@ -360,4 +368,26 @@ public class TradeOrderDO extends BaseDO {
      */
     private Long pointActivityId;
 
+    /**
+     * 接收信息扩展
+     */
+    @Data
+    public static class ReceiverExtend implements Serializable {
+
+        /**
+         * QQ 号
+         */
+        private String qq;
+
+        /**
+         * 微信号
+         */
+        private String wx;
+
+        /**
+         * 邮箱号
+         */
+        private String email;
+    }
+
 }

+ 27 - 0
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/dal/dataobject/order/TradeOrderItemDO.java

@@ -8,8 +8,10 @@ import com.baomidou.mybatisplus.annotation.KeySequence;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
 
 import java.io.Serializable;
@@ -64,6 +66,12 @@ public class TradeOrderItemDO extends BaseDO {
      * 冗余 ProductSkuDO 的 spuName 名称
      */
     private String spuName;
+    /**
+     * 商品 SPU 类型
+     *
+     * 冗余 ProductSkuDO 的 type 类型
+     */
+    private String spuType;
     /**
      * 商品 SKU 编号
      *
@@ -77,6 +85,12 @@ public class TradeOrderItemDO extends BaseDO {
      */
     @TableField(typeHandler = JacksonTypeHandler.class)
     private List<Property> properties;
+    /**
+     * 扩展信息
+     * 冗余 ProductSkuDO 的 extend 字典
+     */
+    @TableField(typeHandler = JacksonTypeHandler.class)
+    private Extend extend;
     /**
      * 商品图片
      */
@@ -211,5 +225,18 @@ public class TradeOrderItemDO extends BaseDO {
 
     }
 
+    /**
+     * SKU信息扩展
+     */
+    @Data
+    public static class Extend implements Serializable {
+
+        /**
+         * 文件地址
+         */
+        private List<String> fileUrls;
+
+    }
+
 }
 

+ 2 - 1
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/framework/rpc/config/RpcConfiguration.java

@@ -22,6 +22,7 @@ import com.citu.module.promotion.api.luck.LuckLotteryApi;
 import com.citu.module.promotion.api.point.PointActivityApi;
 import com.citu.module.promotion.api.reward.RewardActivityApi;
 import com.citu.module.promotion.api.seckill.SeckillActivityApi;
+import com.citu.module.system.api.mail.MailSendApi;
 import com.citu.module.system.api.notify.NotifyMessageSendApi;
 import com.citu.module.system.api.social.SocialClientApi;
 import com.citu.module.system.api.social.SocialUserApi;
@@ -36,7 +37,7 @@ import org.springframework.context.annotation.Configuration;
         MemberUserApi.class, MemberPointApi.class, MemberLevelApi.class, MemberAddressApi.class, MemberConfigApi.class,
         ProductSpuApi.class, ProductSkuApi.class, ProductCommentApi.class, ProductCategoryApi.class, LuckLotteryApi.class,
         PayOrderApi.class, PayRefundApi.class, PayTransferApi.class, PayWalletApi.class,
-        AdminUserApi.class, NotifyMessageSendApi.class, SocialClientApi.class, SocialUserApi.class
+        AdminUserApi.class, NotifyMessageSendApi.class, SocialClientApi.class, SocialUserApi.class, MailSendApi.class
 })
 public class RpcConfiguration {
 }

+ 7 - 0
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/order/TradeOrderUpdateService.java

@@ -67,6 +67,13 @@ public interface TradeOrderUpdateService {
      */
     void deliveryOrder(TradeOrderDeliveryReqVO deliveryReqVO);
 
+    /**
+     * 【系统】自动发货交易订单
+     *
+     * @param deliveryReqVO 发货请求
+     */
+    void automaticDeliveryOrder(TradeOrderDeliveryReqVO deliveryReqVO);
+
     /**
      * 【会员】收货交易订单
      *

+ 43 - 8
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/order/TradeOrderUpdateServiceImpl.java

@@ -88,16 +88,18 @@ import static com.citu.module.trade.enums.MessageTemplateConstants.WXA_ORDER_DEL
 @Slf4j
 public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
 
+    @Resource
+    public SocialClientApi socialClientApi;
+    @Resource
+    public PayRefundApi payRefundApi;
     @Resource
     private TradeOrderMapper tradeOrderMapper;
     @Resource
     private TradeOrderItemMapper tradeOrderItemMapper;
     @Resource
     private TradeNoRedisDAO tradeNoRedisDAO;
-
     @Resource
     private List<TradeOrderHandler> tradeOrderHandlers;
-
     @Resource
     private CartService cartService;
     @Resource
@@ -108,18 +110,12 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     private TradeMessageService tradeMessageService;
     @Resource
     private DeliveryPickUpStoreService pickUpStoreService;
-
     @Resource
     private PayOrderApi payOrderApi;
     @Resource
     private MemberAddressApi addressApi;
     @Resource
     private ProductCommentApi productCommentApi;
-    @Resource
-    public SocialClientApi socialClientApi;
-    @Resource
-    public PayRefundApi payRefundApi;
-
     @Resource
     private TradeOrderProperties tradeOrderProperties;
 
@@ -403,6 +399,45 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         getSelf().sendDeliveryOrderMessage(order, deliveryReqVO);
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_DELIVERY)
+    public void automaticDeliveryOrder(TradeOrderDeliveryReqVO deliveryReqVO) {
+        // 1.1 校验并获得交易订单(可发货)
+        TradeOrderDO order = validateOrderDeliverable(deliveryReqVO.getId());
+        // 1.2 校验 deliveryType 是否为快递,是快递才可以发货
+        if (null != order.getDeliveryType()) {
+            return;
+        }
+
+        // 2. 更新订单为已发货
+        TradeOrderDO updateOrderObj = new TradeOrderDO();
+        // 2.1 快递发货
+        DeliveryExpressDO express = null;
+
+        // 2.2 无需发货
+        updateOrderObj.setLogisticsId(0L).setLogisticsNo("");
+
+        // 执行更新
+        updateOrderObj.setStatus(TradeOrderStatusEnum.DELIVERED.getStatus())
+                .setDeliveryTime(LocalDateTime.now());
+        int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(), updateOrderObj);
+        if (updateCount == 0) {
+            throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);
+        }
+
+        // 3. 记录订单日志
+        TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.DELIVERED.getStatus(),
+                MapUtil.<String, Object>builder().put("deliveryName", express != null ? express.getName() : "")
+                        .put("logisticsNo", express != null ? deliveryReqVO.getLogisticsNo() : "").build());
+
+        // 4.1 发送站内信
+        tradeMessageService.sendMessageWhenDeliveryOrder(new TradeOrderMessageWhenDeliveryOrderReqBO()
+                .setOrderId(order.getId()).setUserId(order.getUserId()).setMessage(null));
+        // 4.2 发送订阅消息
+        getSelf().sendDeliveryOrderMessage(order, deliveryReqVO);
+    }
+
     @Async
     public void sendDeliveryOrderMessage(TradeOrderDO order, TradeOrderDeliveryReqVO deliveryReqVO) {
         // 构建并发送模版消息

+ 117 - 0
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/order/handler/TradeAutomaticDeliveryOrderHandler.java

@@ -0,0 +1,117 @@
+package com.citu.module.trade.service.order.handler;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.MapUtil;
+import com.citu.framework.common.util.object.BeanUtils;
+import com.citu.module.product.api.sku.ProductSkuApi;
+import com.citu.module.product.api.sku.dto.ProductSkuExtendRespDTO;
+import com.citu.module.product.api.sku.dto.ProductSkuRespDTO;
+import com.citu.module.system.api.mail.MailSendApi;
+import com.citu.module.system.api.mail.dto.MailSendSingleToUserReqDTO;
+import com.citu.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
+import com.citu.module.trade.dal.dataobject.order.TradeOrderDO;
+import com.citu.module.trade.dal.dataobject.order.TradeOrderItemDO;
+import com.citu.module.trade.dal.mysql.order.TradeOrderItemMapper;
+import com.citu.module.trade.service.order.TradeOrderUpdateService;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static com.citu.module.trade.enums.MessageTemplateConstants.EMAIL_ORDER_DELIVERY;
+
+/**
+ * 订单自动发货 {@link TradeOrderHandler} 实现类
+ *
+ * @author Rayson
+ */
+@Component
+public class TradeAutomaticDeliveryOrderHandler implements TradeOrderHandler {
+
+    @Resource
+    @Lazy // 延迟加载,避免循环依赖
+    private TradeOrderUpdateService orderUpdateService;
+
+    @Resource
+    @Lazy // 延迟加载,避免循环依赖
+    private TradeOrderItemMapper tradeOrderItemMapper;
+
+    @Resource
+    private ProductSkuApi productSkuApi;
+
+    @Resource
+    private MailSendApi mailSendApi;
+
+    private boolean validateOrderAutomaticDelivery(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
+        return true;
+    }
+
+    @Override
+    public void beforeOrderCreate(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
+        // 效验
+        if (!validateOrderAutomaticDelivery(order, orderItems)) {
+            return;
+        }
+    }
+
+    @Override
+    public void afterPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
+        // 支付成功后
+//        if (!validateOrderAutomaticDelivery(order, orderItems)) {
+//            return;
+//        }
+
+        // 发货操作
+        orderUpdateService.automaticDeliveryOrder(new TradeOrderDeliveryReqVO().setId(order.getId()));
+
+        // 获取订单信息
+        List<ProductSkuRespDTO> skuList =  productSkuApi.getSkuList(
+                orderItems.stream()
+                        .map(TradeOrderItemDO::getSkuId).collect(Collectors.toList())
+        ).getCheckedData();
+
+        if(CollUtil.isEmpty(skuList)) {
+            return;
+        }
+
+        List<String> allFileUrls = skuList.stream()
+                .map(ProductSkuRespDTO::getExtend)
+                .filter(Objects::nonNull)
+                .map(ProductSkuExtendRespDTO::getFileUrls)
+                .flatMap(List::stream)
+                .collect(Collectors.toList());
+
+
+        for (TradeOrderItemDO item : orderItems) {
+            ProductSkuRespDTO spu = skuList.stream()
+                            .filter(sku -> sku.getId().equals(item.getSkuId())).findFirst().orElse(null);
+            if(null!= spu) {
+                // 修改订单项 扩展信息
+                tradeOrderItemMapper.updateById(new TradeOrderItemDO()
+                        .setId(item.getId())
+                        .setExtend(BeanUtils.toBean(spu.getExtend(), TradeOrderItemDO.Extend.class ))
+                );
+
+            }
+        }
+
+        if(CollUtil.isEmpty(allFileUrls)) {
+            return;
+        }
+
+        // 发送邮件
+        MailSendSingleToUserReqDTO reqDTO = new MailSendSingleToUserReqDTO();
+        reqDTO.setMail(order.getReceiverExtend().getEmail());
+        reqDTO.setTemplateCode(EMAIL_ORDER_DELIVERY);
+        reqDTO.setFileUrl(allFileUrls);
+
+        reqDTO.setTemplateParams(MapUtil.<String, Object>builder().build());
+
+        mailSendApi.sendSingleMailToMember2(reqDTO);
+    }
+}

+ 11 - 0
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/price/bo/TradePriceCalculateRespBO.java

@@ -1,8 +1,10 @@
 package com.citu.module.trade.service.price.bo;
 
 import com.citu.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
+import com.citu.module.product.api.sku.dto.ProductSkuExtendRespDTO;
 import com.citu.module.promotion.enums.common.PromotionTypeEnum;
 import com.citu.module.trade.enums.order.TradeOrderTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
 import java.time.LocalDateTime;
@@ -223,6 +225,10 @@ public class TradePriceCalculateRespBO {
          * 商品名
          */
         private String spuName;
+        /**
+         * 商品类型
+         */
+        private String spuType;
         /**
          * 商品图片
          *
@@ -265,6 +271,11 @@ public class TradePriceCalculateRespBO {
          */
         private List<ProductPropertyValueDetailRespDTO> properties;
 
+        /**
+         * extend
+         */
+        private ProductSkuExtendRespDTO extend;
+
         /**
          * 赠送的积分
          */

+ 1 - 1
citu-module-mall/citu-module-trade-biz/src/main/java/com/citu/module/trade/service/price/calculator/TradePriceCalculatorHelper.java

@@ -59,7 +59,7 @@ public class TradePriceCalculatorHelper {
             orderItem.setPicUrl(sku.getPicUrl()).setProperties(sku.getProperties())
                     .setWeight(sku.getWeight()).setVolume(sku.getVolume());
             // spu 信息
-            orderItem.setSpuName(spu.getName()).setCategoryId(spu.getCategoryId())
+            orderItem.setSpuName(spu.getName()).setSpuType(spu.getType()).setCategoryId(spu.getCategoryId())
                     .setDeliveryTypes(spu.getDeliveryTypes()).setDeliveryTemplateId(spu.getDeliveryTemplateId())
                     .setGivePoint(spu.getGiveIntegral()).setUsePoint(0);
             if (StrUtil.isBlank(orderItem.getPicUrl())) {

+ 3 - 0
citu-module-system/citu-module-system-api/src/main/java/com/citu/module/system/api/mail/MailSendApi.java

@@ -26,4 +26,7 @@ public interface MailSendApi {
     @Operation(summary = "发送单条邮件给 Member 用户", description = "在 mail 为空时,使用 userId 加载对应 Member 的邮箱")
     CommonResult<Long> sendSingleMailToMember(@Valid @RequestBody MailSendSingleToUserReqDTO reqDTO);
 
+    @PostMapping(PREFIX + "/send-single-member2")
+    @Operation(summary = "发送单条邮件给 Member 用户", description = "在 mail 为空时,使用 userId 加载对应 Member 的邮箱")
+    CommonResult<Long> sendSingleMailToMember2(@Valid @RequestBody MailSendSingleToUserReqDTO reqDTO);
 }

+ 4 - 0
citu-module-system/citu-module-system-api/src/main/java/com/citu/module/system/api/mail/dto/MailSendSingleToUserReqDTO.java

@@ -5,6 +5,7 @@ import lombok.Data;
 
 import javax.validation.constraints.Email;
 import javax.validation.constraints.NotNull;
+import java.util.List;
 import java.util.Map;
 
 @Schema(description = "RPC 服务 - 邮件发送给 Admin 或者 Member 用户 Request DTO")
@@ -24,4 +25,7 @@ public class MailSendSingleToUserReqDTO {
     @Schema(description = "邮件模板参数")
     private Map<String, Object> templateParams;
 
+    @Schema(description = "邮件附件")
+    private List<String> fileUrl;
+
 }

+ 6 - 0
citu-module-system/citu-module-system-biz/src/main/java/com/citu/module/system/api/mail/MailSendApiImpl.java

@@ -1,5 +1,6 @@
 package com.citu.module.system.api.mail;
 
+import com.citu.framework.common.enums.UserTypeEnum;
 import com.citu.framework.common.pojo.CommonResult;
 import com.citu.module.system.api.mail.dto.MailSendSingleToUserReqDTO;
 import com.citu.module.system.service.mail.MailSendService;
@@ -29,4 +30,9 @@ public class MailSendApiImpl implements MailSendApi {
                 reqDTO.getTemplateCode(), reqDTO.getTemplateParams()));
     }
 
+    @Override
+    public CommonResult<Long> sendSingleMailToMember2(MailSendSingleToUserReqDTO reqDTO) {
+        return success(mailSendService.sendSingleMail(reqDTO.getMail(), reqDTO.getUserId(),
+                UserTypeEnum.MEMBER.getValue(), reqDTO.getTemplateCode(), reqDTO.getTemplateParams(), reqDTO.getFileUrl()));
+    }
 }

+ 6 - 0
citu-module-system/citu-module-system-biz/src/main/java/com/citu/module/system/mq/message/mail/MailSendMessage.java

@@ -4,6 +4,7 @@ import lombok.Data;
 
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
+import java.util.List;
 
 /**
  * 邮箱发送消息
@@ -44,4 +45,9 @@ public class MailSendMessage {
     @NotEmpty(message = "邮件内容不能为空")
     private String content;
 
+    /**
+     * 邮件附件
+     */
+    private List<String> fileUrl;
+
 }

+ 3 - 2
citu-module-system/citu-module-system-biz/src/main/java/com/citu/module/system/mq/producer/mail/MailProducer.java

@@ -6,6 +6,7 @@ import org.springframework.context.ApplicationContext;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
+import java.util.List;
 
 /**
  * Mail 邮件相关消息的 Producer
@@ -31,10 +32,10 @@ public class MailProducer {
      * @param content 邮件内容
      */
     public void sendMailSendMessage(Long sendLogId, String mail, Long accountId,
-                                    String nickname, String title, String content) {
+                                    String nickname, String title, String content,List<String> fileUrl) {
         MailSendMessage message = new MailSendMessage()
                 .setLogId(sendLogId).setMail(mail).setAccountId(accountId)
-                .setNickname(nickname).setTitle(title).setContent(content);
+                .setNickname(nickname).setTitle(title).setContent(content).setFileUrl(fileUrl);
         applicationContext.publishEvent(message);
     }
 

+ 3 - 1
citu-module-system/citu-module-system-biz/src/main/java/com/citu/module/system/service/mail/MailSendService.java

@@ -2,6 +2,7 @@ package com.citu.module.system.service.mail;
 
 import com.citu.module.system.mq.message.mail.MailSendMessage;
 
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -44,10 +45,11 @@ public interface MailSendService {
      * @param userType 用户类型
      * @param templateCode 邮件模版编码
      * @param templateParams 邮件模版参数
+     * @param fileUrl 附件地址
      * @return 发送日志编号
      */
     Long sendSingleMail(String mail, Long userId, Integer userType,
-                        String templateCode, Map<String, Object> templateParams);
+                        String templateCode, Map<String, Object> templateParams, List<String> fileUrl);
 
     /**
      * 执行真正的邮件发送

+ 72 - 8
citu-module-system/citu-module-system-biz/src/main/java/com/citu/module/system/service/mail/MailSendServiceImpl.java

@@ -1,8 +1,11 @@
 package com.citu.module.system.service.mail;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.extra.mail.MailAccount;
 import cn.hutool.extra.mail.MailUtil;
+import cn.hutool.http.HttpUtil;
 import com.citu.framework.common.enums.CommonStatusEnum;
 import com.citu.framework.common.enums.UserTypeEnum;
 import com.citu.module.system.dal.dataobject.mail.MailAccountDO;
@@ -18,6 +21,9 @@ import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 
 import static com.citu.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -49,6 +55,49 @@ public class MailSendServiceImpl implements MailSendService {
     @Resource
     private MailProducer mailProducer;
 
+    /**
+     * 下载文件并保留原始文件名
+     *
+     * @param fileUrls 文件URL列表
+     * @return 下载的文件列表
+     */
+    private static List<File> downloadFilesFromUrls(List<String> fileUrls) {
+        if (CollUtil.isEmpty(fileUrls)) {
+            return null;
+        }
+        List<File> tempFiles = new ArrayList<>();
+        for (String fileUrl : fileUrls) {
+            try {
+                // 从URL中提取文件名
+                String fileName = StrUtil.subAfter(fileUrl, "/", true);
+                if (StrUtil.isBlank(fileName)) {
+                    fileName = "unknown_file"; // 如果URL中没有文件名,使用默认名称
+                }
+
+                // 创建临时文件
+                File tempFile = FileUtil.createTempFile(null, null, true);
+
+                // 使用 Hutool 的 HttpUtil.downloadFile 下载文件到临时文件
+                long size = HttpUtil.downloadFile(fileUrl, tempFile);
+
+                if (size > 0) {
+                    // 将临时文件重命名为原始文件名
+                    File targetFile = new File(tempFile.getParent(), fileName);
+                    FileUtil.rename(tempFile, targetFile.getName(), true);
+
+                    log.info("文件下载成功: " + fileUrl + ", 文件大小: " + size + " 字节");
+                    tempFiles.add(targetFile);
+                } else {
+                    log.info("文件下载失败: " + fileUrl);
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+                log.info("文件下载失败: " + fileUrl);
+            }
+        }
+        return tempFiles;
+    }
+
     @Override
     public Long sendSingleMailToAdmin(String mail, Long userId,
                                       String templateCode, Map<String, Object> templateParams) {
@@ -60,7 +109,7 @@ public class MailSendServiceImpl implements MailSendService {
             }
         }
         // 执行发送
-        return sendSingleMail(mail, userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams);
+        return sendSingleMail(mail, userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams, null);
     }
 
     @Override
@@ -71,12 +120,12 @@ public class MailSendServiceImpl implements MailSendService {
             mail = memberService.getMemberUserEmail(userId);
         }
         // 执行发送
-        return sendSingleMail(mail, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams);
+        return sendSingleMail(mail, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams,null);
     }
 
     @Override
     public Long sendSingleMail(String mail, Long userId, Integer userType,
-                               String templateCode, Map<String, Object> templateParams) {
+                               String templateCode, Map<String, Object> templateParams,List<String> fileUrl) {
         // 校验邮箱模版是否合法
         MailTemplateDO template = validateMailTemplate(templateCode);
         // 校验邮箱账号是否合法
@@ -95,7 +144,7 @@ public class MailSendServiceImpl implements MailSendService {
         // 发送 MQ 消息,异步执行发送短信
         if (isSend) {
             mailProducer.sendMailSendMessage(sendLogId, mail, account.getId(),
-                    template.getNickname(), title, content);
+                    template.getNickname(), title, content,fileUrl);
         }
         return sendLogId;
     }
@@ -104,16 +153,31 @@ public class MailSendServiceImpl implements MailSendService {
     public void doSendMail(MailSendMessage message) {
         // 1. 创建发送账号
         MailAccountDO account = validateMailAccount(message.getAccountId());
-        MailAccount mailAccount  = buildMailAccount(account, message.getNickname());
+        MailAccount mailAccount = buildMailAccount(account, message.getNickname());
         // 2. 发送邮件
+
+        // 下载所有文件到本地临时文件
+        List<File> tempFiles = downloadFilesFromUrls(message.getFileUrl());
         try {
-            String messageId = MailUtil.send(mailAccount, message.getMail(),
-                    message.getTitle(), message.getContent(), true);
+            String messageId = null;
+            if (CollUtil.isEmpty(tempFiles)) {
+                // 无附件
+                messageId = MailUtil.send(mailAccount, message.getMail(),
+                        message.getTitle(), message.getContent(), true);
+            } else {
+                // 加入附件
+                messageId = MailUtil.send(mailAccount, message.getMail(),
+                        message.getTitle(), message.getContent(), true, tempFiles.toArray(new File[0]));
+            }
             // 3. 更新结果(成功)
             mailLogService.updateMailSendResult(message.getLogId(), messageId, null);
         } catch (Exception e) {
             // 3. 更新结果(异常)
             mailLogService.updateMailSendResult(message.getLogId(), null, e);
+        } finally {
+            if (CollUtil.isNotEmpty(tempFiles)) {
+                tempFiles.forEach(FileUtil::del);
+            }
         }
     }
 
@@ -158,7 +222,7 @@ public class MailSendServiceImpl implements MailSendService {
     /**
      * 校验邮件参数是否确实
      *
-     * @param template 邮箱模板
+     * @param template       邮箱模板
      * @param templateParams 参数列表
      */
     @VisibleForTesting

+ 16 - 16
citu-module-system/citu-module-system-biz/src/test/java/com/citu/module/system/service/mail/MailSendServiceImplTest.java

@@ -104,7 +104,7 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
         assertEquals(mailLogId, resultMailLogId);
         // 断言调用
         verify(mailProducer).sendMailSendMessage(eq(mailLogId), eq(user.getEmail()),
-                eq(account.getId()), eq(template.getNickname()), eq(title), eq(content));
+                eq(account.getId()), eq(template.getNickname()), eq(title), eq(content), null);
     }
 
     @Test
@@ -145,7 +145,7 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
         assertEquals(mailLogId, resultMailLogId);
         // 断言调用
         verify(mailProducer).sendMailSendMessage(eq(mailLogId), eq(mail),
-                eq(account.getId()), eq(template.getNickname()), eq(title), eq(content));
+                eq(account.getId()), eq(template.getNickname()), eq(title), eq(content), null);
     }
 
     /**
@@ -182,12 +182,12 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
                 eq(account), eq(template), eq(content), eq(templateParams), eq(true))).thenReturn(mailLogId);
 
         // 调用
-        Long resultMailLogId = mailSendService.sendSingleMail(mail, userId, userType, templateCode, templateParams);
+        Long resultMailLogId = mailSendService.sendSingleMail(mail, userId, userType, templateCode, templateParams, null);
         // 断言
         assertEquals(mailLogId, resultMailLogId);
         // 断言调用
         verify(mailProducer).sendMailSendMessage(eq(mailLogId), eq(mail),
-                eq(account.getId()), eq(template.getNickname()), eq(title), eq(content));
+                eq(account.getId()), eq(template.getNickname()), eq(title), eq(content), null);
     }
 
     /**
@@ -224,12 +224,12 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
                 eq(account), eq(template), eq(content), eq(templateParams), eq(false))).thenReturn(mailLogId);
 
         // 调用
-        Long resultMailLogId = mailSendService.sendSingleMail(mail, userId, userType, templateCode, templateParams);
+        Long resultMailLogId = mailSendService.sendSingleMail(mail, userId, userType, templateCode, templateParams, null);
         // 断言
         assertEquals(mailLogId, resultMailLogId);
         // 断言调用
         verify(mailProducer, times(0)).sendMailSendMessage(anyLong(), anyString(),
-                anyLong(), anyString(), anyString(), anyString());
+                anyLong(), anyString(), anyString(), anyString(), null);
     }
 
     @Test
@@ -279,16 +279,16 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
             // mock 方法(发送邮件)
             String messageId = randomString();
             mailUtilMock.when(() -> MailUtil.send(
-                    argThat(mailAccount -> {
-                        assertEquals("芋艿 <7685@qq.com>", mailAccount.getFrom());
-                        assertTrue(mailAccount.isAuth());
-                        assertEquals(account.getUsername(), mailAccount.getUser());
-                        assertEquals(account.getPassword(), mailAccount.getPass());
-                        assertEquals(account.getHost(), mailAccount.getHost());
-                        assertEquals(account.getPort(), mailAccount.getPort());
-                        assertEquals(account.getSslEnable(), mailAccount.isSslEnable());
-                        return true;
-                    }), eq(message.getMail()), eq(message.getTitle()), eq(message.getContent()), eq(true)))
+                            argThat(mailAccount -> {
+                                assertEquals("芋艿 <7685@qq.com>", mailAccount.getFrom());
+                                assertTrue(mailAccount.isAuth());
+                                assertEquals(account.getUsername(), mailAccount.getUser());
+                                assertEquals(account.getPassword(), mailAccount.getPass());
+                                assertEquals(account.getHost(), mailAccount.getHost());
+                                assertEquals(account.getPort(), mailAccount.getPort());
+                                assertEquals(account.getSslEnable(), mailAccount.isSslEnable());
+                                return true;
+                            }), eq(message.getMail()), eq(message.getTitle()), eq(message.getContent()), eq(true)))
                     .thenReturn(messageId);
 
             // 调用