# BudgetDatabaseConfigOtherTabItemServiceImpl.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.BudgetDatabaseConfigOtherTab;
    import cloud.wconnect.rateshop.entity.budgetdatabase.BudgetDatabaseConfigOtherTabItem;
    import cloud.wconnect.rateshop.entity.budgetdatabase.BudgetDatabaseOtherRevenue;
    import cloud.wconnect.rateshop.mapper.budgetdatabase.BudgetDatabaseConfigOtherTabItemMapper;
    import cloud.wconnect.rateshop.pojo.dto.budgetdatabase.ConfigItemDTO;
    import cloud.wconnect.rateshop.pojo.dto.budgetdatabase.UpdateOtherConfigItemDTO;
    import cloud.wconnect.rateshop.pojo.query.budgetdatabase.ConfigItemQuery;
    import cloud.wconnect.rateshop.service.budgetdatabase.IBudgetDatabaseCalculateRevenueAndRoomService;
    import cloud.wconnect.rateshop.service.budgetdatabase.IBudgetDatabaseConfigOtherTabItemService;
    import cloud.wconnect.rateshop.service.budgetdatabase.IBudgetDatabaseOtherRevenueService;
    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 BudgetDatabaseConfigOtherTabItemServiceImpl extends ServiceImpl<BudgetDatabaseConfigOtherTabItemMapper, BudgetDatabaseConfigOtherTabItem> implements IBudgetDatabaseConfigOtherTabItemService {

        @Autowired
        private BeanMapper beanMapper;
        @Lazy
        @Autowired
        private IBudgetDatabaseCalculateRevenueAndRoomService budgetDatabaseCalculateRevenueAndRoomService;
        @Lazy
        @Autowired
        private IBudgetDatabaseOtherRevenueService budgetDatabaseOtherRevenueService;
        @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<BudgetDatabaseConfigOtherTabItem> baseSql = new QueryWrapper<BudgetDatabaseConfigOtherTabItem>().lambda()
                    .eq(BudgetDatabaseConfigOtherTabItem::getPropertyId, propertyId)
                    .eq(BudgetDatabaseConfigOtherTabItem::getOtherTabId, tabId)
                    .eq(BudgetDatabaseConfigOtherTabItem::getClassification, query.getClassification());

            long total;
            List<BudgetDatabaseConfigOtherTabItem> list;
            if (Objects.nonNull(query.getPage()) && Objects.nonNull(query.getSize())) {
                Page<BudgetDatabaseConfigOtherTabItem> page = page(new Page<>(query.getPage(), query.getSize()),
                        baseSql.like(StringUtils.isNotEmpty(query.getName()), BudgetDatabaseConfigOtherTabItem::getName, query.getName())
                                .orderByAsc(BudgetDatabaseConfigOtherTabItem::getSort));
                total = page.getTotal();
                list = page.getRecords();
            } else {
                list = list(baseSql.eq(StringUtils.isNotEmpty(query.getName()), BudgetDatabaseConfigOtherTabItem::getName, query.getName())
                        .ne(Objects.nonNull(query.getId()), BudgetDatabaseConfigOtherTabItem::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 name           名称
         * @param id             排除自身
         * @author yyt
         * @date 2025/11/10
         **/
        @Override
        public void checkRepeat(Integer propertyId, int tabId, Integer classification, String name, Integer id) {
            BudgetDatabaseConfigOtherTabItem config = getOne(new QueryWrapper<BudgetDatabaseConfigOtherTabItem>().lambda()
                    .eq(BudgetDatabaseConfigOtherTabItem::getPropertyId, propertyId)
                    .eq(BudgetDatabaseConfigOtherTabItem::getOtherTabId, tabId)
                    .eq(BudgetDatabaseConfigOtherTabItem::getClassification, classification)
                    .eq(BudgetDatabaseConfigOtherTabItem::getName, name)
                    .ne(Objects.nonNull(id), BudgetDatabaseConfigOtherTabItem::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(BudgetDatabaseConfigOtherTab tab, UpdateOtherConfigItemDTO updateConfigItemDTO, int userId) {
            Integer tabId = tab.getId();
            Integer propertyId = tab.getPropertyId();
            Integer maxSort = baseMapper.getMaxSortForUpdate(propertyId, tabId, updateConfigItemDTO.getClassification());
            if (Objects.isNull(maxSort)) {
                maxSort = 10;
            } else {
                maxSort += 10;
            }

            BudgetDatabaseConfigOtherTabItem config = beanMapper.map(updateConfigItemDTO, BudgetDatabaseConfigOtherTabItem.class);
            config.setPropertyId(propertyId)
                    .setOtherTabId(tabId)
                    .setSort(maxSort)
                    .setEnableBudgetRoom(false)
                    .setUpdatedBy(userId)
                    .setUpdatedTime(DateTimeUtils.nowTimestamp());
            save(config);

            // 若开启计算，则处理相关数据
            if (updateConfigItemDTO.getEnableBudgetRevenue()) {
                // 重新計算 revenue 分类的预算收入
                budgetDatabaseCalculateRevenueAndRoomService.updateBudgetRevenue(propertyId, tab.getBudgetYear(), Lists.newArrayList(config.getBudgetRevenueVariableId()));
            }
        }

        /**
         * 检查存在
         *
         * @param id 配置 id
         * @return 指标
         * @author yyt
         * @date 2025/11/10
         **/
        @Override
        public BudgetDatabaseConfigOtherTabItem checkExist(int id) {
            BudgetDatabaseConfigOtherTabItem 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(BudgetDatabaseConfigOtherTabItem 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 budgetDatabaseConfigOtherTabItem;propertyId:" + propertyId + ",budgetDatabaseConfigOtherTabItemPropertyId:" +
                        config.getPropertyId() + ",budgetDatabaseConfigOtherTabItemId:" + 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(BudgetDatabaseConfigOtherTab tab, BudgetDatabaseConfigOtherTabItem config, UpdateOtherConfigItemDTO updateConfigItemDTO, int userId) {
            // 修改配置
            BudgetDatabaseConfigOtherTabItem update = beanMapper.map(updateConfigItemDTO, BudgetDatabaseConfigOtherTabItem.class);
            update.setId(config.getId())
                    .setUpdatedBy(userId)
                    .setUpdatedTime(DateTimeUtils.nowTimestamp());
            updateById(update);

            update.setPropertyId(config.getPropertyId()).setOtherTabId(config.getOtherTabId());

            if (Objects.equals(updateConfigItemDTO.getClassification(), FbClassificationEnum.REVENUE.getCode())) {
                // 若开启 revenue 计算，则重置数据
                if (updateConfigItemDTO.getEnableBudgetRevenue()) {
                    budgetDatabaseCalculateRevenueAndRoomService.updateBudgetRevenue(tab.getPropertyId(), tab.getBudgetYear(), Lists.newArrayList(update.getBudgetRevenueVariableId()));
                }
            }
        }

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

            // 删除指标
            removeById(configId);

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

            return false;
        }

        /**
         * 查询指标配置
         *
         * @param tabId tab id
         * @return 指标配置
         * @author yyt
         * @date 2025/11/11
         **/
        @Override
        public List<BudgetDatabaseConfigOtherTabItem> listByTabId(Integer tabId) {
            return list(new QueryWrapper<BudgetDatabaseConfigOtherTabItem>().lambda()
                    .eq(BudgetDatabaseConfigOtherTabItem::getOtherTabId, 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<BudgetDatabaseConfigOtherTabItem>().lambda()
                        .in(BudgetDatabaseConfigOtherTabItem::getId, itemIds)
                        .eq(BudgetDatabaseConfigOtherTabItem::getEnableBudgetRevenue, true)
                        .eq(BudgetDatabaseConfigOtherTabItem::getBudgetRevenueVariableId, variableId)) > 0;
            } else {
                return count(new QueryWrapper<BudgetDatabaseConfigOtherTabItem>().lambda()
                        .in(BudgetDatabaseConfigOtherTabItem::getId, itemIds)
                        .eq(BudgetDatabaseConfigOtherTabItem::getEnableBudgetRoom, true)
                        .eq(BudgetDatabaseConfigOtherTabItem::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<BudgetDatabaseConfigOtherTabItem>().lambda()
                        .eq(BudgetDatabaseConfigOtherTabItem::getBudgetRevenueVariableId, variableId)) > 0;
            } else {
                return count(new QueryWrapper<BudgetDatabaseConfigOtherTabItem>().lambda()
                        .eq(BudgetDatabaseConfigOtherTabItem::getBudgetRoomVariableId, variableId)) > 0;
            }
        }

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

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

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

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

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

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

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

    }