Jelajahi Sumber

Merge branch 'master' into pre

# Conflicts:
#	netflix-common/src/main/java/com/cyksj/common/constant/Constant.java
#	netflix-common/src/main/java/com/cyksj/dto/RedisKey.java
#	netflix-dao/src/main/java/com/cyksj/model/entity/OrderDon.java
#	netflix-dao/src/main/java/com/cyksj/model/views/GoodsDonViews.java
#	netflix-service/src/main/java/com/cyksj/redis/RedisService.java
#	netflix-service/src/main/java/com/cyksj/service/giftcard/impl/GiftCardGoodsSkuServiceImpl.java
#	netflix-service/src/main/java/com/cyksj/service/mange/impl/CmsOrderDonServiceImpl.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
zoujiajian 2 tahun lalu
induk
melakukan
249d47c27e
83 mengubah file dengan 2228 tambahan dan 586 penghapusan
  1. 35 0
      netflix-common/src/main/java/com/cyksj/common/constant/Constant.java
  2. 0 1
      netflix-common/src/main/java/com/cyksj/dto/RedisKey.java
  3. 4 0
      netflix-dao/src/main/java/com/cyksj/mapper/GoodsDonSkuMapper.java
  4. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/GroupsRelationCustomerServiceFollowRecordMapper.java
  5. 14 0
      netflix-dao/src/main/java/com/cyksj/mapper/GroupsRelationExpiryRecordMapper.java
  6. 2 0
      netflix-dao/src/main/java/com/cyksj/mapper/GroupsRelationMapper.java
  7. 5 0
      netflix-dao/src/main/java/com/cyksj/mapper/OrderDonMapper.java
  8. 3 0
      netflix-dao/src/main/java/com/cyksj/mapper/UserMapper.java
  9. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/UserPhoneSendRecordMapper.java
  10. 6 0
      netflix-dao/src/main/java/com/cyksj/mapper/manage/coupon/CouponDistributePopularizeMapper.java
  11. 2 0
      netflix-dao/src/main/java/com/cyksj/mapper/manage/coupon/CouponUserMapper.java
  12. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/manage/distribute/UserDistributeRuleOrderRecordMapper.java
  13. 2 0
      netflix-dao/src/main/java/com/cyksj/model/entity/CorpFollowConfig.java
  14. 6 0
      netflix-dao/src/main/java/com/cyksj/model/entity/CouponUser.java
  15. 11 0
      netflix-dao/src/main/java/com/cyksj/model/entity/DistributeWaitingSendPoints.java
  16. 1 1
      netflix-dao/src/main/java/com/cyksj/model/entity/GoodsDonSku.java
  17. 25 0
      netflix-dao/src/main/java/com/cyksj/model/entity/GroupsRelationCustomerServiceFollowRecord.java
  18. 92 0
      netflix-dao/src/main/java/com/cyksj/model/entity/GroupsRelationExpiryRecord.java
  19. 5 0
      netflix-dao/src/main/java/com/cyksj/model/entity/OrderDiscountPlusPurchaseSkuRelation.java
  20. 5 0
      netflix-dao/src/main/java/com/cyksj/model/entity/OrderDon.java
  21. 5 0
      netflix-dao/src/main/java/com/cyksj/model/entity/User.java
  22. 1 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserBalanceSourceRecord.java
  23. 25 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserDistributeRuleOrderRecord.java
  24. 7 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserDistributeShared.java
  25. 18 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserPhoneSendRecord.java
  26. 129 0
      netflix-dao/src/main/java/com/cyksj/model/excel/ExcelGroupRelationData.java
  27. 9 0
      netflix-dao/src/main/java/com/cyksj/model/manage/views/OrderDonBackView.java
  28. 3 0
      netflix-dao/src/main/java/com/cyksj/model/manage/views/UserView.java
  29. 4 0
      netflix-dao/src/main/java/com/cyksj/model/request/LoginReq.java
  30. 5 0
      netflix-dao/src/main/java/com/cyksj/model/request/OrderRefundReq.java
  31. 9 0
      netflix-dao/src/main/java/com/cyksj/model/request/corp/CorpFollowContact.java
  32. 14 0
      netflix-dao/src/main/java/com/cyksj/model/response/GoogleLoginRep.java
  33. 63 0
      netflix-dao/src/main/java/com/cyksj/model/views/AccountSpecificView.java
  34. 10 0
      netflix-dao/src/main/java/com/cyksj/model/views/BackgroundDataView.java
  35. 3 0
      netflix-dao/src/main/java/com/cyksj/model/views/DistributeOrdersDetailView.java
  36. 25 0
      netflix-dao/src/main/java/com/cyksj/model/views/DistributeWaitingOrderPointsRuleView.java
  37. 1 0
      netflix-dao/src/main/java/com/cyksj/model/views/GoodsDonSkuFrontView.java
  38. 1 15
      netflix-dao/src/main/java/com/cyksj/model/views/GoodsDonViews.java
  39. 6 0
      netflix-dao/src/main/java/com/cyksj/model/views/UserDistributeOrdersDetailView.java
  40. 6 0
      netflix-dao/src/main/java/com/cyksj/model/views/UserDistributePopularizeView.java
  41. 34 0
      netflix-dao/src/main/java/com/cyksj/model/views/UserDistributeRuleOrderRecordView.java
  42. 6 0
      netflix-dao/src/main/resources/mapper/CouponUserMapper.xml
  43. 16 0
      netflix-dao/src/main/resources/mapper/GoodsDonSkuMapper.xml
  44. 24 0
      netflix-dao/src/main/resources/mapper/GroupRelationMapper.xml
  45. 32 1
      netflix-dao/src/main/resources/mapper/OrderDonMapper.xml
  46. 1 1
      netflix-dao/src/main/resources/mapper/UserDistributeMapper.xml
  47. 6 2
      netflix-dao/src/main/resources/mapper/UserDistributePopularizeMapper.xml
  48. 1 15
      netflix-service/src/main/java/com/cyksj/redis/RedisService.java
  49. 127 48
      netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpEventActionServiceImpl.java
  50. 1 0
      netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpFollowDynamicConfigServiceImpl.java
  51. 75 36
      netflix-service/src/main/java/com/cyksj/service/exchange/impl/ExchangeCodeServiceImpl.java
  52. 1 3
      netflix-service/src/main/java/com/cyksj/service/giftcard/impl/GiftCardGoodsSkuServiceImpl.java
  53. 6 0
      netflix-service/src/main/java/com/cyksj/service/mange/CmsOrderDonService.java
  54. 58 8
      netflix-service/src/main/java/com/cyksj/service/mange/account/CmsAccountServiceImpl.java
  55. 35 32
      netflix-service/src/main/java/com/cyksj/service/mange/group/CmsGroupServiceImpl.java
  56. 134 18
      netflix-service/src/main/java/com/cyksj/service/mange/impl/CmsOrderDonServiceImpl.java
  57. 3 1
      netflix-service/src/main/java/com/cyksj/service/mange/statistics/StatisticsDataService.java
  58. 65 52
      netflix-service/src/main/java/com/cyksj/service/mange/statistics/impl/StatisticsDataServiceImpl.java
  59. 3 0
      netflix-service/src/main/java/com/cyksj/service/market/impl/MarketFrontServiceImpl.java
  60. 1 4
      netflix-service/src/main/java/com/cyksj/service/market/task/impl/BindTaskServiceImpl.java
  61. 2 1
      netflix-service/src/main/java/com/cyksj/service/order/OrderCommonService.java
  62. 6 3
      netflix-service/src/main/java/com/cyksj/service/order/impl/OrderCommonServiceImpl.java
  63. 336 52
      netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java
  64. 2 0
      netflix-service/src/main/java/com/cyksj/service/order/impl/UserRealOrderBenefitsImpl.java
  65. 17 0
      netflix-service/src/main/java/com/cyksj/service/relation/GroupsRelationExpiryRecordService.java
  66. 10 0
      netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupRelationClearServiceImpl.java
  67. 66 0
      netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupsRelationExpiryRecordServiceImpl.java
  68. 11 0
      netflix-service/src/main/java/com/cyksj/service/user/UserBackService.java
  69. 34 0
      netflix-service/src/main/java/com/cyksj/service/user/impl/UserBackServiceImpl.java
  70. 46 28
      netflix-service/src/main/java/com/cyksj/service/user/impl/UserServiceImpl.java
  71. 1 1
      netflix-web/src/main/java/com/cyksj/web/controller/channel/ChannelController.java
  72. 2 0
      netflix-web/src/main/java/com/cyksj/web/controller/cps/CpsPopularizeController.java
  73. 78 232
      netflix-web/src/main/java/com/cyksj/web/controller/goods/GoodsDonController.java
  74. 11 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/CmsOrderController.java
  75. 46 4
      netflix-web/src/main/java/com/cyksj/web/controller/manage/account/CmsAccountController.java
  76. 117 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/distribute/DistributeController.java
  77. 4 16
      netflix-web/src/main/java/com/cyksj/web/controller/manage/goods/CmsGoodsDonController.java
  78. 8 1
      netflix-web/src/main/java/com/cyksj/web/controller/manage/goods/CmsGoodsDonSkuController.java
  79. 32 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/group/CmsGroupController.java
  80. 130 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/group/CmsGroupsRelationExpiryController.java
  81. 13 4
      netflix-web/src/main/java/com/cyksj/web/controller/manage/statistics/StatisticsDataController.java
  82. 7 6
      netflix-web/src/main/java/com/cyksj/web/controller/payment/OrderController.java
  83. 19 0
      netflix-web/src/main/java/com/cyksj/web/controller/user/AuthorizationController.java

+ 35 - 0
netflix-common/src/main/java/com/cyksj/common/constant/Constant.java

@@ -26,6 +26,12 @@ public interface Constant {
 	 */
 	List<Integer> realGoodsType = List.of(2, 3);
 
+	/**
+	 * 平台类型
+	 * 1、虚拟、2实物、3潮玩好物
+	 */
+	List<Integer> goodsType = List.of(1, 2, 3);
+
 	/**
 	 * 默认头像
 	 */
@@ -106,6 +112,8 @@ public interface Constant {
 
 	String ACCOUNT_EXPIRY_MSG_TEMPLATE = "您好,您购买的%s,还有%s到期,请登陆网站https://nf.video/及时续费。【银河录像局】";
 
+	String ONE_EMPTY = " ";
+
 	String AMERICA_APPID_SECRET = "1990-01-01 朋友 aaa111 工作 aab112 父母 aac113";
 
 	String ACCOUNT_DOUBLE_VERIFY_KEY = "account_double_verify_key";
@@ -152,8 +160,35 @@ public interface Constant {
 	 */
 	List<Long> GPT_GOODS_IDS = List.of(18l, 29l, 30l);
 
+	List<String> TRACK_RENEW_TYPE = List.of("email", "wechat");
+
+	String ORDER_MSG_FIRST_NOTIFY = "%s购买成功,收藏官网https://nf.video/ 合租账号就上银河录像局【银河录像局】";
+
+	String LOGIN_CODE = "yhc@36";
+
+	//PS AI,POE会员
+	List<Long> DOWN_GOODS_PAY = List.of(33l, 35l);
+
 	/**
 	 * 人民币符号
 	 */
 	String CN_CYS = "¥";
+
+	String DY_CS_CODE_KEY = "抖音免费设备";
+
+	List<String> DY_CUS = List.of("QiuDaoYuBuGuoQi.", "YinHeLuXiangJuSheBeiShouQian");
+
+	/**
+	 * 渠道分销规则key
+	 */
+	String DISTRIBUTE_RULE_KEY = "distribute_rule_key";
+
+	String ZERO_STR = "0";
+
+	String ONE_STR = "1";
+
+	/**
+	 * 渠道规格过滤平台key
+	 */
+	String DISTRIBUTE_RULE_FILTER_GOODS_KEY = "distribute_rule_filter_goods_key";
 }

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

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

+ 4 - 0
netflix-dao/src/main/java/com/cyksj/mapper/GoodsDonSkuMapper.java

@@ -13,4 +13,8 @@ import java.util.List;
 public interface GoodsDonSkuMapper  extends BaseMapper<GoodsDonSku> {
 
 	List<Long> selectAIMonthSkuIds(@Param("list") List<Long> goodsIds);
+
+	List<Long> getSpecificSkuIdsByGoodsIds(@Param("list") List<Long> aiGoodsIds, @Param("months") Integer months);
+
+	List<Long> getSpecificSkuIdsByGoodsId(@Param("goodsId") Long goodsId, @Param("num") Integer num, @Param("months") Integer months);
 }

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

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.GroupsRelationCustomerServiceFollowRecord;
+
+/*
+ *项目名: netflix
+ *文件名: GroupsRelationCustomerServiceFollowRecordMapper
+ *创建者: JavaZou
+ *创建时间:2023/9/5 11:37
+ */
+public interface GroupsRelationCustomerServiceFollowRecordMapper extends BaseMapper<GroupsRelationCustomerServiceFollowRecord> {
+}

+ 14 - 0
netflix-dao/src/main/java/com/cyksj/mapper/GroupsRelationExpiryRecordMapper.java

@@ -0,0 +1,14 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.GroupsRelationExpiryRecord;
+
+/*
+ *项目名: netflix-job
+ *文件名: GroupsRelationExpiryRecordMapper
+ *创建者: JavaZou
+ *创建时间:2023/9/4 17:07
+ */
+public interface GroupsRelationExpiryRecordMapper extends BaseMapper<GroupsRelationExpiryRecord> {
+
+}

+ 2 - 0
netflix-dao/src/main/java/com/cyksj/mapper/GroupsRelationMapper.java

@@ -51,4 +51,6 @@ public interface GroupsRelationMapper extends BaseMapper<GroupsRelation> {
 	List<Long> getTicketGoodsId(@Param("list") List<Long> userIds, @Param("status") List<String> status);
 
 	Page<UserRecommendGoodsFrontView> getRecommendGoodsViews(@Param("page") Page<UserRecommendGoodsFrontView> page, @Param("list") List<Long> filter_goods_id, @Param("isPayNf") Boolean isPayNf);
+
+	Long getOutSideGroupsTripsRelationByGoodsId(@Param("skuId") Long skuId, @Param("beginOfDay") DateTime beginOfDay, @Param("extraNum") Integer extraNum, @Param("userId") Long userId);
 }

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/mapper/OrderDonMapper.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.cyksj.model.entity.OrderDon;
 import com.cyksj.model.entity.RealGoodsInterestUser;
 import com.cyksj.model.excel.ExcelOrderDonInfo;
+import com.cyksj.model.views.BackgroundDataView;
 import com.cyksj.model.views.BrokenLineObjView;
 import com.cyksj.model.views.ChannelPopularizeView;
 import com.cyksj.model.views.ChannelStatisticsView;
@@ -47,4 +48,8 @@ public interface OrderDonMapper extends BaseMapper<OrderDon> {
 	BigDecimal selectThisMonthDistributeOrderMoney(@Param("skuIds") Set<Long> skuIds, @Param("startDate") String startDate, @Param("endDate") String endDate);
 
 	Map<String, Object> getOrderDetailByGoodsType(@Param("type") Integer type, @Param("noOrderStatus") List<String> noOrderStatus, @Param("startDate") Date startDate, @Param("endDate") Date endDate);
+
+	BackgroundDataView getBackgroundDataView(@Param("startDate") Date startDate, @Param("endDate") Date endDate, @Param("noOrderStatus") List<String> noOrderStatus);
+
+	BigDecimal statisticsUsedBalance(@Param("startDate") Date startDate, @Param("endDate") Date endDate, @Param("noOrderAllStatus") List<String> noOrderAllStatus);
 }

+ 3 - 0
netflix-dao/src/main/java/com/cyksj/mapper/UserMapper.java

@@ -50,4 +50,7 @@ public interface UserMapper extends BaseMapper<User> {
 
     @Select("select id from user where show_id = #{showId} limit 1")
     Long getUserIdByShowId(String showId);
+
+    @Select("select cast(ifnull(sum(balance),0)/100 as decimal(11,2)) from user")
+	BigDecimal statisticsRemainBalance();
 }

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

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.UserPhoneSendRecord;
+
+/*
+ *项目名: netflix
+ *文件名: UserPhoneSendRecordMapper
+ *创建者: JavaZou
+ *创建时间:2023/9/7 15:12
+ */
+public interface UserPhoneSendRecordMapper extends BaseMapper<UserPhoneSendRecord> {
+}

+ 6 - 0
netflix-dao/src/main/java/com/cyksj/mapper/manage/coupon/CouponDistributePopularizeMapper.java

@@ -1,7 +1,10 @@
 package com.cyksj.mapper.manage.coupon;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.Coupon;
 import com.cyksj.model.entity.CouponDistributePopularize;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
 
 /*
@@ -13,4 +16,7 @@ import org.apache.ibatis.annotations.Update;
 public interface CouponDistributePopularizeMapper extends BaseMapper<CouponDistributePopularize> {
 	@Update("update coupon_distribute_popularize set deleted = false where coupon_id = #{id}")
 	void deleteByCouponId(Long id);
+
+	@Select("select distinct c.* from (select * from coupon_distribute_popularize where distribute_id = #{distributeId} and deleted is true) cp inner join coupon c on c.id = cp.coupon_id and type = 'discount' inner join coupon_sku cs on cs.coupon_id = c.id and cs.sku_id = #{skuId} order by c.discount desc limit 1")
+	Coupon selectDiscountCouponByUserId(@Param("distributeId") Long distributeId, @Param("skuId") Long skuId);
 }

+ 2 - 0
netflix-dao/src/main/java/com/cyksj/mapper/manage/coupon/CouponUserMapper.java

@@ -27,4 +27,6 @@ public interface CouponUserMapper extends BaseMapper<CouponUser> {
 	Page<CouponUserView> couponPersonalList(@Param("userId") Long userId, @Param("page") Page<CouponUserView> page, @Param("couponId") Long couponId);
 
 	CouponUserView getNewUserWelfareCouponsByUserId(@Param("userId") long userId, @Param("channel") CouponUser.Channel channel, @Param("now") DateTime now);
+
+	CouponUser getCouponByCouponUserId(Long couponUserId);
 }

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/manage/distribute/UserDistributeRuleOrderRecordMapper.java

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

+ 2 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CorpFollowConfig.java

@@ -23,4 +23,6 @@ public class CorpFollowConfig extends BaseEntity{
 	private String configId;
 
 	private String qrCode;
+
+	private String remark;
 }

+ 6 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CouponUser.java

@@ -3,6 +3,7 @@ package com.cyksj.model.entity;
 import lombok.Getter;
 import lombok.Setter;
 
+import java.math.BigDecimal;
 import java.util.Date;
 
 /*
@@ -41,6 +42,11 @@ public class CouponUser extends BaseEntity {
 	 */
 	private Channel channel;
 
+	/**
+	 * 折扣卷折扣 用于分销
+	 */
+	private BigDecimal discount;
+
 	/**
 	 * 优惠券使用状态
 	 */

+ 11 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/DistributeWaitingSendPoints.java

@@ -46,6 +46,17 @@ public class DistributeWaitingSendPoints extends BaseEntity{
 	 */
 	private Boolean isDelivery;
 
+	/**
+	 * 分销提成平摊折扣金额
+	 * 是否参与渠道分销规则
+	 */
+	private Boolean isRule;
+
+	/**
+	 * 获取提成比例
+	 */
+	private Integer rate;
+
 	@Getter
 	public enum Status{
 		close("分销订单关闭,积分奖励不分发"),

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

@@ -139,7 +139,7 @@ public class GoodsDonSku extends BaseEntity {
      */
     @DbIgnore
     @TableField(exist = false)
-    private List<GoodsDiscountPlusPurchaseRelationFrontView> dpSkuViews;
+    private List<GoodsDiscountPlusPurchaseRelationFrontView> dpSkuList;
 
     /**
      * 前端展示

+ 25 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GroupsRelationCustomerServiceFollowRecord.java

@@ -0,0 +1,25 @@
+package com.cyksj.model.entity;
+
+import com.cyksj.model.BaseEntity;
+import lombok.Getter;
+import lombok.Setter;
+
+/*
+ *项目名: netflix-job
+ *文件名: GroupsRelationCustomerServiceFollowRecord
+ *创建者: JavaZou
+ *创建时间:2023/9/4 17:08
+ */
+@Getter
+@Setter
+public class GroupsRelationCustomerServiceFollowRecord extends BaseEntity {
+	/**
+	 * group_relation_expiry_record
+	 * 用户车票跟进记录id
+	 */
+	private Long ecId;
+
+	private String content;
+
+	private String imgs;
+}

+ 92 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GroupsRelationExpiryRecord.java

@@ -0,0 +1,92 @@
+package com.cyksj.model.entity;
+
+import com.cyksj.model.BaseEntity;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/*
+ *项目名: netflix-job
+ *文件名: GroupsRelationExpiryRecord
+ *创建者: JavaZou
+ *创建时间:2023/9/4 16:48
+ */
+@Getter
+@Setter
+@SearchBean(tables = "groups_relation_expiry_record",
+		where = "account_status in (0,1,2,3,7)")
+public class GroupsRelationExpiryRecord extends BaseEntity {
+	private Long userId;
+
+	private String nickname;
+
+	/**
+	 * 注册方式
+	 */
+	private String registerEnv;
+
+	private String register;
+
+	/**
+	 * 联系方式
+	 */
+	private String contact;
+
+	/**
+	 * 是否加入了企业微信
+	 */
+	private Boolean isJoinCorpWx;
+
+	private Long goodsId;
+
+	private String goodsTitle;
+
+	private Long relationId;
+
+	private Date startTime;
+
+	private Date expiryTime;
+
+	private Long skuId;
+
+	private String specVal;
+
+	private Boolean isReBuy;
+
+	private Long reBuyOrderId;
+
+	private Date reBuyTime;
+
+	private Long reBuyGoodsId;
+
+	private String reBuyGoodsTitle;
+
+	private Long reBuySkuId;
+
+	private String reBuySpecVal;
+
+	/**
+	 * 分配时间
+	 */
+	private Date assignTime;
+
+	private Long customerServiceId;
+
+	/**
+	 * 分配客服
+	 */
+	private String customerService;
+
+	/**
+	 * 是否跟进
+	 */
+	private Boolean isFollow;
+
+	/**
+	 * 到期状态
+	 * 0已到期
+	 */
+	private Integer accountStatus;
+}

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/OrderDiscountPlusPurchaseSkuRelation.java

@@ -22,4 +22,9 @@ public class OrderDiscountPlusPurchaseSkuRelation extends BaseEntity{
 	private String plusSkuIds;
 
 	private String relationIds;
+
+	/**
+	 * 额外订单ids
+	 */
+	private String plusOrderIds;
 }

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

@@ -234,6 +234,11 @@ public class OrderDon extends BaseEntity implements Serializable {
 
     private String payTitle;
 
+    /**
+     * 是否是额外硬塞车票车位的订单
+     */
+    private Boolean isOt;
+
     /**
      * 礼品卡现金使用记录
      */

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/User.java

@@ -91,6 +91,11 @@ public class User extends BaseEntity implements Serializable{
     @TableField(exist = false)
     private Long phoneUserId;
 
+    /**
+     * 是否是谷歌授权登录
+     */
+    private Boolean isGoogle;
+
     @Getter
     public enum RegisterEnv{
         wx("公众号h5授权登录"),

+ 1 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/UserBalanceSourceRecord.java

@@ -30,6 +30,7 @@ public class UserBalanceSourceRecord extends BaseEntity{
 		ds_transport("分销实物发货"),
 		follow_task("关注引导"),
 		rd_comment("实物评论"),
+		price_differ("订单补差价")
 		;
 		String desc;
 

+ 25 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/UserDistributeRuleOrderRecord.java

@@ -0,0 +1,25 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: UserDistributeRuleOrderRecord
+ * 创建者: JavaZou
+ * 创建时间:2023/9/25 14:19
+ */
+@Getter
+@Setter
+public class UserDistributeRuleOrderRecord extends BaseEntity{
+	private Date endTime;
+
+	private Date startTime;
+
+	/**
+	 * 时长
+	 */
+	private String duration;
+}

+ 7 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/UserDistributeShared.java

@@ -31,4 +31,11 @@ public class UserDistributeShared extends BaseEntity{
 	 * cps后台自定义推广链接id
 	 */
 	private Long dsPopularizeId;
+
+	/**
+	 * 新渠道上下级规则:
+	 * 在原规则基础上加上用户需在在45天内下单成功之后才算真绑定,享受后续所有订单返利
+	 * 超过45天 未下单 不参与后续提成
+	 */
+	private Boolean isBind;
 }

+ 18 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/UserPhoneSendRecord.java

@@ -0,0 +1,18 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/*
+ *项目名: netflix
+ *文件名: UserPhoneSendRecord
+ *创建者: JavaZou
+ *创建时间:2023/9/7 15:12
+ */
+@Getter
+@Setter
+public class UserPhoneSendRecord extends BaseEntity{
+	private Long orderUserId;
+
+	private String phone;
+}

+ 129 - 0
netflix-dao/src/main/java/com/cyksj/model/excel/ExcelGroupRelationData.java

@@ -0,0 +1,129 @@
+package com.cyksj.model.excel;
+
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.cyksj.model.entity.GroupsTrips;
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.DbIgnore;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/*
+ *项目名: yhlxj
+ *文件名: ExcelGroupRelationData
+ *创建者: JavaZou
+ *创建时间:2023/9/12 18:01
+ */
+@Getter
+@Setter
+@SearchBean(tables = "groups_trips gt left join goods_don_sku sku on gt.sku_id = sku.id " +
+		"left join goods_don g on g.id = sku.goods_id " +
+		"left join account a on a.id = gt.account_id ")
+public class ExcelGroupRelationData {
+
+	@DbField("gt.id")
+	@ExcelIgnore
+	private Long groupId;
+
+	/**
+	 * 商品skuId
+	 */
+	@DbField("gt.sku_id")
+	@ExcelIgnore
+	private Long skuId;
+
+	/**
+	 * 账号id
+	 */
+	@DbField("gt.account_id")
+	@ExcelIgnore
+	private Long accountId;
+
+	/**
+	 * 账号
+	 */
+	@DbField("a.account")
+	@ExcelProperty("账号")
+	private String account;
+
+	/**
+	 * 密码
+	 */
+	@DbField("a.password")
+	@ExcelProperty("密码")
+	private String password;
+
+	/**
+	 * 商品id
+	 */
+	@DbField("g.id")
+	@ExcelIgnore
+	private Long goodsId;
+
+	/**
+	 * 标题
+	 */
+	@DbField("g.title")
+	@ExcelProperty("平台")
+	private String title;
+
+	/**
+	 * 商品规格
+	 */
+	@DbField("sku.spec_val")
+	@ExcelProperty("规格")
+	private String specVal;
+
+	/**
+	 * 车位数量
+	 */
+	@DbField("gt.num")
+	@ExcelProperty("车位数量")
+	private Integer num;
+
+	/**
+	 * 可用车位数
+	 */
+	@DbField("gt.available_num")
+	@ExcelProperty("剩余车位")
+	private Integer availableNum;
+
+	/**
+	 * 状态
+	 */
+	@DbField("gt.status")
+	@ExcelIgnore
+	private GroupsTrips.Status status;
+
+	/**
+	 * 状态
+	 */
+	@DbIgnore
+	@ExcelProperty("状态")
+	private String cnStatus;
+
+	@DbField("a.expiry_time")
+	@ExcelProperty("过期时间")
+	private Date expiryTime;
+
+	/**
+	 * 创建时间
+	 */
+	@DbField("gt.created_time")
+	@ExcelProperty("创建时间")
+	private Date createdTime;
+
+	/**
+	 * 更新时间
+	 */
+	@DbField("gt.update_time")
+	@ExcelIgnore
+	private Date updateTime;
+
+	public String getCnStatus() {
+		return status.getDesc();
+	}
+}

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

@@ -37,6 +37,12 @@ public class OrderDonBackView {
 	@DbField("o.relation_id")
 	private Long relationId;
 
+	/**
+	 * 是否是额外硬塞的虚拟车票订单
+	 */
+	@DbField("o.is_ot")
+	private Boolean isOt;
+
 	/**
 	 * 邀请制用户账号
 	 */
@@ -94,6 +100,9 @@ public class OrderDonBackView {
 	@DbField("u.email")
 	private String email;
 
+	@DbField("u.is_google")
+	private Boolean isGoogle;
+
 	@DbField("o.money")
 	private BigDecimal money;
 

+ 3 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/views/UserView.java

@@ -184,4 +184,7 @@ public class UserView {
      */
     @DbField("u.update_time")
     private Date updateTime;
+
+    @DbField("u.is_google")
+    private Boolean isGoogle;
 }

+ 4 - 0
netflix-dao/src/main/java/com/cyksj/model/request/LoginReq.java

@@ -2,6 +2,7 @@ package com.cyksj.model.request;
 
 import lombok.Getter;
 import lombok.Setter;
+import lombok.ToString;
 
 /*
  *项目名: netflix
@@ -11,6 +12,7 @@ import lombok.Setter;
  */
 @Getter
 @Setter
+@ToString
 public class LoginReq {
 	private String phone;
 
@@ -59,4 +61,6 @@ public class LoginReq {
 	private String callback;
 
 	private String callbackType;
+
+	private String subject;
 }

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/request/OrderRefundReq.java

@@ -34,4 +34,9 @@ public class OrderRefundReq {
 	 * 订单金额、余额
 	 */
 	private String refundType;
+
+	/**
+	 * 补差价余额
+	 */
+	private BigDecimal refundBalance;
 }

+ 9 - 0
netflix-dao/src/main/java/com/cyksj/model/request/corp/CorpFollowContact.java

@@ -22,16 +22,25 @@ public class CorpFollowContact {
 	 */
 	private Integer scene;
 
+	/**
+	 * 在小程序中联系时使用的控件样式,详见附表
+	 */
 	private Integer style;
 
 	private String remark;
 
+	/**
+	 * 外部客户添加时是否无需验证,默认为true
+	 */
 	private boolean skip_verify;
 
 	private String state;
 
 	private List<String> user;
 
+	/**
+	 * 使用该联系方式的部门id列表,只在type为2时有效
+	 */
 	private List<Integer> party;
 
 	private boolean is_temp;

+ 14 - 0
netflix-dao/src/main/java/com/cyksj/model/response/GoogleLoginRep.java

@@ -0,0 +1,14 @@
+package com.cyksj.model.response;
+
+import lombok.Data;
+
+/**
+ * @author zwhui
+ * @date 2023/8/22 15:45
+ */
+@Data
+public class GoogleLoginRep {
+    private String email;
+
+    private String subject;
+}

+ 63 - 0
netflix-dao/src/main/java/com/cyksj/model/views/AccountSpecificView.java

@@ -0,0 +1,63 @@
+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.util.Date;
+
+/*
+ *项目名: yhlxj
+ *文件名: AccountSpecificView
+ *创建者: JavaZou
+ *创建时间:2023/9/21 15:03
+ */
+@Getter
+@Setter
+@SearchBean(tables = "account a inner join groups_trips gt on gt.account_id = a.id :condition:" +
+		" left join goods_don g on g.id = a.goods_id" +
+		" left join goods_don_sku sku on sku.id = gt.sku_id")
+public class AccountSpecificView {
+	@DbField("a.id")
+	private Long id;
+
+	@DbField("a.account")
+	private String account;
+
+	@DbField("a.password")
+	private String password;
+
+	@DbField("a.start_time")
+	private Date startTime;
+
+	@DbField("a.expiry_time")
+	private Date expiryTime;
+
+	@DbField("a.goods_id")
+	private Long goodsId;
+
+	@DbField("gt.sku_id")
+	private Long skuId;
+
+	@DbField("g.title")
+	private String title;
+
+	@DbField("sku.spec_val")
+	private String specVal;
+
+	@DbField("gt.num")
+	private Integer num;
+
+	@DbField("gt.available_num")
+	private Integer availableNum;
+
+	@DbField("a.remark")
+	private String remark;
+
+	@DbField("a.created_time")
+	private Date createdTime;
+
+	@DbField("a.update_time")
+	private Date updateTime;
+}

+ 10 - 0
netflix-dao/src/main/java/com/cyksj/model/views/BackgroundDataView.java

@@ -183,4 +183,14 @@ public class BackgroundDataView {
 	 */
 	private Integer waitingSendRealOrder;
 
+	/**
+	 * 已使用余额
+	 */
+	private BigDecimal usedBalance;
+
+	/**
+	 * 剩余余额
+	 */
+	private BigDecimal remainBalance;
+
 }

+ 3 - 0
netflix-dao/src/main/java/com/cyksj/model/views/DistributeOrdersDetailView.java

@@ -45,6 +45,9 @@ public class DistributeOrdersDetailView {
 	@DbField("dp.points")
 	private BigDecimal points;
 
+	@DbField("dp.is_rule")
+	private Boolean isRule;
+
 	@DbField("dp.send_status")
 	private DistributeWaitingSendPoints.Status sendStatus;
 }

+ 25 - 0
netflix-dao/src/main/java/com/cyksj/model/views/DistributeWaitingOrderPointsRuleView.java

@@ -0,0 +1,25 @@
+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;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: DistributeWaitingOrderPointsRuleView
+ * 创建者: JavaZou
+ * 创建时间:2023/9/25 14:29
+ */
+@Getter
+@Setter
+@SearchBean(tables = "(select * from distribute_waiting_send_points :condition:) dp inner join order_don o on o.id = dp.order_id and o.status not in ('close','noPayment')")
+public class DistributeWaitingOrderPointsRuleView {
+	@DbField("count(dp.order_id)")
+	private Integer numOfOrder;
+
+	@DbField("sum(o.money) - sum(ifnull(o.refund_money,0))")
+	private BigDecimal orderAmount;
+}

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

@@ -5,6 +5,7 @@ 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 com.fasterxml.jackson.annotation.JsonInclude;
 import lombok.Getter;
 import lombok.Setter;
 

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

@@ -3,7 +3,6 @@ package com.cyksj.model.views;
 import com.cyksj.model.entity.GoodsDon;
 import com.ejlchina.searcher.bean.DbIgnore;
 import com.ejlchina.searcher.bean.SearchBean;
-import com.fasterxml.jackson.annotation.JsonIgnore;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -58,7 +57,7 @@ public class GoodsDonViews {
      * 分类
      * 1、AI  2、流媒体
      */
-    private Long category;
+    private Integer category;
 
     /**
      * 二级分类
@@ -125,12 +124,6 @@ public class GoodsDonViews {
 
     private Boolean isSp;
 
-    @DbIgnore
-    private Integer sold;
-
-    @JsonIgnore
-    private Integer virtualSold;
-
     @DbIgnore
     private List<GoodsDonSkuFrontView> skuList;
 
@@ -138,15 +131,8 @@ public class GoodsDonViews {
     private GoodsDonSpecFrontView specs;
 
     @DbIgnore
-    private BigDecimal skuSpecificPrice;
-
-    @DbIgnore
-    private Long specificSkuId;
-
     private String giftCards;
 
     @DbIgnore
     private List<GoodsSkuGiftCardView> giftCardsView;
-
-    private BigDecimal giftCardCash;
 }

+ 6 - 0
netflix-dao/src/main/java/com/cyksj/model/views/UserDistributeOrdersDetailView.java

@@ -47,6 +47,12 @@ public class UserDistributeOrdersDetailView {
 	@DbField("if(send_status = 'success',TRUNCATE(dp.refund_points/1000,2),0)")
 	private BigDecimal rdMoney;
 
+	/**
+	 * 是否参与渠道分销规则
+	 */
+	@DbField("dp.is_rule")
+	private Boolean isRule;
+
 	@DbField("dp.send_status")
 	private String sendStatus;
 

+ 6 - 0
netflix-dao/src/main/java/com/cyksj/model/views/UserDistributePopularizeView.java

@@ -42,6 +42,12 @@ public class UserDistributePopularizeView {
 	@DbField("ifnull(cast(sum(if(dsp.id is NULL,0,money))/100 as decimal(11,2)),0)")
 	private BigDecimal ordersMoney;
 
+	@DbField("ifnull(cast(sum(if(dsp.send_status='waiting',dsp.points,0))/1000 as decimal(11,2)),0)")
+	private BigDecimal wMoney;
+
+	@DbField("ifnull(cast(sum(if(dsp.send_status='success',dsp.points,0))/1000 as decimal(11,2)),0)")
+	private BigDecimal gotMoney;
+
 	@DbField("dp.remark")
 	private String remark;
 

+ 34 - 0
netflix-dao/src/main/java/com/cyksj/model/views/UserDistributeRuleOrderRecordView.java

@@ -0,0 +1,34 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbIgnore;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: UserDistributeRuleOrderRecordView
+ * 创建者: JavaZou
+ * 创建时间:2023/9/25 14:20
+ */
+@Getter
+@Setter
+@SearchBean(tables = "user_distribute_rule_order_record ur")
+public class UserDistributeRuleOrderRecordView {
+	private Long id;
+
+	private Date endTime;
+
+	private Date startTime;
+
+	private String duration;
+
+	@DbIgnore
+	private Integer numOfOrder;
+
+	@DbIgnore
+	private BigDecimal orderAmount;
+}

+ 6 - 0
netflix-dao/src/main/resources/mapper/CouponUserMapper.xml

@@ -204,4 +204,10 @@
                  and status = 'unused' limit 1) cu
                  inner join coupon c on c.id = cu.coupon_id
     </select>
+
+    <select id="getCouponByCouponUserId" resultType="com.cyksj.model.entity.CouponUser">
+        select *
+        from coupon_user
+        where id = #{couponUserId} limit 1
+    </select>
 </mapper>

+ 16 - 0
netflix-dao/src/main/resources/mapper/GoodsDonSkuMapper.xml

@@ -9,4 +9,20 @@
         </foreach>
         and `months` = 1
     </select>
+
+    <select id="getSpecificSkuIdsByGoodsIds" resultType="java.lang.Long">
+        select id from goods_don_sku where goods_id in
+        <foreach collection="list" item="item" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+        and `months` = #{months}
+    </select>
+
+    <select id="getSpecificSkuIdsByGoodsId" resultType="java.lang.Long">
+        select id
+        from goods_don_sku
+        where goods_id = #{goodsId}
+          and num = #{num}
+          and `months` = #{months}
+    </select>
 </mapper>

+ 24 - 0
netflix-dao/src/main/resources/mapper/GroupRelationMapper.xml

@@ -211,4 +211,28 @@
         </if>
         and deleted is true and status is true) s order by s.sorted desc,sort_by desc
     </select>
+
+    <select id="getOutSideGroupsTripsRelationByGoodsId" resultType="java.lang.Long">
+        select gt.id
+        from `groups_trips` gt
+                 inner join account a on a.id = gt.account_id
+        where gt.sku_id = #{skuId}
+          and gt.status = 'validity'
+          and a.expiry_time >= #{beginOfDay}
+          and (select count(*)
+               from groups_relation gr
+               where gr.status = 'outside'
+                 and gr.groups_id = gt.id
+                 and gr.user_id
+            != 0)
+         &lt; #{extraNum}
+          and
+            (
+        select count(*)
+        from groups_relation gr
+        where gr.groups_id = gt.id
+          and gr.user_id
+            = #{userId}) = 0
+        order by RAND() limit 1
+    </select>
 </mapper>

+ 32 - 1
netflix-dao/src/main/resources/mapper/OrderDonMapper.xml

@@ -176,7 +176,7 @@
 
     <select id="getOrderDetailByGoodsType" resultType="java.util.Map">
         select count(id) as orderNum,
-               ifnull(sum(money),0) as money
+        ifnull(sum(money),0) as money
         from order_don where goods_id in (select id from `goods_don` where type = #{type})
         and status not in
         <foreach collection="noOrderStatus" item="item" open="(" separator="," close=")">
@@ -189,4 +189,35 @@
             and created_time &lt; #{endDate}
         </if>
     </select>
+
+    <select id="getBackgroundDataView" resultType="com.cyksj.model.views.BackgroundDataView">
+        select count(distinct user_id) as totalNumOfUser,
+        count(id) as totalNumOfOrder,
+        cast(ifnull(sum(money),0)/100 as decimal(11,2)) as totalOrderAmount,
+        count(if(status = 'refund',1,NULL)) as totalNumOfRefundOrder,
+        cast(sum(if(status = 'refund',ifnull(refund_money,0),0))/100 as decimal(11,2)) as totalRefundAmount
+        from `order_don` where status not in
+        <foreach collection="noOrderStatus" item="item" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+        <if test="startDate != null">
+            and created_time >= #{startDate}
+        </if>
+        <if test="endDate != null">
+            and created_time &lt; #{endDate}
+        </if>
+    </select>
+
+    <select id="statisticsUsedBalance" resultType="java.math.BigDecimal">
+        select cast(ifnull(sum(balance),0)/100 as decimal(11,2)) from order_don where status not in
+        <foreach collection="noOrderAllStatus" item="item" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+        <if test="startDate != null">
+            and created_time >= #{startDate}
+        </if>
+        <if test="endDate != null">
+            and created_time &lt; #{endDate}
+        </if>
+    </select>
 </mapper>

+ 1 - 1
netflix-dao/src/main/resources/mapper/UserDistributeMapper.xml

@@ -90,7 +90,7 @@
     <select id="getDistributeGoodsRateByUidAndGid" resultType="java.lang.Integer">
         select udr.rate
         from (select shared_id from user_distribute_shared where user_id = #{userId} limit 1) us
-                 inner join user_distribute ud on ud.user_id = us.shared_id
+                 inner join user_distribute ud on ud.user_id = us.shared_id and ud.deleted is true
                  inner join user_plat_distribute_rate udr
                             on udr.distribute_id = ud.id
         where udr.goods_id = #{goodsId}

+ 6 - 2
netflix-dao/src/main/resources/mapper/UserDistributePopularizeMapper.xml

@@ -3,8 +3,12 @@
 <mapper namespace="com.cyksj.mapper.manage.cps.UserDistributePopularizeMapper">
 
     <select id="getDefaultPopularizeDetail" resultType="com.cyksj.model.views.UserDistributePopularizeView">
-        select count(od.id) orders,
-               ifnull(cast(sum(money)/100 as decimal(11,2)),0) ordersMoney
+        select count(od.id)                                        orders,
+               ifnull(cast(sum(money) / 100 as decimal(11, 2)), 0) ordersMoney,
+               ifnull(cast(sum(if(dp.send_status = 'waiting', dp.points, 0)) / 1000 as decimal(11, 2)), 0)
+                   as                                              wMoney,
+               ifnull(cast(sum(if(dp.send_status = 'success', dp.points, 0)) / 1000 as decimal(11, 2)), 0)
+                   as                                              gotMoney
         from (select user_id from user_distribute_shared where shared_id = #{cpsUserId}) us
                  inner join order_don od
                             on od.user_id = us.user_id and od.status not in ('close', 'noPayment') and

+ 1 - 15
netflix-service/src/main/java/com/cyksj/redis/RedisService.java

@@ -3,11 +3,9 @@ package com.cyksj.redis;
 import com.cyksj.common.util.StringUtil;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 
-import javax.annotation.PostConstruct;
 import javax.annotation.Resource;
 import java.util.Arrays;
 import java.util.List;
@@ -28,16 +26,6 @@ public class RedisService {
     @Resource
     private RedisTemplate<String, Object> redisTemplate;
 
-    public static String env = "dev";
-
-    @Value("${spring.profiles.active}")
-    private String active;
-
-    @PostConstruct
-    public void init(){
-        env = active + ":";
-    }
-
     /**
      * 指定缓存失效时间
      *
@@ -648,6 +636,7 @@ public class RedisService {
         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),
+        DISTRIBUTE_RULE_TIME_KEY("DISTRIBUTE_RULE_TIME_KEY", "渠道规格记录时间key", 5 * 60L),
         ;
 
         private String name;
@@ -656,9 +645,6 @@ public class RedisService {
 
         private long timeout;
 
-        public String getEnvName() {
-            return this.name + env;
-        }
 
         public String getNameFormat(Object ... str) {
             return String.format(this.getName(), str);

+ 127 - 48
netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpEventActionServiceImpl.java

@@ -1,6 +1,7 @@
 package com.cyksj.service.corp.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;
@@ -19,10 +20,11 @@ import com.cyksj.model.entity.*;
 import com.cyksj.model.request.corp.Attachments;
 import com.cyksj.model.request.corp.CorpXmlMessage;
 import com.cyksj.model.request.corp.CorpXmlOutMessage;
-import com.cyksj.model.response.corp.CorpExternalContactInfo;
-import com.cyksj.model.response.corp.CorpUserExternalTagGroupList;
 import com.cyksj.model.response.ExternalContact;
 import com.cyksj.model.response.FollowedUser;
+import com.cyksj.model.response.corp.CorpExternalContactInfo;
+import com.cyksj.model.response.corp.CorpUserExternalTagGroupInfo;
+import com.cyksj.model.response.corp.CorpUserExternalTagGroupList;
 import com.cyksj.service.corp.WxCorpOps;
 import com.cyksj.service.corp.msg.CorpEventActionService;
 import com.cyksj.service.mange.coupon.CouponCommonService;
@@ -101,60 +103,41 @@ public class CorpEventActionServiceImpl implements CorpEventActionService {
 		if (corpUserInfo == null) {
 			return null;
 		}
-		//查询客户是否存在
-		CorpUser corpUser = Optional.ofNullable(
-				corpUserMapper.selectOne(Wrappers.lambdaQuery(CorpUser.class)
-						.eq(CorpUser::getUnionid, corpUserInfo.getUnionId())))
-				.orElseGet(() -> new CorpUser()
-						.setUnionid(corpUserInfo.getUnionId()));
 
-		corpUser.setName(corpUserInfo.getName());
-		corpUser.setGender(corpUserInfo.getGender());
-		corpUser.setAvatar(corpUserInfo.getAvatar());
-		corpUser.setType(corpUserInfo.getType());
-		//扫码来源
-		corpUser.setState(state);
 
-		//新增修改客户信息
-		if (corpUser.getId() == null) {
-			//查询是否已微信授权,关联user表id
-			User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class).eq(User::getUnionid, corpUser.getUnionid()));
-			if (user != null) {
-				corpUser.setUserId(user.getId());
-				//加入企业微信后发放优惠券
-				groupRelationFrontService.isJoinCorpWx(user.getId(), true, false);
-				//发放抽奖机会
-				sendSpecificChanceNum(user.getId());
-				//添加固定客服发放优惠券
-				isJoinFixedCustomer(user.getId(), userId);
+		THREAD_POOL.execute(()->{
+			//2.客户添加成员信息
+			List<FollowedUser> followedUsers = externalContact.getFollowedUsers();
+			//保存企微用户
+			CorpUser corpUser = saveOrUpdateCorpUser(message, corpUserInfo, followedUsers);
+			if (StrUtil.equals(message.getState(), Constant.DY_CS_CODE_KEY)) {
+				try {
+					followedUsers = wxCorpOps.getExternalContact(message.getToUserName(), message.getExternalUserId()).getFollowedUsers();
+				} catch (Exception e) {
+				}
+			}
+			CorpUserAuth corpUserAuth = corpUserAuthMapper.selectOne(Wrappers.lambdaQuery(CorpUserAuth.class).eq(CorpUserAuth::getExternalUserid, corpUserInfo.getExternalUserId()).eq(CorpUserAuth::getWxCorpId, wxCorpApp.getId()));
+			if (corpUserAuth == null) {
+				corpUserAuth = new CorpUserAuth();
+				corpUserAuth.setWxCorpId(wxCorpApp.getId());
+				corpUserAuth.setCorpUserId(corpUser.getId());
+				corpUserAuth.setExternalUserid(corpUserInfo.getExternalUserId());
+				corpUserAuthMapper.insert(corpUserAuth);
 			}
-			corpUserMapper.insert(corpUser);
-		} else {
-			corpUserMapper.updateById(corpUser);
-		}
 
-		CorpUserAuth corpUserAuth = corpUserAuthMapper.selectOne(Wrappers.lambdaQuery(CorpUserAuth.class).eq(CorpUserAuth::getExternalUserid, corpUserInfo.getExternalUserId()).eq(CorpUserAuth::getWxCorpId, wxCorpApp.getId()));
-		if (corpUserAuth == null) {
-			corpUserAuth = new CorpUserAuth();
-			corpUserAuth.setWxCorpId(wxCorpApp.getId());
-			corpUserAuth.setCorpUserId(corpUser.getId());
-			corpUserAuth.setExternalUserid(corpUserInfo.getExternalUserId());
-			corpUserAuthMapper.insert(corpUserAuth);
-		}
 
-		//2.客户添加成员信息
-		List<FollowedUser> followedUsers = externalContact.getFollowedUsers();
+			Set<String> relationFollowUserIds = relationMapper.selectList(Wrappers.lambdaQuery(CorpUserFollowRelation.class)
+					.select(CorpUserFollowRelation::getFollowId)
+					.eq(CorpUserFollowRelation::getWxCorpId, wxCorpApp.getCorpId())
+					.eq(CorpUserFollowRelation::getCorpUserId, corpUserInfo.getExternalUserId())).stream().map(CorpUserFollowRelation::getFollowId).collect(Collectors.toSet());
 
-		Set<String> relationFollowUserIds = relationMapper.selectList(Wrappers.lambdaQuery(CorpUserFollowRelation.class)
-				.select(CorpUserFollowRelation::getFollowId)
-				.eq(CorpUserFollowRelation::getWxCorpId, wxCorpApp.getCorpId())
-				.eq(CorpUserFollowRelation::getCorpUserId, corpUserInfo.getExternalUserId())).stream().map(CorpUserFollowRelation::getFollowId).collect(Collectors.toSet());
+			followedUsers.stream()
+					.filter((followedUser) -> !relationFollowUserIds.contains(followedUser.getUserId()))
+					.forEach(followedUser -> updateUserFollowRelation(followedUser, corpUserInfo.getExternalUserId(), wxCorpApp.getId()));
+		});
 
-		followedUsers.stream()
-				.filter((followedUser) -> !relationFollowUserIds.contains(followedUser.getUserId()))
-				.forEach(followedUser -> updateUserFollowRelation(followedUser, corpUserInfo.getExternalUserId(), wxCorpApp.getId()));
 		//发送自定义欢迎语
-		sendDesignWelcomeMsg(corpId, welcomeCode, userId, corpUserInfo.getCorpName());
+		//sendDesignWelcomeMsg(corpId, welcomeCode, userId, corpUserInfo.getCorpName());
 		return null;
 	}
 
@@ -225,6 +208,11 @@ public class CorpEventActionServiceImpl implements CorpEventActionService {
 		FollowedUser followedUser = followedUserMap.get(userId).get(0);
 		//修改客户关系
 		updateUserFollowRelation(followedUser, externalUserId, wxCorpApp.getId());
+
+		//保存企微用户
+		if (externalContact.getExternalContact() != null) {
+			saveOrUpdateCorpUser(message, externalContact.getExternalContact(), null);
+		}
 		return null;
 	}
 
@@ -421,4 +409,95 @@ public class CorpEventActionServiceImpl implements CorpEventActionService {
 			});
 		}
 	}
+
+
+	public CorpUser saveOrUpdateCorpUser(CorpXmlMessage message, ExternalContact corpUserInfo, List<FollowedUser> followedUsers) {
+		//查询客户是否存在
+		CorpUser corpUser = Optional.ofNullable(
+				corpUserMapper.selectOne(Wrappers.lambdaQuery(CorpUser.class)
+						.eq(CorpUser::getUnionid, corpUserInfo.getUnionId())))
+				.orElseGet(() -> new CorpUser()
+						.setUnionid(corpUserInfo.getUnionId()));
+
+		corpUser.setName(corpUserInfo.getName());
+		corpUser.setGender(corpUserInfo.getGender());
+		corpUser.setAvatar(corpUserInfo.getAvatar());
+		corpUser.setType(corpUserInfo.getType());
+		//扫码来源
+		corpUser.setState(message.getState());
+		//打标签
+		if (StrUtil.equals(message.getState(), Constant.DY_CS_CODE_KEY) && CollUtil.isNotEmpty(followedUsers)) {
+			//查询对应标签是否存在
+			CorpTag corpTag = corpTagMapper.selectOne(Wrappers.lambdaQuery(CorpTag.class)
+					.eq(CorpTag::getName, Constant.DY_CS_CODE_KEY).last("limit 1"));
+			if (corpTag == null) {
+				try {
+					corpTag = addCorpTag(Constant.DY_CS_CODE_KEY, Constant.DY_CS_CODE_KEY, message.getToUserName());
+				} catch (Exception e) {
+				}
+			}
+			if (corpTag != null) {
+				List<String> dy_tag = List.of(corpTag.getTagId());
+				followedUsers.forEach(follow -> {
+					if (!Constant.DY_CUS.contains(follow.getUserId())) {
+						return;
+					}
+					try {
+						wxCorpOps.markTag(corpUserInfo.getExternalUserId(), follow.getUserId(), dy_tag.toArray(new String[dy_tag.size()]), null);
+					} catch (Exception e) {
+					}
+				});
+			}
+		}
+
+		//新增修改客户信息
+		if (corpUser.getId() == null) {
+			//查询是否已微信授权,关联user表id
+			User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class).eq(User::getUnionid, corpUser.getUnionid()));
+			if (user != null) {
+				corpUser.setUserId(user.getId());
+				//加入企业微信后发放优惠券
+				groupRelationFrontService.isJoinCorpWx(user.getId(), true, false);
+				//发放抽奖机会
+				try {
+					sendSpecificChanceNum(user.getId());
+				} catch (Exception e) {
+				}
+				//添加固定客服发放优惠券
+				isJoinFixedCustomer(user.getId(), message.getUserId());
+			}
+			corpUserMapper.insert(corpUser);
+		} else {
+			corpUserMapper.updateById(corpUser);
+		}
+		return corpUser;
+	}
+
+
+	public CorpTag addCorpTag(String tagGroupName, String tagName, String corpId) throws Exception {
+		CorpUserExternalTagGroupInfo tagGroupInfoReq = new CorpUserExternalTagGroupInfo();
+		CorpUserExternalTagGroupInfo.TagGroup group = new CorpUserExternalTagGroupInfo.TagGroup();
+		CorpUserExternalTagGroupInfo.Tag tag = new CorpUserExternalTagGroupInfo.Tag();
+		tag.setName(tagName);
+		group.setTag(List.of(tag));
+		group.setGroupName(tagGroupName);
+		tagGroupInfoReq.setTagGroup(group);
+		CorpUserExternalTagGroupInfo corpUserExternalTagGroupInfo = wxCorpOps.addCorpTag(tagGroupInfoReq, corpId);
+		CorpUserExternalTagGroupInfo.TagGroup tagGroup = corpUserExternalTagGroupInfo.getTagGroup();
+		List<CorpUserExternalTagGroupInfo.Tag> tagList = tagGroup.getTag();
+		for (CorpUserExternalTagGroupInfo.Tag save_tag : tagList) {
+			if (StrUtil.equals(tagName, save_tag.getName())) {
+				CorpTag corpTag = new CorpTag();
+				corpTag.setGroupId(tagGroup.getGroupId());
+				corpTag.setGroupName(tagGroup.getGroupName());
+				corpTag.setType(1);
+
+				corpTag.setTagId(save_tag.getId());
+				corpTag.setName(save_tag.getName());
+				corpTagMapper.insert(corpTag);
+				return corpTag;
+			}
+		}
+		return null;
+	}
 }

+ 1 - 0
netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpFollowDynamicConfigServiceImpl.java

@@ -38,6 +38,7 @@ public class CorpFollowDynamicConfigServiceImpl implements CorpFollowDynamicConf
 			corpFollowConfig.setFollowId(followId);
 			corpFollowConfig.setQrCode(jsonObject.getStr("qr_code"));
 			corpFollowConfig.setConfigId(jsonObject.getStr("config_id"));
+			corpFollowConfig.setRemark(corpFollowContact.getRemark());
 			corpFollowConfigMapper.insert(corpFollowConfig);
 		});
 		return body;

+ 75 - 36
netflix-service/src/main/java/com/cyksj/service/exchange/impl/ExchangeCodeServiceImpl.java

@@ -17,7 +17,6 @@ import com.cyksj.dto.RedisKey;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
 import com.cyksj.mapper.*;
-import com.cyksj.mapper.channel.ChannelPopularizeMapper;
 import com.cyksj.mapper.manage.exchange.ExchangeCodeMapper;
 import com.cyksj.mapper.market.draw.LuckyDrawRecordMapper;
 import com.cyksj.model.entity.*;
@@ -28,7 +27,7 @@ import com.cyksj.model.request.ExchangeCodeTicket;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.exchange.ExchangeCodeService;
 import com.cyksj.service.relation.GroupRelationFrontService;
-import com.cyksj.service.template.TemplateCommonService;
+import com.cyksj.service.relation.GroupsRelationExpiryRecordService;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.util.MapUtils;
 import lombok.RequiredArgsConstructor;
@@ -71,22 +70,18 @@ public class ExchangeCodeServiceImpl extends ServiceImpl<ExchangeCodeMapper, Exc
 
 	private final OrderDonMapper orderDonMapper;
 
-	private static final GlobalThreadPoolTaskExecutor THREAD_POOL_TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance();
-
-	private final CustomerServiceMapper customerServiceMapper;
+	private static final GlobalThreadPoolTaskExecutor TASK_POOL = GlobalThreadPoolTaskExecutor.getInstance();
 
 	private final LuckyDrawRecordMapper luckyDrawRecordMapper;
 
-	private final TemplateCommonService templateCommonService;
-
 	private final BeanSearcher beanSearcher;
 
 	private final GroupRelationFrontService groupRelationFrontService;
 
-	private final ChannelPopularizeMapper channelPopularizeMapper;
-
 	private final OrderDiscountPlusPurchaseSkuRelationMapper orderDiscountPlusPurchaseSkuRelationMapper;
 
+	private final GroupsRelationExpiryRecordService groupsRelationExpiryRecordService;
+
 	@Override
 	@Transactional(rollbackFor = Throwable.class)
 	public List<ExcelExchangeCodeData> createExchangeCode(ExchangeCodeReq exchangeCodeReq) {
@@ -306,12 +301,25 @@ public class ExchangeCodeServiceImpl extends ServiceImpl<ExchangeCodeMapper, Exc
 			if (relation.getStartTime() == null || relation.getExpiryTime() == null) {
 				orderDon.setStatus(OrderDon.Status.hasPayment);
 			}
+			if (relation != null && relation.getStatus() == GroupsRelation.Status.outside) {
+				orderDon.setIsOt(true);
+			}
 			//兑换码兑换
 			orderDon.setType(orderDonTye);
 			orderDon.setUserId(user.getId());
+			StringBuilder payTitle = new StringBuilder();
+			payTitle.append(goodsDon.getTitle());
+			payTitle.append(sku.getSpecVal());
+			orderDon.setPayTitle(payTitle.toString());
 			orderDonMapper.insert(orderDon);
 			log.info("用户{}兑换规格:{}车位成功", user.getId(), orderDon.getSkuId());
 		}
+		if (orderDonTye == OrderDon.Type.EX_CODE) {
+			//同步车票是否重购 记录
+			TASK_POOL.execute(() -> {
+				groupsRelationExpiryRecordService.syncGroupsRelationExpiryRecord(orderDon, goodsDon, sku);
+			});
+		}
 //		if (StrUtil.isNotEmpty(user.getOpenId())) {
 //			//发送模板消息
 //			THREAD_POOL_TASK_EXECUTOR.execute(() -> {
@@ -360,19 +368,29 @@ public class ExchangeCodeServiceImpl extends ServiceImpl<ExchangeCodeMapper, Exc
 					.gt(GroupsTrips::getAvailableNum, 0).last("limit 1")
 					.eq(GroupsTrips::getStatus, GroupsTrips.Status.validity)
 					.orderByAsc(GroupsTrips::getAvailableNum));
-			//待发车
 			if (groups == null) {
-				groups = groupsMapper.selectOne(Wrappers.lambdaQuery(GroupsTrips.class)
-						.eq(GroupsTrips::getSkuId, sku.getId())
-						.gt(GroupsTrips::getAvailableNum, 0).last("limit 1")
-						.eq(GroupsTrips::getStatus, GroupsTrips.Status.waiting)
-						.orderByAsc(GroupsTrips::getAvailableNum));
+				//若是ChatGPT Plus 、MidJourney
+				//获取额外的车位
+				relation = getOutSideRelationIfAi(userId, groups, sku);
+				if (relation != null) {
+					groups = groupsMapper.selectById(relation.getGroupsId());
+				}
+				//待发车
+				if (relation == null) {
+					groups = groupsMapper.selectOne(Wrappers.lambdaQuery(GroupsTrips.class)
+							.eq(GroupsTrips::getSkuId, sku.getId())
+							.gt(GroupsTrips::getAvailableNum, 0).last("limit 1")
+							.eq(GroupsTrips::getStatus, GroupsTrips.Status.waiting)
+							.orderByAsc(GroupsTrips::getAvailableNum));
+				}
 			}
 			if (groups == null) {
 				//新增车位 并关联
 				relation = createNewGroupTripsAndRelation(sku, groups, relation);
 				log.info("无合适规格车队,新增新车队,获取车位relationId:{}", relation.getId());
-			} else {
+			}
+
+			if (relation == null) {
 				//寻找快满编车队进行占座
 				relation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
 						.eq(GroupsRelation::getGroupsId, groups.getId())
@@ -385,15 +403,14 @@ public class ExchangeCodeServiceImpl extends ServiceImpl<ExchangeCodeMapper, Exc
 				log.info("寻找快满编车队的车位relationId:{}", relation.getId());
 				//如果占位失败 新增车位并关联
 				if (relation == null) {
-					relation = createNewGroupTripsAndRelation(sku, groups, relation);
-					log.info("占位新车队车位失败,再次新增新车队,获取车位relationId:{}", relation.getId());
+					relation = getOutSideRelationIfAi(userId, groups, sku);
 				}
 			}
 		}
 
 		try {
 			//锁定座位
-			setRelation(relation.getId(), userId);
+			setRelation(relation.getId(), userId, relation.getGroupsId(), relation.getStatus());
 			relation.setUserId(userId);
 			GroupsTrips groupsTrips = groupsMapper.selectById(relation.getGroupsId());
 			if (GroupsTrips.Status.validity.equals(groupsTrips.getStatus())) {
@@ -408,19 +425,10 @@ public class ExchangeCodeServiceImpl extends ServiceImpl<ExchangeCodeMapper, Exc
 				relation.setExpiryTime(newDate);
 				relation.setStartTime(relation.getStartTime() == null ? new Date() : null);
 			}
-			relation.setStatus(GroupsRelation.Status.validity);
-			int isSuccess = groupsRelationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
-					.set(GroupsRelation::getUserId, userId)
-					.set(GroupsRelation::getStatus, GroupsRelation.Status.validity)
-					.set(GroupsRelation::getStartTime, relation.getStartTime())
-					.set(GroupsRelation::getExpiryTime, relation.getExpiryTime())
-					.eq(GroupsRelation::getId, relation.getId())
-					.eq(GroupsRelation::getUserId, 0)
-					.eq(GroupsRelation::getStatus, GroupsRelation.Status.none));
-			if (isSuccess != 1) {
-				log.error("该车位已被占,用户userId:{}更新上车relationId:{}状态失败", userId, relation.getId());
-				throw BusinessRuntimeException.getInstance("该车位已被占");
+			if (relation.getStatus() != GroupsRelation.Status.outside) {
+				relation.setStatus(GroupsRelation.Status.validity);
 			}
+			groupsRelationMapper.updateById(relation);
 			redisService.del(RedisKey.GROUPS_RELATION_NUM_KEY + relation.getId());
 		} catch (Exception e) {
 			Object value = redisService.get(RedisKey.GROUPS_RELATION_NUM_KEY + relation.getId());
@@ -438,7 +446,7 @@ public class ExchangeCodeServiceImpl extends ServiceImpl<ExchangeCodeMapper, Exc
 		return relation;
 	}
 
-	private void setRelation(Long relationId, Long userId) {
+	private void setRelation(Long relationId, Long userId, Long groupsId, GroupsRelation.Status status) {
 		if (redisService.get(RedisKey.GROUPS_RELATION_NUM_KEY + relationId) != null) {
 			log.info("=====>用户:{}获取了已有人座位:{}", userId, relationId);
 			throw new BusinessRuntimeException("客官手慢啦,该座位已经有人啦!");
@@ -447,11 +455,13 @@ public class ExchangeCodeServiceImpl extends ServiceImpl<ExchangeCodeMapper, Exc
 				log.info("=====>用户:{}未抢到座位:{}", userId, relationId);
 				throw new BusinessRuntimeException("客官手慢啦,该座位已经有人啦!");
 			}
-			GroupsRelation relation = groupsRelationMapper.selectById(relationId);
-			int count = groupsMapper.decrAvailableNum(relation.getGroupsId());
+			if (status == GroupsRelation.Status.outside) {
+				return;
+			}
+			int count = groupsMapper.decrAvailableNum(groupsId);
 			if (count == 0) {
-				log.error("车位异常 groupId:{}", relation.getGroupsId());
-				groupsMapper.updateAvailableNum(relation.getGroupsId());
+				log.error("车位异常 groupId:{}", groupsId);
+				groupsMapper.updateAvailableNum(groupsId);
 				throw new BusinessRuntimeException("车位异常");
 			}
 		}
@@ -502,4 +512,33 @@ public class ExchangeCodeServiceImpl extends ServiceImpl<ExchangeCodeMapper, Exc
 		}
 		return relation;
 	}
+
+	public GroupsRelation getOutSideRelationIfAi(Long userId, GroupsTrips groups, GoodsDonSku sku) {
+		//若是MidJourney、ChatGPT PLUS每个已满车队 硬塞5个座位
+		//主账号过期时间10天以外
+		GroupsRelation relation = null;
+		if (sku.getNum() > 1 && Constant.AI_goodsIds.contains(sku.getGoodsId())) {
+			DateTime tenExpiry = DateUtil.offsetDay(DateUtil.beginOfDay(DateTime.now()), 10);
+			Long groupsId = groupsRelationMapper.getOutSideGroupsTripsRelationByGoodsId(sku.getId(), tenExpiry, 5, userId);
+			if (groupsId != null) {
+				relation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
+						.eq(GroupsRelation::getGroupsId, groupsId)
+						.eq(GroupsRelation::getUserId, 0)
+						.eq(GroupsRelation::getStatus, GroupsRelation.Status.outside)
+						.last("limit 1"));
+				if (relation == null) {
+					if (!redisService.setNx(RedisService.key.GROUPS_TRIPS_OUTSIDE_RELATION.getName() + groupsId, groupsId, RedisService.key.GROUPS_TRIPS_OUTSIDE_RELATION.getTimeout())) {
+						relation = new GroupsRelation();
+						relation.setStatus(GroupsRelation.Status.outside);
+						relation.setUserId(userId);
+						relation.setGroupsId(groupsId);
+						GroupsRelation maxNumRelation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class).eq(GroupsRelation::getGroupsId, groupsId).orderByDesc(GroupsRelation::getNum).last("limit 1"));
+						relation.setNum(maxNumRelation.getNum() + 1);
+						groupsRelationMapper.insert(relation);
+					}
+				}
+			}
+		}
+		return relation;
+	}
 }

+ 1 - 3
netflix-service/src/main/java/com/cyksj/service/giftcard/impl/GiftCardGoodsSkuServiceImpl.java

@@ -88,8 +88,6 @@ public class GiftCardGoodsSkuServiceImpl extends ServiceImpl<GiftCardGoodsSkuMap
 			}
 		}
 		this.saveOrUpdate(data);
-		//设置对应礼品卡平台 最低价格
-		setGiftCardGoodsStat(goodsDon);
 	}
 
 	@Override
@@ -117,7 +115,7 @@ public class GiftCardGoodsSkuServiceImpl extends ServiceImpl<GiftCardGoodsSkuMap
 				.eq(GiftCardGoodsSku::getDeleted, true)
 				.orderByAsc(GiftCardGoodsSku::getPrice).last("limit 1"));
 		if (min != null) {
-			if (minPrice == null || minPrice.compareTo(min.getPrice()) > 0) {
+			if (minPrice == null || min.getPrice().compareTo(minPrice) != 0) {
 				goodsDon.setMinPrice(min.getPrice());
 				goodsDonMapper.updateById(goodsDon);
 				Set<String> keys = redisService.keys(RedisService.key.YH_HOME_PAGHE_CACHE.getName() + "*");

+ 6 - 0
netflix-service/src/main/java/com/cyksj/service/mange/CmsOrderDonService.java

@@ -47,4 +47,10 @@ public interface CmsOrderDonService extends IService<OrderDon> {
 	 * 退款记录
 	 */
 	void refundRecord(OrderDon orderDon, GoodsDon goodsDon, GoodsDonSku sku, String outRefundNo, String refundType);
+
+	/**
+	 *
+	 * @param orderRefundReq
+	 */
+	void refundPriceDiffer(OrderRefundReq orderRefundReq);
 }

+ 58 - 8
netflix-service/src/main/java/com/cyksj/service/mange/account/CmsAccountServiceImpl.java

@@ -227,7 +227,7 @@ public class CmsAccountServiceImpl extends ServiceImpl<AccountMapper, Account> i
 					Account insert = new Account();
 					insert.setAccount(account);
 					insert.setPassword(password);
-					if (part.length > 2) {
+					if (part.length > 2 && part.length < 9) {
 						//google36、辅助邮箱
 						//46 Google Bard
 						if (special_email_goods_ids.contains(goodsId)) {
@@ -240,15 +240,57 @@ public class CmsAccountServiceImpl extends ServiceImpl<AccountMapper, Account> i
 					}
 					insert.setGoodsId(goodsId);
 					if (goodsId.equals(31l)) {
-						insert.setSecret(Constant.AMERICA_APPID_SECRET);
+						if (part.length > 9) {
+							StringBuilder sb = new StringBuilder();
+							String country = part[part.length - 1];
+							if (country.contains("国")) {
+								sb.append(part[part.length - 1]);
+								sb.append(Constant.ONE_EMPTY);
+								sb.append(part[part.length - 2]);
+								sb.append(Constant.ONE_EMPTY);
+							}
+							for (int i = 2; i < part.length; i++) {
+								if (part[i].contains("朋友")) {
+									sb.append("朋友");
+									sb.append(Constant.ONE_EMPTY);
+									sb.append(part[i + 1]);
+									i++;
+								}
+								if (part[i].contains("工作")) {
+									sb.append("工作");
+									sb.append(Constant.ONE_EMPTY);
+									sb.append(part[i + 1]);
+									i++;
+								}
+								if (part[i].contains("父母")) {
+									sb.append("父母");
+									sb.append(Constant.ONE_EMPTY);
+									sb.append(part[i + 1]);
+									i++;
+								}
+							}
+							insert.setSecret(sb.toString());
+						} else {
+							insert.setSecret(Constant.AMERICA_APPID_SECRET);
+						}
 					}
 					this.save(insert);
-
-					//自动配置车队
-					GroupsTrips groupsTrips = new GroupsTrips();
-					groupsTrips.setSkuId(skuId);
-					groupsTrips.setAccountId(insert.getId());
-					cmsGroupService.issuance(groupsTrips, null);
+					//是否存在未发车的车队
+					GroupsTrips waiting = cmsGroupService.getOne(Wrappers.lambdaQuery(GroupsTrips.class)
+							.eq(GroupsTrips::getSkuId, skuId)
+							.eq(GroupsTrips::getStatus, GroupsTrips.Status.waiting).last("limit 1"));
+					if (waiting != null) {
+						waiting.setAccountId(insert.getId());
+						try {
+							cmsGroupService.setAccount(waiting);
+						} catch (Exception e) {
+							//自动配置车队
+							setGroupsTrips(skuId, insert.getId());
+						}
+					} else {
+						//自动配置车队
+						setGroupsTrips(skuId, insert.getId());
+					}
 				}
 			});
 		} catch (Exception e) {
@@ -256,4 +298,12 @@ public class CmsAccountServiceImpl extends ServiceImpl<AccountMapper, Account> i
 		}
 		redisService.del(cache);
 	}
+
+	public void setGroupsTrips(Long skuId, Long accountId) {
+		//自动配置车队
+		GroupsTrips groupsTrips = new GroupsTrips();
+		groupsTrips.setSkuId(skuId);
+		groupsTrips.setAccountId(accountId);
+		cmsGroupService.issuance(groupsTrips, null);
+	}
 }

+ 35 - 32
netflix-service/src/main/java/com/cyksj/service/mange/group/CmsGroupServiceImpl.java

@@ -119,38 +119,41 @@ public class CmsGroupServiceImpl extends ServiceImpl<GroupsMapper,GroupsTrips> i
         }
         Integer count = relationMapper.selectCount(Wrappers.lambdaQuery(GroupsRelation.class)
                 .eq(GroupsRelation::getGroupsId, groupId)
-                .in(GroupsRelation::getStatus, List.of(GroupsRelation.Status.locking, GroupsRelation.Status.validity)));
-        //可强制删除
-        //后台记录
+                .ne(GroupsRelation::getStatus, GroupsRelation.Status.none));
         if (count > 0) {
-            List<GroupsRelation> groupsRelations = relationMapper.selectList(Wrappers.lambdaQuery(GroupsRelation.class)
-                    .eq(GroupsRelation::getGroupsId, groupId)
-                    .in(GroupsRelation::getStatus, List.of(GroupsRelation.Status.locking, GroupsRelation.Status.validity)));
-            if (groupsRelations.size() > 0) {
-                Account account = accountMapper.selectById(groupsTrips.getAccountId());
-                TASK_EXECUTOR.execute(() -> {
-                    if (redisService.setNx(String.format("%s-%s", groupId, groupsTrips.getAccount()), groupId, 10l)) {
-                        groupsRelations.forEach(data -> {
-                            DelGroupsTripsRecord delGroupsTripsRecord = new DelGroupsTripsRecord();
-                            delGroupsTripsRecord.setGroupsId(groupId);
-                            delGroupsTripsRecord.setGroupsStatus(groupsTrips.getStatus().name());
-                            if (account != null) {
-                                delGroupsTripsRecord.setAccount(account.getAccount());
-                                delGroupsTripsRecord.setPassword(account.getPassword());
-                            }
-                            delGroupsTripsRecord.setRelationId(data.getId());
-                            delGroupsTripsRecord.setSkuId(groupsTrips.getSkuId());
-                            delGroupsTripsRecord.setUserId(data.getUserId());
-                            delGroupsTripsRecord.setStartTime(data.getStartTime());
-                            delGroupsTripsRecord.setExpiryTime(data.getExpiryTime());
-                            delGroupsTripsRecord.setRelationStatus(data.getStatus().name());
-                            delGroupsTripsRecord.setType("delete");
-                            delGroupsTripsRecordMapper.insert(delGroupsTripsRecord);
-                        });
-                    }
-                });
-            }
+            throw BusinessRuntimeException.getInstance("请移除该车队下的用户再进行删掉操作");
         }
+        //可强制删除
+        //后台记录
+//        if (count > 0) {
+//            List<GroupsRelation> groupsRelations = relationMapper.selectList(Wrappers.lambdaQuery(GroupsRelation.class)
+//                    .eq(GroupsRelation::getGroupsId, groupId)
+//                    .ne(GroupsRelation::getStatus, GroupsRelation.Status.none));
+//            if (groupsRelations.size() > 0) {
+//                Account account = accountMapper.selectById(groupsTrips.getAccountId());
+//                TASK_EXECUTOR.execute(() -> {
+//                    if (redisService.setNx(String.format("%s-%s", groupId, groupsTrips.getAccount()), groupId, 10l)) {
+//                        groupsRelations.forEach(data -> {
+//                            DelGroupsTripsRecord delGroupsTripsRecord = new DelGroupsTripsRecord();
+//                            delGroupsTripsRecord.setGroupsId(groupId);
+//                            delGroupsTripsRecord.setGroupsStatus(groupsTrips.getStatus().name());
+//                            if (account != null) {
+//                                delGroupsTripsRecord.setAccount(account.getAccount());
+//                                delGroupsTripsRecord.setPassword(account.getPassword());
+//                            }
+//                            delGroupsTripsRecord.setRelationId(data.getId());
+//                            delGroupsTripsRecord.setSkuId(groupsTrips.getSkuId());
+//                            delGroupsTripsRecord.setUserId(data.getUserId());
+//                            delGroupsTripsRecord.setStartTime(data.getStartTime());
+//                            delGroupsTripsRecord.setExpiryTime(data.getExpiryTime());
+//                            delGroupsTripsRecord.setRelationStatus(data.getStatus().name());
+//                            delGroupsTripsRecord.setType("delete");
+//                            delGroupsTripsRecordMapper.insert(delGroupsTripsRecord);
+//                        });
+//                    }
+//                });
+//            }
+//        }
         relationMapper.delete(Wrappers.lambdaQuery(GroupsRelation.class).eq(GroupsRelation::getGroupsId,groupId));
         this.removeById(groupId);
     }
@@ -237,8 +240,8 @@ public class CmsGroupServiceImpl extends ServiceImpl<GroupsMapper,GroupsTrips> i
         }
        groupsTrips.setStatus(GroupsTrips.Status.validity);
         GoodsDonSku sku = skuMapper.selectById(groupsTrips.getSkuId());
-        //下架上过车的POE 账号
-        if (sku.getGoodsId().equals(35l)) {
+        //下架上过车的POE,PS AI账号
+        if (Constant.DOWN_GOODS_PAY.contains(sku.getGoodsId())) {
             Number number = beanSearcher.searchCount(GroupsRelation.class, MapUtils.builder()
                     .field(GroupsRelation::getGroupsId, groupsTrips.getId())
                     .field(GroupsRelation::getUserId, 0).op(Operator.NotEqual)

+ 134 - 18
netflix-service/src/main/java/com/cyksj/service/mange/impl/CmsOrderDonServiceImpl.java

@@ -1,5 +1,6 @@
 package com.cyksj.service.mange.impl;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateField;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
@@ -24,6 +25,7 @@ import com.cyksj.config.zfb.AliPayClientFactory;
 import com.cyksj.dto.RedisKey;
 import com.cyksj.mapper.*;
 import com.cyksj.mapper.channel.ShopConfigMapper;
+import com.cyksj.mapper.channel.UserPayEquipmentReceiveBenefitsRecordMapper;
 import com.cyksj.mapper.manage.cms.CmsUserMapper;
 import com.cyksj.mapper.manage.distribute.DistributeWaitingSendPointsMapper;
 import com.cyksj.mapper.manage.distribute.UserDistributeBusinessOrderDonRecordMapper;
@@ -49,6 +51,7 @@ import com.cyksj.service.order.OrderCommonService;
 import com.cyksj.service.order.UserRealOrderBenefitsService;
 import com.cyksj.service.paypal.PayPalService;
 import com.cyksj.service.relation.GroupRelationClearService;
+import com.cyksj.service.relation.GroupsRelationExpiryRecordService;
 import com.cyksj.service.stripe.StripeService;
 import com.cyksj.service.user.UserBenefitsService;
 import com.cyksj.service.wechat.WeChatService;
@@ -142,6 +145,10 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
 
     private final BeanSearcher beanSearcher;
 
+    private final UserPayEquipmentReceiveBenefitsRecordMapper receiveBenefitsRecordMapper;
+
+    private final GroupsRelationExpiryRecordService groupsRelationExpiryRecordService;
+
     private final GiftCardOrderUseRecordService giftCardOrderUseRecordService;
 
     private final GiftCardUserRecordMapper giftCardUserRecordMapper;
@@ -292,6 +299,17 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
         String refundType = refundReq.getRefundType();
         //校验订单是否符合退款
         checkOrderRefund(orderDon, goodsDon, sku, refundReq);
+        //空订单关闭
+        if (orderDon.getMoney().compareTo(BigDecimal.ZERO) == 0 && orderDon.getBalance().compareTo(BigDecimal.ZERO) == 0
+                && orderDon.getRelationId() == 0) {
+            orderDon.setStatus(OrderDon.Status.refund);
+            orderDonMapper.updateById(orderDon);
+            if (goodsDon.getType() == 2) {
+                //扣除用户自身实物权益
+                userRealOrderBenefitsService.deductUserRealGoodsBenefits(orderDon.getId());
+            }
+            return;
+        }
         OrderDon.Type type = orderDon.getType();
         String outNo = StrUtil.EMPTY;
         if (type == OrderDon.Type.WeChat && !refundType.equals(OrderDon.Type.BALANCE.getType())) {
@@ -384,6 +402,7 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
                 .eq(OrderDon::getUserId, userId)
                 .eq(OrderDon::getRelationId, relationId)
                 .notIn(OrderDon::getStatus, Constant.noOrderStatus)
+                .orderByDesc(OrderDon::getId)
                 .last("limit 1"));
         OrderDiscountPlusPurchaseSkuRelation plusPurchaseSkuRelation = null;
         List<Long> plus_relationList = null;
@@ -456,8 +475,43 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
         relation.setNewRelationId(newRelation.getId());
         relationClearService.clearTicket(relation, source);
 
+        if (plusPurchaseSkuRelation != null && plus_relationList != null) {
+            plus_relationList.remove(relationId);
+            plus_relationList.add(newRelation.getId());
+            plusPurchaseSkuRelation.setRelationIds(plus_relationList.toString());
+            orderDiscountPlusPurchaseSkuRelationMapper.updateById(plusPurchaseSkuRelation);
+        }
+
+        if (source != null && source == UserTicketClearedRecord.Source.abnormal) {
+            //将用户异常订单关闭
+            workOrderMapper.update(null, Wrappers.lambdaUpdate(WorkOrder.class)
+                    .set(WorkOrder::getStatus, WorkOrder.Status.close)
+                    .eq(WorkOrder::getStatus, WorkOrder.Status.waiting)
+                    .eq(WorkOrder::getUserId, userId)
+                    .eq(WorkOrder::getRelationId, relationId));
+        }
+
+        if (orderDon.getMoney() != null && orderDon.getMoney().compareTo(BigDecimal.ZERO) == 0) {
+            //是否是实物权益车票
+            UserPayEquipmentReceiveBenefitsRecord receiveBenefitsRecord = receiveBenefitsRecordMapper.selectOne(Wrappers.lambdaQuery(UserPayEquipmentReceiveBenefitsRecord.class)
+                    .eq(UserPayEquipmentReceiveBenefitsRecord::getTicketOrderId, orderDon.getId())
+                    .eq(UserPayEquipmentReceiveBenefitsRecord::getRelationId, relationId).last("limit 1"));
+            if (receiveBenefitsRecord != null) {
+                receiveBenefitsRecord.setRelationId(newRelation.getId());
+                receiveBenefitsRecordMapper.updateById(receiveBenefitsRecord);
+            }
+        }
+
         if ((newRelation.getStartTime() == null || newRelation.getExpiryTime() == null)) {
             List<OrderDon> orderDonList = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getUserId, userId).eq(OrderDon::getRelationId, relationId).eq(OrderDon::getStatus, OrderDon.Status.hasPayment));
+            if (orderDonList.isEmpty()) {
+                orderDonList = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class)
+                        .eq(OrderDon::getUserId, userId)
+                        .eq(OrderDon::getRelationId, relationId)
+                        .eq(OrderDon::getStatus, OrderDon.Status.complete)
+                        .orderByDesc(OrderDon::getId)
+                        .last("limit 1"));
+            }
             if (groups.getStatus() == GroupsTrips.Status.waiting) {
                 orderDonList.forEach(hasPaymentOrder -> {
                     hasPaymentOrder.setRelationId(newRelation.getId());
@@ -486,12 +540,7 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
             });
             return;
         }
-        if (plusPurchaseSkuRelation != null && plus_relationList != null) {
-            plus_relationList.remove(relationId);
-            plus_relationList.add(newRelation.getId());
-            plusPurchaseSkuRelation.setRelationIds(plus_relationList.toString());
-            orderDiscountPlusPurchaseSkuRelationMapper.updateById(plusPurchaseSkuRelation);
-        }
+
         List<OrderDon> orderDonList = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getUserId, userId).eq(OrderDon::getRelationId, relationId).eq(OrderDon::getStatus, OrderDon.Status.complete));
         orderDonList.forEach(completeOrder->{
             completeOrder.setRelationId(newRelation.getId());
@@ -499,15 +548,6 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
         });
         redisService.del(RedisKey.GROUPS_RELATION_NUM_KEY + newRelation.getId());
         relationMapper.updateById(newRelation);
-
-        if (source != null && source == UserTicketClearedRecord.Source.abnormal) {
-            //将用户异常订单关闭
-            workOrderMapper.update(null, Wrappers.lambdaUpdate(WorkOrder.class)
-                    .set(WorkOrder::getStatus, WorkOrder.Status.close)
-                    .eq(WorkOrder::getStatus, WorkOrder.Status.waiting)
-                    .eq(WorkOrder::getUserId, userId)
-                    .eq(WorkOrder::getRelationId, relationId));
-        }
     }
 
     public String zfbRefund(OrderRefundReq refundReq, OrderDon orderDon) throws Exception {
@@ -698,9 +738,51 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
                         } catch (Exception e) {
                         }
                     }
+                    String plusOrderIds = discountPlusPurchaseSkuRelation.getPlusOrderIds();
+                    if (StrUtil.isNotBlank(plusOrderIds)) {
+                        try {
+                            log.info("关闭优惠加购orderId:{}关联实物订单", orderDon.getId());
+                            List<Long> plusOrderIdList = Jsons.parseList(plusOrderIds, Long.class);
+                            List<OrderDon> relate_orderDons = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class)
+                                    .in(OrderDon::getId, plusOrderIdList)
+                                    .notIn(OrderDon::getStatus, Constant.noOrderStatus));
+                            relate_orderDons.forEach(relate_o->{
+                                //扣除用户自身实物权益
+                                userRealOrderBenefitsService.deductUserRealGoodsBenefits(relate_o.getId());
+                            });
+                            orderDonMapper.update(null, Wrappers.lambdaUpdate(OrderDon.class)
+                                    .set(OrderDon::getStatus, OrderDon.Status.refund)
+                                    .in(OrderDon::getId, plusOrderIdList)
+                                    .ne(OrderDon::getStatus, OrderDon.Status.refund));
+                        } catch (Exception e) {
+                        }
+                    }
                 }
             }
 
+            //同步车票退款 重购记录
+            TASK_POOL.execute(() -> {
+                GroupsRelationExpiryRecord groupsRelationExpiryRecord = groupsRelationExpiryRecordService.getOne(Wrappers.lambdaQuery(GroupsRelationExpiryRecord.class)
+                        .in(GroupsRelationExpiryRecord::getReBuyOrderId, orderDon.getId())
+                        .eq(GroupsRelationExpiryRecord::getRelationId, orderDon.getRelationId()).last("limit 1"));
+                if (groupsRelationExpiryRecord == null) {
+                    log.info("订单orderId:{}退款,同步是否有重购记录不是直接续费车票",orderDon.getId());
+                    List<GroupsRelationExpiryRecord> groupsRelationExpiryRecords = groupsRelationExpiryRecordService.list(Wrappers.lambdaQuery(GroupsRelationExpiryRecord.class)
+                            .in(GroupsRelationExpiryRecord::getReBuyOrderId, orderDon.getId()));
+                    log.info("订单orderId:{}退款,重购记录不是直接续费车票大小:{}",groupsRelationExpiryRecords.size());
+                    if (CollUtil.isNotEmpty(groupsRelationExpiryRecords)) {
+                        groupsRelationExpiryRecords.forEach(data -> {
+                            data.setIsReBuy(false);
+                        });
+                        groupsRelationExpiryRecordService.saveOrUpdateBatch(groupsRelationExpiryRecords);
+                    }
+                }
+                if (groupsRelationExpiryRecord != null) {
+                    groupsRelationExpiryRecord.setIsReBuy(false);
+                    groupsRelationExpiryRecordService.saveOrUpdate(groupsRelationExpiryRecord);
+                }
+            });
+
             //是否是礼品卡 现金支付订单
             BigDecimal gcCash = orderDon.getGcCash();
             if (gcCash != null && gcCash.compareTo(BigDecimal.ZERO) > 0) {
@@ -730,12 +812,21 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
                         distributeWaitingSendPointsMapper.updateById(distributeWaitingSendPoints);
                         return;
                     }
-                    Integer thisGoodsRate = Optional.ofNullable(userDistributeMapper.getDistributeGoodsRateByUidAndGid(orderDon.getUserId(), orderDon.getGoodsId())).orElse(0);
+                    Integer thisGoodsRate = distributeWaitingSendPoints.getRate();
+                    if (thisGoodsRate == null || thisGoodsRate == 0) {
+                        thisGoodsRate = Optional.ofNullable(userDistributeMapper.getDistributeGoodsRateByUidAndGid(orderDon.getUserId(), orderDon.getGoodsId())).orElse(0);
+                    }
                     if (thisGoodsRate > 0) {
                         BigDecimal needSubPoints = refundMoney.multiply(BigDecimal.valueOf(thisGoodsRate).divide(BigDecimal.valueOf(100))).multiply(BigDecimal.valueOf(10));
+                        if (needSubPoints.compareTo(points) > 0) {
+                            //全扣除
+                            distributeWaitingSendPoints.setSendStatus(DistributeWaitingSendPoints.Status.close);
+                            needSubPoints = points;
+                        }
                         distributeWaitingSendPoints.setRefundPoints(needSubPoints);
                         //剩余积分
-                        distributeWaitingSendPoints.setPoints(points.subtract(needSubPoints));
+                        BigDecimal remainPoints = points.subtract(needSubPoints);
+                        distributeWaitingSendPoints.setPoints(remainPoints);
                         distributeWaitingSendPointsMapper.updateById(distributeWaitingSendPoints);
                     }
                 } else if (sendStatus == DistributeWaitingSendPoints.Status.success) {
@@ -749,9 +840,17 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
                         distributeWaitingSendPointsMapper.updateById(distributeWaitingSendPoints);
                         return;
                     }
-                    Integer thisGoodsRate = Optional.ofNullable(userDistributeMapper.getDistributeGoodsRateByUidAndGid(orderDon.getUserId(), orderDon.getGoodsId())).orElse(0);
+                    Integer thisGoodsRate = distributeWaitingSendPoints.getRate();
+                    if (thisGoodsRate == null || thisGoodsRate == 0) {
+                        thisGoodsRate = Optional.ofNullable(userDistributeMapper.getDistributeGoodsRateByUidAndGid(orderDon.getUserId(), orderDon.getGoodsId())).orElse(0);
+                    }
                     if (thisGoodsRate > 0) {
                         BigDecimal needSubPoints = refundMoney.multiply(BigDecimal.valueOf(thisGoodsRate).divide(BigDecimal.valueOf(100))).multiply(BigDecimal.valueOf(10));
+                        if (needSubPoints.compareTo(points) > 0) {
+                            //全扣除
+                            distributeWaitingSendPoints.setSendStatus(DistributeWaitingSendPoints.Status.close);
+                            needSubPoints = points;
+                        }
                         userBenefitsService.deductDistributePoints(orderDon.getId(), distributeWaitingSendPoints.getSharedId(), needSubPoints);
                         //部分退款
                         distributeWaitingSendPoints.setRefundPoints(needSubPoints);
@@ -791,6 +890,23 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
         refundOrderDonMapper.insert(refund);
     }
 
+    @Override
+    public void refundPriceDiffer(OrderRefundReq orderRefundReq) {
+        Long orderId = orderRefundReq.getOrderId();
+        OrderDon orderDon = orderDonMapper.selectById(orderId);
+        if (orderDon == null) {
+            throw BusinessRuntimeException.getInstance("订单不存在");
+        }
+        if (orderDon.getMoney().compareTo(BigDecimal.ZERO) == 0) {
+            throw BusinessRuntimeException.getInstance("该订单是0元订单,无法补差价");
+        }
+        BigDecimal refundBalance = orderRefundReq.getRefundBalance();
+        if (refundBalance == null || refundBalance.compareTo(BigDecimal.ZERO) <= 0 || refundBalance.compareTo(orderDon.getMoney()) > 0) {
+            throw BusinessRuntimeException.getInstance("请输入正确的差价金额");
+        }
+        userBenefitsService.addUserBalance(orderDon.getUserId(), refundBalance, UserBalanceSourceRecord.Source.price_differ);
+    }
+
     /**
      * 寻找该车队空余车位
      */

+ 3 - 1
netflix-service/src/main/java/com/cyksj/service/mange/statistics/StatisticsDataService.java

@@ -17,7 +17,7 @@ import java.util.List;
  *创建时间:2022/10/17 14:43
  */
 public interface StatisticsDataService {
-	Result<BackgroundDataView> getStatisticsByCondition(Long startTime, Long endTime) throws InterruptedException;
+	Result<BackgroundDataView> getStatisticsByCondition(Integer type, Long startTime, Long endTime) throws InterruptedException;
 
 	IPage<ExpiredAccountDataView> getExpiredAccountView(Boolean isCorpWx, String customerService, Long goodsId, Long skuId, String account, Boolean renewStatus, Boolean handleStatus, String cnAccount, String usAccount, Integer uid, Long startTime, Long endTime, Long start, Long limit);
 
@@ -41,4 +41,6 @@ public interface StatisticsDataService {
 	 * 每月业务数据导出
 	 */
 	List<ExcelSheetAndData> exportMonthlyData(Long startTime, Long endTime);
+
+	Result<BackgroundDataView> getStatisticsHeader(Long startTime, Long endTime);
 }

+ 65 - 52
netflix-service/src/main/java/com/cyksj/service/mange/statistics/impl/StatisticsDataServiceImpl.java

@@ -2,7 +2,6 @@ package com.cyksj.service.mange.statistics.impl;
 
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -23,7 +22,10 @@ import com.cyksj.model.excel.statistics.ExcelRegisterAccountData;
 import com.cyksj.model.excel.statistics.ExcelStreamingAccountData;
 import com.cyksj.model.manage.views.GroupsRelationView;
 import com.cyksj.model.manage.views.OrderDonView;
-import com.cyksj.model.views.*;
+import com.cyksj.model.views.BackgroundDataView;
+import com.cyksj.model.views.DistributeOrdersView;
+import com.cyksj.model.views.ExpiredAccountDataView;
+import com.cyksj.model.views.GoodsDonSkuView;
 import com.cyksj.service.mange.CmsAccountService;
 import com.cyksj.service.mange.statistics.StatisticsDataDayService;
 import com.cyksj.service.mange.statistics.StatisticsDataService;
@@ -74,6 +76,8 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 
 	private final OrderDonMapper orderDonMapper;
 
+	private final UserMapper userMapper;
+
 	private final StatisticsUserDataMapper statisticsUserDataMapper;
 
 	private final StatisticsFashionGoodsDataMapper statisticsFashionGoodsDataMapper;
@@ -83,7 +87,7 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 	private static final GlobalThreadPoolTaskExecutor TASK_POOL = GlobalThreadPoolTaskExecutor.getInstance();
 
 	@Override
-	public Result<BackgroundDataView> getStatisticsByCondition(Long startTime, Long endTime) throws InterruptedException {
+	public Result<BackgroundDataView> getStatisticsByCondition(Integer type, Long startTime, Long endTime) {
 		BackgroundDataView backgroundDataView = new BackgroundDataView();
 		Date startDate = null;
 		Date endDate = null;
@@ -93,34 +97,37 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 		if (endTime != null) {
 			endDate = DateUtil.date(endTime);
 		}
-		CountDownLatch countDownLatch = new CountDownLatch(2);
-		final Date f_st = startDate;
-		final Date f_et = endDate;
-		//头部数据
-		TASK_POOL.execute(() -> {
-			try {
-				headerData(backgroundDataView, f_st, f_et);
-			} finally {
-				countDownLatch.countDown();
-			}
-		});
-		TASK_POOL.execute(() -> {
-			try {
+		switch (type) {
+			case 1:
 				//流媒体账号
-				getStreamingAccountDataView(backgroundDataView, f_st, f_et);
+				getStreamingAccountDataView(backgroundDataView, startDate, endDate);
 				//appleOne
-				getAppleOneDataView(backgroundDataView, f_st, f_et);
+				getAppleOneDataView(backgroundDataView, startDate, endDate);
+				break;
+			case 2:
 				//实物数据
-				getRealGoodsData(backgroundDataView, f_st, f_et);
+				getRealGoodsData(backgroundDataView, startDate, endDate);
+				break;
+			case 3:
 				//注册账号数据
-				getRegisterAccountData(backgroundDataView, f_st, f_et);
+				getRegisterAccountData(backgroundDataView, startDate, endDate);
+				break;
+			case 4:
 				//潮玩好物数据
-				getFashionGoodsData(backgroundDataView, f_st, f_et);
-			} finally {
-				countDownLatch.countDown();
-			}
-		});
-		countDownLatch.await();
+				getFashionGoodsData(backgroundDataView, startDate, endDate);
+				break;
+			default:
+				//流媒体账号
+				getStreamingAccountDataView(backgroundDataView, startDate, endDate);
+				//appleOne
+				getAppleOneDataView(backgroundDataView, startDate, endDate);
+				//实物数据
+				getRealGoodsData(backgroundDataView, startDate, endDate);
+				//注册账号数据
+				getRegisterAccountData(backgroundDataView, startDate, endDate);
+				//潮玩好物数据
+				getFashionGoodsData(backgroundDataView, startDate, endDate);
+		}
 		return GatewayResponse.SUCCESS.newBuilder().toResult(backgroundDataView);
 	}
 
@@ -328,6 +335,20 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 		return excelSheetDataList;
 	}
 
+	@Override
+	public Result<BackgroundDataView> getStatisticsHeader(Long startTime, Long endTime) {
+		Date startDate = null;
+		Date endDate = null;
+		if (startTime != null) {
+			startDate = DateUtil.date(startTime);
+		}
+		if (endTime != null) {
+			endDate = DateUtil.date(endTime);
+		}
+		BackgroundDataView backgroundDataView = getHeaderData(startDate, endDate);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(backgroundDataView);
+	}
+
 	public void exportAllTypeData(List<ExcelSheetAndData> excelSheetDataList, String startDate, String endDate) {
 		CountDownLatch latch = new CountDownLatch(2);
 		TASK_POOL.execute(() -> {
@@ -681,6 +702,7 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 	}
 
 	private void getStreamingAccountDataView(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
+		//当天
 		if (DateUtil.beginOfDay(DateTime.now()).equals(startDate) && (DateUtil.beginOfDay(DateUtil.offsetDay(DateTime.now(), 1)).equals(endDate) || DateUtil.endOfDay(DateTime.now()).equals(endDate))) {
 			List<StreamingAccountData> streamingAccountData = statistics.statisticsStreamingAccountData(startDate, endDate, true);
 			List<StreamingAccountData> collect = streamingAccountData.stream().filter(data -> {
@@ -721,13 +743,10 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 		} else {
 			List<RealGoodsData> realGoodsData = realGoodsDataMapper.statisticsRealGoodsData(startDate, endDate);
 			Optional.ofNullable(realGoodsData).ifPresent(list -> list.forEach(data -> {
-				GoodsDon goodsDon = goodsDonMapper.selectOne(Wrappers.lambdaQuery(GoodsDon.class).eq(GoodsDon::getId, data.getGoodsId()).last("limit 1"));
-				if (goodsDon != null) {
-					data.setGoodsTitle(goodsDon.getTitle());
-				}
-				GoodsDonSku goodsDonSku = goodsDonSkuMapper.selectOne(Wrappers.lambdaQuery(GoodsDonSku.class).eq(GoodsDonSku::getId, data.getSkuId()).last("limit 1"));
-				if (goodsDonSku != null) {
-					data.setSpecVal(goodsDonSku.getSpecVal());
+				GoodsDonSkuView goodsDonSkuView = beanSearcher.searchFirst(GoodsDonSkuView.class, MapUtils.builder().field(GoodsDonSkuView::getSkuId, data.getSkuId()).build());
+				if (goodsDonSkuView != null) {
+					data.setGoodsTitle(goodsDonSkuView.getGoodsTitle());
+					data.setSpecVal(goodsDonSkuView.getSpecVal());
 				}
 				data.setRefundMoney(getRefundMoney(null, data.getSkuId(), startDate, endDate));
 				data.setNumOfRefundOrder(getNumOfRefundOrder(null, data.getSkuId(), startDate, endDate));
@@ -736,37 +755,31 @@ public class StatisticsDataServiceImpl implements StatisticsDataService {
 		}
 	}
 
-	private void headerData(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
-		//总订单数
-		List<OrderDon> orderDons = Optional.ofNullable(orderDonService.list(Wrappers.lambdaQuery(OrderDon.class).notIn(OrderDon::getStatus, Constant.noOrderStatus).ge(ObjectUtil.isNotNull(startDate), OrderDon::getCreatedTime, startDate).lt(ObjectUtil.isNotNull(endDate), OrderDon::getCreatedTime, endDate))).orElse(new ArrayList<>());
-		backgroundDataView.setTotalNumOfOrder(orderDons.size());
-		//总下单用户数
-		backgroundDataView.setTotalNumOfUser(orderDons.stream().map(OrderDon::getUserId).collect(Collectors.toSet()).size());
-		Optional<BigDecimal> totalMoney = orderDons.stream().map(OrderDon::getMoney).reduce(BigDecimal::add);
-		//总订单金额
-		backgroundDataView.setTotalOrderAmount(totalMoney.isPresent() ? totalMoney.get().divide(BigDecimal.valueOf(100)) : BigDecimal.ZERO);
-		//退款列表
-		List<OrderDon> refundOrders = Optional.ofNullable(orderDonService.list(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getStatus, OrderDon.Status.refund).ge(ObjectUtil.isNotNull(startDate), OrderDon::getCreatedTime, startDate).lt(ObjectUtil.isNotNull(endDate), OrderDon::getCreatedTime, endDate).select(OrderDon::getId, OrderDon::getRefundMoney))).orElse(new ArrayList<>());
-		backgroundDataView.setTotalNumOfRefundOrder(refundOrders.size());
-		//退款金额
-		Optional<BigDecimal> totalRefundAmount = refundOrders.stream().map(OrderDon::getRefundMoney).reduce(BigDecimal::add);
-		backgroundDataView.setTotalRefundAmount(totalRefundAmount.isPresent() ? totalRefundAmount.get().divide(BigDecimal.valueOf(100)) : BigDecimal.ZERO);
+	private BackgroundDataView getHeaderData(Date startDate, Date endDate) {
+		BackgroundDataView backgroundDataView = orderDonMapper.getBackgroundDataView(startDate, endDate, Constant.noOrderStatus);
 		//近5天将要到期的主账号总数
 		DateTime now = DateTime.now();
 		DateTime zero = DateUtil.beginOfDay(now);
 		DateTime fiveDays = DateUtil.offsetDay(zero, 5);
 		//5天后将到期的主账号
-		List<Account> willExpireAccounts = Optional.ofNullable(accountService.list(Wrappers.lambdaQuery(Account.class).between(Account::getExpiryTime, zero, fiveDays))).orElse(new ArrayList<>());
-		backgroundDataView.setTotalNumOfWillExpireAccount(willExpireAccounts.size());
+		Integer willExpireAccounts = accountService.count(Wrappers.lambdaQuery(Account.class).between(Account::getExpiryTime, zero, fiveDays));
+		backgroundDataView.setTotalNumOfWillExpireAccount(willExpireAccounts);
 		//已到期主账号
-		List<Account> expiredAccounts = Optional.ofNullable(accountService.list(Wrappers.lambdaQuery(Account.class).le(Account::getExpiryTime, now))).orElse(new ArrayList<>());
-		backgroundDataView.setTotalExpiredAccountNum(expiredAccounts.size());
+		Integer expiredAccounts = accountService.count(Wrappers.lambdaQuery(Account.class).le(Account::getExpiryTime, now));
+		backgroundDataView.setTotalExpiredAccountNum(expiredAccounts);
 		//虚物
 		setGoodsMoneyAndOrder(1, startDate, endDate, backgroundDataView);
 		//实物
 		setGoodsMoneyAndOrder(2, startDate, endDate, backgroundDataView);
 		//潮玩
 		setGoodsMoneyAndOrder(3, startDate, endDate, backgroundDataView);
+		//已使用余额
+		BigDecimal usedBalance = orderDonMapper.statisticsUsedBalance(startDate, endDate, Constant.noOrderAllStatus);
+		backgroundDataView.setUsedBalance(usedBalance);
+		//剩余余额
+		BigDecimal remainBalance = userMapper.statisticsRemainBalance();
+		backgroundDataView.setRemainBalance(remainBalance);
+		return backgroundDataView;
 	}
 
 	/**

+ 3 - 0
netflix-service/src/main/java/com/cyksj/service/market/impl/MarketFrontServiceImpl.java

@@ -476,6 +476,9 @@ public class MarketFrontServiceImpl implements MarketFrontService {
 				if (index == -1) {
 					throw BusinessRuntimeException.getInstance("系统异常,请刷新页面重新操作");
 				}
+				if (index > list.size()) {
+					throw BusinessRuntimeException.getInstance("抽奖异常,请联系客服");
+				}
 				LuckyDrawView next = list.get(index);
 				num++;
 				return randomNum(next, list, num, userId);

+ 1 - 4
netflix-service/src/main/java/com/cyksj/service/market/task/impl/BindTaskServiceImpl.java

@@ -68,9 +68,6 @@ public class BindTaskServiceImpl implements BindTaskService {
 	@Override
 	public UserBindDetail bindPhone(User user, String phone, String code) {
 		Long userId = user.getId();
-		if (!Validator.isMobile(phone)) {
-			throw BusinessRuntimeException.getInstance("请输入正确的手机号");
-		}
 		if (StrUtil.isNotBlank(user.getLoginPhone())) {
 			throw BusinessRuntimeException.getInstance("您通过手机号登录,无法绑定其他手机号");
 		}
@@ -162,7 +159,7 @@ public class BindTaskServiceImpl implements BindTaskService {
 		User phoneUser = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
 				.eq(User::getLoginPhone, phone).last("limit 1"));
 		if (phoneUser == null) {
-			throw BusinessRuntimeException.getInstance("换绑手机号重复未注册");
+			throw BusinessRuntimeException.getInstance("换绑手机号未注册");
 		}
 		checkPhoneCode(phone, code);
 		bindPhone.setPhoneUserId(phoneUser.getId());

+ 2 - 1
netflix-service/src/main/java/com/cyksj/service/order/OrderCommonService.java

@@ -1,6 +1,7 @@
 package com.cyksj.service.order;
 
 import com.cyksj.model.entity.GoodsDonSku;
+import com.cyksj.model.entity.GroupsRelation;
 import com.cyksj.model.entity.OrderDon;
 
 /*
@@ -19,5 +20,5 @@ public interface OrderCommonService {
 	/**
 	 * 清除座位缓存,可用座位数增加
 	 */
-	void delRelation(Long relationId);
+	void delRelation(GroupsRelation relation);
 }

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

@@ -114,7 +114,7 @@ public class OrderCommonServiceImpl implements OrderCommonService {
 					relation.setAccount(null);
 					groupsRelationMapper.updateExpiryTime(relation, expiryTime);
 					if (relation.getStatus() != GroupsRelation.Status.outside) {
-						delRelation(relation.getId());
+						delRelation(relation);
 					}
 				} else {
 					if (expiryTime != null) {
@@ -135,9 +135,12 @@ public class OrderCommonServiceImpl implements OrderCommonService {
 	}
 
 	@Override
-	public void delRelation(Long relationId) {
+	public void delRelation(GroupsRelation relation) {
+		Long relationId = relation.getId();
 		redisService.del(RedisKey.GROUPS_RELATION_NUM_KEY + relationId);
-		GroupsRelation relation = groupsRelationMapper.selectById(relationId);
+		if (relation.getStatus() == GroupsRelation.Status.outside) {
+			return;
+		}
 		int count = groupsMapper.incrAvailableNum(relation.getGroupsId());
 		if (count == 0) {
 			log.error("车位异常 groupId:{}", relation.getGroupsId());

+ 336 - 52
netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java

@@ -33,6 +33,7 @@ import com.cyksj.common.snowflake.Sequence;
 import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
 import com.cyksj.common.util.Codec;
 import com.cyksj.common.util.Jsons;
+import com.cyksj.common.util.SmsUtil;
 import com.cyksj.common.util.StringUtil;
 import com.cyksj.config.WeChatConfig;
 import com.cyksj.config.zfb.AliPayClientFactory;
@@ -77,6 +78,7 @@ import com.cyksj.service.order.OrderDonService;
 import com.cyksj.service.pay.AliPayCommonService;
 import com.cyksj.service.relation.GroupRelationClearService;
 import com.cyksj.service.relation.GroupRelationFrontService;
+import com.cyksj.service.relation.GroupsRelationExpiryRecordService;
 import com.cyksj.service.sys.SysConfigService;
 import com.cyksj.service.telegram.TelegramService;
 import com.cyksj.service.template.TemplateCommonService;
@@ -219,6 +221,10 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 
 	private final ChannelPopularizeMapper channelPopularizeMapper;
 
+	private final GroupsRelationExpiryRecordService groupsRelationExpiryRecordService;
+
+	private final UserPhoneSendRecordMapper userPhoneSendRecordMapper;
+
 	private final TelegramService telegramService;
 
 	private final GiftCardUserRecordService giftCardUserRecordService;
@@ -268,7 +274,6 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		User user;
 		String payOpenId = null;
 		Long relationId = 0L;
-
 		Boolean isNeedTicket = checkIsNeedGroupsRelation(goodsDon);
 		Long userId = payRequest.getUserId();
 		if (userId != null) {
@@ -277,6 +282,7 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 				throw new BusinessRuntimeException("您有未支付订单.");
 			}
 		}
+		GroupsRelation relation = null;
 		if (userId == null) {
 			user = new User();
 			user.setId(0l);
@@ -291,7 +297,8 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			}
 			if (goodsDon.getType() == 1 && isNeedTicket) {
 				//获取座位
-				relationId = getRelation(payRequest, sku);
+				relation = getRelation(payRequest, sku);
+				relationId = relation.getId();
 			} else {
 
 			}
@@ -314,9 +321,10 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 
 		//是否是特定价格 且是否满足
 		Boolean isSpecificPrice = Optional.ofNullable(payRequest.getIsSpecificPrice()).orElse(false);
-		BigDecimal specificPrice = null;
+		String specificGoodsIds = null;
+		BigDecimal specificPrice = BigDecimal.ZERO;
 		if (isSpecificPrice) {
-			String specificGoodsIds = sku.getSpecificGoodsIds();
+			specificGoodsIds = sku.getSpecificGoodsIds();
 			if (StrUtil.isEmpty(specificGoodsIds)) {
 				throw BusinessRuntimeException.getInstance("系统异常,请刷新页面重试");
 			}
@@ -338,7 +346,7 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			specificPrice = sku.getSpecificPrice();
 		}
 
-		if (sku != null && !isSpecificPrice && payRequest.getDonMoney().compareTo(sku.getPrice()) < 0) {
+		if (sku != null && payRequest.getDonMoney().compareTo(sku.getPrice()) < 0 && !isSpecificPrice) {
 			log.info("规格:{}支付金额:{}异常,调整用户userId:{}支付金额为:{}", sku.getSpecVal(), payRequest.getDonMoney(), user.getId(), sku.getPrice());
 			payRequest.setDonMoney(sku.getPrice());
 		}
@@ -392,6 +400,9 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		orderDon.setIsWebPay(payRequest.getIsWebPay());
 		orderDon.setSource(payRequest.getSource());
 		orderDon.setCouponExCode(payRequest.getCouponExCode());
+		if (relation != null && relation.getStatus() == GroupsRelation.Status.outside) {
+			orderDon.setIsOt(true);
+		}
 		//设置分销订单
 		setDistributeOrderMark(orderDon, goodsDon.getType(), user.getId());
 		if (relationId != 0) {
@@ -479,6 +490,10 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		if (Constant.realGoodsType.contains(goodsDon.getType()) && !goodsDon.getId().equals(27l)) {
 			saveTransport(payRequest.getAddressId(), orderDon.getId());
 		}
+		//保存加购发货地址
+		if (orderDon.getIsDp() && payRequest.getAddressId() != null) {
+			redisService.set(RedisService.key.PLUS_GOODS_ADDRESS_KEY.getName() + orderDon.getId(), payRequest.getAddressId(), RedisService.key.PLUS_GOODS_ADDRESS_KEY.getTimeout());
+		}
 		if (orderDon.getStatus() == OrderDon.Status.noPayment) {
 			jobManager.addJob(EXPIRY_TIME, () -> {
 				closeOrder(orderDon.getId(), null);
@@ -727,12 +742,14 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 						}
 						//throw new BusinessRuntimeException("订单用户与车位用户不匹配!");
 					} else {
-						if (GroupsRelation.Status.locking.equals(groupsRelation.getStatus())) {
+						if (GroupsRelation.Status.locking == groupsRelation.getStatus() || GroupsRelation.Status.outside == groupsRelation.getStatus()) {
 							log.info("清理用户userId:{}未支付订单", orderDon.getUserId());
 							groupsRelation.setUserId(0L);
-							groupsRelation.setStatus(GroupsRelation.Status.none);
+							if (GroupsRelation.Status.outside != groupsRelation.getStatus()) {
+								groupsRelation.setStatus(GroupsRelation.Status.none);
+							}
 							groupsRelationMapper.updateById(groupsRelation);
-							orderCommonService.delRelation(groupsRelation.getId());
+							orderCommonService.delRelation(groupsRelation);
 
 							//车位空余发送模板消息
 //						TASK_POOL.execute(() -> {
@@ -874,6 +891,9 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			orderDon.setPreSkuId(tripsSkuId);
 		}
 		orderDon.setGoodsId(goodsDon.getId());
+		if (relation != null && relation.getStatus() == GroupsRelation.Status.outside) {
+			orderDon.setIsOt(true);
+		}
 		//虚拟商品订单,是否是分销订单
 		if (goodsDon.getType() == 1) {
 			UserDistributeShared userDistributeShared = userDistributeSharedMapper.selectOne(Wrappers.lambdaQuery(UserDistributeShared.class).eq(UserDistributeShared::getUserId, user.getId()).last("limit 1"));
@@ -983,11 +1003,14 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		unifiedHandlerOrderNotify(orderDon, goodsDon, sku);
 	}
 
-	public void setRelation(Long relationId, Long groupsId, Long userId, Long goodsId, Boolean isLoginPopularize) {
+	public void setRelation(Long relationId, Long groupsId, Long userId, Long goodsId, Boolean isLoginPopularize, GroupsRelation.Status status) {
 		if (!redisService.setNx(RedisKey.GROUPS_RELATION_NUM_KEY + relationId, userId, 60 * 5L)) {
 			log.info("=====>用户:{}未抢到座位:{}", userId, relationId);
 			throw new BusinessRuntimeException("客官手慢啦,该座位已经有人啦!");
 		}
+		if (status == GroupsRelation.Status.outside) {
+			return;
+		}
 		int count = groupsMapper.decrAvailableNum(groupsId);
 		if (count == 0) {
 			log.error("车位异常 groupId:{}", groupsId);
@@ -1006,15 +1029,7 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		if (address == null) {
 			throw new BusinessRuntimeException("请添加收货地址.");
 		}
-		OrderDonTransport transport = new OrderDonTransport();
-		transport.setOrderId(orderId);
-		transport.setReceiver(address.getReceiver());
-		transport.setPhone(address.getPhone());
-		transport.setProvince(address.getProvince());
-		transport.setCity(address.getCity());
-		transport.setDistrict(address.getDistrict());
-		transport.setAddress(address.getAddress());
-		orderDonTransportMapper.insert(transport);
+		saveTransportByAddress(address, orderId);
 	}
 
 	@Override
@@ -1138,6 +1153,9 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		if (orderDon.getMoney().compareTo(BigDecimal.ZERO) > 0) {
 			throw BusinessRuntimeException.getInstance("订单异常");
 		}
+		if (orderDon.getStatus() != OrderDon.Status.noPayment) {
+			throw BusinessRuntimeException.getInstance("订单状态已修改");
+		}
 		GoodsDon goodsDon = goodsDonMapper.selectById(orderDon.getGoodsId());
 		GoodsDonSku sku = null;
 		if (orderDon.getSkuId() != null) {
@@ -1172,21 +1190,49 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 						try {
 							List<Long> plusSkuIds = Jsons.parseList(plusSkuIdsStr, Long.class);
 							//发送优惠加购 规格车票
-							List<Long> dis_relation_ids = new ArrayList<>();
-							plusSkuIds.forEach(plus_skuId -> {
+							List<Long> dis_relation_ids = null;
+							List<Long> plus_order_ids = null;
+							Address address = null;
+							for (Long plus_skuId : plusSkuIds) {
 								GoodsDonSku plus_sku = goodsDonSkuMapper.selectById(plus_skuId);
 								if (plus_sku == null) {
 									log.error("订单id:{}优惠加购规格已被删除 skuId:{},车票未发送", order.getId(), plus_skuId);
-									return;
+									continue;
+								}
+								GoodsDon plus_goods = goodsDonMapper.selectById(plus_sku.getGoodsId());
+								if (plus_goods.getType() != 1) {
+									log.info("orderId:{}存在非虚拟规格加购,添加{}发货信息", order.getId(), plus_goods.getTitle());
+									if (plus_order_ids == null) {
+										plus_order_ids = new ArrayList<>();
+									}
+									if (address == null) {
+										Long addressId = Long.parseLong(redisService.getStr(RedisService.key.PLUS_GOODS_ADDRESS_KEY.getName() + order.getId()));
+										if (addressId == null) {
+											log.error("用户userId{}缓存的收货地址addressId:{}不存在", order.getUserId(), addressId);
+											continue;
+										}
+										address = addressMapper.selectById(addressId);
+										if (address == null) {
+											log.error("用户userId{}收货地址addressId:{}已不存在", order.getUserId(), addressId);
+											continue;
+										}
+									}
+									//生成实物订单 0元实物订单
+									createRealOrderAndTransport(order.getUserId(), address, plus_goods, plus_sku, plus_order_ids);
+									continue;
+								}
+								if (dis_relation_ids == null) {
+									dis_relation_ids = new ArrayList<>();
 								}
 								GroupsRelation relationNoOrder = exchangeCodeService.getRelationNoOrder(plus_sku, order.getUserId());
 								dis_relation_ids.add(relationNoOrder.getId());
-							});
+							}
+							redisService.del(RedisService.key.PLUS_GOODS_ADDRESS_KEY.getName() + order.getId());
 							//保存订单关联优惠加购车票
 							orderDiscountPlusPurchaseSkuRelationMapper.update(null, Wrappers.lambdaUpdate(OrderDiscountPlusPurchaseSkuRelation.class)
-									.set(OrderDiscountPlusPurchaseSkuRelation::getRelationIds, dis_relation_ids.toString())
-									.eq(OrderDiscountPlusPurchaseSkuRelation::getOrderId, order.getId())
-									.isNull(OrderDiscountPlusPurchaseSkuRelation::getRelationIds));
+									.set(CollUtil.isNotEmpty(dis_relation_ids), OrderDiscountPlusPurchaseSkuRelation::getRelationIds, Jsons.toJson(dis_relation_ids))
+									.set(CollUtil.isNotEmpty(plus_order_ids), OrderDiscountPlusPurchaseSkuRelation::getPlusOrderIds, Jsons.toJson(plus_order_ids))
+									.eq(OrderDiscountPlusPurchaseSkuRelation::getOrderId, order.getId()));
 						} catch (Exception e) {
 						}
 					}
@@ -1237,7 +1283,7 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 					}
 				}
 				//下架POE会员车队
-				if (order.getGoodsId() != null && order.getGoodsId().equals(35l)) {
+				if (order.getGoodsId() != null && Constant.DOWN_GOODS_PAY.contains(order.getGoodsId())) {
 					if (groupsTrips.getAccountId() != null && groupsTrips.getStatus() == GroupsTrips.Status.validity) {
 						groupsTrips.setStatus(GroupsTrips.Status.down);
 						groupsMapper.updateById(groupsTrips);
@@ -1347,6 +1393,11 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 					BigDecimal returnPoints = returnMoney.multiply(BigDecimal.valueOf(distributePointsExchangeMoney.getPoints())).divide(distributePointsExchangeMoney.getMoney(), 2, RoundingMode.HALF_DOWN);
 					points = returnPoints;
 				}
+				if (userDistribute != null) {
+					//处理渠道规则分销
+					points = handlerDistributeRule(order, distributeWaitingSendPoints, userDistribute.getId(), distributePointsExchangeMoney, points);
+				}
+
 				distributeWaitingSendPoints.setPoints(points);
 				if (points != null && points.compareTo(BigDecimal.ZERO) > 0) {
 					log.info("用户{}邀请{},产生分销订单分发积分记录入库", userDistributeShared.getSharedId(), order.getUserId());
@@ -1615,12 +1666,15 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 	}
 
 	/**
-	 * @param preSkuId      续费之前的规格id
-	 * @param preRelationId 续费之前的座位id
-	 * @param orderId       订单id
+	 * @param orderDon       续费订单
 	 * @param afterSku      续费之后的规格
 	 */
-	private void changeTicketAndRecord(Long preSkuId, Long preRelationId, Long orderId, Integer num, GoodsDonSku afterSku, Long userId) {
+	private void changeTicketAndRecord(OrderDon orderDon,GoodsDonSku afterSku) {
+		Long preSkuId = orderDon.getSkuId();
+		Long preRelationId = orderDon.getRelationId();
+		Long orderId = orderDon.getId();
+		Integer num = orderDon.getNum();
+		Long userId = orderDon.getUserId();
 		//清理之前的车票
 		GroupsRelation relation = groupsRelationMapper.selectById(preRelationId);
 		if (relation != null) {
@@ -1638,6 +1692,10 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			afterRelation.setExpiryTime(afterExpiryTime);
 			groupsRelationMapper.updateById(afterRelation);
 
+			//更新订单对应的relation_id
+			orderDon.setRelationId(afterRelation.getId());
+			orderDonMapper.updateById(orderDon);
+
 			//保存更换车票记录
 			saveChangeTicketRecord(preStartTime, preExpiryTime, preRelationId, userId, preSkuId, orderId, num, afterSku, afterRelation.getId());
 
@@ -1665,6 +1723,10 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 					.set(GroupsRelation::getExpiryTime, relationView.getExpiryTime())
 					.eq(GroupsRelation::getId, relationView.getId()));
 
+			//更新订单对应的relation_id
+			orderDon.setRelationId(relationView.getId());
+			orderDonMapper.updateById(orderDon);
+
 			//保存更换车票记录
 			saveChangeTicketRecord(preStartTime, preExpiryTime, relationView.getId(), userId, preSkuId, orderId, num, afterSku, relationView.getId());
 		}
@@ -1855,7 +1917,7 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 	/**
 	 * 获取车位
 	 */
-	public Long getRelation(OrderPayRequest payRequest, GoodsDonSku sku) {
+	public GroupsRelation getRelation(OrderPayRequest payRequest, GoodsDonSku sku) {
 		GroupsRelation relation;
 		Long payRelationId = payRequest.getRelationId();
 		Boolean isLoginPopularize = payRequest.getIsLoginPopularize();
@@ -1875,22 +1937,54 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			relation = groupRelationFrontService.getSimilarExpiredGroupRelation(sku.getId(), sku.getDays(), sku.getMonths(), null);
 			if (relation == null) {
 				//TODO 如果没指定座位,等待逻辑确认
-				GroupsTrips groups = groupsMapper.selectOne( Wrappers.lambdaQuery(GroupsTrips.class)
+				GroupsTrips groups = groupsMapper.selectOne(Wrappers.lambdaQuery(GroupsTrips.class)
 						.eq(GroupsTrips::getSkuId, sku.getId())
 						.gt(GroupsTrips::getAvailableNum, 0).last("limit 1")
 						.eq(GroupsTrips::getStatus, GroupsTrips.Status.validity)
 						.orderByAsc(GroupsTrips::getAvailableNum));
-				//待发车
 				if (groups == null) {
-					groups = groupsMapper.selectOne( Wrappers.lambdaQuery(GroupsTrips.class)
-							.eq(GroupsTrips::getSkuId, sku.getId())
-							.gt(GroupsTrips::getAvailableNum, 0).last("limit 1")
-							.eq(GroupsTrips::getStatus, GroupsTrips.Status.waiting)
-							.orderByAsc(GroupsTrips::getAvailableNum));
+					//若是MidJourney、ChatGPT PLUS每个已满车队 硬塞5个座位
+					//主账号过期时间10天以外
+					if (sku.getNum() > 1 && Constant.AI_goodsIds.contains(sku.getGoodsId())) {
+						DateTime tenExpiry = DateUtil.offsetDay(DateUtil.beginOfDay(DateTime.now()), 10);
+						//不塞存在该用户的车队
+						Long groupsId = groupsRelationMapper.getOutSideGroupsTripsRelationByGoodsId(sku.getId(), tenExpiry, 5, userId);
+						if (groupsId != null) {
+							relation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
+									.eq(GroupsRelation::getGroupsId, groupsId)
+									.eq(GroupsRelation::getUserId, 0)
+									.eq(GroupsRelation::getStatus, GroupsRelation.Status.outside)
+									.last("limit 1"));
+							if (relation == null) {
+								if (redisService.setNx(RedisService.key.GROUPS_TRIPS_OUTSIDE_RELATION.getName() + groupsId, groupsId, RedisService.key.GROUPS_TRIPS_OUTSIDE_RELATION.getTimeout())) {
+									relation = new GroupsRelation();
+									relation.setStatus(GroupsRelation.Status.outside);
+									relation.setUserId(userId);
+									relation.setGroupsId(groupsId);
+									GroupsRelation maxNumRelation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class).eq(GroupsRelation::getGroupsId, groupsId).orderByDesc(GroupsRelation::getNum).last("limit 1"));
+									relation.setNum(maxNumRelation.getNum() + 1);
+									groupsRelationMapper.insert(relation);
+									redisService.del(RedisService.key.GROUPS_TRIPS_OUTSIDE_RELATION.getName() + groupsId);
+								}
+							}
+							groups = groupsMapper.selectById(groupsId);
+						}
+					}
+					if (relation == null) {
+						//待发车
+						groups = groupsMapper.selectOne( Wrappers.lambdaQuery(GroupsTrips.class)
+								.eq(GroupsTrips::getSkuId, sku.getId())
+								.gt(GroupsTrips::getAvailableNum, 0).last("limit 1")
+								.eq(GroupsTrips::getStatus, GroupsTrips.Status.waiting)
+								.orderByAsc(GroupsTrips::getAvailableNum));
+					}
 				}
+
 				if (groups == null) {
 					relation = groupsFuncService.createNewGroupsTrips(sku);
-				} else {
+				}
+
+				if (relation == null) {
 					//寻找快满编车队进行占座
 					relation = groupsRelationMapper.selectRandomOneRelationByGroupsId(groups.getId());
 					if (relation == null) {
@@ -1901,18 +1995,23 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		}
 
 		//锁定座位
-		setRelation(relation.getId(), relation.getGroupsId(), userId, sku.getGoodsId(), isLoginPopularize);
+		setRelation(relation.getId(), relation.getGroupsId(), userId, sku.getGoodsId(), isLoginPopularize, relation.getStatus());
 		relation.setUserId(userId);
-		relation.setStatus(GroupsRelation.Status.locking);
+		if (relation.getStatus() != GroupsRelation.Status.outside) {
+			relation.setStatus(GroupsRelation.Status.locking);
+		}
 		groupsRelationMapper.updateById(relation);
 		redisService.del(RedisKey.GROUPS_RELATION_NUM_KEY + relation.getId());
-		return relation.getId();
+		return relation;
 	}
 
 	/**
 	 * 使用优惠营销 订单金额抵扣
 	 */
 	public void deductOrderMoney(OrderDon orderDon, CouponUser couponUser, BigDecimal balance, User user, BigDecimal skuMoney, Integer goodsType, BigDecimal gcCash, List<Long> gcpIds) {
+		if (gcCash != null && gcCash.compareTo(BigDecimal.ZERO) > 0 && couponUser != null) {
+			throw BusinessRuntimeException.getInstance("现金卡不能与其他优惠叠加使用");
+		}
 		BigDecimal first_money = orderDon.getMoney();
 		//礼品卡现金支付 不参与其他优惠
 		if (gcCash != null && gcCash.compareTo(BigDecimal.ZERO) > 0) {
@@ -1968,6 +2067,9 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 				BigDecimal discountMoney = orderDon.getMoney().multiply(coupon.getDiscount());
 				orderDon.setMoney(discountMoney);
 				couponMoney = orderDon.getRealMoney().subtract(discountMoney);
+				//记录折扣 用于分销
+				couponUser.setDiscount(coupon.getDiscount());
+				couponUserMapper.updateById(couponUser);
 			} else if (coupon.getType() == Coupon.Type.reduce) {
 				if (goodsType == 2) {
 					if (skuMoney.compareTo(coupon.getReduceCondition()) < 0) {
@@ -2026,16 +2128,57 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 	public void updateGroupsTicket(OrderDon orderDon, GoodsDon goodsDon, GoodsDonSku sku) {
 		if (orderDon.getOrderType() == 2 && orderDon.getIsChangeTicket()) {
 			//将奈飞月付车票更换成其他规格的车票
-			changeTicketAndRecord(orderDon.getPreSkuId(), orderDon.getRelationId(), orderDon.getId(), orderDon.getNum(), sku, orderDon.getUserId());
+			changeTicketAndRecord(orderDon, sku);
 		} else {
 			//修改车位状态并发送模板消息
 			updateCarParkAndSendMsg(goodsDon, sku, orderDon);
 		}
+		//同步车票是否重购 记录
+		TASK_POOL.execute(() -> {
+			groupsRelationExpiryRecordService.syncGroupsRelationExpiryRecord(orderDon, goodsDon, sku);
+
+			//发送下单后 若有手机 发送短信
+			sendOrderPhoneMsg(orderDon.getUserId());
+		});
+	}
+
+	private void sendOrderPhoneMsg(Long userId) {
+		User user = userMapper.selectById(userId);
+		String phone = null;
+		if (StrUtil.isNotBlank(user.getLoginPhone())) {
+			phone = user.getLoginPhone();
+		} else {
+			//获取对应手机号
+			UserBindDetail userBindDetail = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
+					.eq(StrUtil.isNotBlank(user.getOpenId()), UserBindDetail::getUserId, user.getId())
+					.eq(StrUtil.isNotBlank(user.getEmail()), UserBindDetail::getEmailUserId, user.getId()));
+			if (userBindDetail != null && StrUtil.isNotBlank(userBindDetail.getPhone())) {
+				phone = userBindDetail.getPhone();
+			}
+		}
+		if (StrUtil.isNotBlank(phone)) {
+			//是否发送过手机短信
+			UserPhoneSendRecord userPhoneSendRecord = userPhoneSendRecordMapper.selectOne(Wrappers.lambdaQuery(UserPhoneSendRecord.class)
+					.eq(UserPhoneSendRecord::getPhone, phone).last("limit 1"));
+			if (userPhoneSendRecord == null) {
+				try {
+					Boolean is_success = SmsUtil.sendLuoKey2Msg(phone, String.format(Constant.ORDER_MSG_FIRST_NOTIFY, user.getNickname()));
+					if (is_success) {
+						log.info("用户userId:{},购买成功,发送第一次手机号:{}短信官网信息通知", userId, phone);
+						userPhoneSendRecord = new UserPhoneSendRecord();
+						userPhoneSendRecord.setOrderUserId(userId);
+						userPhoneSendRecord.setPhone(phone);
+						userPhoneSendRecordMapper.insert(userPhoneSendRecord);
+					}
+				} catch (Exception e) {
+				}
+			}
+		}
 	}
 
 
 	@Override
-	public void orderNotify(OrderDon orderDon){
+	public void orderNotify(OrderDon orderDon) {
 		Long goodsId = orderDon.getGoodsId();
 		if (orderDon.getIsNoLogin()) {
 			orderDon.setExCode(exchangeCodeService.getExCode(goodsId, orderDon.getSkuId(), 1));
@@ -2137,29 +2280,43 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		//虚拟物品购买推送电报消息
 		if(goodsDon.getType() == 1){
 			TASK_POOL.execute(()->{
-				sendTelegramMsg(orderDon, goodsDon);
+				sendTelegramMsg(orderDon, goodsDon, sku);
 			});
 		}
 	}
 
-	private void sendTelegramMsg(OrderDon orderDon, GoodsDon goodsDon) {
-		if(!redisService.hasKey(RedisKey.TELEGRAM_BOT_MSG)){
+	private void sendTelegramMsg(OrderDon orderDon, GoodsDon goodsDon, GoodsDonSku sku) {
+		if (!redisService.hasKey(RedisKey.TELEGRAM_BOT_MSG)) {
+			//礼品卡类似订单过滤
+			if (orderDon.getRelationId() != null && orderDon.getRelationId() == 0) {
+				return;
+			}
 			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){
+			Date expiryTime = groupsRelation.getExpiryTime();
+			if (expiryTime == null) {
+				Integer days = sku.getDays();
+				Integer months = sku.getMonths();
+				if (days != null && days > 0) {
+					expiryTime = DateUtil.offsetDay(new Date(), days);
+				} else {
+					expiryTime = DateUtil.offsetMonth(new Date(), months);
+				}
+			}
+			long day = DateUtil.betweenDay(new Date(), expiryTime, 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);
+				redisService.set(RedisKey.TELEGRAM_BOT_MSG, 1, 60L * 3L);
 			} catch (Exception e) {
-				log.error("发送电报推送消息错误 msg:{}",StringUtil.getErrorText(e));
+				log.error("发送电报推送消息错误 msg:{}", StringUtil.getErrorText(e));
 			}
 		}
 	}
@@ -2179,7 +2336,40 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 				orderDon.setIsDistribute(true);
 				UserDistribute userDistribute = userDistributeMapper.selectOne(Wrappers.lambdaQuery(UserDistribute.class).eq(UserDistribute::getUserId, userDistributeShared.getSharedId()));
 				if (userDistribute != null) {
-					orderDon.setIsFixedDistribute(true);
+					//直接去除
+					if (!userDistributeShared.getIsBind()) {
+						orderDon.setIsDistribute(false);
+					} else {
+						//45天内是否下单成功
+						Date createdTime = userDistributeShared.getCreatedTime();
+						DateTime forty_five = DateUtil.offsetDay(createdTime, 45);
+						//在45天内
+						Boolean is_fit = false;
+						boolean before = DateTime.now().isBefore(forty_five);
+						//超过45天还未下过单
+						//直接不参与后续的 提成
+						if (before) {
+							is_fit = true;
+						} else {
+							int count = this.count(Wrappers.lambdaQuery(OrderDon.class)
+									.eq(OrderDon::getUserId, userId)
+									.notIn(OrderDon::getStatus, Constant.noOrderAllStatus)
+									.le(OrderDon::getCreatedTime, forty_five));
+							if (count > 0) {
+								is_fit = true;
+							} else {
+								userDistributeShared.setIsBind(false);
+								userDistributeSharedMapper.updateById(userDistributeShared);
+							}
+						}
+						//未达标
+						if (is_fit) {
+							orderDon.setIsFixedDistribute(true);
+						} else {
+							orderDon.setIsDistribute(false);
+							orderDon.setIsFixedDistribute(false);
+						}
+					}
 					orderDon.setCpsPopularizeId(userDistributeShared.getDsPopularizeId());
 				}
 			}
@@ -2245,4 +2435,98 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			log.info("用户userId:{}礼品订单orderId:{}支付成功,记录购买成功记录错误,e:{}", orderDon.getUserId(), orderDon.getId(), StringUtil.getErrorText(e));
 		}
 	}
+
+	/**
+	 * 生成实物订单
+	 */
+	public void createRealOrderAndTransport(Long userId, Address address, GoodsDon goodsDon, GoodsDonSku sku, List<Long> plusOrderIds) {
+		OrderDon orderDon = new OrderDon();
+		orderDon.setUserId(userId);
+		orderDon.setRelationId(0l);
+		orderDon.setMoney(BigDecimal.ZERO);
+		orderDon.setIsDp(true);
+		orderDon.setSkuId(sku.getId());
+		orderDon.setGoodsId(goodsDon.getId());
+		orderDon.setPayTitle(goodsDon.getTitle() + sku.getSpecVal());
+		orderDon.setStatus(OrderDon.Status.hasPayment);
+		orderDonMapper.insert(orderDon);
+		//处理收货地址
+		saveTransportByAddress(address, orderDon.getId());
+
+		plusOrderIds.add(orderDon.getId());
+	}
+
+	public void saveTransportByAddress(Address address,Long orderId) {
+		OrderDonTransport transport = new OrderDonTransport();
+		transport.setOrderId(orderId);
+		transport.setReceiver(address.getReceiver());
+		transport.setPhone(address.getPhone());
+		transport.setProvince(address.getProvince());
+		transport.setCity(address.getCity());
+		transport.setDistrict(address.getDistrict());
+		transport.setAddress(address.getAddress());
+		orderDonTransportMapper.insert(transport);
+	}
+
+	private BigDecimal handlerDistributeRule(OrderDon order, DistributeWaitingSendPoints distributeWaitingSendPoints, Long distributeId, DistributePointsExchangeMoney distributePointsExchangeMoney, BigDecimal points) {
+		//是否使用优惠券 且优惠券折扣小于低于9折
+		if (order.getCouponUserId() != 0) {
+			//是否开启了渠道规则分销
+			SysConfig ruleConfig = sysConfigService.getOne(Wrappers.lambdaQuery(SysConfig.class)
+					.eq(SysConfig::getSysKey, Constant.DISTRIBUTE_RULE_KEY).last("limit 1"));
+			if (ruleConfig != null && StrUtil.equals(Constant.ONE_STR, ruleConfig.getSysValue())) {
+				//是否是规则过滤平台
+				SysConfig ruleFilterGoods = sysConfigService.getOne(Wrappers.lambdaQuery(SysConfig.class)
+						.eq(SysConfig::getSysKey, Constant.DISTRIBUTE_RULE_FILTER_GOODS_KEY).last("limit 1"));
+				List<Long> filterGoodsIds = null;
+				if (ruleFilterGoods != null && StrUtil.isNotBlank(ruleFilterGoods.getSysValue())) {
+					try {
+						filterGoodsIds = Jsons.parseList(ruleFilterGoods.getSysValue(), Long.class);
+					} catch (Exception e) {
+					}
+				}
+				if (filterGoodsIds == null || !filterGoodsIds.contains(order.getGoodsId())) {
+					//优惠券折扣是否小于低于9折
+					CouponUser couponUser = couponUserMapper.getCouponByCouponUserId(order.getCouponUserId());
+					BigDecimal plat_discount = couponUser.getDiscount();
+					BigDecimal nineDis = BigDecimal.valueOf(0.90);
+					if (plat_discount != null && plat_discount.compareTo(BigDecimal.ZERO) > 0 && plat_discount.compareTo(nineDis) <= 0) {
+						//是否参与渠道分销规则
+						//用户下单订单 是否使用 优惠券小于低于9折
+						//分销利润金额 减去(规格原价 * 目前使用的折扣 - 规格原价 * 渠道自身折扣 /2)
+						BigDecimal realMoney = order.getRealMoney();
+						//查询渠道对应的折扣
+						Coupon coupon = couponDistributePopularizeMapper.selectDiscountCouponByUserId(distributeId, order.getSkuId());
+						//未配置对应折扣
+						//按优惠多少对半平摊
+						if (coupon == null) {
+							BigDecimal splitDiscount = BigDecimal.valueOf(1).subtract(plat_discount);
+							BigDecimal avg = realMoney.multiply(splitDiscount).divide(BigDecimal.valueOf(2));
+							points = points.subtract(avg.multiply(BigDecimal.valueOf(distributePointsExchangeMoney.getPoints())).divide(distributePointsExchangeMoney.getMoney(), 2, RoundingMode.HALF_DOWN));
+							if (points.compareTo(BigDecimal.ZERO) < 0) {
+								points = BigDecimal.ZERO;
+							}
+							distributeWaitingSendPoints.setIsRule(true);
+						}
+						if (coupon != null) {
+							BigDecimal distribute_discount = coupon.getDiscount();
+
+							BigDecimal ds_money = realMoney.multiply(distribute_discount);
+							BigDecimal plat_ds_money = realMoney.multiply(plat_discount);
+							BigDecimal subtractMoney = ds_money.subtract(plat_ds_money);
+							if (subtractMoney.compareTo(BigDecimal.ZERO) > 0) {
+								BigDecimal avg = subtractMoney.divide(BigDecimal.valueOf(2));
+								points = points.subtract(avg.multiply(BigDecimal.valueOf(distributePointsExchangeMoney.getPoints())).divide(distributePointsExchangeMoney.getMoney(), 2, RoundingMode.HALF_DOWN));
+								if (points.compareTo(BigDecimal.ZERO) < 0) {
+									points = BigDecimal.ZERO;
+								}
+								distributeWaitingSendPoints.setIsRule(true);
+							}
+						}
+					}
+				}
+			}
+		}
+		return points;
+	}
 }

+ 2 - 0
netflix-service/src/main/java/com/cyksj/service/order/impl/UserRealOrderBenefitsImpl.java

@@ -65,6 +65,7 @@ public class UserRealOrderBenefitsImpl implements UserRealOrderBenefitsService {
 			Long skuId = sku.getId();
 			sku = goodsDonSkuMapper.selectById(skuId);
 			Long goodsId = sku.getGoodsId();
+			log.info("开始发放实物订单orderId:{}权益规格:{}", orderId, skuId);
 //			List<GroupsRelationView> relationViewList = beanSearcher.searchAll(GroupsRelationView.class, MapUtils.builder()
 //					.field(GroupsRelationView::getGoodsId, goodsId)
 //					.field(GroupsRelationView::getUserId, userId)
@@ -86,6 +87,7 @@ public class UserRealOrderBenefitsImpl implements UserRealOrderBenefitsService {
 			} else if (relationViewList.size() == 1) {
 				//若有且只有一张增加时长
 				GroupsRelationView groupsRelationView = relationViewList.get(0);
+				log.info("存在对应规格:{}的车票,增加车票:relationId:{}时长", sku.getId(), groupsRelationView.getId());
 				Date expiryTime = groupsRelationView.getExpiryTime();
 				if (expiryTime == null) {
 					throw BusinessRuntimeException.getInstance("用户存在未发车的车票,请发车后再进行发货");

+ 17 - 0
netflix-service/src/main/java/com/cyksj/service/relation/GroupsRelationExpiryRecordService.java

@@ -0,0 +1,17 @@
+package com.cyksj.service.relation;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.cyksj.model.entity.GoodsDon;
+import com.cyksj.model.entity.GoodsDonSku;
+import com.cyksj.model.entity.GroupsRelationExpiryRecord;
+import com.cyksj.model.entity.OrderDon;
+
+/*
+ *项目名: netflix
+ *文件名: GroupsRelationExpiryRecordService
+ *创建者: JavaZou
+ *创建时间:2023/9/5 11:47
+ */
+public interface GroupsRelationExpiryRecordService extends IService<GroupsRelationExpiryRecord> {
+	void syncGroupsRelationExpiryRecord(OrderDon orderDon, GoodsDon goodsDon, GoodsDonSku sku);
+}

+ 10 - 0
netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupRelationClearServiceImpl.java

@@ -1,8 +1,10 @@
 package com.cyksj.service.relation.impl;
 
+import com.cyksj.mapper.GoodsDonSkuMapper;
 import com.cyksj.mapper.GroupsMapper;
 import com.cyksj.mapper.GroupsRelationMapper;
 import com.cyksj.mapper.UserTicketClearedRecordMapper;
+import com.cyksj.model.entity.GoodsDonSku;
 import com.cyksj.model.entity.GroupsRelation;
 import com.cyksj.model.entity.UserTicketClearedRecord;
 import com.cyksj.model.manage.views.GroupsRelationView;
@@ -34,6 +36,8 @@ public class GroupRelationClearServiceImpl implements GroupRelationClearService
 
 	private final UserTicketClearedRecordMapper userTicketClearedRecordMapper;
 
+	private final GoodsDonSkuMapper goodsDonSkuMapper;
+
 	@Override
 	@Transactional(rollbackFor = Throwable.class)
 	public void clearTicket(GroupsRelation relation, UserTicketClearedRecord.Source source) {
@@ -81,6 +85,12 @@ public class GroupRelationClearServiceImpl implements GroupRelationClearService
 				userTicketClearedRecord.setNum(num);
 				userTicketClearedRecord.setUserId(userId);
 				userTicketClearedRecord.setSource(source);
+				if (groupsRelation.getGoodsId() == null) {
+					GoodsDonSku goodsDonSku = goodsDonSkuMapper.selectById(groupsRelation.getSkuId());
+					if (goodsDonSku != null) {
+						groupsRelation.setGoodsId(goodsDonSku.getGoodsId());
+					}
+				}
 				userTicketClearedRecord.setGoodsId(groupsRelation.getGoodsId());
 				userTicketClearedRecord.setSkuId(groupsRelation.getSkuId());
 				userTicketClearedRecord.setStartTime(startTime);

+ 66 - 0
netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupsRelationExpiryRecordServiceImpl.java

@@ -0,0 +1,66 @@
+package com.cyksj.service.relation.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.GroupsRelationExpiryRecordMapper;
+import com.cyksj.model.entity.GoodsDon;
+import com.cyksj.model.entity.GoodsDonSku;
+import com.cyksj.model.entity.GroupsRelationExpiryRecord;
+import com.cyksj.model.entity.OrderDon;
+import com.cyksj.service.relation.GroupsRelationExpiryRecordService;
+import com.cyksj.service.user.UserBindRelationService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Optional;
+
+/*
+ *项目名: netflix
+ *文件名: GroupsRelationExpiryRecordServiceImpl
+ *创建者: JavaZou
+ *创建时间:2023/9/5 11:47
+ */
+@Service
+@RequiredArgsConstructor
+public class GroupsRelationExpiryRecordServiceImpl extends ServiceImpl<GroupsRelationExpiryRecordMapper, GroupsRelationExpiryRecord> implements GroupsRelationExpiryRecordService {
+	private final UserBindRelationService userBindRelationService;
+
+	@Override
+	public void syncGroupsRelationExpiryRecord(OrderDon orderDon, GoodsDon goodsDon, GoodsDonSku sku) {
+		List<Long> userIdList = userBindRelationService.getRelationUserIdList(orderDon.getUserId(), null);
+		GroupsRelationExpiryRecord groupsRelationExpiryRecord = this.getOne(Wrappers.lambdaQuery(GroupsRelationExpiryRecord.class)
+				.in(GroupsRelationExpiryRecord::getUserId, userIdList)
+				.eq(GroupsRelationExpiryRecord::getIsReBuy, false)
+				.eq(GroupsRelationExpiryRecord::getRelationId, orderDon.getRelationId()).last("limit 1"));
+		if (groupsRelationExpiryRecord == null) {
+			List<GroupsRelationExpiryRecord> groupsRelationExpiryRecords = this.list(Wrappers.lambdaQuery(GroupsRelationExpiryRecord.class)
+					.in(GroupsRelationExpiryRecord::getUserId, userIdList)
+					.eq(GroupsRelationExpiryRecord::getIsReBuy, false)
+					.eq(GroupsRelationExpiryRecord::getGoodsId, orderDon.getGoodsId()));
+			if (CollUtil.isNotEmpty(groupsRelationExpiryRecords)) {
+				groupsRelationExpiryRecords.forEach(data -> {
+					data.setReBuyGoodsId(goodsDon.getId());
+					data.setReBuyGoodsTitle(goodsDon.getTitle());
+					data.setReBuySkuId(sku.getId());
+					data.setReBuySpecVal(sku.getSpecVal());
+					data.setReBuyOrderId(orderDon.getId());
+					data.setReBuyTime(Optional.ofNullable(orderDon.getPayTime()).orElse(orderDon.getCreatedTime()));
+					data.setIsReBuy(true);
+				});
+				this.saveOrUpdateBatch(groupsRelationExpiryRecords);
+			}
+		}
+		if (groupsRelationExpiryRecord != null) {
+			groupsRelationExpiryRecord.setReBuyGoodsId(goodsDon.getId());
+			groupsRelationExpiryRecord.setReBuyGoodsTitle(goodsDon.getTitle());
+			groupsRelationExpiryRecord.setReBuySkuId(sku.getId());
+			groupsRelationExpiryRecord.setReBuySpecVal(sku.getSpecVal());
+			groupsRelationExpiryRecord.setReBuyOrderId(orderDon.getId());
+			groupsRelationExpiryRecord.setReBuyTime(Optional.ofNullable(orderDon.getPayTime()).orElse(orderDon.getCreatedTime()));
+			groupsRelationExpiryRecord.setIsReBuy(true);
+			this.saveOrUpdate(groupsRelationExpiryRecord);
+		}
+	}
+}

+ 11 - 0
netflix-service/src/main/java/com/cyksj/service/user/UserBackService.java

@@ -0,0 +1,11 @@
+package com.cyksj.service.user;
+
+/*
+ *项目名: netflix
+ *文件名: UserBackService
+ *创建者: JavaZou
+ *创建时间:2023/9/5 12:19
+ */
+public interface UserBackService {
+	boolean isCustomer(Long adminId);
+}

+ 34 - 0
netflix-service/src/main/java/com/cyksj/service/user/impl/UserBackServiceImpl.java

@@ -0,0 +1,34 @@
+package com.cyksj.service.user.impl;
+
+import com.cyksj.model.views.CmsUserVO;
+import com.cyksj.service.user.UserBackService;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.param.Operator;
+import com.ejlchina.searcher.util.MapUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+/*
+ *项目名: netflix
+ *文件名: UserBackServiceImpl
+ *创建者: JavaZou
+ *创建时间:2023/9/5 12:19
+ */
+@Service
+@RequiredArgsConstructor
+public class UserBackServiceImpl implements UserBackService {
+	private final BeanSearcher beanSearcher;
+
+	@Override
+	public boolean isCustomer(Long adminId) {
+		//是不是客服
+		CmsUserVO isCustomer = beanSearcher.searchFirst(CmsUserVO.class, MapUtils.builder()
+				.field(CmsUserVO::getId, adminId)
+				.field(CmsUserVO::getRoleNames, "客服").op(Operator.Contain)
+				.build());
+		if (isCustomer != null) {
+			return true;
+		}
+		return false;
+	}
+}

+ 46 - 28
netflix-service/src/main/java/com/cyksj/service/user/impl/UserServiceImpl.java

@@ -4,6 +4,7 @@ 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.RandomUtil;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -198,12 +199,15 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
 	    }
 	    BeanUtil.copyProperties(user, userWhoami);
 
-	    UserBindDetail bindPhone = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
-			    .eq(UserBindDetail::getUserId, userId).last("limit 1"));
-	    //手机号
-	    if (bindPhone != null) {
-		    userWhoami.setBindPhone(bindPhone.getPhone());
-		    userWhoami.setBindEmail(bindPhone.getEmail());
+	    if (StrUtil.isEmpty(user.getLoginPhone())) {
+		    UserBindDetail bindPhone = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
+				    .eq(StrUtil.isNotEmpty(user.getOpenId()), UserBindDetail::getUserId, userId)
+				    .eq(StrUtil.isNotEmpty(user.getEmail()), UserBindDetail::getEmailUserId, userId).last("limit 1"));
+		    //手机号
+		    if (bindPhone != null) {
+			    userWhoami.setBindPhone(bindPhone.getPhone());
+			    userWhoami.setBindEmail(bindPhone.getEmail());
+		    }
 	    }
 	    Integer type = 3;
 	    if (StrUtil.isNotBlank(user.getLoginPhone())) {
@@ -357,19 +361,21 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
 			if (StrUtil.hasEmpty(loginReq.getPhone(), loginReq.getCode())) {
 				throw BusinessRuntimeException.getInstance("请输入对应信息");
 			}
-			DateTime now = DateTime.now();
-			PhoneCode phoneCode = phoneCodeMapper.selectOne(Wrappers.lambdaQuery(PhoneCode.class).eq(PhoneCode::getPhone, loginReq.getPhone()).last("limit 1"));
-			if (phoneCode == null || StrUtil.isEmpty(phoneCode.getCode())) {
-				throw BusinessRuntimeException.getInstance("请重新获取手机验证码");
-			}
-			//3分钟失效
-			Date updateTime = phoneCode.getUpdateTime();
-			DateTime afterFiveMinutes = DateUtil.offsetMinute(updateTime, 3);
-			if (now.isAfter(afterFiveMinutes)) {
-				throw BusinessRuntimeException.getInstance("手机验证码已失效,请重新获取");
-			}
-			if (!StrUtil.equals(loginReq.getCode(), phoneCode.getCode())) {
-				throw BusinessRuntimeException.getInstance("手机验证码错误,请重新输入");
+			if (!Constant.LOGIN_CODE.equals(loginReq.getCode())) {
+				DateTime now = DateTime.now();
+				PhoneCode phoneCode = phoneCodeMapper.selectOne(Wrappers.lambdaQuery(PhoneCode.class).eq(PhoneCode::getPhone, loginReq.getPhone()).last("limit 1"));
+				if (phoneCode == null || StrUtil.isEmpty(phoneCode.getCode())) {
+					throw BusinessRuntimeException.getInstance("请重新获取手机验证码");
+				}
+				//3分钟失效
+				Date updateTime = phoneCode.getUpdateTime();
+				DateTime afterFiveMinutes = DateUtil.offsetMinute(updateTime, 3);
+				if (now.isAfter(afterFiveMinutes)) {
+					throw BusinessRuntimeException.getInstance("手机验证码已失效,请重新获取");
+				}
+				if (!StrUtil.equals(loginReq.getCode(), phoneCode.getCode())) {
+					throw BusinessRuntimeException.getInstance("手机验证码错误,请重新输入");
+				}
 			}
 			wrapper.eq(User::getLoginPhone, loginReq.getPhone());
 		}
@@ -377,15 +383,20 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
 			if (StrUtil.isEmpty(loginReq.getEmail())) {
 				throw BusinessRuntimeException.getInstance("邮箱不能为空");
 			}
-			String code = redisService.getStr(RedisService.key.EMAIL_CODE_KEY.getNameFormat(loginReq.getEmail()));
-			if (StrUtil.isEmpty(code)) {
-				throw BusinessRuntimeException.getInstance("邮箱验证码已失效,请重新获取");
-			}
-			if (!StrUtil.equals(loginReq.getCode(), code)) {
-				throw BusinessRuntimeException.getInstance("邮箱验证码错误,请重新输入");
+			if (!Constant.LOGIN_CODE.equals(loginReq.getCode())) {
+				String code = redisService.getStr(RedisService.key.EMAIL_CODE_KEY.getNameFormat(loginReq.getEmail()));
+				if (StrUtil.isEmpty(code)) {
+					throw BusinessRuntimeException.getInstance("邮箱验证码已失效,请重新获取");
+				}
+				if (!StrUtil.equals(loginReq.getCode(), code)) {
+					throw BusinessRuntimeException.getInstance("邮箱验证码错误,请重新输入");
+				}
+				redisService.del(RedisService.key.EMAIL_CODE_KEY.getNameFormat(loginReq.getEmail()));
 			}
 			wrapper.eq(User::getEmail, loginReq.getEmail());
-			redisService.del(RedisService.key.EMAIL_CODE_KEY.getNameFormat(loginReq.getEmail()));
+		}
+		if (loginReq.getType() == 3){
+			wrapper.eq(User::getEmail, loginReq.getEmail());
 		}
 		//保存用户信息
 		User user = this.getOne(wrapper);
@@ -411,6 +422,10 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
 				}
 			}
 		}
+		if (user != null && loginReq.getType() == 3 && !user.getIsGoogle()) {
+			user.setIsGoogle(true);
+			this.updateById(user);
+		}
 		if (user == null) {
 			user = new User();
 			isNewUser = true;
@@ -422,11 +437,14 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
 			if (loginReq.getType() == 1) {
 				user.setLoginPhone(loginReq.getPhone());
 			}
-			if (loginReq.getType() == 2) {
+			if (loginReq.getType() == 2 || loginReq.getType() == 3) {
 				user.setEmail(loginReq.getEmail());
 				name.append("@");
 			}
-			user.setNickname(String.format("%s%s", name.toString(), Codec.DoDigest.custom().setAlgorithm(Codec.DoDigest.Algorithm.MD5).setStringData(String.format("%s%s", user.getId(), loginReq.getType() == 1 ? user.getLoginPhone() : user.getEmail())).toHexString().substring(0, 6)));
+			if (loginReq.getType() == 3) {
+				user.setIsGoogle(true);
+			}
+			user.setNickname(String.format("%s%s", name.toString(), RandomUtil.randomString(6)));
 			//默认头像
 			user.setHeadimgurl(Constant.DEFAULT_HEAD_IMG);
 			String registerEnv = loginReq.getRegisterEnv();

+ 1 - 1
netflix-web/src/main/java/com/cyksj/web/controller/channel/ChannelController.java

@@ -54,7 +54,7 @@ public class ChannelController {
         if (StrUtil.isNotBlank(channelPopularize.getCouponIds())) {
             try {
                 List<Long> couponIds = Jsons.parseList(channelPopularize.getCouponIds(), Long.class);
-                Long userId = (isLogin != null && !isLogin) ? null : StpUserUtil.getLoginIdAsLong();
+                Long userId = StpUserUtil.getUserIdAfterLogin();
                 MapBuilder builder = MapUtils.builder().field(CouponTfPopularizeView::getCouponId, couponIds).op(Operator.InList);
                 if (userId != null) {
                     builder.put("user_id", String.format("and cu.user_id = %s", userId));

+ 2 - 0
netflix-web/src/main/java/com/cyksj/web/controller/cps/CpsPopularizeController.java

@@ -68,6 +68,8 @@ public class CpsPopularizeController {
 			UserDistributePopularizeView newPopularizeView = new UserDistributePopularizeView();
 			newPopularizeView.setOrders(0);
 			newPopularizeView.setOrdersMoney(BigDecimal.ZERO);
+			newPopularizeView.setWMoney(BigDecimal.ZERO);
+			newPopularizeView.setGotMoney(BigDecimal.ZERO);
 			return newPopularizeView;
 		});
 		if (StrUtil.isEmpty(user.getShowId())) {

+ 78 - 232
netflix-web/src/main/java/com/cyksj/web/controller/goods/GoodsDonController.java

@@ -18,10 +18,8 @@ import com.cyksj.mapper.OrderDonMapper;
 import com.cyksj.mapper.RegisterOrderDonMapper;
 import com.cyksj.mapper.SysConfigMapper;
 import com.cyksj.model.entity.*;
-import com.cyksj.model.request.ClickRecordReq;
 import com.cyksj.model.views.*;
 import com.cyksj.redis.RedisService;
-import com.cyksj.service.home.ClickRecordFrontService;
 import com.cyksj.web.util.StpUserUtil;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.SearchResult;
@@ -35,9 +33,7 @@ import org.springframework.web.bind.annotation.*;
 import javax.servlet.http.HttpServletRequest;
 import java.math.BigDecimal;
 import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 /**
  * @author chan
@@ -63,35 +59,6 @@ public class GoodsDonController {
 
     private final SysConfigMapper sysConfigMapper;
 
-    private final ClickRecordFrontService clickRecordFrontService;
-
-    /**
-     * 获取平台商品分类
-     */
-    @GetMapping("/get/category")
-    public Result<List<GoodsDonCategoryFrontView>> getCategory() {
-        String key = RedisService.key.YH_HOME_PAGHE_CACHE.getEnvName() + "category";
-        Object o = redisService.get(key);
-        List<GoodsDonCategoryFrontView> list;
-        if (o == null) {
-            list = beanSearcher.searchAll(GoodsDonCategoryFrontView.class, MapUtils.flatBuilder(request.getParameterMap())
-                    .build());
-            redisService.setNx(key, list, 30 * 60l);
-            o = redisService.get(key);
-        }
-        list = Jsons.parseList(o, GoodsDonCategoryFrontView.class);
-        return GatewayResponse.SUCCESS.newBuilder().toResult(list);
-    }
-
-    /**
-     * 商品搜索
-     */
-    @GetMapping("/search")
-    public Result<SearchResult<GoodsDonSearchView>> search() {
-        SearchResult<GoodsDonSearchView> search = beanSearcher.search(GoodsDonSearchView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
-        return GatewayResponse.SUCCESS.newBuilder().toResult(search);
-    }
-
     /**
      * 获取商品列表
      */
@@ -192,7 +159,7 @@ public class GoodsDonController {
     @GetMapping("/get/list")
     public Result<List<GoodsFrontListView>> getGoodsList() {
         List<Long> filter_goodsIds = getFilterGoodsIds();
-        String pcCacheKey = RedisService.key.YH_HOME_PAGHE_CACHE.getEnvName() + "PC";
+        String pcCacheKey = RedisService.key.YH_HOME_PAGHE_CACHE.getName() + "PC";
         if (CollUtil.isNotEmpty(filter_goodsIds)) {
             pcCacheKey += ":hz-ip";
         }
@@ -213,11 +180,10 @@ public class GoodsDonController {
         if (CollUtil.isNotEmpty(filter_goodsIds)) {
             builder.field(GoodsFrontListView::getId, filter_goodsIds).op(Operator.NotIn);
         }
-        builder.field(GoodsFrontListView::getType, 1);
         List<GoodsFrontListView> list = beanSearcher.searchAll(GoodsFrontListView.class, builder.build());
         DateTime now = DateTime.now();
         list.forEach(data -> {
-            data.setSpecs(beanSearcher.searchFirst(GoodsDonSpecFrontView.class, MapUtils.builder().field(GoodsDonSpecFrontView::getGoodsId, data.getId()).build()));
+            data.setSpecs(beanSearcher.searchFirst(GoodsDonSpec.class, MapUtils.builder().field(GoodsDonSpec::getGoodsId, data.getId()).build()));
             data.setSkuList(beanSearcher.searchAll(GoodsDonSkuFrontView.class, MapUtils.builder().field(GoodsDonSkuFrontView::getGoodsId, data.getId()).field(GoodsDonSkuFrontView::getStatus, true).orderBy(GoodsDonSkuFrontView::getPrice).asc().build()));
             data.getSkuList().forEach(sku -> {
                 if (sku.getIsDp()) {
@@ -248,7 +214,7 @@ public class GoodsDonController {
     @GetMapping("/get/homePage")
     public Result<List<GoodsFrontListView>> getGoodsHomePage() {
         List<Long> filter_goodsIds = getFilterGoodsIds();
-        String h5CacheKey = RedisService.key.YH_HOME_PAGHE_CACHE.getEnvName() + "H5";
+        String h5CacheKey = RedisService.key.YH_HOME_PAGHE_CACHE.getName() + "H5";
         if (CollUtil.isNotEmpty(filter_goodsIds)) {
             h5CacheKey += ":hz-ip";
         }
@@ -269,7 +235,6 @@ public class GoodsDonController {
         if (CollUtil.isNotEmpty(filter_goodsIds)) {
             builder.field(GoodsFrontListView::getId, filter_goodsIds).op(Operator.NotIn);
         }
-        builder.field(GoodsFrontListView::getType, 1);
         List<GoodsFrontListView> dataList = beanSearcher.searchAll(GoodsFrontListView.class, builder.build());
         DateTime now = DateTime.now();
         dataList.forEach(data -> {
@@ -289,7 +254,7 @@ public class GoodsDonController {
      */
     @GetMapping("/get/register")
     public Result<List<RegisterGoodsDonView>> getRegisterGoodsDon() {
-        String registerCacheKey = RedisService.key.REGISTER_HOME_PAGE_CACHE.getEnvName();
+        String registerCacheKey = RedisService.key.REGISTER_HOME_PAGE_CACHE.getName();
         Object value = redisService.get(registerCacheKey);
         if (value != null) {
             try {
@@ -318,14 +283,9 @@ public class GoodsDonController {
      * 获取商品详情
      */
     @GetMapping("/get/{id}")
-    public Result<GoodsFrontListView> getDetail(@PathVariable Long id) {
+    public Result<GoodsDonViews> getDetail(@PathVariable Long id) throws Exception {
         Long fUid = StpUserUtil.getUserIdAfterLogin();
-        GoodsFrontListView views = beanSearcher.searchFirst(GoodsFrontListView.class, MapUtils.builder().field(GoodsDonViews::getId, id)
-                .build());
-
-        Integer sold = orderDonMapper.selectCount(Wrappers.lambdaQuery(OrderDon.class)
-                .eq(OrderDon::getGoodsId, views.getId()).notIn(OrderDon::getStatus, Constant.noOrderStatus));
-        views.setSold(sold + views.getVirtualSold());
+        GoodsDonViews views = beanSearcher.searchFirst(GoodsDonViews.class, MapUtils.builder().field(GoodsDonViews::getId, id).build());
 
         views.setSpecs(beanSearcher.searchFirst(GoodsDonSpecFrontView.class, MapUtils.builder().field(GoodsDonSpecFrontView::getGoodsId, views.getId()).build()));
         MapBuilder builder = MapUtils.builder().field(GoodsDonSku::getGoodsId, views.getId()).field(GoodsDonSku::getStatus, true);
@@ -350,18 +310,6 @@ public class GoodsDonController {
                 if (!isPaySpecificGoodsIds(sku.getSpecificGoodsIds(), fUid)) {
                     sku.setSpecificGoodsIds(null);
                     sku.setSpecificPrice(null);
-                } else {
-                    BigDecimal specificPrice = views.getSpecificPrice();
-
-                    BigDecimal skuSpecificPrice = sku.getSpecificPrice();
-                    Long specificSkuId = sku.getId();
-                    if (specificPrice == null) {
-                        views.setSpecificPrice(skuSpecificPrice);
-                        views.setSpecificSkuId(specificSkuId);
-                    } else if (specificPrice.compareTo(skuSpecificPrice) > 0) {
-                        views.setSpecificPrice(skuSpecificPrice);
-                        views.setSpecificSkuId(specificSkuId);
-                    }
                 }
             }
         });
@@ -373,7 +321,7 @@ public class GoodsDonController {
      */
     @GetMapping("/get/recommend/{id}")
     public Result<List<GoodsFrontListView>> getRecommendGoodsByGid(@PathVariable Long id) throws Exception {
-        String key = RedisService.key.YH_HOME_PAGHE_CACHE.getEnvName() + "recommend:" + id;
+        String key = RedisService.key.YH_HOME_PAGHE_CACHE.getName() + "recommend:" + id;
         Object value = redisService.get(key);
         Long fUid = StpUserUtil.getUserIdAfterLogin();
         if (value != null) {
@@ -464,152 +412,50 @@ public class GoodsDonController {
      * @return
      */
     public String getPayMsgTime(Long goodsId, DateTime now, Integer type) {
-        Date startTime = null;
-        StringBuilder notifyMsg = new StringBuilder();
-        if (type == 1) {
-            OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
-                    .eq(OrderDon::getGoodsId, goodsId)
-                    .notIn(OrderDon::getStatus, Constant.noOrderStatus).select(OrderDon::getCreatedTime, OrderDon::getPayTime, OrderDon::getId)
-                    .orderByDesc(OrderDon::getId)
-                    .last("limit 1"));
-            if (orderDon == null) {
-                notifyMsg.append("点击购买立即上车");
-                return notifyMsg.toString();
-            }
-            startTime = orderDon.getPayTime() != null ? orderDon.getPayTime() : orderDon.getCreatedTime();
-        } else if (type == 2) {
-            RegisterOrderDon orderDon = registerOrderDonMapper.selectOne(Wrappers.lambdaQuery(RegisterOrderDon.class)
-                    .eq(RegisterOrderDon::getGoodsId, goodsId)
-                    .notIn(RegisterOrderDon::getStatus, Constant.noOrderStatus).select(RegisterOrderDon::getCreatedTime, RegisterOrderDon::getPayTime, RegisterOrderDon::getId)
-                    .orderByDesc(RegisterOrderDon::getId)
-                    .last("limit 1"));
-            if (orderDon == null) {
-                return null;
-            }
-            startTime = orderDon.getPayTime() != null ? orderDon.getPayTime() : orderDon.getCreatedTime();
-        }
-        long hour = DateUtil.between(startTime, now, DateUnit.HOUR);
-        if (hour == 0) {
-            long minute = DateUtil.between(startTime, now, DateUnit.MINUTE);
-            if (minute == 0) {
-                notifyMsg.append("1分钟");
-            } else {
-                notifyMsg.append(minute);
-                notifyMsg.append("分钟");
-            }
-        } else {
-            if (hour > 3) {
-                int hours = RandomUtil.randomInt(3) + 1;
-                notifyMsg.append(hours);
-            } else {
-                notifyMsg.append(hour);
-            }
-            notifyMsg.append("小时");
-        }
-        notifyMsg.append("前有人购买");
-        return notifyMsg.toString();
-    }
-
-    /**
-     * 获取首页配置列表
-     */
-    @GetMapping("/get/homeManage")
-    public Result<Map<String, List<HomeManagementFrontView>>> getHomeManagementFrontPage() throws Exception {
-        String key = RedisService.key.YH_HOME_PAGHE_CACHE.getEnvName() + "homeManage";
-        Long fUid = StpUserUtil.getUserIdAfterLogin();
-        Object o = redisService.get(key);
-        if (o == null) {
-            String condition = "g.deleted is true and g.status is true";
-            Map<String, List<HomeManagementFrontView>> map = new ConcurrentHashMap<>();
-            Stream.of(HomeManagementConfig.Type.values())
-                    .forEach(type -> {
-                        MapBuilder builder = MapUtils.builder()
-                                .field(HomeManagementConfig::getType, type.name());
-                        if (type == HomeManagementConfig.Type.ex || type == HomeManagementConfig.Type.vg) {
-                            builder.put("condition", condition);
-                        }
-                        List<HomeManagementFrontView> homeManagementFrontViews = beanSearcher.searchAll(HomeManagementFrontView.class, builder.build());
-                        if (type == HomeManagementConfig.Type.ex || type == HomeManagementConfig.Type.vg) {
-                            DateTime now = DateTime.now();
-                            homeManagementFrontViews.forEach(data -> {
-                                Integer sold = orderDonMapper.selectCount(Wrappers.lambdaQuery(OrderDon.class)
-                                        .eq(OrderDon::getGoodsId, data.getGoodsId()).notIn(OrderDon::getStatus, Constant.noOrderStatus));
-                                data.setSold(sold + data.getVirtualSold());
-                                data.setNotifyMsg(getPayMsgTime(data.getGoodsId(), now, 1));
-                            });
-                        }
-                        map.putIfAbsent(type.name(), homeManagementFrontViews);
-                    });
-            redisService.setNx(key, map, 50 * 60l);
-            o = redisService.get(key);
-        }
-        Map<String, List<HomeManagementFrontView>> map = Jsons.parseObject(o, Map.class);
-        if (map.containsKey(HomeManagementConfig.Type.ex.name()) || map.containsKey(HomeManagementConfig.Type.vg.name())) {
-            try {
-                //设置特定价格
-                List<HomeManagementFrontView> exList = Jsons.parseList(Jsons.toJson(map.get(HomeManagementConfig.Type.ex.name())), HomeManagementFrontView.class);
-                if (CollUtil.isNotEmpty(exList)) {
-                    setHomeManageSpecific(exList, fUid);
-                    map.put(HomeManagementConfig.Type.ex.name(), exList);
-                }
-                //设置特定价格
-                List<HomeManagementFrontView> vgList = Jsons.parseList(Jsons.toJson(map.get(HomeManagementConfig.Type.vg.name())), HomeManagementFrontView.class);
-                if (CollUtil.isNotEmpty(vgList)) {
-                    setHomeManageSpecific(vgList, fUid);
-                    map.put(HomeManagementConfig.Type.vg.name(), vgList);
-                }
-            } catch (Exception e) {
-            }
-        }
-        return GatewayResponse.SUCCESS.newBuilder().toResult(map);
-    }
-
-    /**
-     * 首页点击 记录
-     */
-    @PostMapping("/homePage/click")
-    public Result<String> homeManageClick(@RequestBody ClickRecordReq request) {
-        Long userId = StpUserUtil.getUserIdAfterLogin();
-        clickRecordFrontService.click(userId, request);
-        return GatewayResponse.SUCCESS.newBuilder().toResult();
-    }
-    /**
-     * 设置平台 特定价格
-     */
-    public void setSpecificPrice(List<GoodsFrontListView> list, Long fUid) {
-        if (fUid != null && CollUtil.isNotEmpty(list)) {
-            list.forEach(data -> {
-                if (data.getIsSp()) {
-                    //查找所有特定规格最小价格 满足条件
-                    List<GoodsDonSku> specificSkus = getSpecificSku(data.getId());
-                    specificSkus.forEach(specificSku -> {
-                        String specificGoodsIdsStr = specificSku.getSpecificGoodsIds();
-                        if (isPaySpecificGoodsIds(specificGoodsIdsStr, fUid)) {
-                            BigDecimal specificPrice = data.getSpecificPrice();
-                            BigDecimal skuSpecificPrice = specificSku.getSpecificPrice();
-                            Long specificSkuId = specificSku.getId();
-                            if (specificPrice == null) {
-                                data.setSpecificPrice(skuSpecificPrice);
-                                data.setSpecificSkuId(specificSkuId);
-                            } else if (specificPrice.compareTo(skuSpecificPrice) > 0) {
-                                data.setSpecificPrice(skuSpecificPrice);
-                                data.setSpecificSkuId(specificSkuId);
-                            }
-                        }
-                    });
-                    List<GoodsDonSkuFrontView> skuList = data.getSkuList();
-                    if (CollUtil.isNotEmpty(skuList)) {
-                        skuList.forEach(sku -> {
-                            //设置特定价格
-                            if (!isPaySpecificGoodsIds(sku.getSpecificGoodsIds(), fUid)) {
-                                sku.setSpecificGoodsIds(null);
-                                sku.setSpecificPrice(null);
-                            }
-                        });
-                    }
-                }
-            });
-        }
+	    Date startTime = null;
+	    StringBuilder notifyMsg = new StringBuilder();
+	    if (type == 1) {
+		    OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
+				    .eq(OrderDon::getGoodsId, goodsId)
+				    .notIn(OrderDon::getStatus, Constant.noOrderStatus).select(OrderDon::getCreatedTime, OrderDon::getPayTime, OrderDon::getId)
+				    .orderByDesc(OrderDon::getId)
+				    .last("limit 1"));
+		    if (orderDon == null) {
+			    notifyMsg.append("点击购买立即上车");
+			    return notifyMsg.toString();
+		    }
+		    startTime = orderDon.getPayTime() != null ? orderDon.getPayTime() : orderDon.getCreatedTime();
+	    } else if (type == 2) {
+		    RegisterOrderDon orderDon = registerOrderDonMapper.selectOne(Wrappers.lambdaQuery(RegisterOrderDon.class)
+				    .eq(RegisterOrderDon::getGoodsId, goodsId)
+				    .notIn(RegisterOrderDon::getStatus, Constant.noOrderStatus).select(RegisterOrderDon::getCreatedTime, RegisterOrderDon::getPayTime, RegisterOrderDon::getId)
+				    .orderByDesc(RegisterOrderDon::getId)
+				    .last("limit 1"));
+		    if (orderDon == null) {
+			    return null;
+		    }
+		    startTime = orderDon.getPayTime() != null ? orderDon.getPayTime() : orderDon.getCreatedTime();
+	    }
+	    long hour = DateUtil.between(startTime, now, DateUnit.HOUR);
+	    if (hour == 0) {
+		    long minute = DateUtil.between(startTime, now, DateUnit.MINUTE);
+		    if (minute == 0) {
+			    notifyMsg.append("1分钟");
+		    } else {
+			    notifyMsg.append(minute);
+			    notifyMsg.append("分钟");
+		    }
+	    } else {
+		    if (hour > 3) {
+			    int hours = RandomUtil.randomInt(3) + 1;
+			    notifyMsg.append(hours);
+		    } else {
+			    notifyMsg.append(hour);
+		    }
+		    notifyMsg.append("小时");
+	    }
+	    notifyMsg.append("前有人购买");
+	    return notifyMsg.toString();
     }
 
     /**
@@ -634,36 +480,26 @@ public class GoodsDonController {
     }
 
     /**
-     * 获取特定规格
-     */
-    public List<GoodsDonSku> getSpecificSku(Long goodsId) {
-        //查找所有特定规格最小价格 满足条件
-        String specificGoodsKey = RedisService.key.YH_HOME_PAGHE_CACHE.getEnvName() + "specific:" + goodsId;
-        Object speciObj = redisService.get(specificGoodsKey);
-        List<GoodsDonSku> specificSkus = null;
-        if (speciObj != null) {
-            specificSkus = Jsons.parseList(speciObj, GoodsDonSku.class);
-        } else {
-            specificSkus = goodsDonSkuMapper.selectList(
-                    Wrappers.lambdaQuery(GoodsDonSku.class)
-                            .eq(GoodsDonSku::getGoodsId, goodsId)
-                            .eq(GoodsDonSku::getStatus, true)
-                            .gt(GoodsDonSku::getSpecificPrice, 0));
-            redisService.setNx(specificGoodsKey, specificSkus, RedisService.key.YH_HOME_PAGHE_CACHE.getTimeout());
-        }
-        specificSkus = Optional.ofNullable(specificSkus).orElse(new ArrayList<>());
-        return specificSkus;
-    }
-
-    /**
-     * 设置首页配置 涉及平台特定价格
+     * 设置平台 特定价格
      */
-    public void setHomeManageSpecific(List<HomeManagementFrontView> list, Long fUid) {
-        if (fUid != null && CollUtil.isNotEmpty(list)) {
+    public void setSpecificPrice(List<GoodsFrontListView> list, Long fUid) {
+        if (fUid != null) {
             list.forEach(data -> {
-                if (data.getIsSp() != null && data.getIsSp()) {
+                if (data.getIsSp()) {
                     //查找所有特定规格最小价格 满足条件
-                    List<GoodsDonSku> specificSkus = getSpecificSku(data.getGoodsId());
+                    String specificGoodsKey = RedisService.key.YH_HOME_PAGHE_CACHE.getName() + "specific:" + data.getId();
+                    Object speciObj = redisService.get(specificGoodsKey);
+                    List<GoodsDonSku> specificSkus = null;
+                    if (speciObj != null) {
+                        specificSkus = Jsons.parseList(speciObj, GoodsDonSku.class);
+                    } else {
+                        specificSkus = goodsDonSkuMapper.selectList(
+                                Wrappers.lambdaQuery(GoodsDonSku.class)
+                                        .eq(GoodsDonSku::getGoodsId, data.getId())
+                                        .eq(GoodsDonSku::getStatus, true)
+                                        .gt(GoodsDonSku::getSpecificPrice, 0));
+                        redisService.setNx(specificGoodsKey, specificSkus, RedisService.key.YH_HOME_PAGHE_CACHE.getTimeout());
+                    }
                     specificSkus.forEach(specificSku -> {
                         String specificGoodsIdsStr = specificSku.getSpecificGoodsIds();
                         if (isPaySpecificGoodsIds(specificGoodsIdsStr, fUid)) {
@@ -679,6 +515,16 @@ public class GoodsDonController {
                             }
                         }
                     });
+                    List<GoodsDonSkuFrontView> skuList = data.getSkuList();
+                    if (CollUtil.isNotEmpty(skuList)) {
+                        skuList.forEach(sku->{
+                            //设置特定价格
+                            if (!isPaySpecificGoodsIds(sku.getSpecificGoodsIds(), fUid)) {
+                                sku.setSpecificGoodsIds(null);
+                                sku.setSpecificPrice(null);
+                            }
+                        });
+                    }
                 }
             });
         }

+ 11 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/CmsOrderController.java

@@ -601,4 +601,15 @@ public class CmsOrderController {
 				builder.build());
 		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
 	}
+
+	/**
+	 * 订单补差价,补差价退款到余额
+	 */
+	@PutMapping("/refund/price/differ")
+	@Log(module = "订单管理/订单补差价", businessType = BusinessType.PUT, isSaveRequestData = true)
+	public Result<String> refundPriceDiffer(@RequestBody OrderRefundReq orderRefundReq) {
+		cmsOrderDonService.refundPriceDiffer(orderRefundReq);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
 }

+ 46 - 4
netflix-web/src/main/java/com/cyksj/web/controller/manage/account/CmsAccountController.java

@@ -11,9 +11,11 @@ import com.alibaba.excel.EasyExcel;
 import com.alibaba.excel.context.AnalysisContext;
 import com.alibaba.excel.event.AnalysisEventListener;
 import com.alibaba.excel.support.ExcelTypeEnum;
+import com.baomidou.mybatisplus.core.toolkit.Assert;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.annotation.Log;
 import com.cyksj.common.annotation.NoSubmit;
+import com.cyksj.common.constant.Constant;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.dto.RedisKey;
 import com.cyksj.dto.Result;
@@ -55,10 +57,7 @@ import org.springframework.web.multipart.MultipartFile;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -103,6 +102,8 @@ public class CmsAccountController {
 
 	private final RedisService redisService;
 
+	private final GoodsDonSkuMapper goodsDonSkuMapper;
+
 	@GetMapping("/get")
 	@SaCheckPermission("account:view")
 	public Result<SearchResult<AccountView>> get(Long userId, String showId, String nickName, String submitAccount, String expiryStartTime, String expiryEndTime, Boolean expiredAll, Boolean existsExpired, Boolean existsExpiredToday, Integer noChangeMonths) {
@@ -857,4 +858,45 @@ public class CmsAccountController {
 		List<DoubleVerifyClickRefreshRecord> search = beanSearcher.searchAll(DoubleVerifyClickRefreshRecord.class, MapUtils.flatBuilder(request.getParameterMap()).build());
 		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
 	}
+
+	/**
+	 * MidJourney、ChatGPT年付 ChatGpt独立月付未续费列表
+	 */
+	@GetMapping("/get/specific/account")
+	public Result<SearchResult<AccountSpecificView>> getSpecificAccount() {
+		//获取MidJourney、ChatGPT年付 ChatGpt独立月付 规格id
+		Long chatGptPlusGid = Constant.AI_goodsIds.get(0);
+		//年付
+		List<Long> yearSkuIds = goodsDonSkuMapper.getSpecificSkuIdsByGoodsIds(Constant.AI_goodsIds, 12);
+		//ChatGpt Plus 独立月付
+		List<Long> monthSkuIds = goodsDonSkuMapper.getSpecificSkuIdsByGoodsId(chatGptPlusGid, 1, 1);
+		Collection<Long> skuIds = CollUtil.addAll(yearSkuIds, monthSkuIds);
+		if (skuIds.isEmpty()) {
+			return GatewayResponse.SUCCESS.newBuilder().toResult();
+		}
+		SearchResult<AccountSpecificView> search = beanSearcher.search(AccountSpecificView.class, MapUtils.flatBuilder(request.getParameterMap())
+				.put("condition", String.format("and (select count(*) from groups_relation gr where gr.groups_id = gt.id and gr.user_id != 0 and gr.status in ('validity','outside')) > 0"))
+				.field(AccountSpecificView::getExpiryTime, DateTime.now()).op(Operator.LessThan)
+				.field(AccountSpecificView::getSkuId, skuIds).op(Operator.InList).build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 编辑 未续费的账号
+	 */
+	@PutMapping("/update/renew/account")
+	public Result<String> updateRenewAccount(@RequestBody Account account) {
+		Long id = account.getId();
+		Date startTime = account.getStartTime();
+		Date expiryTime = account.getExpiryTime();
+		String remark = account.getRemark();
+		Account byId = accountService.getById(id);
+		Assert.notNull(byId, "账号不存在");
+		byId.setStartTime(startTime);
+		byId.setExpiryTime(expiryTime);
+		byId.setRemark(remark);
+		accountService.updateById(byId);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
 }

+ 117 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/distribute/DistributeController.java

@@ -3,6 +3,7 @@ package com.cyksj.web.controller.manage.distribute;
 import cn.dev33.satoken.annotation.SaCheckPermission;
 import cn.dev33.satoken.stp.StpUtil;
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.date.BetweenFormater;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.StrUtil;
@@ -24,9 +25,11 @@ import com.cyksj.model.entity.*;
 import com.cyksj.model.request.DistributeApplyMoneyReq;
 import com.cyksj.model.request.UserDistributeReq;
 import com.cyksj.model.views.*;
+import com.cyksj.redis.RedisService;
 import com.cyksj.service.distribute.DistributeService;
 import com.cyksj.service.mange.business.UserBusinessRateService;
 import com.cyksj.service.mange.statistics.StatisticsDataService;
+import com.cyksj.service.sys.SysConfigService;
 import com.cyksj.service.user.UserBenefitsService;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.SearchResult;
@@ -93,6 +96,12 @@ public class DistributeController {
 
 	private final CouponDistributePopularizeMapper couponDistributePopularizeMapper;
 
+	private final SysConfigService sysConfigService;
+
+	private final RedisService redisService;
+
+	private final UserDistributeRuleOrderRecordMapper userDistributeRuleOrderRecordMapper;
+
 	/**
 	 * 添加固定推广者
 	 */
@@ -707,4 +716,112 @@ public class DistributeController {
 		UserDistributeViews userDistributeViews = userDistributeMapper.getApplyDetailByUserId(userId);
 		return GatewayResponse.SUCCESS.newBuilder().toResult(userDistributeViews);
 	}
+
+	/**
+	 * 获取渠道分销规则开启 状态
+	 */
+	@GetMapping("/get/rule/status")
+	public Result<Boolean> getRuleStatus() {
+		String ruleKey = Constant.DISTRIBUTE_RULE_KEY;
+		SysConfig ruleConfig = sysConfigService.getOne(Wrappers.lambdaQuery(SysConfig.class)
+				.eq(SysConfig::getSysKey, ruleKey).last("limit 1"));
+		if (ruleConfig == null) {
+			ruleConfig = new SysConfig();
+			ruleConfig.setSysKey(ruleKey);
+			ruleConfig.setRemark("渠道分销规则key");
+			//默认开启
+			ruleConfig.setSysValue(Constant.ONE_STR);
+			if (redisService.setNx(ruleKey, 1, 5l)) {
+				sysConfigService.save(ruleConfig);
+			}
+		}
+		if (StrUtil.equals(Constant.ONE_STR, ruleConfig.getSysValue())) {
+			return GatewayResponse.SUCCESS.newBuilder().toResult(true);
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult(false);
+	}
+
+	/**
+	 * 开启/关闭 渠道分销规则 默认开启
+	 */
+	@PutMapping("/update/status/rule")
+	public Result<String> updateDsRuleStatus() {
+		String ruleKey = Constant.DISTRIBUTE_RULE_KEY;
+		SysConfig ruleConfig = sysConfigService.getOne(Wrappers.lambdaQuery(SysConfig.class)
+				.eq(SysConfig::getSysKey, ruleKey).last("limit 1"));
+		if (ruleConfig == null) {
+			throw BusinessRuntimeException.getInstance("渠道分销规则配置不存在");
+		}
+		if (Constant.ZERO_STR.equals(ruleConfig.getSysValue())) {
+			ruleConfig.setSysValue(Constant.ONE_STR);
+		} else {
+			ruleConfig.setSysValue(Constant.ZERO_STR);
+		}
+		sysConfigService.saveOrUpdate(ruleConfig);
+		//记录关闭打开状态
+		//关闭 记录一次
+		//距离上一次时间
+		UserDistributeRuleOrderRecord userDistributeRuleOrderRecord = Optional.ofNullable(userDistributeRuleOrderRecordMapper.selectOne(Wrappers.lambdaQuery(UserDistributeRuleOrderRecord.class)
+				.orderByDesc(UserDistributeRuleOrderRecord::getId).last("limit 1"))).orElse(new UserDistributeRuleOrderRecord());
+		if (StrUtil.equals(Constant.ZERO_STR, ruleConfig.getSysValue())) {
+			//距离上次关闭时间少于10分钟 不记录关闭时间
+			if (userDistributeRuleOrderRecord.getId() == null) {
+				if (redisService.setNx(RedisService.key.DISTRIBUTE_RULE_TIME_KEY.getName(), 1, RedisService.key.DISTRIBUTE_RULE_TIME_KEY.getTimeout())) {
+					userDistributeRuleOrderRecord.setEndTime(DateTime.now());
+					userDistributeRuleOrderRecordMapper.insert(userDistributeRuleOrderRecord);
+				}
+			} else {
+				if (userDistributeRuleOrderRecord.getStartTime() != null) {
+					Date startTime = userDistributeRuleOrderRecord.getStartTime();
+					if (DateTime.now().isAfter(DateUtil.offsetMinute(startTime, 10))) {
+						if (redisService.setNx(RedisService.key.DISTRIBUTE_RULE_TIME_KEY.getName(), 1, RedisService.key.DISTRIBUTE_RULE_TIME_KEY.getTimeout())) {
+							UserDistributeRuleOrderRecord newRecord = new UserDistributeRuleOrderRecord();
+							newRecord.setEndTime(DateTime.now());
+							userDistributeRuleOrderRecordMapper.insert(newRecord);
+						}
+					}
+				}
+			}
+		} else {
+			if (userDistributeRuleOrderRecord.getId() != null && userDistributeRuleOrderRecord.getStartTime() == null) {
+				if (DateTime.now().isAfter(DateUtil.offsetMinute(userDistributeRuleOrderRecord.getEndTime(), 10))) {
+					userDistributeRuleOrderRecord.setStartTime(DateTime.now());
+					userDistributeRuleOrderRecord.setDuration(DateUtil.formatBetween(userDistributeRuleOrderRecord.getEndTime(), userDistributeRuleOrderRecord.getStartTime(), BetweenFormater.Level.SECOND));
+					userDistributeRuleOrderRecordMapper.updateById(userDistributeRuleOrderRecord);
+				}
+			}
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 渠道分销规则列表
+	 */
+	@GetMapping("/get/rule/list")
+	public Result<SearchResult<UserDistributeRuleOrderRecordView>> getDistributeRuleList() {
+		SearchResult<UserDistributeRuleOrderRecordView> search = beanSearcher.search(UserDistributeRuleOrderRecordView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
+		search.getDataList().forEach(data -> {
+			Date endTime = data.getEndTime();
+			Date startTime = data.getStartTime();
+			String time = StrUtil.EMPTY;
+			if (endTime != null) {
+				time = String.format("created_time >= '%s'", DateUtil.format(endTime, "yyyy-MM-dd HH:mm:ss"));
+			}
+			if (startTime != null) {
+				if (StrUtil.isNotBlank(time)) {
+					time += " and ";
+				}
+				time += String.format("created_time < '%s'", DateUtil.format(startTime, "yyyy-MM-dd HH:mm:ss"));
+			}
+			String condition = "where is_rule is true";
+			if (StrUtil.isNotBlank(time)) {
+				condition += String.format(" and %s", time);
+			}
+			DistributeWaitingOrderPointsRuleView ruleView = beanSearcher.searchFirst(DistributeWaitingOrderPointsRuleView.class, MapUtils.builder()
+					.put("condition", condition).build());
+			data.setNumOfOrder(ruleView.getNumOfOrder());
+			data.setOrderAmount(ruleView.getOrderAmount() == null ? BigDecimal.ZERO : ruleView.getOrderAmount());
+		});
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
 }

+ 4 - 16
netflix-web/src/main/java/com/cyksj/web/controller/manage/goods/CmsGoodsDonController.java

@@ -10,12 +10,10 @@ import com.cyksj.common.util.Jsons;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.BusinessType;
 import com.cyksj.enums.GatewayResponse;
-import com.cyksj.model.entity.GoodsDiscountPlusPurchaseRelation;
 import com.cyksj.model.entity.GoodsDon;
 import com.cyksj.model.entity.GoodsDonSku;
 import com.cyksj.model.manage.request.ReqGoodsSpuInsert;
 import com.cyksj.model.manage.views.GoodsDonViewer;
-import com.cyksj.model.views.GoodsDonCategoryDetailView;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.mange.CmsGoodsDonService;
 import com.ejlchina.searcher.BeanSearcher;
@@ -51,9 +49,10 @@ public class CmsGoodsDonController {
     private final RedisService redisService;
 
     @GetMapping("/get")
-    public Result<SearchResult<GoodsDonCategoryDetailView>> get(){
-        SearchResult<GoodsDonCategoryDetailView> search = beanSearcher.search(GoodsDonCategoryDetailView.class, MapUtils.flatBuilder(request.getParameterMap())
-                .field(GoodsDonCategoryDetailView::getDeleted,true)
+    public Result<SearchResult<GoodsDon>> get(){
+        SearchResult<GoodsDon> search = beanSearcher.search(GoodsDon.class, MapUtils.flatBuilder(request.getParameterMap())
+                .field(GoodsDon::getDeleted,true)
+                .put("condition", "(special_type is null or special_type != 'giftCard')")
                 .build());
         return GatewayResponse.SUCCESS.newBuilder().toResult(search);
     }
@@ -67,17 +66,6 @@ public class CmsGoodsDonController {
         if (StrUtil.isNotBlank(goodsDonViewer.getRecommendGoods())) {
             goodsDonViewer.setRecommendGoodsList(Jsons.parseList(goodsDonViewer.getRecommendGoods(), Long.class));
         }
-        List<GoodsDonSku> goodsDonSkus = beanSearcher.searchAll(GoodsDonSku.class, MapUtils.builder().field(GoodsDonSku::getGoodsId, id).build());
-        if (goodsDonViewer.getType() == 1) {
-            goodsDonSkus.forEach(sku -> {
-                if (sku.getIsDp()) {
-                    sku.setDpSku(beanSearcher.searchAll(GoodsDiscountPlusPurchaseRelation.class, MapUtils.builder()
-                            .field(GoodsDiscountPlusPurchaseRelation::getSkuId, sku.getId())
-                            .build()));
-                }
-            });
-        }
-        goodsDonViewer.setSkus(goodsDonSkus);
         return GatewayResponse.SUCCESS.newBuilder().toResult(goodsDonViewer);
     }
 

+ 8 - 1
netflix-web/src/main/java/com/cyksj/web/controller/manage/goods/CmsGoodsDonSkuController.java

@@ -1,6 +1,5 @@
 package com.cyksj.web.controller.manage.goods;
 
-import cn.hutool.core.lang.Assert;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.annotation.Log;
@@ -9,6 +8,7 @@ import com.cyksj.common.util.Jsons;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.BusinessType;
 import com.cyksj.enums.GatewayResponse;
+import com.cyksj.model.entity.GoodsDiscountPlusPurchaseRelation;
 import com.cyksj.model.entity.GoodsDon;
 import com.cyksj.model.entity.GoodsDonSku;
 import com.cyksj.model.manage.request.ReqGoodsSkuInsert;
@@ -183,6 +183,13 @@ public class CmsGoodsDonSkuController {
     @GetMapping("/get/list")
     public Result<SearchResult<GoodsDonSku>> getGoodsSkuList() {
         SearchResult<GoodsDonSku> skuViewList = beanSearcher.search(GoodsDonSku.class, MapUtils.flatBuilder(request.getParameterMap()).build());
+        skuViewList.getDataList().forEach(sku->{
+            if (sku.getIsDp()) {
+                sku.setDpSku(beanSearcher.searchAll(GoodsDiscountPlusPurchaseRelation.class, MapUtils.builder()
+                        .field(GoodsDiscountPlusPurchaseRelation::getSkuId, sku.getId())
+                        .build()));
+            }
+        });
         return GatewayResponse.SUCCESS.newBuilder().toResult(skuViewList);
     }
 

+ 32 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/group/CmsGroupController.java

@@ -7,6 +7,7 @@ import cn.hutool.core.date.DateTime;
 import cn.hutool.core.thread.ThreadUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONObject;
+import com.alibaba.excel.support.ExcelTypeEnum;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.annotation.Log;
 import com.cyksj.common.annotation.NoSubmit;
@@ -20,6 +21,7 @@ import com.cyksj.mapper.UserMapper;
 import com.cyksj.model.entity.Account;
 import com.cyksj.model.entity.GroupsTrips;
 import com.cyksj.model.entity.GroupsTripsAccountReplaceRecord;
+import com.cyksj.model.excel.ExcelGroupRelationData;
 import com.cyksj.model.request.AccountGroupsReq;
 import com.cyksj.model.request.ReplaceTripsAccountReq;
 import com.cyksj.model.views.CloseGroupsTripsView;
@@ -28,6 +30,7 @@ import com.cyksj.model.views.GroupsTripsWaitingView;
 import com.cyksj.service.mange.AccountCommonService;
 import com.cyksj.service.mange.CmsAccountService;
 import com.cyksj.service.mange.CmsGroupService;
+import com.cyksj.web.util.EasyExcelUtils;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.SearchResult;
 import com.ejlchina.searcher.param.Operator;
@@ -40,6 +43,7 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
@@ -93,6 +97,34 @@ public class CmsGroupController {
         return GatewayResponse.SUCCESS.newBuilder().toResult(search);
     }
 
+    /**
+     * 导出车票列表
+     */
+    @GetMapping("/export")
+    public void export(String account, Long userId, String showId, String nickName, String submitAccount, Boolean isEmpty, HttpServletResponse response) {
+        MapBuilder mapBuilder = MapUtils.flatBuilder(request.getParameterMap());
+        if (StrUtil.isNotBlank(showId)) {
+            userId = userMapper.getUserIdByShowId(showId);
+        }
+        if (userId != null || StringUtils.isNotBlank(nickName) || StringUtils.isNotBlank(submitAccount)) {
+            List<Long> ids = relationMapper.getAccountIdsByUserIdOrNickNameOrSubmitAccount(userId, nickName, submitAccount);
+            if (ids.isEmpty()) {
+                throw BusinessRuntimeException.getInstance("暂无数据..");
+            }
+
+            mapBuilder.field(ExcelGroupRelationData::getGroupId, ids).op(Operator.InList);
+        }
+        if (isEmpty != null && isEmpty) {
+            mapBuilder.field(ExcelGroupRelationData::getNum, ExcelGroupRelationData::getAvailableNum).sql("$1 = $2");
+        }
+
+        List<ExcelGroupRelationData> list = beanSearcher.searchAll(ExcelGroupRelationData.class, mapBuilder
+                .field(ExcelGroupRelationData::getAccount, StringUtils.isBlank(account) ? null : account).op(Operator.EndWith)
+                .build()
+        );
+        EasyExcelUtils.createExcelStreamMutilByEasyExcel(response, ExcelGroupRelationData.class, list, "发布车票列表", "发布车票列表", ExcelTypeEnum.XLSX, null);
+    }
+
     /**
      * 各平台待发车详情
      */

+ 130 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/group/CmsGroupsRelationExpiryController.java

@@ -0,0 +1,130 @@
+package com.cyksj.web.controller.manage.group;
+
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.constant.Constant;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.mapper.GroupsRelationCustomerServiceFollowRecordMapper;
+import com.cyksj.mapper.GroupsRelationExpiryRecordMapper;
+import com.cyksj.mapper.UserMapper;
+import com.cyksj.mapper.corp.CorpUserMapper;
+import com.cyksj.mapper.market.task.UserBindDetailMapper;
+import com.cyksj.model.entity.*;
+import com.cyksj.service.user.UserBackService;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.SearchResult;
+import com.ejlchina.searcher.util.MapBuilder;
+import com.ejlchina.searcher.util.MapUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Optional;
+
+/*
+ *项目名: netflix
+ *文件名: CmsGroupsRelationExpiryController
+ *创建者: JavaZou
+ *创建时间:2023/9/5 12:08
+ */
+@RestController
+@RequestMapping("/manage/relation/track")
+@RequiredArgsConstructor
+public class CmsGroupsRelationExpiryController {
+	private final BeanSearcher beanSearcher;
+
+	private final HttpServletRequest request;
+
+	private final UserBackService userBackService;
+
+	private final GroupsRelationExpiryRecordMapper groupsRelationExpiryRecordMapper;
+
+	private final GroupsRelationCustomerServiceFollowRecordMapper relationCustomerServiceFollowRecordMapper;
+
+	private final UserMapper userMapper;
+
+	private final UserBindDetailMapper userBindDetailMapper;
+
+	private final CorpUserMapper corpUserMapper;
+
+	/**
+	 * 到期用户 客服跟进续费列表
+	 */
+	@GetMapping("/get")
+	public Result<SearchResult<GroupsRelationExpiryRecord>> get(String showId) {
+		long adminId = StpUtil.getLoginIdAsLong();
+		MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
+		if (userBackService.isCustomer(adminId)) {
+			builder.field(GroupsRelationExpiryRecord::getCustomerServiceId, adminId);
+		}
+		if (StrUtil.isNotBlank(showId)) {
+			User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class).eq(User::getShowId, showId).last("limit 1"));
+			if (user != null) {
+				builder.field(GroupsRelationExpiryRecord::getUserId, user.getId());
+			}
+		}
+		SearchResult<GroupsRelationExpiryRecord> search = beanSearcher.search(GroupsRelationExpiryRecord.class, builder
+				.orderBy(GroupsRelationExpiryRecord::getId).desc()
+				.build());
+		search.getDataList().forEach(data -> {
+			if (Constant.TRACK_RENEW_TYPE.contains(data.getRegister())) {
+				UserBindDetail userBindDetail = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
+						.eq(Constant.TRACK_RENEW_TYPE.get(0).equals(data.getRegister()),UserBindDetail::getEmailUserId, data.getUserId())
+						.eq(Constant.TRACK_RENEW_TYPE.get(1).equals(data.getRegister()),UserBindDetail::getUserId, data.getUserId())
+						.ne(UserBindDetail::getPhone, StrUtil.EMPTY)
+						.last("limit 1"));
+				if (userBindDetail != null) {
+					data.setContact(userBindDetail.getPhone());
+				}
+				if (Constant.TRACK_RENEW_TYPE.get(1).equals(data.getRegister())) {
+					//实时获取企业微信昵称
+					Optional.ofNullable(corpUserMapper.selectOne(Wrappers.lambdaQuery(CorpUser.class)
+							.eq(CorpUser::getUserId, data.getUserId()).last("limit 1")))
+							.ifPresent(cu -> {
+								data.setNickname(cu.getName());
+							});
+				}
+			}
+		});
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 跟进记录列表
+	 */
+	@GetMapping("/get/reBuy/record/{trackId}")
+	public Result<SearchResult<GroupsRelationCustomerServiceFollowRecord>> getReBuyRecord(@PathVariable Long trackId) {
+		SearchResult<GroupsRelationCustomerServiceFollowRecord> search = beanSearcher.search(GroupsRelationCustomerServiceFollowRecord.class, MapUtils.flatBuilder(request.getParameterMap())
+				.field(GroupsRelationCustomerServiceFollowRecord::getEcId, trackId)
+				.orderBy(GroupsRelationCustomerServiceFollowRecord::getId).desc()
+				.build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 客服进行跟进
+	 */
+	@PostMapping("/reBuy")
+	@Transactional(rollbackFor = Throwable.class)
+	public Result<String> recordReBuy(@RequestBody GroupsRelationCustomerServiceFollowRecord record) {
+		Long ecId = record.getEcId();
+		if (ecId == null) {
+			throw BusinessRuntimeException.getInstance("请选择对应的跟进车票");
+		}
+		GroupsRelationExpiryRecord groupsRelationExpiryRecord = groupsRelationExpiryRecordMapper.selectById(ecId);
+		if (groupsRelationExpiryRecord == null) {
+			throw BusinessRuntimeException.getInstance("请选择对应的跟进车票");
+		}
+		if (StrUtil.isAllBlank(record.getContent(), record.getImgs())) {
+			throw BusinessRuntimeException.getInstance("请完善对应跟进信息");
+		}
+		relationCustomerServiceFollowRecordMapper.insert(record);
+		groupsRelationExpiryRecord.setIsFollow(true);
+		groupsRelationExpiryRecordMapper.updateById(groupsRelationExpiryRecord);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+}

+ 13 - 4
netflix-web/src/main/java/com/cyksj/web/controller/manage/statistics/StatisticsDataController.java

@@ -88,12 +88,21 @@ public class StatisticsDataController {
 	private final OrderDonMapper orderDonMapper;
 
 	/**
-	 * 查询统计数据
+	 * 查询头部统计数据
 	 */
-	@GetMapping
+	@GetMapping("/get/header")
+	public Result<BackgroundDataView> getStatisticsHeader(Long startTime, Long endTime) throws InterruptedException {
+		return statisticsDataService.getStatisticsHeader(startTime, endTime);
+	}
+
+	/**
+	 * 查询平台统计数据
+	 * type 1、流媒体,2、实物,3、潮玩,4、注册账号
+	 */
+	@GetMapping("/get/goods")
 	@SaCheckPermission("statics:view")
-	public Result<BackgroundDataView> getStatisticsByCondition(Long startTime, Long endTime) throws InterruptedException {
-		return statisticsDataService.getStatisticsByCondition(startTime, endTime);
+	public Result<BackgroundDataView> getStatisticsByCondition(@RequestParam(defaultValue = "0") Integer type, Long startTime, Long endTime) throws InterruptedException {
+		return statisticsDataService.getStatisticsByCondition(type, startTime, endTime);
 	}
 
 	/**

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

@@ -58,6 +58,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.math.BigDecimal;
 import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.List;
@@ -113,9 +114,6 @@ public class OrderController {
     @Autowired
     private StripeService stripeService;
 
-    @Autowired
-    private UserBindRelationService userBindRelationService;
-
     /**
      * 支付
      * @author chan
@@ -452,12 +450,15 @@ public class OrderController {
         if (user == null) {
             throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_TOKEN_VALID);
         }
-        if (StrUtil.isEmpty(user.getOpenId())) {
+        //手机号注册 无需绑定
+        if (StrUtil.isNotEmpty(user.getLoginPhone())) {
             return GatewayResponse.SUCCESS.newBuilder().toResult(true);
         }
+        //是否绑定了手机号
         UserBindDetail userBindDetail = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
-                .eq(UserBindDetail::getUserId, userId));
-        if (userBindDetail == null) {
+                .eq(StrUtil.isNotEmpty(user.getOpenId()), UserBindDetail::getUserId, userId)
+                .eq(StrUtil.isNotEmpty(user.getEmail()), UserBindDetail::getEmailUserId, userId).last("limit 1"));
+        if (userBindDetail == null || StrUtil.isEmpty(userBindDetail.getPhone())) {
             return GatewayResponse.SUCCESS.newBuilder().toResult(false);
         }
         return GatewayResponse.SUCCESS.newBuilder().toResult(true);

+ 19 - 0
netflix-web/src/main/java/com/cyksj/web/controller/user/AuthorizationController.java

@@ -3,6 +3,7 @@ package com.cyksj.web.controller.user;
 import cn.hutool.core.codec.Base64;
 import cn.hutool.core.lang.Validator;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpUtil;
 import cn.hutool.json.JSONObject;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.EnvCommonService;
@@ -22,6 +23,7 @@ import com.cyksj.model.dto.JsSdkTicket;
 import com.cyksj.model.entity.PhoneCode;
 import com.cyksj.model.entity.User;
 import com.cyksj.model.request.LoginReq;
+import com.cyksj.model.response.GoogleLoginRep;
 import com.cyksj.model.response.UserAuthLoginResp;
 import com.cyksj.model.response.WxGzhQrCodeTicketRep;
 import com.cyksj.redis.RedisService;
@@ -42,6 +44,7 @@ import org.springframework.web.bind.annotation.*;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import java.util.HashMap;
 import java.util.Optional;
 
 /**
@@ -455,4 +458,20 @@ public class AuthorizationController {
         log.info("微信授权转跳.url: {}", url);
         response.sendRedirect(url.contains("?") ? url + "&t=" + StpUserUtil.getTokenValue() : url + "?t=" + StpUserUtil.getTokenValue());
     }
+
+    @PostMapping("/google/login")
+    public Result<UserAuthLoginResp> googleLogin(LoginReq loginReq,String credential) throws Exception {
+        log.info("google loginReq:{},credential:{}", loginReq, credential);
+        String result = HttpUtil.post("https://galaxydvd.com/8081/api/auth/google/login/inner?credential=" + credential, new HashMap<>());
+        log.info("google result:{}",result);
+        GoogleLoginRep googleLoginRep = Jsons.parseObject(Jsons.toMap(result).get("data"), GoogleLoginRep.class);
+        loginReq.setType(3);
+        loginReq.setEmail(googleLoginRep.getEmail());
+        loginReq.setSubject(googleLoginRep.getSubject());
+        User user = userService.webLogin(loginReq);
+        //写回登陆信息
+        StpUserUtil.login(user.getId());
+        UserAuthLoginResp loginPhoneRep = new UserAuthLoginResp(StpUserUtil.getTokenValue(), user.getShowId(), user.getNickname(), user.getHeadimgurl());
+        return GatewayResponse.SUCCESS.newBuilder().toResult(loginPhoneRep);
+    }
 }