Răsfoiți Sursa

Merge branch 'abroad_coupon_0808' into abroad_pre

# Conflicts:
#	netflix-dao/src/main/java/com/cyksj/mapper/OrderDonMapper.java
#	netflix-dao/src/main/java/com/cyksj/model/entity/OrderDon.java
#	netflix-dao/src/main/resources/mapper/OrderDonMapper.xml
#	netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java
zoujiajian 2 ani în urmă
părinte
comite
3c1cc61cfd
57 a modificat fișierele cu 3520 adăugiri și 25 ștergeri
  1. 5 0
      netflix-common/src/main/java/com/cyksj/common/constant/Constant.java
  2. 2 0
      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. 1 0
      netflix-dao/src/main/java/com/cyksj/mapper/manage/distribute/UserDistributeSharedWhiteMapper.java
  9. 26 5
      netflix-dao/src/main/java/com/cyksj/model/entity/DistributeMoneyApply.java
  10. 37 1
      netflix-dao/src/main/java/com/cyksj/model/entity/DistributeWaitingSendPoints.java
  11. 4 0
      netflix-dao/src/main/java/com/cyksj/model/entity/OrderDon.java
  12. 6 1
      netflix-dao/src/main/java/com/cyksj/model/entity/UserDistribute.java
  13. 22 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserDistributeReturnMoneyDetail.java
  14. 8 1
      netflix-dao/src/main/java/com/cyksj/model/entity/UserDistributeShared.java
  15. 24 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserDistributeSharedRelateUnbind.java
  16. 1 1
      netflix-dao/src/main/java/com/cyksj/model/entity/UserDistributeSharedWhite.java
  17. 13 1
      netflix-dao/src/main/java/com/cyksj/model/request/ApplyMoneyReq.java
  18. 5 1
      netflix-dao/src/main/java/com/cyksj/model/request/TransferAccountsReq.java
  19. 22 2
      netflix-dao/src/main/java/com/cyksj/model/request/UserDistributeReq.java
  20. 3 1
      netflix-dao/src/main/java/com/cyksj/model/views/BrokenLineObjView.java
  21. 22 0
      netflix-dao/src/main/java/com/cyksj/model/views/BusinessDistributeDefaultRateDetailReq.java
  22. 23 0
      netflix-dao/src/main/java/com/cyksj/model/views/BusinessDistributeRateDetailView.java
  23. 45 0
      netflix-dao/src/main/java/com/cyksj/model/views/BusinessDistributeSkuRateView.java
  24. 50 0
      netflix-dao/src/main/java/com/cyksj/model/views/CouponDistributePopularizeDetailView.java
  25. 18 0
      netflix-dao/src/main/java/com/cyksj/model/views/DistributeGoodsGeneralRateView.java
  26. 42 0
      netflix-dao/src/main/java/com/cyksj/model/views/DistributePlatOrderDonBrokenLineView.java
  27. 15 3
      netflix-dao/src/main/java/com/cyksj/model/views/DistributePopularizeOrdersView.java
  28. 1 1
      netflix-dao/src/main/java/com/cyksj/model/views/DistributePopularizeView.java
  29. 27 0
      netflix-dao/src/main/java/com/cyksj/model/views/DistributeSearchView.java
  30. 40 0
      netflix-dao/src/main/java/com/cyksj/model/views/GoodsDonSkuRateView.java
  31. 65 0
      netflix-dao/src/main/java/com/cyksj/model/views/UserCommonDistributeView.java
  32. 31 0
      netflix-dao/src/main/java/com/cyksj/model/views/UserDistributeRateDetailView.java
  33. 44 0
      netflix-dao/src/main/java/com/cyksj/model/views/UserSkuDistributeView.java
  34. 18 0
      netflix-dao/src/main/resources/mapper/OrderDonMapper.xml
  35. 13 0
      netflix-dao/src/main/resources/mapper/UserDistributeSharedRelateUnbindMapper.xml
  36. 2 0
      netflix-service/src/main/java/com/cyksj/redis/RedisService.java
  37. 13 0
      netflix-service/src/main/java/com/cyksj/service/distribute/DistributeExtraRebateService.java
  38. 35 0
      netflix-service/src/main/java/com/cyksj/service/distribute/DistributeService.java
  39. 19 0
      netflix-service/src/main/java/com/cyksj/service/distribute/UserBusinessFrontService.java
  40. 14 0
      netflix-service/src/main/java/com/cyksj/service/distribute/UserDistributeReturnMoneyDetailService.java
  41. 76 0
      netflix-service/src/main/java/com/cyksj/service/distribute/impl/DistributeExtraRebateServiceImpl.java
  42. 523 0
      netflix-service/src/main/java/com/cyksj/service/distribute/impl/DistributeServiceImpl.java
  43. 227 0
      netflix-service/src/main/java/com/cyksj/service/distribute/impl/UserBusinessFrontServiceImpl.java
  44. 31 0
      netflix-service/src/main/java/com/cyksj/service/distribute/impl/UserDistributeReturnMoneyDetailServiceImpl.java
  45. 18 0
      netflix-service/src/main/java/com/cyksj/service/mange/business/UserBusinessRateService.java
  46. 85 0
      netflix-service/src/main/java/com/cyksj/service/mange/business/impl/UserBusinessRateServiceImpl.java
  47. 318 2
      netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java
  48. 18 0
      netflix-service/src/main/java/com/cyksj/service/pay/TransferFuncService.java
  49. 185 0
      netflix-service/src/main/java/com/cyksj/service/pay/impl/TransferFuncServiceImpl.java
  50. 7 0
      netflix-service/src/main/java/com/cyksj/service/user/impl/UserServiceImpl.java
  51. 922 0
      netflix-web/src/main/java/com/cyksj/web/controller/manage/distribute/DistributeController.java
  52. 320 0
      netflix-web/src/main/java/com/cyksj/web/controller/user/DistributePopularizeController.java
  53. 3 1
      netflix-web/src/main/resources/i18n/yhlx_en_US.properties
  54. 3 1
      netflix-web/src/main/resources/i18n/yhlx_ja_JP.properties
  55. 3 1
      netflix-web/src/main/resources/i18n/yhlx_ko_KR.properties
  56. 3 1
      netflix-web/src/main/resources/i18n/yhlx_zh_CN.properties
  57. 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;
 }

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

@@ -51,4 +51,6 @@ public interface OrderDonMapper extends BaseMapper<OrderDon> {
 	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);
 }

+ 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

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

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

@@ -64,6 +64,10 @@ public class OrderDon extends BaseEntity implements Serializable {
      */
     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;
+}

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

+ 18 - 0
netflix-dao/src/main/resources/mapper/OrderDonMapper.xml

@@ -196,4 +196,22 @@
         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;

+ 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));
+	}
+}

+ 318 - 2
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,6 +313,9 @@ 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());
@@ -1242,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));
+			}
+		});
+
 	}
 
 	/**
@@ -1348,4 +1384,284 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		//存在余额
 //		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"));
+	}
+}

+ 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();

+ 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=请输入正确的銀行卡號