浏览代码

Merge branch 'user_mirror_fission'

zoujiajian 1 年之前
父节点
当前提交
8a1dacbaa5
共有 24 个文件被更改,包括 746 次插入64 次删除
  1. 2 0
      netflix-dao/src/main/java/com/cyksj/mapper/GroupsRelationMapper.java
  2. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/fission/UserMirrorFissionInvertRecordMapper.java
  3. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/fission/UserMirrorFissionReceiveRecordMapper.java
  4. 20 0
      netflix-dao/src/main/java/com/cyksj/mapper/fission/UserMirrorFissionRecordMapper.java
  5. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/fission/UserMirrorFissionTicketConfigMapper.java
  6. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/fission/UserMirrorFissionUserMapper.java
  7. 1 1
      netflix-dao/src/main/java/com/cyksj/model/entity/GroupsRelation.java
  8. 20 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserMirrorFissionInvertRecord.java
  9. 27 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserMirrorFissionReceiveRecord.java
  10. 43 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserMirrorFissionRecord.java
  11. 24 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserMirrorFissionTicketConfig.java
  12. 16 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserMirrorFissionUser.java
  13. 6 0
      netflix-dao/src/main/java/com/cyksj/model/request/OrderPayRequest.java
  14. 29 0
      netflix-dao/src/main/java/com/cyksj/model/response/UserMirrorFissionReceiveResp.java
  15. 1 1
      netflix-dao/src/main/java/com/cyksj/model/views/RenewalView.java
  16. 37 0
      netflix-dao/src/main/java/com/cyksj/model/views/UserMirrorFissionReceiveRecordView.java
  17. 4 0
      netflix-dao/src/main/resources/mapper/GroupRelationMapper.xml
  18. 22 0
      netflix-service/src/main/java/com/cyksj/service/fission/UserMirrorFissionFrontService.java
  19. 249 0
      netflix-service/src/main/java/com/cyksj/service/fission/impl/UserMirrorFissionFrontServiceImpl.java
  20. 33 7
      netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java
  21. 9 0
      netflix-service/src/main/java/com/cyksj/service/relation/GroupRelationFrontService.java
  22. 48 0
      netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupRelationFrontServiceImpl.java
  23. 7 55
      netflix-service/src/main/java/com/cyksj/service/ticket/impl/UserReceiveTrialTicketRecordServiceImpl.java
  24. 96 0
      netflix-web/src/main/java/com/cyksj/web/controller/fission/UserMirrorFissionController.java

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

@@ -78,4 +78,6 @@ public interface GroupsRelationMapper extends BaseMapper<GroupsRelation> {
 	GroupsRelation selectRelationByAccountAndNum(@Param("account") String account, @Param("password") String password, @Param("goodsId") Long goodsId, @Param("num") Integer num);
 
 	List<GroupsRelation> selectExtraRelation(@Param("userId") Long userId, @Param("skuId") Long skuId, @Param("relationId") Long relationId);
+
+	void incrExpiryTime(@Param("relationId") Long relationId, @Param("userId") Long userId);
 }

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

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.fission;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.UserMirrorFissionInvertRecord;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserMirrorFissionInvertRecordMapper
+ * 创建者: JavaZou
+ * 创建时间:2024/11/21 18:22
+ */
+public interface UserMirrorFissionInvertRecordMapper extends BaseMapper<UserMirrorFissionInvertRecord> {
+}

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

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.fission;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.UserMirrorFissionReceiveRecord;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserMirrorFissionReceiveRecordMapper
+ * 创建者: JavaZou
+ * 创建时间:2024/11/21 17:48
+ */
+public interface UserMirrorFissionReceiveRecordMapper extends BaseMapper<UserMirrorFissionReceiveRecord> {
+}

+ 20 - 0
netflix-dao/src/main/java/com/cyksj/mapper/fission/UserMirrorFissionRecordMapper.java

@@ -0,0 +1,20 @@
+package com.cyksj.mapper.fission;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.UserMirrorFissionRecord;
+import org.apache.ibatis.annotations.Update;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserMirrorFissionRecordMapper
+ * 创建者: JavaZou
+ * 创建时间:2024/11/21 17:46
+ */
+public interface UserMirrorFissionRecordMapper extends BaseMapper<UserMirrorFissionRecord> {
+
+	@Update("update user_mirror_fission_record set remain_num = remain_num - 1 where id = #{fissionId} and remain_num > 0")
+	Integer updateFissionRemainNum(Long fissionId);
+
+	@Update("update user_mirror_fission_record set remain_num = remain_num + 1 where id = #{fissionId}")
+	void incrFissionRemainNum(Long fissionId);
+}

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

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.fission;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.UserMirrorFissionTicketConfig;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserMirrorFissionTicketConfigMapper
+ * 创建者: JavaZou
+ * 创建时间:2024/11/22 15:41
+ */
+public interface UserMirrorFissionTicketConfigMapper extends BaseMapper<UserMirrorFissionTicketConfig> {
+}

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

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.fission;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.UserMirrorFissionUser;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserMirrorFissionUserMapper
+ * 创建者: JavaZou
+ * 创建时间:2024/11/27 11:46
+ */
+public interface UserMirrorFissionUserMapper extends BaseMapper<UserMirrorFissionUser> {
+}

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

@@ -110,7 +110,7 @@ public class GroupsRelation extends BaseEntity {
     private Integer maxNum;
 
     /**
-     * 车票获取类型 默认1购买,2.体验
+     * 车票获取类型 默认1购买,2.体验,3.镜像裂变
      */
     private Integer aqType;
 

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

@@ -0,0 +1,20 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserMirrorFissionInvertRecord
+ * 创建者: JavaZou
+ * 创建时间:2024/11/21 18:21
+ */
+@Getter
+@Setter
+public class UserMirrorFissionInvertRecord extends BaseEntity{
+	private Long fissionId;
+
+	private Long userId;
+
+	private Long orderId;
+}

+ 27 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/UserMirrorFissionReceiveRecord.java

@@ -0,0 +1,27 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserMirrorFissionReceiveRecord
+ * 创建者: JavaZou
+ * 创建时间:2024/11/21 17:47
+ */
+@Getter
+@Setter
+public class UserMirrorFissionReceiveRecord extends BaseEntity{
+	private Long fissionId;
+
+	private Long userId;
+
+	private Long goodsId;
+
+	/**
+	 * 试用车票规格
+	 */
+	private Long skuId;
+
+	private Long relationId;
+}

+ 43 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/UserMirrorFissionRecord.java

@@ -0,0 +1,43 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserMirrorFissionRecord
+ * 创建者: JavaZou
+ * 创建时间:2024/11/21 17:44
+ */
+@Getter
+@Setter
+public class UserMirrorFissionRecord extends BaseEntity{
+	private Long userId;
+
+	private Long goodsId;
+
+	/**
+	 * 用户裂变车票id
+	 */
+	private Long relationId;
+
+	/**
+	 * 试用车票id
+	 */
+	private Long trialSkuId;
+
+	/**
+	 * 试用车票可用数量
+	 */
+	private Integer num;
+
+	/**
+	 * 试用车票可领取剩余数量
+	 */
+	private Integer remainNum;
+
+	/**
+	 * 唯一标识
+	 */
+	private String code;
+}

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

@@ -0,0 +1,24 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserMirrorFissionTicketConfig
+ * 创建者: JavaZou
+ * 创建时间:2024/11/22 15:40
+ */
+@Getter
+@Setter
+public class UserMirrorFissionTicketConfig extends BaseEntity{
+
+	private Long goodsId;
+
+	private Long trialSkuId;
+
+	/**
+	 * 裂变赠送车票次数
+	 */
+	private Integer num;
+}

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

@@ -0,0 +1,16 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserMirrorFissionUser
+ * 创建者: JavaZou
+ * 创建时间:2024/11/27 11:45
+ */
+@Getter
+@Setter
+public class UserMirrorFissionUser extends BaseEntity{
+	private Long userId;
+}

+ 6 - 0
netflix-dao/src/main/java/com/cyksj/model/request/OrderPayRequest.java

@@ -181,6 +181,12 @@ public class OrderPayRequest {
      */
     private Boolean isTrial;
 
+    /**
+     * 车票获取类型
+     * 默认1购买,2.体验 3.镜像裂变
+     */
+    private Integer aqType;
+
     /**
      * 用户海报记录id
      */

+ 29 - 0
netflix-dao/src/main/java/com/cyksj/model/response/UserMirrorFissionReceiveResp.java

@@ -0,0 +1,29 @@
+package com.cyksj.model.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserMirrorFissionReceiveResp
+ * 创建者: JavaZou
+ * 创建时间:2024/11/25 13:51
+ */
+@Getter
+@Setter
+public class UserMirrorFissionReceiveResp {
+	private Status status;
+
+	@Getter
+	public enum Status{
+		success("领取成功"),
+		purchased("购买过"),
+		claimed("已领取"),
+		completed("领取完");
+		String msg;
+
+		Status(String msg) {
+			this.msg = msg;
+		}
+	}
+}

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

@@ -176,7 +176,7 @@ public class RenewalView {
     private Integer cmt;
 
     /**
-     * 车票获取类型 默认1购买,2.体验
+     * 车票获取类型 默认1购买,2.体验 3.镜像裂变
      */
     @DbField("gr.aq_type")
     private Integer aqType;

+ 37 - 0
netflix-dao/src/main/java/com/cyksj/model/views/UserMirrorFissionReceiveRecordView.java

@@ -0,0 +1,37 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserMirrorFissionReceiveRecordView
+ * 创建者: JavaZou
+ * 创建时间:2024/11/22 16:00
+ */
+@Getter
+@Setter
+@SearchBean(tables = "user_mirror_fission_receive_record umr inner join user u on u.id = umr.user_id" +
+		" inner join user_mirror_fission_record umf on umf.id = umr.fission_id")
+public class UserMirrorFissionReceiveRecordView {
+	@DbField("umf.code")
+	private String code;
+
+	@DbField("umr.user_id")
+	@JsonIgnore
+	private Long userId;
+
+	@DbField("u.nickname")
+	private String nickname;
+
+	@DbField("u.headimgurl")
+	private String headimgurl;
+
+	@DbField("umr.created_time")
+	private Date createdTime;
+}

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

@@ -26,6 +26,10 @@
         </if>
     </update>
 
+    <update id="incrExpiryTime">
+        update groups_relation set expiry_time = DATE_ADD(expiry_time,interval 1 day) where id = #{relationId} and user_id = #{userId}
+    </update>
+
     <select id="getAccountIdsByUserIdOrNickNameOrSubmitAccount" resultType="java.lang.Long">
         select gr.groups_id
         from groups_relation gr,

+ 22 - 0
netflix-service/src/main/java/com/cyksj/service/fission/UserMirrorFissionFrontService.java

@@ -0,0 +1,22 @@
+package com.cyksj.service.fission;
+
+import com.cyksj.model.entity.UserMirrorFissionRecord;
+import com.cyksj.model.response.UserMirrorFissionReceiveResp;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserMirrorFissionFrontService
+ * 创建者: JavaZou
+ * 创建时间:2024/11/21 18:23
+ */
+public interface UserMirrorFissionFrontService {
+	Boolean getPurchasedMirrorStatus(long userId, Long goodsId);
+
+	UserMirrorFissionReceiveResp receiveTrialMirrorTicket(long userId, String code);
+
+	UserMirrorFissionRecord getPresentFissionTicket(long userId);
+
+	UserMirrorFissionRecord recordUserMirrorFission(long userId, Long relationId) throws Exception;
+
+	Boolean getPermitStatus(long userId, Long goodsId) throws Exception;
+}

+ 249 - 0
netflix-service/src/main/java/com/cyksj/service/fission/impl/UserMirrorFissionFrontServiceImpl.java

@@ -0,0 +1,249 @@
+package com.cyksj.service.fission.impl;
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.util.RandomUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.constant.Constant;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.mapper.GoodsDonSkuMapper;
+import com.cyksj.mapper.GroupsMapper;
+import com.cyksj.mapper.GroupsRelationMapper;
+import com.cyksj.mapper.OrderDonMapper;
+import com.cyksj.mapper.fission.UserMirrorFissionReceiveRecordMapper;
+import com.cyksj.mapper.fission.UserMirrorFissionRecordMapper;
+import com.cyksj.mapper.fission.UserMirrorFissionTicketConfigMapper;
+import com.cyksj.mapper.fission.UserMirrorFissionUserMapper;
+import com.cyksj.model.entity.*;
+import com.cyksj.model.response.UserMirrorFissionReceiveResp;
+import com.cyksj.model.views.RenewalView;
+import com.cyksj.service.fission.UserMirrorFissionFrontService;
+import com.cyksj.service.relation.GroupRelationClearService;
+import com.cyksj.service.relation.GroupRelationFrontService;
+import com.cyksj.service.user.UserBindRelationService;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.param.Operator;
+import com.ejlchina.searcher.util.MapUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserMirrorFissionFrontServiceImpl
+ * 创建者: JavaZou
+ * 创建时间:2024/11/21 18:23
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class UserMirrorFissionFrontServiceImpl implements UserMirrorFissionFrontService {
+	private final UserBindRelationService userBindRelationService;
+
+	private final OrderDonMapper orderDonMapper;
+
+	private final UserMirrorFissionRecordMapper userMirrorFissionRecordMapper;
+
+	private final GoodsDonSkuMapper goodsDonSkuMapper;
+
+	private final UserMirrorFissionReceiveRecordMapper userMirrorFissionReceiveRecordMapper;
+
+	private final GroupRelationFrontService groupRelationFrontService;
+
+	private final GroupsRelationMapper groupsRelationMapper;
+
+	private final GroupsMapper groupsMapper;
+
+	private final UserMirrorFissionTicketConfigMapper userMirrorFissionTicketConfigMapper;
+
+	private final UserMirrorFissionUserMapper userMirrorFissionUserMapper;
+
+	private final BeanSearcher beanSearcher;
+
+	private final GroupRelationClearService groupRelationClearService;
+
+	@Override
+	public Boolean getPurchasedMirrorStatus(long userId, Long goodsId) {
+		return hasPaidMirrorTicket(userId, goodsId);
+	}
+
+	@Override
+	@Transactional(rollbackFor = Throwable.class)
+	public UserMirrorFissionReceiveResp receiveTrialMirrorTicket(long userId, String code) {
+		UserMirrorFissionRecord userMirrorFissionRecord = userMirrorFissionRecordMapper.selectOne(Wrappers.lambdaQuery(UserMirrorFissionRecord.class)
+				.eq(UserMirrorFissionRecord::getCode, code)
+				.last("limit 1"));
+		if (userMirrorFissionRecord == null) {
+			throw BusinessRuntimeException.getInstance("活动不存在");
+		}
+		Long fissionId = userMirrorFissionRecord.getId();
+		UserMirrorFissionReceiveResp resp = new UserMirrorFissionReceiveResp();
+		resp.setStatus(UserMirrorFissionReceiveResp.Status.success);
+		if (userMirrorFissionRecord.getRemainNum() == 0) {
+			resp.setStatus(UserMirrorFissionReceiveResp.Status.completed);
+//			throw BusinessRuntimeException.getInstance("很抱歉,您来晚了,体验卡已被领完");
+			return resp;
+		}
+		if (hasPaidMirrorTicket(userId, userMirrorFissionRecord.getGoodsId())) {
+			resp.setStatus(UserMirrorFissionReceiveResp.Status.purchased);
+//			throw BusinessRuntimeException.getInstance("很抱歉,您已购买过GPT镜像车票,无法参加此活动");
+			return resp;
+		}
+		Long trialSkuId = userMirrorFissionRecord.getTrialSkuId();
+		//发送试用镜像车票
+		GoodsDonSku sku = goodsDonSkuMapper.selectById(userMirrorFissionRecord.getTrialSkuId());
+		if (sku == null) {
+			throw BusinessRuntimeException.getInstance("试用车票异常,请联系客服..");
+		}
+		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+		Integer selectCount = userMirrorFissionReceiveRecordMapper.selectCount(Wrappers.lambdaQuery(UserMirrorFissionReceiveRecord.class)
+				.in(UserMirrorFissionReceiveRecord::getUserId, userIdList)
+				.eq(UserMirrorFissionReceiveRecord::getSkuId, trialSkuId));
+		if (selectCount > 0) {
+			resp.setStatus(UserMirrorFissionReceiveResp.Status.claimed);
+//			throw BusinessRuntimeException.getInstance("您已领取该试用车票");
+			return resp;
+		}
+		Integer update = userMirrorFissionRecordMapper.updateFissionRemainNum(fissionId);
+		if (update == 0) {
+			resp.setStatus(UserMirrorFissionReceiveResp.Status.completed);
+//			throw BusinessRuntimeException.getInstance("很抱歉,您来晚了,体验卡已被领完");
+			return resp;
+		}
+		Long relationId = null;
+		try {
+			UserMirrorFissionReceiveRecord receiveRecord = new UserMirrorFissionReceiveRecord();
+			receiveRecord.setUserId(userId);
+			receiveRecord.setGoodsId(sku.getGoodsId());
+			receiveRecord.setSkuId(trialSkuId);
+			receiveRecord.setFissionId(fissionId);
+			//车票id
+			relationId = groupRelationFrontService.getTrialTicketByUserIdAndGoodsId(userId, trialSkuId, 3);
+			receiveRecord.setRelationId(relationId);
+			userMirrorFissionReceiveRecordMapper.insert(receiveRecord);
+			//给裂变活动发起者车票添加时长
+			groupsRelationMapper.incrExpiryTime(userMirrorFissionRecord.getRelationId(), userMirrorFissionRecord.getUserId());
+		} catch (DuplicateKeyException e) {
+			resp.setStatus(UserMirrorFissionReceiveResp.Status.claimed);
+			if (relationId != null) {
+				GroupsRelation relation = groupsRelationMapper.selectById(relationId);
+				if (relation.getUserId().equals(userId)) {
+					groupRelationClearService.clearTicket(relation, UserTicketClearedRecord.Source.manual);
+				}
+			}
+			userMirrorFissionRecordMapper.incrFissionRemainNum(fissionId);
+//			throw BusinessRuntimeException.getInstance("您已领取该试用车票");
+		}
+		return resp;
+	}
+
+	@Override
+	public UserMirrorFissionRecord getPresentFissionTicket(long userId) {
+		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+		UserMirrorFissionRecord userMirrorFissionRecord = userMirrorFissionRecordMapper.selectOne(Wrappers.lambdaQuery(UserMirrorFissionRecord.class)
+				.in(UserMirrorFissionRecord::getUserId, userIdList)
+				.select(UserMirrorFissionRecord::getCode, UserMirrorFissionRecord::getRelationId, UserMirrorFissionRecord::getGoodsId, UserMirrorFissionRecord::getTrialSkuId, UserMirrorFissionRecord::getNum, UserMirrorFissionRecord::getRemainNum)
+				.last("limit 1"));
+		return userMirrorFissionRecord;
+	}
+
+	@Override
+	public UserMirrorFissionRecord recordUserMirrorFission(long userId, Long relationId) throws Exception {
+		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+		GroupsRelation relation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
+				.in(GroupsRelation::getUserId, userIdList)
+				.eq(GroupsRelation::getId, relationId)
+				.gt(GroupsRelation::getExpiryTime, DateTime.now())
+				.last("limit 1"));
+		if (relation == null) {
+			throw BusinessRuntimeException.getInstance("车票不存在");
+		}
+		UserMirrorFissionRecord userMirrorFissionRecord;
+		GroupsTrips groupsTrips = groupsMapper.selectById(relation.getGroupsId());
+		GoodsDonSku sku = goodsDonSkuMapper.selectById(groupsTrips.getSkuId());
+		if (!sku.getIsMirror()) {
+			throw BusinessRuntimeException.getInstance("只支持镜像车票");
+		}
+		Integer count = userMirrorFissionRecordMapper.selectCount(Wrappers.lambdaQuery(UserMirrorFissionRecord.class)
+				.eq(UserMirrorFissionRecord::getGoodsId, sku.getGoodsId())
+				.in(UserMirrorFissionRecord::getUserId, userIdList));
+		if (count > 0) {
+			userMirrorFissionRecord = userMirrorFissionRecordMapper.selectOne(Wrappers.lambdaQuery(UserMirrorFissionRecord.class)
+					.in(UserMirrorFissionRecord::getUserId, userIdList)
+					.eq(UserMirrorFissionRecord::getRelationId, relationId)
+					.eq(UserMirrorFissionRecord::getGoodsId, sku.getGoodsId())
+					.last("limit 1"));
+			return userMirrorFissionRecord;
+		}
+		//特定老用户可进行镜像裂变活动
+		UserMirrorFissionUser userMirrorFissionUser = userMirrorFissionUserMapper.selectOne(Wrappers.lambdaQuery(UserMirrorFissionUser.class).
+				in(UserMirrorFissionUser::getUserId, userIdList)
+				.last("limit 1"));
+		if (userMirrorFissionUser == null) {
+			throw BusinessRuntimeException.getInstance("您不符合该活动要求");
+		}
+		UserMirrorFissionTicketConfig userMirrorFissionTicketConfig = userMirrorFissionTicketConfigMapper.selectOne(Wrappers.lambdaQuery(UserMirrorFissionTicketConfig.class)
+				.eq(UserMirrorFissionTicketConfig::getGoodsId, sku.getGoodsId())
+				.last("limit 1"));
+		if (userMirrorFissionTicketConfig == null) {
+			throw BusinessRuntimeException.getInstance("活动不存在");
+		}
+		try {
+			userMirrorFissionRecord = new UserMirrorFissionRecord();
+			userMirrorFissionRecord.setUserId(relation.getUserId());
+			userMirrorFissionRecord.setRelationId(relationId);
+			userMirrorFissionRecord.setGoodsId(sku.getGoodsId());
+			userMirrorFissionRecord.setNum(userMirrorFissionTicketConfig.getNum());
+			userMirrorFissionRecord.setRemainNum(userMirrorFissionTicketConfig.getNum());
+			userMirrorFissionRecord.setTrialSkuId(userMirrorFissionTicketConfig.getTrialSkuId());
+			userMirrorFissionRecord.setCode(RandomUtil.randomString(6));
+			userMirrorFissionRecordMapper.insert(userMirrorFissionRecord);
+		} catch (DuplicateKeyException e) {
+			userMirrorFissionRecord = userMirrorFissionRecordMapper.selectOne(Wrappers.lambdaQuery(UserMirrorFissionRecord.class)
+					.in(UserMirrorFissionRecord::getUserId, userIdList)
+					.eq(UserMirrorFissionRecord::getRelationId, relationId)
+					.eq(UserMirrorFissionRecord::getGoodsId, sku.getGoodsId())
+					.last("limit 1"));
+		}
+		return userMirrorFissionRecord;
+	}
+
+	@Override
+	public Boolean getPermitStatus(long userId, Long goodsId) throws Exception {
+		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+		//特定老用户可进行镜像裂变活动
+		UserMirrorFissionUser userMirrorFissionUser = userMirrorFissionUserMapper.selectOne(Wrappers.lambdaQuery(UserMirrorFissionUser.class).
+				in(UserMirrorFissionUser::getUserId, userIdList)
+				.last("limit 1"));
+		if (userMirrorFissionUser == null) {
+			return false;
+		}
+		Number count = beanSearcher.searchCount(RenewalView.class, MapUtils.builder()
+				.field(RenewalView::getGoodsId, goodsId)
+				.field(RenewalView::getIsMirror, true)
+				.field(RenewalView::getUserId, userIdList).op(Operator.InList)
+				.field(RenewalView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
+				.build());
+		if (count.intValue() == 0) {
+			return false;
+		}
+		return true;
+	}
+
+
+	public Boolean hasPaidMirrorTicket(long userId, Long goodsId) {
+		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+		Integer count = orderDonMapper.selectCount(Wrappers.lambdaQuery(OrderDon.class)
+				.in(OrderDon::getUserId, userIdList)
+				.notIn(OrderDon::getStatus, Constant.noOrderStatus)
+				//未购买 且不是镜像店铺订单
+				.apply(String.format("sku_id in (select id from goods_don_sku where goods_id = %s and is_mirror) and not exists (select 1 from user_mirror_shop_order_relate ocr where ocr.order_id = order_don.id)", goodsId)));
+		if (count > 0) {
+			return true;
+		}
+		return false;
+	}
+}

+ 33 - 7
netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java

@@ -47,6 +47,8 @@ import com.cyksj.mapper.channel.UserPayEquipmentAvailableBenefitsMapper;
 import com.cyksj.mapper.corp.CorpInteractiveUserOrderRelationMapper;
 import com.cyksj.mapper.corp.CorpUserMapper;
 import com.cyksj.mapper.corp.CorpUserTagMapper;
+import com.cyksj.mapper.fission.UserMirrorFissionInvertRecordMapper;
+import com.cyksj.mapper.fission.UserMirrorFissionReceiveRecordMapper;
 import com.cyksj.mapper.manage.coupon.CouponDistributePopularizeMapper;
 import com.cyksj.mapper.manage.coupon.CouponMapper;
 import com.cyksj.mapper.manage.coupon.CouponSkuMapper;
@@ -350,6 +352,10 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 
 	private final UserMirrorShopDistributeWaitingSendPointsMapper userMirrorShopDistributeWaitingSendPointsMapper;
 
+	private final UserMirrorFissionReceiveRecordMapper userMirrorFissionReceiveRecordMapper;
+
+	private final UserMirrorFissionInvertRecordMapper userMirrorFissionInvertRecordMapper;
+
 	private final List<String> noChekGoodsTemp = List.of("Apple One", "Youtube", "Spotify");
 
 	@Transactional(rollbackFor = Throwable.class)
@@ -730,7 +736,7 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 		//记录补贴订单关联
 		recordOrderDonSubsidyRelate(orderId, payRequest.getSubsidyId());
 		//试用车票跳转记录
-		recordOrderTrialTicketJumpPay(orderId, payRequest.getIsTrial());
+		recordOrderTrialTicketJumpPay(orderId, payRequest.getAqType(), payRequest.getUserId(), payRequest.getSkuId());
 		//记录用户推广海报下单记录
 		recordPosterUserOrder(orderId, payRequest.getRid());
 		//记录用户镜像店铺订单
@@ -3275,7 +3281,8 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 				groupsRelation.setStatus(GroupsRelation.Status.none);
 			}
 			groupsRelation.setYhsId(0l);
-			groupsRelationMapper.updateById(groupsRelation);
+			groupsRelation.setCmt(0);
+			groupsRelation.setAqType(1);
 			orderCommonService.delRelation(groupsRelation);
 		}
 	}
@@ -4322,11 +4329,30 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 	/**
 	 * 试用车票跳转购买正式车票订单记录
 	 */
-	public void recordOrderTrialTicketJumpPay(Long orderId, Boolean isTrial) {
-		if (isTrial != null && isTrial) {
-			UserTrialTicketJumpPayRecord userTrialTicketJumpPayRecord = new UserTrialTicketJumpPayRecord();
-			userTrialTicketJumpPayRecord.setOrderId(orderId);
-			userTrialTicketJumpPayRecordMapper.insert(userTrialTicketJumpPayRecord);
+	public void recordOrderTrialTicketJumpPay(Long orderId, Integer aqType, Long userId, Long skuId) {
+		if (aqType != null) {
+			//普通试用
+			if (aqType == 2) {
+				UserTrialTicketJumpPayRecord userTrialTicketJumpPayRecord = new UserTrialTicketJumpPayRecord();
+				userTrialTicketJumpPayRecord.setOrderId(orderId);
+				userTrialTicketJumpPayRecordMapper.insert(userTrialTicketJumpPayRecord);
+			}
+			//镜像裂变试用
+			if (aqType == 3) {
+				List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+				GoodsDonSku sku = goodsDonSkuMapper.selectById(skuId);
+				UserMirrorFissionReceiveRecord receiveRecord = userMirrorFissionReceiveRecordMapper.selectOne(Wrappers.lambdaQuery(UserMirrorFissionReceiveRecord.class)
+						.in(UserMirrorFissionReceiveRecord::getUserId, userIdList)
+						.eq(UserMirrorFissionReceiveRecord::getGoodsId, sku.getGoodsId())
+						.last("limit 1"));
+				if (receiveRecord != null) {
+					UserMirrorFissionInvertRecord invertRecord = new UserMirrorFissionInvertRecord();
+					invertRecord.setOrderId(orderId);
+					invertRecord.setUserId(receiveRecord.getUserId());
+					invertRecord.setFissionId(receiveRecord.getFissionId());
+					userMirrorFissionInvertRecordMapper.insert(invertRecord);
+				}
+			}
 		}
 	}
 

+ 9 - 0
netflix-service/src/main/java/com/cyksj/service/relation/GroupRelationFrontService.java

@@ -80,4 +80,13 @@ public interface GroupRelationFrontService {
 	Integer getNetflixErrorAccountStatus(long userId, Long relationId);
 
 	List<NetflixUserAccountStatusRecord> getUserNetflixSubmitRecord(long userId);
+
+	/**
+	 * 获取试用车票
+	 *
+	 * @param userId
+	 * @param trialSkuId
+	 * @return
+	 */
+	Long getTrialTicketByUserIdAndGoodsId(Long userId, Long trialSkuId, Integer ticketType);
 }

+ 48 - 0
netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupRelationFrontServiceImpl.java

@@ -1205,6 +1205,54 @@ public class GroupRelationFrontServiceImpl implements GroupRelationFrontService
 		return netflixUseAccountStatusRecords;
 	}
 
+	@Override
+	public Long getTrialTicketByUserIdAndGoodsId(Long userId, Long trialSkuId, Integer ticketType) {
+		Retryer<Long> build = RetryerBuilder.<Long>newBuilder()
+				.retryIfException()
+				//运行时异常重试
+				.retryIfRuntimeException()
+				//false重试
+				.retryIfResult(res -> res == null)
+				//1s 间隔
+				.withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS))
+				//停止策略 : 尝试请求3次
+				.withStopStrategy(StopStrategies.stopAfterAttempt(3)).build();
+		try {
+			return build.call(() -> {
+				//体验规格
+				GroupsTrips groups = groupsMapper.selectCollegeStudentUserGptTicket(trialSkuId);
+				GroupsRelation relation = null;
+				if (groups != null) {
+					relation = groupsRelationMapper.selectRandomOneRelationByGroupsId(groups.getId());
+				}
+				if (relation == null) {
+					//生成空车队
+					GoodsDonSku sku = goodsDonSkuMapper.selectById(trialSkuId);
+					relation = groupsFuncService.createNewGroupsTrips(sku);
+				}
+				DateTime startTime = DateTime.now();
+				DateTime expiryTime = DateUtil.offsetDay(startTime, 1);
+				int update = groupsRelationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
+						.set(GroupsRelation::getUserId, userId)
+						.set(GroupsRelation::getStartTime, startTime)
+						.set(GroupsRelation::getExpiryTime, expiryTime)
+						.set(GroupsRelation::getStatus, GroupsRelation.Status.validity)
+						.set(GroupsRelation::getAqType, ticketType)
+						.eq(GroupsRelation::getId, relation.getId())
+						.eq(GroupsRelation::getUserId, 0));
+				if (update > 0) {
+					groupsMapper.decrAvailableNum(groups.getId());
+					return relation.getId();
+				}
+				log.error("发送用户:{} GPT镜像车票体验失败,进行重试", userId);
+				return null;
+			});
+		} catch (ExecutionException | RetryException e) {
+			log.error("发送用户GPT镜像体验失败:{}", StringUtil.getErrorText(e));
+			return null;
+		}
+	}
+
 	private DistributePosterGoodsDetailView setGoodsPoster(RenewalView ticket, User user, List<Long> userIds) {
 		DistributePosterGoodsDetailView distributePosterGoodsDetailView = beanSearcher.searchFirst(DistributePosterGoodsDetailView.class, MapUtils.flatBuilder(request.getParameterMap())
 				.field(DistributePosterGoodsFrontView::getGoodsId, ticket.getGoodsId()).build());

+ 7 - 55
netflix-service/src/main/java/com/cyksj/service/ticket/impl/UserReceiveTrialTicketRecordServiceImpl.java

@@ -1,25 +1,22 @@
 package com.cyksj.service.ticket.impl;
 
-import cn.hutool.core.date.DateTime;
-import cn.hutool.core.date.DateUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.exception.BusinessRuntimeException;
-import com.cyksj.common.util.StringUtil;
 import com.cyksj.mapper.*;
-import com.cyksj.model.entity.*;
+import com.cyksj.model.entity.GoodsDonSku;
+import com.cyksj.model.entity.MidjourneyUser;
+import com.cyksj.model.entity.UserReceiveTrialTicketRecord;
 import com.cyksj.service.groups.GroupsFuncService;
 import com.cyksj.service.midjourney.MidjourneyAccountService;
+import com.cyksj.service.relation.GroupRelationFrontService;
 import com.cyksj.service.ticket.UserReceiveTrialTicketRecordService;
 import com.cyksj.service.user.UserBindRelationService;
-import com.github.rholder.retry.*;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.dao.DuplicateKeyException;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
 
 /**
  * 项目名: yhlxj
@@ -47,6 +44,8 @@ public class UserReceiveTrialTicketRecordServiceImpl implements UserReceiveTrial
 
 	private final MidjourneyAccountService midjourneyAccountService;
 
+	private final GroupRelationFrontService groupRelationFrontService;
+
 	@Override
 	public void sendTicketAndRecord(Long userId, Long trialSkuId) {
 		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
@@ -76,7 +75,7 @@ public class UserReceiveTrialTicketRecordServiceImpl implements UserReceiveTrial
 
 			userReceiveTrialTicketRecordMapper.insert(userReceiveTrialTicketRecord);
 
-			Long relationId = getTrialTicketByUserIdAndGoodsId(userId, trialSkuId);
+			Long relationId = groupRelationFrontService.getTrialTicketByUserIdAndGoodsId(userId, trialSkuId, 2);
 			userReceiveTrialTicketRecord.setRelationId(relationId);
 			try {
 				//mj user
@@ -104,51 +103,4 @@ public class UserReceiveTrialTicketRecordServiceImpl implements UserReceiveTrial
 				.eq(UserReceiveTrialTicketRecord::getSkuId, trialSkuId));
 		return selectCount > 0 ? true : false;
 	}
-
-	public Long getTrialTicketByUserIdAndGoodsId(Long userId, Long trialSkuId) {
-		Retryer<Long> build = RetryerBuilder.<Long>newBuilder()
-				.retryIfException()
-				//运行时异常重试
-				.retryIfRuntimeException()
-				//false重试
-				.retryIfResult(res -> res == null)
-				//1s 间隔
-				.withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS))
-				//停止策略 : 尝试请求3次
-				.withStopStrategy(StopStrategies.stopAfterAttempt(3)).build();
-		try {
-			return build.call(() -> {
-				//体验规格
-				GroupsTrips groups = groupsMapper.selectCollegeStudentUserGptTicket(trialSkuId);
-				GroupsRelation relation = null;
-				if (groups != null) {
-					relation = groupsRelationMapper.selectRandomOneRelationByGroupsId(groups.getId());
-				}
-				if (relation == null) {
-					//生成空车队
-					GoodsDonSku sku = goodsDonSkuMapper.selectById(trialSkuId);
-					relation = groupsFuncService.createNewGroupsTrips(sku);
-				}
-				DateTime startTime = DateTime.now();
-				DateTime expiryTime = DateUtil.offsetDay(startTime, 1);
-				int update = groupsRelationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
-						.set(GroupsRelation::getUserId, userId)
-						.set(GroupsRelation::getStartTime, startTime)
-						.set(GroupsRelation::getExpiryTime, expiryTime)
-						.set(GroupsRelation::getStatus, GroupsRelation.Status.validity)
-						.set(GroupsRelation::getAqType, 2)
-						.eq(GroupsRelation::getId, relation.getId())
-						.eq(GroupsRelation::getUserId, 0));
-				if (update > 0) {
-					groupsMapper.decrAvailableNum(groups.getId());
-					return relation.getId();
-				}
-				log.error("发送用户:{} GPT镜像车票体验失败,进行重试", userId);
-				return null;
-			});
-		} catch (ExecutionException | RetryException e) {
-			log.error("发送用户GPT镜像体验失败:{}", StringUtil.getErrorText(e));
-			return null;
-		}
-	}
 }

+ 96 - 0
netflix-web/src/main/java/com/cyksj/web/controller/fission/UserMirrorFissionController.java

@@ -0,0 +1,96 @@
+package com.cyksj.web.controller.fission;
+
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.model.entity.UserMirrorFissionRecord;
+import com.cyksj.model.response.UserMirrorFissionReceiveResp;
+import com.cyksj.model.views.UserMirrorFissionReceiveRecordView;
+import com.cyksj.service.fission.UserMirrorFissionFrontService;
+import com.cyksj.web.util.StpUserUtil;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.SearchResult;
+import com.ejlchina.searcher.util.MapUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * server/镜像裂变
+ * 项目名: yhlxj2
+ * 文件名: UserMirrorFissionController
+ * 创建者: JavaZou
+ * 创建时间:2024/11/21 18:10
+ */
+@Slf4j
+@RestController
+@RequestMapping("/applets/mirror/fission")
+@RequiredArgsConstructor
+public class UserMirrorFissionController {
+	private final UserMirrorFissionFrontService userMirrorFissionFrontService;
+
+	private final BeanSearcher beanSearcher;
+
+	private final HttpServletRequest request;
+
+
+	/**
+	 * 是否购买过镜像车票
+	 */
+	@GetMapping("/get/purchased/mirror/status")
+	public Result<Boolean> getPurchasedMirrorStatus(@RequestParam(defaultValue = "18") Long goodsId) {
+		long userId = StpUserUtil.getLoginIdAsLong();
+		Boolean flag = userMirrorFissionFrontService.getPurchasedMirrorStatus(userId, goodsId);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(flag);
+	}
+
+	/**
+	 * 领取镜像试用车票
+	 */
+	@PostMapping("/receive/trial/mirror/ticket/{code}")
+	public Result<String> receiveTrialMirrorTicket(@PathVariable String code) {
+		long userId = StpUserUtil.getLoginIdAsLong();
+		UserMirrorFissionReceiveResp resp = userMirrorFissionFrontService.receiveTrialMirrorTicket(userId, code);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(resp.getStatus().name());
+	}
+
+	/**
+	 * 镜像分裂车票
+	 */
+	@GetMapping("/get/present/ticket")
+	public Result<UserMirrorFissionRecord> getPresentFissionTicket() {
+		long userId = StpUserUtil.getLoginIdAsLong();
+		UserMirrorFissionRecord userMirrorFissionRecord = userMirrorFissionFrontService.getPresentFissionTicket(userId);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(userMirrorFissionRecord);
+	}
+
+	/**
+	 * 镜像分裂车票记录
+	 */
+	@PostMapping("/record/{relationId}")
+	public Result<UserMirrorFissionRecord> recordUserMirrorFission(@PathVariable Long relationId) throws Exception {
+		long userId = StpUserUtil.getLoginIdAsLong();
+		UserMirrorFissionRecord userMirrorFissionRecord = userMirrorFissionFrontService.recordUserMirrorFission(userId, relationId);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(userMirrorFissionRecord);
+	}
+
+	/**
+	 * 镜像分裂车票 赠送记录
+	 */
+	@GetMapping("/get/receive/record/{code}")
+	public Result<SearchResult<UserMirrorFissionReceiveRecordView>> getFissionReceiveRecord(@PathVariable String code) {
+		SearchResult<UserMirrorFissionReceiveRecordView> search = beanSearcher.search(UserMirrorFissionReceiveRecordView.class, MapUtils.flatBuilder(request.getParameterMap()).field(UserMirrorFissionReceiveRecordView::getCode, code).build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	/**
+	 * 是否可进行裂变活动
+	 */
+	@GetMapping("/get/permit/status")
+	public Result<Boolean> getPermitStatus(@RequestParam(defaultValue = "18") Long goodsId) throws Exception {
+		long userId = StpUserUtil.getLoginIdAsLong();
+		Boolean flag = userMirrorFissionFrontService.getPermitStatus(userId, goodsId);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(flag);
+	}
+}