# BudgetDatabaseConfigRoomTabItemServiceImpl.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.RoomClassificationEnum;
    import cloud.wconnect.rateshop.cons.budgetdatabase.VariableTypeEnum;
    import cloud.wconnect.rateshop.entity.budgetdatabase.BudgetDatabaseConfigRoomTab;
    import cloud.wconnect.rateshop.entity.budgetdatabase.BudgetDatabaseConfigRoomTabItem;
    import cloud.wconnect.rateshop.entity.budgetdatabase.BudgetDatabaseRoom;
    import cloud.wconnect.rateshop.entity.budgetdatabase.BudgetDatabaseRoomOther;
    import cloud.wconnect.rateshop.mapper.budgetdatabase.BudgetDatabaseConfigRoomTabItemMapper;
    import cloud.wconnect.rateshop.pojo.dto.budgetdatabase.ConfigItemDTO;
    import cloud.wconnect.rateshop.pojo.dto.budgetdatabase.UpdateRoomConfigItemDTO;
    import cloud.wconnect.rateshop.pojo.query.budgetdatabase.ConfigItemQuery;
    import cloud.wconnect.rateshop.service.budgetdatabase.IBudgetDatabaseCalculateRevenueAndRoomService;
    import cloud.wconnect.rateshop.service.budgetdatabase.IBudgetDatabaseConfigRoomTabItemService;
    import cloud.wconnect.rateshop.service.budgetdatabase.IBudgetDatabaseRoomOtherService;
    import cloud.wconnect.rateshop.service.budgetdatabase.IBudgetDatabaseRoomService;
    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 javax.annotation.Nullable;
    import java.util.Collections;
    import java.util.List;
    import java.util.Objects;
    import java.util.stream.Collectors;

    /**
     * <p>
     *  服务实现类
     * </p>
     *
     * @author yyt
     * @since 2025-11-10
     */
    @Service
    @DS("rate_shop")
    public class BudgetDatabaseConfigRoomTabItemServiceImpl extends ServiceImpl<BudgetDatabaseConfigRoomTabItemMapper, BudgetDatabaseConfigRoomTabItem> implements IBudgetDatabaseConfigRoomTabItemService {

        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private IBudgetDatabaseCalculateRevenueAndRoomService budgetDatabaseCalculateRevenueAndRoomService;
        @Lazy
        @Autowired
        private IBudgetDatabaseRoomOtherService budgetDatabaseRoomOtherService;
        @Lazy
        @Autowired
        private IBudgetDatabaseRoomService budgetDatabaseRoomService;
        @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<BudgetDatabaseConfigRoomTabItem> baseSql = new QueryWrapper<BudgetDatabaseConfigRoomTabItem>().lambda()
                    .eq(BudgetDatabaseConfigRoomTabItem::getPropertyId, propertyId)
                    .eq(BudgetDatabaseConfigRoomTabItem::getRoomTabId, tabId)
                    .eq(BudgetDatabaseConfigRoomTabItem::getClassification, query.getClassification());

            long total;
            List<BudgetDatabaseConfigRoomTabItem> list;
            if (Objects.nonNull(query.getPage()) && Objects.nonNull(query.getSize())) {
                Page<BudgetDatabaseConfigRoomTabItem> page = page(new Page<>(query.getPage(), query.getSize()),
                        baseSql.like(StringUtils.isNotEmpty(query.getName()), BudgetDatabaseConfigRoomTabItem::getName, query.getName())
                                .eq(Objects.nonNull(query.getType()), BudgetDatabaseConfigRoomTabItem::getType, query.getType())
                                .orderByAsc(BudgetDatabaseConfigRoomTabItem::getType, BudgetDatabaseConfigRoomTabItem::getSort));
                total = page.getTotal();
                list = page.getRecords();
            } else {
                list = list(baseSql.eq(StringUtils.isNotEmpty(query.getName()), BudgetDatabaseConfigRoomTabItem::getName, query.getName())
                        .eq(Objects.nonNull(query.getType()), BudgetDatabaseConfigRoomTabItem::getType, query.getType())
                        .ne(Objects.nonNull(query.getId()), BudgetDatabaseConfigRoomTabItem::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, @Nullable Integer type, String name, Integer id) {
            BudgetDatabaseConfigRoomTabItem config = getOne(new QueryWrapper<BudgetDatabaseConfigRoomTabItem>().lambda()
                    .eq(BudgetDatabaseConfigRoomTabItem::getPropertyId, propertyId)
                    .eq(BudgetDatabaseConfigRoomTabItem::getRoomTabId, tabId)
                    .eq(BudgetDatabaseConfigRoomTabItem::getClassification, classification)
                    .eq(Objects.nonNull(type), BudgetDatabaseConfigRoomTabItem::getType, type)
                    .eq(BudgetDatabaseConfigRoomTabItem::getName, name)
                    .ne(Objects.nonNull(id), BudgetDatabaseConfigRoomTabItem::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(BudgetDatabaseConfigRoomTab tab, UpdateRoomConfigItemDTO updateConfigItemDTO, int userId) {
            Integer propertyId = tab.getPropertyId();
            Integer tabId = tab.getId();
            Integer maxSort = baseMapper.getMaxSortForUpdate(propertyId, tabId, updateConfigItemDTO.getClassification(), updateConfigItemDTO.getType());
            if (Objects.isNull(maxSort)) {
                maxSort = 10;
            } else {
                maxSort += 10;
            }

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

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

        /**
         * 检查存在
         *
         * @param id 配置 id
         * @return 指标
         * @author yyt
         * @date 2025/11/10
         **/
        @Override
        public BudgetDatabaseConfigRoomTabItem checkExist(int id) {
            BudgetDatabaseConfigRoomTabItem 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(BudgetDatabaseConfigRoomTabItem 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 tab                 tab
         * @param config              配置
         * @param updateConfigItemDTO 配置信息
         * @param userId              操作人
         * @author yyt
         * @date 2025/11/10
         **/
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void update(BudgetDatabaseConfigRoomTab tab,BudgetDatabaseConfigRoomTabItem config, UpdateRoomConfigItemDTO updateConfigItemDTO, int userId) {
            // 修改配置
            BudgetDatabaseConfigRoomTabItem update = beanMapper.map(updateConfigItemDTO, BudgetDatabaseConfigRoomTabItem.class);
            update.setId(config.getId())
                    .setUpdatedBy(userId)
                    .setUpdatedTime(DateTimeUtils.nowTimestamp());
            updateById(update);

            // 当前指标未启用 room 和 revenue 时，而 revenue 有值（之前启用时设置的值），则清空下数据
            if (Objects.equals(config.getClassification(), RoomClassificationEnum.ROOM.getCode()) && !update.getEnableBudgetRoom() && !update.getEnableBudgetRevenue()) {
                budgetDatabaseRoomService.clearBudgetRevenue(config.getId());
            }

            Integer budgetYear = tab.getBudgetYear();
            if (Objects.equals(updateConfigItemDTO.getClassification(), RoomClassificationEnum.OTHER.getCode())) {
                // 若开启 revenue 计算，则重置数据
                if (updateConfigItemDTO.getEnableBudgetRevenue()) {
                    budgetDatabaseCalculateRevenueAndRoomService.updateBudgetRevenue(config.getPropertyId(), budgetYear, Lists.newArrayList(config.getBudgetRevenueVariableId()));
                }
            } else {
                // 若开启 room 计算 / 开启 revenue 计算，则重置数据
                if ((updateConfigItemDTO.getEnableBudgetRoom() || updateConfigItemDTO.getEnableBudgetRevenue())) {
                    if (updateConfigItemDTO.getEnableBudgetRoom() && updateConfigItemDTO.getEnableBudgetRevenue()) {
                        budgetDatabaseCalculateRevenueAndRoomService.updateBudgetRevenueAndRoomForRoom(tab.getPropertyId(), budgetYear,
                                Lists.newArrayList(updateConfigItemDTO.getBudgetRevenueVariableId()), Lists.newArrayList(updateConfigItemDTO.getBudgetRoomVariableId()));
                    } else {
                        if (updateConfigItemDTO.getEnableBudgetRoom()) {
                            budgetDatabaseCalculateRevenueAndRoomService.updateBudgetRoom(tab.getPropertyId(), budgetYear, Lists.newArrayList(updateConfigItemDTO.getBudgetRoomVariableId()));
                        } else {
                            budgetDatabaseCalculateRevenueAndRoomService.updateBudgetRevenue(tab.getPropertyId(), budgetYear, Lists.newArrayList(updateConfigItemDTO.getBudgetRevenueVariableId()));
                        }
                    }

                }
            }
        }

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

            // 删除指标
            removeById(configId);

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

            return false;
        }

        /**
         * 删除配置
         *
         * @param config 配置
         * @return 是否可以删除
         * @author yyt
         * @date 2025/11/10
         **/
        @Override
        @Transactional(rollbackFor = Exception.class)
        public boolean handleDeleteRoomConfig(BudgetDatabaseConfigRoomTabItem config) {
            // 检查配置是否被占用，若配置有编辑内容，则不能删除
            Integer configId = config.getId();
            List<BudgetDatabaseRoom> revenues = budgetDatabaseRoomService.list(new QueryWrapper<BudgetDatabaseRoom>().lambda()
                    .eq(BudgetDatabaseRoom::getRoomId, configId));
            if (CollectionUtils.isNotEmpty(revenues) && revenues.stream().anyMatch(BudgetDatabaseRoom::hasData)) {
                return true;
            }

            // 删除指标
            removeById(configId);

            if (CollectionUtils.isNotEmpty(revenues)) {
                // 删除指标占用数据
                budgetDatabaseRoomService.removeByIds(revenues.stream().map(BudgetDatabaseRoom::getId).collect(Collectors.toList()));
            }

            return false;
        }

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

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

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

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

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

        /**
         * 查询指标
         *
         * @param tabIds tab id
         * @return 指标
         * @author yyt
         * @date 2025/11/12
         **/
        @Override
        public List<BudgetDatabaseConfigRoomTabItem> listByTabIds(List<Integer> tabIds) {
            if (CollectionUtils.isEmpty(tabIds)) {
                return Collections.emptyList();
            }

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

        /**
         * 查询指标
         *
         * @param tabIds         tab id
         * @param classification 分类
         * @return 指标
         * @author yyt
         * @date 2025/11/12
         **/
        @Override
        public List<BudgetDatabaseConfigRoomTabItem> listByTabIds(List<Integer> tabIds, @Nullable Integer classification) {
            return list(new QueryWrapper<BudgetDatabaseConfigRoomTabItem>().lambda()
                    .in(BudgetDatabaseConfigRoomTabItem::getRoomTabId, tabIds)
                    .eq(Objects.nonNull(classification), BudgetDatabaseConfigRoomTabItem::getClassification, classification));
        }

        /**
         * 检查指标是否存在
         *
         * @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<BudgetDatabaseConfigRoomTabItem> list = list(new QueryWrapper<BudgetDatabaseConfigRoomTabItem>().lambda()
                    .eq(BudgetDatabaseConfigRoomTabItem::getPropertyId, propertyId)
                    .eq(BudgetDatabaseConfigRoomTabItem::getRoomTabId, tabId)
                    .eq(BudgetDatabaseConfigRoomTabItem::getClassification, classification)
                    .in(BudgetDatabaseConfigRoomTabItem::getId, itemIds));
            if (list.size() != itemIds.size()) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_EXIST,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("room item"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the room item not exist");
            }
        }

        /**
         * 查询指标
         *
         * @param tabId          tab id
         * @param classification 分类
         * @return 指标
         * @author yyt
         * @date 2025/11/14
         **/
        @Override
        public List<BudgetDatabaseConfigRoomTabItem> listByTabIdAndClassification(int tabId, int classification) {
            return list(new QueryWrapper<BudgetDatabaseConfigRoomTabItem>().lambda()
                    .eq(BudgetDatabaseConfigRoomTabItem::getRoomTabId, tabId)
                    .eq(BudgetDatabaseConfigRoomTabItem::getClassification, classification)
                    .orderByAsc(BudgetDatabaseConfigRoomTabItem::getSort));
        }

        /**
         * 批量查询指标
         *
         * @param tabId   tab id
         * @param itemIds 指标 id
         * @return 指标
         * @author yyt
         * @date 2025/11/14
         **/
        @Override
        public List<BudgetDatabaseConfigRoomTabItem> listByTabIdAndIds(Integer tabId, List<Integer> itemIds) {
            return list(new QueryWrapper<BudgetDatabaseConfigRoomTabItem>().lambda()
                    .eq(BudgetDatabaseConfigRoomTabItem::getRoomTabId, tabId)
                    .in(BudgetDatabaseConfigRoomTabItem::getId, itemIds));
        }

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

    }