Explorar o código

fix 企业微信绑定手机号/邮箱

zoujiajian hai 9 horas
pai
achega
f5d6708688

+ 28 - 0
netflix-dao/src/main/java/com/cyksj/model/request/corp/CorpBindAccountReq.java

@@ -0,0 +1,28 @@
+package com.cyksj.model.request.corp;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 企业微信客户绑定登录账号请求。
+ */
+@Getter
+@Setter
+public class CorpBindAccountReq {
+
+	@NotEmpty
+	private String externalUserid;
+
+	/**
+	 * 1:手机号,2:邮箱。
+	 */
+	@NotNull
+	private Integer type;
+
+	@NotBlank
+	private String account;
+}

+ 6 - 0
netflix-service/src/main/java/com/cyksj/service/corp/CorpUserService.java

@@ -1,5 +1,6 @@
 package com.cyksj.service.corp;
 
+import com.cyksj.model.request.corp.CorpBindAccountReq;
 import com.cyksj.model.request.corp.CorpCommonReq;
 import com.cyksj.model.views.YHLXUserDetailView;
 
@@ -20,6 +21,11 @@ public interface CorpUserService {
 	 **/
 	void bindOtherUsersByOrderNo(CorpCommonReq corpCommonReq) throws Exception;
 
+	/**
+	 * 为企业微信客户绑定手机号或邮箱账号。
+	 */
+	void bindAccount(String corpId, CorpBindAccountReq corpBindAccountReq) throws Exception;
+
 	void markCorpUser(CorpCommonReq corpCommonReq) throws Exception;
 
 	void spotifySelfService(Long orderId);

+ 132 - 0
netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpUserServiceImpl.java

@@ -1,5 +1,6 @@
 package com.cyksj.service.corp.impl;
 
+import cn.hutool.core.lang.Validator;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -15,6 +16,7 @@ import com.cyksj.mapper.manage.cms.CmsUserMapper;
 import com.cyksj.mapper.market.task.UserBindDetailMapper;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.kf.CorpKfUserInfo;
+import com.cyksj.model.request.corp.CorpBindAccountReq;
 import com.cyksj.model.request.corp.CorpCommonReq;
 import com.cyksj.model.request.corp.CorpXmlMessage;
 import com.cyksj.model.views.YHLXUserDetailView;
@@ -32,6 +34,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
+import java.util.Objects;
 import java.util.Optional;
 
 /**
@@ -233,6 +236,135 @@ public class CorpUserServiceImpl implements CorpUserService {
 		}
 	}
 
+	@Override
+	@Transactional(rollbackFor = Throwable.class)
+	public void bindAccount(String corpId, CorpBindAccountReq corpBindAccountReq) throws Exception {
+		Integer type = corpBindAccountReq.getType();
+		String account = StrUtil.trim(corpBindAccountReq.getAccount());
+		validateBindAccount(type, account);
+
+		CorpUser externalCorpUser = getExternalUserId(corpId, corpBindAccountReq.getExternalUserid());
+		if (externalCorpUser == null) {
+			throw BusinessRuntimeException.getInstance("该企业微信用户不存在");
+		}
+		CorpUser corpUser = corpUserMapper.selectById(externalCorpUser.getId());
+		if (corpUser == null) {
+			throw BusinessRuntimeException.getInstance("该企业微信用户不存在");
+		}
+		if (StrUtil.isBlank(corpUser.getUnionid())) {
+			throw BusinessRuntimeException.getInstance("该企业微信用户未关联微信账号");
+		}
+
+		User corpLoginUser = getCorpLoginUser(corpUser);
+		User accountUser = getAccountUser(type, account);
+		String accountName = type == 1 ? "手机号" : "邮箱";
+		if (accountUser != null && Objects.equals(accountUser.getId(), corpLoginUser.getId())) {
+			throw BusinessRuntimeException.getInstance("该企业微信用户已绑定" + accountName);
+		}
+		if (accountUser != null
+				&& (StrUtil.isNotBlank(accountUser.getUnionid()) || StrUtil.isNotBlank(accountUser.getOpenId()))) {
+			throw BusinessRuntimeException.getInstance("绑定的" + accountName + "属于微信用户,无法绑定");
+		}
+		if (accountUser != null) {
+			account = type == 1 ? accountUser.getLoginPhone() : accountUser.getEmail();
+		}
+
+		UserBindDetail corpBindDetail = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
+				.eq(UserBindDetail::getUserId, corpLoginUser.getId())
+				.last("limit 1"));
+		checkCorpAccountNotBound(type, corpLoginUser, corpBindDetail);
+
+		Long accountUserId = accountUser == null ? null : accountUser.getId();
+		UserBindDetail accountBindDetail = getAccountBindDetail(type, account, accountUserId);
+		if (accountBindDetail != null && accountBindDetail.getUserId() != null) {
+			throw BusinessRuntimeException.getInstance("该" + accountName + "已绑定微信用户");
+		}
+		if (corpBindDetail != null && accountBindDetail != null
+				&& !Objects.equals(corpBindDetail.getId(), accountBindDetail.getId())) {
+			throw BusinessRuntimeException.getInstance("企业微信用户与该" + accountName + "已存在不同绑定关系,无法合并");
+		}
+
+		UserBindDetail bindDetail = Optional.ofNullable(corpBindDetail)
+				.orElseGet(() -> Optional.ofNullable(accountBindDetail).orElse(new UserBindDetail()));
+		bindDetail.setUserId(corpLoginUser.getId());
+		if (type == 1) {
+			bindDetail.setPhone(account);
+			bindDetail.setPhoneUserId(accountUserId);
+		} else {
+			bindDetail.setEmail(account);
+			bindDetail.setEmailUserId(accountUserId);
+		}
+
+		if (bindDetail.getId() == null) {
+			userBindDetailMapper.insert(bindDetail);
+		} else {
+			userBindDetailMapper.updateById(bindDetail);
+		}
+	}
+
+	private void validateBindAccount(Integer type, String account) {
+		if (type == null || (type != 1 && type != 2)) {
+			throw BusinessRuntimeException.getInstance("绑定类型仅支持手机号或邮箱");
+		}
+		if (type == 2 && !Validator.isEmail(account)) {
+			throw BusinessRuntimeException.getInstance("请输入正确的邮箱");
+		}
+	}
+
+	private User getCorpLoginUser(CorpUser corpUser) {
+		User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class).eq(User::getUnionid, corpUser.getUnionid()).last("limit 1"));
+		if (user == null) {
+			throw BusinessRuntimeException.getInstance("该企业微信用户关联的银河用户不存在");
+		}
+		if (!Objects.equals(corpUser.getUnionid(), user.getUnionid())) {
+			throw BusinessRuntimeException.getInstance("该企业微信用户关联的银河用户不一致");
+		}
+		return user;
+	}
+
+	private User getAccountUser(Integer type, String account) {
+		LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class).last("limit 1");
+		if (type == 1) {
+			wrapper.eq(User::getLoginPhone, account);
+		} else {
+			wrapper.eq(User::getEmail, account);
+		}
+		return userMapper.selectOne(wrapper);
+	}
+
+	private void checkCorpAccountNotBound(Integer type, User corpLoginUser, UserBindDetail bindDetail) {
+		boolean bound;
+		if (type == 1) {
+			bound = StrUtil.isNotBlank(corpLoginUser.getLoginPhone())
+					|| bindDetail != null && (StrUtil.isNotBlank(bindDetail.getPhone()) || bindDetail.getPhoneUserId() != null);
+		} else {
+			bound = StrUtil.isNotBlank(corpLoginUser.getEmail())
+					|| bindDetail != null && (StrUtil.isNotBlank(bindDetail.getEmail()) || bindDetail.getEmailUserId() != null);
+		}
+		if (bound) {
+			throw BusinessRuntimeException.getInstance("该企业微信用户已绑定" + (type == 1 ? "手机号" : "邮箱"));
+		}
+	}
+
+	private UserBindDetail getAccountBindDetail(Integer type, String account, Long accountUserId) {
+		LambdaQueryWrapper<UserBindDetail> wrapper = Wrappers.lambdaQuery(UserBindDetail.class)
+				.and(detail -> {
+					if (type == 1) {
+						if (accountUserId != null) {
+							detail.eq(UserBindDetail::getPhoneUserId, accountUserId).or();
+						}
+						detail.eq(UserBindDetail::getPhone, account);
+					} else {
+						if (accountUserId != null) {
+							detail.eq(UserBindDetail::getEmailUserId, accountUserId).or();
+						}
+						detail.eq(UserBindDetail::getEmail, account);
+					}
+				})
+				.last("limit 1");
+		return userBindDetailMapper.selectOne(wrapper);
+	}
+
 
 	@Override
 	public void markCorpUser(CorpCommonReq corpCommonReq) throws Exception {

+ 10 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/corp/WxCorpController.java

@@ -30,6 +30,7 @@ import com.cyksj.model.manage.views.CorpQyMsgAuditChatView;
 import com.cyksj.model.manage.views.CorpWxOrderDonView;
 import com.cyksj.model.request.CcReq;
 import com.cyksj.model.request.OrderRefundReq;
+import com.cyksj.model.request.corp.CorpBindAccountReq;
 import com.cyksj.model.request.corp.CorpCommonReq;
 import com.cyksj.model.views.*;
 import com.cyksj.redis.RedisService;
@@ -304,6 +305,15 @@ public class WxCorpController {
 		return GatewayResponse.SUCCESS.newBuilder().toResult();
 	}
 
+	/**
+	 * 企业微信用户绑定手机号或邮箱账号
+	 */
+	@PostMapping("/bind/account")
+	public Result<String> bindAccount(@RequestBody @Validated CorpBindAccountReq corpBindAccountReq) throws Exception {
+		corpUserService.bindAccount(yhlxWxCorpConfig.getCorpId(), corpBindAccountReq);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
 	/**
 	 * 给企业微信用户 标记
 	 */