# HotelKpiBudgetDatabaseServiceImpl.java

    package cloud.wconnect.workperformance.service.hotelkpi.impl;

    import cloud.wconnect.commonlib.util.JsonUtils;
    import cloud.wconnect.workperformance.entity.hotelkpi.HotelKpiBudgetDatabase;
    import cloud.wconnect.workperformance.mapper.hotelkpi.HotelKpiBudgetDatabaseMapper;
    import cloud.wconnect.workperformance.pojo.bo.modelevent.budgetdb.BudgetDatabaseBO;
    import cloud.wconnect.workperformance.pojo.dto.hotelkpi.budgetdb.*;
    import cloud.wconnect.workperformance.service.hotelkpi.IHotelKpiBudgetDatabaseService;
    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 jakarta.annotation.Resource;
    import org.apache.commons.collections4.CollectionUtils;
    import org.springframework.stereotype.Service;

    import java.math.BigDecimal;
    import java.util.Collections;
    import java.util.List;
    import java.util.Objects;

    /**
     * <p>
     * Hotel KPI Budget Database 数据 服务实现类
     * </p>
     *
     * @author zc
     * @since 2025-08-26
     */
    @Service
    @DS("work_performance")
    public class HotelKpiBudgetDatabaseServiceImpl extends ServiceImpl<HotelKpiBudgetDatabaseMapper, HotelKpiBudgetDatabase> implements IHotelKpiBudgetDatabaseService {

        @Resource
        private ObjectMapper objectMapper;

        /**
         * 根据日期范围查询数据
         *
         * @param propertyId 资产 ID
         * @param startYear  开始年份(yyyy)
         * @param endYear    结束年份(yyyy)
         * @return HotelKpiBudgetDatabaseDTO 集合
         * @author zc
         * @date 2025/8/26
         */
        @Override
        public List<HotelKpiBudgetDatabaseDTO> listByYearRange(int propertyId, int startYear, int endYear) {
            List<HotelKpiBudgetDatabase> budgetDatabaseList = list(new LambdaQueryWrapper<HotelKpiBudgetDatabase>()
                    .eq(HotelKpiBudgetDatabase::getPropertyId, propertyId)
                    .between(HotelKpiBudgetDatabase::getYear, startYear, endYear));
            if (CollectionUtils.isEmpty(budgetDatabaseList)) {
                return Collections.emptyList();
            }
            return budgetDatabaseList.stream().map(budgetDatabase -> {
                HotelKpiBudgetDatabaseDTO databaseDTO = new HotelKpiBudgetDatabaseDTO();
                databaseDTO.setPropertyId(budgetDatabase.getPropertyId());
                databaseDTO.setYear(budgetDatabase.getYear());
                databaseDTO.setRoom(JsonUtils.convertStringToList(objectMapper,
                        budgetDatabase.getRoom(), HotelKpiBudgetDatabaseRoomTabDTO.class));
                databaseDTO.setFb(JsonUtils.convertStringToList(objectMapper,
                        budgetDatabase.getFb(), HotelKpiBudgetDatabaseFbTabDTO.class));
                databaseDTO.setOther(JsonUtils.convertStringToList(objectMapper,
                        budgetDatabase.getOther(), HotelKpiBudgetDatabaseOtherTabDTO.class));
                return databaseDTO;
            }).toList();
        }

        /**
         * 根据日期查询数据
         *
         * @param propertyId 资产 ID
         * @param year       年份(yyyy)
         * @return HotelKpiBudgetDatabaseDTO
         * @author zc
         * @date 2025/8/26
         */
        @Override
        public HotelKpiBudgetDatabaseDTO getByYear(int propertyId, int year) {
            HotelKpiBudgetDatabase budgetDatabase = getOne(new LambdaQueryWrapper<HotelKpiBudgetDatabase>()
                    .eq(HotelKpiBudgetDatabase::getPropertyId, propertyId)
                    .eq(HotelKpiBudgetDatabase::getYear, year));

            HotelKpiBudgetDatabaseDTO databaseDTO = new HotelKpiBudgetDatabaseDTO();
            if (Objects.isNull(budgetDatabase)) {
                return databaseDTO;
            }
            databaseDTO.setPropertyId(budgetDatabase.getPropertyId());
            databaseDTO.setYear(budgetDatabase.getYear());
            databaseDTO.setRoom(JsonUtils.convertStringToList(objectMapper,
                    budgetDatabase.getRoom(), HotelKpiBudgetDatabaseRoomTabDTO.class));
            databaseDTO.setFb(JsonUtils.convertStringToList(objectMapper,
                    budgetDatabase.getFb(), HotelKpiBudgetDatabaseFbTabDTO.class));
            databaseDTO.setOther(JsonUtils.convertStringToList(objectMapper,
                    budgetDatabase.getOther(), HotelKpiBudgetDatabaseOtherTabDTO.class));
            return databaseDTO;
        }

        /**
         * 保存数据
         *
         * @param eventBO 数据
         * @author zc
         * @date 2025/8/26
         */
        @Override
        public void save(BudgetDatabaseBO eventBO) {
            HotelKpiBudgetDatabase budgetDatabase = new HotelKpiBudgetDatabase();
            budgetDatabase.setPropertyId(eventBO.getPropertyId());
            budgetDatabase.setYear(eventBO.getYear());
            budgetDatabase.setRoom(JsonUtils.convertObjListToString(objectMapper, eventBO.getRoom()));
            budgetDatabase.setFb(JsonUtils.convertObjListToString(objectMapper, eventBO.getFb()));
            budgetDatabase.setOther(JsonUtils.convertObjListToString(objectMapper, eventBO.getOther()));
            baseMapper.insertOrUpdateByUnique(budgetDatabase);
        }

        /**
         * 获取房间RGI预算
         *
         * @param budgetDTO 数据
         * @param startDate 开始时间(yyyyMM)
         * @param endDate   结束时间(yyyyMM)
         * @return 房间RGI预算
         * @author zc
         * @date 2025/11/10
         */
        @Override
        public BigDecimal getRoomRgiBudget(HotelKpiBudgetDatabaseDTO budgetDTO, long startDate, long endDate) {
            return budgetDTO.getRoom().stream()
                    .filter(HotelKpiBudgetDatabaseRoomTabDTO::getOpen)  // 获取开启的 tab
                    .flatMap(roomTabDTO -> roomTabDTO.getRgi().stream())  // 展平获取 rgi 列表
                    .filter(data -> data.getYearMonth() >= startDate && data.getYearMonth() <= endDate)  // 时间范围过滤
                    .map(HotelKpiBudgetDatabaseValueDTO::getBudget)
                    .filter(Objects::nonNull).reduce(BigDecimal::add).orElse(null);
        }

        /**
         * 获取房间数销售预算
         *
         * @param budgetDTO 数据
         * @param startDate 开始时间(yyyyMM)
         * @param endDate   结束时间(yyyyMM)
         * @param type      类型
         * @return 房间数销售预算
         * @author zc
         * @date 2025/11/10
         */
        @Override
        public Long getRoomsSoldBudget(HotelKpiBudgetDatabaseDTO budgetDTO, long startDate, long endDate, Integer type) {
            return budgetDTO.getRoom().stream()
                    .filter(HotelKpiBudgetDatabaseRoomTabDTO::getOpen)  // 过滤开启的 tab
                    .flatMap(roomTabDTO -> roomTabDTO.getRoom().stream())  // 展平获取 room 列表
                    .filter(roomDTO -> type == null || Objects.equals(roomDTO.getType(), type))  // 根据 type 过滤
                    .flatMap(roomDTO -> roomDTO.getData().stream())  // 展平获取 data 列表
                    .filter(data -> data.getYearMonth() >= startDate && data.getYearMonth() <= endDate)  // 时间范围过滤
                    .map(HotelKpiBudgetDatabaseValueRoom::getRoomsBudget)
                    .filter(Objects::nonNull).reduce(Long::sum).orElse(null);
        }

        /**
         * 获取房间收入预算
         *
         * @param budgetDTO 数据
         * @param startDate 开始时间(yyyyMM)
         * @param endDate   结束时间(yyyyMM)
         * @param type      类型
         * @return 房间收入预算
         * @author zc
         * @date 2025/11/10
         */
        @Override
        public BigDecimal getRoomRevenueBudget(HotelKpiBudgetDatabaseDTO budgetDTO, long startDate, long endDate, Integer type) {
            return budgetDTO.getRoom().stream()
                    .filter(HotelKpiBudgetDatabaseRoomTabDTO::getOpen)  // 过滤开启的 tab
                    .flatMap(roomTabDTO -> roomTabDTO.getRoom().stream())  // 展平获取 room 列表
                    .filter(roomDTO -> type == null || Objects.equals(roomDTO.getType(), type))  // 根据 type 过滤
                    .flatMap(roomDTO -> roomDTO.getData().stream())  // 展平获取 data 列表
                    .filter(data -> data.getYearMonth() >= startDate && data.getYearMonth() <= endDate)  // 时间范围过滤
                    .map(HotelKpiBudgetDatabaseValueRoom::getRevenueBudget)
                    .filter(Objects::nonNull).reduce(BigDecimal::add).orElse(null);
        }

        /**
         * 获取房间其他收入预算
         *
         * @param budgetDTO 数据
         * @param startDate 开始时间(yyyyMM)
         * @param endDate   结束时间(yyyyMM)
         * @return 房间其他收入预算
         * @author zc
         * @date 2025/11/10
         */
        @Override
        public BigDecimal getRoomOtherRevenueBudget(HotelKpiBudgetDatabaseDTO budgetDTO, long startDate, long endDate) {
            return budgetDTO.getRoom().stream()
                    .filter(HotelKpiBudgetDatabaseRoomTabDTO::getOpen)  // 过滤开启的 tab
                    .flatMap(roomTabDTO -> roomTabDTO.getOther().stream())  // 展平获取 roomOther 列表
                    .flatMap(roomOtherDTO -> roomOtherDTO.getData().stream())  // 展平获取 data 列表
                    .filter(data -> data.getYearMonth() >= startDate && data.getYearMonth() <= endDate)  // 时间范围过滤
                    .map(HotelKpiBudgetDatabaseValueDTO::getBudget)
                    .filter(Objects::nonNull).reduce(BigDecimal::add).orElse(null);
        }

        /**
         * 获取其他收入预算
         *
         * @param budgetDTO 数据
         * @param startDate 开始时间(yyyyMM)
         * @param endDate   结束时间(yyyyMM)
         * @return 其他收入预算
         * @author zc
         * @date 2025/11/10
         */
        @Override
        public BigDecimal getOtherRevenueBudget(HotelKpiBudgetDatabaseDTO budgetDTO, long startDate, long endDate) {
            return budgetDTO.getOther().stream()
                    .filter(HotelKpiBudgetDatabaseOtherTabDTO::getOpen)  // 过滤开启的 tab
                    .flatMap(otherTabDTO -> otherTabDTO.getOther().stream())  // 展平获取 other 列表
                    .flatMap(otherDTO -> otherDTO.getData().stream())  // 展平获取 data 列表
                    .filter(data -> data.getYearMonth() >= startDate && data.getYearMonth() <= endDate)  // 时间范围过滤
                    .map(HotelKpiBudgetDatabaseValueDTO::getBudget)
                    .filter(Objects::nonNull).reduce(BigDecimal::add).orElse(null);
        }

        /**
         * 获取F&B收入预算
         *
         * @param budgetDTO 数据
         * @param startDate 开始时间(yyyyMM)
         * @param endDate   结束时间(yyyyMM)
         * @param type      类型
         * @return F&B收入预算
         * @author zc
         * @date 2025/11/10
         */
        @Override
        public BigDecimal getFBRevenueBudget(HotelKpiBudgetDatabaseDTO budgetDTO, long startDate, long endDate, Integer type) {
            return budgetDTO.getFb().stream()
                    .filter(HotelKpiBudgetDatabaseFbTabDTO::getOpen)  // 过滤开启的 tab
                    .flatMap(fbTabDTO -> fbTabDTO.getRevenue().stream())  // 展平获取 fb 列表
                    .filter(fbDTO -> type == null || Objects.equals(fbDTO.getType(), type))  // 根据 type 过滤
                    .flatMap(fbDTO -> fbDTO.getData().stream())  // 展平获取 data 列表
                    .filter(data -> data.getYearMonth() >= startDate && data.getYearMonth() <= endDate)  // 时间范围过滤
                    .map(HotelKpiBudgetDatabaseValueDTO::getBudget)
                    .filter(Objects::nonNull).reduce(BigDecimal::add).orElse(null);
        }

    }