package cn.fw.valhalla.service.bus.cust; import cn.fw.common.exception.BusinessException; import cn.fw.common.web.auth.LoginAuthBean; import cn.fw.common.web.auth.PassportAuthBean; import cn.fw.data.base.domain.common.Message; import cn.fw.passport.sdk.api.param.WxBCodeParam; import cn.fw.starter.redis.redis.RedisUtil; import cn.fw.third.push.sdk.api.para.im.BusinessType; import cn.fw.third.push.sdk.api.para.im.MessageBusinessType; import cn.fw.third.push.sdk.api.para.im.MsgPara; import cn.fw.valhalla.common.constant.RoleCode; import cn.fw.valhalla.common.utils.DateUtil; import cn.fw.valhalla.common.utils.MessageFormatUtil; import cn.fw.valhalla.common.utils.QRCodeKit; import cn.fw.valhalla.common.utils.StringUtils; import cn.fw.valhalla.domain.db.customer.AffiliationRecord; import cn.fw.valhalla.domain.db.customer.Customer; import cn.fw.valhalla.domain.db.customer.CustomerBaseInfo; import cn.fw.valhalla.domain.db.follow.FollowTask; import cn.fw.valhalla.domain.db.pool.CustomerCluePool; import cn.fw.valhalla.domain.db.pool.StammkundePool; import cn.fw.valhalla.domain.dto.CustomerChangeDto; import cn.fw.valhalla.domain.dto.CustomerDetailDto; import cn.fw.valhalla.domain.enums.*; import cn.fw.valhalla.domain.vo.customer.CustomerChangeInfoVO; import cn.fw.valhalla.domain.vo.customer.CustomerChangeQrCodeVO; import cn.fw.valhalla.rpc.angel.dto.InsuranceDTO; import cn.fw.valhalla.rpc.erp.dto.PostUserDTO; import cn.fw.valhalla.rpc.erp.dto.UserRoleDataRangeDTO; import cn.fw.valhalla.rpc.member.MemberRpcService; import cn.fw.valhalla.rpc.member.dto.MemberUserDTO; import cn.fw.valhalla.rpc.oop.dto.ShopDTO; import cn.fw.valhalla.rpc.passport.PassportService; import cn.fw.valhalla.sdk.enums.CarUseTypeEnum; import cn.fw.valhalla.sdk.enums.GenderEnum; import cn.fw.valhalla.sdk.param.ChangeAdviserReq; import cn.fw.valhalla.service.data.AffiliationRecordService; import cn.fw.valhalla.service.data.CustomerCluePoolService; import cn.fw.valhalla.service.data.FollowTaskService; import cn.fw.valhalla.service.data.PublicPoolService; import cn.fw.valhalla.service.event.CustomerDefeatedEvent; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import java.time.LocalDateTime; import java.util.*; import static cn.fw.common.businessvalidator.Validator.BV; /** * @author : kurisu * @className : CustomerChangeBizService * @description : 档案变更服务 * @date: 2020-08-12 11:23 */ @Slf4j @Service @RequiredArgsConstructor public class CustomerChangeBizService extends AbstractCustomerService { public final String CUSTOMER_CHANGE_CODE = "valhalla:customer:change:key:{0}:{1}"; private final RedisUtil redisUtil; /** * 会员服务 */ private final PassportService passportService; private final MemberRpcService memberRpcService; private final FollowTaskService followTaskService; private final CustomerCluePoolService customerCluePoolService; private final AffiliationRecordService affiliationRecordService; private final PublicPoolService publicPoolService; private final ApplicationEventPublisher eventPublisher; /** * 生成档案变更二维码 * * @param user * @param customerChangeDto * @return */ public CustomerChangeQrCodeVO createQrCode(LoginAuthBean user, CustomerChangeDto customerChangeDto) { String plateNo = customerChangeDto.getPlateNo(); String vin = customerChangeDto.getFrameNo(); ShopDTO shopDTO = queryDealId(user.getUserId(), RoleCode.FWGW); BV.notNull(shopDTO, () -> "用户权限不正确"); if (customerChangeDto.getId() == null) { customerChangeDto.setGroupId(shopDTO.getGroupId()); customerChangeDto.setDealerId(shopDTO.getDealerId()); customerChangeDto.setShopId(shopDTO.getId()); customerChangeDto.setAdviserId(user.getUserId()); } else { Customer cust = customerService.queryById(customerChangeDto.getId()); customerChangeDto.setGroupId(cust.getGroupId()); customerChangeDto.setDealerId(shopDTO.getDealerId()); customerChangeDto.setShopId(cust.getShopId()); customerChangeDto.setAdviserId(cust.getAdviserId()); customerChangeDto.setModelCode(cust.getSpecCode()); } String str = plateNo + vin + user.getUserId(); String key = MessageFormatUtil.MessageFormatTransfer(CUSTOMER_CHANGE_CODE, customerChangeDto.getShopId(), str); try { String customerString = JSON.toJSONString(customerChangeDto); boolean flag = redisUtil.lock(key, 1000 * 15); BV.isTrue(flag, "重复操作,请稍后重试"); int expires = 60 * 30; String s = redisUtil.STRINGS.setEx(key, expires, customerString); BV.isTrue(StringUtils.isValid(s), "操作失败,请稍后重试"); String code = createCode(key, expires, customerChangeDto.getDealerId()); return new CustomerChangeQrCodeVO(code, key); } finally { redisUtil.unlock(key); } } /** * 根据主键查询档案信息 * * @param customerId * @return */ public CustomerChangeInfoVO mpGetById(Long customerId) { final CustomerChangeInfoVO detailVO = new CustomerChangeInfoVO(); Customer customer = customerService.queryById(customerId); if (customer == null) { return null; } CustomerDetailDto customerDetailDto = renderDto(customer); BeanUtils.copyProperties(customerDetailDto, detailVO); detailVO.setId(customer.getId()); Optional dtoOptional = queryInsuInfo(customerId); dtoOptional.ifPresent(t -> { detailVO.setInsurCompanyId(t.getInsurerId()); detailVO.setInsurCompanyName(t.getInsurerName()); detailVO.setInsurExpireDate(t.getExpiryDate()); }); return detailVO; } /** * 用户维护的基础信息查询 * * @param user * @param key * @return */ public CustomerChangeInfoVO getInfo(PassportAuthBean user, String key) { String s = redisUtil.STRINGS.get(key); BV.isTrue(StringUtils.isValid(s), "二维码已失效"); CustomerChangeDto dto = JSON.parseObject(s, CustomerChangeDto.class); final CustomerChangeInfoVO vo = new CustomerChangeInfoVO(); BeanUtils.copyProperties(dto, vo); MemberUserDTO userDto = memberRpcService.user(user.getUserId()); if (userDto != null) { vo.setMobile(userDto.getPhone()); } this.sendMsg(vo.getAdviserId(), false, key); return vo; } /** * 档案修改 * * @param saveDto * @return */ @Transactional(rollbackFor = Exception.class) public Long updateOrSave(PassportAuthBean user, CustomerChangeDto saveDto) { final String key = saveDto.getKey(); final Long adviserId = saveDto.getAdviserId(); saveDto.setMemberId(user.getUserId()); Long nid; CustomerBaseInfo baseInfo = new CustomerBaseInfo(); BeanUtils.copyProperties(saveDto, baseInfo); baseInfo.setId(null); baseInfo.setGender(GenderEnum.ofValue(saveDto.getGender())); baseInfo.setUpdateTime(new Date()); //客户主动修改信息 if (StringUtils.isEmpty(key)) { Customer customer = customerService.queryById(saveDto.getId()); baseInfo.setId(customer.getBaseId()); customerBaseInfoService.updateById(baseInfo); return customer.getId(); } //车牌号有档案 if (Objects.nonNull(saveDto.getMotoId())) { //vin有档案 if (Objects.nonNull(saveDto.getId())) { //档案和行驶证不一致 作废旧档案 更新档案 boolean bool = saveDto.getId().equals(saveDto.getMotoId()); if (!bool) { stammkundePoolService.reject(saveDto.getId(), saveDto.getGroupId()); customerService.forbidden(saveDto.getMotoId()); } Customer customer = customerService.queryById(saveDto.getId()); BV.notNull(customer, "档案信息异常"); baseInfo.setId(customer.getBaseId()); customerBaseInfoService.updateById(baseInfo); BeanUtils.copyProperties(saveDto, customer); customer.setUseType(CarUseTypeEnum.ofValue(saveDto.getUseType())); customer.setUpdateTime(new Date()); customer.setYn(Boolean.TRUE); nid = this.edit(customer); } else { stammkundePoolService.reject(saveDto.getId(), saveDto.getGroupId()); customerService.forbidden(saveDto.getMotoId()); Customer customer = new Customer(); BeanUtils.copyProperties(saveDto, customer); customer.setUseType(CarUseTypeEnum.ofValue(saveDto.getUseType())); customer.setSpecCode(saveDto.getModelCode()); nid = create(customer, baseInfo); } } else { //vin有档案 行驶证车主和vin档案车主一致的情况app直接替换车牌不会到这个流程 if (Objects.nonNull(saveDto.getId())) { stammkundePoolService.reject(saveDto.getId(), saveDto.getGroupId()); customerService.forbidden(saveDto.getId()); saveDto.setId(null); } Customer customer = new Customer(); BeanUtils.copyProperties(saveDto, customer); customer.setUseType(CarUseTypeEnum.ofValue(saveDto.getUseType())); customer.setSpecCode(saveDto.getModelCode()); nid = create(customer, baseInfo); if (Objects.nonNull(saveDto.getId())) { changeTaskFollower(saveDto.getMotoId(), customer.getId(), customer.getGroupId()); } } if (StringUtils.isValid(key)) { redisUtil.KEYS.del(key); this.sendMsg(adviserId, true, key); } return nid; } /** * 变更档案标签 * * @param cusId * @param tags * @return */ @Transactional(rollbackFor = Exception.class) public int updateTagById(Long cusId, String tags) { Customer customer = customerService.queryById(cusId); BV.notNull(customer, "档案信息异常"); customer.setTags(tags); customer.setUpdateTime(new Date()); int updateCount = customerService.getBaseMapper().updateById(customer); if (updateCount > 0) { customerChangeHandler(customer); } return updateCount; } /** * 更新保有客专属服务顾问 * * @param changeAdviserReq 新的服务顾问 * @return 是否成功 */ @Transactional(rollbackFor = Exception.class) public Boolean changeAdviser(ChangeAdviserReq changeAdviserReq) { Customer customer = customerService.queryById(changeAdviserReq.getCusId()); if (Objects.isNull(customer)) { return true; } Long adviserId = changeAdviserReq.getAdviserId(); if (adviserId.equals(customer.getAdviserId())) { return true; } List dataRange = userService.getUserRoleDataRange(adviserId, RoleCode.FWGW); if (CollectionUtils.isEmpty(dataRange) || Objects.isNull(dataRange.get(0).getRangeValue())) { return true; } Long shopId = dataRange.get(0).getRangeValue(); boolean updated = customerService.update(Wrappers.lambdaUpdate() .set(Customer::getAdviserId, adviserId) .set(Customer::getShopId, shopId) .eq(Customer::getId, changeAdviserReq.getCusId())); BV.isTrue(updated, () -> "变更档案服务顾问失败,请重试"); if (Objects.nonNull(customer.getAdviserId()) && Objects.nonNull(customer.getShopId())) { AffiliationRecord entity = createEntity(customer, adviserId, shopId); entity.setReason(DefeatReasonEnum.SYS.getName()); affiliationRecordService.save(entity); StammkundePool pool = stammkundePoolService.getOne(Wrappers.lambdaQuery() .eq(StammkundePool::getCustomerId, customer.getId()) .eq(StammkundePool::getGroupId, customer.getGroupId()) .eq(StammkundePool::getAdviserId, customer.getAdviserId()) .eq(StammkundePool::getAktiv, Boolean.TRUE) ); if (Objects.nonNull(pool)) { stammkundePoolService.reject(customer.getId(), customer.getGroupId()); } } if (Objects.isNull(customer.getAdviserId()) && Objects.isNull(customer.getShopId())) { publicPoolService.removeByCustomerId(customer.getId(), customer.getGroupId()); create(customer, adviserId, true); } return updated; } /** * 二次分配更换跟进人 * * @param task * @return */ @Transactional(rollbackFor = Exception.class) public StammkundePool changeFollowUser(FollowTask task) throws BusinessException { Customer customer = customerService.getById(task.getCustomerId()); if (Objects.isNull(customer)) { log.info("档案信息异常,custId: [{}]", task.getCustomerId()); } BV.notNull(customer, () -> "档案信息不存在"); List userList = userService.getUserByRole(customer.getShopId(), RoleCode.FWGW); BV.isNotEmpty(userList, () -> "更换跟进人员失败:没有更多服务顾问"); Collections.shuffle(userList); PostUserDTO userDTO = userList.get(0); boolean bool = userDTO.getId().equals(task.getFinishUser()) && userList.size() <= 1; if (bool) { return null; } if (userDTO.getId().equals(task.getFinishUser())) { userDTO = userList.get(1); } customer.setAdviserId(userDTO.getUserId()); customer.setShopId(customer.getShopId()); customerService.updateById(customer); AffiliationRecord entity = createEntity(customer, userDTO.getUserId(), customer.getShopId()); entity.setReason(DefeatReasonEnum.OVERDUE.getName()); affiliationRecordService.save(entity); StammkundePool stammkundePool = rejectAndNew(customer, userDTO.getUserId()); stammkundePool.setSources(StammkundeSourcesEnum.REDISTRIBUTION); stammkundePool.setPoolStatus(StammkundeStatusEnum.TWICE); stammkundePool.setAktiv(Boolean.FALSE); stammkundePool.setCreateTime(new Date()); stammkundePool.setGroupId(customer.getGroupId()); stammkundePoolService.save(stammkundePool); eventPublisher.publishEvent(new CustomerDefeatedEvent(task.getClueId(), task.getCustomerId(), task.getType())); return stammkundePool; } /** * 更换跟进人 * * @param task * @return */ @Transactional(rollbackFor = Exception.class) public PostUserDTO changeInsFollowUser(FollowTask task) throws BusinessException { Customer customer = customerService.getById(task.getCustomerId()); if (Objects.isNull(customer)) { log.info("档案信息异常,custId: [{}]", task.getCustomerId()); } BV.notNull(customer, () -> "档案信息不存在"); List userList = userService.getUserByRole(task.getFinishUser(), RoleCode.XBGJ); BV.isNotEmpty(userList, () -> "更换跟进人员失败:没有更多续保跟进员"); Collections.shuffle(userList); PostUserDTO userDTO = userList.get(0); boolean bool = userDTO.getId().equals(task.getFollowUser()) && userList.size() <= 0; if (bool) { return null; } if (userDTO.getId().equals(task.getFollowUser())) { userDTO = userList.get(1); } return userDTO; } /** * 修改档案 * * @param customer * @return */ private Long edit(Customer customer) { boolean updated = customerService.updateById(customer); if (updated) { customerChangeHandler(customer); } return customer.getId(); } private String createCode(String key, int expires, Long dealerId) { final WxBCodeParam param = new WxBCodeParam(); final Map map = new HashMap<>(1); map.put("customerKey", key); param.setParam(map); param.setPage("pgCas/CarArchives/index"); param.setExpires(expires); param.setDealerId(dealerId); final byte[] bytes = passportService.getWxBCode(param); if (Objects.isNull(bytes)) { return null; } return QRCodeKit.byte2Base64String(bytes); } /** * 消息发送 * * @param targetUserId * @param done */ private void sendMsg(Long targetUserId, boolean done, String key) { try { String text = "档案变更通知"; Map ext = new HashMap<>(3); ext.put("type", MessageBusinessType.CUSTOMER_CHANGE_STATUS.getMsg()); ext.put("done", done); ext.put("key", key); final MsgPara msgPara = MsgPara.getCustomMsg(text, "", ext, 0, targetUserId, false).setBusinessType(BusinessType.INTERNAL_NOTIFICATION).build(); final Message msg = imSendMessage.sendMsg(msgPara); log.info("给[{}]推送im消息结果:[{}]", targetUserId, msg.getResult()); } catch (Exception e) { e.printStackTrace(); } } private void changeTaskFollower(Long motoId, Long curId, Long groupId) { CustomerCluePool cluePool = customerCluePoolService.queryByRefererId(motoId, groupId, FollowTypeEnum.FM); if (Objects.nonNull(cluePool)) { boolean equals = ClueStatusEnum.ONGOING.equals(cluePool.getClueStatus()) || ClueStatusEnum.WAITING.equals(cluePool.getClueStatus()); if (equals) { cluePool.setRefererId(curId); customerCluePoolService.updateById(cluePool); } } cluePool = customerCluePoolService.queryByRefererId(motoId, groupId, FollowTypeEnum.RM); if (Objects.nonNull(cluePool)) { boolean equals = ClueStatusEnum.ONGOING.equals(cluePool.getClueStatus()) || ClueStatusEnum.WAITING.equals(cluePool.getClueStatus()); if (equals) { cluePool.setRefererId(curId); customerCluePoolService.updateById(cluePool); } } cluePool = customerCluePoolService.queryByRefererId(motoId, groupId, FollowTypeEnum.IR); if (Objects.nonNull(cluePool)) { boolean equals = ClueStatusEnum.ONGOING.equals(cluePool.getClueStatus()) || ClueStatusEnum.WAITING.equals(cluePool.getClueStatus()); if (equals) { cluePool.setRefererId(curId); customerCluePoolService.updateById(cluePool); } } List list = followTaskService.getListByCustomerId(motoId, null); if (CollectionUtils.isEmpty(list)) { return; } list.forEach(r -> r.setCustomerId(curId)); followTaskService.updateBatchById(list); } private void create(Customer customer, Long adviserId, boolean publicPool) { StammkundePool stammkundePool = rejectAndNew(customer, adviserId); stammkundePool.setSources(StammkundeSourcesEnum.SYSTEMATIC); if (publicPool) { stammkundePool.setSources(StammkundeSourcesEnum.PUBLIC_POOL); } stammkundePool.setPoolStatus(StammkundeStatusEnum.KUNDE); stammkundePool.setAktiv(Boolean.TRUE); stammkundePool.setActivationTime(new Date()); stammkundePool.setCreateTime(new Date()); stammkundePoolService.save(stammkundePool); } private AffiliationRecord createEntity(Customer customer, Long adviserId, Long shopId) { AffiliationRecord record = new AffiliationRecord(); record.setCustomerId(customer.getId()); record.setType(CustomerChangeTypeEnum.DEFEAT); record.setDefeatTime(DateUtil.localDateTime2Date(LocalDateTime.now())); record.setOriginUserId(customer.getAdviserId()); record.setOriginShopId(customer.getShopId()); record.setCurUserId(adviserId); record.setCurShopId(shopId); record.setCreateTime(DateUtil.localDateTime2Date(LocalDateTime.now())); return record; } }