# AdjApproveLevelServiceImpl.java

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

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.ApproveStatusEnum;
    import cloud.wconnect.commonlib.cons.DataPermissionConfigConstant;
    import cloud.wconnect.commonlib.cons.EmailConfigCons;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.pojo.dto.UserDTO;
    import cloud.wconnect.commonlib.pojo.dto.UsergroupDTO;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.service.DataPermissionConfigInternalService;
    import cloud.wconnect.commonlib.service.UserInternalService;
    import cloud.wconnect.commonlib.service.UsergroupInternalService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.JsonUtils;
    import cloud.wconnect.commonlib.util.TransactionUtils;
    import cloud.wconnect.frontoffice.cons.ApproveCons;
    import cloud.wconnect.frontoffice.cons.adjustment.AdjConstant;
    import cloud.wconnect.frontoffice.cons.adjustment.AdjustmentStatusEnum;
    import cloud.wconnect.frontoffice.cons.adjustment.FlowStatusEnum;
    import cloud.wconnect.frontoffice.entity.adjustment.*;
    import cloud.wconnect.frontoffice.mapper.adjustment.AdjApproveLevelMapper;
    import cloud.wconnect.frontoffice.pojo.dto.adjustment.AdjApproveCCDTO;
    import cloud.wconnect.frontoffice.pojo.dto.adjustment.AdjApproveLevelDTO;
    import cloud.wconnect.frontoffice.pojo.dto.adjustment.AdjApproveUser;
    import cloud.wconnect.frontoffice.pojo.dto.adjustment.SubstitutePersonnelDTO;
    import cloud.wconnect.frontoffice.service.adjustment.*;
    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.ImmutableMap;
    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>
     * Adjustment Requests 审批层级表 服务实现类
     * </p>
     *
     * @author lichen
     * @since 2023-03-30
     */
    @Service
    @DS("logbook")
    public class AdjApproveLevelServiceImpl extends ServiceImpl<AdjApproveLevelMapper, AdjApproveLevel> implements IAdjApproveLevelService {

        @Autowired
        private IAdjApproveConfigService approveConfigService;
        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        @Lazy
        private IAdRequestService adRequestService;
        @Autowired
        private IAdjApproveLogService approveLogService;
        @Autowired
        private AdjApproveLevelMapper approveLevelMapper;
        @Autowired
        @Lazy
        private IAdjSendNotifyService adjSendEmailService;
        @Autowired
        private Executor executor;
        @Autowired
        private UserInternalService userInternalService;
        @Autowired
        private UsergroupInternalService usergroupInternalService;
        @Autowired
        private ObjectMapper objectMapper;
        @Autowired
        @Lazy
        private IAdjSenderService senderService;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;
        @Lazy
        @Autowired
        private IAdjOutOfOfficeConfigService adjOutOfOfficeConfigService;
        @Autowired
        private DataPermissionConfigInternalService dataPermissionConfigInternalService;
        @Autowired
        private IAdjApproveLogService adjApproveLogService;

        /**
         * 查询审批层级信息
         *
         * @param propertyId 资产id
         * @param type       调整类型
         * @return java.util.List<cloud.wconnect.frontoffice.pojo.dto.adjustment.AdjApproveLevelDTO>
         * @author lichen
         * @date 2024/3/11
         */
        @Override
        public List<AdjApproveLevelDTO> list(int propertyId, Integer type) {
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            Integer tenantId = propertyDTO.getTenantId();

            //查询approve level 信息
            LambdaQueryWrapper<AdjApproveLevel> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(AdjApproveLevel::getPropertyId, propertyId);
            queryWrapper.eq(AdjApproveLevel::getType, type);
            queryWrapper.orderByAsc(AdjApproveLevel::getId);
            List<AdjApproveLevel> levelList = list(queryWrapper);
            if (CollectionUtils.isEmpty(levelList)) {
                return Collections.emptyList();
            }

            //查询approve config信息
            List<AdjApproveConfig> configList = approveConfigService.listByLevelIds(propertyId,
                    levelList.stream().map(AdjApproveLevel::getId).toList());

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

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

            // 查询审批人员的补位人员配置
            List<AdjOutOfOfficeConfig> outOfOfficeConfigs = adjOutOfOfficeConfigService.listEffectiveConfig(propertyId, type, userIdsByApproveConfig);
            Map<Integer, AdjOutOfOfficeConfig> outOfOfficeConfigByApproveUserId = outOfOfficeConfigs.stream().collect(toMap(AdjOutOfOfficeConfig::getUpdatedBy, v -> v));

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

            // 查询用户审批权限
            Map<Integer, Boolean> hasPermissionByUserId = dataPermissionConfigInternalService.checkContainsApi(tenantId, propertyId,
                    ImmutableMap.of(DataPermissionConfigConstant.IDENTITY_TYPE_USER, new HashSet<>(allUserIds)),
                    DataPermissionConfigConstant.ADJ_APPROVE_API_ID).getOrDefault(DataPermissionConfigConstant.IDENTITY_TYPE_USER, Collections.emptyMap());

            //用户组集合
            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, AdjApproveLevelDTO.class, (entity, dto) -> {
                //审批人集合
                List<AdjApproveUser> approveUsers = levelId2UserIds.getOrDefault(dto.getId(), Collections.emptyList()).stream()
                        .map(userId -> {
                            // 设置审批人信息
                            UserDTO userDTO = userId2UserDTO.get(userId);
                            AdjApproveUser adjApproveUser = new AdjApproveUser();
                            adjApproveUser.setId(userId);
                            adjApproveUser.setName(userDTO.getName());
                            adjApproveUser.setEmail(userDTO.getEmail());
                            adjApproveUser.setPhone(userDTO.getPhone());
                            adjApproveUser.setAccount(userDTO.getAccount());
                            adjApproveUser.setAvatar(userDTO.getAvatar());
                            adjApproveUser.setStatus(!userDTO.getStatus() ? AdjConstant.USER_CLOSE :
                                    hasPermissionByUserId.getOrDefault(userId, false) ? AdjConstant.USER_EFFECTIVE : AdjConstant.USER_NO_PERMISSION);

                            // 设置补位人员信息
                            AdjOutOfOfficeConfig outOfOfficeConfig = outOfOfficeConfigByApproveUserId.get(userId);
                            if(Objects.nonNull(outOfOfficeConfig)){
                                SubstitutePersonnelDTO substitutePersonnelDTO = beanMapper.map(outOfOfficeConfig, SubstitutePersonnelDTO.class);
                                Integer substitutePersonnelId = outOfOfficeConfig.getSubstitutePersonnelId();
                                UserDTO substitutePersonnel = userId2UserDTO.get(substitutePersonnelId);
                                substitutePersonnelDTO.setSubstitutePersonnelName(substitutePersonnel.getName());
                                substitutePersonnelDTO.setSubstitutePersonnelStatus(!substitutePersonnel.getStatus() ? AdjConstant.USER_CLOSE :
                                        hasPermissionByUserId.getOrDefault(substitutePersonnelId, false) ? AdjConstant.USER_EFFECTIVE : AdjConstant.USER_NO_PERMISSION);
                                substitutePersonnelDTO.setSubstitutePersonnelEmail(substitutePersonnel.getEmail());
                                substitutePersonnelDTO.setSubstitutePersonnelAvatar(substitutePersonnel.getAvatar());
                                adjApproveUser.setSubstitutePersonnel(substitutePersonnelDTO);
                            }

                            return adjApproveUser;
                        } )
                        .toList();
                dto.setUsers(approveUsers);

                //抄送人集合
                String cc = entity.getCc();
                if (StringUtils.isNotBlank(cc)) {
                    List<AdjApproveCCDTO> approveCCDTOS = JsonUtils.convertStringToList(objectMapper, cc, AdjApproveCCDTO.class);
                    for (AdjApproveCCDTO 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());
                }
            });
        }

        /**
         * 新增审批层级
         *
         * @param adjApproveLevelDTO 审批层级DTO
         * @return void
         * @author lichen
         * @date 2024/3/11
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void insert(AdjApproveLevelDTO adjApproveLevelDTO) {
            //查询最大的index
            Integer maxIndex = approveLevelMapper.getMaxIndexForUpdate(adjApproveLevelDTO.getPropertyId(), adjApproveLevelDTO.getType());
            if (Objects.isNull(maxIndex)) {
                adjApproveLevelDTO.setApproveIndex(1);
            } else {
                //设置index = maxIndex + 1
                adjApproveLevelDTO.setApproveIndex(++maxIndex);
            }
            //新增approve level
            AdjApproveLevel adjApproveLevel = beanMapper.map(adjApproveLevelDTO, AdjApproveLevel.class, entity -> {
                if (CollectionUtils.isNotEmpty(adjApproveLevelDTO.getCcList())) {
                    entity.setCc(JsonUtils.convertObjListToString(objectMapper, adjApproveLevelDTO.getCcList()));
                }else{
                    entity.setCc("[]");
                }
            });
            save(adjApproveLevel);
            //批量新增approve config
            saveBatchApproveConfig(adjApproveLevelDTO.getUsers(), adjApproveLevel);
        }

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

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

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

        /**
         * 获取资产审批层级
         *
         * @param propertyId 资产id
         * @return 审批层级
         * @author yyt
         * @date 2026/3/25
         */
        @Override
        public List<AdjApproveLevel> listByPropertyId(Integer propertyId) {
            return list(new LambdaQueryWrapper<AdjApproveLevel>()
                    .eq(AdjApproveLevel::getPropertyId, propertyId));
        }

        /**
         * 查询资产的第一层审批级别
         *
         * @param propertyId 资产
         * @param type       类型
         * @return cloud.wconnect.frontoffice.entity.adjustment.AdjApproveLevel
         * @author lichen
         * @date 2024/1/29
         */
        @Override
        public AdjApproveLevel getFirstApproveLevel(Integer propertyId, Integer type) {
            LambdaQueryWrapper<AdjApproveLevel> approveLevelQueryWrapper = new LambdaQueryWrapper<>();
            approveLevelQueryWrapper.eq(AdjApproveLevel::getPropertyId, propertyId);
            approveLevelQueryWrapper.eq(AdjApproveLevel::getType, type);
            approveLevelQueryWrapper.orderByAsc(AdjApproveLevel::getApproveIndex);
            approveLevelQueryWrapper.last("limit 1");
            return getOne(approveLevelQueryWrapper);
        }

        /**
         * 查询下一个审批节点
         *
         * @param propertyId          资产Id
         * @param type                类型
         * @param currentApproveIndex 当前审批节点
         * @param adRequests          当前节点上的 adj
         * @return cloud.wconnect.frontoffice.entity.adjustment.AdjApproveLevel
         * @author lichen
         * @date 2024/1/29
         */
        @Override
        public AdjApproveLevel getNextApproveLevelByApproveIndex(Integer propertyId, Integer type, Integer currentApproveIndex, List<AdRequest> adRequests) {
            List<AdjApproveLog> adjSkipApproveLogs = new ArrayList<>();
            AdjApproveLevel adjApproveLevel = getAppropriateApprovalLevel(propertyId, type, currentApproveIndex, adjSkipApproveLogs);

            if (CollectionUtils.isNotEmpty(adjSkipApproveLogs)) {
                List<AdjApproveLog> allSkipApproveLogs = Lists.newArrayListWithExpectedSize(adjSkipApproveLogs.size() * adRequests.size());
                for (AdRequest adRequest : adRequests) {
                    Long adjId = adRequest.getId();
                    Long batchId = adRequest.getBatchId();
                    for (AdjApproveLog approveLog : adjSkipApproveLogs) {
                        AdjApproveLog adjApproveLog = beanMapper.map(approveLog, AdjApproveLog.class);
                        adjApproveLog.setPropertyId(propertyId).setBatchId(batchId).setAdjId(adjId);
                        allSkipApproveLogs.add(adjApproveLog);
                    }
                }
                adjApproveLogService.saveBatch(allSkipApproveLogs);
            }

            return adjApproveLevel;
        }

        /**
         * 查询上一个审批节点
         *
         * @param approveLevel 审批级别
         * @return cloud.wconnect.frontoffice.entity.adjustment.AdjApproveLevel
         * @author lichen
         * @date 2025/6/11
         */
        @Override
        public AdjApproveLevel getPrevApproveLevel(AdjApproveLevel approveLevel) {
            //查询下一个节点
            LambdaQueryWrapper<AdjApproveLevel> approveLevelQueryWrapper = new LambdaQueryWrapper<>();
            approveLevelQueryWrapper.eq(AdjApproveLevel::getPropertyId, approveLevel.getPropertyId());
            approveLevelQueryWrapper.eq(AdjApproveLevel::getType, approveLevel.getType());
            approveLevelQueryWrapper.lt(AdjApproveLevel::getApproveIndex, approveLevel.getApproveIndex());
            approveLevelQueryWrapper.orderByDesc(AdjApproveLevel::getApproveIndex);
            approveLevelQueryWrapper.last("limit 1");
            return getOne(approveLevelQueryWrapper);
        }

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

        /**
         * @param oriApprove        更新前的审核配置
         * @param type              1: 删除某一节点时推送 2.修改某一节点规则，由全部改为任一时推送 3.节点规则是全部时，删除某一节点上的人员时推送
         * @param updApproveUserIds 更新后的审批配置
         * @return void
         * @description 推送数据至下一个节点审核
         * @author lichen
         * @date 2023/3/30 11:39
         */
        private void pushNextIndex(AdjApproveLevel oriApprove, int type, List<Integer> updApproveUserIds) {
            //查询当前节点下待审核的数据
            LambdaQueryWrapper<AdRequest> adjLambdaQueryWrapper = new LambdaQueryWrapper<>();
            adjLambdaQueryWrapper.eq(AdRequest::getPropertyId, oriApprove.getPropertyId());
            adjLambdaQueryWrapper.eq(AdRequest::getApproveLevelId, oriApprove.getId());
            adjLambdaQueryWrapper.eq(AdRequest::getFlowStatus, FlowStatusEnum.APPROVAING.getFlowStatus());
            List<AdRequest> adRequests = adRequestService.list(adjLambdaQueryWrapper);
            //数据为空时，直接return
            if (CollectionUtils.isEmpty(adRequests)) return;

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

            // 处理推送至下个审批层级
            handlePushNextIndex(oriApprove, pushList, type);
        }

        /**
         * 处理推送至下个审批层级
         *
         * @param approveLevel 当前审批层级
         * @param pushList     需推送的 adj
         * @param type         1: 删除某一节点时推送 2.修改某一节点规则，由全部改为任一时推送 3.节点规则是全部时，删除某一节点上的人员时推送
         * @author yyt
         * @date 2026/3/20
         **/
        @Override
        public void handlePushNextIndex(AdjApproveLevel approveLevel, List<AdRequest> pushList, Integer type) {
            //查询下一个节点
            Integer propertyId = approveLevel.getPropertyId();
            Integer requestType = approveLevel.getType();
            Integer approveIndex = approveLevel.getApproveIndex();
            AdjApproveLevel nextApproveIndex = getNextApproveLevelByApproveIndex(propertyId, requestType, approveIndex, pushList);
            if (Objects.isNull(nextApproveIndex)) {
                //批量更新数据为【状态=有效】【流程状态=审批结束】
                pushList.forEach(item -> {
                    item.setFlowStatus(FlowStatusEnum.APPROVAL_COMPLETED.getFlowStatus());
                    item.setStatus(AdjustmentStatusEnum.VALID.getStatus());
                });

                /*
                 * 删除审批层级时，如果调账数据在被删除的层级上没有人审批时，则回退到上一个审批节点
                 * 当没有上一个审批节点时，approveIndex置为0
                 */
                if (Objects.nonNull(type) && type == ApproveCons.PUSH_TP_DELETE) {
                    //查询上一个层级
                    AdjApproveLevel prevApproveLevel = getPrevApproveLevel(approveLevel);
                    int prevApproveIndex = Objects.isNull(prevApproveLevel) ? 0 : prevApproveLevel.getApproveIndex();
                    Long prevApproveLevelId = Objects.isNull(prevApproveLevel) ? 0 : prevApproveLevel.getId();

                    //查询调账数据在指定审批层级下的审批记录
                    List<Long> batchIds = pushList.stream().map(AdRequest::getBatchId).collect(toList());
                    Map<Long, List<AdjApproveLog>> adjId2ApproveLogs = approveLogService.listByLevelIdAndBatchIds(propertyId,
                            approveLevel.getId(), batchIds);

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

                adRequestService.updateBatchById(pushList);
                TransactionUtils.afterCommitAsyncExecute(executor, () -> {
                    //发邮件给责任人
                    adjSendEmailService.batchNotifyDutyUserByApproved(pushList);
                    //发送adjustment数据变更事件
                    senderService.batchPublishSave(propertyId, pushList.stream().map(AdRequest::getId).toList());
                });
            } else {
                //批量推送数据至下一个审核节点
                pushList.forEach(item -> {
                    item.setApproveIndex(nextApproveIndex.getApproveIndex());
                    item.setApproveLevelId(nextApproveIndex.getId());
                });
                adRequestService.updateBatchById(pushList);

                //发邮件给审核人
                TransactionUtils.afterCommitAsyncExecute(executor, () -> adjSendEmailService.notifyNextApprovalNodeApprover(pushList, nextApproveIndex));
            }
        }

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

        /**
         * 获取合适的下层审批层级
         *
         * @param adRequest 调账
         * @return 审批层级
         * @author yyt
         * @date 2026/3/18
         */
        @Override
        public AdjApproveLevel getAppropriateApprovalLevel(AdRequest adRequest) {
            Integer propertyId = adRequest.getPropertyId();
            List<AdjApproveLog> adjSkipApproveLogs = new ArrayList<>();
            int approveIndex = Objects.isNull(adRequest.getApproveIndex()) ? 0 : adRequest.getApproveIndex();
            AdjApproveLevel adjApproveLevel = getAppropriateApprovalLevel(propertyId, adRequest.getRequestType(), approveIndex, adjSkipApproveLogs);

            if (CollectionUtils.isNotEmpty(adjSkipApproveLogs)) {
                Long adjId = adRequest.getId();
                Long batchId = adRequest.getBatchId();
                adjApproveLogService.saveBatch(adjSkipApproveLogs.stream()
                        .peek(item -> item.setPropertyId(propertyId).setBatchId(batchId).setAdjId(adjId))
                        .toList());
            }

            return adjApproveLevel;
        }

        /**
         * 获取合适的下层审批层级
         *
         * @param propertyId         资产 id
         * @param type               类型
         * @param approveIndex       层级索引
         * @param adjSkipApproveLogs 已跳过审批日志
         * @return 审批层级
         * @author yyt
         * @date 2026/3/19
         **/
        private AdjApproveLevel getAppropriateApprovalLevel(Integer propertyId, Integer type, Integer approveIndex, List<AdjApproveLog> adjSkipApproveLogs) {
            // 查询指定索引后的第一个审批层级，若层级是最后一个审批层级，则返回
            // 若不是最后一个层级，则检查当前层级下的人员是否全部是禁用用户 ，若是，则生成这些层级下已跳过审批日志，并递归向下找下个层级，若不全部是禁用用户，则返回
            List<AdjApproveLevel> adjApproveLevels = list(propertyId, type);
            if (CollectionUtils.isEmpty(adjApproveLevels)) return null;

            Integer tenantId = propertyI18nRedisService.get(propertyId).getTenantId();
            List<AdjApproveConfig> adjApproveConfigs = approveConfigService.listApproverByLevelIds(propertyId, adjApproveLevels.stream().map(AdjApproveLevel::getId).toList());
            Set<Integer> effectiveUserIds = userInternalService.getUsers(tenantId, adjApproveConfigs.stream().map(AdjApproveConfig::getUserId).toList())
                    .stream().filter(UserDTO::getStatus).map(UserDTO::getId).collect(toSet());
            Map<Long, Set<Integer>> approveUserIdsByLevelId = adjApproveConfigs.stream().collect(groupingBy(AdjApproveConfig::getLevelId,
                    mapping(AdjApproveConfig::getUserId, toSet())));

            return getNextApproveLevel(approveIndex, adjApproveLevels, approveUserIdsByLevelId, effectiveUserIds, adjSkipApproveLogs);
        }

        /**
         * 递归获取下一个审批层级
         *
         * @param approveIndex            层级索引
         * @param adjApproveLevels        审批层级列表
         * @param approveUserIdsByLevelId 审批人列表
         * @param effectiveUserIds        有效用户列表
         * @param adjSkipApproveLogs      已跳过审批日志
         * @return 下一个审批层级
         * @author yyt
         * @date 2026/3/18
         */
        private AdjApproveLevel getNextApproveLevel(int approveIndex, List<AdjApproveLevel> adjApproveLevels, Map<Long, Set<Integer>> approveUserIdsByLevelId,
                                                    Set<Integer> effectiveUserIds, List<AdjApproveLog> adjSkipApproveLogs) {
            List<AdjApproveLevel> nextLevels = adjApproveLevels.stream()
                    .filter(item -> item.getApproveIndex() > approveIndex)
                    .sorted(Comparator.comparing(AdjApproveLevel::getApproveIndex))
                    .toList();
            // 若没有后续审批层级，则返回 null
            if (CollectionUtils.isEmpty(nextLevels)) return null;
            // 若只有最后一个层级，则返回最后一个层级
            if (nextLevels.size() == 1) return nextLevels.get(0);

            AdjApproveLevel nextLevel = nextLevels.get(0);
            Set<Integer> approveUsers = approveUserIdsByLevelId.getOrDefault(nextLevel.getId(), Collections.emptySet());
            if (CollectionUtils.isEmpty(approveUsers)) return nextLevel;

            long now = DateTimeUtils.nowTimestamp();
            // 审批人有效，则返回此层级
            if (effectiveUserIds.containsAll(approveUsers)) {
                return nextLevel;
            } else {
                // 若当前层级下的审批人都已禁用，则跳过当前层级，继续找下个层级
                if (approveUsers.stream().noneMatch(effectiveUserIds::contains)) {
                    adjSkipApproveLogs.addAll(approveUsers.stream().map(userId -> new AdjApproveLog()
                            .setLevelId(nextLevel.getId())
                            .setApproveIndex(nextLevel.getApproveIndex())
                            .setApproveBy(userId)
                            .setApproveStatus(ApproveStatusEnum.SKIPPED.getStatus())
                            .setApproveTime(now)).toList());

                    return getNextApproveLevel(nextLevel.getApproveIndex(), adjApproveLevels, approveUserIdsByLevelId, effectiveUserIds, adjSkipApproveLogs);
                } else {
                    // 若有未禁用用户，则返回此层级
                    return nextLevel;
                }
            }
        }

        /**
         * 查询审批层级
         *
         * @param propertyId   资产 id
         * @param requestType  类型
         * @author yyt
         * @date 2026/3/18
         **/
        private List<AdjApproveLevel> list(Integer propertyId, Integer requestType) {
            return list(new LambdaQueryWrapper<AdjApproveLevel>()
                    .eq(AdjApproveLevel::getPropertyId, propertyId)
                    .eq(AdjApproveLevel::getType, requestType)
                    .orderByAsc(AdjApproveLevel::getApproveIndex));
        }

    }