Переглянути джерело

用户端奈飞恢复接口,奈飞替换接口

zoujiajian 1 рік тому
батько
коміт
c0f6f8ebca

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

@@ -611,4 +611,9 @@ public interface Constant {
 	 * 提现默认支付宝
 	 */
 	String TAKE_MONEY_DEFAULT_ZFB = "take_money_default_zfb";
+
+	/**
+	 * 异常奈飞车票更换其他规格key
+	 */
+	String ERROR_NETFLIX_CHANGE_OTHER_SKU_KEY = "error_netflix_change_other_sku_key";
 }

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

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.NetflixUserAccountSubmitRecoverRecord;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: NetflixUserAccountSubmitRecoverRecordMapper
+ * 创建者: JavaZou
+ * 创建时间:2025/6/24 10:18
+ */
+public interface NetflixUserAccountSubmitRecoverRecordMapper extends BaseMapper<NetflixUserAccountSubmitRecoverRecord> {
+}

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

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.NetflixUserChangeOtherTicketRecord;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: NetflixUserChangeOtherTicketRecordMapper
+ * 创建者: JavaZou
+ * 创建时间:2025/6/24 10:24
+ */
+public interface NetflixUserChangeOtherTicketRecordMapper extends BaseMapper<NetflixUserChangeOtherTicketRecord> {
+}

+ 20 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/ErrorNetflixChangeOtherSkuTicketDto.java

@@ -0,0 +1,20 @@
+package com.cyksj.model.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: ErrorNetflixChangeOtherSkuTicketDto
+ * 创建者: JavaZou
+ * 创建时间:2025/6/24 11:06
+ */
+@Getter
+@Setter
+public class ErrorNetflixChangeOtherSkuTicketDto {
+	private Long remainDays;
+
+	private List<Long> skuIds;
+}

+ 18 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/TicketChangeDto.java

@@ -0,0 +1,18 @@
+package com.cyksj.model.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: TicketChangeDto
+ * 创建者: JavaZou
+ * 创建时间:2025/6/24 11:01
+ */
+@Getter
+@Setter
+public class TicketChangeDto {
+	private Long otherRelationId;
+
+	private Long otherOrderId;
+}

+ 29 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/NetflixUserAccountSubmitRecoverRecord.java

@@ -0,0 +1,29 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: NetflixUserAccountSubmitRecoverRecord
+ * 创建者: JavaZou
+ * 创建时间:2025/6/24 10:17
+ */
+@Getter
+@Setter
+public class NetflixUserAccountSubmitRecoverRecord extends BaseEntity{
+	private Long userId;
+
+	private Long relationId;
+
+	private Long skuId;
+
+	private String account;
+
+	private Long remainDays;
+
+	/**
+	 * 0未更换 1.替换成功 2.车票失效
+	 */
+	private Integer status;
+}

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

@@ -0,0 +1,27 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: NetflixUserChangeOtherTicketReocrd
+ * 创建者: JavaZou
+ * 创建时间:2025/6/24 10:22
+ */
+@Getter
+@Setter
+public class NetflixUserChangeOtherTicketRecord extends BaseEntity{
+	private Long userId;
+
+	private Long orderId;
+
+	private Long relationId;
+
+	private Long relateOrderId;
+
+	/**
+	 * 其他车票id
+	 */
+	private Long otherRelationId;
+}

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

@@ -344,7 +344,8 @@ public class OrderDon extends BaseEntity implements Serializable {
         PAY_EQUIPMENT("pay_equipment", "自购设备"),
         BALANCE("balance", "余额支付"),
         PAYPAL("paypal","paypal支付"),
-        STRIPE("stripe","stripe支付")
+        STRIPE("stripe","stripe支付"),
+        TICKET_REPLACE("ticket_replace", "车票替换"),
         ;
         String type;
         String desc;

+ 23 - 0
netflix-dao/src/main/java/com/cyksj/model/request/ErrorNetflixChangeReq.java

@@ -0,0 +1,23 @@
+package com.cyksj.model.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: ErrorNetflixChangeReq
+ * 创建者: JavaZou
+ * 创建时间:2025/6/24 10:37
+ */
+@Getter
+@Setter
+public class ErrorNetflixChangeReq {
+	private Long relationId;
+
+	private Long userId;
+
+	/**
+	 * 更换规格
+	 */
+	private Long skuId;
+}

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

@@ -0,0 +1,34 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: GoodsCategorySkuView
+ * 创建者: JavaZou
+ * 创建时间:2025/6/24 11:37
+ */
+@Getter
+@Setter
+@SearchBean(tables = "goods_don_category gc left join goods_don_category_relate gcr on gcr.category = gc.id" +
+		" left join goods_don g on g.id = gcr.goods_id and g.deleted is true" +
+		" left join goods_don_sku sku on sku.goods_id = g.id")
+public class GoodsCategorySkuView {
+	@DbField("gc.name")
+	private String categoryName;
+
+	@DbField("g.id")
+	private Long goodsId;
+
+	@DbField("g.title")
+	private String title;
+
+	@DbField("sku.id")
+	private Long skuId;
+
+	@DbField("sku.spec_val")
+	private String specVal;
+}

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

@@ -5,8 +5,10 @@ import com.cyksj.model.entity.GoodsDonSku;
 import com.cyksj.model.entity.GroupsRelation;
 import com.cyksj.model.entity.NetflixUserAccountStatusRecord;
 import com.cyksj.model.manage.views.AccountView;
+import com.cyksj.model.request.ErrorNetflixChangeReq;
 import com.cyksj.model.request.SpecialGoodsTicketReq;
 import com.cyksj.model.request.TicketLoginReq;
+import com.cyksj.model.views.GoodsCategorySkuView;
 import com.cyksj.model.views.RenewalView;
 import com.cyksj.model.views.UserRecommendGoodsFrontView;
 import com.ejlchina.searcher.SearchResult;
@@ -98,4 +100,9 @@ public interface GroupRelationFrontService {
 	Long getTicket(Long userId, Long skuId, Boolean isVip);
 
 	Boolean getVipMirrorTicketIfEmpty(long userId, Long skuId);
+	void netflixSubmitRecover(ErrorNetflixChangeReq req);
+
+	void errorNetflixSubmitChangeOtherTicket(ErrorNetflixChangeReq req) throws Exception;
+
+	List<GoodsCategorySkuView> getNetflixReplaceOtherSkus(long userId, Long relationId) throws Exception;
 }

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

@@ -13,6 +13,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.cyksj.common.constant.Constant;
 import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.snowflake.Sequence;
 import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
 import com.cyksj.common.util.Jsons;
 import com.cyksj.common.util.StringUtil;
@@ -28,9 +29,12 @@ import com.cyksj.mapper.sys.SysConfigMapper;
 import com.cyksj.mapper.sys.SysEmailMapper;
 import com.cyksj.mapper.vip.VipGoodsSkuMapper;
 import com.cyksj.mapper.vip.VipUserMapper;
+import com.cyksj.model.dto.ErrorNetflixChangeOtherSkuTicketDto;
+import com.cyksj.model.dto.TicketChangeDto;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.manage.views.AccountView;
 import com.cyksj.model.manage.views.GroupsRelationView;
+import com.cyksj.model.request.ErrorNetflixChangeReq;
 import com.cyksj.model.request.SpecialGoodsTicketReq;
 import com.cyksj.model.request.TicketLoginReq;
 import com.cyksj.model.views.*;
@@ -57,6 +61,7 @@ import com.ejlchina.searcher.util.MapUtils;
 import com.github.rholder.retry.*;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -178,6 +183,12 @@ public class GroupRelationFrontServiceImpl implements GroupRelationFrontService
 
 	private final VipGoodsSkuMapper vipGoodsSkuMapper;
 
+	private static final Sequence SEQUENCE = new Sequence(0);
+
+	private final NetflixUserChangeOtherTicketRecordMapper netflixUserChangeOtherTicketRecordMapper;
+
+	private final NetflixUserAccountSubmitRecoverRecordMapper netflixUserAccountSubmitRecoverRecordMapper;
+
 	@Override
 	public SearchResult<RenewalView> getMyTicket(long userId, Boolean isLoginPopularize, String customId, String account, String orderNo, Integer cmt) {
 		User u = userMapper.selectById(userId);
@@ -1406,6 +1417,97 @@ public class GroupRelationFrontServiceImpl implements GroupRelationFrontService
 		return false;
 	}
 
+	@Override
+	public void netflixSubmitRecover(ErrorNetflixChangeReq req) {
+		Long relationId = req.getRelationId();
+		Long userId = req.getUserId();
+		//校验奈飞账号状态
+		GroupsRelationView netflixRelationView = checkNetflixErrorStatus(relationId, userId);
+		Date expiryTime = netflixRelationView.getExpiryTime();
+		NetflixUserAccountSubmitRecoverRecord recoverRecord = new NetflixUserAccountSubmitRecoverRecord();
+		recoverRecord.setRelationId(relationId);
+		recoverRecord.setUserId(netflixRelationView.getUserId());
+		recoverRecord.setSkuId(netflixRelationView.getSkuId());
+		recoverRecord.setAccount(netflixRelationView.getAccount());
+		Long betweenDay = DateUtil.betweenDay(DateTime.now(), expiryTime, false) + 1;
+		recoverRecord.setRemainDays(betweenDay);
+		try {
+			netflixUserAccountSubmitRecoverRecordMapper.insert(recoverRecord);
+		} catch (DuplicateKeyException e) {
+			throw BusinessRuntimeException.getInstance("您已申请恢复");
+		}
+	}
+
+	@Override
+	public void errorNetflixSubmitChangeOtherTicket(ErrorNetflixChangeReq req) throws Exception {
+		Long relationId = req.getRelationId();
+		Long userId = req.getUserId();
+		//校验奈飞账号状态
+		GroupsRelationView netflixRelationView = checkNetflixErrorStatus(relationId, userId);
+		Date expiryTime = netflixRelationView.getExpiryTime();
+		//小于15 不可替换其他车票
+		Long betweenDay = DateUtil.betweenDay(DateTime.now(), expiryTime, false) + 1;
+		if (betweenDay <= 15) {
+			throw BusinessRuntimeException.getInstance("您的车票有效期未超过15天");
+		}
+		Long skuId = req.getSkuId();
+		SysConfig sysConfig = sysConfigMapper.selectOne(Wrappers.lambdaQuery(SysConfig.class)
+				.eq(SysConfig::getSysKey, Constant.ERROR_NETFLIX_CHANGE_OTHER_SKU_KEY)
+				.last("limit 1"));
+		List<ErrorNetflixChangeOtherSkuTicketDto> errorNetflixChangeOtherSkuTicketDtos = Jsons.parseList(sysConfig.getSysValue(), ErrorNetflixChangeOtherSkuTicketDto.class);
+		ErrorNetflixChangeOtherSkuTicketDto errorNetflixChangeOtherSkuTicketDto;
+		//自定义顺序 直接获取
+		if (betweenDay <= 60) {
+			//检验规格
+			errorNetflixChangeOtherSkuTicketDto = errorNetflixChangeOtherSkuTicketDtos.get(0);
+		} else if (betweenDay <= 120) {
+			errorNetflixChangeOtherSkuTicketDto = errorNetflixChangeOtherSkuTicketDtos.get(1);
+		} else {
+			errorNetflixChangeOtherSkuTicketDto = errorNetflixChangeOtherSkuTicketDtos.get(2);
+		}
+		List<Long> availableSkuIds = errorNetflixChangeOtherSkuTicketDto.getSkuIds();
+		if (!availableSkuIds.contains(skuId)) {
+			throw BusinessRuntimeException.getInstance("不支持更换该类型车票");
+		}
+		//替换车票
+		TicketChangeDto changeDto = getTicketAndGenerateOrder(userId, skuId, netflixRelationView.getStartTime(), expiryTime);
+		//替换记录
+		NetflixUserChangeOtherTicketRecord changeOtherTicketRecord = new NetflixUserChangeOtherTicketRecord();
+		changeOtherTicketRecord.setUserId(userId);
+		changeOtherTicketRecord.setRelationId(relationId);
+		changeOtherTicketRecord.setOtherRelationId(changeDto.getOtherRelationId());
+		changeOtherTicketRecord.setRelateOrderId(changeDto.getOtherOrderId());
+		netflixUserChangeOtherTicketRecordMapper.insert(changeOtherTicketRecord);
+	}
+
+	@Override
+	public List<GoodsCategorySkuView> getNetflixReplaceOtherSkus(long userId, Long relationId) throws Exception {
+		//校验奈飞账号状态
+		GroupsRelationView netflixRelationView = checkNetflixErrorStatus(relationId, userId);
+		Date expiryTime = netflixRelationView.getExpiryTime();
+		//小于15 不可替换其他车票
+		Long betweenDay = DateUtil.betweenDay(DateTime.now(), expiryTime, false) + 1;
+		SysConfig sysConfig = sysConfigMapper.selectOne(Wrappers.lambdaQuery(SysConfig.class)
+				.eq(SysConfig::getSysKey, Constant.ERROR_NETFLIX_CHANGE_OTHER_SKU_KEY)
+				.last("limit 1"));
+		List<ErrorNetflixChangeOtherSkuTicketDto> errorNetflixChangeOtherSkuTicketDtos = Jsons.parseList(sysConfig.getSysValue(), ErrorNetflixChangeOtherSkuTicketDto.class);
+		ErrorNetflixChangeOtherSkuTicketDto errorNetflixChangeOtherSkuTicketDto;
+		if (betweenDay <= 15) {
+			return null;
+		}
+		//自定义顺序 直接获取
+		if (betweenDay <= 60) {
+			//检验规格
+			errorNetflixChangeOtherSkuTicketDto = errorNetflixChangeOtherSkuTicketDtos.get(0);
+		} else if (betweenDay <= 120) {
+			errorNetflixChangeOtherSkuTicketDto = errorNetflixChangeOtherSkuTicketDtos.get(1);
+		} else {
+			errorNetflixChangeOtherSkuTicketDto = errorNetflixChangeOtherSkuTicketDtos.get(2);
+		}
+		List<GoodsCategorySkuView> goodsCategorySkuViews = beanSearcher.searchAll(GoodsCategorySkuView.class, MapUtils.builder().field(GoodsCategorySkuView::getSkuId, errorNetflixChangeOtherSkuTicketDto.getSkuIds()).build());
+		return goodsCategorySkuViews;
+	}
+
 	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());
@@ -1625,4 +1727,116 @@ public class GroupRelationFrontServiceImpl implements GroupRelationFrontService
 			}
 		}
 	}
+
+	/**
+	 * 检验奈飞账号状态
+	 */
+	public GroupsRelationView checkNetflixErrorStatus(Long relationId, Long userId) {
+		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+		NetflixUserAccountStatusRecord netflixUseAccountStatusRecord = netflixUserAccountStatusRecordMapper.selectOne(Wrappers.lambdaQuery(NetflixUserAccountStatusRecord.class)
+				.eq(NetflixUserAccountStatusRecord::getRelationId, relationId)
+				.eq(NetflixUserAccountStatusRecord::getDeleted, 1)
+				.in(NetflixUserAccountStatusRecord::getUserId, userIdList)
+				.last("limit 1"));
+		if (netflixUseAccountStatusRecord == null) {
+			throw BusinessRuntimeException.getInstance("请先提交账号检测");
+		}
+		Integer state = netflixUseAccountStatusRecord.getState();
+		if (state == 0) {
+			throw BusinessRuntimeException.getInstance("您的账号检测中");
+		}
+		//2是登录失败 3是被封号
+		if (state != 3) {
+			throw BusinessRuntimeException.getInstance("您的账号未封禁");
+		}
+		GroupsRelationView netflixRelationView = beanSearcher.searchFirst(GroupsRelationView.class, MapUtils.builder()
+				.field(GroupsRelationView::getId, relationId)
+				.field(GroupsRelationView::getUserId, userIdList).op(Operator.InList)
+				.field(GroupsRelationView::getGoodsId, Constant.NETFLIX_GID)
+				.field(GroupsRelationView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
+				.build());
+		if (netflixRelationView == null) {
+			throw BusinessRuntimeException.getInstance("奈飞车票已过期");
+		}
+		return netflixRelationView;
+	}
+
+	/**
+	 * 获取车票 并生成订单
+	 */
+	public TicketChangeDto getTicketAndGenerateOrder(Long userId, Long skuId, Date startTime, Date expiryTime) {
+		Retryer<TicketChangeDto> build = RetryerBuilder.<TicketChangeDto>newBuilder()
+				.retryIfException()
+				//运行时异常重试
+				.retryIfRuntimeException()
+				//false重试
+				.retryIfResult(res -> res == null)
+				//1s 间隔
+				.withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS))
+				//停止策略 : 尝试请求1次
+				.withStopStrategy(StopStrategies.stopAfterAttempt(1)).build();
+		if (startTime == null) {
+			startTime = DateTime.now();
+		}
+		GoodsDonSku sku = goodsDonSkuMapper.selectById(skuId);
+		if (expiryTime == null) {
+			if (sku.getDays() != null) {
+				expiryTime = DateUtil.offsetDay(startTime, sku.getDays());
+			} else {
+				expiryTime = DateUtil.offsetMonth(startTime, sku.getMonths());
+			}
+		}
+		Date finalStartTime = startTime;
+		Date finalExpiryTime = expiryTime;
+		try {
+			return build.call(() -> {
+				GroupsTrips groups = groupsMapper.selectCollegeStudentUserGptTicket(skuId);
+				GroupsRelation relation = null;
+				if (groups != null) {
+					relation = groupsRelationMapper.selectRandomOneRelationByGroupsId(groups.getId());
+				}
+				//生成空车队
+				if (relation == null) {
+					relation = groupsFuncService.createNewGroupsTrips(sku);
+				}
+				int update = groupsRelationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
+						.set(GroupsRelation::getUserId, userId)
+						.set(GroupsRelation::getStartTime, finalStartTime)
+						.set(GroupsRelation::getExpiryTime, finalExpiryTime)
+						.set(GroupsRelation::getStatus, GroupsRelation.Status.validity)
+						.eq(GroupsRelation::getId, relation.getId())
+						.eq(GroupsRelation::getUserId, 0));
+				if (update > 0) {
+					groupsMapper.decrAvailableNum(groups.getId());
+					Long relationId = relation.getId();
+					//生成新的订单
+					OrderDon otherOrderDon = generateNewTicketOrder(relationId, userId, sku);
+
+					TicketChangeDto ticketChangeDto = new TicketChangeDto();
+					ticketChangeDto.setOtherRelationId(relationId);
+					ticketChangeDto.setOtherOrderId(otherOrderDon.getId());
+					return ticketChangeDto;
+				}
+				log.error("发送用户:{} GPT镜像车票失败,进行重试", userId);
+				return null;
+			});
+		} catch (ExecutionException | RetryException e) {
+			log.error("发送用户GPT镜像失败:{}", StringUtil.getErrorText(e));
+			return null;
+		}
+	}
+
+	private OrderDon generateNewTicketOrder(Long relationId, Long userId, GoodsDonSku sku) {
+		OrderDon orderDon = new OrderDon();
+		orderDon.setUserId(userId);
+		orderDon.setOrderNo(SEQUENCE.nextId().toString());
+		orderDon.setMoney(BigDecimal.ZERO);
+		orderDon.setRelationId(relationId);
+		orderDon.setGoodsId(sku.getGoodsId());
+		orderDon.setSkuId(sku.getId());
+		orderDon.setType(OrderDon.Type.TICKET_REPLACE);
+		orderDon.setStatus(OrderDon.Status.complete);
+		orderDonMapper.insert(orderDon);
+		return orderDon;
+	}
 }

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

@@ -1142,6 +1142,7 @@ public class GroupRelationController {
      * 申请更换车票
      */
     @PostMapping("/change/ticket")
+    @Deprecated
     public Result<String> changeTicket(@RequestBody ChangeTicketReq changeTicketReq) {
         long userId = StpUserUtil.getLoginIdAsLong();
         List<Long> relationIds = changeTicketReq.getRelationIds();
@@ -1211,6 +1212,38 @@ public class GroupRelationController {
         return GatewayResponse.SUCCESS.newBuilder().toResult(state);
     }
 
+    /**
+     * 奈飞可替换其他规格车票列表
+     */
+    @GetMapping("/get/netflix/replace/other/skus/{relationId}")
+    public Result<List<GoodsCategorySkuView>> getNetflixReplaceOtherSkus(@PathVariable Long relationId) throws Exception {
+        long userId = StpUserUtil.getLoginIdAsLong();
+        List<GoodsCategorySkuView> goodsCategorySkuViews = groupRelationFrontService.getNetflixReplaceOtherSkus(userId, relationId);
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
+
+    /**
+     * 奈飞账号申请恢复
+     */
+    @PostMapping("/netflix/submit/recover")
+    public Result<Integer> netflixSubmitRecover(@RequestBody ErrorNetflixChangeReq req) {
+        long userId = StpUserUtil.getLoginIdAsLong();
+        req.setUserId(userId);
+        groupRelationFrontService.netflixSubmitRecover(req);
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
+
+    /**
+     * 奈飞更换其他车票
+     */
+    @PostMapping("/netflix/submit/change/otherTicket")
+    public Result<Integer> errorNetflixSubmitChangeOtherTicket(@RequestBody ErrorNetflixChangeReq req) throws Exception {
+        long userId = StpUserUtil.getLoginIdAsLong();
+        req.setUserId(userId);
+        groupRelationFrontService.errorNetflixSubmitChangeOtherTicket(req);
+        return GatewayResponse.SUCCESS.newBuilder().toResult();
+    }
+
     /**
      * AI镜像车票 每周弹窗
      */