# BudgetDatabaseConfigFbTabItemServiceImpl.java

    package cloud.wconnect.rateshop.service.budgetdatabase.impl;

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.CommonErrorI18nConstant;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.exception.ForbiddenException;
    import cloud.wconnect.commonlib.pojo.dto.ListPagedDTO;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.rateshop.cons.budgetdatabase.FbClassificationEnum;
    import cloud.wconnect.rateshop.cons.budgetdatabase.VariableTypeEnum;
    import cloud.wconnect.rateshop.entity.budgetdatabase.BudgetDatabaseConfigFbTab;
    import cloud.wconnect.rateshop.entity.budgetdatabase.BudgetDatabaseConfigFbTabItem;
    import cloud.wconnect.rateshop.entity.budgetdatabase.BudgetDatabaseFbCovers;
    import cloud.wconnect.rateshop.entity.budgetdatabase.BudgetDatabaseFbRevenue;
    import cloud.wconnect.rateshop.mapper.budgetdatabase.BudgetDatabaseConfigFbTabItemMapper;
    import cloud.wconnect.rateshop.pojo.dto.budgetdatabase.ConfigItemDTO;
    import cloud.wconnect.rateshop.pojo.dto.budgetdatabase.UpdateFbConfigItemDTO;
    import cloud.wconnect.rateshop.pojo.query.budgetdatabase.ConfigItemQuery;
    import cloud.wconnect.rateshop.service.budgetdatabase.IBudgetDatabaseCalculateRevenueAndRoomService;
    import cloud.wconnect.rateshop.service.budgetdatabase.IBudgetDatabaseConfigFbTabItemService;
    import cloud.wconnect.rateshop.service.budgetdatabase.IBudgetDatabaseFbCoversService;
    import cloud.wconnect.rateshop.service.budgetdatabase.IBudgetDatabaseFbRevenueService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    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.Collections;
    import java.util.List;
    import java.util.Objects;

    /**
     * <p>
     *  服务实现类
     * </p>
     *
     * @author yyt
     * @since 2025-11-10
     */
    @Service
    @DS("rate_shop")
    public class BudgetDatabaseConfigFbTabItemServiceImpl extends ServiceImpl<BudgetDatabaseConfigFbTabItemMapper, BudgetDatabaseConfigFbTabItem> implements IBudgetDatabaseConfigFbTabItemService {

        @Autowired
        private BeanMapper beanMapper;
        @Lazy
        @Autowired
        private IBudgetDatabaseCalculateRevenueAndRoomService budgetDatabaseCalculateRevenueAndRoomService;
        @Lazy
        @Autowired
        private IBudgetDatabaseFbRevenueService budgetDatabaseFbRevenueService;
        @Autowired
        private IBudgetDatabaseFbCoversService budgetDatabaseFbCoversService;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;

        /**
         * 查询配置
         *
         * @param propertyId 资产 id
         * @param tabId      tab id
         * @param query      查询条件
         * @return 配置
         * @author yyt
         * @date 2025/11/10
         **/
        @Override
        public ListPagedDTO<ConfigItemDTO> list(Integer propertyId, int tabId, ConfigItemQuery query) {
            LambdaQueryWrapper<BudgetDatabaseConfigFbTabItem> baseSql = new QueryWrapper<BudgetDatabaseConfigFbTabItem>().lambda()
                    .eq(BudgetDatabaseConfigFbTabItem::getPropertyId, propertyId)
                    .eq(BudgetDatabaseConfigFbTabItem::getFbTabId, tabId)
                    .eq(BudgetDatabaseConfigFbTabItem::getClassification, query.getClassification());

            long total;
            List<BudgetDatabaseConfigFbTabItem> list;
            if (Objects.nonNull(query.getPage()) && Objects.nonNull(query.getSize())) {
                Page<BudgetDatabaseConfigFbTabItem> page = page(new Page<>(query.getPage(), query.getSize()),
                        baseSql.like(StringUtils.isNotEmpty(query.getName()), BudgetDatabaseConfigFbTabItem::getName, query.getName())
                                .eq(Objects.nonNull(query.getType()), BudgetDatabaseConfigFbTabItem::getType, query.getType())
                                .orderByAsc(BudgetDatabaseConfigFbTabItem::getType, BudgetDatabaseConfigFbTabItem::getSort));
                total = page.getTotal();
                list = page.getRecords();
            } else {
                list = list(baseSql.eq(StringUtils.isNotEmpty(query.getName()), BudgetDatabaseConfigFbTabItem::getName, query.getName())
                        .eq(Objects.nonNull(query.getType()), BudgetDatabaseConfigFbTabItem::getType, query.getType())
                        .ne(Objects.nonNull(query.getId()), BudgetDatabaseConfigFbTabItem::getId, query.getId()));
                total = list.size();
            }

            return new ListPagedDTO<>(total, beanMapper.mapList(list, ConfigItemDTO.class));
        }

        /**
         * 检查重复
         *
         * @param propertyId     资产 id
         * @param tabId          tab id
         * @param classification 分类
         * @param type           类型
         * @param name           名称
         * @param id             排除自身
         * @author yyt
         * @date 2025/11/10
         **/
        @Override
        public void checkRepeat(Integer propertyId, int tabId, Integer classification, Integer type, String name, Integer id) {
            BudgetDatabaseConfigFbTabItem config = getOne(new QueryWrapper<BudgetDatabaseConfigFbTabItem>().lambda()
                    .eq(BudgetDatabaseConfigFbTabItem::getPropertyId, propertyId)
                    .eq(BudgetDatabaseConfigFbTabItem::getFbTabId, tabId)
                    .eq(BudgetDatabaseConfigFbTabItem::getClassification, classification)
                    .eq(BudgetDatabaseConfigFbTabItem::getType, type)
                    .eq(BudgetDatabaseConfigFbTabItem::getName, name)
                    .ne(Objects.nonNull(id), BudgetDatabaseConfigFbTabItem::getId, id)
                    .last("limit 1"));
            if (Objects.nonNull(config)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_EXISTED,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the config is exist");
            }
        }

        /**
         * 保存配置
         *
         * @param tab                 tab
         * @param updateConfigItemDTO 配置信息
         * @param userId              操作人
         * @author yyt
         * @date 2025/11/10
         **/
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void save(BudgetDatabaseConfigFbTab tab, UpdateFbConfigItemDTO updateConfigItemDTO, int userId) {
            Integer tabId = tab.getId();
            Integer propertyId = tab.getPropertyId();
            Integer maxSort = baseMapper.getMaxSortForUpdate(propertyId, tabId, updateConfigItemDTO.getClassification(), updateConfigItemDTO.getType());
            if (Objects.isNull(maxSort)) {
                maxSort = 10;
            } else {
                maxSort += 10;
            }

            BudgetDatabaseConfigFbTabItem config = beanMapper.map(updateConfigItemDTO, BudgetDatabaseConfigFbTabItem.class);
            config.setPropertyId(propertyId)
                    .setFbTabId(tabId)
                    .setSort(maxSort)
                    .setUpdatedBy(userId)
                    .setUpdatedTime(DateTimeUtils.nowTimestamp());
            save(config);

            Integer budgetYear = tab.getBudgetYear();
            // 若开启计算，则处理相关数据
            if (Objects.equals(updateConfigItemDTO.getClassification(), FbClassificationEnum.REVENUE.getCode()) && updateConfigItemDTO.getEnableBudgetRevenue()) {
                // 重新計算 revenue 分类的预算收入
                budgetDatabaseCalculateRevenueAndRoomService.updateBudgetRevenue(propertyId, budgetYear, Lists.newArrayList(config.getBudgetRevenueVariableId()));
            }
            if (Objects.equals(updateConfigItemDTO.getClassification(), FbClassificationEnum.COVERS.getCode())) {
                // 重新计算 covers
                if (updateConfigItemDTO.getEnableBudgetRevenue()) {
                    budgetDatabaseCalculateRevenueAndRoomService.updateBudgetRevenue(propertyId, budgetYear, Lists.newArrayList(config.getBudgetRevenueVariableId()));
                }
                if (updateConfigItemDTO.getEnableBudgetRoom()) {
                    budgetDatabaseCalculateRevenueAndRoomService.updateBudgetRoom(propertyId, budgetYear, Lists.newArrayList(config.getBudgetRoomVariableId()));
                }
            }
        }

        /**
         * 检查存在
         *
         * @param id 配置 id
         * @return 指标
         * @author yyt
         * @date 2025/11/10
         **/
        @Override
        public BudgetDatabaseConfigFbTabItem checkExist(int id) {
            BudgetDatabaseConfigFbTabItem config = getById(id);
            if (Objects.isNull(config)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_FOUND,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the config is not exist");
            }
            return config;
        }

        /**
         * 校验数据归属
         *
         * @param config     配置
         * @param propertyId 资产id
         * @author yyt
         * @date 2025/8/16
         */
        @Override
        public void checkBelong(BudgetDatabaseConfigFbTabItem config, Integer propertyId) {
            if (!config.getPropertyId().equals(propertyId)) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(),
                        BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(), "the property id parameter is different from " +
                        "the property id of the budgetDatabaseConfigRoomTabItem;propertyId:" + propertyId + ",budgetDatabaseConfigRoomTabItemPropertyId:" +
                        config.getPropertyId() + ",budgetDatabaseConfigRoomTabItemId:" + config.getId());
            }
        }

        /**
         * 修改配置
         *
         * @param config              配置
         * @param updateConfigItemDTO 配置信息
         * @param userId              操作人
         * @author yyt
         * @date 2025/11/10
         **/
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void update(BudgetDatabaseConfigFbTab tab, BudgetDatabaseConfigFbTabItem config, UpdateFbConfigItemDTO updateConfigItemDTO, int userId) {
            // 修改配置
            BudgetDatabaseConfigFbTabItem update = beanMapper.map(updateConfigItemDTO, BudgetDatabaseConfigFbTabItem.class);
            update.setId(config.getId())
                    .setUpdatedBy(userId)
                    .setUpdatedTime(DateTimeUtils.nowTimestamp());
            updateById(update);

            Integer propertyId = tab.getPropertyId();
            Integer budgetYear = tab.getBudgetYear();

            if (Objects.equals(updateConfigItemDTO.getClassification(), FbClassificationEnum.REVENUE.getCode())) {
                // 若开启 revenue 计算，则重置数据
                if (updateConfigItemDTO.getEnableBudgetRevenue()) {
                    budgetDatabaseCalculateRevenueAndRoomService.updateBudgetRevenue(propertyId, budgetYear, Lists.newArrayList(update.getBudgetRevenueVariableId()));
                }
            } else {
                // 只能开启一个
                // 若开启 room 计算，则重置数据
                if (updateConfigItemDTO.getEnableBudgetRoom()) {
                    budgetDatabaseCalculateRevenueAndRoomService.updateBudgetRoom(propertyId, budgetYear, Lists.newArrayList(update.getBudgetRoomVariableId()));
                }
                // 若开启 revenue 计算，则重置数据
                if (updateConfigItemDTO.getEnableBudgetRevenue()) {
                    budgetDatabaseCalculateRevenueAndRoomService.updateBudgetRevenue(propertyId, budgetYear, Lists.newArrayList(update.getBudgetRevenueVariableId()));
                }
            }
        }

        /**
         * 删除配置
         *
         * @param config 配置
         * @return 是否可以删除
         * @author yyt
         * @date 2025/11/10
         **/
        @Override
        @Transactional(rollbackFor = Exception.class)
        public boolean handleDeleteRevenueConfig(BudgetDatabaseConfigFbTabItem config) {
            // 检查配置是否被占用， 若配置有编辑内容，则不能删除
            Integer configId = config.getId();
            BudgetDatabaseFbRevenue revenue = budgetDatabaseFbRevenueService.getByItemId(configId);
            if (Objects.nonNull(revenue) && revenue.hasData()) {
                return true;
            }

            // 删除指标
            removeById(configId);

            if (Objects.nonNull(revenue)) {
                // 删除指标占用数据
                budgetDatabaseFbRevenueService.removeById(revenue.getId());
            }

            return false;
        }

        /**
         * 删除配置
         *
         * @param config 配置
         * @return 是否可以删除
         * @author yyt
         * @date 2025/11/10
         **/
        @Override
        @Transactional(rollbackFor = Exception.class)
        public boolean handleDeleteCoversConfig(BudgetDatabaseConfigFbTabItem config) {
            // 检查配置是否被占用，若配置有编辑内容，则不能删除
            Integer configId = config.getId();
            BudgetDatabaseFbCovers revenue = budgetDatabaseFbCoversService.getByItemId(configId);
            if (Objects.nonNull(revenue) && revenue.hasData()) {
                return true;
            }

            // 删除指标
            removeById(configId);

            if (Objects.nonNull(revenue)) {
                // 删除指标占用数据
                budgetDatabaseFbCoversService.removeById(revenue.getId());
            }

            return false;
        }

        /**
         * 查询指标配置
         *
         * @param tabId tab id
         * @return 指标配置
         * @author yyt
         * @date 2025/11/11
         **/
        @Override
        public List<BudgetDatabaseConfigFbTabItem> listByTabId(Integer tabId) {
            return list(new QueryWrapper<BudgetDatabaseConfigFbTabItem>().lambda()
                    .eq(BudgetDatabaseConfigFbTabItem::getFbTabId, tabId));
        }

        /**
         * 检查指标是否启用
         *
         * @param itemIds   指标 id
         * @param variableId  变量配置 id
         * @param type      变量配置类型
         * @return 是否启用
         * @author yyt
         * @date 2025/11/11
         **/
        @Override
        public boolean checkEnabledTheVariable(List<Integer> itemIds, int variableId, Integer type) {
            if (Objects.equals(type, VariableTypeEnum.REVENUE.getCode())) {
                return count(new QueryWrapper<BudgetDatabaseConfigFbTabItem>().lambda()
                        .in(BudgetDatabaseConfigFbTabItem::getId, itemIds)
                        .eq(BudgetDatabaseConfigFbTabItem::getEnableBudgetRevenue, true)
                        .eq(BudgetDatabaseConfigFbTabItem::getBudgetRevenueVariableId, variableId)) > 0;
            } else {
                return count(new QueryWrapper<BudgetDatabaseConfigFbTabItem>().lambda()
                        .in(BudgetDatabaseConfigFbTabItem::getId, itemIds)
                        .eq(BudgetDatabaseConfigFbTabItem::getEnableBudgetRoom, true)
                        .eq(BudgetDatabaseConfigFbTabItem::getBudgetRoomVariableId, variableId)) > 0;
            }
        }

        /**
         * 检查变量配置是否被使用
         *
         * @param variableId  变量配置 id
         * @param type      变量配置类型
         * @return 是否被使用
         * @author yyt
         * @date 2025/11/11
         **/
        @Override
        public boolean checkUsedTheVariable(int variableId, Integer type) {
            if (Objects.equals(type, VariableTypeEnum.REVENUE.getCode())) {
                return count(new QueryWrapper<BudgetDatabaseConfigFbTabItem>().lambda()
                        .eq(BudgetDatabaseConfigFbTabItem::getBudgetRevenueVariableId, variableId)) > 0;
            } else {
                return count(new QueryWrapper<BudgetDatabaseConfigFbTabItem>().lambda()
                        .eq(BudgetDatabaseConfigFbTabItem::getBudgetRoomVariableId, variableId)) > 0;
            }
        }

        /**
         * 根据 tab id 批量查询
         *
         * @param tabIds tab id
         * @return 配置
         * @author yyt
         * @date 2025/11/11
         **/
        @Override
        public List<BudgetDatabaseConfigFbTabItem> listByTabIds(List<Integer> tabIds) {
            if (CollectionUtils.isEmpty(tabIds)) {
                return Collections.emptyList();
            }

            return list(new QueryWrapper<BudgetDatabaseConfigFbTabItem>().lambda()
                    .in(BudgetDatabaseConfigFbTabItem::getFbTabId, tabIds));
        }

        /**
         * 根据 tab id 和 分类查询
         *
         * @param tabIds         tab id
         * @param classification 分类
         * @return 配置
         * @author yyt
         * @date 2025/11/11
         **/
        @Override
        public List<BudgetDatabaseConfigFbTabItem> listByTabIdsAndClassification(List<Integer> tabIds, Integer classification) {
            return list(new QueryWrapper<BudgetDatabaseConfigFbTabItem>().lambda()
                    .in(BudgetDatabaseConfigFbTabItem::getFbTabId, tabIds)
                    .eq(BudgetDatabaseConfigFbTabItem::getClassification, classification));
        }

        /**
         * 根据 tab id 和 分类查询
         *
         * @param tabId          tab id
         * @param classification 分类
         * @return 配置
         * @author yyt
         * @date 2025/11/11
         **/
        @Override
        public List<BudgetDatabaseConfigFbTabItem> listByTabIdAndClassification(int tabId, Integer classification) {
            return list(new QueryWrapper<BudgetDatabaseConfigFbTabItem>().lambda()
                    .eq(BudgetDatabaseConfigFbTabItem::getFbTabId, tabId)
                    .eq(BudgetDatabaseConfigFbTabItem::getClassification, classification)
                    .orderByAsc(BudgetDatabaseConfigFbTabItem::getSort));
        }

        /**
         * 根据 tab id 和 fb id 查询
         *
         * @param tabId tab id
         * @param fbIds fb id
         * @return 配置
         * @author yyt
         * @date 2025/11/11
         **/
        @Override
        public List<BudgetDatabaseConfigFbTabItem> listByTabIdAndIds(Integer tabId, List<Integer> fbIds) {
            return list(new QueryWrapper<BudgetDatabaseConfigFbTabItem>().lambda()
                    .eq(BudgetDatabaseConfigFbTabItem::getFbTabId, tabId)
                    .in(BudgetDatabaseConfigFbTabItem::getId, fbIds));
        }

        /**
         * 检查指标是否存在
         *
         * @param propertyId     资产 id
         * @param tabId          tab id
         * @param classification 分类
         * @param itemIds        指标 id
         * @author yyt
         * @date 2025/11/14
         **/
        @Override
        public void checkExist(int propertyId, int tabId, int classification, List<Integer> itemIds) {
            List<BudgetDatabaseConfigFbTabItem> list = list(new QueryWrapper<BudgetDatabaseConfigFbTabItem>().lambda()
                    .eq(BudgetDatabaseConfigFbTabItem::getPropertyId, propertyId)
                    .eq(BudgetDatabaseConfigFbTabItem::getFbTabId, tabId)
                    .eq(BudgetDatabaseConfigFbTabItem::getClassification, classification)
                    .in(BudgetDatabaseConfigFbTabItem::getId, itemIds));
            if (list.size() != itemIds.size()) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_EXIST,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("fb item"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the fb item not exist");
            }
        }

        /**
         * 查询引用 revenue 变量配置的指标
         *
         * @param variableId 变量 id
         * @return 指标
         * @author yyt
         * @date 2025/11/12
         **/
        @Override
        public List<BudgetDatabaseConfigFbTabItem> listByBudgetRevenueVariableId(Integer variableId) {
            return list(new QueryWrapper<BudgetDatabaseConfigFbTabItem>().lambda()
                    .eq(BudgetDatabaseConfigFbTabItem::getEnableBudgetRevenue, true)
                    .eq(BudgetDatabaseConfigFbTabItem::getBudgetRevenueVariableId, variableId));
        }

        /**
         * 查询引用 room 变量配置的指标
         *
         * @param variableId 变量 id
         * @return 指标
         * @author yyt
         * @date 2025/11/12
         **/
        @Override
        public List<BudgetDatabaseConfigFbTabItem> listByBudgetRoomVariableId(Integer variableId) {
            return list(new QueryWrapper<BudgetDatabaseConfigFbTabItem>().lambda()
                    .eq(BudgetDatabaseConfigFbTabItem::getEnableBudgetRoom, true)
                    .eq(BudgetDatabaseConfigFbTabItem::getBudgetRoomVariableId, variableId));
        }

        /**
         * 查询资产下的所有指标
         *
         * @param propertyId 资产 id
         * @return 指标
         * @author yyt
         * @date 2025/11/14
         **/
        @Override
        public List<BudgetDatabaseConfigFbTabItem> listByPropertyId(Integer propertyId) {
            return list(new QueryWrapper<BudgetDatabaseConfigFbTabItem>().lambda()
                    .eq(BudgetDatabaseConfigFbTabItem::getPropertyId, propertyId));
        }

    }