Forráskód Böngészése

优惠券、渠道分销

zoujiajian 2 éve
szülő
commit
e963ec0d35
72 módosított fájl, 3998 hozzáadás és 345 törlés
  1. 5 0
      netflix-common/src/main/java/com/cyksj/common/constant/Constant.java
  2. 5 1
      netflix-dao/src/main/java/com/cyksj/mapper/OrderDonMapper.java
  3. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/UserDistributeReturnMoneyDetailMapper.java
  4. 17 0
      netflix-dao/src/main/java/com/cyksj/mapper/UserDistributeSharedRelateUnbindMapper.java
  5. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/UserDistributeSharedWhiteMapper.java
  6. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/UserDistributeSpecialMapper.java
  7. 3 0
      netflix-dao/src/main/java/com/cyksj/mapper/UserMapper.java
  8. 3 0
      netflix-dao/src/main/java/com/cyksj/mapper/manage/coupon/CouponMapper.java
  9. 6 1
      netflix-dao/src/main/java/com/cyksj/mapper/manage/coupon/CouponUserMapper.java
  10. 1 0
      netflix-dao/src/main/java/com/cyksj/mapper/manage/distribute/UserDistributeSharedWhiteMapper.java
  11. 4 1
      netflix-dao/src/main/java/com/cyksj/model/entity/BackInfoTranslations.java
  12. 6 0
      netflix-dao/src/main/java/com/cyksj/model/entity/CouponUser.java
  13. 26 5
      netflix-dao/src/main/java/com/cyksj/model/entity/DistributeMoneyApply.java
  14. 37 1
      netflix-dao/src/main/java/com/cyksj/model/entity/DistributeWaitingSendPoints.java
  15. 9 0
      netflix-dao/src/main/java/com/cyksj/model/entity/OrderDon.java
  16. 6 1
      netflix-dao/src/main/java/com/cyksj/model/entity/UserDistribute.java
  17. 22 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserDistributeReturnMoneyDetail.java
  18. 8 1
      netflix-dao/src/main/java/com/cyksj/model/entity/UserDistributeShared.java
  19. 24 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserDistributeSharedRelateUnbind.java
  20. 1 1
      netflix-dao/src/main/java/com/cyksj/model/entity/UserDistributeSharedWhite.java
  21. 13 1
      netflix-dao/src/main/java/com/cyksj/model/request/ApplyMoneyReq.java
  22. 5 1
      netflix-dao/src/main/java/com/cyksj/model/request/TransferAccountsReq.java
  23. 22 2
      netflix-dao/src/main/java/com/cyksj/model/request/UserDistributeReq.java
  24. 3 1
      netflix-dao/src/main/java/com/cyksj/model/views/BrokenLineObjView.java
  25. 22 0
      netflix-dao/src/main/java/com/cyksj/model/views/BusinessDistributeDefaultRateDetailReq.java
  26. 23 0
      netflix-dao/src/main/java/com/cyksj/model/views/BusinessDistributeRateDetailView.java
  27. 45 0
      netflix-dao/src/main/java/com/cyksj/model/views/BusinessDistributeSkuRateView.java
  28. 50 0
      netflix-dao/src/main/java/com/cyksj/model/views/CouponDistributePopularizeDetailView.java
  29. 45 0
      netflix-dao/src/main/java/com/cyksj/model/views/CouponReceiptDetailView.java
  30. 59 0
      netflix-dao/src/main/java/com/cyksj/model/views/CouponUsedDetailView.java
  31. 4 1
      netflix-dao/src/main/java/com/cyksj/model/views/CouponView.java
  32. 18 0
      netflix-dao/src/main/java/com/cyksj/model/views/DistributeGoodsGeneralRateView.java
  33. 42 0
      netflix-dao/src/main/java/com/cyksj/model/views/DistributePlatOrderDonBrokenLineView.java
  34. 15 3
      netflix-dao/src/main/java/com/cyksj/model/views/DistributePopularizeOrdersView.java
  35. 1 1
      netflix-dao/src/main/java/com/cyksj/model/views/DistributePopularizeView.java
  36. 27 0
      netflix-dao/src/main/java/com/cyksj/model/views/DistributeSearchView.java
  37. 40 0
      netflix-dao/src/main/java/com/cyksj/model/views/GoodsDonSkuRateView.java
  38. 65 0
      netflix-dao/src/main/java/com/cyksj/model/views/UserCommonDistributeView.java
  39. 31 0
      netflix-dao/src/main/java/com/cyksj/model/views/UserDistributeRateDetailView.java
  40. 44 0
      netflix-dao/src/main/java/com/cyksj/model/views/UserSkuDistributeView.java
  41. 7 0
      netflix-dao/src/main/resources/mapper/CouponMapper.xml
  42. 63 31
      netflix-dao/src/main/resources/mapper/CouponUserMapper.xml
  43. 25 1
      netflix-dao/src/main/resources/mapper/OrderDonMapper.xml
  44. 13 0
      netflix-dao/src/main/resources/mapper/UserDistributeSharedRelateUnbindMapper.xml
  45. 2 0
      netflix-service/src/main/java/com/cyksj/redis/RedisService.java
  46. 7 11
      netflix-service/src/main/java/com/cyksj/service/coupon/CouponFontService.java
  47. 35 49
      netflix-service/src/main/java/com/cyksj/service/coupon/impl/CouponFontServiceImpl.java
  48. 13 0
      netflix-service/src/main/java/com/cyksj/service/distribute/DistributeExtraRebateService.java
  49. 35 0
      netflix-service/src/main/java/com/cyksj/service/distribute/DistributeService.java
  50. 19 0
      netflix-service/src/main/java/com/cyksj/service/distribute/UserBusinessFrontService.java
  51. 14 0
      netflix-service/src/main/java/com/cyksj/service/distribute/UserDistributeReturnMoneyDetailService.java
  52. 76 0
      netflix-service/src/main/java/com/cyksj/service/distribute/impl/DistributeExtraRebateServiceImpl.java
  53. 523 0
      netflix-service/src/main/java/com/cyksj/service/distribute/impl/DistributeServiceImpl.java
  54. 227 0
      netflix-service/src/main/java/com/cyksj/service/distribute/impl/UserBusinessFrontServiceImpl.java
  55. 31 0
      netflix-service/src/main/java/com/cyksj/service/distribute/impl/UserDistributeReturnMoneyDetailServiceImpl.java
  56. 18 0
      netflix-service/src/main/java/com/cyksj/service/mange/business/UserBusinessRateService.java
  57. 85 0
      netflix-service/src/main/java/com/cyksj/service/mange/business/impl/UserBusinessRateServiceImpl.java
  58. 375 3
      netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java
  59. 18 0
      netflix-service/src/main/java/com/cyksj/service/pay/TransferFuncService.java
  60. 185 0
      netflix-service/src/main/java/com/cyksj/service/pay/impl/TransferFuncServiceImpl.java
  61. 10 0
      netflix-service/src/main/java/com/cyksj/service/translations/BackInfoTranslationsFrontService.java
  62. 68 5
      netflix-service/src/main/java/com/cyksj/service/translations/impl/BackInfoTranslationsFrontServiceImpl.java
  63. 7 0
      netflix-service/src/main/java/com/cyksj/service/user/impl/UserServiceImpl.java
  64. 25 146
      netflix-web/src/main/java/com/cyksj/web/controller/coupon/CouponFrontController.java
  65. 64 72
      netflix-web/src/main/java/com/cyksj/web/controller/manage/coupon/CouponController.java
  66. 922 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/distribute/DistributeController.java
  67. 320 0
      netflix-web/src/main/java/com/cyksj/web/controller/user/DistributePopularizeController.java
  68. 3 1
      netflix-web/src/main/resources/i18n/yhlx_en_US.properties
  69. 3 1
      netflix-web/src/main/resources/i18n/yhlx_ja_JP.properties
  70. 3 1
      netflix-web/src/main/resources/i18n/yhlx_ko_KR.properties
  71. 3 1
      netflix-web/src/main/resources/i18n/yhlx_zh_CN.properties
  72. 3 1
      netflix-web/src/main/resources/i18n/yhlx_zh_HK.properties

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

@@ -144,4 +144,9 @@ public interface Constant {
 	 * GPT 平台账号重复
 	 */
 	List<Long> GPT_GOODS_IDS = List.of(18l, 29l, 30l);
+
+	/**
+	 * 渠道专属优惠码
+	 */
+	Long DISTRIBUTE_POPULARIZE_COUPON_ID = 56l;
 }

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

@@ -36,7 +36,7 @@ public interface OrderDonMapper extends BaseMapper<OrderDon> {
 
 	ChannelStatisticsView selectChannelStatistics(@Param("first") String first, @Param("end") String end);
 
-	Integer selectCouponCodeUserNum(@Param("dsPopularizeId") Long dsPopularizeId, @Param("noOrderAllStatus") List<String> noOrderAllStatus);
+	Integer selectCouponCodeUserNum(@Param("dsPopularizeId") Long dsPopularizeId, @Param("exCode") String exCode, @Param("noOrderAllStatus") List<String> noOrderAllStatus);
 
 	ChannelPopularizeView countPopularizeOrderDetail(@Param("popularizeId") Long popularizeId, @Param("startTime") String startTime, @Param("endTime") String endTime);
 
@@ -49,4 +49,8 @@ public interface OrderDonMapper extends BaseMapper<OrderDon> {
 	OrderDonCustomerServiceRelate selectOrderRelate(Long orderId);
 
 	String selectMaxRefundGoodsName(@Param("operator") String operator, @Param("startTime") String startTime, @Param("endTime") String endTime);
+
+	BigDecimal getCouponUsedMoney(Long couponId);
+
+	BrokenLineObjView selectDsPlatBrokenLineMoney(@Param("sharedId") Long sharedId, @Param("first") String first, @Param("end") String end);
 }

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

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.UserDistributeReturnMoneyDetail;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: UserDistributeReturnMoneyDetailMapper
+ * 创建者: JavaZou
+ * 创建时间:2024/7/29 18:46
+ */
+public interface UserDistributeReturnMoneyDetailMapper extends BaseMapper<UserDistributeReturnMoneyDetail> {
+}

+ 17 - 0
netflix-dao/src/main/java/com/cyksj/mapper/UserDistributeSharedRelateUnbindMapper.java

@@ -0,0 +1,17 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.UserDistributeSharedRelateUnbind;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: UserDistributeSharedRelateUnbindMapper
+ * 创建者: JavaZou
+ * 创建时间:2023/12/6 15:38
+ */
+public interface UserDistributeSharedRelateUnbindMapper extends BaseMapper<UserDistributeSharedRelateUnbind> {
+	void batchInsert(@Param("list") List<Long> userBind);
+}

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

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

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

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

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

@@ -32,4 +32,7 @@ public interface UserMapper extends BaseMapper<User> {
 
     @Select("select id from user where show_id = #{showId} limit 1")
     Long getUserIdByShowId(String showId);
+
+    @Update("update user set points = points - #{points} where id = #{id} and points >= #{points} and points > 0")
+    Integer subPoints(@Param("id") Long id, @Param("points") BigDecimal points);
 }

+ 3 - 0
netflix-dao/src/main/java/com/cyksj/mapper/manage/coupon/CouponMapper.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.cyksj.model.dto.CouponPopularizeDto;
 import com.cyksj.model.entity.Coupon;
 import com.cyksj.model.entity.CouponUser;
+import com.cyksj.model.entity.GoodsDonSku;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 
@@ -29,4 +30,6 @@ public interface CouponMapper extends BaseMapper<Coupon> {
 
 	@Select("select name from coupon where id = #{couponId}")
 	String getCouponNameById(Long couponId);
+
+	List<GoodsDonSku> getCouponSku(Long couponId);
 }

+ 6 - 1
netflix-dao/src/main/java/com/cyksj/mapper/manage/coupon/CouponUserMapper.java

@@ -10,6 +10,7 @@ import com.cyksj.model.views.CouponUserView;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
+import java.util.Map;
 
 /*
  *项目名: netflix
@@ -24,7 +25,11 @@ public interface CouponUserMapper extends BaseMapper<CouponUser> {
 
 	Page<CouponActiveView> couponCenterList(@Param("userId") Long userId, IPage<CouponUserView> page);
 
-	Page<CouponUserView> couponPersonalList(@Param("userId") Long userId, @Param("page") Page<CouponUserView> page);
+	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);
+
+	Map<String, Long> selectCouponUserNumData(Long couponId);
+
+	CouponUserView getCouponDetailById(@Param("userId") long userId, @Param("couponId") Long couponId);
 }

+ 1 - 0
netflix-dao/src/main/java/com/cyksj/mapper/manage/distribute/UserDistributeSharedWhiteMapper.java

@@ -1,6 +1,7 @@
 package com.cyksj.mapper.manage.distribute;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.UserDistributeSharedWhite;
 
 /**
  * 项目名: yhlxj2

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

@@ -39,7 +39,10 @@ public class BackInfoTranslations extends BaseEntity{
 	public enum Type {
 		goods("商品"),
 		sku("规格"),
-		spec("一级规格");
+		spec("一级规格"),
+		coupon("优惠券"),
+		coupon_classification("优惠券分类"),
+		;
 		String remark;
 
 		Type(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;
+
 	/**
 	 * 优惠券使用状态
 	 */

+ 26 - 5
netflix-dao/src/main/java/com/cyksj/model/entity/DistributeMoneyApply.java

@@ -27,6 +27,11 @@ public class DistributeMoneyApply extends BaseEntity {
 
 	private Status verifyStatus;
 
+	/**
+	 * 功能类型
+	 */
+	private MType mType;
+
 	private Type type;
 
 	private String account;
@@ -51,11 +56,8 @@ public class DistributeMoneyApply extends BaseEntity {
 
 	@Getter
 	public enum Type {
-		zfb("支付宝"),
-		wechat("微信"),
 		usdt("usdt"),
-		pwdRed("口令红包"),
-		other("其他")
+		bank("银行卡"),
 		;
 		String desc;
 
@@ -88,4 +90,23 @@ public class DistributeMoneyApply extends BaseEntity {
 			return Arrays.stream(Status.values()).filter(st -> st.name().equals(status)).findFirst().orElse(null);
 		}
 	}
-}
+
+	@Getter
+	public enum MType {
+		ds("用户分销"),
+		sub("邀请奖励"),
+		;
+		String desc;
+
+		MType(String desc) {
+			this.desc = desc;
+		}
+
+		public MType getType(String value) {
+			if (StrUtil.isEmpty(value)) {
+				return null;
+			}
+			return Arrays.stream(MType.values()).filter(type -> type.name().equals(value)).findFirst().get();
+		}
+	}
+}

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

@@ -29,6 +29,21 @@ public class DistributeWaitingSendPoints extends BaseEntity{
 
 	private BigDecimal points;
 
+	/**
+	 * 额外返利积分(目前只针对普通推广)
+	 */
+	private BigDecimal extraRebate;
+
+	/**
+	 * 倍数
+	 */
+	private BigDecimal extraMultiple;
+
+	/**
+	 * 原本积分奖励
+	 */
+	private BigDecimal oriPoints;
+
 	private BigDecimal refundPoints;
 
 	/**
@@ -46,6 +61,27 @@ public class DistributeWaitingSendPoints extends BaseEntity{
 	 */
 	private Boolean isDelivery;
 
+	/**
+	 * 分销提成平摊折扣金额
+	 * 是否参与渠道分销规则
+	 */
+	private Boolean isRule;
+
+	/**
+	 * 平摊积分
+	 */
+	private BigDecimal deductPoints;
+
+	/**
+	 * 获取提成比例
+	 */
+	private Integer rate;
+
+	/**
+	 * 是否特殊设备分销订单
+	 */
+	private Boolean isSpecialEp;
+
 	@Getter
 	public enum Status{
 		close("分销订单关闭,积分奖励不分发"),
@@ -59,4 +95,4 @@ public class DistributeWaitingSendPoints extends BaseEntity{
 			this.desc = desc;
 		}
 	}
-}
+}

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

@@ -59,6 +59,15 @@ public class OrderDon extends BaseEntity implements Serializable {
     @DbIgnore
     private BigDecimal dpMoney;
 
+    /**
+     * 主平台订单金额 用于加购订单分销
+     */
+    private BigDecimal oriMoney;
+
+    @DbIgnore
+    @TableField(exist = false)
+    private BigDecimal dsMoney;
+
     /**
      * 货币单位
      */

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

@@ -17,6 +17,11 @@ import java.util.Date;
 public class UserDistribute extends BaseEntity{
 	private Long userId;
 
+	/**
+	 * 类型
+	 */
+	private String type;
+
 	/**
 	 * 备注
 	 */
@@ -34,4 +39,4 @@ public class UserDistribute extends BaseEntity{
 
 	@TableLogic(value = "1", delval = "0")
 	private Boolean deleted;
-}
+}

+ 22 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/UserDistributeReturnMoneyDetail.java

@@ -0,0 +1,22 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: UserDistributeReturnMoneyDetail
+ * 创建者: JavaZou
+ * 创建时间:2024/7/29 18:46
+ */
+@Getter
+@Setter
+public class UserDistributeReturnMoneyDetail extends BaseEntity{
+	private Long userId;
+
+	private BigDecimal money;
+
+	private String source;
+}

+ 8 - 1
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;
+}

+ 24 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/UserDistributeSharedRelateUnbind.java

@@ -0,0 +1,24 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: UserDistributeSharedRelateUnbind
+ * 创建者: JavaZou
+ * 创建时间:2023/12/6 15:37
+ */
+@Getter
+@Setter
+public class UserDistributeSharedRelateUnbind {
+	/**
+	 * 被分销用户id
+	 */
+	private Long userId;
+
+	/**
+	 * 是否解绑 false
+	 */
+	private Boolean isUnbind;
+}

+ 1 - 1
netflix-dao/src/main/java/com/cyksj/mapper/manage/distribute/UserDistributeSharedWhite.java → netflix-dao/src/main/java/com/cyksj/model/entity/UserDistributeSharedWhite.java

@@ -1,4 +1,4 @@
-package com.cyksj.mapper.manage.distribute;
+package com.cyksj.model.entity;
 
 import com.baomidou.mybatisplus.annotation.FieldFill;
 import com.baomidou.mybatisplus.annotation.IdType;

+ 13 - 1
netflix-dao/src/main/java/com/cyksj/model/request/ApplyMoneyReq.java

@@ -17,8 +17,18 @@ public class ApplyMoneyReq {
 
 	private DistributeMoneyApply.Type type;
 
+	/**
+	 * 功能类型
+	 */
+	private DistributeMoneyApply.MType mType = DistributeMoneyApply.MType.ds;
+
 	private String realName;
 
+	/**
+	 * 卡号
+	 */
+	private String bankNo;
+
 	/**
 	 * true提现所有积分金额
 	 */
@@ -33,4 +43,6 @@ public class ApplyMoneyReq {
 	 * 备注
 	 */
 	private String remark;
-}
+
+	private Long userId;
+}

+ 5 - 1
netflix-dao/src/main/java/com/cyksj/model/request/TransferAccountsReq.java

@@ -47,4 +47,8 @@ public class TransferAccountsReq {
 	private Integer scope;
 
 	private Long userId;
-}
+
+	private Integer channelType;
+
+	private String remark;
+}

+ 22 - 2
netflix-dao/src/main/java/com/cyksj/model/request/UserDistributeReq.java

@@ -1,6 +1,6 @@
 package com.cyksj.model.request;
 
-import com.cyksj.model.entity.UserPlatDistributeRate;
+import com.cyksj.model.entity.*;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -27,10 +27,30 @@ public class UserDistributeReq {
 	 */
 	private Long businessId;
 
+	/**
+	 * 分类
+	 */
+	private String type;
+
 	private String remark;
 
 	/**
 	 * 平台分销比例
 	 */
 	private List<UserPlatDistributeRate> rates;
-}
+
+	/**
+	 * 平台规格分销比例
+	 */
+	private List<UserPlatSkuDistributeRate> skuRates;
+
+	/**
+	 * 渠道关联优惠券 列表
+	 */
+	private List<CouponDistributePopularize> couponRelates;
+
+	/**
+	 * 渠道目标额
+	 */
+	private List<UserDistributeTargetAlert> targets;
+}

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

@@ -32,5 +32,7 @@ public class BrokenLineObjView {
 
 	private Map<Long, List<PlatOrderDonBrokenLineView>> goodsData;
 
+	private Map<Long, List<DistributePlatOrderDonBrokenLineView>> dsGoodsData;
+
 	private Map<Long, List<PersonDistributeBrokenLineView>> distributeData;
-}
+}

+ 22 - 0
netflix-dao/src/main/java/com/cyksj/model/views/BusinessDistributeDefaultRateDetailReq.java

@@ -0,0 +1,22 @@
+package com.cyksj.model.views;
+
+import com.cyksj.model.entity.BusinessDistributeDefaultRateConfig;
+import com.cyksj.model.entity.BusinessDistributeDefaultSkuRateConfig;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: BusinessDistributeDefaultRateDetailReq
+ * 创建者: JavaZou
+ * 创建时间:2023/11/15 16:15
+ */
+@Getter
+@Setter
+public class BusinessDistributeDefaultRateDetailReq {
+	private List<BusinessDistributeDefaultRateConfig> rates;
+
+	private List<BusinessDistributeDefaultSkuRateConfig> skuRates;
+}

+ 23 - 0
netflix-dao/src/main/java/com/cyksj/model/views/BusinessDistributeRateDetailView.java

@@ -0,0 +1,23 @@
+package com.cyksj.model.views;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: BusinessDistributeRateDetailView
+ * 创建者: JavaZou
+ * 创建时间:2023/11/14 15:05
+ */
+@Getter
+@Setter
+public class BusinessDistributeRateDetailView {
+
+	private List<BusinessDistributeRateView> rates;
+
+
+	private List<BusinessDistributeSkuRateView> skuRates;
+
+}

+ 45 - 0
netflix-dao/src/main/java/com/cyksj/model/views/BusinessDistributeSkuRateView.java

@@ -0,0 +1,45 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: BusinessDistributeSkuRateView
+ * 创建者: JavaZou
+ * 创建时间:2023/11/14 15:06
+ */
+@Getter
+@Setter
+@SearchBean(tables = "goods_don g left join goods_don_sku sku on sku.goods_id = g.id" +
+		" left join business_distribute_default_sku_rate_config bdc on bdc.sku_id = sku.id",
+		where = "g.deleted is true and g.status is true and g.is_distribute is true and g.is_sku_distribute is true and sku.status is true",
+		orderBy = "g.id")
+public class BusinessDistributeSkuRateView {
+
+	@DbField("bdc.id")
+	private Long id;
+
+	@DbField("g.id")
+	private Long goodsId;
+
+	@DbField("g.title")
+	private String title;
+
+	@DbField("g.type")
+	private Integer type;
+
+	@DbField("sku.id")
+	private Long skuId;
+
+	@DbField("sku.spec_val")
+	private String specVal;
+
+	@DbField("bdc.rate")
+	private Integer rate;
+
+	@DbField("bdc.second_rate")
+	private Integer secondRate;
+}

+ 50 - 0
netflix-dao/src/main/java/com/cyksj/model/views/CouponDistributePopularizeDetailView.java

@@ -0,0 +1,50 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: CouponDistributePopularizeDetailView
+ * 创建者: JavaZou
+ * 创建时间:2023/11/27 12:14
+ */
+@Getter
+@Setter
+@SearchBean(tables = "coupon_distribute_popularize cp inner join coupon c on c.id = cp.coupon_id",
+		where = "cp.deleted is true and cp.is_general is false and c.deleted is true")
+public class CouponDistributePopularizeDetailView {
+	@DbField("cp.id")
+	private Long id;
+
+	@DbField("cp.coupon_id")
+	private Long couponId;
+
+	@DbField("c.name")
+	private String couponName;
+
+	@DbField("c.classification_id")
+	private Long classificationId;
+	/**
+	 * 固定推广者id
+	 */
+	@DbField("cp.distribute_id")
+	private Long distributeId;
+
+	@DbField("cp.user_id")
+	private Long userId;
+
+	/**
+	 * 是否是普通 默认不是
+	 */
+	@DbField("cp.is_general")
+	private Boolean isGeneral;
+
+	/**
+	 * 兑换码
+	 */
+	@DbField("cp.ex_code")
+	private String exCode;
+}

+ 45 - 0
netflix-dao/src/main/java/com/cyksj/model/views/CouponReceiptDetailView.java

@@ -0,0 +1,45 @@
+package com.cyksj.model.views;
+
+import com.cyksj.model.entity.CouponUser;
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: CouponReceiptDetailView
+ * 创建者: JavaZou
+ * 创建时间:2024/4/16 16:58
+ */
+@Getter
+@Setter
+@SearchBean(tables = "(select id,name from coupon where deleted is true :cid:) c inner join coupon_user cu on cu.coupon_id = c.id inner join user u on u.id = cu.user_id")
+public class CouponReceiptDetailView {
+
+	@DbField("cu.id")
+	private Long id;
+
+	@DbField("c.id")
+	private Long couponId;
+
+	@DbField("c.name")
+	private String name;
+
+	@DbField("u.id")
+	private Long userId;
+
+	@DbField("u.nickname")
+	private String nickname;
+
+	@DbField("cu.status")
+	private CouponUser.Status status;
+
+	@DbField("cu.created_time")
+	private Date receiptTime;
+
+	@DbField("cu.valid_end_time")
+	private Date expiryTime;
+}

+ 59 - 0
netflix-dao/src/main/java/com/cyksj/model/views/CouponUsedDetailView.java

@@ -0,0 +1,59 @@
+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
+ * 文件名: CouponUsedDetailView
+ * 创建者: JavaZou
+ * 创建时间:2024/4/16 17:05
+ */
+@Getter
+@Setter
+@SearchBean(tables = "(select id,name from coupon where deleted is true :cid:) c inner join coupon_user cu on cu.coupon_id = c.id inner join user u on u.id = cu.user_id" +
+		" inner join order_don o on o.coupon_user_id = cu.id and o.status not in ('close','noPayment','refund')" +
+		" left join goods_don g on g.id = o.goods_id" +
+		" left join goods_don_sku sku on sku.id = o.sku_id")
+public class CouponUsedDetailView {
+
+	@DbField("cu.id")
+	private Long id;
+
+	@DbField("c.id")
+	private Long couponId;
+
+	@DbField("c.name")
+	private String name;
+
+	@DbField("u.id")
+	private Long userId;
+
+	@DbField("u.nickname")
+	private String nickname;
+
+	@DbField("o.order_no")
+	private String orderNo;
+
+	@DbField("cu.created_time")
+	private Date receiptTime;
+
+	@DbField("sku.id")
+	private Long skuId;
+
+	@DbField("sku.spec_val")
+	private String specVal;
+
+	@DbField("g.id")
+	private Long goodsId;
+
+	@DbField("g.title")
+	private String goodsName;
+
+	@DbField("o.created_time")
+	private Date usedTime;
+}

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

@@ -124,6 +124,9 @@ public class CouponView {
 	@DbIgnore
 	private Integer usedNum;
 
+	@DbIgnore
+	private Integer receiptNum;
+
 	/**
 	 * 发放状态
 	 */
@@ -147,4 +150,4 @@ public class CouponView {
 
 	@DbField("c.created_time")
 	private Date createdTime;
-}
+}

+ 18 - 0
netflix-dao/src/main/java/com/cyksj/model/views/DistributeGoodsGeneralRateView.java

@@ -0,0 +1,18 @@
+package com.cyksj.model.views;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: DistributeGoodsGeneralRateView
+ * 创建者: JavaZou
+ * 创建时间:2024/1/11 14:26
+ */
+@Getter
+@Setter
+public class DistributeGoodsGeneralRateView {
+	private Integer rate;
+
+	private String goodsInfo;
+}

+ 42 - 0
netflix-dao/src/main/java/com/cyksj/model/views/DistributePlatOrderDonBrokenLineView.java

@@ -0,0 +1,42 @@
+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
+ * 文件名: DistributePlatOrderDonBrokenLineView
+ * 创建者: JavaZou
+ * 创建时间:2023/11/17 18:05
+ */
+@Getter
+@Setter
+@SearchBean(tables = "(select order_id from distribute_waiting_send_points dp :sid:) dp inner join order_don od on od.id = dp.order_id",
+		where = "od.status not in ('noPayment','close','refund')",
+		groupBy = "od.goods_id,date_format(od.created_time,'%Y-%m-%d')")
+public class DistributePlatOrderDonBrokenLineView {
+	@DbField("od.goods_id")
+	private Long goodsId;
+
+	/**
+	 * 平台名称
+	 */
+	@DbField("select title from goods_don where id = od.goods_id")
+	private String goodsTitle;
+
+	/**
+	 * 当前日期订单金额
+	 */
+	@DbField("cast(sum(od.money)/100 as decimal(10,2))")
+	private BigDecimal money;
+
+	/**
+	 * 日期
+	 */
+	@DbField("date_format(od.created_time,'%Y-%m-%d')")
+	private String date;
+}

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

@@ -34,7 +34,7 @@ public class DistributePopularizeOrdersView {
 	@JsonIgnore
 	private Long skuId;
 
-	@DbField("od.money")
+	@DbField("if(od.is_dp and od.ori_money != 0,od.ori_money,od.money)")
 	private BigDecimal money;
 
 	@DbField("dw.shared_id")
@@ -47,9 +47,21 @@ public class DistributePopularizeOrdersView {
 	@DbField("dw.points")
 	private BigDecimal points;
 
+	@DbField("dw.extra_rebate")
+	private BigDecimal extraRebate;
+
+	/**
+	 * 原本积分奖励
+	 */
+	@DbField("dw.ori_points")
+	private BigDecimal oriPoints;
+
 	@DbIgnore
 	private BigDecimal waitGetMoney;
 
+	@DbIgnore
+	private BigDecimal oriGetMoney;
+
 	@DbField("dw.send_status")
 	private String sendStatus;
 
@@ -59,9 +71,9 @@ public class DistributePopularizeOrdersView {
 	@DbField("od.status")
 	private OrderDon.Status orderStatus;
 
-	@DbIgnore
+	@DbField("od.pay_title")
 	private String specVal;
 
 	@DbField("od.created_time")
 	private Date createdTime;
-}
+}

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

@@ -68,5 +68,5 @@ public class DistributePopularizeView {
 	/**
 	 * 普通低分销比例
 	 */
-	private List<GoodsDon> generalDistributes;
+	private List<DistributeGoodsGeneralRateView> generalDistributes;
 }

+ 27 - 0
netflix-dao/src/main/java/com/cyksj/model/views/DistributeSearchView.java

@@ -0,0 +1,27 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: DistributeSearchView
+ * 创建者: JavaZou
+ * 创建时间:2024/1/2 15:34
+ */
+@Getter
+@Setter
+@SearchBean(tables = "user_distribute ud inner join user u on u.id = ud.user_id and ud.deleted is true")
+public class DistributeSearchView {
+
+	@DbField("ud.id")
+	private Long distributeId;
+
+	@DbField("u.nickname")
+	private String nickname;
+
+	@DbField("ud.user_id")
+	private Long userId;
+}

+ 40 - 0
netflix-dao/src/main/java/com/cyksj/model/views/GoodsDonSkuRateView.java

@@ -0,0 +1,40 @@
+package com.cyksj.model.views;
+
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: GoodsDonSkuRateView
+ * 创建者: JavaZou
+ * 创建时间:2024/6/24 14:17
+ */
+
+@Getter
+@Setter
+@SearchBean(tables = "goods_don_sku sku inner join goods_don g on g.id = sku.goods_id" +
+		" left join distribute_general_sku_rate sr on sr.sku_id = sku.id",
+		where = "g.is_distribute is true and g.is_sku_distribute is true and g.type = 1 and g.status is true and g.deleted is true and sku.status is true",
+		orderBy = "sku.goods_id asc")
+public class GoodsDonSkuRateView {
+	@DbField("sr.id")
+	private Long id;
+
+	@DbField("sku.goods_id")
+	private Long goodsId;
+
+	@DbField("g.title")
+	private String title;
+
+	@DbField("sku.id")
+	private Long skuId;
+
+	@DbField("sku.spec_val")
+	private String specVal;
+
+	@DbField("sr.rate")
+	private Integer rate;
+}

+ 65 - 0
netflix-dao/src/main/java/com/cyksj/model/views/UserCommonDistributeView.java

@@ -0,0 +1,65 @@
+package com.cyksj.model.views;
+
+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.math.BigDecimal;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserCommonDistributeView
+ * 创建者: JavaZou
+ * 创建时间:2024/1/31 17:35
+ */
+@Getter
+@Setter
+@SearchBean(tables = "(select id,nickname from user where 1 = 1 :condition:) u left join user_distribute_shared us on u.id = us.shared_id" +
+		" left join user_distribute ud on ud.user_id = u.id and ud.deleted is true" +
+		" left join order_don od on od.user_id = us.user_id and od.is_distribute = 1 and od.status not in ('noPayment', 'close') :time:"
+		, where = "ud.id is null",
+		groupBy = "u.id,u.nickname")
+public class UserCommonDistributeView {
+
+	@DbField("u.id")
+	private Long userId;
+
+	@DbField("u.nickname")
+	private String nickname;
+
+	@DbField("count(od.id)")
+	private Integer orders;
+
+	/**
+	 * 分销人数
+	 * 其中拉新用户购买一单又退款,且无后续下单动作的不算分销用户,不统计在此字段内
+	 */
+	@DbField("count(DISTINCT CASE WHEN od.status != 'refund' THEN us.user_id ELSE null END)")
+	private Integer distributeUserNum;
+
+	/**
+	 * 邀请人数
+	 */
+	@DbField("count(DISTINCT us.user_id)")
+	private Integer inviteNum;
+
+	/**
+	 * 分销订单金额(无需产生积分)
+	 */
+	@DbField("(ifnull(sum(if(od.is_dp and od.ori_money != 0,od.ori_money,od.money)),0) - ifnull(sum(od.refund_money),0))")
+	private BigDecimal distributeOrdersMoney;
+
+	/**
+	 * 分销消费占比
+	 */
+	@DbField("ifnull(cast(count(DISTINCT CASE WHEN od.status != 'refund' THEN us.user_id ELSE null END)/count(DISTINCT us.user_id) as decimal(10,2)),0)")
+	private BigDecimal distributeConsumerRate;
+
+	/**
+	 * 销量最高的产品
+	 */
+	@DbIgnore
+	private String goodsTitle;
+}

+ 31 - 0
netflix-dao/src/main/java/com/cyksj/model/views/UserDistributeRateDetailView.java

@@ -0,0 +1,31 @@
+package com.cyksj.model.views;
+
+import com.cyksj.model.entity.UserDistributeTargetAlert;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: UserDistributeRateDetailView
+ * 创建者: JavaZou
+ * 创建时间:2023/11/14 13:58
+ */
+@Getter
+@Setter
+public class UserDistributeRateDetailView {
+	private List<UserDistributeView> rates;
+
+	private List<UserSkuDistributeView> skuRates;
+
+	/**
+	 * 渠道关联优惠券 列表
+	 */
+	private List<CouponDistributePopularizeDetailView> couponRelates;
+
+	/**
+	 * 渠道目标额
+	 */
+	private List<UserDistributeTargetAlert> targets;
+}

+ 44 - 0
netflix-dao/src/main/java/com/cyksj/model/views/UserSkuDistributeView.java

@@ -0,0 +1,44 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: UserSkuDistributeView
+ * 创建者: JavaZou
+ * 创建时间:2023/11/14 13:59
+ */
+@Getter
+@Setter
+@SearchBean(tables = "goods_don gd left join goods_don_sku sku on sku.goods_id = gd.id" +
+		" left join user_plat_sku_distribute_rate up on sku.id = up.sku_id :dis_id:" +
+		" left join business_distribute_default_sku_rate_config bdc on bdc.sku_id = sku.id",
+		where = "gd.deleted is true and gd.status is true and gd.is_distribute is true and gd.is_sku_distribute is true and sku.status is true")
+public class UserSkuDistributeView {
+	@DbField("up.id")
+	private Long id;
+
+	@DbField("gd.id")
+	private Long goodsId;
+
+	@DbField("gd.title")
+	private String title;
+
+	@DbField("sku.id")
+	private Long skuId;
+
+	@DbField("sku.spec_val")
+	private String specVal;
+
+	@DbField("ifnull(up.rate,bdc.rate)")
+	private Integer rate;
+
+	@DbField("gd.type")
+	private Integer type;
+
+	@DbField("ifnull(up.second_rate,bdc.second_rate)")
+	private Integer secondRate;
+}

+ 7 - 0
netflix-dao/src/main/resources/mapper/CouponMapper.xml

@@ -41,4 +41,11 @@
         where cp.deleted is true
           and (cp.ex_code = #{couponExCode} or cdp.ex_code = #{couponExCode}) limit 1
     </select>
+
+    <select id="getCouponSku" resultType="com.cyksj.model.entity.GoodsDonSku">
+        select sku.id, sku.goods_id, sku.spec_val
+        from `coupon_sku` ck
+                 left join `goods_don_sku` gdk on gdk.id = ck.sku_id
+        where ck.coupon_id = #{couponId}
+    </select>
 </mapper>

+ 63 - 31
netflix-dao/src/main/resources/mapper/CouponUserMapper.xml

@@ -139,10 +139,49 @@
 
     <select id="couponPersonalList" resultType="com.cyksj.model.views.CouponUserView">
         select s.* from (select cu.id,
-               cu.channel,
-               cu.user_id,
-               c.id                     as couponId,
-               ca.id                    as couponActiveId,
+        cu.channel,
+        cu.user_id,
+        c.id                     as couponId,
+        ca.id                    as couponActiveId,
+        c.name,
+        c.goods_type,
+        c.type,
+        c.reduce_condition,
+        c.reduce_money,
+        c.discount,
+        c.use_scope,
+        c.goods_sku_ids,
+        c.is_valid_time,
+        cu.valid_start_time,
+        c.valid_days,
+        c.valid_hours,
+        cu.valid_end_time,
+        (case
+        when cu.status = 'used' then 'used'
+        when cu.valid_end_time &lt; now() then 'expired'
+        when ca.id is not null and ca.expiry_status = 0 then 'invalid'
+        when cu.valid_start_time > now() then 'notEffective'
+        else cu.status end) as couponUserStatus,
+        (case
+        when cu.status = 'used' then 4
+        when cu.valid_end_time &lt; now() then 2
+        when ca.id is not null and ca.expiry_status = 0 then 3
+        when cu.valid_start_time > now() then 1
+        when cu.status = 'unused' then 0
+        end)                 as orderby
+        from `coupon_user` cu
+        left join `coupon` c on c.id = cu.coupon_id
+        left join `coupon_active` ca on ca.id = cu.coupon_active_id
+        where cu.user_id = #{userId}
+        <if test="couponId !=null">
+            and cu.coupon_id = #{couponId}
+        </if>
+        and cu.channel != 'exCode'
+        order by `orderby`)s where s.couponUserStatus != 'expired' and s.couponUserStatus != 'invalid'
+    </select>
+
+    <select id="getNewUserWelfareCouponsByUserId" resultType="com.cyksj.model.views.CouponUserView">
+        select cu.*,
                c.name,
                c.goods_type,
                c.type,
@@ -151,33 +190,28 @@
                c.discount,
                c.use_scope,
                c.goods_sku_ids,
-               c.is_valid_time,
                cu.valid_start_time,
-               c.valid_days,
-               c.valid_hours,
                cu.valid_end_time,
-               (case
-                    when cu.status = 'used' then 'used'
-                    when cu.valid_end_time &lt; now() then 'expired'
-                    when ca.id is not null and ca.expiry_status = 0 then 'invalid'
-                    when cu.valid_start_time > now() then 'notEffective'
-                    else cu.status end) as couponUserStatus,
-               (case
-                    when cu.status = 'used' then 4
-                    when cu.valid_end_time &lt; now() then 2
-                    when ca.id is not null and ca.expiry_status = 0 then 3
-                    when cu.valid_start_time > now() then 1
-                    when cu.status = 'unused' then 0
-                   end)                 as orderby
-        from `coupon_user` cu
-                 left join `coupon` c on c.id = cu.coupon_id
-                 left join `coupon_active` ca on ca.id = cu.coupon_active_id
-        where cu.user_id = #{userId}
-          and cu.channel != 'exCode'
-        order by `orderby`)s where s.couponUserStatus != 'expired' and s.couponUserStatus != 'invalid'
+               unix_timestamp(cu.valid_end_time) * 1000 as validEndTimestamp
+        from (select coupon_id,
+                     valid_start_time,
+                     valid_end_time,
+                     status as couponUserStatus
+              from `coupon_user`
+              where channel = #{channel}
+                and user_id = #{userId}
+                and valid_end_time > #{now}
+                 and status = 'unused' limit 1) cu
+                 inner join coupon c on c.id = cu.coupon_id
     </select>
 
-    <select id="getNewUserWelfareCouponsByUserId" resultType="com.cyksj.model.views.CouponUserView">
+    <select id="selectCouponUserNumData" resultType="java.util.Map">
+        select count(if(status = 'used', 1, NULL)) usedNum, count(*) receiptNum
+        from coupon_user
+        where coupon_id = #{couponId}
+    </select>
+
+    <select id="getCouponDetailById" resultType="com.cyksj.model.views.CouponUserView">
         select cu.*,
                c.name,
                c.goods_type,
@@ -195,10 +229,8 @@
                      valid_end_time,
                      status as couponUserStatus
               from `coupon_user`
-              where channel = #{channel}
-                and user_id = #{userId}
-                and valid_end_time > #{now}
-                 and status = 'unused' limit 1) cu
+              where user_id = #{userId}
+                and coupon_id = #{couponId} limit 1) cu
                  inner join coupon c on c.id = cu.coupon_id
     </select>
 </mapper>

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

@@ -103,7 +103,7 @@
     </select>
 
     <select id="selectCouponCodeUserNum" resultType="java.lang.Integer">
-        select count(distinct user_id) from order_don where ds_popularize_id = #{dsPopularizeId}
+        select count(distinct user_id) from order_don where (ds_popularize_id = #{dsPopularizeId} or coupon_ex_code = #{exCode})
         and status not in
         <foreach collection="noOrderAllStatus" item="item" open="(" separator="," close=")">
             #{item}
@@ -190,4 +190,28 @@
         group by o.goods_id
         order by count(*) desc limit 1
     </select>
+
+    <select id="getCouponUsedMoney" resultType="java.math.BigDecimal">
+        select sum(money) - sum(ifnull(refund_money, 0))
+        from (select id from coupon_user where coupon_id = #{couponId}) cu
+                 inner join order_don o on o.coupon_user_id = cu.id and o.status not in ('close', 'noPayment')
+    </select>
+
+    <select id="selectDsPlatBrokenLineMoney" resultType="com.cyksj.model.views.BrokenLineObjView">
+        select min(curdate) as firstDate,
+        max(curdate) as lastDate
+        from (select cast(sum(od.money)/100 as decimal(10,2)) as curdateMoney,
+        date_format(od.created_time,'%Y-%m-%d') curdate from (select order_id from distribute_waiting_send_points where
+        shared_id = #{sharedId}) dp inner join order_don od
+        on od.id = dp.order_id
+        where od.status not in ('noPayment','close','refund')
+        group by od.goods_id,date_format(od.created_time,'%Y-%m-%d'))s
+        where 1 = 1
+        <if test="first != null">
+            and curdate >= #{first}
+        </if>
+        <if test="end != null">
+            and curdate &lt; #{end}
+        </if>
+    </select>
 </mapper>

+ 13 - 0
netflix-dao/src/main/resources/mapper/UserDistributeSharedRelateUnbindMapper.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.cyksj.mapper.UserDistributeSharedRelateUnbindMapper">
+
+
+    <insert id="batchInsert">
+        insert ignore into user_distribute_shared_relate_unbind(`user_id`,`created_time`,`update_time`)
+        values
+        <foreach collection="list" item="item" separator=",">
+            (#{item},now(),now())
+        </foreach>
+    </insert>
+</mapper>

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

@@ -636,6 +636,8 @@ public class RedisService {
         CLOSE_ORDER_TIME_KEY("close_order_time_key:", "关闭订单key", 3 * 60),
         GROUPS_TRIPS_OUTSIDE_RELATION("groups_trips_outside_relation:key:%s:%s", "额外车位", 30l),
         DOUBLE_VERIFY_CODE_VIEW_MINUTES_KEY("double_verify_code_view_minutes_key","双重验证码查看同时间段人数限制",60),
+        USER_DISTRIBUTE_ADD_KEY("user_distribute_add_key:%s", "分销用户新增key", 30l),
+        APPLY_MONEY_DAY_LIMIT_KEY("apply_money_day_limit_key:%s:%s:%s", "每日提现次数限制", 60 * 60 * 24L),
         ;
 
         private String name;

+ 7 - 11
netflix-service/src/main/java/com/cyksj/service/coupon/CouponFontService.java

@@ -20,20 +20,10 @@ public interface CouponFontService {
 	 */
 	void collectCoupon(CouponCollectReq couponCollectReq, Long userId);
 
-	/**
-	 * 领取推荐优惠券
-	 */
-	void collectRecommendCoupon(CouponCollectReq couponCollectReq, Long userId);
-
-	/**
-	 * 一键领取推荐优惠券
-	 */
-	void collectWholeRecommendCoupon(Long userId);
-
 	/**
 	 * 可用/不可用优惠券
 	 */
-	Page<CouponUserView> getAvailableCouponList(Long skuId, Long couponId, Long userId, Boolean isRenew, Long start, Long limit);
+	Page<CouponUserView> getAvailableCouponList(Long skuId, Long couponId, Long userId, Boolean isRenew, Long start, Long limit, String lang);
 
 	/**
 	 * 优惠券状态
@@ -66,4 +56,10 @@ public interface CouponFontService {
 	 * 新用户福利优惠券
 	 */
 	CouponUserView getNewUserWelfareCoupons(long userId, DateTime now);
+
+	CouponUserView getCouponDetailById(long userId, Long couponId, String lang);
+
+	CouponUserView receiveCoupon(long userId, Long couponId, String lang);
+
+	String setCouponSkuLanguage(Long couponId, String lang);
 }

+ 35 - 49
netflix-service/src/main/java/com/cyksj/service/coupon/impl/CouponFontServiceImpl.java

@@ -19,6 +19,7 @@ import com.cyksj.model.request.ChannelPopularizeCouponReq;
 import com.cyksj.model.request.CouponCollectReq;
 import com.cyksj.model.views.*;
 import com.cyksj.service.coupon.CouponFontService;
+import com.cyksj.service.translations.BackInfoTranslationsFrontService;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.param.Operator;
 import com.ejlchina.searcher.util.MapUtils;
@@ -62,6 +63,8 @@ public class CouponFontServiceImpl implements CouponFontService {
 
 	private final UserMapper userMapper;
 
+	private final BackInfoTranslationsFrontService backInfoTranslationsFrontService;
+
 	@Override
 	@Transactional(rollbackFor = Throwable.class)
 	public void collectCoupon(CouponCollectReq couponCollectReq, Long userId) {
@@ -86,45 +89,7 @@ public class CouponFontServiceImpl implements CouponFontService {
 	}
 
 	@Override
-	@Transactional(rollbackFor = Throwable.class)
-	public void collectRecommendCoupon(CouponCollectReq couponCollectReq, Long userId) {
-		collectCommonCheck(couponCollectReq.getCouponId(), userId);
-
-		receiveCouponUser(couponCollectReq.getCouponId(), userId, CouponUser.Channel.recommend);
-	}
-
-	@Override
-	@Transactional(rollbackFor = Throwable.class)
-	public void collectWholeRecommendCoupon(Long userId) {
-		CouponNewUserView couponNewUserView = beanSearcher.searchFirst(CouponNewUserView.class, MapUtils.builder().field(CouponNewUserView::getUserId, userId).op(Operator.Equal).build());
-		Boolean isNewUser = true;
-		if (couponNewUserView != null) {
-			isNewUser = false;
-		}
-		//查询所有可领取的推荐优惠券
-		List<CouponAvailableRecommendView> couponAvailableRecommendViews = recommendMapper.getRecommendCouponList(userId, isNewUser);
-		couponAvailableRecommendViews.stream().forEach(data -> {
-			//领取优惠券
-			CouponUser couponUser = new CouponUser();
-			couponUser.setUserId(userId);
-			couponUser.setCouponId(data.getCouponId());
-			//推荐渠道
-			couponUser.setChannel(CouponUser.Channel.recommend);
-			couponUser.setStatus(CouponUser.Status.unused);
-			couponUser.setRecommendId(data.getRecommendId());
-			//优惠券有效时间
-			this.updateCouponUserValidTime(data.getCouponId(), couponUser);
-			try {
-				couponUserMapper.insert(couponUser);
-			} catch (DuplicateKeyException e) {
-				//插入失败继续插入 不影响
-				log.info("用户:{}一键领取推荐优惠券{}插入数据错误", userId, data.getCouponId());
-			}
-		});
-	}
-
-	@Override
-	public Page<CouponUserView> getAvailableCouponList(Long skuId, Long couponId, Long userId, Boolean isRenew, Long start, Long limit) {
+	public Page<CouponUserView> getAvailableCouponList(Long skuId, Long couponId, Long userId, Boolean isRenew, Long start, Long limit, String lang) {
 		DateTime now = DateTime.now();
 		Long goodsId = null;
 		//实物还是虚物
@@ -137,10 +102,9 @@ public class CouponFontServiceImpl implements CouponFontService {
 			goodsId = goodsDonSkuView.getGoodsId();
 		}
 		Page<CouponUserView> availableCouponList = couponUserMapper.getAvailableCouponList(skuId, couponId, goodsId, userId, isRenew, new Page<>(start, limit));
-		Optional.ofNullable(availableCouponList).ifPresent(page->{
-			page.getRecords().stream().forEach(data->{
-				String str = couponSkuMapper.selectGoodsSkuStr(data.getCouponId());
-				data.setGoodsSkuStr(str.replaceAll(",", "/").replaceAll(";", ""));
+		Optional.ofNullable(availableCouponList).ifPresent(page -> {
+			page.getRecords().stream().forEach(data -> {
+				data.setGoodsSkuStr(backInfoTranslationsFrontService.setCouponGoodsSkuStrLanguage(data.getCouponId(), lang));
 				List<CouponSkuView> couponSkus = couponSkuMapper.getGoodsSkuByCouponId(data.getCouponId());
 				try {
 					data.setGoodsSkuIds(Jsons.toJson(couponSkus));
@@ -149,12 +113,6 @@ public class CouponFontServiceImpl implements CouponFontService {
 				}
 
 				if (!data.getIsAvailable()) {
-//					data.setReason(String.format("仅限%s", data.getGoodsSkuStr()));
-//					if (data.getUseScope() == Coupon.UseScope.renew) {
-//						data.setReason(String.format("%s续费时可使用", data.getReason()));
-//					} else if (data.getUseScope() == Coupon.UseScope.orders) {
-//						data.setReason(String.format("%s下单时可使用", data.getReason()));
-//					}
 					if (data.getUseScope() == Coupon.UseScope.renew) {
 						data.setReason(I18nMessageUtil.getI18nMsg("coupon_sku_not_available_renew_error"));
 					} else if (data.getUseScope() == Coupon.UseScope.orders) {
@@ -372,4 +330,32 @@ public class CouponFontServiceImpl implements CouponFontService {
 	public CouponUserView getNewUserWelfareCoupons(long userId, DateTime now) {
 		return couponUserMapper.getNewUserWelfareCouponsByUserId(userId, CouponUser.Channel.new_welfare, now);
 	}
+
+	@Override
+	public String setCouponSkuLanguage(Long couponId, String lang) {
+		return backInfoTranslationsFrontService.setCouponGoodsSkuStrLanguage(couponId, lang);
+	}
+
+	@Override
+	public CouponUserView getCouponDetailById(long userId, Long couponId, String lang) {
+		CouponUserView couponUserView = couponUserMapper.getCouponDetailById(userId, couponId);
+		if (couponUserView != null) {
+			//多语言
+			backInfoTranslationsFrontService.setFieldLanguage(CouponUserView.class, couponUserView, BackInfoTranslations.Type.coupon.ordinal(), couponUserView.getCouponId(), lang);
+
+			String goodsSkuStr = backInfoTranslationsFrontService.setCouponGoodsSkuStrLanguage(couponId, lang);
+			couponUserView.setGoodsSkuStr(goodsSkuStr);
+		}
+		return couponUserView;
+	}
+
+	@Override
+	public CouponUserView receiveCoupon(long userId, Long couponId, String lang) {
+		try {
+			receiveCouponUser(couponId, userId, CouponUser.Channel.manual);
+		} catch (Exception e) {
+			return null;
+		}
+		return getCouponDetailById(userId, couponId, lang);
+	}
 }

+ 13 - 0
netflix-service/src/main/java/com/cyksj/service/distribute/DistributeExtraRebateService.java

@@ -0,0 +1,13 @@
+package com.cyksj.service.distribute;
+
+import com.cyksj.model.entity.DistributeExtraRebateConfig;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: DistributeExtraRebateService
+ * 创建者: JavaZou
+ * 创建时间:2024/5/29 15:24
+ */
+public interface DistributeExtraRebateService {
+	DistributeExtraRebateConfig getRandomExtraRebate();
+}

+ 35 - 0
netflix-service/src/main/java/com/cyksj/service/distribute/DistributeService.java

@@ -0,0 +1,35 @@
+package com.cyksj.service.distribute;
+
+import com.cyksj.model.entity.DistributeGeneralSkuRate;
+import com.cyksj.model.request.UserDistributeReq;
+
+import java.util.List;
+
+/*
+ *项目名: netflix
+ *文件名: DistributeService
+ *创建者: JavaZou
+ *创建时间:2022/11/14 12:21
+ */
+public interface DistributeService {
+	void insertDistribute(UserDistributeReq userDistributeReq);
+
+	void editDistribute(UserDistributeReq userDistributeReq);
+
+	/**
+	 * 保存分销邀请记录
+	 * sharedId: 邀请人
+	 * userId: 被邀请人
+	 * dsPopularizeId: 后台自定义推广链接id
+	 */
+	void saveDistributionInvitation(Long sharedId, Long userId, Long dsPopularizeId);
+
+	/**
+	 * 普通推广者绑定优惠推广码
+	 */
+	void bindPopularizeCode(Long userId, String code);
+
+	void unbindUserDistributeShared(List<Object> userBind) throws Exception;
+
+	void setDistributeCommonSkuRate(List<DistributeGeneralSkuRate> skuRates);
+}

+ 19 - 0
netflix-service/src/main/java/com/cyksj/service/distribute/UserBusinessFrontService.java

@@ -0,0 +1,19 @@
+package com.cyksj.service.distribute;
+
+import com.cyksj.model.entity.OrderDon;
+
+/*
+ *项目名: netflix
+ *文件名: UserBusinessFrontService
+ *创建者: JavaZou
+ *创建时间:2023/3/23 14:19
+ */
+public interface UserBusinessFrontService {
+	/**
+	 * @param sharedId   分销人id
+	 * @param businessId 商务id
+	 * @param order      订单
+	 * @param distributeRate      平台分销比例
+	 */
+	void taskDistributeRateBenefits(Long sharedId, Long businessId, Integer goodsType, OrderDon order, Integer distributeRate);
+}

+ 14 - 0
netflix-service/src/main/java/com/cyksj/service/distribute/UserDistributeReturnMoneyDetailService.java

@@ -0,0 +1,14 @@
+package com.cyksj.service.distribute;
+
+import java.math.BigDecimal;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: UserDistributeReturnMoneyDetailService
+ * 创建者: JavaZou
+ * 创建时间:2024/7/29 18:52
+ */
+public interface UserDistributeReturnMoneyDetailService {
+
+	void recordDistributeReturnMoney(Long userId, BigDecimal money, String source);
+}

+ 76 - 0
netflix-service/src/main/java/com/cyksj/service/distribute/impl/DistributeExtraRebateServiceImpl.java

@@ -0,0 +1,76 @@
+package com.cyksj.service.distribute.impl;
+
+import com.cyksj.mapper.manage.distribute.DistributeExtraRebateConfigMapper;
+import com.cyksj.model.entity.DistributeExtraRebateConfig;
+import com.cyksj.service.distribute.DistributeExtraRebateService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: DistributeExtraRebateServiceImpl
+ * 创建者: JavaZou
+ * 创建时间:2024/5/29 15:24
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class DistributeExtraRebateServiceImpl implements DistributeExtraRebateService {
+	private final DistributeExtraRebateConfigMapper distributeExtraRebateConfigMapper;
+
+	private static BigDecimal sums =  new BigDecimal(0);
+
+	private static List<DistributeExtraRebateConfig> distributeExtraRebateConfigs = null;
+
+	@PostConstruct
+	public void initConfig() {
+		distributeExtraRebateConfigs = distributeExtraRebateConfigMapper.selectList(null);
+
+		distributeExtraRebateConfigs.forEach(e->{
+			sums = sums.add(e.getRate());
+		});
+	}
+
+	@Override
+	public DistributeExtraRebateConfig getRandomExtraRebate() {
+		if (distributeExtraRebateConfigs == null) {
+			return null;
+		}
+		int i = randomProbabilityIndex(distributeExtraRebateConfigs);
+		if (i == -1) {
+			log.info("普通分销 推广奖励倍数异常..");
+			return null;
+		}
+		return distributeExtraRebateConfigs.get(i);
+	}
+
+	public int randomProbabilityIndex(List<DistributeExtraRebateConfig> list) {
+		int random = -1;
+		//总权重
+		Double totalProbability = sums.doubleValue();
+		//产生随机数
+		Double randomNumber = ThreadLocalRandom.current().nextDouble();
+		//根据随机数在所有奖品分布的区域并确定所抽奖品
+		Double d1 = 0d;
+		Double d2 = 0d;
+		for (int i = 0; i < list.size(); i++) {
+			d2 += Double.parseDouble(String.valueOf(list.get(i).getRate())) / totalProbability;
+			if (i == 0) {
+				d1 = 0d;
+			} else {
+				d1 += Double.parseDouble(String.valueOf(list.get(i - 1).getRate())) / totalProbability;
+			}
+			if (randomNumber >= d1 && randomNumber < d2) {
+				random = i;
+				break;
+			}
+		}
+		return random;
+	}
+}

+ 523 - 0
netflix-service/src/main/java/com/cyksj/service/distribute/impl/DistributeServiceImpl.java

@@ -0,0 +1,523 @@
+package com.cyksj.service.distribute.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.ObjectUtil;
+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.common.util.Jsons;
+import com.cyksj.mapper.GoodsDonMapper;
+import com.cyksj.mapper.UserDistributeSharedRelateUnbindMapper;
+import com.cyksj.mapper.UserMapper;
+import com.cyksj.mapper.manage.coupon.CouponDistributePopularizeMapper;
+import com.cyksj.mapper.manage.coupon.CouponMapper;
+import com.cyksj.mapper.manage.distribute.*;
+import com.cyksj.model.entity.*;
+import com.cyksj.model.request.UserDistributeReq;
+import com.cyksj.redis.RedisService;
+import com.cyksj.service.distribute.DistributeService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+/*
+ *项目名: netflix
+ *文件名: DistributeServiceImpl
+ *创建者: JavaZou
+ *创建时间:2022/11/14 12:21
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class DistributeServiceImpl implements DistributeService {
+	private final UserDistributeMapper userDistributeMapper;
+
+	private final UserPlatDistributeRateMapper userPlatDistributeRateMapper;
+
+	private final GoodsDonMapper goodsDonMapper;
+
+	private final UserDistributeSharedMapper userDistributeSharedMapper;
+
+	private final UserBusinessDefaultRateConfigMapper defaultRateConfigMapper;
+
+	private final RedisService redisService;
+
+	private final CouponMapper couponMapper;
+
+	private final CouponDistributePopularizeMapper couponDistributePopularizeMapper;
+
+	private final UserPlatSkuDistributeRateMapper userPlatSkuDistributeRateMapper;
+
+	private final UserDistributeTargetAlertMapper targetAlertMapper;
+
+	private final UserDistributeSharedRelateUnbindMapper userDistributeSharedRelateUnbindMapper;
+
+	private final DistributeGeneralSkuRateMapper generalSkuRateMapper;
+
+	private final UserMapper userMapper;
+
+	@Override
+	@Transactional(rollbackFor = Throwable.class)
+	public void insertDistribute(UserDistributeReq userDistributeReq) {
+		if (!redisService.setNx(RedisService.key.USER_DISTRIBUTE_ADD_KEY.getNameFormat(userDistributeReq.getUserId()), userDistributeReq.getUserId(), 2 * 5l)) {
+			return;
+		}
+		UserDistribute exists = userDistributeMapper.selectOne(Wrappers.lambdaQuery(UserDistribute.class).eq(UserDistribute::getUserId, userDistributeReq.getUserId()).eq(UserDistribute::getDeleted, true).last("limit 1"));
+		if (exists != null) {
+			throw BusinessRuntimeException.getInstance("该推广者已添加");
+		}
+		Long businessId = userDistributeReq.getBusinessId();
+		UserDistribute userDistribute = new UserDistribute();
+		userDistribute.setUserId(userDistributeReq.getUserId());
+		userDistribute.setRemark(userDistributeReq.getRemark());
+		userDistribute.setType(userDistributeReq.getType());
+		userDistribute.setBusinessId(businessId);
+		if (businessId != null && businessId != 0) {
+			userDistribute.setBusinessBindTime(DateTime.now());
+		}
+		userDistributeMapper.insert(userDistribute);
+		for (UserPlatDistributeRate rate : userDistributeReq.getRates()) {
+			if (rate.getRate() == null) {
+				rate.setRate(0);
+			}
+			if (rate.getSecondRate() == null) {
+				rate.setSecondRate(0);
+			}
+			if (rate.getRate() < 0 || rate.getRate() > 100) {
+				throw new BusinessRuntimeException("比例错误");
+			}
+			GoodsDon goodsDon = goodsDonMapper.selectById(rate.getGoodsId());
+			if (goodsDon == null || !goodsDon.getDeleted() || goodsDon.getType() == 3) {
+				throw new BusinessRuntimeException("平台错误");
+			}
+			//分销者虚物分销比例且配置商务
+			if (businessId != null && goodsDon.getType() == 1) {
+				checkDistributorAndBusinessRate(rate.getRate(), goodsDon.getId(), goodsDon.getTitle());
+			}
+			rate.setDistributeId(userDistribute.getId());
+			userPlatDistributeRateMapper.insert(rate);
+		}
+		List<UserPlatSkuDistributeRate> skuRates = userDistributeReq.getSkuRates();
+		if (CollUtil.isNotEmpty(skuRates)) {
+			Map<Long, GoodsDon> map = new ConcurrentHashMap<>();
+			for (UserPlatSkuDistributeRate skuRate : skuRates) {
+				if (skuRate.getRate() == null) {
+					skuRate.setRate(0);
+				}
+				if (skuRate.getSecondRate() == null) {
+					skuRate.setSecondRate(0);
+				}
+				if (skuRate.getRate() < 0 || skuRate.getRate() > 100) {
+					throw new BusinessRuntimeException("比例错误");
+				}
+				GoodsDon goodsDon = map.get(skuRate.getGoodsId());
+				if (goodsDon == null) {
+					goodsDon = goodsDonMapper.selectById(skuRate.getGoodsId());
+					map.putIfAbsent(skuRate.getSkuId(), goodsDon);
+				}
+				try {
+					skuRate.setDistributeId(userDistribute.getId());
+					if (businessId != null && goodsDon.getType() == 1) {
+						checkDistributorAndBusinessRate(skuRate.getRate(), skuRate.getGoodsId(), goodsDon.getTitle());
+					}
+					userPlatSkuDistributeRateMapper.insert(skuRate);
+				} catch (DuplicateKeyException e) {
+				}
+			}
+		}
+		//渠道附加功能
+		handlerDistributeOtherFunc(userDistribute, userDistributeReq);
+		//设置过个人专属推广码 升级为渠道专属优惠码
+		setDistributePopularizeCode(userDistribute.getId(), userDistribute.getUserId());
+	}
+
+	@Override
+	@Transactional(rollbackFor = Throwable.class)
+	public void editDistribute(UserDistributeReq userDistributeReq) {
+		if (userDistributeReq.getId() == null || userDistributeReq.getId() < 1) {
+			throw BusinessRuntimeException.getInstance("id错误");
+		}
+		Long id = userDistributeReq.getId();
+		UserDistribute userDistribute = userDistributeMapper.selectById(id);
+		if (userDistribute == null || !userDistribute.getDeleted()) {
+			return;
+		}
+		userDistribute.setId(userDistributeReq.getId());
+		userDistribute.setRemark(userDistributeReq.getRemark());
+		Long businessId = userDistributeReq.getBusinessId();
+		if (businessId == null) {
+			userDistribute.setBusinessId(0l);
+		} else {
+			if (userDistribute.getBusinessId() != null && !userDistribute.getBusinessId().equals(businessId)) {
+				userDistribute.setBusinessBindTime(DateTime.now());
+			}
+			userDistribute.setBusinessId(businessId);
+		}
+		userDistribute.setType(userDistributeReq.getType());
+		userDistributeMapper.updateById(userDistribute);
+		for (UserPlatDistributeRate rate : userDistributeReq.getRates()) {
+			if (rate.getRate() == null) {
+				rate.setRate(0);
+			}
+			if (rate.getSecondRate() == null) {
+				rate.setSecondRate(0);
+			}
+			if (rate.getRate() < 0 || rate.getRate() > 100) {
+				throw new BusinessRuntimeException("比例错误");
+			}
+			GoodsDon goodsDon = goodsDonMapper.selectById(rate.getGoodsId());
+			if (rate.getId() != null && (goodsDon == null || !goodsDon.getDeleted())) {
+				userPlatDistributeRateMapper.deleteById(rate.getId());
+				continue;
+			}
+			if (goodsDon == null || !goodsDon.getDeleted() || goodsDon.getType() == 3) {
+				throw new BusinessRuntimeException("平台错误");
+			}
+			//分销者虚物分销比例且配置商务
+			if (businessId != null && goodsDon.getType() == 1) {
+				checkDistributorAndBusinessRate(rate.getRate(), goodsDon.getId(), goodsDon.getTitle());
+			}
+			rate.setDistributeId(userDistribute.getId());
+			if (rate.getId() == null) {
+				try {
+					userPlatDistributeRateMapper.insert(rate);
+				} catch (DuplicateKeyException e) {
+					userPlatDistributeRateMapper.update(null, Wrappers.lambdaUpdate(UserPlatDistributeRate.class)
+							.eq(UserPlatDistributeRate::getDistributeId, userDistribute.getId())
+							.eq(UserPlatDistributeRate::getGoodsId, rate.getGoodsId())
+							.set(UserPlatDistributeRate::getRate, rate.getRate()));
+				}
+			} else {
+				UserPlatDistributeRate dbPlateRate = userPlatDistributeRateMapper.selectById(rate.getId());
+				if (dbPlateRate == null) {
+					continue;
+				}
+				if (dbPlateRate.getRate() != rate.getRate() || dbPlateRate.getSecondRate() != rate.getSecondRate()) {
+					userPlatDistributeRateMapper.updateById(rate);
+				}
+			}
+		}
+
+		//特殊平台 按规格分销比例
+		List<UserPlatSkuDistributeRate> skuRates = userDistributeReq.getSkuRates();
+		if (CollUtil.isNotEmpty(skuRates)) {
+			Map<Long, GoodsDon> map = new ConcurrentHashMap<>();
+			for (UserPlatSkuDistributeRate skuRate : skuRates) {
+				if (skuRate.getRate() == null) {
+					skuRate.setRate(0);
+				}
+				if (skuRate.getSecondRate() == null) {
+					skuRate.setSecondRate(0);
+				}
+				if (skuRate.getRate() < 0 || skuRate.getRate() > 100) {
+					throw new BusinessRuntimeException("比例错误");
+				}
+				GoodsDon goodsDon = map.get(skuRate.getGoodsId());
+				if (goodsDon == null) {
+					goodsDon = goodsDonMapper.selectById(skuRate.getGoodsId());
+					map.putIfAbsent(skuRate.getSkuId(), goodsDon);
+				}
+				if (businessId != null && goodsDon.getType() == 1) {
+					checkDistributorAndBusinessRate(skuRate.getRate(), goodsDon.getId(), goodsDon.getTitle());
+				}
+				if (skuRate.getId() != null) {
+					userPlatSkuDistributeRateMapper.updateById(skuRate);
+					continue;
+				}
+				try {
+					skuRate.setDistributeId(userDistribute.getId());
+					userPlatSkuDistributeRateMapper.insert(skuRate);
+				} catch (DuplicateKeyException e) {
+				}
+			}
+		}
+		handlerDistributeOtherFunc(userDistribute, userDistributeReq);
+	}
+
+	/**
+	 * 渠道附加功能
+	 */
+	public void handlerDistributeOtherFunc(UserDistribute userDistribute, UserDistributeReq userDistributeReq) {
+		//处理优惠券关联
+		handlerDistributeCouponRelate(userDistribute.getId(), userDistribute.getUserId(), userDistributeReq.getCouponRelates());
+
+		//渠道目标额配置
+		handlerDistributeTargetAlert(userDistribute.getId(), userDistributeReq.getTargets());
+	}
+
+	@Override
+	public void saveDistributionInvitation(Long sharedId, Long userId, Long dsPopularizeId) {
+		if (sharedId == 0l || sharedId.equals(userId)) {
+			return;
+		}
+		User user = userMapper.selectById(sharedId);
+		if (user == null) {
+			return;
+		}
+		UserDistributeShared userDistributeShared = new UserDistributeShared();
+		userDistributeShared.setSharedId(sharedId);
+		//存在分销
+		userDistributeShared.setUserId(userId);
+		userDistributeShared.setDsPopularizeId(dsPopularizeId);
+		try {
+			userDistributeSharedMapper.insert(userDistributeShared);
+		} catch (DuplicateKeyException e) {
+			log.info("分销被邀请人重复插入");
+		}
+	}
+
+	@Override
+	@Transactional(rollbackFor = Throwable.class)
+	public void bindPopularizeCode(Long userId, String code) {
+		Coupon coupon = couponMapper.getCouponById(Constant.GENERAL_POPULARIZE_COUPON_ID);
+		if (!redisService.setNx(RedisService.key.GENERAL_POPULARIZE_CODE.getName() + code, userId, RedisService.key.GENERAL_POPULARIZE_CODE.getTimeout())) {
+			throw BusinessRuntimeException.getInstance("该专属推广优惠码已被设置");
+		}
+		UserDistribute userDistribute = userDistributeMapper.selectOne(Wrappers.lambdaQuery(UserDistribute.class)
+				.eq(UserDistribute::getUserId, userId)
+				.eq(UserDistribute::getDeleted, true)
+				.last("limit 1"));
+		if (userDistribute != null) throw BusinessRuntimeException.getInstance("只适用于普通用户进行专属推广");
+		CouponDistributePopularize is_exists = couponDistributePopularizeMapper.selectOne(Wrappers.lambdaQuery(CouponDistributePopularize.class)
+				.eq(CouponDistributePopularize::getUserId, userId)
+				.last("limit 1"));
+		if (is_exists != null) throw BusinessRuntimeException.getInstance("你已设置专属推广优惠码");
+		CouponDistributePopularize couponDistributePopularize = new CouponDistributePopularize();
+		couponDistributePopularize.setCouponId(coupon.getId());
+		couponDistributePopularize.setUserId(userId);
+		couponDistributePopularize.setIsGeneral(true);
+		CouponDistributePopularize exists = couponDistributePopularizeMapper.selectOne(Wrappers.lambdaQuery(CouponDistributePopularize.class)
+				.eq(CouponDistributePopularize::getExCode, code)
+				.eq(CouponDistributePopularize::getDeleted, true)
+				.ne(CouponDistributePopularize::getUserId, userId)
+				.select(CouponDistributePopularize::getId)
+				.last("limit 1"));
+		if (exists != null) {
+			throw BusinessRuntimeException.getInstance("该专属推广优惠码已被设置");
+		} else {
+			Coupon existsCoupon = couponMapper.selectOne(Wrappers.lambdaQuery(Coupon.class)
+					.eq(Coupon::getExCode, code)
+					.eq(Coupon::getDeleted, true)
+					.select(Coupon::getId)
+					.last("limit 1"));
+			if (existsCoupon != null) {
+				throw BusinessRuntimeException.getInstance("该专属推广优惠码已被设置");
+			}
+		}
+		couponDistributePopularize.setExCode(code);
+		couponDistributePopularizeMapper.insert(couponDistributePopularize);
+	}
+
+	@Override
+	public void unbindUserDistributeShared(List<Object> userBind) throws Exception {
+		List<Long> save_userIds = new ArrayList<>(500);
+		userBind.forEach(e -> {
+			Map<String, Object> map = Jsons.toMap(e);
+			Object value0 = map.get("0");
+			if (value0 != null) {
+				Long userId = Long.parseLong(value0.toString());
+				save_userIds.add(userId);
+				if (save_userIds.size() == 500) {
+					userDistributeSharedRelateUnbindMapper.batchInsert(save_userIds);
+					save_userIds.clear();
+				}
+			}
+		});
+		if (save_userIds.size() > 0) {
+			userDistributeSharedRelateUnbindMapper.batchInsert(save_userIds);
+			save_userIds.clear();
+		}
+	}
+
+	@Override
+	public void setDistributeCommonSkuRate(List<DistributeGeneralSkuRate> skuRates) {
+		List<Long> collect = skuRates.stream().map(DistributeGeneralSkuRate::getSkuId).collect(Collectors.toList());
+		if (CollUtil.isNotEmpty(collect)) {
+			generalSkuRateMapper.delete(Wrappers.lambdaQuery(DistributeGeneralSkuRate.class)
+					.notIn(DistributeGeneralSkuRate::getSkuId, collect));
+		}
+		skuRates.forEach(e -> {
+			Integer rate = e.getRate();
+			if (rate == null || rate < 0 || rate > 100) {
+				throw BusinessRuntimeException.getInstance("请输入正确的比例");
+			}
+			if (e.getId() == null) {
+				try {
+					generalSkuRateMapper.insert(e);
+				} catch (DuplicateKeyException ex) {
+				}
+			} else {
+				generalSkuRateMapper.updateById(e);
+			}
+		});
+	}
+
+	public void checkDistributorAndBusinessRate(Integer distributeGoodsRate, Long goodsId, String goodsName) {
+		UserBusinessDefaultRateConfig defaultGoodsRateConfig = defaultRateConfigMapper.selectOne(Wrappers.lambdaQuery(UserBusinessDefaultRateConfig.class)
+				.eq(UserBusinessDefaultRateConfig::getGoodsId, goodsId)
+				.last("limit 1"));
+		Optional.ofNullable(defaultGoodsRateConfig).ifPresent(config -> {
+			if (distributeGoodsRate > config.getMaxRate()) {
+				throw BusinessRuntimeException.getInstance(String.format("该%s平台最高可配置分销比例为%s", goodsName, config.getMaxRate()));
+			}
+		});
+	}
+
+	private void handlerDistributeCouponRelate(Long distributeId, Long userId, List<CouponDistributePopularize> couponRelates) {
+		Map<Long, CouponDistributePopularize> map = new ConcurrentHashMap<>();
+		couponRelates.forEach(data -> {
+			data.setDistributeId(distributeId);
+			if (data.getCouponId() == null) {
+				throw BusinessRuntimeException.getInstance("优惠券不存在");
+			}
+			Integer exists = couponMapper.selectCount(Wrappers.lambdaQuery(Coupon.class).eq(Coupon::getId, data.getCouponId()).eq(Coupon::getDeleted, 1));
+			if (exists == 0) {
+				throw BusinessRuntimeException.getInstance("id为{0}的优惠券不存在", data.getCouponId());
+			}
+			String exCode = data.getExCode();
+			if (StrUtil.isEmpty(exCode)) {
+				throw BusinessRuntimeException.getInstance("优惠码为空");
+			}
+			List<CouponDistributePopularize> popularizeList = couponDistributePopularizeMapper.selectList(Wrappers.lambdaQuery(CouponDistributePopularize.class)
+					.eq(CouponDistributePopularize::getDeleted, 1)
+					.eq(CouponDistributePopularize::getExCode, exCode));
+			//个人渠道
+			for (CouponDistributePopularize couponDistributePopularize : popularizeList) {
+				Long disId = couponDistributePopularize.getDistributeId();
+				if (disId != null && !ObjectUtil.equal(disId, distributeId)) {
+					throw BusinessRuntimeException.getInstance("优惠码:{0}已存在", exCode);
+				}
+				Long uid = couponDistributePopularize.getUserId();
+				if (uid != null && !ObjectUtil.equal(uid, userId)) {
+					throw BusinessRuntimeException.getInstance("优惠码:{0}已存在", exCode);
+				}
+			}
+			Integer count = couponMapper.selectCount(Wrappers.lambdaQuery(Coupon.class).eq(Coupon::getExCode, exCode).eq(Coupon::getDeleted, true));
+			if (count > 0) {
+				throw BusinessRuntimeException.getInstance("优惠码:{0}已存在", exCode);
+			}
+			if (data.getId() != null) {
+				couponDistributePopularizeMapper.updateById(data);
+			} else {
+				couponDistributePopularizeMapper.insert(data);
+			}
+			map.put(data.getId(), data);
+		});
+
+		List<CouponDistributePopularize> dbCouponPopularizes = couponDistributePopularizeMapper.selectList(Wrappers.lambdaQuery(CouponDistributePopularize.class)
+				.eq(CouponDistributePopularize::getDistributeId, distributeId)
+				.eq(CouponDistributePopularize::getDeleted, 1));
+
+		//不存在的删除
+		List<Long> delDbCouponPids = new ArrayList<>();
+		dbCouponPopularizes.forEach(db -> {
+			if (map.get(db.getId()) == null) {
+				delDbCouponPids.add(db.getId());
+			}
+		});
+
+		if (CollUtil.isNotEmpty(delDbCouponPids)) {
+			couponDistributePopularizeMapper.update(null, Wrappers.lambdaUpdate(CouponDistributePopularize.class)
+					.set(CouponDistributePopularize::getDeleted, 0)
+					.in(CouponDistributePopularize::getId, delDbCouponPids)
+					.eq(CouponDistributePopularize::getDeleted, 1));
+		}
+	}
+
+
+	/**
+	 * 渠道目标额 设置
+	 */
+	private void handlerDistributeTargetAlert(Long distributeId, List<UserDistributeTargetAlert> targets) {
+		Map<Long, UserDistributeTargetAlert> map = new ConcurrentHashMap<>();
+		for (UserDistributeTargetAlert targetAlert : targets) {
+			targetAlert.setDistributeId(distributeId);
+			Integer type = targetAlert.getType();
+			BigDecimal target = targetAlert.getTarget();
+			Assert.notNull(type, "请选择对应目标类型");
+			Assert.notNull(target, "请输入对应目标额");
+			if (type < 1 || type > 3) {
+				throw BusinessRuntimeException.getInstance("请选择正确的目标类型");
+			}
+
+			if (target.compareTo(BigDecimal.ZERO) <= 0) {
+				throw BusinessRuntimeException.getInstance("请输入正确的目标额值");
+			}
+
+			if ((type == 2 || type == 3) && target.compareTo(BigDecimal.ZERO) < 0) {
+				throw BusinessRuntimeException.getInstance("请输入正确的变化比例");
+			}
+			Long id = targetAlert.getId();
+
+			try {
+				if (id != null) {
+					UserDistributeTargetAlert dbAlert = targetAlertMapper.selectById(id);
+					if (dbAlert != null) {
+						//目标额 变化 去掉下次提醒时间
+						if (dbAlert.getTarget().compareTo(targetAlert.getTarget()) != 0) {
+							targetAlert.setNextAlertTime(null);
+						}
+						//关闭一周内提醒 去掉下次提醒时间
+						if (!targetAlert.getIsWeek()) {
+							targetAlert.setNextAlertTime(null);
+						}
+						targetAlertMapper.updateById(targetAlert);
+					}
+				} else {
+					targetAlertMapper.insert(targetAlert);
+				}
+				map.put(targetAlert.getId(), targetAlert);
+			} catch (DuplicateKeyException e) {
+			}
+		}
+
+		List<UserDistributeTargetAlert> dbTargetAlert = targetAlertMapper.selectList(Wrappers.lambdaQuery(UserDistributeTargetAlert.class)
+				.eq(UserDistributeTargetAlert::getDistributeId, distributeId));
+
+		//不存在的删除
+		List<Long> delDbTargetAlert = new ArrayList<>();
+		dbTargetAlert.forEach(db -> {
+			if (map.get(db.getId()) == null) {
+				delDbTargetAlert.add(db.getId());
+			}
+		});
+
+		if (CollUtil.isNotEmpty(delDbTargetAlert)) {
+			targetAlertMapper.deleteBatchIds(delDbTargetAlert);
+		}
+	}
+
+	private void setDistributePopularizeCode(Long distributeId, Long userId) {
+		CouponDistributePopularize couponDistributePopularize = couponDistributePopularizeMapper.selectOne(Wrappers.lambdaQuery(CouponDistributePopularize.class)
+				.eq(CouponDistributePopularize::getCouponId, Constant.GENERAL_POPULARIZE_COUPON_ID)
+				.eq(CouponDistributePopularize::getUserId, userId)
+				.eq(CouponDistributePopularize::getDeleted, 1)
+				.eq(CouponDistributePopularize::getIsGeneral, 1)
+				.last("limit 1"));
+		if (couponDistributePopularize != null) {
+			//先删除
+			couponDistributePopularize.setDeleted(false);
+			couponDistributePopularizeMapper.updateById(couponDistributePopularize);
+
+			//后升级
+			CouponDistributePopularize newPopularizeCode = new CouponDistributePopularize();
+			newPopularizeCode.setDistributeId(distributeId);
+			newPopularizeCode.setExCode(couponDistributePopularize.getExCode());
+			newPopularizeCode.setCouponId(Constant.DISTRIBUTE_POPULARIZE_COUPON_ID);
+			couponDistributePopularizeMapper.insert(newPopularizeCode);
+		}
+	}
+}

+ 227 - 0
netflix-service/src/main/java/com/cyksj/service/distribute/impl/UserBusinessFrontServiceImpl.java

@@ -0,0 +1,227 @@
+package com.cyksj.service.distribute.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.constant.Constant;
+import com.cyksj.mapper.OrderDonMapper;
+import com.cyksj.mapper.UserDistributeSpecialMapper;
+import com.cyksj.mapper.UserRenewChangeTicketRecordMapper;
+import com.cyksj.mapper.manage.distribute.UserBusinessDefaultRateConfigMapper;
+import com.cyksj.mapper.manage.distribute.UserDistributeBusinessOrderDonRecordMapper;
+import com.cyksj.mapper.manage.distribute.UserDistributeBusinessRateMapper;
+import com.cyksj.model.entity.*;
+import com.cyksj.redis.RedisService;
+import com.cyksj.service.distribute.UserBusinessFrontService;
+import com.ejlchina.searcher.BeanSearcher;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+
+/*
+ *项目名: netflix
+ *文件名: UserBusinessFrontServiceImpl
+ *创建者: JavaZou
+ *创建时间:2023/3/23 14:20
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class UserBusinessFrontServiceImpl implements UserBusinessFrontService {
+	private final BeanSearcher beanSearcher;
+
+	private final UserDistributeBusinessRateMapper userDistributeBusinessRateMapper;
+
+	private final OrderDonMapper orderDonMapper;
+
+	private final UserDistributeBusinessOrderDonRecordMapper businessOrderDonRecordMapper;
+
+	private final UserRenewChangeTicketRecordMapper renewChangeTicketRecordMapper;
+
+	private final RedisService redisService;
+
+	private final UserBusinessDefaultRateConfigMapper defaultRateConfigMapper;
+
+	private final UserDistributeSpecialMapper userDistributeSpecialMapper;
+
+	@Override
+	public void taskDistributeRateBenefits(Long sharedId, Long businessId, Integer goodsType, OrderDon order, Integer distributeRate) {
+		LambdaQueryWrapper<UserDistributeBusinessRate> wrapper = Wrappers.lambdaQuery(UserDistributeBusinessRate.class)
+				.eq(UserDistributeBusinessRate::getBusinessId, businessId)
+				.eq(UserDistributeBusinessRate::getGoodsId, order.getGoodsId())
+				.last("limit 1");
+		if (goodsType == 1) {
+			wrapper.eq(UserDistributeBusinessRate::getSkuId, order.getSkuId());
+		}
+		UserDistributeBusinessRate businessRate = userDistributeBusinessRateMapper.selectOne(wrapper);
+		//06-21 奈飞平台商务比例特殊处理
+		UserDistributeSpecial userDistributeSpecial = userDistributeSpecialMapper.selectOne(Wrappers.lambdaQuery(UserDistributeSpecial.class)
+				.eq(UserDistributeSpecial::getSkuId, order.getSkuId())
+				.eq(UserDistributeSpecial::getSharedId, sharedId)
+				.eq(UserDistributeSpecial::getBusinessId, businessId)
+				.last("limit 1"));
+		if (userDistributeSpecial != null) {
+			businessRate.setFirstOrderRate(userDistributeSpecial.getFirstRate());
+			businessRate.setRenewOrderRate(userDistributeSpecial.getRenewRate());
+		}
+		if (businessRate != null) {
+			if (order.getOrderType() == 1) {
+				//实物商务分销提成 无首单
+				if (goodsType != 1) {
+					UserDistributeBusinessOrderDonRecord record = saveBusinessTakeMoneyRecord(order, businessId, sharedId, businessRate.getFirstOrderRate(), null, distributeRate);
+					if (record == null) {
+						return;
+					}
+					businessOrderDonRecordMapper.insert(record);
+					log.info("开始给商务人员:{}分配分销人:{}分销的用户:{}实物:{}提成", businessId, sharedId, order.getUserId(), order.getId());
+					return;
+				}
+				//首单
+				log.info("商务首单orderId:{}分销分配提成开始", order.getId());
+				//用户之前是否下过单
+				Integer count = orderDonMapper.selectCount(Wrappers.lambdaQuery(OrderDon.class)
+						.eq(OrderDon::getUserId, order.getUserId())
+						.ne(OrderDon::getId, order.getId()).notIn(OrderDon::getStatus, Constant.noOrderAllStatus));
+				if (count == 0) {
+					//是否享受过该用户带来的首单 提成
+					UserDistributeBusinessOrderDonRecord record = businessOrderDonRecordMapper.selectOne(Wrappers.lambdaQuery(UserDistributeBusinessOrderDonRecord.class)
+							.eq(UserDistributeBusinessOrderDonRecord::getBusinessId, businessId)
+							.eq(UserDistributeBusinessOrderDonRecord::getUserId, order.getUserId())
+							.eq(UserDistributeBusinessOrderDonRecord::getOrderType, 1)
+							.eq(UserDistributeBusinessOrderDonRecord::getStatus, UserDistributeBusinessOrderDonRecord.Status.success)
+							.last("limit 1"));
+					if (record == null) {
+						try {
+							boolean isSuccess = redisService.setNx(RedisService.key.BUSINESS_FIRST_ORDER_USER_KEY.getNameFormat(order.getUserId()), businessId, RedisService.key.BUSINESS_FIRST_ORDER_USER_KEY.getTimeout());
+							if (isSuccess) {
+								//首单虚物规格 提成
+								record = saveBusinessTakeMoneyRecord(order, businessId, sharedId, businessRate.getFirstOrderRate(), null, distributeRate);
+								if (record == null) {
+									return;
+								}
+								businessOrderDonRecordMapper.insert(record);
+								log.info("开始给商务人员:{}分配分销人:{}分销的用户:{}首单:{}提成", businessId, sharedId, order.getUserId(), order.getId());
+								redisService.del(RedisService.key.BUSINESS_FIRST_ORDER_USER_KEY.getNameFormat(order.getUserId()));
+							}
+						} catch (DuplicateKeyException e) {
+							log.error("商务:{}重复获取分销人:{}分销的用户:{}首单:{}提成", businessId, businessId, order.getUserId(), order.getId());
+						}
+					}
+				}
+			}
+			//续费
+			if (order.getOrderType() == 2) {
+				log.info("商务首单续费分销分配提成开始");
+				//是否享受过该用户首单 提成
+				UserDistributeBusinessOrderDonRecord record = businessOrderDonRecordMapper.selectOne(Wrappers.lambdaQuery(UserDistributeBusinessOrderDonRecord.class)
+						.eq(UserDistributeBusinessOrderDonRecord::getBusinessId, businessId)
+						.eq(UserDistributeBusinessOrderDonRecord::getUserId, order.getUserId())
+						.eq(UserDistributeBusinessOrderDonRecord::getOrderType, 1)
+						.eq(UserDistributeBusinessOrderDonRecord::getStatus, UserDistributeBusinessOrderDonRecord.Status.success)
+						.last("limit 1"));
+				if (record != null) {
+					log.info("开始给商务人员:{}分配用户:{}首单续费提成", businessId, order.getUserId());
+					//是否更换过车票规格座位号
+					Long preRelationId = record.getPreRelationId();
+					Long relationId = order.getRelationId();
+					if (relationId.equals(preRelationId)) {
+						try {
+							//分配首单续费提成
+							record = saveBusinessTakeMoneyRecord(order, businessId, sharedId, null, businessRate.getRenewOrderRate(), distributeRate);
+							if (record == null) {
+								return;
+							}
+							businessOrderDonRecordMapper.insert(record);
+							log.info("开始给商务人员:{}分配分销人:{}分销的用户:{}续费首单:{}提成", businessId, sharedId, order.getUserId(), order.getId());
+						} catch (DuplicateKeyException e) {
+							log.error("商务:{}重复获取分销人:{}分销的用户:{}续费首单:{}提成", businessId, businessId, order.getUserId(), order.getId());
+						}
+					} else {
+						UserRenewChangeTicketRecord renewChangeTicketRecord = renewChangeTicketRecordMapper.selectOne(Wrappers.lambdaQuery(UserRenewChangeTicketRecord.class)
+								.eq(UserRenewChangeTicketRecord::getUserId, order.getUserId())
+								.eq(UserRenewChangeTicketRecord::getAfterRelationId, relationId)
+								.last("limit 1"));
+						if (renewChangeTicketRecord != null && renewChangeTicketRecord.getPreRelationId().equals(preRelationId)) {
+							try {
+								//分配首单续费更换车位后提成
+								record = saveBusinessTakeMoneyRecord(order, businessId, sharedId, null, businessRate.getRenewOrderRate(), distributeRate);
+								if (record == null) {
+									return;
+								}
+								businessOrderDonRecordMapper.insert(record);
+								log.info("开始给商务人员:{}分配分销人:{}分销的用户:{}续费首单:{}更换后车位提成", businessId, sharedId, order.getUserId(), order.getId());
+							} catch (DuplicateKeyException e) {
+								log.error("商务:{}重复获取分销人:{}分销的用户:{}续费首单:{}更换后车位提成", businessId, businessId, order.getUserId(), order.getId());
+							}
+						}
+					}
+
+				}
+			}
+		}
+	}
+
+
+	/**
+	 * 保存商务分配提成记录
+	 */
+	public UserDistributeBusinessOrderDonRecord saveBusinessTakeMoneyRecord(OrderDon order, Long businessId, Long sharedId, Integer firstOrderRate, Integer renewOrderRate, Integer distributeRate) {
+		UserBusinessDefaultRateConfig defaultGoodsRateConfig = defaultRateConfigMapper.selectOne(Wrappers.lambdaQuery(UserBusinessDefaultRateConfig.class)
+				.eq(UserBusinessDefaultRateConfig::getGoodsId, order.getGoodsId()).last("limit 1"));
+		if (defaultGoodsRateConfig == null) {
+			log.info("系统默认商务分销配置未配置,businessId:{},orderId:{}", businessId, order.getId());
+			return null;
+		}
+		UserDistributeBusinessOrderDonRecord record = new UserDistributeBusinessOrderDonRecord();
+		record.setBusinessId(businessId);
+		record.setUserId(order.getUserId());
+		record.setSharedId(sharedId);
+		record.setOrderType(order.getOrderType());
+		record.setOrderCreatedTime(order.getCreatedTime());
+		record.setOrderId(order.getId());
+		record.setPreRelationId(order.getRelationId());
+		//是否超过默认配置平台比例
+		Integer defaultGoodsRate = defaultGoodsRateConfig.getRate();
+		//首单提成比例
+		BigDecimal orderMoney = order.getDsMoney();
+		BigDecimal takeMoney = BigDecimal.ZERO;
+		if (firstOrderRate != null) {
+			if (distributeRate > defaultGoodsRate) {
+				if (defaultGoodsRateConfig.getIsPlatPay()) {
+					log.info("首单,平台承担商务businessId:{}配置分销者sharedId:{}超过平台goodsId:{}标准分销比例:{}", businessId, sharedId, order.getGoodsId(), defaultGoodsRate);
+				} else {
+					firstOrderRate -= distributeRate - defaultGoodsRate;
+					log.info("商务businessId:{}配置分销者sharedId:{}比例超过标准比例,可获取首单提成比例为:{}", businessId, sharedId, firstOrderRate);
+					if (firstOrderRate <= 0) {
+						log.info("商务businessId:{}获得分销者sharedId:{}首单提成比例不大于0", businessId, sharedId);
+						return null;
+					}
+				}
+			}
+			record.setRate(firstOrderRate);
+			BigDecimal firstRate = BigDecimal.valueOf(firstOrderRate).divide(BigDecimal.valueOf(100));
+			takeMoney = orderMoney.multiply(firstRate);
+		}
+		if (renewOrderRate != null) {
+			if (distributeRate > defaultGoodsRate) {
+				if (defaultGoodsRateConfig.getIsPlatPay()) {
+					log.info("首单续费,平台承担商务businessId:{}配置分销者sharedId:{}超过平台goodsId:{}标准分销比例:{}", businessId, sharedId, order.getGoodsId(), defaultGoodsRate);
+				} else {
+					renewOrderRate -= distributeRate - defaultGoodsRate;
+					log.info("商务businessId:{}配置分销者sharedId:{}比例超过标准比例,可获取首单续费提成比例为:{}", businessId, sharedId, renewOrderRate);
+					if (renewOrderRate <= 0) {
+						log.info("商务businessId:{}获得分销者sharedId:{}首单续费提成比例不大于0", businessId, sharedId);
+						return null;
+					}
+				}
+			}
+			record.setRate(renewOrderRate);
+			BigDecimal renewRate = BigDecimal.valueOf(renewOrderRate).divide(BigDecimal.valueOf(100));
+			takeMoney = orderMoney.multiply(renewRate);
+		}
+		record.setTakeMoney(takeMoney);
+		return record;
+	}
+}

+ 31 - 0
netflix-service/src/main/java/com/cyksj/service/distribute/impl/UserDistributeReturnMoneyDetailServiceImpl.java

@@ -0,0 +1,31 @@
+package com.cyksj.service.distribute.impl;
+
+import com.cyksj.mapper.UserDistributeReturnMoneyDetailMapper;
+import com.cyksj.model.entity.UserDistributeReturnMoneyDetail;
+import com.cyksj.service.distribute.UserDistributeReturnMoneyDetailService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: UserDistributeReturnMoneyDetailServiceImpl
+ * 创建者: JavaZou
+ * 创建时间:2024/7/29 18:52
+ */
+@Service
+@RequiredArgsConstructor
+public class UserDistributeReturnMoneyDetailServiceImpl implements UserDistributeReturnMoneyDetailService {
+	private final UserDistributeReturnMoneyDetailMapper userDistributeReturnMoneyDetailMapper;
+
+
+	@Override
+	public void recordDistributeReturnMoney(Long userId, BigDecimal money, String source) {
+		UserDistributeReturnMoneyDetail userDistributeReturnMoneyDetail = new UserDistributeReturnMoneyDetail();
+		userDistributeReturnMoneyDetail.setUserId(userId);
+		userDistributeReturnMoneyDetail.setMoney(money);
+		userDistributeReturnMoneyDetail.setSource(source);
+		userDistributeReturnMoneyDetailMapper.insert(userDistributeReturnMoneyDetail);
+	}
+}

+ 18 - 0
netflix-service/src/main/java/com/cyksj/service/mange/business/UserBusinessRateService.java

@@ -0,0 +1,18 @@
+package com.cyksj.service.mange.business;
+
+/*
+ *项目名: netflix
+ *文件名: UserBusinessRateService
+ *创建者: JavaZou
+ *创建时间:2023/3/23 14:02
+ */
+public interface UserBusinessRateService {
+	/**
+	 * 若无配置商务人员比例,保存商务人员比例
+	 */
+	void saveBusinessRate(Long businessId);
+
+	Boolean isBusiness(Long businessId);
+
+	void deleteBusinessRateByUid(Long businessId);
+}

+ 85 - 0
netflix-service/src/main/java/com/cyksj/service/mange/business/impl/UserBusinessRateServiceImpl.java

@@ -0,0 +1,85 @@
+package com.cyksj.service.mange.business.impl;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.mapper.manage.distribute.UserDistributeBusinessRateMapper;
+import com.cyksj.mapper.manage.distribute.UserDistributeMapper;
+import com.cyksj.model.entity.UserDistribute;
+import com.cyksj.model.entity.UserDistributeBusinessRate;
+import com.cyksj.model.views.CmsUserVO;
+import com.cyksj.model.views.GoodsDonSkuView;
+import com.cyksj.service.mange.business.UserBusinessRateService;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.param.Operator;
+import com.ejlchina.searcher.util.MapUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/*
+ *项目名: netflix
+ *文件名: UserBusinessRateServiceImpl
+ *创建者: JavaZou
+ *创建时间:2023/3/23 14:02
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class UserBusinessRateServiceImpl implements UserBusinessRateService {
+	private final UserDistributeBusinessRateMapper userDistributeBusinessRateMapper;
+
+	private final BeanSearcher beanSearcher;
+
+	private final UserDistributeMapper userDistributeMapper;
+
+	@Override
+	public void saveBusinessRate(Long businessId) {
+		if (businessId != null) {
+			List<GoodsDonSkuView> goodsDonSkuList = beanSearcher.searchAll(GoodsDonSkuView.class, MapUtils.builder().field(GoodsDonSkuView::getType, 1)
+					.field(GoodsDonSkuView::getGoodsDonDeleted, true)
+					.field(GoodsDonSkuView::getSkuId).op(Operator.NotNull)
+					.build());
+			goodsDonSkuList.forEach(goodsDonSku -> {
+				Long goodsId = goodsDonSku.getGoodsId();
+				Long skuId = goodsDonSku.getSkuId();
+				UserDistributeBusinessRate businessRate = userDistributeBusinessRateMapper.selectOne(Wrappers.lambdaQuery(UserDistributeBusinessRate.class)
+						.eq(UserDistributeBusinessRate::getGoodsId, goodsId)
+						.eq(UserDistributeBusinessRate::getSkuId, skuId)
+						.eq(UserDistributeBusinessRate::getBusinessId, businessId).last("limit 1"));
+				if (businessRate == null) {
+					try {
+						businessRate = new UserDistributeBusinessRate();
+						businessRate.setBusinessId(businessId);
+						businessRate.setGoodsId(goodsId);
+						businessRate.setSkuId(skuId);
+						userDistributeBusinessRateMapper.insert(businessRate);
+					} catch (DuplicateKeyException e) {
+
+					}
+				}
+			});
+		}
+	}
+
+	@Override
+	public Boolean isBusiness(Long businessId) {
+		//是否是商务人员
+		CmsUserVO isBusiness = beanSearcher.searchFirst(CmsUserVO.class, MapUtils.builder().field(CmsUserVO::getId, businessId).field(CmsUserVO::getRoleNames, "商务").op(Operator.Contain).build());
+		if (isBusiness != null) {
+			return true;
+		}
+		return false;
+	}
+
+	@Override
+	public void deleteBusinessRateByUid(Long businessId) {
+		userDistributeBusinessRateMapper.delete(Wrappers.lambdaQuery(UserDistributeBusinessRate.class)
+				.eq(UserDistributeBusinessRate::getBusinessId, businessId));
+
+		userDistributeMapper.update(null, Wrappers.lambdaUpdate(UserDistribute.class)
+				.set(UserDistribute::getBusinessId, 0)
+				.eq(UserDistribute::getBusinessId, businessId));
+	}
+}

+ 375 - 3
netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java

@@ -21,12 +21,13 @@ import com.cyksj.common.util.SmsUtil;
 import com.cyksj.common.util.StringUtil;
 import com.cyksj.dto.RedisKey;
 import com.cyksj.enums.GatewayApiCode;
+import com.cyksj.mapper.UserDistributeSharedWhiteMapper;
 import com.cyksj.mapper.*;
+import com.cyksj.mapper.manage.coupon.CouponDistributePopularizeMapper;
 import com.cyksj.mapper.manage.coupon.CouponMapper;
 import com.cyksj.mapper.manage.coupon.CouponSkuMapper;
 import com.cyksj.mapper.manage.coupon.CouponUserMapper;
-import com.cyksj.mapper.manage.distribute.UserDistributeMapper;
-import com.cyksj.mapper.manage.distribute.UserDistributeSharedMapper;
+import com.cyksj.mapper.manage.distribute.*;
 import com.cyksj.model.dto.ChatGPTPlusPurchaseLimitDto;
 import com.cyksj.model.dto.CouponPopularizeDto;
 import com.cyksj.model.dto.OrderDonPostDataDto;
@@ -158,6 +159,26 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 
 	private final EnvCommonService envCommonService;
 
+	private final CouponDistributePopularizeMapper couponDistributePopularizeMapper;
+
+	private final UserDistributeSharedRelateUnbindMapper userDistributeSharedRelateUnbindMapper;
+
+	private final UserDistributeSharedWhiteMapper userDistributeSharedWhiteMapper;
+
+	private final DistributePointsExchangeMoneyMapper distributePointsExchangeMoneyMapper;
+
+	private final DistributeWaitingSendPointsMapper distributeWaitingSendPointsMapper;
+
+	private final DistributeGeneralSkuRateMapper distributeGeneralSkuRateMapper;
+
+	private final UserPlatSkuDistributeRateMapper userPlatSkuDistributeRateMapper;
+
+	private final BusinessDistributeDefaultSkuRateConfigMapper businessDistributeDefaultSkuRateConfigMapper;
+
+	private final UserPlatDistributeRateMapper userPlatDistributeRateMapper;
+
+	private final BusinessDistributeDefaultRateConfigMapper businessDistributeDefaultRateConfigMapper;
+
 	@Transactional(rollbackFor = Throwable.class)
 	@Override
 	public OrderDon submit(OrderPayRequest payRequest) throws Exception {
@@ -292,12 +313,15 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			orderDon.setIsDp(true);
 		}
 
+		//虚拟商品订单,是否是分销订单
+		setDistributeOrderMark(orderDon, goodsDon.getType(), user.getId());
+
 		//渠道链接id
 		if (payRequest.getPopularizeId() != null) {
 			orderDon.setPopularizeId(payRequest.getPopularizeId());
 		}
 		//扣除使用优惠券、余额的订单金额
-//		deductOrderMoney(orderDon, couponUser, payRequest.getBalance(), user, sku.getPrice(), goodsDon.getType());
+		deductOrderMoney(orderDon, couponUser, payRequest.getBalance(), user, sku.getPrice(), goodsDon.getType());
 
 		orderDon.setSkuId(payRequest.getSkuId());
 		orderDon.setRelationId(relationId);
@@ -406,6 +430,10 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 					clearUserLockingRelation(groupsRelation, orderDon);
 				}
 			}
+			//返还优惠券
+			if (orderDon.getCouponUserId() != 0) {
+				couponFontService.updateOrderDonCouponStatus(orderDon);
+			}
 		}
 	}
 
@@ -1238,6 +1266,18 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		if (orderDon.getBalance().compareTo(BigDecimal.ZERO) > 0) {
 			userBenefitsService.recordBalanceBySource(orderDon.getUserId(), orderDon.getBalance().negate(), UserBalanceSourceRecord.Source.payment, orderDon.getId(), goodsDon.getTitle() + UserBalanceSourceRecord.Source.payment.getDesc());
 		}
+
+		TASK_POOL.execute(()->{
+			try {
+				//发放积分
+				if (orderDon.getMoney().compareTo(BigDecimal.ZERO) > 0 && orderDon.getIsDistribute()) {
+					distributeWaitingSendPointsRecord(orderDon);
+				}
+			} catch (Exception e) {
+				log.error("回调修改订单信息错误,orderId:{},error:{}", orderDon.getId(), StringUtil.getErrorText(e));
+			}
+		});
+
 	}
 
 	/**
@@ -1292,4 +1332,336 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		}
 		return user;
 	}
+
+
+	/**
+	 * 使用优惠营销 订单金额抵扣
+	 */
+	public void deductOrderMoney(OrderDon orderDon, CouponUser couponUser, BigDecimal balance, User user, BigDecimal skuMoney, Integer goodsType) {
+		BigDecimal first_money = orderDon.getMoney();
+		//存在优惠券
+		if (couponUser != null) {
+			Long couponId = couponUser.getCouponId();
+			Coupon coupon = couponMapper.getCouponById(couponId);
+			BigDecimal couponMoney = null;
+			BigDecimal payMoney = orderDon.getMoney();
+			BigDecimal needDeductMoney = payMoney;
+			if (orderDon.getOriMoney() == null) {
+				orderDon.setOriMoney(payMoney);
+			}
+			if (orderDon.getIsDp() != null && orderDon.getIsDp()) {
+				needDeductMoney = needDeductMoney.subtract(orderDon.getDpMoney());
+			}
+			if (coupon.getType() == Coupon.Type.discount) {
+				couponMoney = needDeductMoney.multiply(BigDecimal.valueOf(1).subtract(coupon.getDiscount()));
+				//需支付金额
+				orderDon.setMoney(payMoney.subtract(couponMoney));
+
+				orderDon.setOriMoney(orderDon.getOriMoney().multiply(coupon.getDiscount()));
+				//记录折扣 用于分销
+				couponUser.setDiscount(coupon.getDiscount());
+				couponUserMapper.updateById(couponUser);
+			} else if (coupon.getType() == Coupon.Type.reduce) {
+				//设备
+				if (goodsType == 2) {
+					if (skuMoney.compareTo(coupon.getReduceCondition()) < 0) {
+						throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("sys_error"));
+					}
+				}
+				BigDecimal subtractMoney = payMoney.subtract(coupon.getReduceMoney());
+				orderDon.setMoney(subtractMoney);
+				couponMoney = coupon.getReduceMoney();
+
+				orderDon.setOriMoney(orderDon.getOriMoney().subtract(coupon.getReduceMoney()));
+			}
+			if (couponMoney != null && couponMoney.compareTo(first_money) >= 0) {
+				throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("coupon_money_error"));
+			}
+			orderDon.setCouponMoney(couponMoney);
+			orderDon.setCouponUserId(couponUser.getId());
+		}
+
+		//存在余额
+//		deductBalancePayOrderMoney(orderDon, balance, user);
+	}
+
+	public void setDistributeOrderMark(OrderDon orderDon, Integer goodsType, Long userId) {
+		if (userId == null || userId == 0) {
+			return;
+		}
+		//虚拟商品订单,是否是分销订单
+		if (goodsType == 1 || goodsType == 2) {
+			//若该订单使用了规定推广者的兑换码 增加上下级关系
+			if (StrUtil.isNotBlank(orderDon.getCouponExCode()) && orderDon.getUserId() != 0) {
+				addDistributeCouponCode(orderDon.getUserId(), orderDon.getCouponExCode());
+			}
+			UserDistributeShared userDistributeShared = userDistributeSharedMapper.selectOne(Wrappers.lambdaQuery(UserDistributeShared.class).eq(UserDistributeShared::getUserId, userId).last("limit 1"));
+			if (userDistributeShared != null) {
+				orderDon.setIsDistribute(true);
+				UserDistribute userDistribute = userDistributeMapper.selectOne(Wrappers.lambdaQuery(UserDistribute.class).eq(UserDistribute::getUserId, userDistributeShared.getSharedId()).eq(UserDistribute::getDeleted, 1));
+				if (userDistribute != null) {
+					orderDon.setCpsPopularizeId(userDistributeShared.getDsPopularizeId());
+					//直接去除
+					if (!userDistributeShared.getIsBind()) {
+						UserDistributeSharedRelateUnbind userDistributeSharedRelateUnbind = userDistributeSharedRelateUnbindMapper.selectOne(Wrappers.lambdaQuery(UserDistributeSharedRelateUnbind.class)
+								.eq(UserDistributeSharedRelateUnbind::getUserId, userId)
+								.eq(UserDistributeSharedRelateUnbind::getIsUnbind, 1)
+								.last("limit 1"));
+						if (userDistributeSharedRelateUnbind != null) {
+							//是否是渠道用户白名单
+							UserDistributeSharedWhite userDistributeSharedWhite = userDistributeSharedWhiteMapper.selectOne(Wrappers.lambdaQuery(UserDistributeSharedWhite.class)
+									.eq(UserDistributeSharedWhite::getUserId, userDistributeShared.getSharedId())
+									.last("limit 1"));
+							if (userDistributeSharedWhite != null) {
+								orderDon.setIsFixedDistribute(true);
+								return;
+							}
+						}
+						orderDon.setIsDistribute(false);
+					} else {
+						//45天内是否下单成功 ==>改为30天
+						Date createdTime = userDistributeShared.getCreatedTime();
+						DateTime time = DateUtil.offsetDay(createdTime, 30);
+						//在45天内
+						Boolean is_fit = false;
+						boolean before = DateTime.now().isBefore(time);
+						//超过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, time));
+							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);
+						}
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * 使用推广者的优惠码增加上下级
+	 */
+	private void addDistributeCouponCode(Long userId, String couponExCode) {
+		UserDistributeShared userDistributeShared = userDistributeSharedMapper.selectOne(Wrappers.lambdaQuery(UserDistributeShared.class)
+				.eq(UserDistributeShared::getUserId, userId).last("limit 1"));
+		if (userDistributeShared == null) {
+			CouponDistributePopularize couponDistributePopularize = couponDistributePopularizeMapper.selectOne(Wrappers.lambdaQuery(CouponDistributePopularize.class).eq(CouponDistributePopularize::getExCode, couponExCode).last("limit 1"));
+			Optional.ofNullable(couponDistributePopularize).ifPresent(popularize -> {
+				try {
+					Long sharedId;
+					//是否是普通推广专属关联
+					if (popularize.getIsGeneral()) {
+						sharedId = popularize.getUserId();
+					} else {
+						UserDistribute userDistribute = userDistributeMapper.selectById(popularize.getDistributeId());
+						if (userDistribute == null || !userDistribute.getDeleted()) {
+							return;
+						}
+						sharedId = userDistribute.getUserId();
+					}
+					if (sharedId.equals(userId)) {
+						return;
+					}
+					UserDistributeShared ud = new UserDistributeShared();
+					ud.setUserId(userId);
+					ud.setSharedId(sharedId);
+					ud.setRemark("优惠码");
+					userDistributeSharedMapper.insert(ud);
+					log.info("userId:{}使用优惠码:{}与推广用户sharedId:{}建立关系", userId, couponExCode, sharedId);
+				} catch (DuplicateKeyException e) {
+
+				}
+			});
+		}
+	}
+
+
+	/**
+	 * 分销待发积分记录
+	 */
+	public void distributeWaitingSendPointsRecord(OrderDon order) {
+		log.info("订单id:{}产生分销积分开始--->", order.getId());
+		DistributeWaitingSendPoints distributeWaitingSendPoints = new DistributeWaitingSendPoints();
+		distributeWaitingSendPoints.setOrderId(order.getId());
+		distributeWaitingSendPoints.setUserId(order.getUserId());
+		BigDecimal orderMoney = order.getMoney();
+		//是否是加购订单
+		if (order.getIsDp()) {
+			//加购订单使用 主平台金额 分销
+			orderMoney = order.getOriMoney();
+			if (orderMoney.compareTo(BigDecimal.ZERO) == 0) {
+				log.info("orderId:{}之前加购订单,无主平台金额,使用规格金额", order.getId());
+				GoodsDonSku sku = goodsDonSkuMapper.selectById(order.getSkuId());
+				orderMoney = sku.getPrice();
+			}
+		}
+		order.setDsMoney(orderMoney);
+		BigDecimal points = null;
+		BigDecimal returnMoney = null;
+		Long businessId = null;
+		//普通分销
+		GoodsDon goodsDon = goodsDonMapper.selectById(order.getGoodsId());
+		GoodsDonSku goodsDonSku = null;
+		if (goodsDon == null || !goodsDon.getIsDistribute()) {
+			log.info("分销订单orderId:{}对应平台goodsId:{}不存在或已不参与分成比例", order.getId(), order.getGoodsId());
+			return;
+		}
+		if (order.getSkuId() != null) {
+			goodsDonSku = goodsDonSkuMapper.selectById(order.getSkuId());
+		}
+		UserDistributeShared userDistributeShared = userDistributeSharedMapper.selectOne(Wrappers.lambdaQuery(UserDistributeShared.class).eq(UserDistributeShared::getUserId, order.getUserId()).last("limit 1"));
+		if (userDistributeShared != null) {
+			distributeWaitingSendPoints.setSharedId(userDistributeShared.getSharedId());
+			DistributePointsExchangeMoney distributePointsExchangeMoney = distributePointsExchangeMoneyMapper.selectOne(Wrappers.lambdaQuery(DistributePointsExchangeMoney.class).orderByDesc(DistributePointsExchangeMoney::getPoints).last("limit 1"));
+			if (distributePointsExchangeMoney == null) {
+				log.info("分销兑换积分比例未配置");
+			} else {
+				UserDistribute userDistribute = userDistributeMapper.selectOne(Wrappers.lambdaQuery(UserDistribute.class).eq(UserDistribute::getUserId, userDistributeShared.getSharedId()).eq(UserDistribute::getDeleted, true).last("limit 1"));
+				//分销比例
+				Integer rate = 0;
+				if (userDistribute == null) {
+					//普通分销者 是否享受过该用户的首单分销
+					DistributeWaitingSendPoints isReceived = distributeWaitingSendPointsMapper.selectOne(Wrappers.lambdaQuery(DistributeWaitingSendPoints.class)
+							.eq(DistributeWaitingSendPoints::getSharedId, userDistributeShared.getSharedId())
+							.eq(DistributeWaitingSendPoints::getUserId, order.getUserId())
+							.in(DistributeWaitingSendPoints::getSendStatus, List.of(DistributeWaitingSendPoints.Status.waiting.name(), DistributeWaitingSendPoints.Status.success.name()))
+							.last("limit 1"));
+					if (isReceived != null) {
+						return;
+					}
+					rate = goodsDon.getRate();
+					//实物分销比例
+					if (goodsDon.getType() == 2) {
+						if (goodsDonSku != null) {
+							//不包含套餐权益
+							if (!goodsDonSku.getIsBenefits()) {
+								rate = goodsDon.getSecondRate();
+							}
+						}
+					}
+					//该平台是否开启规格分销
+					if (goodsDon.getIsSkuDistribute()) {
+						//是否设置对应规格分销比例
+						DistributeGeneralSkuRate skuRate = distributeGeneralSkuRateMapper.selectOne(Wrappers.lambdaQuery(DistributeGeneralSkuRate.class)
+								.eq(DistributeGeneralSkuRate::getSkuId, goodsDonSku.getId()).last("limit 1"));
+						if (skuRate != null) rate = skuRate.getRate();
+					}
+					returnMoney = orderMoney.multiply(BigDecimal.valueOf(rate)).divide(BigDecimal.valueOf(100));
+				} else {
+					businessId = userDistribute.getBusinessId();
+					UserPlatDistributeRate userPlatDistributeRate = null;
+					Integer secondRate = 0;
+					//该商品是否开启了 规格分销
+					if (goodsDon.getIsSkuDistribute()) {
+						//规格分销 比例
+						UserPlatSkuDistributeRate userPlatSkuDistributeRate = userPlatSkuDistributeRateMapper.selectOne(Wrappers.lambdaQuery(UserPlatSkuDistributeRate.class)
+								.eq(UserPlatSkuDistributeRate::getDistributeId, userDistribute.getId())
+								.eq(UserPlatSkuDistributeRate::getSkuId, order.getSkuId()).last("limit 1"));
+						if (userPlatSkuDistributeRate != null) {
+							userPlatDistributeRate = getUserPlatDistributeRate(userPlatSkuDistributeRate.getRate(), userPlatSkuDistributeRate.getSecondRate());
+						}
+					}
+					if (userPlatDistributeRate == null) {
+						//默认规格分销比例
+						if (goodsDon.getIsSkuDistribute()) {
+							BusinessDistributeDefaultSkuRateConfig businessDistributeDefaultSkuRateConfig = businessDistributeDefaultSkuRateConfigMapper.selectOne(Wrappers.lambdaQuery(BusinessDistributeDefaultSkuRateConfig.class)
+									.eq(BusinessDistributeDefaultSkuRateConfig::getSkuId, order.getSkuId())
+									.last("limit 1"));
+							if (businessDistributeDefaultSkuRateConfig != null) {
+								userPlatDistributeRate = getUserPlatDistributeRate(businessDistributeDefaultSkuRateConfig.getRate(), businessDistributeDefaultSkuRateConfig.getSecondRate());
+							}
+						}
+					}
+					if (userPlatDistributeRate == null) {
+						//固定推广分销 平台比例
+						userPlatDistributeRate = userPlatDistributeRateMapper.selectOne(Wrappers.lambdaQuery(UserPlatDistributeRate.class)
+								.eq(UserPlatDistributeRate::getGoodsId, order.getGoodsId())
+								.eq(UserPlatDistributeRate::getDistributeId, userDistribute.getId())
+								.last("limit 1"));
+					}
+					//未配置平台分销比例 寻找默认比例
+					if (userPlatDistributeRate == null) {
+						BusinessDistributeDefaultRateConfig defaultRateConfig = businessDistributeDefaultRateConfigMapper.selectOne(Wrappers.lambdaQuery(BusinessDistributeDefaultRateConfig.class)
+								.eq(BusinessDistributeDefaultRateConfig::getGoodsId, order.getGoodsId())
+								.last("limit 1"));
+						if (defaultRateConfig != null) {
+							userPlatDistributeRate = getUserPlatDistributeRate(defaultRateConfig.getRate(), defaultRateConfig.getSecondRate());
+						}
+					}
+					if (userPlatDistributeRate != null) {
+						rate = userPlatDistributeRate.getRate();
+						secondRate = userPlatDistributeRate.getSecondRate();
+						if (goodsDon.getType() == 2) {
+							goodsDonSku = goodsDonSkuMapper.selectById(order.getSkuId());
+							if (goodsDonSku != null) {
+								//不包含套餐权益
+								if (!goodsDonSku.getIsBenefits()) {
+									rate = secondRate;
+								}
+							}
+							distributeWaitingSendPoints.setIsDelivery(false);
+						}
+						returnMoney = orderMoney.multiply(BigDecimal.valueOf(rate)).divide(BigDecimal.valueOf(100));
+					}
+				}
+				if (returnMoney != null) {
+					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());
+					distributeWaitingSendPoints.setSendStatus(DistributeWaitingSendPoints.Status.waiting);
+					distributeWaitingSendPoints.setSendTime(DateUtil.offsetDay(order.getPayTime(), 3));
+					distributeWaitingSendPoints.setRate(rate);
+					//普通分销 额外返利
+					if (userDistribute == null && points.compareTo(BigDecimal.ZERO) > 0) {
+						distributeWaitingSendPoints.setOriPoints(points);
+						if (goodsDonSku == null) {
+							goodsDonSku = goodsDonSkuMapper.selectById(order.getSkuId());
+						}
+						if (goodsDonSku.getIsMirror()) {
+							//镜像规格 默认百分之20 提成
+							distributeWaitingSendPoints.setRate(20);
+							//最新返利积分
+							BigDecimal newReturnMoney = orderMoney.multiply(BigDecimal.valueOf(distributeWaitingSendPoints.getRate())).divide(BigDecimal.valueOf(100));
+							points = newReturnMoney.multiply(BigDecimal.valueOf(distributePointsExchangeMoney.getPoints())).divide(distributePointsExchangeMoney.getMoney(), 2, RoundingMode.HALF_DOWN);
+							distributeWaitingSendPoints.setPoints(points);
+						} else {
+							//额外返利 去除
+						}
+					}
+					distributeWaitingSendPointsMapper.insert(distributeWaitingSendPoints);
+				}
+			}
+		}
+	}
+
+	public UserPlatDistributeRate getUserPlatDistributeRate(Integer rate, Integer secondRate) {
+		UserPlatDistributeRate userPlatDistributeRate = new UserPlatDistributeRate();
+		userPlatDistributeRate.setRate(rate);
+		userPlatDistributeRate.setSecondRate(secondRate);
+		return userPlatDistributeRate;
+	}
 }

+ 18 - 0
netflix-service/src/main/java/com/cyksj/service/pay/TransferFuncService.java

@@ -0,0 +1,18 @@
+package com.cyksj.service.pay;
+
+import com.cyksj.dto.Result;
+import com.cyksj.model.request.ApplyMoneyReq;
+
+/*
+ *项目名: yhlxj
+ *文件名: TransferFuncService
+ *创建者: JavaZou
+ *创建时间:2023/9/20 18:54
+ */
+public interface TransferFuncService {
+
+	/**
+	 * 分销渠道提现
+	 */
+	Result distributeApply(ApplyMoneyReq applyMoneyReq) throws Exception;
+}

+ 185 - 0
netflix-service/src/main/java/com/cyksj/service/pay/impl/TransferFuncServiceImpl.java

@@ -0,0 +1,185 @@
+package com.cyksj.service.pay.impl;
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.EnvCommonService;
+import com.cyksj.common.constant.Constant;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.i18n.I18nMessageUtil;
+import com.cyksj.common.snowflake.Sequence;
+import com.cyksj.common.util.SmsUtil;
+import com.cyksj.common.util.StringUtil;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.mapper.UserMapper;
+import com.cyksj.mapper.manage.distribute.DistributeMoneyApplyMapper;
+import com.cyksj.mapper.manage.distribute.DistributePointsExchangeMoneyMapper;
+import com.cyksj.mapper.manage.distribute.UserDistributeMapper;
+import com.cyksj.model.entity.DistributeMoneyApply;
+import com.cyksj.model.entity.DistributePointsExchangeMoney;
+import com.cyksj.model.entity.User;
+import com.cyksj.model.request.ApplyMoneyReq;
+import com.cyksj.redis.RedisService;
+import com.cyksj.service.distribute.UserDistributeReturnMoneyDetailService;
+import com.cyksj.service.pay.TransferFuncService;
+import com.cyksj.service.sys.SysConfigService;
+import com.cyksj.service.user.UserBenefitsService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Optional;
+
+/*
+ *项目名: yhlxj
+ *文件名: TransferFuncServiceImpl
+ *创建者: JavaZou
+ *创建时间:2023/9/20 18:55
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class TransferFuncServiceImpl implements TransferFuncService {
+	private static final Sequence SEQUENCE = new Sequence(0);
+
+	private final UserMapper userMapper;
+
+	private final UserBenefitsService userBenefitsService;
+
+	private final EnvCommonService envCommonService;
+
+	private final UserDistributeMapper userDistributeMapper;
+
+	private final DistributePointsExchangeMoneyMapper distributePointsExchangeMoneyMapper;
+
+	private final DistributeMoneyApplyMapper distributeMoneyApplyMapper;
+
+	private final RedisService redisService;
+
+	private final SysConfigService sysConfigService;
+
+	private final UserDistributeReturnMoneyDetailService userDistributeReturnMoneyDetailService;
+
+	@Override
+	public Result distributeApply(ApplyMoneyReq applyMoneyReq) throws Exception {
+		applyMoneyReq.setMType(DistributeMoneyApply.MType.ds);
+		String key = String.format(RedisService.key.APPLY_MONEY_DAY_LIMIT_KEY.getName(), DateTime.now().toDateStr(), applyMoneyReq.getMType(), applyMoneyReq.getUserId());
+		if (!redisService.setNx(key, applyMoneyReq.getUserId(), RedisService.key.APPLY_MONEY_DAY_LIMIT_KEY.getTimeout())) {
+			throw BusinessRuntimeException.getInstance("每天仅可提现一次");
+		}
+		try {
+			Result result = commonApplyMoney(applyMoneyReq);
+			if (result.isFlag()) {
+				redisService.set(key, applyMoneyReq.getUserId(), RedisService.key.APPLY_MONEY_DAY_LIMIT_KEY.getTimeout());
+			} else {
+				redisService.del(key);
+			}
+			return result;
+		} catch (Exception e) {
+			redisService.del(key);
+			throw BusinessRuntimeException.getInstance(StringUtil.getErrorMsg(e));
+		}
+	}
+
+
+	public Result commonApplyMoney(ApplyMoneyReq applyMoneyReq) throws Exception {
+		Long userId = applyMoneyReq.getUserId();
+		User user = userMapper.selectById(userId);
+		if (user == null) {
+			throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("sys_error"));
+		}
+		if (user.getIsBlack()) throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("user_black_error"));
+		Boolean isTakeAll = applyMoneyReq.getIsTakeAll();
+		DistributeMoneyApply.Type type = applyMoneyReq.getType();
+		if (type == null) type = DistributeMoneyApply.Type.usdt;
+		if (type == DistributeMoneyApply.Type.usdt) {
+			if (StrUtil.isEmpty(applyMoneyReq.getWalletAddr())) {
+				throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("distribute_apply_money_usdt_address_error"));
+			}
+			if (applyMoneyReq.getWalletAddr().length() > 1000) {
+				throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("distribute_apply_money_usdt_address_error"));
+			}
+			isTakeAll = true;
+		}
+		if (type == DistributeMoneyApply.Type.bank) {
+			if (StrUtil.isEmpty(applyMoneyReq.getRealName())) {
+				throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg(I18nMessageUtil.getI18nMsg("reaL_name_error")));
+			}
+			if (StrUtil.isEmpty(applyMoneyReq.getBankNo())) {
+				throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("enter_bank_no_error"));
+			}
+			isTakeAll = true;
+		}
+		if (StrUtil.isNotBlank(applyMoneyReq.getRemark()) && applyMoneyReq.getRemark().length() > 512) {
+			throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("distribute_apply_money_remark_length_error"));
+		}
+		DistributeMoneyApply.MType mType = applyMoneyReq.getMType();
+		DistributeMoneyApply distributeMoneyApply = null;
+//		//今日是否已提现
+//		DistributeMoneyApply apply = distributeMoneyApplyMapper.selectOne(Wrappers.lambdaQuery(DistributeMoneyApply.class).eq(DistributeMoneyApply::getUserId, userId).between(DistributeMoneyApply::getCreatedTime, DateUtil.beginOfDay(DateTime.now()), DateUtil.endOfDay(DateTime.now())).last("limit 1"));
+//		if (apply != null) {
+//			throw BusinessRuntimeException.getInstance("今日已提现,请明日再进行操作");
+//		}
+		BigDecimal userPoints = null;
+		BigDecimal needSubPoints = null;
+		BigDecimal needApplyMoney = null;
+		BigDecimal fourHundred = null;
+		if (mType == DistributeMoneyApply.MType.ds) {
+			userPoints = user.getPoints();
+			DistributePointsExchangeMoney distributePointsExchangeMoney = distributePointsExchangeMoneyMapper.selectOne(Wrappers.lambdaQuery(DistributePointsExchangeMoney.class).orderByDesc(DistributePointsExchangeMoney::getPoints).last("limit 1"));
+			BigDecimal minPoints = BigDecimal.valueOf(distributePointsExchangeMoney.getMinPoints());
+			BigDecimal ratePoints = BigDecimal.valueOf(distributePointsExchangeMoney.getPoints());
+			BigDecimal minMoney = distributePointsExchangeMoney.getMoney();
+			if (userPoints.compareTo(minPoints) < 0) {
+				throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("distribute_apply_money_thresholds_error"));
+			}
+			BigDecimal num = userPoints.divide(ratePoints, 0, RoundingMode.DOWN);
+			needApplyMoney = num.multiply(minMoney);
+			needSubPoints = num.multiply(ratePoints);
+			fourHundred = BigDecimal.valueOf(4 * 100 * 100);
+			if (isTakeAll == null || !isTakeAll) {
+				if (needApplyMoney.compareTo(fourHundred) > 0) {
+					needApplyMoney = fourHundred;
+					needSubPoints = fourHundred.divide(minMoney).multiply(ratePoints);
+				}
+			}
+		}
+		Integer update = 0;
+		if (mType == DistributeMoneyApply.MType.ds) {
+			update = userMapper.subPoints(user.getId(), needSubPoints);
+		}
+		if (update == 1) {
+			distributeMoneyApply = Optional.ofNullable(distributeMoneyApply).orElse(new DistributeMoneyApply());
+			distributeMoneyApply.setUserId(userId);
+			distributeMoneyApply.setPoints(needSubPoints);
+			distributeMoneyApply.setMoney(needApplyMoney);
+			distributeMoneyApply.setAccount(applyMoneyReq.getAccount());
+			distributeMoneyApply.setRealName(applyMoneyReq.getRealName());
+			distributeMoneyApply.setWalletAddr(applyMoneyReq.getWalletAddr());
+			distributeMoneyApply.setRemark(applyMoneyReq.getRemark());
+			distributeMoneyApply.setType(applyMoneyReq.getType());
+			distributeMoneyApply.setMType(applyMoneyReq.getMType());
+			if (isTakeAll != null && isTakeAll) {
+				distributeMoneyApply.setVerifyStatus(DistributeMoneyApply.Status.verifying);
+			} else {
+				//支付宝提现去掉
+			}
+			try {
+				distributeMoneyApplyMapper.insert(distributeMoneyApply);
+				//大额提现 超过400
+				if (envCommonService.isPrdEnv() && distributeMoneyApply.getVerifyStatus() == DistributeMoneyApply.Status.verifying && distributeMoneyApply.getMoney().compareTo(fourHundred) > 0) {
+					SmsUtil.sendLuoKey2Msg(Constant.ZK_MOBILE, "银河海外推广有大额提现申请【银河录像局】");
+				}
+				userDistributeReturnMoneyDetailService.recordDistributeReturnMoney(distributeMoneyApply.getUserId(), distributeMoneyApply.getMoney().negate(), "提现");
+			} catch (Exception e) {
+				userBenefitsService.addDistributePoints(userId, distributeMoneyApply.getPoints());
+				return GatewayResponse.FAIL.newBuilder().setMsg(I18nMessageUtil.getI18nMsg("sys_error")).toResult();
+			}
+			return GatewayResponse.SUCCESS.newBuilder().toResult(distributeMoneyApply);
+		}
+		throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("sys_error"));
+	}
+}

+ 10 - 0
netflix-service/src/main/java/com/cyksj/service/translations/BackInfoTranslationsFrontService.java

@@ -2,6 +2,7 @@ package com.cyksj.service.translations;
 
 import com.cyksj.model.entity.GoodsDonSku;
 import com.cyksj.model.manage.views.GoodsDonViewer;
+import com.cyksj.model.views.CouponView;
 import com.cyksj.model.views.GoodsFrontListCategoryView;
 import com.cyksj.model.views.GoodsFrontListView;
 
@@ -27,4 +28,13 @@ public interface BackInfoTranslationsFrontService {
 	String setSpecVal(Long skuId, String lang);
 
 	String setGoodsTitle(Long goodsId, String lang);
+
+	void setCouponLanguage(CouponView couponView, String lang);
+
+	void setFieldLanguage(Class<?> tclass, Object obj, Integer type, Long funcId, String lang);
+
+	/**
+	 * 设置优惠券规格展示多语言
+	 */
+	String setCouponGoodsSkuStrLanguage(Long couponId, String lang);
 }

+ 68 - 5
netflix-service/src/main/java/com/cyksj/service/translations/impl/BackInfoTranslationsFrontServiceImpl.java

@@ -4,19 +4,21 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.mapper.BackInfoTranslationsMapper;
+import com.cyksj.mapper.manage.coupon.CouponMapper;
+import com.cyksj.mapper.manage.coupon.CouponSkuMapper;
 import com.cyksj.model.entity.BackInfoTranslations;
 import com.cyksj.model.entity.GoodsDonSku;
+import com.cyksj.model.entity.UserPageLanguage;
 import com.cyksj.model.manage.views.GoodsDonViewer;
-import com.cyksj.model.views.GoodsDonSkuFrontView;
-import com.cyksj.model.views.GoodsDonSpecFrontView;
-import com.cyksj.model.views.GoodsFrontListCategoryView;
-import com.cyksj.model.views.GoodsFrontListView;
+import com.cyksj.model.views.*;
 import com.cyksj.service.translations.BackInfoTranslationsFrontService;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 
 import java.lang.reflect.Field;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 项目名: yhlxj2
@@ -29,6 +31,10 @@ import java.util.List;
 public class BackInfoTranslationsFrontServiceImpl implements BackInfoTranslationsFrontService {
 	private final BackInfoTranslationsMapper backInfoTranslationsMapper;
 
+	private final CouponMapper couponMapper;
+
+	private final CouponSkuMapper couponSkuMapper;
+
 	@Override
 	public void setGoodsDetailLanguage(GoodsFrontListView views, String lang) {
 		if (views == null) {
@@ -112,8 +118,24 @@ public class BackInfoTranslationsFrontServiceImpl implements BackInfoTranslation
 		return null;
 	}
 
+	@Override
+	public void setCouponLanguage(CouponView couponView, String lang) {
+		setFieldLanguage(couponView.getClass(), couponView, BackInfoTranslations.Type.coupon.ordinal(), couponView.getId(), lang);
+		if (couponView.getClassificationId() != null) {
+			BackInfoTranslations classificationTranslation = backInfoTranslationsMapper.selectOne(Wrappers.lambdaQuery(BackInfoTranslations.class)
+					.eq(BackInfoTranslations::getType, BackInfoTranslations.Type.coupon_classification.ordinal())
+					.eq(BackInfoTranslations::getLang, lang)
+					.eq(BackInfoTranslations::getFuncId, couponView.getClassificationId())
+					.eq(BackInfoTranslations::getFieldName, "name"));
+			if (classificationTranslation != null) {
+				couponView.setCouponClassificationName(classificationTranslation.getDesp());
+			}
+		}
+	}
+
+	@Override
 	public void setFieldLanguage(Class<?> tclass, Object obj, Integer type, Long funcId, String lang) {
-		if (StrUtil.isEmpty(lang)) {
+		if (StrUtil.isEmpty(lang) || StrUtil.equals(UserPageLanguage.Language.zh_HK.name(), lang)) {
 			return;
 		}
 		List<BackInfoTranslations> backInfoTranslations = backInfoTranslationsMapper.selectList(Wrappers.lambdaQuery(BackInfoTranslations.class)
@@ -134,4 +156,45 @@ public class BackInfoTranslationsFrontServiceImpl implements BackInfoTranslation
 			});
 		}
 	}
+
+
+	@Override
+	public String setCouponGoodsSkuStrLanguage(Long couponId, String lang) {
+		if (StrUtil.isEmpty(lang) || StrUtil.equals(UserPageLanguage.Language.zh_HK.name(), lang)) {
+			String str = couponSkuMapper.selectGoodsSkuStr(couponId);
+			str = str.replaceAll(",", "/").replaceAll(";", "");
+			return str;
+		}
+
+		List<GoodsDonSku> goodsDonSkus = couponMapper.getCouponSku(couponId);
+		StringBuilder skuGoodsStrSb = new StringBuilder(128);
+		Map<Long, String> map = new HashMap<>();
+		goodsDonSkus.forEach(sku -> {
+			String title = map.get(sku.getGoodsId());
+			if (StrUtil.isEmpty(title)) {
+				BackInfoTranslations backGoodsInfoTranslations = backInfoTranslationsMapper.selectOne(Wrappers.lambdaQuery(BackInfoTranslations.class)
+						.eq(BackInfoTranslations::getType, BackInfoTranslations.Type.goods.ordinal())
+						.eq(BackInfoTranslations::getLang, lang)
+						.eq(BackInfoTranslations::getFieldName, "title")
+						.eq(BackInfoTranslations::getFuncId, sku.getGoodsId()));
+				if (backGoodsInfoTranslations != null) {
+					title = backGoodsInfoTranslations.getDesp();
+					map.put(sku.getGoodsId(), title);
+				}
+			}
+			BackInfoTranslations backSkuInfoTranslations = backInfoTranslationsMapper.selectOne(Wrappers.lambdaQuery(BackInfoTranslations.class)
+					.eq(BackInfoTranslations::getType, BackInfoTranslations.Type.sku.ordinal())
+					.eq(BackInfoTranslations::getLang, lang)
+					.eq(BackInfoTranslations::getFieldName, "specVal")
+					.eq(BackInfoTranslations::getFuncId, sku.getId()));
+			if (skuGoodsStrSb.length() > 0) {
+				skuGoodsStrSb.append("/");
+			}
+			if (backSkuInfoTranslations != null) {
+				skuGoodsStrSb.append(title).append(" ").append(backSkuInfoTranslations.getDesp());
+			}
+		});
+
+		return skuGoodsStrSb.toString();
+	}
 }

+ 7 - 0
netflix-service/src/main/java/com/cyksj/service/user/impl/UserServiceImpl.java

@@ -29,6 +29,7 @@ import com.cyksj.model.request.ExchangeCodeTicket;
 import com.cyksj.model.request.LoginReq;
 import com.cyksj.model.request.OrderBindCommonReq;
 import com.cyksj.redis.RedisService;
+import com.cyksj.service.distribute.DistributeService;
 import com.cyksj.service.exchange.ExchangeCodeService;
 import com.cyksj.service.user.UserService;
 import lombok.RequiredArgsConstructor;
@@ -67,6 +68,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
 
 	private final GroupsRelationMapper relationMapper;
 
+	private final DistributeService distributeService;
+
 	private static final GlobalThreadPoolTaskExecutor TASK_POOL = GlobalThreadPoolTaskExecutor.getInstance();
 
     @Override
@@ -234,6 +237,10 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
 				user.setEmail(loginReq.getEmail());
 			}
 			this.save(user);
+			//新用户分销
+			if (sharedId != null) {
+				distributeService.saveDistributionInvitation(sharedId, user.getId(), dsPopularizeId);
+			}
 			//缓存用户注册 回传信息
 			String callback = loginReq.getCallback();
 			String callbackType = loginReq.getCallbackType();

+ 25 - 146
netflix-web/src/main/java/com/cyksj/web/controller/coupon/CouponFrontController.java

@@ -4,7 +4,6 @@ import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.cyksj.common.annotation.NoSubmit;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.common.i18n.I18nMessageUtil;
 import com.cyksj.common.util.Jsons;
@@ -12,14 +11,12 @@ import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
 import com.cyksj.mapper.UserMapper;
 import com.cyksj.mapper.manage.coupon.CouponMapper;
-import com.cyksj.mapper.manage.coupon.CouponRecommendMapper;
 import com.cyksj.mapper.manage.coupon.CouponSkuMapper;
 import com.cyksj.mapper.manage.coupon.CouponUserMapper;
 import com.cyksj.mapper.manage.distribute.UserDistributeMapper;
 import com.cyksj.mapper.manage.distribute.UserDistributeSharedMapper;
 import com.cyksj.model.dto.CouponPopularizeDto;
 import com.cyksj.model.entity.*;
-import com.cyksj.model.request.ChannelPopularizeCouponReq;
 import com.cyksj.model.request.CouponCollectReq;
 import com.cyksj.model.views.*;
 import com.cyksj.redis.RedisService;
@@ -29,9 +26,9 @@ import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.param.Operator;
 import com.ejlchina.searcher.util.MapUtils;
 import lombok.RequiredArgsConstructor;
-import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
+import javax.servlet.http.HttpServletRequest;
 import java.math.BigDecimal;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -60,47 +57,25 @@ public class CouponFrontController {
 
 	private final UserDistributeMapper userDistributeMapper;
 
-	private final CouponRecommendMapper couponRecommendMapper;
+	private final HttpServletRequest request;
 
 	private final UserDistributeSharedMapper userDistributeSharedMapper;
 
 	private final UserMapper userMapper;
-
-	/**
-	 * 优惠券领取中心列表
-	 */
-	@GetMapping("/center/list")
-	public Result<Page<CouponActiveView>> couponCenterList(@RequestParam(defaultValue = "1") Long start, @RequestParam(defaultValue = "5") Long limit) {
-		Long userId = StpUserUtil.getLoginIdAsLong();
-		Page<CouponActiveView> page = couponUserMapper.couponCenterList(userId, new Page<>(start, limit));
-		page.getRecords().forEach(data -> {
-			String str = couponSkuMapper.selectGoodsSkuStr(data.getCouponId());
-			data.setGoodsSkuStr(str.replaceAll(",", "/").replaceAll(";", ""));
-			List<CouponSkuView> couponSkus = couponSkuMapper.getGoodsSkuByCouponId(data.getCouponId());
-			try {
-				data.setGoodsSkuIds(Jsons.toJson(couponSkus));
-			} catch (Exception e) {
-
-			}
-		});
-		return GatewayResponse.SUCCESS.newBuilder().toResult(page);
-	}
-
 	/**
 	 * 个人优惠券列表
 	 */
 	@GetMapping("/personal/list")
-	public Result<Page<CouponUserView>> couponPersonalList(@RequestParam(defaultValue = "1") Long start, @RequestParam(defaultValue = "5") Long limit) {
+	public Result<Page<CouponUserView>> couponPersonalList(@RequestParam(defaultValue = "1") Long start, @RequestParam(defaultValue = "5") Long limit, Long couponId) {
+		String lang = request.getHeader("lang");
 		Long userId = StpUserUtil.getLoginIdAsLong();
-		Page<CouponUserView> page = couponUserMapper.couponPersonalList(userId, new Page<>(start, limit));
+		Page<CouponUserView> page = couponUserMapper.couponPersonalList(userId, new Page<>(start, limit), couponId);
 		page.getRecords().forEach(data -> {
-			String str = couponSkuMapper.selectGoodsSkuStr(data.getCouponId());
-			data.setGoodsSkuStr(str.replaceAll(",", "/").replaceAll(";", ""));
+			data.setGoodsSkuStr(couponFontService.setCouponSkuLanguage(data.getCouponId(), lang));
 			List<CouponSkuView> couponSkus = couponSkuMapper.getGoodsSkuByCouponId(data.getCouponId());
 			try {
 				data.setGoodsSkuIds(Jsons.toJson(couponSkus));
 			} catch (Exception e) {
-
 			}
 		});
 		return GatewayResponse.SUCCESS.newBuilder().toResult(page);
@@ -138,65 +113,12 @@ public class CouponFrontController {
 
 	@GetMapping("/available/list")
 	public Result<Page<CouponUserView>> availableCouponList(Long skuId, Long couponId, Boolean isRenew, @RequestParam(defaultValue = "1") Long start, @RequestParam(defaultValue = "5") Long limit) {
+		String lang = request.getHeader("lang");
 		Long userId = StpUserUtil.getLoginIdAsLong();
-		Page<CouponUserView> couponActiveViewList = couponFontService.getAvailableCouponList(skuId, couponId, userId, isRenew, start, limit);
+		Page<CouponUserView> couponActiveViewList = couponFontService.getAvailableCouponList(skuId, couponId, userId, isRenew, start, limit, lang);
 		return GatewayResponse.SUCCESS.newBuilder().toResult(couponActiveViewList);
 	}
 
-	/**
-	 * 推荐优惠券列表
-	 */
-	@GetMapping("/recommend/list")
-	public Result<Page<CouponRecommendView>> getRecommendList(@RequestParam(defaultValue = "1") Long start, @RequestParam(defaultValue = "5") Long limit) {
-		Long userId = StpUserUtil.getLoginIdAsLong();
-		CouponNewUserView couponNewUserView = beanSearcher.searchFirst(CouponNewUserView.class, MapUtils.builder().field(CouponNewUserView::getUserId, userId).op(Operator.Equal).build());
-		Boolean isNewUser = true;
-		if (couponNewUserView != null) {
-			isNewUser = false;
-		}
-		Page<CouponRecommendView> page = couponRecommendMapper.getRecommendCouponViewList(userId, isNewUser, new Page<>(start, limit));
-		page.getRecords().forEach(data -> {
-			if (data.getCouponStatus() == CouponActiveView.CouponStatus.received) {
-				data.setValidStartTime(data.getUserValidStartTime());
-				data.setValidEndTime(data.getUserValidEndTime());
-			}
-			String str = couponSkuMapper.selectGoodsSkuStr(data.getCouponId());
-			data.setGoodsSkuStr(str.replaceAll(",", "/").replaceAll(";", ""));
-			List<CouponSkuView> couponSkus = couponSkuMapper.getGoodsSkuByCouponId(data.getCouponId());
-			try {
-				data.setGoodsSkuIds(Jsons.toJson(couponSkus));
-			} catch (Exception e) {
-
-			}
-		});
-		return GatewayResponse.SUCCESS.newBuilder().toResult(page);
-	}
-
-	/**
-	 * 一键领取推荐优惠券
-	 */
-	@PostMapping("/collect/recommend/whole")
-	@NoSubmit
-	public Result<String> collectWholeRecommendCoupon() {
-		Long userId = StpUserUtil.getLoginIdAsLong();
-		couponFontService.collectWholeRecommendCoupon(userId);
-		return GatewayResponse.SUCCESS.newBuilder().toResult();
-	}
-
-	/**
-	 * 今日推荐优惠券弹窗已弹
-	 */
-	@GetMapping("/get/recommend/appear")
-	public Result<Boolean> recommendIsAppear() {
-		Long userId = StpUserUtil.getLoginIdAsLong();
-		String zero = DateUtil.beginOfDay(DateTime.now()).toString();
-		Object exists = redisService.get(RedisService.key.RECOMMEND_COUPON_DAY.getNameFormat(String.format("%s-%s", zero, userId)));
-		if (exists == null) {
-			redisService.set(RedisService.key.RECOMMEND_COUPON_DAY.getNameFormat(String.format("%s-%s", zero, userId)), userId, RedisService.key.RECOMMEND_COUPON_DAY.getTimeout());
-		}
-		return GatewayResponse.SUCCESS.newBuilder().toResult(exists == null ? false : true);
-	}
-
 	/**
 	 * 领取优惠券
 	 */
@@ -207,31 +129,6 @@ public class CouponFrontController {
 		return GatewayResponse.SUCCESS.newBuilder().toResult();
 	}
 
-	/**
-	 * 领取推荐优惠券
-	 */
-	@PostMapping("/recommend/collect")
-	public Result<String> collectRecommendCoupon(@RequestBody CouponCollectReq couponCollectReq) {
-		Long userId = StpUserUtil.getLoginIdAsLong();
-		couponFontService.collectRecommendCoupon(couponCollectReq, userId);
-		return GatewayResponse.SUCCESS.newBuilder().toResult();
-	}
-
-	/**
-	 * 查询有可以领取的推荐优惠券
-	 */
-	@GetMapping("/recommend/collect/num")
-	public Result<Integer> collectRecommendCouponNum() {
-		Long userId = StpUserUtil.getLoginIdAsLong();
-		CouponNewUserView couponNewUserView = beanSearcher.searchFirst(CouponNewUserView.class, MapUtils.builder().field(CouponNewUserView::getUserId, userId).op(Operator.Equal).build());
-		Boolean isNewUser = true;
-		if (couponNewUserView != null) {
-			isNewUser = false;
-		}
-		Integer num = couponFontService.collectRecommendCouponNum(userId, isNewUser);
-		return GatewayResponse.SUCCESS.newBuilder().toResult(num);
-	}
-
 
 	/**
 	 * 优惠码详情
@@ -245,7 +142,7 @@ public class CouponFrontController {
 		}
 		BigDecimal skuMoney = goodsDonSkuView.getMoney();
 		if (goodsDonSkuView.getType() == 2) {
-			throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("coupon_sku_not_available_error"));
+			throw BusinessRuntimeException.getInstance("");
 		}
 		CouponPopularizeDto dto = couponMapper.checkExCode(exCode);
 		if (dto == null) {
@@ -272,10 +169,10 @@ public class CouponFrontController {
 						throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("coupon_code_new_user_error"));
 					}
 					CouponNewUserView couponNewUserView = beanSearcher.searchFirst(CouponNewUserView.class, MapUtils.builder().field(CouponNewUserView::getUserId, userId).op(Operator.Equal).build());
-					if (couponNewUserView != null) throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("coupon_code_new_user_error"));
+					if (couponNewUserView != null) throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("coupon_code_new_user_error"));;
 				}
 				if (userDistributeShared != null && !userDistributeShared.getSharedId().equals(dto.getUserId())) {
-					throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("coupon_code_popularize_repeat_use_error"));
+					throw BusinessRuntimeException.getInstance("");
 				}
 			}
 		}
@@ -288,13 +185,13 @@ public class CouponFrontController {
 		if (isRenew != null && isRenew) {
 			Coupon.UseScope useScope = dto.getUseScope();
 			if (useScope == Coupon.UseScope.orders) {
-				throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("coupon_code_only_order_error"));
+				throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("coupon_only_order_error"));
 			}
 		}
 		if (isRenew == null || !isRenew) {
 			Coupon.UseScope useScope = dto.getUseScope();
 			if (useScope == Coupon.UseScope.renew) {
-				throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("coupon_code_only_renew_order_error"));
+				throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("coupon_only_renew_error"));
 			}
 		}
 		if (dto.getIsValidTime() && dto.getValidStartTime().after(DateTime.now())) {
@@ -308,12 +205,7 @@ public class CouponFrontController {
 				.eq(CouponSku::getCouponId, dto.getCouponId())
 				.select(CouponSku::getId).last("limit 1"));
 		if (couponSku == null) {
-			throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("coupon_sku_not_available_error"));
-		}
-		if (goodsDonSkuView.getType() == 2) {
-			if (dto.getType() == Coupon.Type.reduce && skuMoney.compareTo(dto.getReduceCondition()) < 0) {
-				throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("coupon_reduce_money_not_available_error"));
-			}
+			throw BusinessRuntimeException.getInstance("");
 		}
 		return GatewayResponse.SUCCESS.newBuilder().toResult(dto);
 	}
@@ -328,40 +220,27 @@ public class CouponFrontController {
 		}
 		List<CouponView> couponViews = beanSearcher.searchAll(CouponView.class, MapUtils.builder()
 				.field(CouponView::getId, couponIds).op(Operator.InList)
-				.orderBy(CouponView ::getId).desc()
+				.orderBy(CouponView::getId).desc()
 				.build());
 		return GatewayResponse.SUCCESS.newBuilder().toResult(couponViews);
 	}
 
-	/**
-	 * 渠道推广用户领取优惠券
-	 */
-	@PostMapping("/channel/popularize/receive")
-	public Result<String> receiveChannelPopularizeCoupon(@RequestBody @Validated ChannelPopularizeCouponReq req) {
+	@GetMapping("/get/coupon/detail/{couponId}")
+	public Result<CouponUserView> getCouponDetailById(@PathVariable Long couponId) {
+		String lang = request.getHeader("lang");
 		long userId = StpUserUtil.getLoginIdAsLong();
-		req.setUserId(userId);
-		couponFontService.receiveChannelPopularizeCoupon(req);
-		return GatewayResponse.SUCCESS.newBuilder().toResult();
-	}
-
-	/**
-	 * 渠道推广一键领取优惠券
-	 */
-	@PostMapping("/channel/popularize/collectAll/{popularizeId}")
-	public Result<String> collectAllChannelCoupons(@PathVariable Long popularizeId) {
-		long userId = StpUserUtil.getLoginIdAsLong();
-		couponFontService.collectAllChannelCoupons(userId, popularizeId);
-		return GatewayResponse.SUCCESS.newBuilder().toResult();
+		CouponUserView couponUserView = couponFontService.getCouponDetailById(userId, couponId, lang);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(couponUserView);
 	}
 
 	/**
-	 * 新用户福利 优惠券详情展示
+	 * 领取优惠券
 	 */
-	@GetMapping("/get/newUser/welfare")
-	public Result<CouponUserView> getNewUserWelfare() {
+	@PostMapping("/receive/coupon/{couponId}")
+	public Result<CouponUserView> receiveCoupon(@PathVariable Long couponId) {
+		String lang = request.getHeader("lang");
 		long userId = StpUserUtil.getLoginIdAsLong();
-		DateTime now = DateTime.now();
-		CouponUserView couponUserView = couponFontService.getNewUserWelfareCoupons(userId, now);
+		CouponUserView couponUserView = couponFontService.receiveCoupon(userId, couponId, lang);
 		return GatewayResponse.SUCCESS.newBuilder().toResult(couponUserView);
 	}
 }

+ 64 - 72
netflix-web/src/main/java/com/cyksj/web/controller/manage/coupon/CouponController.java

@@ -1,5 +1,6 @@
 package com.cyksj.web.controller.manage.coupon;
 
+import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.annotation.Log;
 import com.cyksj.common.constant.Constant;
@@ -15,6 +16,8 @@ import com.cyksj.model.request.CouponClassificationReq;
 import com.cyksj.model.request.CouponDistributeReq;
 import com.cyksj.model.views.*;
 import com.cyksj.service.mange.coupon.CouponCommonService;
+import com.cyksj.service.translations.BackInfoTranslationsFrontService;
+import com.cyksj.service.translations.BackInfoTranslationsService;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.SearchResult;
 import com.ejlchina.searcher.util.MapUtils;
@@ -27,8 +30,11 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
-import javax.validation.constraints.Min;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 import java.util.stream.Collectors;
 
 /*
@@ -60,6 +66,10 @@ public class CouponController {
 
 	private final CouponClassificationMapper couponClassificationMapper;
 
+	private final BackInfoTranslationsService backInfoTranslationsService;
+
+	private final BackInfoTranslationsFrontService backInfoTranslationsFrontService;
+
 	private final OrderDonMapper orderDonMapper;
 
 	private final HttpServletRequest request;
@@ -95,7 +105,12 @@ public class CouponController {
 	@PutMapping
 	@Log(module = "优惠券/编辑优惠券", businessType = BusinessType.PUT, isSaveRequestData = true)
 	public Result<String> putCoupon(@RequestBody @Validated Coupon coupon) throws Exception {
-		couponCommonService.updateCoupon(coupon);
+		String lang = request.getHeader("lang");
+		if (!StrUtil.equals(UserPageLanguage.Language.zh_HK.name(), lang)) {
+			backInfoTranslationsService.saveOrUpdateBackInfoTranslations(BackInfoTranslations.Type.coupon, coupon.getId(), coupon, lang);
+		} else {
+			couponCommonService.updateCoupon(coupon);
+		}
 		return GatewayResponse.SUCCESS.newBuilder().toResult("修改优惠券成功");
 	}
 
@@ -109,15 +124,6 @@ public class CouponController {
 		return GatewayResponse.SUCCESS.newBuilder().toResult("发放优惠券成功");
 	}
 
-	/**
-	 * 优惠券 设置为推荐优惠券
-	 */
-	@PutMapping("/set/hot/{couponId}")
-	@Log(module = "优惠券/推荐优惠券", businessType = BusinessType.POST)
-	public Result<String> setHotCoupon(@PathVariable @Min(value = 1) Long couponId) {
-		couponCommonService.setHotCoupon(couponId);
-		return GatewayResponse.SUCCESS.newBuilder().toResult("推荐优惠券成功");
-	}
 
 	/**
 	 * 优惠券关联固定推广者
@@ -144,7 +150,7 @@ public class CouponController {
 	public Result<SearchResult<CouponDistributePopularizeView>> getRelationList(HttpServletRequest request) {
 		SearchResult<CouponDistributePopularizeView> search = beanSearcher.search(CouponDistributePopularizeView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
 		search.getDataList().forEach(data -> {
-			Integer usedNum = orderDonMapper.selectCouponCodeUserNum(data.getId(), Constant.noOrderAllStatus);
+			Integer usedNum = orderDonMapper.selectCouponCodeUserNum(data.getId(), data.getExCode(), Constant.noOrderAllStatus);
 			data.setUsedNum(usedNum);
 		});
 		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
@@ -164,16 +170,21 @@ public class CouponController {
 	 */
 	@GetMapping
 	public Result<SearchResult<CouponView>> couponList(HttpServletRequest request) {
+		String lang = request.getHeader("lang");
 		SearchResult<CouponView> search = beanSearcher.search(CouponView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
 		search.getDataList().forEach(data -> {
 			data.setRelationNum(couponDistributePopularizeMapper.selectCount(Wrappers.lambdaQuery(CouponDistributePopularize.class).eq(CouponDistributePopularize::getCouponId, data.getId())));
 
-			Integer usedNum = couponUserMapper.selectCount(Wrappers.lambdaQuery(CouponUser.class)
-					.eq(CouponUser::getCouponId, data.getId()).eq(CouponUser::getStatus, CouponUser.Status.used));
+			Map<String, Long> couponUserNumData = couponUserMapper.selectCouponUserNumData(data.getId());
+			Integer usedNum = Integer.parseInt(couponUserNumData.get("usedNum").toString());
 			data.setUsedNum(usedNum);
-
+			Integer receiptNum = Integer.parseInt(couponUserNumData.get("receiptNum").toString());
+			data.setReceiptNum(receiptNum);
 			List<GoodsDonSkuView> skuViewList = couponSkuMapper.selectGoodsSkuViewList(data.getId());
 			data.setSkuViewList(skuViewList);
+			if (!StrUtil.equals(UserPageLanguage.Language.zh_HK.name(), lang)) {
+				backInfoTranslationsFrontService.setCouponLanguage(data, lang);
+			}
 		});
 		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
 	}
@@ -245,62 +256,6 @@ public class CouponController {
 		return GatewayResponse.SUCCESS.newBuilder().toResult("失效发放优惠券成功");
 	}
 
-
-	/**
-	 * 推荐发放列表
-	 */
-	@GetMapping("/recommend/list")
-	public Result<SearchResult<CouponRecommendView>> couponRecommendList(HttpServletRequest request) {
-		SearchResult<CouponRecommendView> search = beanSearcher.search(CouponRecommendView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
-		search.getDataList().forEach(data -> {
-			Integer usedNum = couponUserMapper.selectCount(Wrappers.lambdaQuery(CouponUser.class)
-					.eq(CouponUser::getRecommendId, data.getId()).eq(CouponUser::getStatus, CouponUser.Status.used));
-			Integer receiptNum = couponUserMapper.selectCount(Wrappers.lambdaQuery(CouponUser.class)
-					.eq(CouponUser::getRecommendId, data.getId()));
-			data.setReceiptNum(receiptNum);
-			data.setUsedNum(usedNum);
-
-			List<GoodsDonSkuView> skuViewList = couponSkuMapper.selectGoodsSkuViewList(data.getCouponId());
-			data.setSkuViewList(skuViewList);
-		});
-		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
-	}
-
-	/**
-	 * 推荐优惠券设置/取消推荐
-	 */
-	@PutMapping("/recommend/putStatus/{recommendId}")
-	public Result<String> putRecommendStatusById(@PathVariable Long recommendId) {
-		CouponRecommend couponRecommend = couponRecommendMapper.selectById(recommendId);
-		if (couponRecommend == null || !couponRecommend.getDeleted()) {
-			throw BusinessRuntimeException.getInstance("该推荐优惠券不存在");
-		}
-		couponRecommend.setStatus(!couponRecommend.getStatus());
-		couponRecommendMapper.updateById(couponRecommend);
-		return GatewayResponse.SUCCESS.newBuilder().toResult("操作成功");
-	}
-
-	/**
-	 * 删除推荐优惠券
-	 */
-	@DeleteMapping("/recommend/del/{recommendId}")
-	public Result<String> deleteRecommendById(@PathVariable Long recommendId) {
-		CouponRecommend couponRecommend = couponRecommendMapper.selectById(recommendId);
-		if (couponRecommend == null || !couponRecommend.getDeleted()) {
-			throw BusinessRuntimeException.getInstance("该推荐优惠券不存在");
-		}
-		if (couponRecommend.getStatus()) {
-			throw BusinessRuntimeException.getInstance("取消推荐优惠券,才可删除");
-		}
-		couponRecommendMapper.deleteById(recommendId);
-		Coupon coupon = couponMapper.selectById(couponRecommend.getCouponId());
-		if (coupon != null && coupon.getDeleted()) {
-			coupon.setHotStatus(false);
-			couponMapper.updateById(coupon);
-		}
-		return GatewayResponse.SUCCESS.newBuilder().toResult("删除推荐优惠券成功");
-	}
-
 	/**
 	 * 新增优惠券分类
 	 */
@@ -358,13 +313,19 @@ public class CouponController {
 	 */
 	@PutMapping("/update/classification")
 	public Result<String> updateClassification(@RequestBody @Validated CouponClassification classification) {
+		String lang = request.getHeader("lang");
 		Long classificationId = classification.getId();
 		Assert.notNull(classificationId, "分类id为空");
 		CouponClassification couponClassification = couponClassificationMapper.selectById(classificationId);
 		if (couponClassification == null) {
 			throw BusinessRuntimeException.getInstance("该分类不存在");
 		}
-		couponClassificationMapper.updateById(classification);
+		//多语言设置
+		if (!StrUtil.equals(UserPageLanguage.Language.zh_HK.name(), lang)) {
+			backInfoTranslationsService.saveOrUpdateBackInfoTranslations(BackInfoTranslations.Type.coupon_classification, classification.getId(), classification, lang);
+		} else {
+			couponClassificationMapper.updateById(classification);
+		}
 		return GatewayResponse.SUCCESS.newBuilder().toResult("编辑分类成功");
 	}
 
@@ -385,4 +346,35 @@ public class CouponController {
 		List<CouponClassification> CouponClassifications = beanSearcher.searchAll(CouponClassification.class, MapUtils.flatBuilder(request.getParameterMap()).build());
 		return GatewayResponse.SUCCESS.newBuilder().toResult(CouponClassifications);
 	}
+
+	/**
+	 * 优惠券领取详情
+	 */
+	@GetMapping("/get/receipt/detail/{couponId}")
+	public Result<SearchResult<CouponReceiptDetailView>> getReceiptDetail(@PathVariable Long couponId) {
+		SearchResult<CouponReceiptDetailView> search = beanSearcher.search(CouponReceiptDetailView.class, MapUtils.flatBuilder(request.getParameterMap())
+				.put("cid",String.format("and id = %s", couponId))
+				.build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 优惠券使用详情
+	 */
+	@GetMapping("/get/used/detail/{couponId}")
+	public Result<SearchResult<CouponUsedDetailView>> getUsedDetail(@PathVariable Long couponId) {
+		SearchResult<CouponUsedDetailView> search = beanSearcher.search(CouponUsedDetailView.class, MapUtils.flatBuilder(request.getParameterMap())
+				.put("cid",String.format("and id = %s", couponId))
+				.build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 使用优惠券订单金额
+	 */
+	@GetMapping("/get/used/money/{couponId}")
+	public Result<BigDecimal> getUsedMoney(@PathVariable Long couponId) {
+		BigDecimal money = Optional.ofNullable(orderDonMapper.getCouponUsedMoney(couponId)).orElse(BigDecimal.ZERO);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(money.divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN));
+	}
 }

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

@@ -0,0 +1,922 @@
+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.collection.CollUtil;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.excel.EasyExcel;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.annotation.Log;
+import com.cyksj.common.constant.Constant;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.util.StringUtil;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.BusinessType;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.mapper.GoodsDonMapper;
+import com.cyksj.mapper.GoodsDonSkuMapper;
+import com.cyksj.mapper.OrderDonMapper;
+import com.cyksj.mapper.UserMapper;
+import com.cyksj.mapper.manage.cms.CmsUserMapper;
+import com.cyksj.mapper.manage.coupon.CouponDistributePopularizeMapper;
+import com.cyksj.mapper.manage.distribute.*;
+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.distribute.UserDistributeReturnMoneyDetailService;
+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;
+import com.ejlchina.searcher.param.Operator;
+import com.ejlchina.searcher.util.MapBuilder;
+import com.ejlchina.searcher.util.MapUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+/** admin/分销管理
+ *项目名: netflix
+ *文件名: DistributeController
+ *创建者: JavaZou
+ *创建时间:2022/11/14 12:06
+ */
+@RestController
+@RequestMapping("/manage/distribute")
+@RequiredArgsConstructor
+@Slf4j
+public class DistributeController {
+
+	private final DistributeService distributeService;
+
+	private final UserDistributeMapper userDistributeMapper;
+
+	private final BeanSearcher beanSearcher;
+
+	private final DistributeMoneyApplyMapper distributeMoneyApplyMapper;
+
+	private final DistributePointsExchangeMoneyMapper distributePointsExchangeMoneyMapper;
+
+	private final GoodsDonMapper goodsDonMapper;
+
+	private final UserMapper userMapper;
+
+	private final GoodsDonSkuMapper goodsDonSkuMapper;
+
+	private final StatisticsDataService statisticsDataService;
+
+	private final UserBusinessRateService userBusinessRateService;
+
+	private final UserDistributeBusinessRateMapper userDistributeBusinessRateMapper;
+
+	private final HttpServletRequest request;
+
+	private final CmsUserMapper cmsUserMapper;
+
+	private final UserBusinessDefaultRateConfigMapper defaultRateConfigMapper;
+
+	private final BusinessDistributeDefaultRateConfigMapper businessDefaultRateConfigMapper;
+
+	private final BusinessDistributeDefaultSkuRateConfigMapper businessDistributeDefaultSkuRateConfigMapper;
+
+	private final UserBenefitsService userBenefitsService;
+
+	private final CouponDistributePopularizeMapper couponDistributePopularizeMapper;
+
+	private final SysConfigService sysConfigService;
+
+	private final RedisService redisService;
+
+	private final UserDistributeRuleOrderRecordMapper userDistributeRuleOrderRecordMapper;
+
+	private final UserDistributeBusinessGeneralRateMapper businessGeneralRateMapper;
+
+	private final OrderDonMapper orderDonMapper;
+
+	private final UserDistributeTargetAlertMapper targetAlertMapper;
+
+	private final UserDistributeTargetAlertRecordMapper targetAlertRecordMapper;
+
+	private final UserDistributeSharedWhiteMapper userDistributeSharedWhiteMapper;
+
+	private final UserDistributeReturnMoneyDetailService userDistributeReturnMoneyDetailService;
+	/**
+	 * 添加固定推广者
+	 */
+	@PostMapping
+	@SaCheckPermission("distribute:add")
+	@Log(module = "分销管理/增加推广者", businessType = BusinessType.POST, isSaveRequestData = true)
+	public Result<String> saveDistributes(@RequestBody @NotNull UserDistributeReq userDistributeReq) {
+		try {
+			distributeService.insertDistribute(userDistributeReq);
+			Long businessId = userDistributeReq.getBusinessId();
+			//保存商务人员提成比例
+			userBusinessRateService.saveBusinessRate(businessId);
+			//清除 之前有普通推广专属码
+			couponDistributePopularizeMapper.delete(Wrappers.lambdaQuery(CouponDistributePopularize.class)
+					.eq(CouponDistributePopularize::getUserId, userDistributeReq.getUserId())
+					.eq(CouponDistributePopularize::getIsGeneral, true));
+		} catch (Exception e) {
+			String cacheKey = RedisService.key.USER_DISTRIBUTE_ADD_KEY.getNameFormat(userDistributeReq.getUserId());
+			if (redisService.hasKey(cacheKey)) {
+				redisService.del(cacheKey);
+			}
+			throw BusinessRuntimeException.getInstance(e.getMessage());
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult("添加成功");
+	}
+
+	/**
+	 * 删除固定推广者
+	 */
+	@DeleteMapping("/del/{id}")
+	@SaCheckPermission("distribute:delete")
+	@Log(module = "分销管理/删除推广者", businessType = BusinessType.DELETE, isSaveRequestData = true)
+	public Result<String> deleteDistributesById(@PathVariable Long id) {
+		if (id == null || id < 1) {
+			throw BusinessRuntimeException.getInstance("id不存在");
+		}
+		userDistributeMapper.deleteById(id);
+		//删除对应的优惠码关联
+		couponDistributePopularizeMapper.update(null, Wrappers.lambdaUpdate(CouponDistributePopularize.class)
+				.set(CouponDistributePopularize::getDeleted, 0)
+				.eq(CouponDistributePopularize::getDistributeId, id)
+				.eq(CouponDistributePopularize::getDeleted, 1));
+		return GatewayResponse.SUCCESS.newBuilder().toResult("删除成功");
+	}
+
+	/**
+	 * 推广者编辑
+	 */
+	@PutMapping
+	@SaCheckPermission("distribute:update")
+	@Log(module = "分销管理/编辑推广者", businessType = BusinessType.PUT, isSaveRequestData = true)
+	public Result<String> editDistribute(@RequestBody UserDistributeReq userDistributeReq) {
+		distributeService.editDistribute(userDistributeReq);
+		return GatewayResponse.SUCCESS.newBuilder().toResult("编辑成功");
+	}
+
+	/**
+	 * 固定推广者详情
+	 */
+	@GetMapping("/get/detail/{id}")
+	public Result<UserDistributeRateDetailView> getDetailById(@PathVariable Long id) {
+		UserDistributeRateDetailView rateDetailView = new UserDistributeRateDetailView();
+		List<UserDistributeView> rates = beanSearcher.searchAll(UserDistributeView.class, MapUtils.builder()
+				.put("dis_id", String.format(" and up.distribute_id = %s", id))
+				.orderBy(UserDistributeView::getGoodsId).asc()
+				.build());
+		rateDetailView.setRates(rates);
+		List<UserSkuDistributeView> skuRates = beanSearcher.searchAll(UserSkuDistributeView.class, MapUtils.builder()
+				.put("dis_id", String.format(" and up.distribute_id = %s", id))
+				.orderBy(UserSkuDistributeView::getGoodsId).asc()
+				.build());
+		rateDetailView.setSkuRates(skuRates);
+
+		List<CouponDistributePopularizeDetailView> distributePopularizes = beanSearcher.searchAll(CouponDistributePopularizeDetailView.class, MapUtils.builder()
+				.field(CouponDistributePopularizeDetailView::getDistributeId, id)
+				.build());
+		rateDetailView.setCouponRelates(distributePopularizes);
+
+		List<UserDistributeTargetAlert> targets = targetAlertMapper.selectList(Wrappers.lambdaQuery(UserDistributeTargetAlert.class)
+				.eq(UserDistributeTargetAlert::getDistributeId, id));
+		rateDetailView.setTargets(targets);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(rateDetailView);
+	}
+
+	/**
+	 * 固定渠道平台分销详情 趋势图
+	 */
+	@GetMapping("/get/distribute/plat/brokenLine/{sharedId}")
+	public Result<BrokenLineObjView> getDsPlatBrokenLine(@PathVariable Long sharedId, Long firstDate, Long lastDate) {
+		String first = null;
+		String end = null;
+		if (firstDate != null) {
+			first = DateUtil.format(DateTime.of(firstDate), "yyyy-MM-dd");
+		}
+		if (lastDate != null) {
+			end = DateUtil.format(DateTime.of(lastDate), "yyyy-MM-dd");
+		}
+		BrokenLineObjView brokenLineObjView = Optional.ofNullable(orderDonMapper.selectDsPlatBrokenLineMoney(sharedId, first, end))
+				.orElse(new BrokenLineObjView());
+
+		if (brokenLineObjView != null) {
+			List<DistributePlatOrderDonBrokenLineView> views = beanSearcher.searchAll(DistributePlatOrderDonBrokenLineView.class, MapUtils.flatBuilder(request.getParameterMap())
+					.field(DistributePlatOrderDonBrokenLineView::getDate, first, end).op(Operator.Between)
+					.put("sid", String.format("where shared_id = %s", sharedId))
+					.orderBy(DistributePlatOrderDonBrokenLineView::getDate).asc()
+					.build());
+			Map<Long, List<DistributePlatOrderDonBrokenLineView>> goodsMap = views.stream().collect(Collectors.groupingBy(DistributePlatOrderDonBrokenLineView::getGoodsId));
+			brokenLineObjView.setDsGoodsData(goodsMap);
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult(brokenLineObjView);
+	}
+
+	/**
+	 * 固定推广者列表
+	 */
+	@GetMapping
+	public Result<SearchResult<UserDistributeViews>> distributeList(String nickname, String showId, String startTime, String endTime, Boolean isSpecialEp) {
+		long adminId = StpUtil.getLoginIdAsLong();
+		MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
+		//是否是商务人员
+		if (userBusinessRateService.isBusiness(adminId)) {
+			builder.field(UserDistributeViews::getBusinessId, adminId);
+		}
+		if (StrUtil.isNotBlank(showId)) {
+			builder.field(UserDistributeViews::getUserId, userMapper.getUserIdByShowId(showId));
+		}
+		if (StrUtil.isNotBlank(nickname)) {
+			List<Long> userIds = userMapper.selectListByNickname(nickname);
+			if (CollUtil.isNotEmpty(userIds)) {
+				builder.field(UserDistributeViews::getUserId, userIds).op(Operator.InList);
+			}
+		}
+		String timeSql = StrUtil.EMPTY;
+		if (StrUtil.isNotBlank(startTime)) {
+			timeSql += String.format("and od.created_time >= '%s'", startTime);
+		}
+		if (StrUtil.isNotBlank(endTime)) {
+			timeSql += String.format("and od.created_time < '%s'", endTime);
+		}
+		if (StrUtil.isNotBlank(timeSql)) {
+			builder.put("time", timeSql);
+			//按时间筛选 固定推广人分销情况 倒序
+			builder.orderBy(UserDistributeViews::getDistributeOrdersMoney).desc();
+		}
+		if (isSpecialEp != null) {
+			//是否是特殊设备分销渠道商
+			String condition = String.format(" and %s (select 1 from user_distribute_equipment up where up.distribute_id = ud.id limit 1)", isSpecialEp ? "exists" : "not exists");
+			builder.put("condition", condition);
+		}
+		Map<Long, String> businessNameMap = new ConcurrentHashMap<>();
+		SearchResult<UserDistributeViews> search = beanSearcher.search(UserDistributeViews.class,
+				builder.build());
+		search.getDataList().forEach(view -> {
+			if (view.getDistributeOrdersMoney().compareTo(BigDecimal.ZERO) > 0) {
+				Optional.ofNullable(userDistributeMapper.selectSoldMaxGoods(view.getUserId())).ifPresent(title -> view.setGoodsTitle(title));
+			}
+			String businessName = businessNameMap.get(view.getBusinessId());
+			view.setBusinessName(businessName);
+			if (StrUtil.isEmpty(businessName)) {
+				Optional.ofNullable(cmsUserMapper.selectById(view.getBusinessId()))
+						.ifPresent(cmsUser -> {
+							businessNameMap.putIfAbsent(view.getBusinessId(), cmsUser.getNickname());
+							view.setBusinessName(cmsUser.getNickname());
+						});
+			}
+			Optional.ofNullable(userMapper.selectById(view.getUserId()))
+					.ifPresent(user -> view.setNickname(user.getNickname()));
+		});
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 渠道推广者查询列表
+	 */
+	@GetMapping("/search")
+	public Result<SearchResult<DistributeSearchView>> searchDistribute() {
+		SearchResult<DistributeSearchView> search = beanSearcher.search(DistributeSearchView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 所有固定推广者列表
+	 */
+	@GetMapping("/get/all")
+	public Result<List<UserDistributeVo>> getAllDistributes() {
+		List<UserDistributeVo> userDistributes = beanSearcher.searchAll(UserDistributeVo.class, MapUtils.flatBuilder(request.getParameterMap())
+				.build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(userDistributes);
+	}
+
+	/**
+	 * 获取平台分销比例
+	 */
+	@GetMapping("/get/plat")
+	public Result<List<GoodsDon>> getGoodsDistributeRate() {
+		return GatewayResponse.SUCCESS.newBuilder().toResult(goodsDonMapper.selectList(Wrappers.lambdaQuery(GoodsDon.class).in(GoodsDon::getType, Constant.dsGoodsIds).eq(GoodsDon::getDeleted, true)
+				.eq(GoodsDon::getStatus, true).orderByAsc(GoodsDon::getType)
+				.eq(GoodsDon::getIsDistribute, true)
+				.orderByAsc(GoodsDon::getId)
+				.select(GoodsDon::getId, GoodsDon::getType, GoodsDon::getTitle, GoodsDon::getRate, GoodsDon::getSecondRate)));
+	}
+
+	/**
+	 * 平台开启规格分销
+	 */
+	@GetMapping("/get/sku/rate")
+	public Result<List<GoodsDonSkuRateView>> getSkuRate() {
+		List<GoodsDonSkuRateView> goodsDonSkuRateViews = beanSearcher.searchAll(GoodsDonSkuRateView.class, MapUtils.flatBuilder(request.getParameterMap())
+				.orderBy(GoodsDonSkuRateView::getGoodsId).asc()
+				.build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(goodsDonSkuRateViews);
+	}
+
+	/**
+	 * 设置普通分销平台规格比例
+	 */
+	@PutMapping("/set/common/sku/rate")
+	public Result<String> setDistributeCommonSkuRate(@RequestBody List<DistributeGeneralSkuRate> skuRates) {
+		distributeService.setDistributeCommonSkuRate(skuRates);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 获取推广者分销订单详情
+	 */
+	@GetMapping("/get/distribute/order/detail")
+	public Result<SearchResult<DistributeOrdersDetailView>> getDistributeOrderDetail() {
+		SearchResult<DistributeOrdersDetailView> search = beanSearcher.search(DistributeOrdersDetailView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 新注册分销人数
+	 */
+	@GetMapping("/get/register/distribute/user")
+	public Result<SearchResult<RegisterDistributeOrdersView>> getRegisterDistributeUserDetail() {
+		SearchResult<RegisterDistributeOrdersView> search = beanSearcher.search(RegisterDistributeOrdersView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
+		search.getDataList().forEach(data -> {
+			List<RegisterDistributeOrdersDetailView> ordersDetailViewList = beanSearcher.searchAll(RegisterDistributeOrdersDetailView.class, MapUtils.flatBuilder(request.getParameterMap()).field(RegisterDistributeOrdersDetailView::getUserId, data.getUserId()).op(Operator.Equal).build());
+			data.setOrderNums(ordersDetailViewList.size());
+			Optional<BigDecimal> money = ordersDetailViewList.stream().filter(order -> {
+				if (!Constant.noOrderAllStatus.contains(order.getStatus().name())) {
+					return true;
+				}
+				return false;
+			}).map(RegisterDistributeOrdersDetailView::getMoney).reduce(BigDecimal::add);
+			data.setMoney(money.isPresent() ? money.get() : BigDecimal.ZERO);
+		});
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 获取新注册的分销用户订单数据
+	 */
+	@GetMapping("/get/register/distribute/user/order/detail")
+	public Result<SearchResult<RegisterDistributeOrdersDetailView>> getRegisterDistributeOrderDetail() {
+		SearchResult<RegisterDistributeOrdersDetailView> search = beanSearcher.search(RegisterDistributeOrdersDetailView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
+		search.getDataList().forEach(data -> {
+			User user = userMapper.selectById(data.getUserId());
+			GoodsDonSku sku = goodsDonSkuMapper.selectById(data.getSkuId());
+			data.setNickname(user != null ? user.getNickname() : "");
+			data.setSpecVal(sku != null ? sku.getSpecVal() : "");
+		});
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 平台分销比例修改
+	 */
+	@PutMapping("/put/goods/rate")
+	@Log(module = "分销管理/修改平台分销比例", businessType = BusinessType.PUT, isSaveRequestData = true)
+	public Result<String> editGoodsDistributeRate(@RequestBody UserDistributeReq userDistributeReq) {
+		for (UserPlatDistributeRate rate : userDistributeReq.getRates()) {
+			if (rate.getRate() == null) {
+				rate.setRate(0);
+			}
+			if (rate.getSecondRate() == null) {
+				rate.setSecondRate(0);
+			}
+			if (rate.getRate() < 0 || rate.getRate() > 100) {
+				throw new BusinessRuntimeException("比例错误");
+			}
+			GoodsDon goodsDon = goodsDonMapper.selectById(rate.getGoodsId());
+			if (goodsDon == null || goodsDon.getType() == 3) {
+				throw new BusinessRuntimeException("平台错误");
+			}
+			goodsDon.setRate(rate.getRate());
+			goodsDon.setSecondRate(rate.getSecondRate());
+			goodsDonMapper.updateById(goodsDon);
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult("编辑成功");
+	}
+
+	/**
+	 * 提现title
+	 */
+	@GetMapping("/get/applyMoney/title")
+	public Result<MoneyApplyView> applyMoneyTitle() {
+		MoneyApplyView moneyApplyView = new MoneyApplyView();
+		moneyApplyView.setThreshold(distributePointsExchangeMoneyMapper.selectOne(null));
+		List<DistributeMoneyApply> distributeMoneyApplies = distributeMoneyApplyMapper.selectList(Wrappers.lambdaQuery(DistributeMoneyApply.class).eq(DistributeMoneyApply::getVerifyStatus, DistributeMoneyApply.Status.success).select(DistributeMoneyApply::getMoney));
+		Optional<BigDecimal> reduce = distributeMoneyApplies.stream().map(DistributeMoneyApply::getMoney).reduce(BigDecimal::add);
+		moneyApplyView.setGotMoney(reduce.isPresent() ? reduce.get() : BigDecimal.ZERO);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(moneyApplyView);
+	}
+
+	/**
+	 * 提现列表
+	 */
+	@GetMapping("/get/applyMoney/list")
+	@SaCheckPermission("distribute:applyView")
+	public Result<SearchResult<DistributeMoneyApplyView>> applyMoneyList() {
+		SearchResult<DistributeMoneyApplyView> search = beanSearcher.search(DistributeMoneyApplyView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 提现审核
+	 */
+	@PutMapping("/verify/applyMoney")
+	public Result<String> verifyApplyMoney(@RequestBody @Validated DistributeApplyMoneyReq distributeApplyMoneyReq) {
+		DistributeMoneyApply.Status status = DistributeMoneyApply.Status.checkStatus(distributeApplyMoneyReq.getVerifyStatus());
+		if (status == null || status == DistributeMoneyApply.Status.verifying) {
+			throw BusinessRuntimeException.getInstance("审核状态错误");
+		}
+		DistributeMoneyApply distributeMoneyApply = distributeMoneyApplyMapper.selectById(distributeApplyMoneyReq.getId());
+		if (distributeMoneyApply == null) {
+			throw BusinessRuntimeException.getInstance("提现记录不存在");
+		}
+		if (distributeMoneyApply.getVerifyStatus() != DistributeMoneyApply.Status.verifying) {
+			throw BusinessRuntimeException.getInstance("该提现记录已处理,无法再进行审核");
+		}
+		distributeMoneyApply.setVerifyStatus(status);
+		if (DistributeMoneyApply.Status.fail.name().equals(distributeApplyMoneyReq.getVerifyStatus()) && StrUtil.isEmpty(distributeApplyMoneyReq.getReason())) {
+			throw BusinessRuntimeException.getInstance("拒绝原因为空");
+		}
+		if (DistributeMoneyApply.Status.fail.name().equals(distributeApplyMoneyReq.getVerifyStatus())) {
+			distributeMoneyApply.setReason(distributeApplyMoneyReq.getReason());
+			Long userId = distributeMoneyApply.getUserId();
+			userBenefitsService.addDistributePoints(userId, distributeMoneyApply.getPoints());
+			log.info("归还积分:{}至用户{}结束", distributeMoneyApply.getPoints(), userId);
+			//记录返现明细
+			userDistributeReturnMoneyDetailService.recordDistributeReturnMoney(distributeMoneyApply.getUserId(), distributeMoneyApply.getMoney(), "提现失败");
+		}
+		if (DistributeMoneyApply.Status.success.name().equals(distributeApplyMoneyReq.getVerifyStatus())) {
+//			if (StrUtil.isBlank(distributeApplyMoneyReq.getImg())) {
+//				throw BusinessRuntimeException.getInstance("审核成功时,打款图片不存在");
+//			}
+			distributeMoneyApply.setImg(distributeApplyMoneyReq.getImg());
+		}
+		distributeMoneyApplyMapper.updateById(distributeMoneyApply);
+
+		if (distributeMoneyApply.getVerifyStatus() == DistributeMoneyApply.Status.fail) {
+			String key = String.format(RedisService.key.APPLY_MONEY_DAY_LIMIT_KEY.getName(), DateTime.now().toDateStr(), DistributeMoneyApply.MType.ds.name(), distributeMoneyApply.getUserId());
+			redisService.del(key);
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult("审核操作成功");
+	}
+
+	/**
+	 * 审核成功,编辑打款截图
+	 */
+	@PutMapping("/verify/applyMoney/img")
+	public Result<String> putApplyMoneyImg(@RequestBody @Validated DistributeApplyMoneyReq distributeApplyMoneyReq) {
+		DistributeMoneyApply entity = distributeMoneyApplyMapper.selectById(distributeApplyMoneyReq.getId());
+		if (entity == null || entity.getVerifyStatus() != DistributeMoneyApply.Status.success) {
+			throw BusinessRuntimeException.getInstance("审核记录错误");
+		}
+//		if (StrUtil.isBlank(distributeApplyMoneyReq.getImg())) {
+//			throw BusinessRuntimeException.getInstance("打款截图为空");
+//		}
+		DistributeMoneyApply apply = new DistributeMoneyApply();
+		apply.setImg(distributeApplyMoneyReq.getImg());
+		apply.setId(distributeApplyMoneyReq.getId());
+		distributeMoneyApplyMapper.updateById(apply);
+		return GatewayResponse.SUCCESS.newBuilder().toResult("编辑成功");
+	}
+
+	/**
+	 * 获取分销head
+	 */
+	@GetMapping("/get/headData")
+	public Result<BackgroundDataView> getDistributeHeadData(Long startTime, Long endTime) {
+		BackgroundDataView backgroundDataView = new BackgroundDataView();
+		Date startDate = null;
+		Date endDate = null;
+		if (startTime != null) {
+			startDate = DateUtil.date(startTime);
+		}
+		if (endTime != null) {
+			endDate = DateUtil.date(endTime);
+		}
+		//分销金额数据统计
+		statisticsDataService.distribute(backgroundDataView, startDate, endDate);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(backgroundDataView);
+	}
+
+	/**
+	 * 绑定固定分销者的商务人员详情
+	 */
+	@GetMapping("/get/business/list")
+	public Result<SearchResult<DistributeBusinessView>> getDistributeBusinessView() {
+		long adminId = StpUtil.getLoginIdAsLong();
+		MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
+		DateTime beginOfMonth = DateUtil.beginOfMonth(DateTime.now());
+		String thisMonth = beginOfMonth.toString("yyyy-MM");
+		//是否是商务人员
+		if (userBusinessRateService.isBusiness(adminId)) {
+			builder.field(DistributeBusinessView::getBusinessId, adminId);
+		}
+		builder.put("time", String.format("date_format(ubr.order_created_time,'%%Y-%%m') = '%s'", thisMonth));
+		SearchResult<DistributeBusinessView> search = beanSearcher.search(DistributeBusinessView.class, builder.build());
+		search.getDataList().forEach(data -> {
+			Number numOfRelation = beanSearcher.searchCount(UserDistribute.class, MapUtils.builder().field(UserDistribute::getBusinessId, data.getBusinessId()).field(UserDistribute::getDeleted, true).build());
+			data.setNumOfRelation(numOfRelation.intValue());
+		});
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 商务人员列表
+	 */
+	@GetMapping("/get/businessList")
+	public Result<List<DistributeBusinessListVo>> getBusinessList() {
+		long adminId = StpUtil.getLoginIdAsLong();
+		MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
+		//是否是商务人员
+		if (userBusinessRateService.isBusiness(adminId)) {
+			builder.field(DistributeBusinessListVo::getBusinessId, adminId);
+		}
+		List<DistributeBusinessListVo> list = beanSearcher.searchAll(DistributeBusinessListVo.class, builder.build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(list);
+	}
+
+	/**
+	 * 商务人员提成详情
+	 */
+	@GetMapping("/get/takeMoney/detail")
+	public Result<SearchResult<BusinessTakeMoneyDetail>> getTakeMoneyDetail(String firstMonthDate, String secondMonthDate) {
+		long adminId = StpUtil.getLoginIdAsLong();
+		MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
+		//是否是商务人员
+		if (userBusinessRateService.isBusiness(adminId)) {
+			builder.field(BusinessTakeMoneyDetail::getBusinessId, adminId);
+		}
+		String timeSql = StringUtil.EMPTY;
+		if (StrUtil.isNotBlank(firstMonthDate)) {
+			timeSql += String.format("date_format(ubr.order_created_time,'%%Y-%%m') >= '%s'", firstMonthDate);
+		}
+		if (StrUtil.isNotBlank(secondMonthDate)) {
+			timeSql += String.format("and date_format(ubr.order_created_time,'%%Y-%%m') <= '%s'", secondMonthDate);
+		}
+		if (StrUtil.isNotBlank(timeSql)) {
+			builder.put("time", timeSql);
+		}
+		SearchResult<BusinessTakeMoneyDetail> search = beanSearcher.search(BusinessTakeMoneyDetail.class, builder.build());
+		search.getDataList().forEach(data -> {
+			User user = userMapper.selectById(data.getUserId());
+			Optional.ofNullable(user).ifPresent(u -> {
+				data.setNickname(u.getNickname());
+				data.setCreatedTime(u.getCreatedTime());
+			});
+			CmsUser business = cmsUserMapper.selectById(data.getBusinessId());
+			Optional.ofNullable(business).ifPresent(bs -> data.setBusinessName(bs.getNickname()));
+		});
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 商务提成head
+	 */
+	@GetMapping("/get/business/headData")
+	public Result<BusinessTakeMoneyHeadView> getTakeMoneyHeadDetail(String firstMonthDate, String secondMonthDate) {
+		long adminId = StpUtil.getLoginIdAsLong();
+		MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
+		//是否是商务人员
+		if (userBusinessRateService.isBusiness(adminId)) {
+			builder.field(BusinessTakeMoneyHeadView::getBusinessId, adminId);
+		}
+		String timeSql = StringUtil.EMPTY;
+		if (StrUtil.isNotBlank(firstMonthDate)) {
+			timeSql += String.format("date_format(ubr.order_created_time,'%%Y-%%m') >= '%s'", firstMonthDate);
+		}
+		if (StrUtil.isNotBlank(secondMonthDate)) {
+			timeSql += String.format("and date_format(ubr.order_created_time,'%%Y-%%m') <= '%s'", secondMonthDate);
+		}
+		if (StrUtil.isNotBlank(timeSql)) {
+			builder.put("time", timeSql);
+		}
+		BusinessTakeMoneyHeadView headView = beanSearcher.searchFirst(BusinessTakeMoneyHeadView.class, builder.build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(headView);
+	}
+
+	/**
+	 * 查看商务人员提成比例
+	 */
+	@GetMapping("/get/business/rate")
+	public Result<List<UserDistributeBusinessRateRecordView>> getUserDistributeBusinessRateDetail(Long businessId, Integer type) {
+		if (type == null) type = 1;
+		List<UserDistributeBusinessRateRecordView> userDistributeBusinessRate = beanSearcher.searchAll(UserDistributeBusinessRateRecordView.class, MapUtils.builder()
+				.put("business_id", String.format(" and ur.business_id = %s", businessId))
+				.field(UserDistributeBusinessRateRecordView::getType, type)
+				.orderBy(UserDistributeBusinessRateRecordView::getGoodsId).asc()
+				.orderBy(UserDistributeBusinessRateRecordView::getSkuId).asc()
+				.build());
+		userDistributeBusinessRate.forEach(data -> {
+			data.setBusinessId(businessId);
+		});
+		return GatewayResponse.SUCCESS.newBuilder().toResult(userDistributeBusinessRate);
+	}
+
+	/**
+	 * 修改商务人员提成比例
+	 */
+	@PutMapping("/put/business/rate")
+	@Log(module = "分销管理/修改商务人员比例", businessType = BusinessType.PUT, isSaveRequestData = true)
+	public Result<String> updateBusinessRate(@RequestBody @Validated List<UserDistributeBusinessRate> rates) {
+		List<Long> newDsSkuIds = new ArrayList<>();
+		rates.forEach(userDistributeBusinessRate -> {
+			Long rateId = userDistributeBusinessRate.getId();
+			UserDistributeBusinessRate businessRate = Optional.ofNullable(userDistributeBusinessRateMapper.selectById(rateId)).orElse(new UserDistributeBusinessRate());
+			BeanUtil.copyProperties(userDistributeBusinessRate, businessRate);
+			Number number = beanSearcher.searchCount(GoodsDonSkuView.class, MapUtils.builder()
+					.field(GoodsDonSkuView::getGoodsId, userDistributeBusinessRate.getGoodsId())
+					.field(GoodsDonSkuView::getSkuId, userDistributeBusinessRate.getSkuId())
+					.field(GoodsDonSkuView::getGoodsDonDeleted, true)
+					.build());
+			if (number.intValue() == 0) {
+				userDistributeBusinessRateMapper.delete(Wrappers.lambdaQuery(UserDistributeBusinessRate.class)
+						.eq(UserDistributeBusinessRate::getBusinessId, userDistributeBusinessRate.getBusinessId())
+						.eq(UserDistributeBusinessRate::getGoodsId, userDistributeBusinessRate.getGoodsId())
+						.eq(UserDistributeBusinessRate::getSkuId, userDistributeBusinessRate.getSkuId()));
+				return;
+			}
+			if (businessRate.getId() == null) {
+				try {
+					userDistributeBusinessRateMapper.insert(businessRate);
+
+					newDsSkuIds.add(businessRate.getSkuId());
+				} catch (DuplicateKeyException e) {
+				}
+			} else {
+				userDistributeBusinessRateMapper.updateById(businessRate);
+			}
+		});
+		return GatewayResponse.SUCCESS.newBuilder().toResult("修改比例成功");
+	}
+
+	/**
+	 * 商务默认分配平台比例
+	 */
+	@GetMapping("/get/defaultRateConfig")
+	public Result<List<UserBusinessDefaultRateConfigView>> getDefaultRateConfig() {
+		List<UserBusinessDefaultRateConfigView> search = beanSearcher.searchAll(UserBusinessDefaultRateConfigView.class, MapUtils.flatBuilder(request.getParameterMap()).build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 编辑商务默认平台比例
+	 */
+	@PutMapping("/update/business/defaultRate")
+	public Result<String> updateBusinessDefaultRate(@RequestBody List<UserBusinessDefaultRateConfig> configs) {
+		configs.forEach(rateConfig -> {
+			Long rateConfigId = rateConfig.getId();
+			UserBusinessDefaultRateConfig config = Optional.ofNullable(defaultRateConfigMapper.selectById(rateConfigId)).orElse(new UserBusinessDefaultRateConfig());
+			BeanUtil.copyProperties(rateConfig, config);
+			Number number = beanSearcher.searchCount(GoodsDonSkuView.class, MapUtils.builder()
+					.field(GoodsDonSkuView::getGoodsId, rateConfig.getGoodsId())
+					.field(GoodsDonSkuView::getGoodsDonDeleted, true)
+					.build());
+			if (number.intValue() == 0) {
+				defaultRateConfigMapper.delete(Wrappers.lambdaQuery(UserBusinessDefaultRateConfig.class)
+						.eq(UserBusinessDefaultRateConfig::getGoodsId, rateConfig.getGoodsId()));
+				return;
+			}
+			if (rateConfig.getId() == null) {
+				try {
+					defaultRateConfigMapper.insert(config);
+					return;
+				} catch (DuplicateKeyException e) {
+
+				}
+			}
+			defaultRateConfigMapper.updateById(config);
+		});
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 商务人员推广平台分销比例默认配置列表
+	 */
+	@GetMapping("/get/business/distribute/rate")
+	public Result<BusinessDistributeRateDetailView> getBusinessDistributeRateConfigList() {
+		BusinessDistributeRateDetailView rateDetailView = new BusinessDistributeRateDetailView();
+		List<BusinessDistributeRateView> rates = beanSearcher.searchAll(BusinessDistributeRateView.class,
+				MapUtils.flatBuilder(request.getParameterMap())
+						.build());
+		rateDetailView.setRates(rates);
+		List<BusinessDistributeSkuRateView> skuRates = beanSearcher.searchAll(BusinessDistributeSkuRateView.class,
+				MapUtils.flatBuilder(request.getParameterMap())
+						.build());
+		rateDetailView.setSkuRates(skuRates);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(rateDetailView);
+	}
+
+	/**
+	 * 编辑商务人员推广平台分销比例默认配置列表
+	 */
+	@PutMapping("/put/business/distribute/rate")
+	@Transactional(rollbackFor = Throwable.class)
+	public Result<String> updateBusinessDistributeRate(@RequestBody BusinessDistributeDefaultRateDetailReq req) {
+		List<BusinessDistributeDefaultRateConfig> rates = req.getRates();
+		List<BusinessDistributeDefaultSkuRateConfig> skuRates = req.getSkuRates();
+		List<Long> alertGoodsId = new ArrayList<>();
+		if (CollUtil.isNotEmpty(rates)) {
+			rates.forEach(config -> {
+				Long id = config.getId();
+				Long goodsId = config.getGoodsId();
+				if (config.getRate() == null) {
+					config.setRate(0);
+				}
+				Integer rate = config.getRate();
+				if (goodsId == null) {
+					throw BusinessRuntimeException.getInstance("平台id为空");
+				}
+				if (rate < 0 && rate > 100) {
+					throw BusinessRuntimeException.getInstance("请输入正确的比例");
+				}
+				if (id == null) {
+					try {
+						businessDefaultRateConfigMapper.insert(config);
+						alertGoodsId.add(config.getGoodsId());
+					} catch (DuplicateKeyException e) {
+					}
+				} else {
+					businessDefaultRateConfigMapper.updateById(config);
+				}
+			});
+		}
+
+		//sku规格比例设置
+		if (CollUtil.isNotEmpty(skuRates)) {
+			List<Long> collect = skuRates.stream().map(BusinessDistributeDefaultSkuRateConfig::getSkuId).collect(Collectors.toList());
+			if (CollUtil.isNotEmpty(collect)) {
+				businessDistributeDefaultSkuRateConfigMapper.delete(Wrappers.lambdaQuery(BusinessDistributeDefaultSkuRateConfig.class)
+						.notIn(BusinessDistributeDefaultSkuRateConfig::getSkuId, collect));
+			}
+			skuRates.forEach(config -> {
+				if (config.getRate() == null) {
+					config.setRate(0);
+				}
+				Integer rate = config.getRate();
+				if (rate < 0 && rate > 100) {
+					throw BusinessRuntimeException.getInstance("请输入正确的比例");
+				}
+				if (config.getId() == null) {
+					try {
+						businessDistributeDefaultSkuRateConfigMapper.insert(config);
+						alertGoodsId.add(config.getGoodsId());
+					} catch (DuplicateKeyException e) {
+					}
+				} else {
+					businessDistributeDefaultSkuRateConfigMapper.updateById(config);
+				}
+			});
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 商务人员数据表
+	 */
+	@GetMapping("/get/business/data")
+	@SaCheckPermission("business:dataView")
+	public Result<SearchResult<BusinessDistributesDataView>> getBusinessDistributesData(String startTime, String endTime) {
+		long adminId = StpUtil.getLoginIdAsLong();
+		MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
+		String time1Sql = StrUtil.EMPTY;
+		String time2Sql = StrUtil.EMPTY;
+		String time3Sql = StrUtil.EMPTY;
+		if (StrUtil.isNotBlank(startTime)) {
+			time1Sql += String.format(" and ud.business_bind_time >= '%s'", startTime);
+			time2Sql += String.format(" and us.created_time >= '%s'", startTime);
+			time3Sql += String.format(" and od.created_time >= '%s'", startTime);
+		}
+		if (StrUtil.isNotBlank(endTime)) {
+			time1Sql += String.format(" and ud.business_bind_time < '%s'", endTime);
+			time2Sql += String.format(" and us.created_time < '%s'", endTime);
+			time3Sql += String.format(" and od.created_time < '%s'", endTime);
+		}
+		if (StrUtil.isNotBlank(time1Sql)) {
+			builder.put("time1", time1Sql);
+		}
+		if (StrUtil.isNotBlank(time2Sql)) {
+			builder.put("time2", time2Sql);
+		}
+		if (StrUtil.isNotBlank(time3Sql)) {
+			builder.put("time3", time3Sql);
+		}
+		//是否是商务人员
+		if (userBusinessRateService.isBusiness(adminId)) {
+			builder.field(BusinessDistributesDataView::getBusinessId, adminId);
+		}
+		SearchResult<BusinessDistributesDataView> search = beanSearcher.search(BusinessDistributesDataView.class, builder.build());
+		search.getDataList().forEach(data -> {
+			Optional.ofNullable(cmsUserMapper.selectById(data.getBusinessId()))
+					.ifPresent(cmsUser -> data.setBusinessName(cmsUser.getNickname()));
+
+		});
+//		search.getDataList().forEach(data -> {
+//			Map<String, Object> reMap = orderDonMapper.selectNumOfDistributeOrders(data.getBusinessId(), startTime, endTime, Constant.noOrderAllStatus);
+//			Object num = reMap.get("num");
+//			Object money = reMap.get("money");
+//			data.setNumOfDistributeOrders(Integer.parseInt(num.toString()));
+//			data.setDistributeOrdersMoney(BigDecimal.valueOf(Long.valueOf(money.toString())));
+//			Integer numOfNewUser = userDistributeSharedMapper.countByBusinessId(data.getBusinessId(), startTime, endTime);
+//			data.setNumOfNewUser(numOfNewUser);
+//		});
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 渠道积分提现详情
+	 */
+	@GetMapping("/get/apply/detail/{userId}")
+	public Result<UserDistributeViews> getApplyDetail(@PathVariable Long userId) {
+		UserDistributeViews userDistributeViews = userDistributeMapper.getApplyDetailByUserId(userId);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(userDistributeViews);
+	}
+
+	/**
+	 * 跟进渠道预警
+	 */
+	@PutMapping("/update/target/alert/status/{id}")
+	public Result<String> updateTargetAlertStatus(@PathVariable Long id) {
+		UserDistributeTargetAlertRecord record = targetAlertRecordMapper.selectById(id);
+		if (record != null && !record.getStatus()) {
+			record.setStatus(true);
+			targetAlertRecordMapper.updateById(record);
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 批量待解绑的用户渠道关联关系记录
+	 */
+	@PostMapping("/import/unbind/distribute/shared")
+	public Result<String> unbindUserDistributeShared(MultipartFile file) throws Exception {
+		if (!file.getOriginalFilename().contains(".xls")) {
+			throw BusinessRuntimeException.getInstance("请导入excel文件");
+		}
+		List<Object> userBind = EasyExcel.read(file.getInputStream()).sheet().headRowNumber(0).doReadSync();
+		distributeService.unbindUserDistributeShared(userBind);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 删除渠道用户白名单
+	 */
+	@DeleteMapping("/del/white/{id}")
+	@Log(module = "分销管理/渠道分销/删除渠道白名单", businessType = BusinessType.DELETE, isSaveRequestData = true)
+	public Result<String> delDistributeWhite(@PathVariable Long id) {
+		userDistributeSharedWhiteMapper.deleteById(id);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 用户白名单列表
+	 */
+	@GetMapping("/get/white")
+	public Result<SearchResult<UserDistributeSharedWhite>> getDistributeWhite() {
+		SearchResult<UserDistributeSharedWhite> search = beanSearcher.search(UserDistributeSharedWhite.class, MapUtils.flatBuilder(request.getParameterMap()).build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 普通渠道列表
+	 */
+	@GetMapping("/get/common/distribute")
+	public Result<SearchResult<UserCommonDistributeView>> getCommonDistribute(Long userId, String nickname) {
+		String condition = StrUtil.EMPTY;
+		if (userId != null) {
+			condition += String.format(" and id = %s", userId);
+		}
+		if (StrUtil.isNotEmpty(nickname)) {
+			condition += String.format(" and nickname like '%%%s%%'", nickname);
+		}
+		MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
+		if (StrUtil.isNotEmpty(condition)) {
+			builder.put("condition", condition);
+		}
+		SearchResult<UserCommonDistributeView> search = beanSearcher.search(UserCommonDistributeView.class,
+				builder.build());
+		search.getDataList().forEach(view -> {
+			if (view.getDistributeOrdersMoney().compareTo(BigDecimal.ZERO) > 0) {
+				Optional.ofNullable(userDistributeMapper.selectSoldMaxGoods(view.getUserId())).ifPresent(title -> view.setGoodsTitle(title));
+			}
+		});
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+}

+ 320 - 0
netflix-web/src/main/java/com/cyksj/web/controller/user/DistributePopularizeController.java

@@ -0,0 +1,320 @@
+package com.cyksj.web.controller.user;
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.qrcode.QrCodeUtil;
+import cn.hutool.extra.qrcode.QrConfig;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.EnvCommonService;
+import com.cyksj.common.annotation.NoSubmit;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.i18n.I18nMessageUtil;
+import com.cyksj.common.util.ValidatorUtil;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.mapper.GoodsDonMapper;
+import com.cyksj.mapper.GoodsDonSkuMapper;
+import com.cyksj.mapper.OrderDonMapper;
+import com.cyksj.mapper.UserMapper;
+import com.cyksj.mapper.manage.coupon.CouponDistributePopularizeMapper;
+import com.cyksj.mapper.manage.coupon.CouponMapper;
+import com.cyksj.mapper.manage.distribute.DistributeMoneyApplyMapper;
+import com.cyksj.mapper.manage.distribute.DistributePointsExchangeMoneyMapper;
+import com.cyksj.mapper.manage.distribute.DistributeWaitingSendPointsMapper;
+import com.cyksj.mapper.manage.distribute.UserDistributeMapper;
+import com.cyksj.model.entity.*;
+import com.cyksj.model.request.ApplyMoneyReq;
+import com.cyksj.model.views.*;
+import com.cyksj.service.distribute.DistributeService;
+import com.cyksj.service.pay.TransferFuncService;
+import com.cyksj.service.translations.BackInfoTranslationsFrontService;
+import com.cyksj.service.user.UserService;
+import com.cyksj.web.util.StpUserUtil;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.SearchResult;
+import com.ejlchina.searcher.param.Operator;
+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.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/*
+ *项目名: netflix
+ *文件名: DistributePopularizeController
+ *创建者: JavaZou
+ *创建时间:2022/11/15 13:59
+ * 服务端-》我的分发推广controller
+ */
+@RestController
+@RequestMapping("/distribute/popularize")
+@RequiredArgsConstructor
+public class DistributePopularizeController {
+	private final EnvCommonService envCommonService;
+
+	private final UserMapper userMapper;
+
+	private final UserService userService;
+
+	private final BeanSearcher beanSearcher;
+
+	private final GoodsDonMapper goodsDonMapper;
+
+	private final GoodsDonSkuMapper goodsDonSkuMapper;
+
+	private final DistributePointsExchangeMoneyMapper distributePointsExchangeMoneyMapper;
+
+	private final DistributeMoneyApplyMapper distributeMoneyApplyMapper;
+
+	private final UserDistributeMapper userDistributeMapper;
+
+	private final DistributeWaitingSendPointsMapper distributeWaitingSendPointsMapper;
+
+	private final OrderDonMapper orderDonMapper;
+
+	private final TransferFuncService transferFuncService;
+
+	private final DistributeService distributeService;
+
+	private final CouponDistributePopularizeMapper couponDistributePopularizeMapper;
+
+	private final CouponMapper couponMapper;
+
+	private final BackInfoTranslationsFrontService backInfoTranslationsFrontService;
+
+	/**
+	 * 推广订单明细
+	 */
+	@GetMapping("/orders/detail")
+	public Result<SearchResult<DistributePopularizeOrdersView>> getOrdersView(HttpServletRequest request) {
+		Long userId = StpUserUtil.getLoginIdAsLong();
+		String lang = request.getHeader("lang");
+		SearchResult<DistributePopularizeOrdersView> search = beanSearcher.search(DistributePopularizeOrdersView.class,
+				MapUtils.flatBuilder(request.getParameterMap())
+						.field(DistributePopularizeOrdersView::getSharedId, userId)
+						.build());
+		DistributePointsExchangeMoney distributePointsExchangeMoney = distributePointsExchangeMoneyMapper.selectOne(Wrappers.lambdaQuery(DistributePointsExchangeMoney.class).orderByDesc(DistributePointsExchangeMoney::getPoints).last("limit 1"));
+		BigDecimal points = BigDecimal.valueOf(distributePointsExchangeMoney.getPoints());
+		BigDecimal money = distributePointsExchangeMoney.getMoney();
+		BigDecimal oneHundred = BigDecimal.valueOf(100);
+		search.getDataList().forEach(data -> {
+			GoodsDon goodsDon = goodsDonMapper.selectById(data.getGoodsId());
+			GoodsDonSku goodsDonSku = goodsDonSkuMapper.selectById(data.getSkuId());
+			data.setGoodsTitle(backInfoTranslationsFrontService.setGoodsTitle(data.getGoodsId(), lang));
+			if (goodsDonSku != null) {
+				data.setSpecVal(backInfoTranslationsFrontService.setSpecVal(data.getSkuId(), lang));
+			}
+			data.setWaitGetMoney(data.getPoints().divide(points).multiply(money).divide(oneHundred, 2, RoundingMode.DOWN));
+			//原先奖励
+			data.setOriGetMoney(data.getOriPoints().divide(points).multiply(money).divide(oneHundred, 2, RoundingMode.DOWN));
+		});
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 提现明细
+	 */
+	@GetMapping("/applyMoney/detail")
+	public Result<SearchResult<DistributeMoneyApplyView>> getApplyMoneyView(HttpServletRequest request) {
+		Long userId = StpUserUtil.getLoginIdAsLong();
+		SearchResult<DistributeMoneyApplyView> search = beanSearcher.search(DistributeMoneyApplyView.class,
+				MapUtils.flatBuilder(request.getParameterMap())
+						.field(DistributeMoneyApplyView::getUserId, userId).op(Operator.Equal)
+						.build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 个人推广详情
+	 */
+	@GetMapping("/get/detail")
+	public Result<DistributePopularizeView> getDetail() {
+		Long userId = StpUserUtil.getLoginIdAsLong();
+		User user = userMapper.selectById(userId);
+		if (StrUtil.isEmpty(user.getShowId())) {
+			user.setShowId(userService.getUserShowId(userId));
+		}
+		DistributePopularizeView distributePopularizeView = new DistributePopularizeView();
+		String dsUrl = String.format(envCommonService.DISTRIBUTE_DEFAULT_URL_PREFIX, user.getShowId());
+		distributePopularizeView.setUrl(dsUrl);
+		distributePopularizeView.setUrlCode(QrCodeUtil.generateAsBase64(distributePopularizeView.getUrl(), QrConfig.create(), "png"));
+		distributePopularizeView.setGotPoints(user.getPoints());
+		Integer orders = userDistributeMapper.count(userId);
+		distributePopularizeView.setDistributeOrders(orders);
+		UserDistribute userDistribute = userDistributeMapper.selectOne(Wrappers.lambdaQuery(UserDistribute.class).eq(UserDistribute::getUserId, userId).eq(UserDistribute::getDeleted, 1).select(UserDistribute::getId).last("limit 1"));
+		if (userDistribute != null) {
+			//是否是固定推广者
+			UserDistributeView userDistributeView = beanSearcher.searchFirst(UserDistributeView.class, MapUtils.builder()
+					.put("dis_id", String.format(" and up.distribute_id = %s", userDistribute.getId()))
+					.orderBy(UserDistributeView::getRate).desc()
+					.build());
+			//最高平台比例
+			distributePopularizeView.setHighestRate(userDistributeView.getRate());
+		} else {
+			GoodsDon goodsDon = goodsDonMapper.selectOne(Wrappers.lambdaQuery(GoodsDon.class).eq(GoodsDon::getDeleted, true).eq(GoodsDon::getStatus, true).orderByDesc(GoodsDon::getRate).select(GoodsDon::getRate).last("limit 1"));
+			distributePopularizeView.setIsGeneral(true);
+			distributePopularizeView.setHighestRate(goodsDon.getRate());
+			Optional.ofNullable(couponDistributePopularizeMapper.selectOne(Wrappers.lambdaQuery(CouponDistributePopularize.class)
+					.eq(CouponDistributePopularize::getUserId, userId)
+					.eq(CouponDistributePopularize::getIsGeneral, true)
+					.last("limit 1")))
+					.ifPresent(couponPopularize -> {
+						Coupon coupon = couponMapper.getCouponById(couponPopularize.getCouponId());
+						distributePopularizeView.setGeneralCode(couponPopularize.getExCode());
+						BigDecimal discount = coupon.getDiscount();
+						String discountStr = String.format("%s折", discount.multiply(BigDecimal.valueOf(100)).intValue());
+						distributePopularizeView.setGeneralDiscount(discountStr);
+					});
+		}
+		List<DistributeWaitingSendPoints> distributeWaitingSendPoints = distributeWaitingSendPointsMapper.selectList(Wrappers.lambdaQuery(DistributeWaitingSendPoints.class).eq(DistributeWaitingSendPoints::getSendStatus, DistributeWaitingSendPoints.Status.waiting).eq(DistributeWaitingSendPoints::getSharedId, userId).select(DistributeWaitingSendPoints::getPoints));
+		BigDecimal waitingPoints = BigDecimal.ZERO;
+		if (!distributeWaitingSendPoints.isEmpty()) {
+			Optional<BigDecimal> points = distributeWaitingSendPoints.stream().map(DistributeWaitingSendPoints::getPoints).reduce(BigDecimal::add);
+			if (points.isPresent()) {
+				waitingPoints = points.get();
+			}
+		}
+		distributePopularizeView.setWaitingSendPoints(waitingPoints);
+		if (user.getPoints().compareTo(BigDecimal.ZERO) <= 0 && waitingPoints.compareTo(BigDecimal.ZERO) <= 0) {
+			distributePopularizeView.setGotMoney(BigDecimal.ZERO);
+			distributePopularizeView.setWaitingMoney(BigDecimal.ZERO);
+		}else {
+			DistributePointsExchangeMoney distributePointsExchangeMoney = distributePointsExchangeMoneyMapper.selectOne(Wrappers.lambdaQuery(DistributePointsExchangeMoney.class).orderByDesc(DistributePointsExchangeMoney::getPoints).last("limit 1"));
+			BigDecimal points = BigDecimal.valueOf(distributePointsExchangeMoney.getPoints());
+			BigDecimal money = distributePointsExchangeMoney.getMoney();
+			BigDecimal oneHundred = BigDecimal.valueOf(100);
+			if (user.getPoints().compareTo(BigDecimal.ZERO) >= 0) {
+				distributePopularizeView.setGotMoney(user.getPoints().divide(points).multiply(money).divide(oneHundred));
+			}
+			if (user.getPoints().compareTo(BigDecimal.ZERO) >= 0) {
+				distributePopularizeView.setWaitingMoney(waitingPoints.divide(points).multiply(money).divide(oneHundred, 2, RoundingMode.DOWN));
+			}
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult(distributePopularizeView);
+	}
+
+	/**
+	 * 个人推广用户每日订单情况折线图
+	 */
+	@GetMapping("/get/order/brokenLine")
+	public Result<BrokenLineObjView> getPersonDistributeBrokenLineView(Long firstDate, Long lastDate) {
+		Long userId = StpUserUtil.getLoginIdAsLong();
+		String first = null;
+		String end = null;
+		if (firstDate != null) {
+			first = DateUtil.format(DateTime.of(firstDate), "yyyy-MM-dd");
+		}
+		if (lastDate != null) {
+			end = DateUtil.format(DateTime.of(lastDate), "yyyy-MM-dd");
+		}
+		BrokenLineObjView brokenLineObjView = Optional.ofNullable(orderDonMapper.selectPersonDistributeBrokenLine(userId, first, end))
+				.orElse(new BrokenLineObjView());
+
+		if (brokenLineObjView != null) {
+			List<PersonDistributeBrokenLineView> views = beanSearcher.searchAll(PersonDistributeBrokenLineView.class, MapUtils.builder()
+					.field(PersonDistributeBrokenLineView::getDate, first, end).op(Operator.Between)
+					.put("userId", String.format("dw.shared_id = %s", userId))
+					.orderBy(PersonDistributeBrokenLineView::getDate).asc()
+					.build());
+			Map<Long, List<PersonDistributeBrokenLineView>> distributeMap = views.stream().collect(Collectors.groupingBy(PersonDistributeBrokenLineView::getGoodsId));
+			brokenLineObjView.setDistributeData(distributeMap);
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult(brokenLineObjView);
+	}
+
+
+	/**
+	 * 提现
+	 */
+	@NoSubmit
+	@PostMapping("/post/applyMoney")
+	@Transactional(rollbackFor = Throwable.class)
+	public Result<DistributeMoneyApply> applyMoney(@RequestBody ApplyMoneyReq applyMoneyReq) throws Exception {
+		Long userId = StpUserUtil.getLoginIdAsLong();
+		applyMoneyReq.setUserId(userId);
+		return transferFuncService.distributeApply(applyMoneyReq);
+	}
+
+	/**
+	 * 获取积分兑换门槛
+	 */
+	@GetMapping("/applyMoney/threshold")
+	public Result<DistributePointsExchangeMoney> getThreshold() {
+		return GatewayResponse.SUCCESS.newBuilder().toResult(distributePointsExchangeMoneyMapper.selectOne(Wrappers.lambdaQuery(DistributePointsExchangeMoney.class).last("limit 1")));
+	}
+
+	/**
+	 * 提现缓存数据
+	 */
+	@GetMapping("/get/applyMoney/detail")
+	public Result<DistributeMoneyApply> getLastApplyDetail() {
+		Long userId = StpUserUtil.getLoginIdAsLong();
+		DistributeMoneyApply apply = distributeMoneyApplyMapper.selectOne(Wrappers.lambdaQuery(DistributeMoneyApply.class).eq(DistributeMoneyApply::getUserId, userId).orderByDesc(DistributeMoneyApply::getId).last("limit 1"));
+		return GatewayResponse.SUCCESS.newBuilder().toResult(apply);
+	}
+
+	/**
+	 * 是否是普通分销者
+	 */
+	@GetMapping("/get/isGeneral/distribute")
+	public Result<Boolean> isGeneralDistribute() {
+		Long userId = StpUserUtil.getLoginIdAsLong();
+		UserDistribute userDistribute = userDistributeMapper.selectOne(Wrappers.lambdaQuery(UserDistribute.class)
+				.eq(UserDistribute::getDeleted, 1)
+				.eq(UserDistribute::getUserId, userId));
+		if (userDistribute != null) {
+			return GatewayResponse.SUCCESS.newBuilder().toResult(false);
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult(true);
+	}
+
+	/**
+	 * 普通分销者弹窗
+	 */
+	@GetMapping("/get/general/distribute/detail")
+	public Result<DistributePopularizeView> getGeneralDistributeDetail() {
+		List<GoodsDon> goodsDons = goodsDonMapper.selectList(Wrappers.lambdaQuery(GoodsDon.class).eq(GoodsDon::getDeleted, true).eq(GoodsDon::getStatus, true).eq(GoodsDon::getType, 1).orderByAsc(GoodsDon::getRate).select(GoodsDon::getRate, GoodsDon::getTitle));
+		if (goodsDons.isEmpty()) {
+			return GatewayResponse.SUCCESS.newBuilder().toResult();
+		}
+		DistributePopularizeView distributePopularizeView = new DistributePopularizeView();
+		GoodsDon highestRateGoods = goodsDons.get(goodsDons.size() - 1);
+		distributePopularizeView.setHighestRate(highestRateGoods.getRate());
+		Map<Integer, List<GoodsDon>> rateMap = goodsDons.stream().filter(gd -> !gd.getRate().equals(highestRateGoods.getRate())).collect(Collectors.groupingBy(GoodsDon::getRate));
+		List<DistributeGoodsGeneralRateView> generalDistributes = new ArrayList<>();
+		rateMap.forEach((rate, v) -> {
+			DistributeGoodsGeneralRateView rateView = new DistributeGoodsGeneralRateView();
+			rateView.setRate(rate);
+			String goodsInfo = v.stream().map(GoodsDon::getTitle).collect(Collectors.joining("/"));
+			rateView.setGoodsInfo(goodsInfo);
+			generalDistributes.add(rateView);
+		});
+		generalDistributes.sort(Comparator.comparing(DistributeGoodsGeneralRateView::getRate).reversed());
+		distributePopularizeView.setGeneralDistributes(generalDistributes);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(distributePopularizeView);
+	}
+
+	/**
+	 * 设置普通推广码
+	 * 绑定个人专属码
+	 */
+	@PostMapping("/general/code/{code}")
+	public Result<String> setGeneralCode(@PathVariable("code") String code) {
+		long userId = StpUserUtil.getLoginIdAsLong();
+		if (StrUtil.isBlank(code)) {
+			throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("params_error"));
+		}
+		if (!ValidatorUtil.isEnNum(code) || code.length() > 20) {
+			throw BusinessRuntimeException.getInstance(I18nMessageUtil.getI18nMsg("params_error"));
+		}
+		code = code.trim();
+		distributeService.bindPopularizeCode(userId, code);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+}

+ 3 - 1
netflix-web/src/main/resources/i18n/yhlx_en_US.properties

@@ -125,4 +125,6 @@ name_too_long=Name is too long
 ticket_login_code=Please check whether the login code was sent
 ticket_verify_link_error=No corresponding verification link obtained
 double_verify_code_time_limit=Someone has obtained the account verification code within one minute. Please obtain it later
-obtain_code_error=Exception in obtaining verification code, please contact customer service
+obtain_code_error=Exception in obtaining verification code, please contact customer service
+reaL_name_error=Please enter your real name
+enter_bank_no_error=Please enter the correct bank card number

+ 3 - 1
netflix-web/src/main/resources/i18n/yhlx_ja_JP.properties

@@ -125,4 +125,6 @@ name_too_long=名前が長すぎます
 ticket_login_code=ログインコードが送信されているか確認してください
 ticket_verify_link_error=対応する検証リンクが取得されていません
 double_verify_code_time_limit=1分以内にアカウント認証コードを取得した人がいるので、後で取得してください
-obtain_code_error=認証コード異常を取得するには、カスタマーサービスに連絡してください
+obtain_code_error=認証コード異常を取得するには、カスタマーサービスに連絡してください
+reaL_name_error=実名を入力してください
+enter_bank_no_error=正しいカード番号を入力してください

+ 3 - 1
netflix-web/src/main/resources/i18n/yhlx_ko_KR.properties

@@ -125,4 +125,6 @@ name_too_long=이름이 너무 깁니다
 ticket_login_code=로그인 번호를 보냈는지 확인하세요
 ticket_verify_link_error=유효성 검사 링크가 없습니다.
 double_verify_code_time_limit=1분 내에 이미 이 계정 인증번호를 획득한 사람이 있습니다. 잠시 후에 획득하세요
-obtain_code_error=인증번호 이상 획득, 고객센터에 연락하세요
+obtain_code_error=인증번호 이상 획득, 고객센터에 연락하세요
+reaL_name_error=실제 이름을 입력하십시오.
+enter_bank_no_error=정확한 카드 번호를 입력하세요

+ 3 - 1
netflix-web/src/main/resources/i18n/yhlx_zh_CN.properties

@@ -125,4 +125,6 @@ name_too_long=名称过长
 ticket_login_code=查询失败,请检查是否发送了登陆码
 ticket_verify_link_error=未获取到对应验证链接
 double_verify_code_time_limit=一分钟内已有人获取该账号验证码,请稍后获取
-obtain_code_error=获取验证码异常,请联系客服
+obtain_code_error=获取验证码异常,请联系客服
+reaL_name_error=请输入真实姓名
+enter_bank_no_error=请输入正确的银行卡号

+ 3 - 1
netflix-web/src/main/resources/i18n/yhlx_zh_HK.properties

@@ -125,4 +125,6 @@ name_too_long=名稱過長
 ticket_login_code=查詢失敗,請檢查是否發送了登陸碼
 ticket_verify_link_error=未獲取到對應驗證鏈接
 double_verify_code_time_limit=壹分鐘內已有人獲取該賬號驗證碼,請稍後獲取
-obtain_code_error=獲取驗證碼異常,請聯系客服
+obtain_code_error=獲取驗證碼異常,請聯系客服
+reaL_name_error=請輸入您的真實姓名
+enter_bank_no_error=请输入正确的銀行卡號