package cn.fw.valhalla.service.bus.pub; import cn.fw.valhalla.common.constant.RoleCode; import cn.fw.valhalla.common.utils.DateUtil; import cn.fw.valhalla.domain.db.customer.AffiliationRecord; import cn.fw.valhalla.domain.db.customer.Customer; import cn.fw.valhalla.domain.db.follow.ClueTask; import cn.fw.valhalla.domain.db.follow.FollowClue; import cn.fw.valhalla.domain.db.pool.PublicPool; import cn.fw.valhalla.domain.db.pool.StammkundePool; import cn.fw.valhalla.domain.db.pub.PubCluePool; import cn.fw.valhalla.domain.db.pub.PubStandStaffInfo; import cn.fw.valhalla.domain.enums.*; import cn.fw.valhalla.domain.vo.setting.SettingVO; import cn.fw.valhalla.rpc.ehr.EhrRpcService; import cn.fw.valhalla.rpc.erp.UserService; import cn.fw.valhalla.rpc.erp.dto.UserInfoDTO; import cn.fw.valhalla.rpc.erp.dto.UserRoleDataRangeDTO; import cn.fw.valhalla.rpc.mkt.MktRpcService; import cn.fw.valhalla.rpc.mkt.dto.QualificationDTO; import cn.fw.valhalla.rpc.oop.OopService; import cn.fw.valhalla.rpc.oop.dto.ShopDTO; import cn.fw.valhalla.rpc.shirasawa.ShirasawaRpcService; import cn.fw.valhalla.service.bus.setting.SettingBizService; import cn.fw.valhalla.service.data.*; import cn.hutool.core.collection.ListUtil; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDate; import java.util.*; import java.util.stream.Collectors; /** * 公共池站岗分配 * * @author : kurisu * @version : 1.0 * @className : PubDBizService * @description : 公共池站岗分配 * @date : 2023-03-11 15:55 */ @RequiredArgsConstructor @Service @Slf4j public class PubDistributeBizService { private final OopService oopService; private final UserService userService; private final EhrRpcService ehrRpcService; private final FollowClueService followClueService; private final ClueTaskService clueTaskService; private final ShirasawaRpcService shirasawaRpcService; private final PublicPoolService publicPoolService; private final CustomerService customerService; private final PubStandStaffInfoService pubStandStaffInfoService; private final PubCluePoolService pubCluePoolService; private final SettingBizService settingBizService; private final StammkundePoolService stammkundePoolService; private final MktRpcService mktRpcService; private final AffiliationRecordService affiliationRecordService; /** * 分配 * * @param id 公共站岗id * @return */ @Transactional(rollbackFor = Exception.class) public Boolean distribute(Long id) { PubStandStaffInfo staffInfo = pubStandStaffInfoService.getById(id); if (Objects.isNull(staffInfo)) { return true; } if (staffInfo.getNoInvolved() || !staffInfo.getLining()) { return true; } Boolean checked = checkStaff(staffInfo); if (null == checked) { return false; } else if (!checked) { return true; } boolean can_distributable = distributable(staffInfo.getStaffId(), staffInfo.getGroupId()); if (!can_distributable) { staffInfo.setLining(false); staffInfo.setQueueable(false); staffInfo.setReasonOfNoLining("被暂停分配资格"); pubStandStaffInfoService.updateById(staffInfo); return true; } Boolean distributed = distribute4Staff(staffInfo); if (Boolean.TRUE.equals(distributed)) { staffInfo.setLining(false); staffInfo.setQueueable(false); staffInfo.setReasonOfNoLining("跟进待办未完成"); pubStandStaffInfoService.updateById(staffInfo); } return distributed; } /** * 检查人员状态 * * @return */ public Boolean checkStaff(PubStandStaffInfo staffInfo) { Boolean aBoolean = shirasawaRpcService.hasOngoingFollow(staffInfo.getStaffId()); if (null == aBoolean) { return null; } if (Boolean.TRUE.equals(aBoolean)) { staffInfo.setLining(false); staffInfo.setQueueable(false); staffInfo.setReasonOfNoLining("跟进待办未完成"); pubStandStaffInfoService.updateById(staffInfo); return false; } return true; } /** * 线索开始跟进后建立专属线索关系(如果能的话) * * @param pubClue */ @Transactional(rollbackFor = Exception.class) public void distributeFromClue(final PubCluePool pubClue) { Customer customer = customerService.queryByEngineNo(pubClue.getVin(), pubClue.getGroupId()); if (Objects.isNull(customer)) { return; } PublicPool publicPool = publicPoolService.queryByVin(pubClue.getVin(), pubClue.getGroupId()); if (Objects.isNull(publicPool)) { return; } if (Objects.nonNull(customer.getAdviserId())) { return; } Optional settingVO = settingBizService.querySettingByType(FollowTypeEnum.OT, SettingTypeEnum.PUBLIC_VALID_DAY, pubClue.getGroupId(), null); int publicValidDay = settingVO.map(SettingVO::getDetailValue).orElse(60); pubClue.setDeadline(LocalDate.now().plusDays(publicValidDay)); UserInfoDTO user = ehrRpcService.user(pubClue.getAdviserId()); if (Objects.nonNull(user)) { pubClue.setAdviserName(user.getUserName()); } ShopDTO shop = oopService.shop(pubClue.getShopId()); if (Objects.nonNull(shop)) { pubClue.setShopName(shop.getShortName()); } createPubRelation(pubClue, customer.getId()); } /** * 查询门店 * * @param staffInfo * @return */ private List getShopIds(final PubStandStaffInfo staffInfo) { List shopIdList = ListUtil.toList(); PubStandRang standRang = Optional.ofNullable(staffInfo.getStandRang()).orElse(PubStandRang.SHOP); switch (standRang) { case SHOP: shopIdList = ListUtil.toList(staffInfo.getShopId()); break; case AREA: shopIdList = oopService.areaShops(staffInfo.getGroupId(), staffInfo.getAreaCode()) .stream().map(ShopDTO::getId) .filter(r -> !r.equals(staffInfo.getShopId())) .collect(Collectors.toList()); break; default: break; } return shopIdList; } /** * 查询是否满足分配条件 * * @param userId * @param groupId * @return */ private boolean distributable(Long userId, Long groupId) { int count = pubCluePoolService.count(Wrappers.lambdaQuery() .eq(PubCluePool::getAdviserId, userId) .eq(PubCluePool::getGroupId, groupId) ); Optional minimumClueCountSetting = settingBizService.querySettingByType(FollowTypeEnum.OT, SettingTypeEnum.MINIMUM_CLUE_COUNT, groupId, null); int initCount = minimumClueCountSetting.map(SettingVO::getDetailValue).orElse(50); if (count > initCount) { Optional settingVO = settingBizService.querySettingByType(FollowTypeEnum.OT, SettingTypeEnum.MINIMUM_CONVERSION_RATE, groupId, null); int minimum_conversion_rate = settingVO.map(SettingVO::getDetailValue).orElse(2000); BigDecimal rate = BigDecimal.valueOf(minimum_conversion_rate).divide(BigDecimal.valueOf(1000_0), 2, RoundingMode.HALF_UP); Optional increaseCountSetting = settingBizService.querySettingByType(FollowTypeEnum.OT, SettingTypeEnum.INCREASE_COUNT, groupId, null); int increaseCount = increaseCountSetting.map(SettingVO::getDetailValue).orElse(10); if (count % increaseCount != 0) { return true; } List list = pubCluePoolService.list(Wrappers.lambdaQuery() .eq(PubCluePool::getGroupId, groupId) .eq(PubCluePool::getAdviserId, userId) .ge(PubCluePool::getStartTime, LocalDate.now().minusDays(60L).atStartOfDay()) ); if (!CollectionUtils.isEmpty(list)) { long completeCount = list.stream().filter(r -> PublicClueStateEnum.COMPLETE.equals(r.getState())).count(); BigDecimal actuallyRate = BigDecimal.valueOf(completeCount).divide(BigDecimal.valueOf(list.size()), 2, RoundingMode.HALF_UP); return actuallyRate.compareTo(rate) >= 0; } return true; } return true; } /** * 分配指定数量的客户 * * @param staffInfo * @return */ private Boolean distribute4Staff(PubStandStaffInfo staffInfo) { List list = getShopIds(staffInfo); if (CollectionUtils.isEmpty(list)) { return false; } List vinList = publicPoolService.queryIdListByShops(list); if (CollectionUtils.isEmpty(vinList)) { return false; } List vinArr = getBeDistributeVin(staffInfo, vinList, 1); if (StringUtils.isEmpty(vinArr)) { return false; } return createClue(vinArr, staffInfo); } /** * 分配给人员 档案 * * @param staffInfo * @param vinList * @param count * @return */ private List getBeDistributeVin(PubStandStaffInfo staffInfo, List vinList, int count) { List vinArr = null; PubStandType standType = Optional.ofNullable(staffInfo.getStandType()).orElse(PubStandType.PUB); switch (standType) { case PUB: vinArr = determinePub(vinList, staffInfo, count); break; case ACTIVITY: vinArr = determineMkt(vinList, staffInfo, count); break; default: break; } return vinArr; } /** * 分配档案 * * @param vinList * @param staffInfo * @param count * @return */ private List determinePub(List vinList, PubStandStaffInfo staffInfo, int count) { List list = new ArrayList<>(); for (String vin : vinList) { if (list.size() >= count) { break; } Customer customer = customerService.queryByFrameNo(vin, staffInfo.getGroupId()); if (Objects.isNull(customer)) { continue; } boolean hasDefeat = affiliationRecordService.count(Wrappers.lambdaQuery() .eq(AffiliationRecord::getCustomerId, customer.getId()) .eq(AffiliationRecord::getOriginUserId, staffInfo.getStaffId()) .ge(AffiliationRecord::getDefeatTime, DateUtil.localDate2Date(LocalDate.now().minusMonths(12L))) ) > 1; if (hasDefeat) { continue; } FollowClue clue = followClueService.getOne(Wrappers.lambdaQuery() .eq(FollowClue::getVin, vin) .eq(FollowClue::getClueType, FollowTypeEnum.IR) .eq(FollowClue::getClueState, ClueStatusEnum.ONGOING) , Boolean.FALSE ); if (Objects.nonNull(clue)) { ClueTask clueTask = clueTaskService.queryOngoingTaskByClueId(clue.getId(), clue.getClueType()); Long followUser = clueTask.getFollowUser(); List roleDataRange = userService.getUserRoleDataRange(followUser, RoleCode.FWGW); if (!staffInfo.getStaffId().equals(followUser) && !CollectionUtils.isEmpty(roleDataRange)) { continue; } } list.add(vin); } return list; } /** * 查询档案用户能否参与活动 * * @param vinList * @param staffInfo * @param count * @return */ private List determineMkt(List vinList, PubStandStaffInfo staffInfo, int count) { List list = new ArrayList<>(); for (String vin : vinList) { if (list.size() >= count) { break; } Customer customer = customerService.queryByFrameNo(vin, staffInfo.getGroupId()); if (Objects.isNull(customer)) { continue; } boolean hasDefeat = affiliationRecordService.count(Wrappers.lambdaQuery() .eq(AffiliationRecord::getCustomerId, customer.getId()) .eq(AffiliationRecord::getOriginUserId, staffInfo.getStaffId()) .ge(AffiliationRecord::getDefeatTime, DateUtil.localDate2Date(LocalDate.now().minusMonths(12L))) ) > 1; if (hasDefeat) { continue; } boolean hasInsFollow = followClueService.count(Wrappers.lambdaQuery() .eq(FollowClue::getVin, vin) .eq(FollowClue::getClueType, FollowTypeEnum.IR) .eq(FollowClue::getClueState, ClueStatusEnum.ONGOING) ) > 0; QualificationDTO dto = QualificationDTO.createWithCustomer(customer); dto.setShopId(staffInfo.getShopId()); dto.setLoseClue(Boolean.FALSE); dto.setRenewalClue(hasInsFollow); dto.setActivityNo(staffInfo.getIdCode()); try { Thread.sleep(450); } catch (InterruptedException e) { log.info("节流失败"); } Boolean canJoinActivity = mktRpcService.queryQualifications(dto); if (Boolean.TRUE.equals(canJoinActivity)) { list.add(vin); } } return list; } /** * 创建线索和分配记录 * * @param vinArr * @param staffInfo * @return */ private boolean createClue(List vinArr, PubStandStaffInfo staffInfo) { List clueList = new ArrayList<>(); List stammkundePoolList = new ArrayList<>(); final Long groupId = staffInfo.getGroupId(); Optional settingVO = settingBizService.querySettingByType(FollowTypeEnum.OT, SettingTypeEnum.PUBLIC_VALID_DAY, groupId, null); int publicValidDay = settingVO.map(SettingVO::getDetailValue).orElse(60); final Long staffId = staffInfo.getStaffId(); final Long shopId = staffInfo.getShopId(); for (String vin : vinArr) { Customer customer = customerService.queryByFrameNo(vin, groupId); if (Objects.isNull(customer) || Objects.nonNull(customer.getAdviserId())) { continue; } PubCluePool pool = new PubCluePool(); pool.setVin(vin); pool.setStartTime(LocalDate.now()); pool.setDeadline(LocalDate.now().plusDays(publicValidDay)); pool.setState(PublicClueStateEnum.ONGOING); pool.setBegun(Boolean.FALSE); pool.setSourceType(staffInfo.getStandType()); pool.setAdviserId(staffId); pool.setAdviserName(staffInfo.getStaffName()); pool.setShopId(shopId); pool.setShopName(staffInfo.getShopName()); pool.setGroupId(groupId); clueList.add(pool); StammkundePool stammkundePool = new StammkundePool(); stammkundePool.setCustomerId(customer.getId()); stammkundePool.setShopId(shopId); stammkundePool.setGroupId(groupId); stammkundePool.setAktiv(Boolean.FALSE); stammkundePool.setCreateTime(new Date()); stammkundePool.setAdviserId(staffId); stammkundePool.setAdviserName(staffInfo.getStaffName()); stammkundePool.setSources(StammkundeSourcesEnum.PUBLIC_POOL); stammkundePool.setPoolStatus(StammkundeStatusEnum.PUBLIC); stammkundePoolList.add(stammkundePool); } if (CollectionUtils.isEmpty(clueList)) { return false; } customerService.afterDistributePubClue(vinArr, staffId, shopId, groupId); pubCluePoolService.saveBatch(clueList); stammkundePoolService.saveBatch(stammkundePoolList); publicPoolService.removeBatchByVin(vinArr, groupId); return true; } private void createPubRelation(PubCluePool pool, Long customerId) { Long staffId = pool.getAdviserId(); Long shopId = pool.getShopId(); Long groupId = pool.getGroupId(); String vin = pool.getVin(); StammkundePool stammkundePool = new StammkundePool(); stammkundePool.setCustomerId(customerId); stammkundePool.setShopId(shopId); stammkundePool.setGroupId(groupId); stammkundePool.setAktiv(Boolean.FALSE); stammkundePool.setCreateTime(new Date()); stammkundePool.setAdviserId(staffId); stammkundePool.setAdviserName(pool.getAdviserName()); stammkundePool.setSources(StammkundeSourcesEnum.PUBLIC_POOL); stammkundePool.setPoolStatus(StammkundeStatusEnum.PUBLIC); customerService.afterDistributePubClue(Collections.singletonList(vin), staffId, shopId, groupId); pubCluePoolService.save(pool); stammkundePoolService.save(stammkundePool); publicPoolService.removeByVin(vin, groupId); } }