# BadGuestApproveLevelServiceImpl.java

    package cloud.wconnect.frontoffice.service.badguest.impl;

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.EmailConfigCons;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.pojo.bo.PropertyBO;
    import cloud.wconnect.commonlib.pojo.dto.UserDTO;
    import cloud.wconnect.commonlib.pojo.dto.UsergroupDTO;
    import cloud.wconnect.commonlib.service.UserInternalService;
    import cloud.wconnect.commonlib.service.UsergroupInternalService;
    import cloud.wconnect.commonlib.util.JsonUtils;
    import cloud.wconnect.commonlib.util.TransactionUtils;
    import cloud.wconnect.frontoffice.cons.ApproveCons;
    import cloud.wconnect.frontoffice.cons.badguest.BlacklistApproveStatusEnum;
    import cloud.wconnect.frontoffice.entity.badguest.BadGuest;
    import cloud.wconnect.frontoffice.entity.badguest.BadGuestApproveConfig;
    import cloud.wconnect.frontoffice.entity.badguest.BadGuestApproveLevel;
    import cloud.wconnect.frontoffice.entity.badguest.BadGuestApproveLog;
    import cloud.wconnect.frontoffice.mapper.badguest.BadGuestApproveLevelMapper;
    import cloud.wconnect.frontoffice.pojo.dto.badguest.ApproveUser;
    import cloud.wconnect.frontoffice.pojo.dto.badguest.BadGuestApproveLevelDTO;
    import cloud.wconnect.frontoffice.pojo.dto.badguest.BgApproveCCDTO;
    import cloud.wconnect.frontoffice.service.badguest.*;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.google.common.collect.Lists;
    import org.apache.commons.collections.CollectionUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Lazy;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.util.*;
    import java.util.concurrent.Executor;
    import java.util.stream.Collectors;

    import static java.util.stream.Collectors.*;

    /**
     * <p>
     * 服务实现类
     * </p>
     *
     * @author lichen
     * @since 2023-03-21
     */
    @Service
    @DS("logbook")
    public class BadGuestApproveLevelServiceImpl extends ServiceImpl<BadGuestApproveLevelMapper, BadGuestApproveLevel> implements IBadGuestApproveLevelService {

        @Autowired
        private IBadGuestApproveConfigService badGuestApproveConfigService;
        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        @Lazy
        private IBadGuestService badGuestService;
        @Autowired
        private IBadGuestApproveLogService badGuestApproveLogService;
        @Autowired
        private BadGuestApproveLevelMapper badGuestApproveLevelMapper;
        @Autowired
        private UserInternalService userInternalService;
        @Autowired
        @Lazy
        private IBadGuestNotifyService badGuestNotifyService;
        @Autowired
        private Executor executor;
        @Autowired
        private ObjectMapper objectMapper;
        @Autowired
        private UsergroupInternalService usergroupInternalService;

        /**
         * 查询资产下的审批配置信息
         *
         * @param tenantId   租户id
         * @param propertyId 资产id
         * @return java.util.List<cloud.wconnect.frontoffice.pojo.dto.badguest.BadGuestApproveLevelDTO>
         * @author lichen
         * @date 2025/8/26
         */
        @Override
        public List<BadGuestApproveLevelDTO> list(Integer tenantId, int propertyId) {
            //查询approve level 信息
            LambdaQueryWrapper<BadGuestApproveLevel> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(BadGuestApproveLevel::getPropertyId, propertyId);
            queryWrapper.orderByAsc(BadGuestApproveLevel::getId);
            List<BadGuestApproveLevel> levelList = list(queryWrapper);
            if (CollectionUtils.isEmpty(levelList)) {
                return Collections.emptyList();
            }

            //查询approve config信息
            List<Long> levelIds = levelList.stream().map(BadGuestApproveLevel::getId).collect(Collectors.toList());
            List<BadGuestApproveConfig> configList = badGuestApproveConfigService.listByLevelIds(propertyId, levelIds);

            //用户信息
            List<Integer> userIdsByApproveConfig = configList.stream().map(BadGuestApproveConfig::getUserId).toList();
            Map<Long, List<Integer>> levelId2UserIds = configList.stream()
                    .collect(groupingBy(BadGuestApproveConfig::getLevelId, mapping(BadGuestApproveConfig::getUserId, toList())));

            //抄送人集合
            List<BgApproveCCDTO> approveCCList = levelList.stream()
                    .filter(approveLevel -> StringUtils.isNotBlank(approveLevel.getCc()) && !approveLevel.getCc().equals("[]"))
                    .map(item -> JsonUtils.convertStringToList(objectMapper, item.getCc(), BgApproveCCDTO.class))
                    .flatMap(Collection::stream)
                    .toList();
            //按照用户来源分组
            Map<Integer, List<Integer>> source2IdentityIdList = approveCCList.stream()
                    .collect(Collectors.groupingBy(BgApproveCCDTO::getSource, Collectors.mapping(BgApproveCCDTO::getIdentityId, Collectors.toList())));

            //用户集合
            List<Integer> allUserIds = new ArrayList<>();
            allUserIds.addAll(source2IdentityIdList.getOrDefault(EmailConfigCons.SOURCE_USER, Collections.emptyList()));
            allUserIds.addAll(userIdsByApproveConfig);
            Map<Integer, UserDTO> userId2UserDTO = userInternalService.getUserMapByIds(tenantId, allUserIds);

            //用户组集合
            Map<Integer, String> usergroupId2Name = usergroupInternalService.getUsergroups(tenantId, propertyId,
                            source2IdentityIdList.getOrDefault(EmailConfigCons.SOURCE_USERGROUP, Collections.emptyList()))
                    .stream().collect(Collectors.toMap(UsergroupDTO::getId, UsergroupDTO::getName));
            return beanMapper.mapList(levelList, BadGuestApproveLevelDTO.class, (entity, dto) -> {
                //审批人集合
                List<ApproveUser> approveUsers = levelId2UserIds.getOrDefault(dto.getId(), Collections.emptyList()).stream()
                        .map(userId -> beanMapper.map(userId2UserDTO.get(userId), ApproveUser.class))
                        .toList();
                dto.setUsers(approveUsers);

                //抄送人集合
                String cc = entity.getCc();
                if (StringUtils.isNotBlank(cc)) {
                    List<BgApproveCCDTO> approveCCDTOS = JsonUtils.convertStringToList(objectMapper, cc, BgApproveCCDTO.class);
                    for (BgApproveCCDTO approveCCDTO : approveCCDTOS) {
                        Integer source = approveCCDTO.getSource();
                        Integer identityId = approveCCDTO.getIdentityId();
                        switch (source) {
                            case EmailConfigCons.SOURCE_USER:
                                UserDTO userDTO = userId2UserDTO.get(identityId);
                                if (Objects.nonNull(userDTO)) {
                                    approveCCDTO.setIdentityName(userDTO.getName());
                                    approveCCDTO.setEmail(userDTO.getEmail());
                                }
                                break;
                            case EmailConfigCons.SOURCE_USERGROUP:
                                approveCCDTO.setIdentityName(usergroupId2Name.get(identityId));
                                break;
                            default:
                                break;
                        }
                    }
                    dto.setCcList(approveCCDTOS);
                } else {
                    dto.setCcList(Collections.emptyList());
                }
            });
        }

        @Override
        @Transactional(rollbackFor = Exception.class)
        public void insert(BadGuestApproveLevelDTO badGuestApproveLevelDTO) {
            //查询最大的index
            Integer maxIndex = badGuestApproveLevelMapper.getMaxIndexForUpdate(badGuestApproveLevelDTO.getPropertyId());
            if (Objects.isNull(maxIndex)) {
                badGuestApproveLevelDTO.setApproveIndex(1);
            } else {
                //设置index = maxIndex + 1
                badGuestApproveLevelDTO.setApproveIndex(++maxIndex);
            }
            //新增approve level
            BadGuestApproveLevel badGuestApproveLevel = beanMapper.map(badGuestApproveLevelDTO, BadGuestApproveLevel.class, entity -> {
                if (CollectionUtils.isNotEmpty(badGuestApproveLevelDTO.getCcList())) {
                    entity.setCc(JsonUtils.convertObjListToString(objectMapper, badGuestApproveLevelDTO.getCcList()));
                } else {
                    entity.setCc("[]");
                }
            });
            save(badGuestApproveLevel);
            //批量新增approve config
            saveBatchApproveConfig(badGuestApproveLevelDTO.getUsers(), badGuestApproveLevel);
        }

        @Override
        @Transactional(rollbackFor = Exception.class)
        public void update(BadGuestApproveLevel oriApprove, BadGuestApproveLevelDTO badGuestApproveLevelDTO) {
            if (!Objects.equals(oriApprove.getRule(), badGuestApproveLevelDTO.getRule()) && badGuestApproveLevelDTO.getRule() == ApproveCons.RULE_ANY) {
                //审批规则由全部 改为 任一 时：当前节点已经有任一人审核过时，推送数据至下一个节点审核
                pushNextIndex(oriApprove, ApproveCons.PUSH_TP_UPDATE_RULE, Collections.emptyList());
            }
            //审批规则是全部时，变更了审批人数量，需要判断是否推送至下一个节点审核
            if (Objects.equals(oriApprove.getRule(), badGuestApproveLevelDTO.getRule()) && badGuestApproveLevelDTO.getRule() == ApproveCons.RULE_ALL) {
                //更新后的审批配置
                List<ApproveUser> approveUsers = badGuestApproveLevelDTO.getUsers();
                List<Integer> updApproveUserIds = approveUsers.stream().map(ApproveUser::getId).collect(toList());
                pushNextIndex(oriApprove, ApproveCons.PUSH_TP_UPDATE_USER, updApproveUserIds);
            }
            //修改approve level
            BadGuestApproveLevel badGuestApproveLevel = beanMapper.map(badGuestApproveLevelDTO, BadGuestApproveLevel.class, entity -> {
                if (CollectionUtils.isNotEmpty(badGuestApproveLevelDTO.getCcList())) {
                    entity.setCc(JsonUtils.convertObjListToString(objectMapper, badGuestApproveLevelDTO.getCcList()));
                } else {
                    entity.setCc("[]");
                }
            });
            updateById(badGuestApproveLevel);
            //批量删除当前节点下的审核人
            LambdaQueryWrapper<BadGuestApproveConfig> removeWrapper = new LambdaQueryWrapper<>();
            removeWrapper.eq(BadGuestApproveConfig::getPropertyId, oriApprove.getPropertyId());
            removeWrapper.eq(BadGuestApproveConfig::getLevelId, oriApprove.getId());
            badGuestApproveConfigService.remove(removeWrapper);
            //批量新增当前节点下的审核人
            List<ApproveUser> users = badGuestApproveLevelDTO.getUsers();
            saveBatchApproveConfig(users, badGuestApproveLevel);
        }

        @Override
        @Transactional(rollbackFor = Exception.class)
        public void remove(BadGuestApproveLevel oriApprove) {
            //推送待审核的数据至下一个节点
            pushNextIndex(oriApprove, ApproveCons.PUSH_TP_DELETE, Collections.emptyList());
            //删除approve level
            removeById(oriApprove.getId());
            //删除approve config
            LambdaQueryWrapper<BadGuestApproveConfig> removeWrapper = new LambdaQueryWrapper<>();
            removeWrapper.eq(BadGuestApproveConfig::getLevelId, oriApprove.getId());
            removeWrapper.eq(BadGuestApproveConfig::getPropertyId, oriApprove.getPropertyId());
            badGuestApproveConfigService.remove(removeWrapper);
        }

        @Override
        public BadGuestApproveLevel getByIndexAndPropertyId(int index, int propertyId) {
            LambdaQueryWrapper<BadGuestApproveLevel> approveLevelQueryWrapper = new LambdaQueryWrapper<>();
            approveLevelQueryWrapper.eq(BadGuestApproveLevel::getPropertyId, propertyId);
            approveLevelQueryWrapper.eq(BadGuestApproveLevel::getApproveIndex, index);
            approveLevelQueryWrapper.last("limit 1");
            return getOne(approveLevelQueryWrapper);
        }

        /**
         * 查询审批层级
         *
         * @param propertyId 资产id
         * @return java.util.List<cloud.wconnect.frontoffice.entity.badguest.BadGuestApproveLevel>
         * @author lichen
         * @date 2023/9/9
         */
        @Override
        public List<BadGuestApproveLevel> listByPropertyId(Integer propertyId) {
            return list(new LambdaQueryWrapper<BadGuestApproveLevel>()
                    .eq(BadGuestApproveLevel::getPropertyId, propertyId)
                    .orderByAsc(BadGuestApproveLevel::getApproveIndex));
        }

        /**
         * 获取资产配置的第一层审批层级
         *
         * @param propertyId 资产id
         * @return cloud.wconnect.frontoffice.entity.badguest.BadGuestApproveLevel
         * @author lichen
         * @date 2025/5/19
         */
        @Override
        public BadGuestApproveLevel getFirstApproveLevelByPropertyId(Integer propertyId) {
            return getOne(new LambdaQueryWrapper<BadGuestApproveLevel>()
                    .eq(BadGuestApproveLevel::getPropertyId, propertyId)
                    .orderByAsc(BadGuestApproveLevel::getApproveIndex)
                    .last("limit 1"));
        }

        /**
         * 获取上一个审批级别
         *
         * @param approveLevel 审批级别
         * @return cloud.wconnect.frontoffice.entity.badguest.BadGuestApproveLevel
         * @author lichen
         * @date 2025/6/11
         */
        @Override
        public BadGuestApproveLevel getPrevApproveLevel(BadGuestApproveLevel approveLevel) {
            return getOne(new LambdaQueryWrapper<BadGuestApproveLevel>()
                    .eq(BadGuestApproveLevel::getPropertyId, approveLevel.getPropertyId())
                    .lt(BadGuestApproveLevel::getApproveIndex, approveLevel.getApproveIndex())
                    .orderByDesc(BadGuestApproveLevel::getApproveIndex)
                    .last("limit 1"));
        }

        /**
         * @param users
         * @param badGuestApproveLevel
         * @return void
         * @description 批量新增approve config
         * @author lichen
         * @date 2023/3/21 15:36
         */
        private void saveBatchApproveConfig(List<ApproveUser> users, BadGuestApproveLevel badGuestApproveLevel) {
            List<BadGuestApproveConfig> approvedConfigs = users.stream().map(user -> BadGuestApproveConfig.builder()
                    .levelId(badGuestApproveLevel.getId())
                    .approveIndex(badGuestApproveLevel.getApproveIndex())
                    .userId(user.getId())
                    .propertyId(badGuestApproveLevel.getPropertyId())
                    .build()
            ).collect(toList());
            badGuestApproveConfigService.saveBatch(approvedConfigs);
        }

        /**
         * @param oriApprove        更新前的审核配置
         * @param type              1: 删除某一节点时推送 2.修改某一节点规则，由全部改为任一时推送 3.节点规则是全部时，删除某一节点上的人员时推送
         * @param updApproveUserIds 更新后的审批配置
         * @return void
         * @description 推送数据至下一个节点审核
         * @author lichen
         * @date 2023/3/21 17:06
         */
        private void pushNextIndex(BadGuestApproveLevel oriApprove, int type, List<Integer> updApproveUserIds) {
            //查询当前节点下待审核的数据
            LambdaQueryWrapper<BadGuest> badGuestLambdaQueryWrapper = new LambdaQueryWrapper<>();
            badGuestLambdaQueryWrapper.eq(BadGuest::getPropertyId, oriApprove.getPropertyId());
            badGuestLambdaQueryWrapper.eq(BadGuest::getApproveIndex, oriApprove.getApproveIndex());
            badGuestLambdaQueryWrapper.eq(BadGuest::getApproveStatus, BlacklistApproveStatusEnum.APPROVEING.getStatus());
            badGuestLambdaQueryWrapper.orderByDesc(BadGuest::getId);
            List<BadGuest> badGuests = badGuestService.list(badGuestLambdaQueryWrapper);
            //数据为空时，直接return
            if (CollectionUtils.isEmpty(badGuests)) return;

            //过滤待推送的数据
            List<BadGuest> pushList = this.filter(badGuests, oriApprove, type, updApproveUserIds);
            if (CollectionUtils.isEmpty(pushList)) return;

            //查询下一个节点
            LambdaQueryWrapper<BadGuestApproveLevel> badGuestApproveLevelQueryWrapper = new LambdaQueryWrapper<>();
            badGuestApproveLevelQueryWrapper.eq(BadGuestApproveLevel::getPropertyId, oriApprove.getPropertyId());
            badGuestApproveLevelQueryWrapper.gt(BadGuestApproveLevel::getApproveIndex, oriApprove.getApproveIndex());
            badGuestApproveLevelQueryWrapper.orderByAsc(BadGuestApproveLevel::getApproveIndex);
            badGuestApproveLevelQueryWrapper.last("limit 1");
            BadGuestApproveLevel nextIndexApprove = getOne(badGuestApproveLevelQueryWrapper);
            if (Objects.isNull(nextIndexApprove)) {
                //批量更新数据为审核结束
                pushList.forEach(badGuest -> badGuest.setApproveStatus(BlacklistApproveStatusEnum.APPROVED.getStatus()));

                /*
                 * 删除审批层级时，如果黑名单数据在被删除的层级上没有人审批时，则回退到上一个审批节点
                 * 当没有上一个审批节点时，approveIndex置为0
                 */
                if (type == ApproveCons.PUSH_TP_DELETE) {
                    //查询上一个层级
                    BadGuestApproveLevel prevApproveLevel = getPrevApproveLevel(oriApprove);
                    int prevApproveIndex = Objects.isNull(prevApproveLevel) ? 0 : prevApproveLevel.getApproveIndex();

                    //查询黑名单数据在当前审批层级下的审批记录
                    List<Long> batchIds = pushList.stream().map(BadGuest::getBatchId).collect(toList());
                    Map<Long, List<BadGuestApproveLog>> badGuestId2ApprovedLogs = badGuestApproveLogService.listApprovedLogs(batchIds, oriApprove);

                    pushList.forEach(badGuest -> {
                        //如果没有审批记录，则回退到上一个审批层级
                        if (CollectionUtils.isEmpty(badGuestId2ApprovedLogs.get(badGuest.getId()))) {
                            badGuest.setApproveIndex(prevApproveIndex);
                        }
                    });
                }

                badGuestService.saveOrUpdateBatch(pushList);
                //发送给创建人
                TransactionUtils.afterCommitAsyncExecute(executor, () -> {
                    badGuestNotifyService.batchNotifyCreateByByApproved(pushList);
                });
            } else {
                //批量推送数据至下一个审核节点
                pushList.forEach(badGuest -> badGuest.setApproveIndex(nextIndexApprove.getApproveIndex()));
                badGuestService.saveOrUpdateBatch(pushList);
                //查询下一个审批层级的审批人
                List<Integer> nextApproveIndexUserIds = badGuestApproveConfigService.listByLevelIds(nextIndexApprove.getPropertyId(), Lists.newArrayList(nextIndexApprove.getId()))
                        .stream().map(BadGuestApproveConfig::getUserId).toList();
                //发送给审批人
                TransactionUtils.afterCommitAsyncExecute(executor, () -> {
                    badGuestNotifyService.notifyNextApproveUsers(oriApprove.getPropertyId(), nextApproveIndexUserIds, pushList, nextIndexApprove.getCc());
                });

            }
        }

        /**
         * @param badGuests         待推送的数据
         * @param oriApprove        原审批配置
         * @param type              推送类型
         * @param updApproveUserIds 更新后的审批配置
         * @return java.util.List<cloud.wconnect.frontoffice.entity.badguest.BadGuest>
         * @description 过滤待推送的数据
         * @author lichen
         * @date 2023/3/22 14:47
         */
        private List<BadGuest> filter(List<BadGuest> badGuests, BadGuestApproveLevel oriApprove, int type, List<Integer> updApproveUserIds) {
            if (type == ApproveCons.PUSH_TP_DELETE) {
                return badGuests;
            } else if (type == ApproveCons.PUSH_TP_UPDATE_RULE) {
                //查询待审核数据 在当前节点下对应的审核日志信息
                List<Long> batchIds = badGuests.stream().map(BadGuest::getBatchId).collect(toList());
                Map<Long, List<BadGuestApproveLog>> logMap = badGuestApproveLogService.listApprovedLogs(batchIds, oriApprove);
                //过滤出当前节点已经有人审批的数据
                return badGuests.stream()
                        .filter(badGuest -> CollectionUtils.isNotEmpty(logMap.get(badGuest.getId())))
                        .collect(toList());
            } else {
                //查询待审核数据 在当前节点下对应的审核日志信息
                List<Long> batchIds = badGuests.stream().map(BadGuest::getBatchId).collect(toList());
                Map<Long, List<BadGuestApproveLog>> logMap = badGuestApproveLogService.listApprovedLogs(batchIds, oriApprove);
                //当已审批的集合 包含 修改的审批人集合 时推送至下一个节点
                return badGuests.stream()
                        .filter(badGuest -> {
                                    //获取黑名单数据对应的已审批人集合
                                    List<BadGuestApproveLog> approveLogList = logMap.get(badGuest.getId());
                                    Set<Integer> approverList = new HashSet<>();
                                    if (CollectionUtils.isNotEmpty(approveLogList)) {
                                        approverList = approveLogList.stream().map(BadGuestApproveLog::getApproveBy).collect(toSet());
                                    }
                                    //过滤出《已审批人》包含《更新后的审批配置》的数据
                                    return approverList.containsAll(updApproveUserIds);
                                }
                        ).collect(toList());
            }
        }
    }