|
|
@@ -79,6 +79,11 @@ import com.fs.sop.service.ISopUserLogsService;
|
|
|
import com.fs.system.service.ISysConfigService;
|
|
|
import com.fs.system.service.ISysDictTypeService;
|
|
|
import com.fs.voice.utils.StringUtil;
|
|
|
+import com.fs.wxwork.dto.WxwGetExternalContactsDTO;
|
|
|
+import com.fs.wxwork.dto.WxwGetExternalContactsPageDTO;
|
|
|
+import com.fs.wxwork.dto.WxwIpadExternalContactItemDTO;
|
|
|
+import com.fs.wxwork.dto.WxWorkResponseDTO;
|
|
|
+import com.fs.wxwork.service.WxWorkService;
|
|
|
import com.google.gson.Gson;
|
|
|
import com.google.gson.reflect.TypeToken;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
@@ -170,6 +175,8 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
|
|
|
@Autowired
|
|
|
private ICrmMsgService crmMsgService;
|
|
|
@Autowired
|
|
|
+ private WxWorkService wxWorkService;
|
|
|
+ @Autowired
|
|
|
QwAutoTagsLogsMapper qwAutoTagsLogsMapper;
|
|
|
@Autowired
|
|
|
IAdHtmlClickLogService iAdHtmlClickLogService;
|
|
|
@@ -1311,6 +1318,180 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
|
|
|
return R.ok(buildTransferSummary(stats));
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public R transferPreCheck(TransferPreCheckParam param) {
|
|
|
+ if (param.getIds() == null || param.getIds().isEmpty()) {
|
|
|
+ return R.error("请选择需要分配的客户");
|
|
|
+ }
|
|
|
+ QwUser takeoverUser = qwUserMapper.selectQwUserById(param.getUserId());
|
|
|
+ if (takeoverUser == null) {
|
|
|
+ return R.error("接替员工不存在");
|
|
|
+ }
|
|
|
+ List<TransferPreCheckCustomerVO> transferable = new ArrayList<>();
|
|
|
+ Map<String, PreCheckFailBucket> untransferableMap = new LinkedHashMap<>();
|
|
|
+ Map<String, IpadContactIndex> ipadContactCache = new HashMap<>();
|
|
|
+
|
|
|
+ for (Long id : param.getIds()) {
|
|
|
+ QwExternalContact contact = qwExternalContactMapper.selectQwExternalContactById(id);
|
|
|
+ if (contact == null) {
|
|
|
+ addPreCheckFail(untransferableMap, "客户不存在", "NOT_FOUND", buildPreCheckCustomer(null, id, null, null));
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ TransferPreCheckCustomerVO customerVO = buildPreCheckCustomer(contact, id,
|
|
|
+ contact.getUserId(), resolveHandoverUserName(contact.getUserId(), contact.getCorpId()));
|
|
|
+ if (contact.getUserId() != null && contact.getUserId().equals(takeoverUser.getQwUserId())) {
|
|
|
+ addPreCheckFail(untransferableMap, "原跟进人与接手人一样,不可继承", "SAME_USER", customerVO);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ QwUser handoverUser = qwUserMapper.selectQwUserByCorpIdAndUserId(contact.getCorpId(), contact.getUserId());
|
|
|
+ if (handoverUser == null || StringUtils.isEmpty(handoverUser.getUid()) || handoverUser.getServerId() == null) {
|
|
|
+ addPreCheckFail(untransferableMap, "所属员工iPad未登录,无法校验好友关系", "IPAD_OFFLINE", customerVO);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String cacheKey = handoverUser.getUid() + ":" + handoverUser.getServerId();
|
|
|
+ IpadContactIndex index = ipadContactCache.computeIfAbsent(cacheKey,
|
|
|
+ k -> loadIpadContactIndex(handoverUser.getUid(), handoverUser.getServerId()));
|
|
|
+ if (index == null) {
|
|
|
+ addPreCheckFail(untransferableMap, "拉取iPad联系人失败,无法校验好友关系", "IPAD_FETCH_FAIL", customerVO);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ WxwIpadExternalContactItemDTO ipadContact = matchIpadContact(contact, index);
|
|
|
+ if (ipadContact == null) {
|
|
|
+ addPreCheckFail(untransferableMap, "没有好友关系", "NO_FRIEND", customerVO);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String statusReason = getIpadFriendStatusReason(ipadContact.getStatus());
|
|
|
+ if (statusReason != null) {
|
|
|
+ addPreCheckFail(untransferableMap, statusReason, "STATUS_" + ipadContact.getStatus(), customerVO);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ transferable.add(customerVO);
|
|
|
+ }
|
|
|
+
|
|
|
+ TransferPreCheckVO result = new TransferPreCheckVO();
|
|
|
+ result.setTransferable(transferable);
|
|
|
+ result.setTransferableCount(transferable.size());
|
|
|
+ result.setUntransferable(rebuildPreCheckGroups(untransferableMap));
|
|
|
+ result.setUntransferableCount(result.getUntransferable().stream().mapToInt(g -> g.getCustomers().size()).sum());
|
|
|
+ return R.ok().put("data", result);
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<TransferPreCheckGroupVO> rebuildPreCheckGroups(Map<String, PreCheckFailBucket> bucketMap) {
|
|
|
+ List<TransferPreCheckGroupVO> groups = new ArrayList<>();
|
|
|
+ bucketMap.forEach((key, bucket) -> {
|
|
|
+ TransferPreCheckGroupVO group = new TransferPreCheckGroupVO();
|
|
|
+ group.setReason(bucket.reason);
|
|
|
+ group.setReasonCode(bucket.reasonCode);
|
|
|
+ group.setCustomers(bucket.customers);
|
|
|
+ groups.add(group);
|
|
|
+ });
|
|
|
+ return groups;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static class PreCheckFailBucket {
|
|
|
+ private final String reason;
|
|
|
+ private final String reasonCode;
|
|
|
+ private final List<TransferPreCheckCustomerVO> customers = new ArrayList<>();
|
|
|
+
|
|
|
+ PreCheckFailBucket(String reason, String reasonCode) {
|
|
|
+ this.reason = reason;
|
|
|
+ this.reasonCode = reasonCode;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addPreCheckFail(Map<String, PreCheckFailBucket> bucketMap, String reason, String reasonCode,
|
|
|
+ TransferPreCheckCustomerVO customerVO) {
|
|
|
+ String key = reasonCode + ":" + reason;
|
|
|
+ bucketMap.computeIfAbsent(key, k -> new PreCheckFailBucket(reason, reasonCode)).customers.add(customerVO);
|
|
|
+ }
|
|
|
+
|
|
|
+ private TransferPreCheckCustomerVO buildPreCheckCustomer(QwExternalContact contact, Long id,
|
|
|
+ String handoverUserId, String handoverUserName) {
|
|
|
+ TransferPreCheckCustomerVO vo = new TransferPreCheckCustomerVO();
|
|
|
+ vo.setId(contact != null ? contact.getId() : id);
|
|
|
+ vo.setName(contact != null ? contact.getName() : "未知客户");
|
|
|
+ vo.setExternalUserId(contact != null ? contact.getExternalUserId() : null);
|
|
|
+ vo.setHandoverUserId(handoverUserId);
|
|
|
+ vo.setHandoverUserName(handoverUserName);
|
|
|
+ return vo;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String resolveHandoverUserName(String handoverUserId, String corpId) {
|
|
|
+ if (StringUtils.isEmpty(handoverUserId)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return qwUserMapper.selectQwUserName(handoverUserId, corpId);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static class IpadContactIndex {
|
|
|
+ private final Map<String, WxwIpadExternalContactItemDTO> byUnionid = new HashMap<>();
|
|
|
+ private final Map<String, WxwIpadExternalContactItemDTO> byNickname = new HashMap<>();
|
|
|
+ }
|
|
|
+
|
|
|
+ private IpadContactIndex loadIpadContactIndex(String uuid, Long serverId) {
|
|
|
+ IpadContactIndex index = new IpadContactIndex();
|
|
|
+ Long seq = 0L;
|
|
|
+ int limit = 100;
|
|
|
+ int maxLoop = 500;
|
|
|
+ for (int i = 0; i < maxLoop; i++) {
|
|
|
+ WxwGetExternalContactsDTO req = new WxwGetExternalContactsDTO();
|
|
|
+ req.setUuid(uuid);
|
|
|
+ req.setLimit(limit);
|
|
|
+ req.setSeq(seq);
|
|
|
+ WxWorkResponseDTO<WxwGetExternalContactsPageDTO> resp = wxWorkService.getIpadExternalContactPage(req, serverId);
|
|
|
+ if (resp == null || resp.getErrcode() == null || resp.getErrcode() != 0 || resp.getData() == null) {
|
|
|
+ return index.byUnionid.isEmpty() && index.byNickname.isEmpty() ? null : index;
|
|
|
+ }
|
|
|
+ List<WxwIpadExternalContactItemDTO> list = resp.getData().getList();
|
|
|
+ if (list == null || list.isEmpty()) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ for (WxwIpadExternalContactItemDTO item : list) {
|
|
|
+ if (StringUtils.isNotEmpty(item.getUnionid())) {
|
|
|
+ index.byUnionid.put(item.getUnionid(), item);
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotEmpty(item.getNickname())) {
|
|
|
+ index.byNickname.putIfAbsent(item.getNickname(), item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Long nextSeq = resp.getData().getSeq();
|
|
|
+ if (nextSeq == null || nextSeq.equals(seq) || list.size() < limit) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ seq = nextSeq;
|
|
|
+ }
|
|
|
+ return index;
|
|
|
+ }
|
|
|
+
|
|
|
+ private WxwIpadExternalContactItemDTO matchIpadContact(QwExternalContact contact, IpadContactIndex index) {
|
|
|
+ if (StringUtils.isNotEmpty(contact.getUnionid())) {
|
|
|
+ WxwIpadExternalContactItemDTO item = index.byUnionid.get(contact.getUnionid());
|
|
|
+ if (item != null) {
|
|
|
+ return item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotEmpty(contact.getName())) {
|
|
|
+ return index.byNickname.get(contact.getName());
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getIpadFriendStatusReason(Integer status) {
|
|
|
+ if (status == null) {
|
|
|
+ return "没有好友关系";
|
|
|
+ }
|
|
|
+ switch (status) {
|
|
|
+ case 0:
|
|
|
+ return "互相删除";
|
|
|
+ case 8:
|
|
|
+ return "主动删除拉黑";
|
|
|
+ case 2049:
|
|
|
+ return "被删除";
|
|
|
+ default:
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private void handleActiveTransferResult(QwTransferCustomerResult transferResult, QwExternalContact qwExternalContact,
|
|
|
QwUser qwUser, Long id, TransferParam param, TransferBatchStats stats) {
|
|
|
String customerName = getTransferCustomerName(qwExternalContact);
|