Browse Source

Merge branch 'gift_card_func' into pre

# Conflicts:
#	netflix-dao/src/main/java/com/cyksj/model/entity/GoodsDon.java
#	netflix-dao/src/main/java/com/cyksj/model/request/OrderPayRequest.java
#	netflix-dao/src/main/java/com/cyksj/model/views/GoodsDonSkuFrontView.java
#	netflix-dao/src/main/java/com/cyksj/model/views/GoodsDonViews.java
#	netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java
#	netflix-web/src/main/java/com/cyksj/web/controller/goods/GoodsDonController.java
#	netflix-web/src/main/java/com/cyksj/web/controller/manage/goods/CmsGoodsDonController.java
#	netflix-web/src/main/java/com/cyksj/web/controller/user/DistributePopularizeController.java
zoujiajian 2 năm trước cách đây
mục cha
commit
711b518fa2
52 tập tin đã thay đổi với 1977 bổ sung358 xóa
  1. 5 0
      netflix-common/src/main/java/com/cyksj/dto/RedisKey.java
  2. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/GiftCardGoodsSkuMapper.java
  3. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/GiftCardOrderRelateMapper.java
  4. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/GiftCardOrderUseRecordMapper.java
  5. 19 0
      netflix-dao/src/main/java/com/cyksj/mapper/GiftCardUserRecordMapper.java
  6. 48 0
      netflix-dao/src/main/java/com/cyksj/model/entity/GiftCardGoodsSku.java
  7. 20 0
      netflix-dao/src/main/java/com/cyksj/model/entity/GiftCardOrderRelate.java
  8. 35 0
      netflix-dao/src/main/java/com/cyksj/model/entity/GiftCardOrderUseRecord.java
  9. 77 0
      netflix-dao/src/main/java/com/cyksj/model/entity/GiftCardUserRecord.java
  10. 5 3
      netflix-dao/src/main/java/com/cyksj/model/entity/GoodsDon.java
  11. 4 1
      netflix-dao/src/main/java/com/cyksj/model/entity/OrderDetailView.java
  12. 16 0
      netflix-dao/src/main/java/com/cyksj/model/entity/OrderDon.java
  13. 38 0
      netflix-dao/src/main/java/com/cyksj/model/manage/dto/GiftCardDto.java
  14. 7 0
      netflix-dao/src/main/java/com/cyksj/model/manage/views/OrderDonBackView.java
  15. 4 1
      netflix-dao/src/main/java/com/cyksj/model/manage/views/OrderDonSearchView.java
  16. 1 1
      netflix-dao/src/main/java/com/cyksj/model/manage/views/OrderDonView.java
  17. 29 0
      netflix-dao/src/main/java/com/cyksj/model/request/GiftCardGoodsSkuReq.java
  18. 24 0
      netflix-dao/src/main/java/com/cyksj/model/request/GiftCardPayReq.java
  19. 24 0
      netflix-dao/src/main/java/com/cyksj/model/request/GiftCardReceiveReq.java
  20. 18 1
      netflix-dao/src/main/java/com/cyksj/model/request/OrderPayRequest.java
  21. 19 0
      netflix-dao/src/main/java/com/cyksj/model/request/TelegramBotMsgReq.java
  22. 1 1
      netflix-dao/src/main/java/com/cyksj/model/views/DistributePopularizeOrdersView.java
  23. 55 0
      netflix-dao/src/main/java/com/cyksj/model/views/GiftCardDetailFrontView.java
  24. 66 0
      netflix-dao/src/main/java/com/cyksj/model/views/GiftCardGoodsSkuFrontView.java
  25. 73 0
      netflix-dao/src/main/java/com/cyksj/model/views/GiftCardGoodsSkuView.java
  26. 79 0
      netflix-dao/src/main/java/com/cyksj/model/views/GiftCardUserPayFrontView.java
  27. 66 0
      netflix-dao/src/main/java/com/cyksj/model/views/GiftCardUserPayView.java
  28. 74 0
      netflix-dao/src/main/java/com/cyksj/model/views/GiftCardUserRecordView.java
  29. 2 0
      netflix-dao/src/main/java/com/cyksj/model/views/GoodsDonSkuFrontView.java
  30. 7 0
      netflix-dao/src/main/java/com/cyksj/model/views/GoodsDonViews.java
  31. 30 0
      netflix-dao/src/main/java/com/cyksj/model/views/GoodsSkuGiftCardView.java
  32. 5 0
      netflix-dao/src/main/java/com/cyksj/model/views/UserPersonalView.java
  33. 5 0
      netflix-dao/src/main/java/com/cyksj/model/views/UserTicketView.java
  34. 3 0
      netflix-service/src/main/java/com/cyksj/redis/RedisService.java
  35. 20 0
      netflix-service/src/main/java/com/cyksj/service/giftcard/GiftCardGoodsSkuService.java
  36. 14 0
      netflix-service/src/main/java/com/cyksj/service/giftcard/GiftCardOrderUseRecordService.java
  37. 13 0
      netflix-service/src/main/java/com/cyksj/service/giftcard/GiftCardUserRecordService.java
  38. 128 0
      netflix-service/src/main/java/com/cyksj/service/giftcard/impl/GiftCardGoodsSkuServiceImpl.java
  39. 47 0
      netflix-service/src/main/java/com/cyksj/service/giftcard/impl/GiftCardOrderUseRecordServiceImpl.java
  40. 17 0
      netflix-service/src/main/java/com/cyksj/service/giftcard/impl/GiftCardUserRecordServiceImpl.java
  41. 31 3
      netflix-service/src/main/java/com/cyksj/service/mange/impl/CmsOrderDonServiceImpl.java
  42. 1 1
      netflix-service/src/main/java/com/cyksj/service/order/impl/OrderCommonServiceImpl.java
  43. 439 326
      netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java
  44. 34 0
      netflix-service/src/main/java/com/cyksj/service/telegram/TelegramService.java
  45. 5 0
      netflix-service/src/main/java/com/cyksj/service/user/UserService.java
  46. 120 2
      netflix-service/src/main/java/com/cyksj/service/user/impl/UserServiceImpl.java
  47. 14 4
      netflix-web/src/main/java/com/cyksj/web/controller/goods/GoodsDonController.java
  48. 2 2
      netflix-web/src/main/java/com/cyksj/web/controller/group/GroupRelationController.java
  49. 13 1
      netflix-web/src/main/java/com/cyksj/web/controller/manage/goods/CmsGoodsDonController.java
  50. 120 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/goods/GiftCardController.java
  51. 1 7
      netflix-web/src/main/java/com/cyksj/web/controller/payment/OrderController.java
  52. 60 4
      netflix-web/src/main/java/com/cyksj/web/controller/user/UserController.java

+ 5 - 0
netflix-common/src/main/java/com/cyksj/dto/RedisKey.java

@@ -56,4 +56,9 @@ public class RedisKey {
 
     public static String DISABLE_ACCOUNT_ASSIGN = "disable_account_assign:";
 
+    /**
+     * Telegram 电报机器人推送
+     */
+    public static String TELEGRAM_BOT_MSG ="telegram:bot:msg";
+
 }

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/GiftCardGoodsSkuMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.GiftCardGoodsSku;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardGoodsSkuMapper
+ *创建者: JavaZou
+ *创建时间:2023/8/28 16:35
+ */
+public interface GiftCardGoodsSkuMapper extends BaseMapper<GiftCardGoodsSku> {
+}

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/GiftCardOrderRelateMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.GiftCardOrderRelate;
+
+/*
+ *项目名: yhlxj
+ *文件名: GiftCardOrderRelateMapper
+ *创建者: JavaZou
+ *创建时间:2023/9/14 16:14
+ */
+public interface GiftCardOrderRelateMapper extends BaseMapper<GiftCardOrderRelate> {
+}

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/GiftCardOrderUseRecordMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.GiftCardOrderUseRecord;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardOrderUseRecordMapper
+ *创建者: JavaZou
+ *创建时间:2023/8/29 16:13
+ */
+public interface GiftCardOrderUseRecordMapper extends BaseMapper<GiftCardOrderUseRecord> {
+}

+ 19 - 0
netflix-dao/src/main/java/com/cyksj/mapper/GiftCardUserRecordMapper.java

@@ -0,0 +1,19 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.GiftCardUserRecord;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Update;
+
+import java.math.BigDecimal;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardUserRecordMapper
+ *创建者: JavaZou
+ *创建时间:2023/8/28 12:01
+ */
+public interface GiftCardUserRecordMapper extends BaseMapper<GiftCardUserRecord> {
+	@Update("update gift_card_user_record set remain_crash = remain_crash + #{addCash},is_used = 0 where id = #{gcId} and remain_crash = #{remainCash}")
+	Integer updateGiftCardRemainCash(@Param("gcId") Long gcId, @Param("addCash") BigDecimal addCash, @Param("remainCash") BigDecimal remainCash);
+}

+ 48 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GiftCardGoodsSku.java

@@ -0,0 +1,48 @@
+package com.cyksj.model.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardGoodsSku
+ *创建者: JavaZou
+ *创建时间:2023/8/28 16:34
+ */
+@Getter
+@Setter
+public class GiftCardGoodsSku extends BaseEntity{
+	private Long goodsId;
+
+	/**
+	 * 礼品卡类型 1现金卡、2虚拟卡
+	 */
+	private Integer gcType;
+
+	@TableField(updateStrategy = FieldStrategy.IGNORED)
+	private Long gcGoodsId;
+
+	@TableField(updateStrategy = FieldStrategy.IGNORED)
+	private Long gcSkuId;
+
+	/**
+	 * 现金
+	 */
+	@TableField(updateStrategy = FieldStrategy.IGNORED)
+	private BigDecimal cash;
+
+	/**
+	 * 对应价格
+	 */
+	private BigDecimal price;
+
+	private String logo;
+
+	private Boolean status;
+
+	private Boolean deleted;
+}

+ 20 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GiftCardOrderRelate.java

@@ -0,0 +1,20 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/*
+ *项目名: yhlxj
+ *文件名: GiftCardOrderRelate
+ *创建者: JavaZou
+ *创建时间:2023/9/14 16:14
+ */
+@Getter
+@Setter
+public class GiftCardOrderRelate extends BaseEntity{
+	private Long orderId;
+
+	private String gcPayDetail;
+
+	private Boolean isPay;
+}

+ 35 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GiftCardOrderUseRecord.java

@@ -0,0 +1,35 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardOrderUseRecord
+ *创建者: JavaZou
+ *创建时间:2023/8/29 16:12
+ */
+@Getter
+@Setter
+public class GiftCardOrderUseRecord extends BaseEntity{
+	private Long orderId;
+
+	private Long userId;
+
+	/**
+	 * 礼品卡id
+	 */
+	private Long gcId;
+
+	/**
+	 * 使用礼品卡现金数量
+	 */
+	private BigDecimal cash;
+
+	/**
+	 * 默认已使用
+	 */
+	private Boolean isUsed;
+}

+ 77 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GiftCardUserRecord.java

@@ -0,0 +1,77 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardUserRecord
+ *创建者: JavaZou
+ *创建时间:2023/8/25 18:16
+ */
+@Getter
+@Setter
+public class GiftCardUserRecord extends BaseEntity{
+	private Long userId;
+
+	private Long orderId;
+
+	/**
+	 * 礼品卡类型
+	 */
+	private Integer gcType;
+
+	/**
+	 * 礼品卡明细
+	 */
+	private String gcDetail;
+
+	private Long gcGoodsId;
+
+	private Long gcSkuId;
+
+	private BigDecimal cash;
+
+	private BigDecimal remainCash;
+
+	private Long toUserId;
+
+	private Boolean isSend;
+
+	/**
+	 * 领取时间
+	 */
+	private Date receivedTime;
+
+	private Date payTime;
+
+	/**
+	 * 是否已购买
+	 */
+	private Boolean isPay;
+
+	/**
+	 * 礼品卡兑换随机码
+	 */
+	private String rc;
+
+	private Boolean isUsed;
+
+	/**
+	 * 礼品卡赠送类型
+	 */
+	private String type;
+
+	/**
+	 * 背景图
+	 */
+	private String img;
+
+	/**
+	 * 座位id
+	 */
+	private Long relationId;
+}

+ 5 - 3
netflix-dao/src/main/java/com/cyksj/model/entity/GoodsDon.java

@@ -17,7 +17,8 @@ import java.util.List;
  */
 @Getter
 @Setter
-@SearchBean(tables = "goods_don")
+@SearchBean(tables = "goods_don",
+		where = ":condition:")
 public class GoodsDon extends BaseEntity {
 
 
@@ -73,7 +74,7 @@ public class GoodsDon extends BaseEntity {
      * 分类
      * 1、AI  2、流媒体
      */
-    private Long category;
+    private Integer category;
 
     /**
      * 二级分类
@@ -187,7 +188,8 @@ public class GoodsDon extends BaseEntity {
     @Getter
     public enum SpecialType {
         recharge("代充"),
-        courseware("课件")
+        courseware("课程"),
+        giftCard("礼品卡")
         ;
 
         private String desc;

+ 4 - 1
netflix-dao/src/main/java/com/cyksj/model/entity/OrderDetailView.java

@@ -17,7 +17,7 @@ import java.math.BigDecimal;
 @Getter
 @Setter
 @SearchBean(tables = "order_don o left join goods_don_sku sku on o.sku_id = sku.id " +
-		"left join goods_don g on g.id = sku.goods_id ")
+		"left join goods_don g on g.id = o.goods_id ")
 public class OrderDetailView {
 	/**
 	 * 订单id
@@ -62,6 +62,9 @@ public class OrderDetailView {
 	@DbField("o.num")
 	private Integer num;
 
+	@DbField("o.pay_title")
+	private String payTitle;
+
 	@DbIgnore
 	private OrderDonWaybill waybill;
 

+ 16 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/OrderDon.java

@@ -2,6 +2,8 @@ package com.cyksj.model.entity;
 
 import com.baomidou.mybatisplus.annotation.FieldStrategy;
 import com.baomidou.mybatisplus.annotation.TableField;
+import com.ejlchina.searcher.bean.DbIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 import lombok.Setter;
@@ -10,6 +12,7 @@ import java.io.Serializable;
 import java.math.BigDecimal;
 import java.util.Arrays;
 import java.util.Date;
+import java.util.List;
 
 /**
  * @author chan
@@ -71,6 +74,11 @@ public class OrderDon extends BaseEntity implements Serializable {
      */
     private BigDecimal refundBalance;
 
+    /**
+     * 礼品卡现金支付金额
+     */
+    private BigDecimal gcCash;
+
     /**
      * 退款原因
      */
@@ -226,6 +234,14 @@ public class OrderDon extends BaseEntity implements Serializable {
 
     private String payTitle;
 
+    /**
+     * 礼品卡现金使用记录
+     */
+    @DbIgnore
+    @TableField(exist = false)
+    @JsonIgnore
+    private List<GiftCardOrderUseRecord> gcUseRecords;
+
     public enum Status {
         /**
          * 订单状态

+ 38 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/dto/GiftCardDto.java

@@ -0,0 +1,38 @@
+package com.cyksj.model.manage.dto;
+
+import com.cyksj.model.request.GiftCardPayReq;
+import com.cyksj.model.views.GiftCardGoodsSkuFrontView;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/*
+ *项目名: yhlxj
+ *文件名: GiftCardDto
+ *创建者: JavaZou
+ *创建时间:2023/9/14 15:40
+ */
+@Getter
+@Setter
+public class GiftCardDto {
+	/**
+	 * 礼品类型
+	 */
+	private String gcShowType;
+
+	/**
+	 * 礼品卡赠送背景
+	 */
+	private String gcImg;
+
+	/**
+	 * 购买 礼品卡
+	 */
+	private List<GiftCardPayReq> giftCards;
+
+	/**
+	 * 购买信息
+	 */
+	private List<GiftCardGoodsSkuFrontView> gcPayDetail;
+}

+ 7 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/views/OrderDonBackView.java

@@ -1,5 +1,6 @@
 package com.cyksj.model.manage.views;
 
+import com.cyksj.model.entity.GoodsDon;
 import com.cyksj.model.entity.OrderDon;
 import com.cyksj.model.entity.OrderDonTransport;
 import com.cyksj.model.entity.OrderDonWaybill;
@@ -63,6 +64,9 @@ public class OrderDonBackView {
 	@DbField("g.title")
 	private String title;
 
+	@DbField("g.special_type")
+	private GoodsDon.SpecialType goodsSpecialType;
+
 	@DbField("o.sku_id")
 	private Long skuId;
 
@@ -96,6 +100,9 @@ public class OrderDonBackView {
 	@DbField("o.balance")
 	private BigDecimal balance;
 
+	@DbField("o.gc_cash")
+	private BigDecimal gcCash;
+
 	@DbField("o.refund_money")
 	private BigDecimal refundMoney;
 

+ 4 - 1
netflix-dao/src/main/java/com/cyksj/model/manage/views/OrderDonSearchView.java

@@ -24,7 +24,7 @@ import java.util.List;
 @Getter
 @Setter
 @SearchBean(tables = "(select * from order_don :orderId:) o left join goods_don_sku sku on o.sku_id = sku.id " +
-		"left join goods_don g on g.id = sku.goods_id " +
+		"left join goods_don g on g.id = o.goods_id " +
 		"left join order_don_transport odt on odt.order_id = o.id")
 public class OrderDonSearchView {
 	@DbField("o.id")
@@ -153,6 +153,9 @@ public class OrderDonSearchView {
 	@DbIgnore
 	private List<GoodsDonSkuView> benefitsViews;
 
+	@DbField("o.pay_title")
+	private String payTitle;
+
 	/**
 	 * 关联兑换码
 	 */

+ 1 - 1
netflix-dao/src/main/java/com/cyksj/model/manage/views/OrderDonView.java

@@ -22,7 +22,7 @@ import java.util.List;
 @Getter
 @Setter
 @SearchBean(tables = "order_don o left join goods_don_sku sku on o.sku_id = sku.id " +
-        "left join goods_don g on g.id = sku.goods_id " +
+        "left join goods_don g on g.id = o.goods_id " +
         "left join order_don_transport odt on odt.order_id = o.id")
 public class OrderDonView {
 

+ 29 - 0
netflix-dao/src/main/java/com/cyksj/model/request/GiftCardGoodsSkuReq.java

@@ -0,0 +1,29 @@
+package com.cyksj.model.request;
+
+import com.cyksj.model.entity.GiftCardGoodsSku;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/*
+ *项目名: yhlxj
+ *文件名: GiftCardGoodsSkuReq
+ *创建者: JavaZou
+ *创建时间:2023/9/13 17:16
+ */
+@Getter
+@Setter
+public class GiftCardGoodsSkuReq {
+	/**
+	 * 礼品卡平台
+	 */
+	private Long goodsId;
+
+	/**
+	 * 礼品卡类型 1现金卡、2虚拟卡
+	 */
+	private Integer gcType;
+
+	private List<GiftCardGoodsSku> configs;
+}

+ 24 - 0
netflix-dao/src/main/java/com/cyksj/model/request/GiftCardPayReq.java

@@ -0,0 +1,24 @@
+package com.cyksj.model.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardPayReq
+ *创建者: JavaZou
+ *创建时间:2023/8/30 11:02
+ */
+@Getter
+@Setter
+public class GiftCardPayReq {
+	/**
+	 * 礼品卡id
+	 */
+	private Long gcId;
+
+	/**
+	 * 礼品卡购买数量
+	 */
+	private Integer num;
+}

+ 24 - 0
netflix-dao/src/main/java/com/cyksj/model/request/GiftCardReceiveReq.java

@@ -0,0 +1,24 @@
+package com.cyksj.model.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotEmpty;
+
+/*
+ *项目名: yhlxj
+ *文件名: GiftCardReceiveReq
+ *创建者: JavaZou
+ *创建时间:2023/9/19 15:01
+ */
+@Getter
+@Setter
+public class GiftCardReceiveReq {
+
+	@NotEmpty
+	private String code;
+
+	private Long userId;
+
+	private Long relationId;
+}

+ 18 - 1
netflix-dao/src/main/java/com/cyksj/model/request/OrderPayRequest.java

@@ -1,6 +1,7 @@
 package com.cyksj.model.request;
 
 import com.cyksj.model.entity.OrderDon;
+import com.cyksj.model.manage.dto.GiftCardDto;
 import lombok.Getter;
 import lombok.Setter;
 import lombok.ToString;
@@ -22,7 +23,6 @@ public class OrderPayRequest {
     /**
      * 商品id
      */
-    @NotNull(message = "缺少必填参数")
     private Long skuId;
 
     /**
@@ -109,4 +109,21 @@ public class OrderPayRequest {
      * 是否是特定价格
      */
     private Boolean isSpecificPrice;
+
+    /**
+     * 礼品卡购买
+     */
+    private GiftCardDto gcPayInfo;
+
+    private Long goodsId;
+
+    /**
+     * 礼品卡现金支付
+     */
+    private BigDecimal gcCash;
+
+    /**
+     * 礼品卡现金支付所拥有id
+     */
+    private List<Long> gcpIds;
 }

+ 19 - 0
netflix-dao/src/main/java/com/cyksj/model/request/TelegramBotMsgReq.java

@@ -0,0 +1,19 @@
+package com.cyksj.model.request;
+
+import lombok.Data;
+
+/**
+ * @author chan
+ * @date 2023/9/12 14:10
+ */
+@Data
+public class TelegramBotMsgReq {
+
+	private String name;
+
+	private String goodsName;
+
+	private Integer number;
+
+	private Long day;
+}

+ 1 - 1
netflix-dao/src/main/java/com/cyksj/model/views/DistributePopularizeOrdersView.java

@@ -59,7 +59,7 @@ public class DistributePopularizeOrdersView {
 	@DbField("od.status")
 	private OrderDon.Status orderStatus;
 
-	@DbIgnore
+	@DbField("od.pay_title")
 	private String specVal;
 
 	@DbField("od.created_time")

+ 55 - 0
netflix-dao/src/main/java/com/cyksj/model/views/GiftCardDetailFrontView.java

@@ -0,0 +1,55 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardDetailFrontView
+ *创建者: JavaZou
+ *创建时间:2023/8/29 17:58
+ */
+@Getter
+@Setter
+@SearchBean(tables = "gift_card_user_record gr left join user u on u.id = gr.user_id")
+public class GiftCardDetailFrontView {
+	@DbField("gr.id")
+	private Long id;
+
+	@DbField("u.headimgurl")
+	private String headimgurl;
+
+	@DbField("u.nickname")
+	private String nickname;
+
+	@DbField("gr.gc_detail")
+	private String gcDetail;
+
+	@DbField("gr.cash")
+	private BigDecimal cash;
+
+	@DbField("gr.gc_goods_id")
+	private Long gcGoodsId;
+
+	@DbField("gr.gc_sku_id")
+	private Long gcSkuId;
+
+	@DbField("gr.remain_cash")
+	private BigDecimal remainCash;
+
+	@DbField("gr.rc")
+	private String code;
+
+	@DbField("gr.gc_type")
+	private Integer gcType;
+
+	@DbField("gr.type")
+	private String gcShowType;
+
+	@DbField("gr.img")
+	private String gcImg;
+}

+ 66 - 0
netflix-dao/src/main/java/com/cyksj/model/views/GiftCardGoodsSkuFrontView.java

@@ -0,0 +1,66 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.DbIgnore;
+import com.ejlchina.searcher.bean.SearchBean;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardGoodsSkuFrontView
+ *创建者: JavaZou
+ *创建时间:2023/8/28 16:36
+ */
+@Getter
+@Setter
+@SearchBean(tables = "gift_card_goods_sku gc left join goods_don g on g.id = gc.gc_goods_id" +
+		" left join goods_don_sku sku on sku.id = gc.gc_sku_id",
+		where = "gc.status is true and gc.deleted is true")
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class GiftCardGoodsSkuFrontView {
+	@DbField("gc.id")
+	private Long id;
+
+	@DbField("gc.goods_id")
+	private Long goodsId;
+
+	@DbField("gc.gc_type")
+	private Integer gcType;
+
+	@DbField("gc.price")
+	private BigDecimal price;
+
+	@DbField("sku.price")
+	private BigDecimal sPrice;
+
+	@DbField("gc.gc_goods_id")
+	private Long gcGoodsId;
+
+	@DbField("gc.gc_sku_id")
+	private Long gcSkuId;
+
+	@DbField("g.title")
+	private String gcGoodsTitle;
+
+	@DbField("sku.spec_val")
+	private String gcSpecVal;
+
+	@DbField("gc.cash")
+	private BigDecimal cash;
+
+	@DbField("gc.logo")
+	private String logo;
+
+	@DbIgnore
+	private Integer gcNum;
+
+	@DbIgnore
+	private String gcShowType;
+
+	@DbIgnore
+	private String gcImg;
+}

+ 73 - 0
netflix-dao/src/main/java/com/cyksj/model/views/GiftCardGoodsSkuView.java

@@ -0,0 +1,73 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardGoodsSkuView
+ *创建者: JavaZou
+ *创建时间:2023/8/30 10:28
+ */
+@Getter
+@Setter
+@SearchBean(tables = "gift_card_goods_sku gc left join goods_don g on g.id = gc.gc_goods_id" +
+		" left join goods_don_sku sku on sku.id = gc.gc_sku_id",
+		where = "gc.deleted is true")
+public class GiftCardGoodsSkuView {
+	@DbField("gc.id")
+	private Long id;
+
+	@DbField("gc.goods_id")
+	private Long goodsId;
+
+	/**
+	 * 礼品卡类型 1现金卡、2虚拟卡
+	 */
+	@DbField("gc.gc_type")
+	private Integer gcType;
+
+	@DbField("gc.gc_goods_id")
+	private Long gcGoodsId;
+
+	@DbField("g.title")
+	private String gcGoodsTitle;
+
+	@DbField("gc.gc_sku_id")
+	private Long gcSkuId;
+
+	@DbField("sku.spec_val")
+	private String gcSpecVal;
+
+	/**
+	 * 现金
+	 */
+	@DbField("gc.cash")
+	private BigDecimal cash;
+
+	/**
+	 * 对应价格
+	 */
+	@DbField("gc.price")
+	private BigDecimal price;
+
+	@DbField("sku.price")
+	private BigDecimal sPrice;
+
+	@DbField("gc.logo")
+	private String logo;
+
+	@DbField("gc.status")
+	private Boolean status;
+
+	@DbField("gc.created_time")
+	private Date createdTime;
+
+	@DbField("gc.update_time")
+	private Date updateTime;
+}

+ 79 - 0
netflix-dao/src/main/java/com/cyksj/model/views/GiftCardUserPayFrontView.java

@@ -0,0 +1,79 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardUserPayFrontView
+ *创建者: JavaZou
+ *创建时间:2023/8/29 17:33
+ * 购买的礼品卡
+ */
+@Getter
+@Setter
+@SearchBean(tables = "(select * from gift_card_user_record where is_pay is true :condition:) gr left join user u on u.id = gr.user_id" +
+		" left join user u2 on u2.id = gr.to_user_id")
+public class GiftCardUserPayFrontView {
+	@DbField("gr.id")
+	private Long id;
+
+	@DbField("gr.gc_type")
+	private Integer gcType;
+
+	@DbField("gr.gc_detail")
+	private String gcDetail;
+
+	/**
+	 * 赠送人
+	 */
+	@DbField("u.nickname")
+	private String donor;
+
+	@DbField("gr.cash")
+	private BigDecimal cash;
+
+	@DbField("gr.gc_goods_id")
+	private Long gcGoodsId;
+
+	@DbField("gr.gc_sku_id")
+	private Long gcSkuId;
+
+	@DbField("gr.remain_cash")
+	private BigDecimal remainCash;
+
+	@DbField("gr.is_send")
+	private Boolean isSend;
+
+	@DbField("gr.rc")
+	private String code;
+
+	@DbField("gr.pay_time")
+	private Date payTime;
+
+	@DbField("gr.received_time")
+	private Date receivedTime;
+
+	/**
+	 * 默认未使用
+	 */
+	@DbField("gr.is_used")
+	private Boolean isUsed;
+
+	@DbField("gr.type")
+	private String gcShowType;
+
+	@DbField("gr.img")
+	private String gcImg;
+
+	@DbField("if(user_id = :uid:,1,2)")
+	private Integer type;
+
+	@DbField("u2.nickname")
+	private String toNickname;
+}

+ 66 - 0
netflix-dao/src/main/java/com/cyksj/model/views/GiftCardUserPayView.java

@@ -0,0 +1,66 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardUserPayView
+ *创建者: JavaZou
+ *创建时间:2023/8/29 18:24
+ */
+@Getter
+@Setter
+@SearchBean(tables = "gift_card_user_record gr left join user u on u.id = gr.user_id" +
+		" left join user u2 on u2.id = gr.to_user_id")
+public class GiftCardUserPayView {
+	@DbField("gr.id")
+	private Long id;
+
+	@DbField("gr.gc_type")
+	private Integer gcType;
+
+	@DbField("gr.gc_detail")
+	private String gcDetail;
+
+	@DbField("gr.user_id")
+	private Long userId;
+
+	/**
+	 * 赠送人
+	 */
+	@DbField("u.nickname")
+	private String donor;
+
+	@DbField("gr.cash")
+	private BigDecimal cash;
+
+	@DbField("gr.remain_cash")
+	private BigDecimal remainCash;
+
+	@DbField("gr.is_send")
+	private Boolean isSend;
+
+	@DbField("gr.is_pay")
+	private Boolean isPay;
+
+	@DbField("gr.to_user_id")
+	private Long toUserId;
+
+	@DbField("u2.nickname")
+	private String toNickname;
+
+	@DbField("gr.rc")
+	private String code;
+
+	@DbField("gr.pay_time")
+	private Date payTime;
+
+	@DbField("gr.received_time")
+	private Date receivedTime;
+}

+ 74 - 0
netflix-dao/src/main/java/com/cyksj/model/views/GiftCardUserRecordView.java

@@ -0,0 +1,74 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/*
+ *项目名: yhlxj
+ *文件名: GiftCardUserRecordView
+ *创建者: JavaZou
+ *创建时间:2023/9/18 11:48
+ */
+@Getter
+@Setter
+@SearchBean(tables = "gift_card_user_record", where = ":uid:")
+public class GiftCardUserRecordView {
+	private Long userId;
+
+	private Long orderId;
+
+	/**
+	 * 礼品卡类型
+	 */
+	private Integer gcType;
+
+	/**
+	 * 礼品卡明细
+	 */
+	private String gcDetail;
+
+	private Long gcGoodsId;
+
+	private Long gcSkuId;
+
+	private BigDecimal cash;
+
+	private BigDecimal remainCash;
+
+	private Long toUserId;
+
+	private Boolean isSend;
+
+	/**
+	 * 领取时间
+	 */
+	private Date receivedTime;
+
+	private Date payTime;
+
+	/**
+	 * 是否已购买
+	 */
+	private Boolean isPay;
+
+	/**
+	 * 礼品卡兑换随机码
+	 */
+	private String rc;
+
+	private Boolean isUsed;
+
+	/**
+	 * 礼品卡赠送类型
+	 */
+	private String type;
+
+	/**
+	 * 背景图
+	 */
+	private String img;
+}

+ 2 - 0
netflix-dao/src/main/java/com/cyksj/model/views/GoodsDonSkuFrontView.java

@@ -3,6 +3,7 @@ package com.cyksj.model.views;
 import com.ejlchina.searcher.bean.DbField;
 import com.ejlchina.searcher.bean.DbIgnore;
 import com.ejlchina.searcher.bean.SearchBean;
+import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import lombok.Getter;
 import lombok.Setter;
@@ -19,6 +20,7 @@ import java.util.List;
 @Getter
 @Setter
 @SearchBean(tables = "goods_don_sku")
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class GoodsDonSkuFrontView {
 
 	private Long id;

+ 7 - 0
netflix-dao/src/main/java/com/cyksj/model/views/GoodsDonViews.java

@@ -142,4 +142,11 @@ public class GoodsDonViews {
 
     @DbIgnore
     private Long specificSkuId;
+
+    private String giftCards;
+
+    @DbIgnore
+    private List<GoodsSkuGiftCardView> giftCardsView;
+
+    private BigDecimal giftCardCash;
 }

+ 30 - 0
netflix-dao/src/main/java/com/cyksj/model/views/GoodsSkuGiftCardView.java

@@ -0,0 +1,30 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+/*
+ *项目名: netflix
+ *文件名: GoodsSkuGiftCardView
+ *创建者: JavaZou
+ *创建时间:2023/8/28 14:23
+ */
+@Getter
+@Setter
+@SearchBean(tables = "goods_don g left join goods_don_sku sku on sku.id = g.goods_id",
+		where = "g.deleted is true and g.status is true and sku.true is true")
+public class GoodsSkuGiftCardView {
+	@DbField("g.id")
+	private Long goodsId;
+
+	@DbField("g.sku_id")
+	private Long skuId;
+
+	@DbField("g.title")
+	private String title;
+
+	@DbField("sku.spec_val")
+	private String specVal;
+}

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/views/UserPersonalView.java

@@ -44,5 +44,10 @@ public class UserPersonalView {
 	 */
 	private Boolean isNoPayment;
 
+	/**
+	 * 礼品卡可用数量
+	 */
+	private Integer numOfGiftCard;
+
 	private String phone;
 }

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/views/UserTicketView.java

@@ -6,6 +6,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
 import lombok.Getter;
 import lombok.Setter;
 
+import java.util.Date;
+
 /*
  *项目名: netflix
  *文件名: UserTicketView
@@ -35,6 +37,9 @@ public class UserTicketView {
 	@DbField("gdk.spec_val")
 	private String specVal;
 
+	@DbField("gr.expiry_time")
+	private Date expiryTime;
+
 	@DbField("gr.status")
 	@JsonIgnore
 	private String status;

+ 3 - 0
netflix-service/src/main/java/com/cyksj/redis/RedisService.java

@@ -645,6 +645,9 @@ public class RedisService {
         ORDER_COMMENT_KEY("order_comment_key:", "订单评价", 10l),
         USER_BIND_ACCOUNT_INFO_KEY("user_bind_account_info_key:", "用户绑定其他账号key", 10l),
         TASK_RECEIVED_KEY("task_received_key:%s:%s", "领取任务奖励key", 10l),
+        CORP_GROUP_CHAT_LIST("corp_group_chat_list:%s", "企业微信客户群列表", 60 * 60 * 24),
+        PLUS_GOODS_ADDRESS_KEY("plus_goods_address_key:", "优惠加购实物地址key", 10 * 60l),
+        GROUPS_TRIPS_OUTSIDE_RELATION("groups_trips_outside_relation:key", "额外车位", 30l),
         ;
 
         private String name;

+ 20 - 0
netflix-service/src/main/java/com/cyksj/service/giftcard/GiftCardGoodsSkuService.java

@@ -0,0 +1,20 @@
+package com.cyksj.service.giftcard;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.cyksj.model.entity.GiftCardGoodsSku;
+import com.cyksj.model.entity.GoodsDon;
+import com.cyksj.model.request.GiftCardGoodsSkuReq;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardGoodsSkuService
+ *创建者: JavaZou
+ *创建时间:2023/8/29 18:19
+ */
+public interface GiftCardGoodsSkuService extends IService<GiftCardGoodsSku> {
+	void setOrUpdateGiftCardSku(GiftCardGoodsSku giftCardSku);
+
+	void setGiftCardSku(GiftCardGoodsSkuReq req);
+
+	void setGiftCardGoodsStat(GoodsDon goodsDon);
+}

+ 14 - 0
netflix-service/src/main/java/com/cyksj/service/giftcard/GiftCardOrderUseRecordService.java

@@ -0,0 +1,14 @@
+package com.cyksj.service.giftcard;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.cyksj.model.entity.GiftCardOrderUseRecord;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardOrderUseRecordService
+ *创建者: JavaZou
+ *创建时间:2023/8/29 16:44
+ */
+public interface GiftCardOrderUseRecordService extends IService<GiftCardOrderUseRecord> {
+	void returnGiftCardCash(Long orderId);
+}

+ 13 - 0
netflix-service/src/main/java/com/cyksj/service/giftcard/GiftCardUserRecordService.java

@@ -0,0 +1,13 @@
+package com.cyksj.service.giftcard;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.cyksj.model.entity.GiftCardUserRecord;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardUserRecordService
+ *创建者: JavaZou
+ *创建时间:2023/8/30 10:54
+ */
+public interface GiftCardUserRecordService extends IService<GiftCardUserRecord> {
+}

+ 128 - 0
netflix-service/src/main/java/com/cyksj/service/giftcard/impl/GiftCardGoodsSkuServiceImpl.java

@@ -0,0 +1,128 @@
+package com.cyksj.service.giftcard.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.mapper.GiftCardGoodsSkuMapper;
+import com.cyksj.mapper.GoodsDonMapper;
+import com.cyksj.mapper.GoodsDonSkuMapper;
+import com.cyksj.model.entity.GiftCardGoodsSku;
+import com.cyksj.model.entity.GoodsDon;
+import com.cyksj.model.entity.GoodsDonSku;
+import com.cyksj.model.request.GiftCardGoodsSkuReq;
+import com.cyksj.redis.RedisService;
+import com.cyksj.service.giftcard.GiftCardGoodsSkuService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Set;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardGoodsSkuServiceImpl
+ *创建者: JavaZou
+ *创建时间:2023/8/29 18:19
+ */
+@Service
+@RequiredArgsConstructor
+public class GiftCardGoodsSkuServiceImpl extends ServiceImpl<GiftCardGoodsSkuMapper, GiftCardGoodsSku> implements GiftCardGoodsSkuService {
+	private final GoodsDonSkuMapper goodsDonSkuMapper;
+
+	private final GoodsDonMapper goodsDonMapper;
+
+	private final RedisService redisService;
+
+	@Override
+	public void setOrUpdateGiftCardSku(GiftCardGoodsSku data) {
+		if (data.getGoodsId() == null) {
+			throw BusinessRuntimeException.getInstance("请选择对应的礼品卡平台");
+		}
+		GoodsDon goodsDon = goodsDonMapper.selectById(data.getGoodsId());
+		if (goodsDon == null) {
+			throw BusinessRuntimeException.getInstance("请选择对应的礼品卡平台");
+		}
+		if (goodsDon.getSpecialType() == null || goodsDon.getSpecialType() != GoodsDon.SpecialType.giftCard) {
+			throw BusinessRuntimeException.getInstance("该{0}平台不是礼品卡特殊类型", goodsDon.getTitle());
+		}
+		BigDecimal cash = data.getCash();
+		Integer gcType = data.getGcType();
+		BigDecimal price = data.getPrice();
+		if (price == null || price.compareTo(BigDecimal.ZERO) <= 0) {
+			throw BusinessRuntimeException.getInstance("请输入正确的礼品卡价格");
+		}
+		Long gcSkuId = data.getGcSkuId();
+		if (gcSkuId == null && cash == null) {
+			throw BusinessRuntimeException.getInstance("请选择对应的礼品卡类型");
+		}
+
+		if (gcSkuId != null && cash != null) {
+			throw BusinessRuntimeException.getInstance("只能选择一种礼品卡类型");
+		}
+		if (cash != null) {
+			if (cash.compareTo(BigDecimal.ZERO) <= 0) {
+				throw BusinessRuntimeException.getInstance("请输入正确的礼品卡价格");
+			}
+			gcType = 1;
+		}
+		//虚拟卡
+		if (gcSkuId != null) {
+			GoodsDonSku sku = goodsDonSkuMapper.selectById(gcSkuId);
+			if (sku == null) {
+				throw BusinessRuntimeException.getInstance("存在未有的虚拟卡规格,请重新选择");
+			}
+			if (!sku.getStatus()) {
+				throw BusinessRuntimeException.getInstance("存在下架的虚拟卡规格,请重新选择");
+			}
+			gcType = 2;
+			data.setGcGoodsId(sku.getGoodsId());
+		}
+		data.setGcType(gcType);
+		if (gcType == 2 && data.getId() == null) {
+			GiftCardGoodsSku one = this.getOne(Wrappers.lambdaQuery(GiftCardGoodsSku.class)
+					.eq(GiftCardGoodsSku::getGcSkuId, gcSkuId).last("limit 1"));
+			if (one != null) {
+				return;
+			}
+		}
+		this.saveOrUpdate(data);
+		//设置对应礼品卡平台 最低价格
+		setGiftCardGoodsStat(goodsDon);
+	}
+
+	@Override
+	public void setGiftCardSku(GiftCardGoodsSkuReq req) {
+		List<GiftCardGoodsSku> giftCardGoodsSkus = req.getConfigs();
+		if (CollUtil.isEmpty(giftCardGoodsSkus)) {
+			throw BusinessRuntimeException.getInstance("请输入对应数据");
+		}
+		giftCardGoodsSkus.forEach(giftCardSku -> {
+			giftCardSku.setGoodsId(req.getGoodsId());
+			setOrUpdateGiftCardSku(giftCardSku);
+		});
+	}
+
+	/**
+	 * 设置对应礼品卡平台 最低价格
+	 */
+	@Override
+	public void setGiftCardGoodsStat(GoodsDon goodsDon) {
+		//设置对应礼品卡平台 最低价格
+		BigDecimal minPrice = goodsDon.getMinPrice();
+		GiftCardGoodsSku min = this.getOne(Wrappers.lambdaQuery(GiftCardGoodsSku.class)
+				.eq(GiftCardGoodsSku::getGoodsId, goodsDon.getId())
+				.eq(GiftCardGoodsSku::getStatus, true)
+				.eq(GiftCardGoodsSku::getDeleted, true)
+				.orderByAsc(GiftCardGoodsSku::getPrice).last("limit 1"));
+		if (min != null) {
+			if (minPrice == null || minPrice.compareTo(min.getPrice()) < 0) {
+				goodsDon.setMinPrice(min.getPrice());
+				goodsDonMapper.updateById(goodsDon);
+				Set<String> keys = redisService.keys(RedisService.key.YH_HOME_PAGHE_CACHE.getName() + "*");
+				redisService.del(keys.toArray(String[]::new));
+			}
+		}
+	}
+}

+ 47 - 0
netflix-service/src/main/java/com/cyksj/service/giftcard/impl/GiftCardOrderUseRecordServiceImpl.java

@@ -0,0 +1,47 @@
+package com.cyksj.service.giftcard.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cyksj.mapper.GiftCardOrderUseRecordMapper;
+import com.cyksj.mapper.GiftCardUserRecordMapper;
+import com.cyksj.model.entity.GiftCardOrderUseRecord;
+import com.cyksj.model.entity.GiftCardUserRecord;
+import com.cyksj.service.giftcard.GiftCardOrderUseRecordService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardOrderUseRecordServiceImpl
+ *创建者: JavaZou
+ *创建时间:2023/8/29 16:44
+ */
+@Service
+@RequiredArgsConstructor
+public class GiftCardOrderUseRecordServiceImpl extends ServiceImpl<GiftCardOrderUseRecordMapper, GiftCardOrderUseRecord> implements GiftCardOrderUseRecordService {
+	private final GiftCardUserRecordMapper giftCardUserRecordMapper;
+
+	@Override
+	public void returnGiftCardCash(Long orderId) {
+		List<GiftCardOrderUseRecord> useRecords = this.list(Wrappers.lambdaQuery(GiftCardOrderUseRecord.class)
+				.eq(GiftCardOrderUseRecord::getOrderId, orderId));
+		if (CollUtil.isNotEmpty(useRecords)) {
+			useRecords.forEach(data -> {
+				while (true) {
+					Long gcId = data.getGcId();
+					BigDecimal addCash = data.getCash();
+					GiftCardUserRecord giftCardUserRecord = giftCardUserRecordMapper.selectById(gcId);
+					BigDecimal remainCash = giftCardUserRecord.getRemainCash();
+					Integer update = giftCardUserRecordMapper.updateGiftCardRemainCash(gcId, addCash, remainCash);
+					if (update > 0) {
+						break;
+					}
+				}
+			});
+		}
+	}
+}

+ 17 - 0
netflix-service/src/main/java/com/cyksj/service/giftcard/impl/GiftCardUserRecordServiceImpl.java

@@ -0,0 +1,17 @@
+package com.cyksj.service.giftcard.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cyksj.mapper.GiftCardUserRecordMapper;
+import com.cyksj.model.entity.GiftCardUserRecord;
+import com.cyksj.service.giftcard.GiftCardUserRecordService;
+import org.springframework.stereotype.Service;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardUserRecordServiceImpl
+ *创建者: JavaZou
+ *创建时间:2023/8/30 10:55
+ */
+@Service
+public class GiftCardUserRecordServiceImpl extends ServiceImpl<GiftCardUserRecordMapper, GiftCardUserRecord> implements GiftCardUserRecordService {
+}

+ 31 - 3
netflix-service/src/main/java/com/cyksj/service/mange/impl/CmsOrderDonServiceImpl.java

@@ -41,6 +41,7 @@ import com.cyksj.model.request.OrderRefundReq;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.coupon.CouponFontService;
 import com.cyksj.service.distribute.equipment.EquipmentDistributeService;
+import com.cyksj.service.giftcard.GiftCardOrderUseRecordService;
 import com.cyksj.service.mange.CmsOrderDonService;
 import com.cyksj.service.mange.stock.GoodsDonStockService;
 import com.cyksj.service.market.MarketFrontService;
@@ -141,6 +142,10 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
 
     private final BeanSearcher beanSearcher;
 
+    private final GiftCardOrderUseRecordService giftCardOrderUseRecordService;
+
+    private final GiftCardUserRecordMapper giftCardUserRecordMapper;
+
     private static final GlobalThreadPoolTaskExecutor TASK_POOL = GlobalThreadPoolTaskExecutor.getInstance();
 
     @Override
@@ -276,8 +281,11 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
     @Transactional(rollbackFor = Throwable.class)
     public void unifiedRefund(OrderRefundReq refundReq) throws Exception {
         OrderDon orderDon = orderDonMapper.selectById(refundReq.getOrderId());
-        GoodsDonSku sku = goodsDonSkuMapper.selectById(orderDon.getSkuId());
-        GoodsDon goodsDon = goodsDonMapper.selectById(sku.getGoodsId());
+        GoodsDonSku sku = null;
+        if (orderDon.getSkuId() != null) {
+            sku = goodsDonSkuMapper.selectById(orderDon.getSkuId());
+        }
+        GoodsDon goodsDon = goodsDonMapper.selectById(orderDon.getGoodsId());
         if (StrUtil.isEmpty(refundReq.getRefundType())) {
             refundReq.setRefundType("money");
         }
@@ -555,7 +563,7 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
         if (OrderDon.Status.noPayment == orderDon.getStatus() || OrderDon.Status.close == orderDon.getStatus()) {
             throw BusinessRuntimeException.getInstance("订单{0}状态不支持退款", orderDon.getStatus());
         }
-        if (goodsDon.getType() == 1) {
+        if (goodsDon.getType() == 1 && sku != null) {
             //虚拟原订单是否已过期
             Integer months = sku.getMonths();
             Integer days = sku.getDays();
@@ -605,9 +613,23 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
             }
             orderDon.setRefundMoney(refundMoney);
         }
+        //礼品卡是否已使用
+        GiftCardUserRecord giftCardUserRecord = null;
+        if (goodsDon.getSpecialType() != null && goodsDon.getSpecialType() == GoodsDon.SpecialType.giftCard) {
+            giftCardUserRecord = giftCardUserRecordMapper.selectOne(Wrappers.lambdaQuery(GiftCardUserRecord.class)
+                    .eq(GiftCardUserRecord::getOrderId, orderDon.getId()).last("limit 1"));
+            if (giftCardUserRecord != null && giftCardUserRecord.getIsUsed()) {
+                throw BusinessRuntimeException.getInstance("该礼品卡已使用无法退款");
+            }
+        }
         if (!redisService.setNx(String.format("%s", refundReq.getOrderId()), refundReq.getOrderId(), 10l)) {
             throw BusinessRuntimeException.getInstance("请勿重复点击,正在退款中..");
         }
+        //礼品卡购买状态
+        if (giftCardUserRecord != null) {
+            giftCardUserRecord.setIsPay(false);
+            giftCardUserRecordMapper.updateById(giftCardUserRecord);
+        }
     }
 
     /**
@@ -678,6 +700,12 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
                     }
                 }
             }
+
+            //是否是礼品卡 现金支付订单
+            BigDecimal gcCash = orderDon.getGcCash();
+            if (gcCash != null && gcCash.compareTo(BigDecimal.ZERO) > 0) {
+                giftCardOrderUseRecordService.returnGiftCardCash(orderDon.getId());
+            }
         });
     }
 

+ 1 - 1
netflix-service/src/main/java/com/cyksj/service/order/impl/OrderCommonServiceImpl.java

@@ -44,7 +44,7 @@ public class OrderCommonServiceImpl implements OrderCommonService {
 
 	@Override
 	public void clearUnrealGoodsDetail(OrderDon orderDon, Integer goodsType, GoodsDonSku sku) {
-		if (goodsType == 1) {
+		if (goodsType == 1 && sku != null) {
 			//清出车队,车位变为已过期
 			Long relationId = orderDon.getRelationId();
 			//更换车票前后的座位id集合

+ 439 - 326
netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java

@@ -4,6 +4,8 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateField;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.RandomUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONObject;
 import com.alipay.api.AlipayApiException;
@@ -12,7 +14,10 @@ import com.alipay.api.AlipayRequest;
 import com.alipay.api.AlipayResponse;
 import com.alipay.api.domain.*;
 import com.alipay.api.internal.util.AlipaySignature;
-import com.alipay.api.request.*;
+import com.alipay.api.request.AlipayFundTransCommonQueryRequest;
+import com.alipay.api.request.AlipayFundTransUniTransferRequest;
+import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest;
+import com.alipay.api.request.AlipayTradeQueryRequest;
 import com.alipay.api.response.AlipayFundTransCommonQueryResponse;
 import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
 import com.alipay.api.response.AlipayTradeQueryResponse;
@@ -48,19 +53,21 @@ import com.cyksj.mapper.market.task.UserBindDetailMapper;
 import com.cyksj.model.dto.*;
 import com.cyksj.model.entity.Address;
 import com.cyksj.model.entity.*;
+import com.cyksj.model.manage.dto.GiftCardDto;
 import com.cyksj.model.manage.views.GroupsRelationView;
 import com.cyksj.model.manage.views.OrderDonView;
-import com.cyksj.model.request.OrderAttach;
-import com.cyksj.model.request.OrderPayRequest;
-import com.cyksj.model.request.TransferAccountsReq;
+import com.cyksj.model.request.*;
 import com.cyksj.model.views.CouponNewUserView;
 import com.cyksj.model.views.CouponUserView;
+import com.cyksj.model.views.GiftCardGoodsSkuFrontView;
 import com.cyksj.model.views.GoodsDonSkuView;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.coupon.CouponFontService;
 import com.cyksj.service.distribute.UserBusinessFrontService;
 import com.cyksj.service.distribute.equipment.EquipmentDistributeService;
 import com.cyksj.service.exchange.ExchangeCodeService;
+import com.cyksj.service.giftcard.GiftCardOrderUseRecordService;
+import com.cyksj.service.giftcard.GiftCardUserRecordService;
 import com.cyksj.service.groups.GroupsFuncService;
 import com.cyksj.service.market.MarketFrontService;
 import com.cyksj.service.market.task.TaskService;
@@ -71,6 +78,7 @@ import com.cyksj.service.pay.AliPayCommonService;
 import com.cyksj.service.relation.GroupRelationClearService;
 import com.cyksj.service.relation.GroupRelationFrontService;
 import com.cyksj.service.sys.SysConfigService;
+import com.cyksj.service.telegram.TelegramService;
 import com.cyksj.service.template.TemplateCommonService;
 import com.cyksj.service.user.UserBenefitsService;
 import com.cyksj.service.user.UserBindRelationService;
@@ -90,6 +98,8 @@ import org.springframework.transaction.annotation.Transactional;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import static com.cyksj.enums.GatewayApiCode.GROUP_INDEX_ALREADY_BE_USER;
 import static com.cyksj.enums.GatewayApiCode.GROUP_INDEX_NOT_FIND;
@@ -209,38 +219,77 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 
 	private final ChannelPopularizeMapper channelPopularizeMapper;
 
+	private final TelegramService telegramService;
+
+	private final GiftCardUserRecordService giftCardUserRecordService;
+
+	private final GiftCardOrderUseRecordService giftCardOrderUseRecordService;
+
+	private final GiftCardOrderRelateMapper giftCardOrderRelateMapper;
+
 	private final List<String> noChekGoodsTemp = List.of("Apple One", "Youtube", "Spotify");
 
 	@Transactional(rollbackFor = Throwable.class)
 	@Override
 	public OrderDon submit(OrderPayRequest payRequest) throws Exception {
+		GoodsDonSku sku = null;
+		Long goodsId;
+		List<GiftCardPayReq> giftCards = null;
+		GiftCardDto gcPayInfo = payRequest.getGcPayInfo();
+		if (gcPayInfo != null && gcPayInfo.getGiftCards() != null) {
+			giftCards = gcPayInfo.getGiftCards();
+		}
+		AtomicBoolean isGiftCardPay = new AtomicBoolean(false);
+		if (CollUtil.isNotEmpty(giftCards)) {
+			goodsId = payRequest.getGoodsId();
+			isGiftCardPay.set(true);
+		} else {
+			if (payRequest.getSkuId() == null) {
+				throw BusinessRuntimeException.getInstance("请指定对应平台规格下单");
+			}
+			sku = goodsDonSkuMapper.selectById(payRequest.getSkuId());
+			Assert.notNull(sku, "规格不存在");
+			goodsId = sku.getGoodsId();
+		}
+		GoodsDon goodsDon = goodsDonMapper.selectById(goodsId);
+		if (goodsDon == null || !goodsDon.getStatus()) {
+			throw new BusinessRuntimeException("商品已下架");
+		}
+		if (isGiftCardPay.get() && (goodsDon.getSpecialType() == null || goodsDon.getSpecialType() != GoodsDon.SpecialType.giftCard)) {
+			throw BusinessRuntimeException.getInstance("非礼品卡类型商品");
+		}
 		CouponUser couponUser = null;
 		if (StrUtil.isNotBlank(payRequest.getCouponExCode()) || payRequest.getCouponId() != null) {
 			CouponPopularizeDto couponPopularizeDto = checkCouponStatus(payRequest.getSkuId(), payRequest.getCouponExCode(), payRequest.getCouponId(), payRequest.getUserId(), false);
 			//记录优惠券使用状态
 			couponUser = couponStatusRecord(payRequest.getCouponExCode(), payRequest.getCouponId(), payRequest.getUserId(), couponPopularizeDto);
 		}
-		GoodsDonSku sku = goodsDonSkuMapper.selectById(payRequest.getSkuId());
-		GoodsDon goodsDon = goodsDonMapper.selectById(sku.getGoodsId());
-		if (goodsDon == null || !goodsDon.getStatus()) {
-			throw new BusinessRuntimeException("商品已下架");
-		}
 		Boolean isNoLogin = payRequest.getIsNoLogin();
 		User user;
 		String payOpenId = null;
 		Long relationId = 0L;
 
-		if (isNoLogin != null && isNoLogin) {
+		Boolean isNeedTicket = checkIsNeedGroupsRelation(goodsDon);
+		Long userId = payRequest.getUserId();
+		if (userId != null) {
+			int noPayCount = count(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getUserId, userId).eq(OrderDon::getGoodsId, goodsId).eq(OrderDon::getStatus, OrderDon.Status.noPayment.toString()));
+			if (noPayCount > 0) {
+				throw new BusinessRuntimeException("您有未支付订单.");
+			}
+		}
+		if (userId == null) {
 			user = new User();
 			user.setId(0l);
 		} else {
-			user = userMapper.selectById(payRequest.getUserId());
+			user = userMapper.selectById(userId);
 			if (user == null) throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_TOKEN_VALID);
 			if (user.getIsBlack()) throw BusinessRuntimeException.getInstance("系统检测操作异常,请稍后再试");
-			//ChatGPT Plus账号限购校验
-			checkChatGPTPlusPurchaseLimit(user.getId(), goodsDon.getId(), goodsDon.getTitle(), sku.getId(), sku.getSpecVal());
 			payOpenId = user.getOpenId();
-			if (goodsDon.getType() == 1) {
+			if (sku != null) {
+				//ChatGPT Plus账号限购校验
+				checkChatGPTPlusPurchaseLimit(user.getId(), goodsDon.getId(), goodsDon.getTitle(), sku.getId(), sku.getSpecVal());
+			}
+			if (goodsDon.getType() == 1 && isNeedTicket) {
 				//获取座位
 				relationId = getRelation(payRequest, sku);
 			} else {
@@ -257,38 +306,39 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		}
 		orderDon.setOrderNo(donNo);
 		orderDon.setOpenId(payOpenId);
-		if (sku.getPrice() == null || sku.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
-			throw BusinessRuntimeException.getInstance("下单商品价格异常");
-		}
-		//是否是特定价格 且是否满足
-		Boolean isSpecificPrice = Optional.ofNullable(payRequest.getIsSpecificPrice()).orElse(false);
-		String specificGoodsIds = sku.getSpecificGoodsIds();
-		BigDecimal specificPrice = BigDecimal.ZERO;
-		if (isSpecificPrice) {
-			if (StrUtil.isEmpty(specificGoodsIds)) {
-				throw BusinessRuntimeException.getInstance("系统异常,请刷新页面重试");
-			}
-			if (payRequest.getDonMoney().compareTo(sku.getSpecificPrice()) <= 0) {
-				payRequest.setDonMoney(sku.getSpecificPrice());
-			}
-			List<Long> specificGoodsList = Jsons.parseList(specificGoodsIds, Long.class);
-			if (CollUtil.isEmpty(specificGoodsList)) {
-				throw BusinessRuntimeException.getInstance("系统异常,请刷新页面重试");
+		if (sku != null) {
+			if (sku.getPrice() == null || sku.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
+				throw BusinessRuntimeException.getInstance("下单商品价格异常");
+			}
+			//是否是特定价格 且是否满足
+			Boolean isSpecificPrice = Optional.ofNullable(payRequest.getIsSpecificPrice()).orElse(false);
+			String specificGoodsIds = sku.getSpecificGoodsIds();
+			BigDecimal specificPrice = BigDecimal.ZERO;
+			if (isSpecificPrice) {
+				if (StrUtil.isEmpty(specificGoodsIds)) {
+					throw BusinessRuntimeException.getInstance("系统异常,请刷新页面重试");
+				}
+				if (payRequest.getDonMoney().compareTo(sku.getSpecificPrice()) <= 0) {
+					payRequest.setDonMoney(sku.getSpecificPrice());
+				}
+				List<Long> specificGoodsList = Jsons.parseList(specificGoodsIds, Long.class);
+				if (CollUtil.isEmpty(specificGoodsList)) {
+					throw BusinessRuntimeException.getInstance("系统异常,请刷新页面重试");
+				}
+				if (user.getId() == 0) throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_TOKEN_VALID);
+				Number count = beanSearcher.searchCount(OrderDon.class, MapUtils.builder().field(OrderDon::getGoodsId, specificGoodsList).op(Operator.InList)
+						.field(OrderDon::getUserId, user.getId())
+						.field(OrderDon::getStatus, Constant.noOrderAllStatus).op(Operator.NotIn)
+						.build());
+				if (count.intValue() <= 0) {
+					throw BusinessRuntimeException.getInstance("你不满足该商品特定价格条件");
+				}
+				specificPrice = sku.getSpecificPrice();
 			}
-			if (user.getId() == 0) throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_TOKEN_VALID);
-			Number count = beanSearcher.searchCount(OrderDon.class, MapUtils.builder().field(OrderDon::getGoodsId, specificGoodsList).op(Operator.InList)
-					.field(OrderDon::getUserId, user.getId())
-					.field(OrderDon::getStatus, Constant.noOrderAllStatus).op(Operator.NotIn)
-					.build());
-			if (count.intValue() <= 0) {
-				throw BusinessRuntimeException.getInstance("你不满足该商品特定价格条件");
+			if (payRequest.getDonMoney().compareTo(sku.getPrice()) < 0) {
+				log.info("规格:{}支付金额:{}异常,调整用户userId:{}支付金额为:{}", sku.getSpecVal(), payRequest.getDonMoney(), user.getId(), sku.getPrice());
+				payRequest.setDonMoney(sku.getPrice());
 			}
-			specificPrice = sku.getSpecificPrice();
-		}
-
-		if (payRequest.getDonMoney().compareTo(sku.getPrice()) < 0 && !isSpecificPrice) {
-			log.info("规格:{}支付金额:{}异常,调整用户userId:{}支付金额为:{}", sku.getSpecVal(), payRequest.getDonMoney(), user.getId(), sku.getPrice());
-			payRequest.setDonMoney(sku.getPrice());
 		}
 
 		orderDon.setMoney(payRequest.getDonMoney());
@@ -324,8 +374,10 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		if (payRequest.getPopularizeId() != null) {
 			orderDon.setPopularizeId(payRequest.getPopularizeId());
 		}
-		//扣除使用优惠券、余额的订单金额
-		deductOrderMoney(orderDon, couponUser, payRequest.getBalance(), user, sku.getPrice(), goodsDon.getType());
+		if (sku != null) {
+			//扣除使用优惠券、余额的订单金额
+			deductOrderMoney(orderDon, couponUser, payRequest.getBalance(), user, sku.getPrice(), goodsDon.getType(), payRequest.getGcCash(), payRequest.getGcpIds());
+		}
 
 		if (isSpecificPrice && (orderDon.getMoney().compareTo(BigDecimal.ZERO) == 0 || orderDon.getMoney().compareTo(specificPrice) != 0)) {
 			throw BusinessRuntimeException.getInstance("专属价格不支持使用其他优惠");
@@ -341,24 +393,8 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		orderDon.setIsWebPay(payRequest.getIsWebPay());
 		orderDon.setSource(payRequest.getSource());
 		orderDon.setCouponExCode(payRequest.getCouponExCode());
-		if (isNoLogin == null || !isNoLogin) {
-			//虚拟商品订单,是否是分销订单
-			if (goodsDon.getType() == 1 || goodsDon.getType() == 2) {
-				//若该订单使用了规定推广者的兑换码 增加上下级关系
-				if (StrUtil.isNotBlank(orderDon.getCouponExCode()) && orderDon.getUserId() != 0) {
-					addDistributeCouponCode(orderDon.getUserId(), orderDon.getCouponExCode());
-				}
-				UserDistributeShared userDistributeShared = userDistributeSharedMapper.selectOne(Wrappers.lambdaQuery(UserDistributeShared.class).eq(UserDistributeShared::getUserId, user.getId()).last("limit 1"));
-				if (userDistributeShared != null) {
-					orderDon.setIsDistribute(true);
-					UserDistribute userDistribute = userDistributeMapper.selectOne(Wrappers.lambdaQuery(UserDistribute.class).eq(UserDistribute::getUserId, userDistributeShared.getSharedId()));
-					if (userDistribute != null) {
-						orderDon.setIsFixedDistribute(true);
-						orderDon.setCpsPopularizeId(userDistributeShared.getDsPopularizeId());
-					}
-				}
-			}
-		}
+		//设置分销订单
+		setDistributeOrderMark(orderDon, goodsDon.getType(), user.getId());
 		if (relationId != 0) {
 			Long gtSkuId = groupsRelationMapper.getGroupTripsSkuIdByRelationId(relationId);
 			if (!gtSkuId.equals(orderDon.getSkuId())) {
@@ -368,7 +404,56 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		orderDon.setPayDesc(goodsDon.getPayDesc());
 		StringBuilder payTitle = new StringBuilder();
 		payTitle.append(goodsDon.getTitle());
-		payTitle.append(sku.getSpecVal());
+		if (sku != null) {
+			payTitle.append(sku.getSpecVal());
+		}
+		if (isGiftCardPay.get()) {
+			//礼品卡规格
+			Map<Long, Integer> giftCardPayNumMap = new ConcurrentHashMap<>();
+			giftCards.stream().forEach(data -> {
+				if (data.getNum() <= 0) {
+					return;
+				}
+				giftCardPayNumMap.putIfAbsent(data.getGcId(), data.getNum());
+			});
+			if (giftCardPayNumMap.isEmpty()) {
+				throw BusinessRuntimeException.getInstance("请选择要购买礼品卡的数量");
+			}
+			List<GiftCardGoodsSkuFrontView> giftCardViews = beanSearcher.searchAll(GiftCardGoodsSkuFrontView.class, MapUtils.builder().field(GiftCardGoodsSkuFrontView::getId, giftCardPayNumMap.keySet()).build());
+			if (giftCardViews.size() != giftCards.size()) {
+				throw BusinessRuntimeException.getInstance("系统异常,请刷新页面重试");
+			}
+			payTitle.append("礼品卡:");
+			BigDecimal gift_card_pay_money = BigDecimal.ZERO;
+			for (GiftCardGoodsSkuFrontView data : giftCardViews) {
+				//礼品卡数量
+				Integer num = giftCardPayNumMap.get(data.getId());
+				data.setGcNum(num);
+				data.setGcShowType(gcPayInfo.getGcShowType());
+				data.setGcImg(gcPayInfo.getGcImg());
+				gift_card_pay_money = gift_card_pay_money.add(data.getPrice().multiply(BigDecimal.valueOf(num)));
+
+				//礼品卡关系
+				if (!payTitle.toString().endsWith("礼品卡:")) {
+					payTitle.append(" + ");
+				}
+				String gcDetail;
+				if (data.getGcType() == 1) {
+					gcDetail = String.format("%s张现金卡%s", num, data.getCash().divide(BigDecimal.valueOf(100)));
+					payTitle.append(gcDetail);
+				} else {
+					gcDetail = String.format("%s张虚拟卡%s%s", num, data.getGcGoodsTitle(), data.getGcSpecVal());
+					payTitle.append(gcDetail);
+				}
+			}
+			gcPayInfo.setGcPayDetail(giftCardViews);
+
+			//调整礼品卡金额
+			if (gift_card_pay_money.compareTo(orderDon.getMoney()) > 0) {
+				orderDon.setMoney(gift_card_pay_money);
+				orderDon.setRealMoney(gift_card_pay_money);
+			}
+		}
 		if (orderDon.getIsDp()) {
 			List<GoodsDonSkuView> dp_skuViewList = beanSearcher.searchAll(GoodsDonSkuView.class, MapUtils.builder().field(GoodsDonSkuView::getSkuId, dpSkuIds).op(Operator.InList).build());
 			if (dp_skuViewList.size() != dpSkuIds.size()) {
@@ -421,9 +506,36 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			}
 		}
 		orderDon.setSpecialType(goodsDon.getSpecialType());
+		//礼品卡购买记录
+		if (CollUtil.isNotEmpty(giftCards)) {
+			log.info("用户userId:{}购买礼品卡下单orderId:{}", userId, orderDon.getId());
+			GiftCardOrderRelate giftCardOrderRelate = new GiftCardOrderRelate();
+			giftCardOrderRelate.setOrderId(orderDon.getId());
+			giftCardOrderRelate.setGcPayDetail(Jsons.toJson(gcPayInfo.getGcPayDetail()));
+			giftCardOrderRelateMapper.insert(giftCardOrderRelate);
+		}
+
+		//礼品卡现金使用记录
+		if (CollUtil.isNotEmpty(orderDon.getGcUseRecords())) {
+			orderDon.getGcUseRecords().forEach(data -> {
+				data.setOrderId(orderDon.getId());
+			});
+			giftCardOrderUseRecordService.saveBatch(orderDon.getGcUseRecords());
+		}
 		return orderDon;
 	}
 
+	private Boolean checkIsNeedGroupsRelation(GoodsDon goodsDon) {
+		if (goodsDon.getType() == 1) {
+			//礼品卡特殊类型不需要车票
+			if (goodsDon.getSpecialType() != null && goodsDon.getSpecialType() == GoodsDon.SpecialType.giftCard) {
+				return false;
+			}
+			return true;
+		}
+		return false;
+	}
+
 	@Override
 	public H5JsPayParams pay(Long orderId, String tradeType) throws Exception {
 		log.info("调起微信支付[start] orderId:{}", orderId);
@@ -533,9 +645,11 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			log.error("回调数据:{}", map);
 			throw BusinessRuntimeException.getInstance("支付成功回调, 校验签名失败.");
 		}
-
-		GoodsDonSku sku = goodsDonSkuMapper.selectById(order.getSkuId());
-		GoodsDon goodsDon = goodsDonMapper.selectById(sku.getGoodsId());
+		GoodsDonSku sku = null;
+		if (order.getSkuId() != null) {
+			sku = goodsDonSkuMapper.selectById(order.getSkuId());
+		}
+		GoodsDon goodsDon = goodsDonMapper.selectById(order.getGoodsId());
 
 		String transactionId = map.get("transaction_id");
 
@@ -546,7 +660,6 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 
 		// 更改订单状态
 		order.setTransactionId(transactionId);
-		order.setStatus(goodsDon.getType() == 1 && goodsDon.getSecondType() == 2 ? OrderDon.Status.complete : OrderDon.Status.hasPayment);
 
 		order.setPayTime(DateUtil.parse(map.get("time_end"), "yyyyMMddHHmmss"));
 		order.setShopId(appId);
@@ -558,63 +671,8 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			order.setOpenId(map.get("openid"));
 		}
 		order.setType(OrderDon.Type.WeChat);
-		if (order.getIsNoLogin()) {
-			order.setStatus(OrderDon.Status.hasPayment);
-		}
 
-		boolean isSuccess = update(Wrappers.lambdaUpdate(OrderDon.class)
-				.set(OrderDon::getStatus, order.getStatus())
-				.in(OrderDon::getStatus, List.of(OrderDon.Status.noPayment, OrderDon.Status.close))
-				.eq(OrderDon::getId, order.getId()));
-		if (!isSuccess) {
-			log.info("微信回调商家订单号:{}订单状态已修改", order.getOrderNo());
-			return;
-		}
-
-		if (!order.getIsNoLogin()) {
-			//更新座位信息
-			updateGroupsTicket(order, goodsDon, sku);
-			if (order.getMoney().compareTo(BigDecimal.ZERO) > 0 && order.getIsDistribute()) {
-				TASK_POOL.execute(() -> distributeWaitingSendPointsRecord(order));
-			}
-			if (goodsDon.getType() == 1) {
-				//无车队,新增车队
-				checkNoGroupsTripsAndSendMsg(sku, order);
-			}
-			//完成任务
-			TASK_POOL.execute(() -> {
-				TaskType taskType = taskTypeMapper.selectOne(Wrappers.lambdaQuery(TaskType.class)
-						.eq(TaskType::getName, TaskTypeEnum.yh_order.getDesc()).last("limit 1"));
-				taskService.completeTask(taskType, order.getUserId());
-			});
-			//客服续费订单
-			handleServiceRenewOrder(order);
-		}
-		//购买Midjourney课程 赠送Midjourney车票
-		if (goodsId != null && goodsId.equals(27l)) {
-			order.setStatus(OrderDon.Status.complete);
-			TASK_POOL.execute(() -> sendMidjourneyTicketIfCourse(order.getUserId()));
-		}
-		this.updateById(order);
-		//配置了特定奖池,增加抽奖机会
-		TASK_POOL.execute(() -> {
-			try {
-				marketFrontService.addSpecificChanceNum(order.getUserId(), order.getId(), order.getGoodsId(), order.getSkuId());
-				if (goodsDon.getType() == 2) {
-					equipmentDistributeService.addDistributeBenefitsChance(order.getUserId(), order.getId());
-				}
-			} catch (Exception e) {
-				log.error("wx增加抽奖机会错误,orderId:{},error:{}", order.getId(), e);
-			}
-		});
-
-		TASK_POOL.execute(()->{
-			try {
-				orderDonPostService.postData((order.getId()));
-			} catch (Exception e) {
-				log.error("回传错误 {}",StringUtil.getErrorText(e));
-			}
-		});
+		unifiedHandlerOrderNotify(order, goodsDon, sku);
 	}
 
 	@Override
@@ -700,6 +758,12 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 				if (orderDon.getBalance().compareTo(BigDecimal.ZERO) > 0) {
 					userBenefitsService.addUserBalance(orderDon.getUserId(), orderDon.getBalance(), UserBalanceSourceRecord.Source.close);
 				}
+
+				//是否是礼品卡 现金支付订单
+				BigDecimal gcCash = orderDon.getGcCash();
+				if (gcCash != null && gcCash.compareTo(BigDecimal.ZERO) > 0) {
+					giftCardOrderUseRecordService.returnGiftCardCash(orderDon.getId());
+				}
 			}
 		}
 	}
@@ -825,7 +889,7 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		}
 		orderDon.setRealMoney(orderDon.getMoney());
 		//扣除使用优惠券、余额的订单金额
-		deductOrderMoney(orderDon, couponUser, payRequest.getBalance(), user, sku.getPrice(), goodsDon.getType());
+		deductOrderMoney(orderDon, couponUser, payRequest.getBalance(), user, sku.getPrice(), goodsDon.getType(), payRequest.getGcCash(), payRequest.getGcpIds());
 		this.saveOrUpdate(orderDon);
 		//订单金额为0 且订单为已完成 更新虚物车票
 		if (orderDon.getMoney().compareTo(BigDecimal.ZERO) == 0) {
@@ -837,6 +901,13 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 				closeOrder(orderDon.getId(), null);
 			});
 		}
+		//礼品卡现金使用记录
+		if (CollUtil.isNotEmpty(orderDon.getGcUseRecords())) {
+			orderDon.getGcUseRecords().forEach(data -> {
+				data.setOrderId(orderDon.getId());
+			});
+			giftCardOrderUseRecordService.saveBatch(orderDon.getGcUseRecords());
+		}
 		return orderDon;
 	}
 
@@ -895,86 +966,25 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		if (orderDon.getIsNoLogin()) {
 			orderDon.setExCode(exchangeCodeService.getExCode(goodsId, orderDon.getSkuId(), 1));
 		}
-		GoodsDonSku sku = goodsDonSkuMapper.selectById(orderDon.getSkuId());
-		GoodsDon goodsDon = goodsDonMapper.selectById(sku.getGoodsId());
+		GoodsDonSku sku = null;
+		if (orderDon.getSkuId() != null) {
+			sku = goodsDonSkuMapper.selectById(orderDon.getSkuId());
+		}
+		GoodsDon goodsDon = goodsDonMapper.selectById(orderDon.getGoodsId());
 		Date payTime = DateTime.now();
 		if (StringUtils.isNotBlank(payTimeStr)) {
 			payTime = DateUtil.parse(payTimeStr, "yyyy-MM-dd HH:mm:ss");
 		}
 		// 更改订单状态
 		orderDon.setTransactionId(transactionId);
-		orderDon.setStatus(goodsDon.getType() == 1 && goodsDon.getSecondType() == 2 ? OrderDon.Status.complete : OrderDon.Status.hasPayment);
 		orderDon.setPayTime(payTime);
 		orderDon.setShopId(appId);
 		orderDon.setType(OrderDon.Type.ALI_PAY);
-		if (orderDon.getIsNoLogin()) {
-			orderDon.setStatus(OrderDon.Status.hasPayment);
-		}
-		boolean isSuccess = update(Wrappers.lambdaUpdate(OrderDon.class)
-				.set(OrderDon::getStatus, orderDon.getStatus())
-				.in(OrderDon::getStatus, List.of(OrderDon.Status.noPayment, OrderDon.Status.close))
-				.eq(OrderDon::getId, orderDon.getId()));
-		if (!isSuccess) {
-			log.info("支付宝回调商家订单号:{}订单状态已修改", orderDon.getOrderNo());
-			return;
-		}
-		if (!orderDon.getIsNoLogin()) {
-			//更新座位信息
-			updateGroupsTicket(orderDon, goodsDon, sku);
-			if (orderDon.getMoney().compareTo(BigDecimal.ZERO) > 0 && orderDon.getIsDistribute()) {
-				TASK_POOL.execute(() -> distributeWaitingSendPointsRecord(orderDon));
-			}
-			if (goodsDon.getType() == 1) {
-				//无车队,新增车队
-				checkNoGroupsTripsAndSendMsg(sku, orderDon);
-			}
-			//完成任务
-			TASK_POOL.execute(() -> {
-				TaskType taskType = taskTypeMapper.selectOne(Wrappers.lambdaQuery(TaskType.class)
-						.eq(TaskType::getName, TaskTypeEnum.yh_order.getDesc()).last("limit 1"));
-				taskService.completeTask(taskType, orderDon.getUserId());
-			});
-			//客服续费订单
-			handleServiceRenewOrder(orderDon);
-		}
-		//购买Midjourney课程 赠送Midjourney车票
-		if (goodsId != null && goodsId.equals(27l)) {
-			orderDon.setStatus(OrderDon.Status.complete);
-			TASK_POOL.execute(() -> sendMidjourneyTicketIfCourse(orderDon.getUserId()));
-		}
-		this.updateById(orderDon);
-		//配置了特定奖池,增加抽奖机会
-		TASK_POOL.execute(() -> {
-			try {
-				marketFrontService.addSpecificChanceNum(orderDon.getUserId(), orderDon.getId(), orderDon.getGoodsId(), orderDon.getSkuId());
-				if (goodsDon.getType() == 2) {
-					equipmentDistributeService.addDistributeBenefitsChance(orderDon.getUserId(), orderDon.getId());
-				}
-				//若该订单使用了规定推广者的兑换码 增加上下级关系
-				if (StrUtil.isNotBlank(orderDon.getCouponExCode())) {
-					addDistributeCouponCode(orderDon.getUserId(), orderDon.getCouponExCode());
-				}
-			} catch (Exception e) {
-				log.error("zfb增加抽奖机会错误,orderId:{},error:{}", orderDon.getId(), e);
-			}
-		});
 
-		TASK_POOL.execute(()->{
-			try {
-				orderDonPostService.postData((orderDon.getId()));
-			} catch (Exception e) {
-				log.error("回传错误 {}",StringUtil.getErrorText(e));
-			}
-		});
+		unifiedHandlerOrderNotify(orderDon, goodsDon, sku);
 	}
 
 	public void setRelation(Long relationId, Long groupsId, Long userId, Long goodsId, Boolean isLoginPopularize) {
-		if (isLoginPopularize == null || !isLoginPopularize) {
-			int noPayCount = count(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getUserId, userId).eq(OrderDon::getGoodsId, goodsId).eq(OrderDon::getStatus, OrderDon.Status.noPayment.toString()));
-			if (noPayCount > 0) {
-				throw new BusinessRuntimeException("您有未支付订单.");
-			}
-		}
 		if (!redisService.setNx(RedisKey.GROUPS_RELATION_NUM_KEY + relationId, userId, 60 * 5L)) {
 			log.info("=====>用户:{}未抢到座位:{}", userId, relationId);
 			throw new BusinessRuntimeException("客官手慢啦,该座位已经有人啦!");
@@ -1130,7 +1140,10 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			throw BusinessRuntimeException.getInstance("订单异常");
 		}
 		GoodsDon goodsDon = goodsDonMapper.selectById(orderDon.getGoodsId());
-		GoodsDonSku sku = goodsDonSkuMapper.selectById(orderDon.getSkuId());
+		GoodsDonSku sku = null;
+		if (orderDon.getSkuId() != null) {
+			sku = goodsDonSkuMapper.selectById(orderDon.getSkuId());
+		}
 		orderDon.setStatus(goodsDon.getType() == 1 && goodsDon.getSecondType() == 2 ? OrderDon.Status.complete : OrderDon.Status.hasPayment);
 		updateGroupsTicket(orderDon, goodsDon, sku);
 		if (orderDon.getBalance().compareTo(BigDecimal.ZERO) > 0) {
@@ -1140,91 +1153,15 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		this.updateById(orderDon);
 	}
 
-	public AliPayParams commonAliPay(Long orderId, String returnUrl, String productCode, String appId, String qrPayMode) throws Exception {
-		AlipayClient alipayClient = AliPayClientFactory.getAlipayClient(Optional.ofNullable(appId).orElse(ShopConfig.ZFB_DEFAULT_APP_ID));
-		// 创建API对应的request
-		AlipayRequest alipayRequest = getAliAayRequest(orderId, productCode, qrPayMode);
-		if (alipayRequest == null) {
-			throw BusinessRuntimeException.getInstance("支付宝不支持该支付方式:{0}", productCode);
-		}
-		//回调地址
-		String host = envCommonService.getHost();
-		String notifyUrl = String.format("%s%s", host, BaseZfbConfig.notifyUrl);
-		if (BaseZfbConfig.qrPayMode_redirect.equals(qrPayMode)) {
-			returnUrl = String.format("%s%s", envCommonService.getDomain(), BaseZfbConfig.loginReturnUrl);
-			alipayRequest.setReturnUrl(returnUrl);
-		} else if (StrUtil.isNotBlank(returnUrl)) {
-			alipayRequest.setReturnUrl(returnUrl);
-		}
-		alipayRequest.setNotifyUrl(notifyUrl);
-		String form = null;
-		try {
-			//调用SDK生成表单
-			//pagePay 统一下单接口
-			form = alipayClient.pageExecute(alipayRequest).getBody();
-		} catch (AlipayApiException e) {
-			log.error("支付宝生成表单错误:{}", e == null ? null : e.getMessage());
-		}
-		log.info("支付宝返回参数:{}", form);
-		return new AliPayParams(form);
-	}
-
-	/**
-	 * 支付宝获取不同的request
-	 * @param productCode 销售产品码,与支付宝签约的产品码名称
-	 * @return
-	 */
-	private AlipayRequest getAliAayRequest(Long orderId, String productCode, String qrPayMode) throws Exception {
-		OrderAttach attach = new OrderAttach();
-		attach.setO(orderId);
-		String body = Codec.DoBase64.custom()
-				.setData(Jsons.toJson(attach)).encodeAsText();
-		OrderDon orderDon = orderDonMapper.selectById(orderId);
-		if (orderDon.getType() != OrderDon.Type.ALI_PAY) {
-			orderDon.setType(OrderDon.Type.ALI_PAY);
-			orderDonMapper.updateById(orderDon);
-		}
-		GoodsDonSku goodsDonSku = goodsDonSkuMapper.selectById(orderDon.getSkuId());
-		GoodsDon goodsDon = goodsDonMapper.selectById(goodsDonSku.getGoodsId());
-		String subject = goodsDon.getTitle().contains("ChatGPT") ? "AI订阅" : goodsDon.getTitle();
-		if (ZfbProductCode.MOBILE_WEB.getProductCode().equals(productCode)) {
-			//手机网站支付
-			AlipayTradeWapPayRequest alipayTradeWapPayRequest = new AlipayTradeWapPayRequest();
-			//手机网站支付支付参数
-			AlipayTradeWapPayModel alipayTradeWapPayModel = new AlipayTradeWapPayModel();
-			alipayTradeWapPayModel.setBody(body);
-			alipayTradeWapPayModel.setOutTradeNo(orderDon.getOrderNo());
-			alipayTradeWapPayModel.setTotalAmount(orderDon.getMoney().divide(new BigDecimal(100), 2, RoundingMode.HALF_EVEN).toString());
-			alipayTradeWapPayModel.setSubject(subject);
-			alipayTradeWapPayModel.setProductCode(productCode);
-			//5分钟订单失效时间
-			alipayTradeWapPayModel.setTimeExpire(DateUtil.offsetMinute(orderDon.getCreatedTime(), 5).toString());
-			alipayTradeWapPayRequest.setBizModel(alipayTradeWapPayModel);
-			return alipayTradeWapPayRequest;
-		} else if (ZfbProductCode.PC_WEB.getProductCode().equals(productCode)) {
-			//电脑网站支付
-			AlipayTradePagePayRequest alipayTradePagePayRequest = new AlipayTradePagePayRequest();
-			//电脑网站支付参数
-			AlipayTradePagePayModel alipayTradePagePayModel = new AlipayTradePagePayModel();
-			alipayTradePagePayModel.setBody(body);
-			alipayTradePagePayModel.setOutTradeNo(orderDon.getOrderNo());
-			alipayTradePagePayModel.setTotalAmount(orderDon.getMoney().divide(new BigDecimal(100), 2, RoundingMode.HALF_EVEN).toString());
-			alipayTradePagePayModel.setSubject(subject);
-			alipayTradePagePayModel.setProductCode(productCode);
-			//5分钟订单失效时间
-			alipayTradePagePayModel.setTimeExpire(DateUtil.offsetMinute(orderDon.getCreatedTime(), 5).toString());
-			alipayTradePagePayModel.setQrPayMode(qrPayMode);
-			alipayTradePagePayRequest.setBizModel(alipayTradePagePayModel);
-			return alipayTradePagePayRequest;
-		}
-		return null;
-	}
-
 	public void updateCarParkAndSendMsg(GoodsDon goodsDon, GoodsDonSku sku, OrderDon order) {
 		if (goodsDon.getType() == 1) {
-			log.info("虚物订单orderNo:{}开始更新车票信息", order.getOrderNo());
 			//修改车位状态
 			GroupsRelation relation = groupsRelationMapper.selectById(order.getRelationId());
+			if (relation == null) {
+				log.info("无需更新车票信息");
+				return;
+			}
+			log.info("虚物订单orderNo:{}开始更新车票信息", order.getOrderNo());
 			if (order.getIsDp()) {
 				//是否已经发送优惠加购车票
 				OrderDiscountPlusPurchaseSkuRelation purchaseSkuRelation = orderDiscountPlusPurchaseSkuRelationMapper.selectOne(Wrappers.lambdaQuery(OrderDiscountPlusPurchaseSkuRelation.class)
@@ -1593,15 +1530,6 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			//新增空车队发送模板消息
 			TASK_POOL.execute(() -> {
 				groupsFuncService.createNewGroupsTrips(sku);
-//				try {
-//					List<CustomerService> customerServices = customerServiceMapper.selectList(null);
-//					for (CustomerService customerService : customerServices) {
-//						log.info("发送客服{}空车位通知消息", customerService.getNickName());
-//						templateCommonService.emptySendMsgNotify(order, customerService.getOpenId());
-//					}
-//				} catch (Exception e) {
-//					log.error("发送{}空车位模板消息至客服失败:{}", order.getGoodsId(), e);
-//				}
 			});
 		}
 	}
@@ -1777,7 +1705,6 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 	 * 查询第三放接口订单是否已支付
 	 */
 	public OrderDon.Status isHasPaid(OrderDon orderDon) {
-		OrderDon.Status noPayment = OrderDon.Status.noPayment;
 		GoodsDon goodsDon = goodsDonMapper.selectById(orderDon.getGoodsId());
 		if (orderDon.getType() == OrderDon.Type.WeChat) {
 			try {
@@ -1787,7 +1714,7 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 					if ("SUCCESS".equals(orderStatus)) {
 						orderDon.setStatus(goodsDon.getType() == 1 && goodsDon.getSecondType() == 2 ? OrderDon.Status.complete : OrderDon.Status.hasPayment);
 						orderDon.setTransactionId(reMap.get("transaction_id"));
-						return updateNoPayment(noPayment, orderDon, goodsDon);
+						return updateNoPayment(orderDon, goodsDon);
 					}
 				}
 			} catch (Exception e) {
@@ -1801,7 +1728,7 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 					if ("TRADE_SUCCESS".equals(tradeStatus)) {
 						orderDon.setStatus(goodsDon.getType() == 1 && goodsDon.getSecondType() == 2 ? OrderDon.Status.complete : OrderDon.Status.hasPayment);
 						orderDon.setTransactionId(zfbOrderDetail.getTradeNo());
-						return updateNoPayment(noPayment, orderDon, goodsDon);
+						return updateNoPayment(orderDon, goodsDon);
 					}
 				}
 			} catch (Exception e) {
@@ -1811,21 +1738,13 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		return orderDon.getStatus();
 	}
 
-	private OrderDon.Status updateNoPayment(OrderDon.Status noPayment, OrderDon orderDon, GoodsDon goodsDon) {
-		boolean isSuccess = update(Wrappers.lambdaUpdate(OrderDon.class)
-				.set(OrderDon::getStatus, orderDon.getStatus())
-				.set(OrderDon::getTransactionId, orderDon.getTransactionId())
-				.eq(OrderDon::getStatus, noPayment)
-				.eq(OrderDon::getId, orderDon.getId()));
-		if (isSuccess) {
-			//更新车位情况
-			GoodsDonSku sku = goodsDonSkuMapper.selectById(orderDon.getSkuId());
-			//更新座位信息
-			updateGroupsTicket(orderDon, goodsDon, sku);
-			updateById(orderDon);
-			return orderDon.getStatus();
+	private OrderDon.Status updateNoPayment(OrderDon orderDon, GoodsDon goodsDon) {
+		GoodsDonSku sku = null;
+		if (orderDon.getSkuId() != null) {
+			sku = goodsDonSkuMapper.selectById(orderDon.getSkuId());
 		}
-		return noPayment;
+		unifiedHandlerOrderNotify(orderDon, goodsDon, sku);
+		return orderDon.getStatus();
 	}
 
 	public void checkIsSameUser(Long relationUserId, Long userId, String openId, String loginPhone) {
@@ -1994,8 +1913,53 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 	/**
 	 * 使用优惠营销 订单金额抵扣
 	 */
-	public void deductOrderMoney(OrderDon orderDon, CouponUser couponUser, BigDecimal balance, User user, BigDecimal skuMoney, Integer goodsType) {
+	public void deductOrderMoney(OrderDon orderDon, CouponUser couponUser, BigDecimal balance, User user, BigDecimal skuMoney, Integer goodsType, BigDecimal gcCash, List<Long> gcpIds) {
 		BigDecimal first_money = orderDon.getMoney();
+		//礼品卡现金支付 不参与其他优惠
+		if (gcCash != null && gcCash.compareTo(BigDecimal.ZERO) > 0) {
+			if (CollUtil.isEmpty(gcpIds)) {
+				throw BusinessRuntimeException.getInstance("礼品卡现金支付参数异常");
+			}
+			BigDecimal money = orderDon.getMoney();
+			if (gcCash.compareTo(money) > 0) {
+				gcCash = money;
+			}
+			List<GiftCardUserRecord> availableGiftCards = giftCardUserRecordService.list(Wrappers.lambdaQuery(GiftCardUserRecord.class)
+					.eq(GiftCardUserRecord::getToUserId, user.getId())
+					.in(GiftCardUserRecord::getId, gcpIds)
+					.eq(GiftCardUserRecord::getIsPay, true)
+					.eq(GiftCardUserRecord::getGcType, 1)
+					.gt(GiftCardUserRecord::getRemainCash, 0));
+			if (availableGiftCards.size() != gcpIds.size()) {
+				throw BusinessRuntimeException.getInstance("礼品卡使用异常,请刷新页面重试");
+			}
+			//需要扣除的礼品卡现金
+			BigDecimal deductCash = gcCash;
+			List<GiftCardOrderUseRecord> gcUseRecords = new ArrayList<>();
+			for (GiftCardUserRecord giftCard : availableGiftCards) {
+				if (deductCash.compareTo(BigDecimal.ZERO) <= 0) {
+					break;
+				}
+				BigDecimal remainCash = giftCard.getRemainCash();
+				//扣完
+				if (remainCash.compareTo(deductCash) == 0) {
+					deductGiftCardCash(user.getId(), giftCard.getId(), deductCash, remainCash, gcUseRecords, true);
+					deductCash = BigDecimal.ZERO;
+				} else if (remainCash.compareTo(deductCash) < 0) {
+					deductGiftCardCash(user.getId(), giftCard.getId(), remainCash, remainCash, gcUseRecords, true);
+					deductCash = deductCash.subtract(remainCash);
+				} else if (remainCash.compareTo(deductCash) > 0) {
+					deductGiftCardCash(user.getId(), giftCard.getId(), deductCash, remainCash, gcUseRecords, false);
+					deductCash = BigDecimal.ZERO;
+				}
+			}
+			orderDon.setMoney(orderDon.getMoney().subtract(gcCash));
+			orderDon.setGcCash(gcCash);
+			if (!gcUseRecords.isEmpty()) {
+				orderDon.setGcUseRecords(gcUseRecords);
+			}
+			return;
+		}
 		//存在优惠券
 		if (couponUser != null) {
 			Long couponId = couponUser.getCouponId();
@@ -2077,13 +2041,19 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		if (orderDon.getIsNoLogin()) {
 			orderDon.setExCode(exchangeCodeService.getExCode(goodsId, orderDon.getSkuId(), 1));
 		}
-		GoodsDonSku sku = goodsDonSkuMapper.selectById(orderDon.getSkuId());
-		GoodsDon goodsDon = goodsDonMapper.selectById(sku.getGoodsId());
-		orderDon.setStatus(goodsDon.getType() == 1 && goodsDon.getSecondType() == 2 ? OrderDon.Status.complete : OrderDon.Status.hasPayment);
-
-		if (orderDon.getIsNoLogin()) {
-			orderDon.setStatus(OrderDon.Status.hasPayment);
+		GoodsDonSku sku = null;
+		if (orderDon.getSkuId() != null) {
+			 sku = goodsDonSkuMapper.selectById(orderDon.getSkuId());
 		}
+		GoodsDon goodsDon = goodsDonMapper.selectById(orderDon.getGoodsId());
+		unifiedHandlerOrderNotify(orderDon, goodsDon, sku);
+	}
+
+	/**
+	 * 统一订单信息回调
+	 */
+	public void unifiedHandlerOrderNotify(OrderDon orderDon, GoodsDon goodsDon, GoodsDonSku sku) {
+		orderDon.setStatus(goodsDon.getType() == 1 && goodsDon.getSecondType() == 2 ? OrderDon.Status.complete : OrderDon.Status.hasPayment);
 		boolean isSuccess = update(Wrappers.lambdaUpdate(OrderDon.class)
 				.set(OrderDon::getStatus, orderDon.getStatus())
 				.in(OrderDon::getStatus, List.of(OrderDon.Status.noPayment, OrderDon.Status.close))
@@ -2092,34 +2062,39 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			log.info("支付宝回调商家订单号:{}订单状态已修改", orderDon.getOrderNo());
 			return;
 		}
-		if (!orderDon.getIsNoLogin()) {
+
+		if (orderDon.getIsNoLogin()) {
+			orderDon.setStatus(OrderDon.Status.hasPayment);
+		}
+		Long goodsId = goodsDon.getId();
+		if (!orderDon.getIsNoLogin() && sku != null) {
 			//更新座位信息
 			updateGroupsTicket(orderDon, goodsDon, sku);
-			if (orderDon.getMoney().compareTo(BigDecimal.ZERO) > 0 && orderDon.getIsDistribute()) {
-				TASK_POOL.execute(() -> distributeWaitingSendPointsRecord(orderDon));
-			}
 			if (goodsDon.getType() == 1) {
 				//无车队,新增车队
 				checkNoGroupsTripsAndSendMsg(sku, orderDon);
 			}
-			//完成任务
-			TASK_POOL.execute(() -> {
-				TaskType taskType = taskTypeMapper.selectOne(Wrappers.lambdaQuery(TaskType.class)
-						.eq(TaskType::getName, TaskTypeEnum.yh_order.getDesc()).last("limit 1"));
-				taskService.completeTask(taskType, orderDon.getUserId());
-			});
 			//客服续费订单
 			handleServiceRenewOrder(orderDon);
 		}
-		//购买Midjourney课程 赠送Midjourney车票
-		if (goodsId != null && goodsId.equals(27l)) {
-			orderDon.setStatus(OrderDon.Status.complete);
-			TASK_POOL.execute(() -> sendMidjourneyTicketIfCourse(orderDon.getUserId()));
-		}
 		this.updateById(orderDon);
-		//配置了特定奖池,增加抽奖机会
-		TASK_POOL.execute(() -> {
+
+		TASK_POOL.execute(()->{
 			try {
+				//发放积分
+				if (orderDon.getMoney().compareTo(BigDecimal.ZERO) > 0 && orderDon.getIsDistribute()) {
+					TASK_POOL.execute(() -> distributeWaitingSendPointsRecord(orderDon));
+				}
+				//完成任务
+				TaskType taskType = taskTypeMapper.selectOne(Wrappers.lambdaQuery(TaskType.class)
+						.eq(TaskType::getName, TaskTypeEnum.yh_order.getDesc()).last("limit 1"));
+				taskService.completeTask(taskType, orderDon.getUserId());
+				//购买Midjourney课程 赠送Midjourney车票
+				if (goodsId != null && goodsId.equals(27l)) {
+					orderDon.setStatus(OrderDon.Status.complete);
+					TASK_POOL.execute(() -> sendMidjourneyTicketIfCourse(orderDon.getUserId()));
+				}
+				//配置了特定奖池,增加抽奖机会
 				marketFrontService.addSpecificChanceNum(orderDon.getUserId(), orderDon.getId(), orderDon.getGoodsId(), orderDon.getSkuId());
 				if (goodsDon.getType() == 2) {
 					equipmentDistributeService.addDistributeBenefitsChance(orderDon.getUserId(), orderDon.getId());
@@ -2128,9 +2103,147 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 				if (StrUtil.isNotBlank(orderDon.getCouponExCode())) {
 					addDistributeCouponCode(orderDon.getUserId(), orderDon.getCouponExCode());
 				}
+
+				//礼品卡
+				if (goodsDon.getSpecialType() != null && goodsDon.getSpecialType() == GoodsDon.SpecialType.giftCard) {
+					//礼品卡购买记录
+					GiftCardOrderRelate giftCardOrderRelate = giftCardOrderRelateMapper.selectOne(Wrappers.lambdaQuery(GiftCardOrderRelate.class)
+							.eq(GiftCardOrderRelate::getOrderId, orderDon.getId())
+							.eq(GiftCardOrderRelate::getIsPay, false).last("limit 1"));
+					if (giftCardOrderRelate != null) {
+						log.info("该订单:{}是礼品卡类型", orderDon.getId());
+						int update = giftCardOrderRelateMapper.update(null, Wrappers.lambdaUpdate(GiftCardOrderRelate.class)
+								.set(GiftCardOrderRelate::getIsPay, true)
+								.eq(GiftCardOrderRelate::getId, giftCardOrderRelate.getId())
+								.eq(GiftCardOrderRelate::getIsPay, false));
+						if (update > 0) {
+							log.info("礼品卡订单:{}开始回调", orderDon.getId());
+							giftCardUserPayRecord(giftCardOrderRelate.getGcPayDetail(), orderDon);
+						}
+					}
+				}
 			} catch (Exception e) {
-				log.error("zfb增加抽奖机会错误,orderId:{},error:{}", orderDon.getId(), e);
+				log.error("回调修改订单信息错误,orderId:{},error:{}", orderDon.getId(), StringUtil.getErrorText(e));
 			}
 		});
+
+		TASK_POOL.execute(()->{
+			try {
+				orderDonPostService.postData((orderDon.getId()));
+			} catch (Exception e) {
+				log.error("回传错误 {}",StringUtil.getErrorText(e));
+			}
+		});
+
+		//虚拟物品购买推送电报消息
+		if(goodsDon.getType() == 1){
+			TASK_POOL.execute(()->{
+				sendTelegramMsg(orderDon, goodsDon);
+			});
+		}
+	}
+
+	private void sendTelegramMsg(OrderDon orderDon, GoodsDon goodsDon) {
+		if(!redisService.hasKey(RedisKey.TELEGRAM_BOT_MSG)){
+			TelegramBotMsgReq msgReq = new TelegramBotMsgReq();
+			msgReq.setGoodsName(goodsDon.getTitle());
+			User user = userMapper.selectById(orderDon.getUserId());
+			msgReq.setName(user.getNickname());
+			GroupsRelation groupsRelation = groupsRelationMapper.selectById(orderDon.getRelationId());
+			long day = DateUtil.betweenDay(new Date(), groupsRelation.getExpiryTime(),true);
+			if(day > 1000){
+				day = 365;
+			}
+			msgReq.setDay(day);
+			msgReq.setNumber(groupsRelation.getNum() >= 10 ? RandomUtil.randomInt(10) + 1 : groupsRelation.getNum());
+			try {
+				telegramService.sendMsg(msgReq);
+				redisService.set(RedisKey.TELEGRAM_BOT_MSG,1, 60L * 3L);
+			} catch (Exception e) {
+				log.error("发送电报推送消息错误 msg:{}",StringUtil.getErrorText(e));
+			}
+		}
+	}
+
+	public void setDistributeOrderMark(OrderDon orderDon, Integer goodsType, Long userId) {
+		if (userId == null || userId == 0) {
+			return;
+		}
+		//虚拟商品订单,是否是分销订单
+		if (goodsType == 1 || goodsType == 2) {
+			//若该订单使用了规定推广者的兑换码 增加上下级关系
+			if (StrUtil.isNotBlank(orderDon.getCouponExCode()) && orderDon.getUserId() != 0) {
+				addDistributeCouponCode(orderDon.getUserId(), orderDon.getCouponExCode());
+			}
+			UserDistributeShared userDistributeShared = userDistributeSharedMapper.selectOne(Wrappers.lambdaQuery(UserDistributeShared.class).eq(UserDistributeShared::getUserId, userId).last("limit 1"));
+			if (userDistributeShared != null) {
+				orderDon.setIsDistribute(true);
+				UserDistribute userDistribute = userDistributeMapper.selectOne(Wrappers.lambdaQuery(UserDistribute.class).eq(UserDistribute::getUserId, userDistributeShared.getSharedId()));
+				if (userDistribute != null) {
+					orderDon.setIsFixedDistribute(true);
+					orderDon.setCpsPopularizeId(userDistributeShared.getDsPopularizeId());
+				}
+			}
+		}
+	}
+
+	private void deductGiftCardCash(Long userId, Long gcId, BigDecimal deductCash, BigDecimal gcRemainCash, List<GiftCardOrderUseRecord> gcUseRecords, Boolean isUsed) {
+		Boolean is_update = giftCardUserRecordService.update(null, Wrappers.lambdaUpdate(GiftCardUserRecord.class)
+				.set(GiftCardUserRecord::getRemainCash, gcRemainCash.subtract(deductCash))
+				.set(isUsed, GiftCardUserRecord::getIsUsed, isUsed)
+				.eq(GiftCardUserRecord::getId, gcId)
+				.eq(GiftCardUserRecord::getIsPay, true)
+				.eq(GiftCardUserRecord::getRemainCash, gcRemainCash));
+		if (!is_update) {
+			throw BusinessRuntimeException.getInstance("礼品卡支付异常,请刷新页面重试");
+		}
+		//记录使用关系 订单关闭 退款使用
+		GiftCardOrderUseRecord useRecord = new GiftCardOrderUseRecord();
+		useRecord.setUserId(userId);
+		useRecord.setCash(deductCash);
+		useRecord.setGcId(gcId);
+		gcUseRecords.add(useRecord);
+	}
+
+	/**
+	 * 用户购买成功礼品卡记录
+	 */
+	private void giftCardUserPayRecord(String gcPayDetail, OrderDon orderDon) {
+		try {
+			//礼品卡规格
+			List<GiftCardGoodsSkuFrontView> gcList = Jsons.parseList(gcPayDetail, GiftCardGoodsSkuFrontView.class);
+			List<GiftCardUserRecord> gcUserPayRecords = new ArrayList<>();
+			for (GiftCardGoodsSkuFrontView data : gcList) {
+				for (Integer i = 0; i < data.getGcNum(); i++) {
+					//礼品卡关系
+					GiftCardUserRecord giftCardUserRecord = new GiftCardUserRecord();
+					String gcDetail;
+					if (data.getGcType() == 1) {
+						gcDetail = String.format("现金卡%s", data.getCash().divide(BigDecimal.valueOf(100)));
+						giftCardUserRecord.setCash(data.getCash());
+						giftCardUserRecord.setRemainCash(data.getCash());
+					} else {
+						gcDetail = String.format("虚拟卡%s%s", data.getGcGoodsTitle(), data.getGcSpecVal());
+						giftCardUserRecord.setGcGoodsId(data.getGcGoodsId());
+						giftCardUserRecord.setGcSkuId(data.getGcSkuId());
+					}
+					giftCardUserRecord.setOrderId(orderDon.getId());
+					giftCardUserRecord.setUserId(orderDon.getUserId());
+					giftCardUserRecord.setGcType(data.getGcType());
+					giftCardUserRecord.setGcDetail(gcDetail);
+					giftCardUserRecord.setType(data.getGcShowType());
+					giftCardUserRecord.setImg(data.getGcImg());
+					giftCardUserRecord.setIsPay(true);
+					giftCardUserRecord.setRc(RandomUtil.randomString(6));
+					giftCardUserRecord.setPayTime(Optional.ofNullable(orderDon.getPayTime()).orElse(orderDon.getCreatedTime()));
+					gcUserPayRecords.add(giftCardUserRecord);
+				}
+			}
+			if (CollUtil.isNotEmpty(gcUserPayRecords)) {
+				giftCardUserRecordService.saveBatch(gcUserPayRecords);
+			}
+		} catch (Exception e) {
+			log.info("用户userId:{}礼品订单orderId:{}支付成功,记录购买成功记录错误,e:{}", orderDon.getUserId(), orderDon.getId(), StringUtil.getErrorText(e));
+		}
 	}
 }

+ 34 - 0
netflix-service/src/main/java/com/cyksj/service/telegram/TelegramService.java

@@ -0,0 +1,34 @@
+package com.cyksj.service.telegram;
+
+import cn.hutool.http.HttpUtil;
+import com.cyksj.common.util.Jsons;
+import com.cyksj.dto.RedisKey;
+import com.cyksj.model.request.TelegramBotMsgReq;
+import com.cyksj.redis.RedisService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author chan
+ * @date 2023/9/12 14:17
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class TelegramService {
+    private final String URL = "https://yinhedvd.com/8082/api/movies/sendMsg";
+
+    private final RedisService redisService;
+
+    public void sendMsg(TelegramBotMsgReq botMsg) throws Exception {
+        Boolean flag = redisService.hasKey(RedisKey.TELEGRAM_BOT_MSG);
+        if(!flag){
+            log.info("电报购买推送 推送内容:{}",botMsg);
+            HttpUtil.post(URL, Jsons.toJson(botMsg));
+            redisService.set(RedisKey.TELEGRAM_BOT_MSG,1,60L*3L);
+        }else {
+            log.info("推送未间隔2分钟,暂不推送.");
+        }
+    }
+}

+ 5 - 0
netflix-service/src/main/java/com/cyksj/service/user/UserService.java

@@ -46,4 +46,9 @@ public interface UserService extends IService<User> {
 	User webLogin(LoginReq loginReq) throws Exception;
 
 	String bindWxAccountRedirect(String code, String state) throws Exception;
+
+	/**
+	 * 领取礼品卡
+	 */
+	void receiveGiftCardByRc(Long userId, String code, Long relationId);
 }

+ 120 - 2
netflix-service/src/main/java/com/cyksj/service/user/impl/UserServiceImpl.java

@@ -1,6 +1,7 @@
 package com.cyksj.service.user.impl;
 
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.StrUtil;
@@ -14,26 +15,33 @@ import com.cyksj.common.util.Codec;
 import com.cyksj.common.util.Jsons;
 import com.cyksj.common.util.StringUtil;
 import com.cyksj.config.wxlogin.WxOpenPlatYHLXLoginConfig;
-import com.cyksj.mapper.PhoneCodeMapper;
-import com.cyksj.mapper.UserMapper;
+import com.cyksj.mapper.*;
 import com.cyksj.mapper.channel.ChannelPopularizeMapper;
 import com.cyksj.mapper.manage.cps.UserDistributePopularizeMapper;
 import com.cyksj.mapper.market.task.UserBindDetailMapper;
 import com.cyksj.model.dto.*;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.request.LoginReq;
+import com.cyksj.model.views.RenewalView;
+import com.cyksj.model.views.UserTicketView;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.distribute.DistributeService;
 import com.cyksj.service.distribute.equipment.EquipmentDistributeService;
+import com.cyksj.service.exchange.ExchangeCodeService;
 import com.cyksj.service.mange.coupon.CouponCommonService;
 import com.cyksj.service.market.task.BindTaskService;
 import com.cyksj.service.sys.SysConfigService;
+import com.cyksj.service.user.UserBindRelationService;
 import com.cyksj.service.user.UserService;
 import com.cyksj.service.wechat.WeChatService;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.param.Operator;
+import com.ejlchina.searcher.util.MapUtils;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.dao.DuplicateKeyException;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.Assert;
 
 import java.util.ArrayList;
@@ -75,6 +83,18 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
 
 	private final WxOpenPlatYHLXLoginConfig wxOpenPlatYHLXLoginConfig;
 
+	private final GiftCardUserRecordMapper giftCardUserRecordMapper;
+
+	private final ExchangeCodeService exchangeCodeService;
+
+	private final GoodsDonSkuMapper goodsDonSkuMapper;
+
+	private final GroupsRelationMapper groupsRelationMapper;
+
+	private final BeanSearcher beanSearcher;
+
+	private final UserBindRelationService userBindRelationService;
+
 	private static final GlobalThreadPoolTaskExecutor TASK_POOL = GlobalThreadPoolTaskExecutor.getInstance();
 
 	@Override
@@ -496,6 +516,104 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
 		return redisService.getStr(re.getMappingId().toString());
 	}
 
+	@Override
+	@Transactional(rollbackFor = Throwable.class)
+	public void receiveGiftCardByRc(Long userId, String code, Long relationId) {
+		GiftCardUserRecord giftCardUserRecord = giftCardUserRecordMapper.selectOne(Wrappers.lambdaQuery(GiftCardUserRecord.class)
+				.eq(GiftCardUserRecord::getRc, code).last("limit 1"));
+		if (giftCardUserRecord == null) {
+			throw BusinessRuntimeException.getInstance("好友赠送礼品卡不存在");
+		}
+		if (!giftCardUserRecord.getIsPay()) {
+			throw BusinessRuntimeException.getInstance("无效礼品卡,好友未购买");
+		}
+		if (giftCardUserRecord.getUserId().equals(userId)) {
+			throw BusinessRuntimeException.getInstance("无法领取自己购买的礼品卡");
+		}
+		if (giftCardUserRecord.getToUserId() != 0 && !giftCardUserRecord.getToUserId().equals(userId)) {
+			throw BusinessRuntimeException.getInstance("好友赠送礼品卡已被领取");
+		}
+		if (giftCardUserRecord.getToUserId().equals(userId)) {
+			throw BusinessRuntimeException.getInstance("您已领取该礼品卡");
+		}
+		giftCardUserRecord.setToUserId(userId);
+		int update = giftCardUserRecordMapper.update(null, Wrappers.lambdaUpdate(GiftCardUserRecord.class)
+				.set(giftCardUserRecord.getGcType() == 2, GiftCardUserRecord::getIsUsed, true)
+				.set(GiftCardUserRecord::getToUserId, userId)
+				.set(GiftCardUserRecord::getIsSend, true)
+				.set(GiftCardUserRecord::getReceivedTime, DateTime.now())
+				.eq(GiftCardUserRecord::getId, giftCardUserRecord.getId())
+				.eq(GiftCardUserRecord::getIsPay, true)
+				.eq(GiftCardUserRecord::getToUserId, 0));
+		if (update > 0) {
+			//虚拟卡
+			//直接发送 对应规格车票
+			if (giftCardUserRecord.getGcType() == 2) {
+				Long gcSkuId = giftCardUserRecord.getGcSkuId();
+				log.info("用户userId:{}领取礼品卡id:{},开始发放虚拟车票skuId:{}", userId, giftCardUserRecord.getId(), gcSkuId);
+				GoodsDonSku sku = goodsDonSkuMapper.selectById(gcSkuId);
+				if (sku == null) {
+					log.info("礼品卡id:{}虚拟车票skuId:{}不存在", giftCardUserRecord.getId(), gcSkuId);
+					throw BusinessRuntimeException.getInstance("该礼品卡对应的虚拟卡不存在,请联系客服");
+				}
+				List<Long> relationUserIdList = userBindRelationService.getRelationUserIdList(userId, null);
+				if (relationId != null) {
+					GroupsRelation groupsRelation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
+							.in(GroupsRelation::getUserId, relationUserIdList)
+							.eq(GroupsRelation::getId, relationId)
+							.in(GroupsRelation::getStatus, List.of(GroupsRelation.Status.validity, GroupsRelation.Status.outside)).last("limit 1"));
+					if (groupsRelation == null) {
+						throw BusinessRuntimeException.getInstance("您选择的车票不存在");
+					}
+					Date expiryTime = groupsRelation.getExpiryTime();
+					if (expiryTime == null) {
+						throw BusinessRuntimeException.getInstance("请等您该类型下的车票配置账号后再增加对应时长");
+					}
+					if (sku.getDays() != null && sku.getDays() > 0) {
+						expiryTime = DateUtil.offsetDay(expiryTime, sku.getDays());
+					} else {
+						expiryTime = DateUtil.offsetMonth(expiryTime, sku.getMonths());
+					}
+					log.info("userId:{}领取虚拟卡skuId:{},增加车票时长至:{}", userId, sku.getId(), expiryTime.toString());
+					groupsRelation.setExpiryTime(expiryTime);
+					groupsRelationMapper.updateById(groupsRelation);
+					return;
+				}
+				//是否存在对应车票
+				List<UserTicketView> ticketViews = beanSearcher.searchAll(UserTicketView.class, MapUtils.builder()
+						.field(UserTicketView::getUserId, relationUserIdList).op(Operator.InList)
+						.field(UserTicketView::getGoodsId, giftCardUserRecord.getGcGoodsId())
+						.field(RenewalView::getStatus, List.of("validity", "outside")).op(Operator.InList)
+						.orderBy(UserTicketView::getRelationId).asc()
+						.build());
+				if (CollUtil.isEmpty(ticketViews)) {
+					GroupsRelation relationNoOrder = exchangeCodeService.getRelationNoOrder(sku, userId);
+					giftCardUserRecordMapper.update(null, Wrappers.lambdaUpdate(GiftCardUserRecord.class)
+							.set(GiftCardUserRecord::getRelationId, relationNoOrder.getId())
+							.eq(GiftCardUserRecord::getId, giftCardUserRecord.getId()));
+					log.info("用户未有该规格:{}车票,发送至用户userId:{}礼品卡虚拟车票结束", gcSkuId, userId);
+					return;
+				}
+				if (ticketViews.size() > 1) {
+					throw BusinessRuntimeException.getInstance("您有多张该类型的车票,请选择一张增加时长");
+				}
+				UserTicketView userTicketView = ticketViews.get(0);
+				Date expiryTime = userTicketView.getExpiryTime();
+				if (expiryTime == null) {
+					throw BusinessRuntimeException.getInstance("请等您该类型下的车票配置账号后再增加对应时长");
+				}
+				if (sku.getDays() != null && sku.getDays() > 0) {
+					expiryTime = DateUtil.offsetDay(expiryTime, sku.getDays());
+				} else {
+					expiryTime = DateUtil.offsetMonth(expiryTime, sku.getMonths());
+				}
+				groupsRelationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
+						.set(GroupsRelation::getExpiryTime, expiryTime)
+						.eq(GroupsRelation::getId, userTicketView.getRelationId()));
+			}
+		}
+	}
+
 	/**
 	 * 发放新用户福利
 	 */

+ 14 - 4
netflix-web/src/main/java/com/cyksj/web/controller/goods/GoodsDonController.java

@@ -109,7 +109,7 @@ public class GoodsDonController {
                     .orderByAsc(GoodsDonSku::getPrice)
                     .last("limit 1")
                     .select(GoodsDonSku::getPrice));
-            Optional.ofNullable(goodsDonSku).ifPresent(sku->{
+            Optional.ofNullable(goodsDonSku).ifPresent(sku -> {
                 goods.setPrice(goodsDonSku.getPrice());
                 goods.setSoldNum(goods.getVirtualSold() + orderDonMapper.selectCount(Wrappers.lambdaQuery(OrderDon.class)
                         .eq(OrderDon::getGoodsId, goods.getId())
@@ -301,12 +301,12 @@ public class GoodsDonController {
         }
         MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
         List<RegisterGoodsDonView> dataList = beanSearcher.searchAll(RegisterGoodsDonView.class, builder.build());
-	    DateTime now = DateTime.now();
-	    dataList.forEach(data->{
+        DateTime now = DateTime.now();
+        dataList.forEach(data -> {
             Integer sold = registerOrderDonMapper.selectCount(Wrappers.lambdaQuery(RegisterOrderDon.class)
                     .eq(RegisterOrderDon::getGoodsId, data.getId()).notIn(RegisterOrderDon::getStatus, Constant.noOrderStatus));
             data.setSold(sold + data.getVirtualSold());
-		    data.setNotifyMsg(getPayMsgTime(data.getId(), now, 2));
+            data.setNotifyMsg(getPayMsgTime(data.getId(), now, 2));
         });
         redisService.setNx(registerCacheKey, dataList, RedisService.key.REGISTER_HOME_PAGE_CACHE.getTimeout());
         return GatewayResponse.SUCCESS.newBuilder().toResult(dataList);
@@ -429,6 +429,16 @@ public class GoodsDonController {
         return GatewayResponse.SUCCESS.newBuilder().toResult(search);
     }
 
+    /**
+     * 获取礼品卡平台性情
+     */
+    @GetMapping("/get/card/{id}")
+    public Result<Map<Integer, List<GiftCardGoodsSkuFrontView>>> getGiftCardDetail(@PathVariable Long id) {
+        List<GiftCardGoodsSkuFrontView> giftCardGoodsSkuFrontViews = beanSearcher.searchAll(GiftCardGoodsSkuFrontView.class, MapUtils.builder().field(GiftCardGoodsSkuFrontView::getGoodsId, id).build());
+        Map<Integer, List<GiftCardGoodsSkuFrontView>> map = giftCardGoodsSkuFrontViews.stream().collect(Collectors.groupingBy(GiftCardGoodsSkuFrontView::getGcType));
+        return GatewayResponse.SUCCESS.newBuilder().toResult(map);
+    }
+
     public List<Long> getFilterGoodsIds() {
         //过滤杭州Ai ChatGPT平台
         //获取当前ip地址

+ 2 - 2
netflix-web/src/main/java/com/cyksj/web/controller/group/GroupRelationController.java

@@ -170,9 +170,9 @@ public class GroupRelationController {
     public Result<List<UserTicketView>> getUserTicketView() {
         long userId = StpUserUtil.getLoginIdAsLong();
         List<Long> userIds = userBindRelationService.getRelationUserIdList(userId, null);
-        List<UserTicketView> ticketViews = beanSearcher.searchAll(UserTicketView.class, MapUtils.builder()
+        List<UserTicketView> ticketViews = beanSearcher.searchAll(UserTicketView.class, MapUtils.flatBuilder(request.getParameterMap())
                 .field(UserTicketView::getUserId, userIds).op(Operator.InList)
-                .field(RenewalView::getStatus, List.of("validity", "overdue", "outside")).op(Operator.InList)
+                .field(RenewalView::getStatus, List.of("validity", "outside")).op(Operator.InList)
                 .orderBy(UserTicketView::getRelationId).asc()
                 .build());
         return GatewayResponse.SUCCESS.newBuilder().toResult(ticketViews);

+ 13 - 1
netflix-web/src/main/java/com/cyksj/web/controller/manage/goods/CmsGoodsDonController.java

@@ -192,8 +192,20 @@ public class CmsGoodsDonController {
     @GetMapping("/get/all")
     public Result<List<GoodsDon>> getAllGoodsList() {
         List<GoodsDon> goodsDons = beanSearcher.searchAll(GoodsDon.class, MapUtils.flatBuilder(request.getParameterMap())
-                .field(GoodsDon::getDeleted,true)
+                .field(GoodsDon::getDeleted, true)
+                .put("condition", "(special_type is null or special_type != 'giftCard')")
                 .onlySelect(GoodsDon::getId, GoodsDon::getCategory, GoodsDon::getType, GoodsDon::getTitle).build());
         return GatewayResponse.SUCCESS.newBuilder().toResult(goodsDons);
     }
+
+    /**
+     * 获取礼品卡平台
+     */
+    @GetMapping("/get/giftCard")
+    public Result<GoodsDon> getGiftCard() {
+        GoodsDon goodsDon = beanSearcher.searchFirst(GoodsDon.class, MapUtils.builder()
+                .field(GoodsDon::getSpecialType, GoodsDon.SpecialType.giftCard.name())
+                .build());
+        return GatewayResponse.SUCCESS.newBuilder().toResult(goodsDon);
+    }
 }

+ 120 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/goods/GiftCardController.java

@@ -0,0 +1,120 @@
+package com.cyksj.web.controller.manage.goods;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.mapper.GoodsDonMapper;
+import com.cyksj.model.entity.GiftCardGoodsSku;
+import com.cyksj.model.request.GiftCardGoodsSkuReq;
+import com.cyksj.model.views.GiftCardGoodsSkuView;
+import com.cyksj.model.views.GiftCardUserPayView;
+import com.cyksj.service.giftcard.GiftCardGoodsSkuService;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.SearchResult;
+import com.ejlchina.searcher.util.MapUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+
+/*
+ *项目名: netflix
+ *文件名: GiftCardController
+ *创建者: JavaZou
+ *创建时间:2023/8/29 18:15
+ */
+@RequestMapping("/manage/giftCard")
+@RestController
+@RequiredArgsConstructor
+public class GiftCardController {
+	private final GiftCardGoodsSkuService giftCardGoodsSkuService;
+
+	private final BeanSearcher beanSearcher;
+
+	private final HttpServletRequest request;
+
+	private final GoodsDonMapper goodsDonMapper;
+
+	/**
+	 * 设置礼品卡 规格
+	 */
+	@PostMapping("/set")
+	public Result<String> setGiftCardSku(@RequestBody GiftCardGoodsSkuReq req) {
+		giftCardGoodsSkuService.setGiftCardSku(req);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 修改礼品卡 规格
+	 */
+	@PutMapping("/put")
+	public Result<String> updateGiftCardSku(@RequestBody GiftCardGoodsSku giftCardSku) {
+		if (giftCardSku.getId() == null) {
+			throw BusinessRuntimeException.getInstance("请指定要修改的礼品卡");
+		}
+		giftCardGoodsSkuService.setOrUpdateGiftCardSku(giftCardSku);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 获取礼品卡规格 配置
+	 */
+	@GetMapping("/get")
+	public Result<SearchResult<GiftCardGoodsSkuView>> getGiftCardGoodsSku() {
+		SearchResult<GiftCardGoodsSkuView> list = beanSearcher.search(GiftCardGoodsSkuView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(list);
+	}
+
+	/**
+	 * 礼品卡用户购买成功 记录
+	 */
+	@GetMapping("/get/pay")
+	public Result<SearchResult<GiftCardUserPayView>> getGiftCardPayRecord() {
+		SearchResult<GiftCardUserPayView> search = beanSearcher.search(GiftCardUserPayView.class, MapUtils.flatBuilder(request.getParameterMap())
+				.field(GiftCardUserPayView::getIsPay, true)
+				.build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 礼品卡上下架
+	 */
+	@PutMapping("/update/status/{id}")
+	public Result<String> updateStatusById(@PathVariable Long id) {
+		GiftCardGoodsSku byId = giftCardGoodsSkuService.getById(id);
+		if (byId == null) {
+			return GatewayResponse.SUCCESS.newBuilder().toResult();
+		}
+		if (!byId.getStatus()) {
+			//校验礼品卡已上架多少个 最多上架三个
+			int count = giftCardGoodsSkuService.count(Wrappers.lambdaQuery(GiftCardGoodsSku.class)
+					.eq(GiftCardGoodsSku::getStatus, true)
+					.eq(GiftCardGoodsSku::getDeleted, true)
+					.eq(GiftCardGoodsSku::getGcType, byId.getGcType()));
+			if (count > 2) {
+				throw BusinessRuntimeException.getInstance(String.format("%s最多上架三个", byId.getGcType() == 1 ? "现金卡" : "虚拟卡"));
+			}
+		}
+		byId.setStatus(!byId.getStatus());
+		giftCardGoodsSkuService.updateById(byId);
+		//设置对应礼品卡平台 最低价格
+		giftCardGoodsSkuService.setGiftCardGoodsStat(goodsDonMapper.selectById(byId.getGoodsId()));
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 删除礼品卡
+	 */
+	@DeleteMapping("/del/{id}")
+	public Result<String> delById(@PathVariable Long id) {
+		GiftCardGoodsSku byId = giftCardGoodsSkuService.getById(id);
+		if (byId == null) {
+			return GatewayResponse.SUCCESS.newBuilder().toResult();
+		}
+		byId.setDeleted(false);
+		giftCardGoodsSkuService.updateById(byId);
+		giftCardGoodsSkuService.setGiftCardGoodsStat(goodsDonMapper.selectById(byId.getGoodsId()));
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+}

+ 1 - 7
netflix-web/src/main/java/com/cyksj/web/controller/payment/OrderController.java

@@ -15,7 +15,6 @@ import com.cyksj.config.zfb.ZfbProductCode;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayApiCode;
 import com.cyksj.enums.GatewayResponse;
-import com.cyksj.mapper.OrderDonMapper;
 import com.cyksj.mapper.OrderDonWaybillMapper;
 import com.cyksj.mapper.UserMapper;
 import com.cyksj.mapper.channel.UserPayEquipmentAvailableBenefitsMapper;
@@ -87,9 +86,6 @@ public class OrderController {
     @Resource
     private HttpServletResponse response;
 
-    @Autowired
-    private OrderDonMapper orderDonMapper;
-
     @Autowired
     private UserBindDetailMapper userBindDetailMapper;
 
@@ -128,9 +124,7 @@ public class OrderController {
     @PostMapping("/post/submit")
     public Result<OrderDon> submit(@Validated @RequestBody OrderPayRequest payRequest) throws Exception {
         final String methodName = "吊起微信支付";
-        if (payRequest.getIsNoLogin() == null || !payRequest.getIsNoLogin()) {
-            payRequest.setUserId(StpUserUtil.getLoginIdAsLong());
-        }
+        payRequest.setUserId(StpUserUtil.getUserIdAfterLogin());
         log.info("{}[start] params:{}",methodName,payRequest);
 
         OrderDon orderDon = orderDonService.submit(payRequest);

+ 60 - 4
netflix-web/src/main/java/com/cyksj/web/controller/user/UserController.java

@@ -13,10 +13,7 @@ import com.cyksj.mapper.manage.coupon.CouponUserMapper;
 import com.cyksj.model.dto.UserWhoami;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.manage.views.GroupsRelationView;
-import com.cyksj.model.request.ExchangeCodeTicket;
-import com.cyksj.model.request.ReceiveBenefitsReq;
-import com.cyksj.model.request.UserReq;
-import com.cyksj.model.request.WorkOrderReq;
+import com.cyksj.model.request.*;
 import com.cyksj.model.response.UserAuthLoginResp;
 import com.cyksj.model.views.*;
 import com.cyksj.service.corp.CropChatService;
@@ -118,6 +115,12 @@ public class UserController {
                 .eq(OrderDon::getUserId, userId)
                 .eq(OrderDon::getStatus, OrderDon.Status.noPayment).last("limit 1"));
         personalView.setIsNoPayment(orderDon != null ? true : false);
+        //礼品卡可用数量
+        Number numOfGiftCard = beanSearcher.searchCount(GiftCardUserRecordView.class, MapUtils.builder()
+                .put("uid", String.format("((user_id = %s and is_send = 0) or (to_user_id = %s and is_used = 0))", userId, userId))
+                .field(GiftCardUserRecordView::getIsPay, true)
+                .build());
+        personalView.setNumOfGiftCard(numOfGiftCard.intValue());
         return GatewayResponse.SUCCESS.newBuilder().toResult(personalView);
     }
 
@@ -338,4 +341,57 @@ public class UserController {
         UserAuthLoginResp loginPhoneRep = new UserAuthLoginResp(StpUserUtil.getTokenValue(), switch_user.getShowId(), switch_user.getNickname(), switch_user.getHeadimgurl());
         return GatewayResponse.SUCCESS.newBuilder().toResult(loginPhoneRep);
     }
+
+    /**
+     * 个人礼品卡列表
+     * @return
+     */
+    @GetMapping("/get/giftCard")
+    public Result<SearchResult<GiftCardUserPayFrontView>> getGiftCard() {
+        long userId = StpUserUtil.getLoginIdAsLong();
+        String condition = String.format("and (user_id = %s or to_user_id = %s)", userId, userId);
+        SearchResult<GiftCardUserPayFrontView> view = beanSearcher.search(GiftCardUserPayFrontView.class, MapUtils.builder()
+                .put("condition", condition)
+                .put("uid", userId)
+                .orderBy(GiftCardUserRecordView::getIsUsed).asc()
+                .orderBy(GiftCardUserPayFrontView::getId).desc().build());
+        return GatewayResponse.SUCCESS.newBuilder().toResult(view);
+    }
+
+    /**
+     * 可用现金礼品卡列表
+     */
+    @GetMapping("/get/available/giftCard")
+    public Result<List<GiftCardUserPayFrontView>> getAvailGiftCard() {
+        long userId = StpUserUtil.getLoginIdAsLong();
+        String condition = String.format("and to_user_id = %s", userId);
+        List<GiftCardUserPayFrontView> view = beanSearcher.searchAll(GiftCardUserPayFrontView.class, MapUtils.builder()
+                .put("condition", condition)
+                .put("uid", userId)
+                //现金卡
+                .field(GiftCardUserPayFrontView::getGcType, 1)
+                .orderBy(GiftCardUserRecordView::getIsUsed).asc()
+                .orderBy(GiftCardUserPayFrontView::getId).desc().build());
+        return GatewayResponse.SUCCESS.newBuilder().toResult(view);
+    }
+
+    /**
+     * 礼品卡分享详情
+     */
+    @GetMapping("/get/giftCard/detail/{code}")
+    public Result<GiftCardDetailFrontView> getGiftCardDetailByCode(@PathVariable String code) {
+        GiftCardDetailFrontView detail = beanSearcher.searchFirst(GiftCardDetailFrontView.class, MapUtils.builder().field(GiftCardDetailFrontView::getCode, code).build());
+        return GatewayResponse.SUCCESS.newBuilder().toResult(detail);
+    }
+
+    /**
+     * 领取他人礼品卡
+     */
+    @PostMapping("/receive/giftCard")
+    public Result<String> receiveGiftCardByRc(@RequestBody GiftCardReceiveReq req) {
+        long userId = StpUserUtil.getLoginIdAsLong();
+        Long relationId = req.getRelationId();
+        userService.receiveGiftCardByRc(userId, req.getCode(), relationId);
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
 }