# MonthlyReportInternalServiceImpl.java

    package cloud.wconnect.workperformance.service.monthlyreport.internal.impl;

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.util.YearMonthUtils;
    import cloud.wconnect.workperformance.entity.monthlyreport.Forecast;
    import cloud.wconnect.workperformance.entity.monthlyreport.MonthlyReport;
    import cloud.wconnect.workperformance.entity.monthlyreport.Profit;
    import cloud.wconnect.workperformance.entity.monthlyreport.RoomRevenue;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.internal.MonthlyReportForecastInternalDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.internal.MonthlyReportProfitInternalDTO;
    import cloud.wconnect.workperformance.pojo.dto.monthlyreport.internal.MonthlyReportRoomRevenueInternalDTO;
    import cloud.wconnect.workperformance.service.monthlyreport.IForecastService;
    import cloud.wconnect.workperformance.service.monthlyreport.IMonthlyReportService;
    import cloud.wconnect.workperformance.service.monthlyreport.IProfitService;
    import cloud.wconnect.workperformance.service.monthlyreport.IRoomRevenueService;
    import cloud.wconnect.workperformance.service.monthlyreport.internal.IMonthlyReportInternalService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import jakarta.annotation.Resource;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.stereotype.Service;

    import java.time.YearMonth;
    import java.util.Collections;
    import java.util.List;
    import java.util.Map;
    import java.util.Objects;
    import java.util.stream.Collectors;

    /**
     * Internal Service: Monthly Report
     *
     * @author zc
     * @date 2024/10/16
     */
    @Service
    @DS("monthly_report")
    public class MonthlyReportInternalServiceImpl implements IMonthlyReportInternalService {
        @Resource
        private IMonthlyReportService monthlyReportService;
        @Resource
        private IForecastService forecastService;
        @Resource
        private IProfitService profitService;
        @Resource
        private IRoomRevenueService roomRevenueService;
        @Resource
        private BeanMapper beanMapper;

        /**
         * 获取 Forecast 数据
         *
         * @param propertyDTO   资产
         * @param forecastMonth 预测数据月份
         * @return MonthlyReportForecastInternalDTO 集合
         * @author zc
         * @date 2024/10/16
         */
        @Override
        public List<MonthlyReportForecastInternalDTO> listFirstForecast(PropertyDTO propertyDTO, long forecastMonth) {
            YearMonth yearMonth = YearMonthUtils.getYearMonth(String.valueOf(forecastMonth));

            // 月报数据需要往前推2个月
            YearMonth monthlyReportYearMonth = yearMonth.minusMonths(2);
            // 获取月报数据
            MonthlyReport monthlyReport = monthlyReportService.getMonthlyReportByYearAndMonth(propertyDTO.getId(),
                    monthlyReportYearMonth.getYear(), monthlyReportYearMonth.getMonthValue());
            if (Objects.isNull(monthlyReport)) {
                return Collections.emptyList();
            }

            List<Forecast> forecastList = forecastService.list(new LambdaQueryWrapper<Forecast>()
                    .eq(Forecast::getReportId, monthlyReport.getId())
                    .eq(Forecast::getDate, forecastMonth));
            if (CollectionUtils.isEmpty(forecastList)) {
                return Collections.emptyList();
            }

            return beanMapper.mapList(forecastList, MonthlyReportForecastInternalDTO.class);
        }

        /**
         * 获取 Profit 数据
         *
         * @param propertyDTO 资产
         * @param startDate   开始时间(yyyyMM)
         * @param endDate     结束时间(yyyyMM)
         * @return MonthlyReportProfitInternalDTO 集合
         * @author zc
         * @date 2025/8/26
         */
        @Override
        public List<MonthlyReportProfitInternalDTO> listProfit(PropertyDTO propertyDTO, long startDate, long endDate) {
            // 获取月报数据
            List<MonthlyReport> monthlyReportList = monthlyReportService.listByDateRange(propertyDTO.getId(), startDate, endDate);
            if (CollectionUtils.isEmpty(monthlyReportList)) {
                return Collections.emptyList();
            }
            List<Long> monthlyReportIds = monthlyReportList.stream().map(MonthlyReport::getId).toList();
            List<Profit> profitList = profitService.list(new LambdaQueryWrapper<Profit>()
                    .in(Profit::getReportId, monthlyReportIds)
                    .eq(Profit::getPropertyId, propertyDTO.getId()));

            Map<Long, Long> reportId2YearMonth = monthlyReportList.stream()
                    .collect(Collectors.toMap(MonthlyReport::getId, item ->
                            YearMonthUtils.parseYearMonthToLong(YearMonth.of(item.getYear(), item.getMonth()))));
            return beanMapper.mapList(profitList, MonthlyReportProfitInternalDTO.class, (entity, dto) ->
                    dto.setYearMonth(reportId2YearMonth.get(entity.getReportId())));
        }

        /**
         * 获取 Room Revenue 数据
         *
         * @param propertyDTO 资产
         * @param startDate   开始时间(yyyyMM)
         * @param endDate     结束时间(yyyyMM)
         * @return MonthlyReportRoomRevenueInternalDTO 集合
         * @author zc
         * @date 2025/8/26
         */
        @Override
        public List<MonthlyReportRoomRevenueInternalDTO> listRoomRevenue(PropertyDTO propertyDTO, long startDate, long endDate) {
            // 获取月报数据
            List<MonthlyReport> monthlyReportList = monthlyReportService.listByDateRange(propertyDTO.getId(), startDate, endDate);
            if (CollectionUtils.isEmpty(monthlyReportList)) {
                return Collections.emptyList();
            }
            List<Long> monthlyReportIds = monthlyReportList.stream().map(MonthlyReport::getId).toList();
            List<RoomRevenue> profitList = roomRevenueService.list(new LambdaQueryWrapper<RoomRevenue>()
                    .in(RoomRevenue::getReportId, monthlyReportIds)
                    .eq(RoomRevenue::getPropertyId, propertyDTO.getId()));

            Map<Long, Long> reportId2YearMonth = monthlyReportList.stream()
                    .collect(Collectors.toMap(MonthlyReport::getId, item ->
                            YearMonthUtils.parseYearMonthToLong(YearMonth.of(item.getYear(), item.getMonth()))));
            return beanMapper.mapList(profitList, MonthlyReportRoomRevenueInternalDTO.class, (entity, dto) ->
                    dto.setYearMonth(reportId2YearMonth.get(entity.getReportId())));
        }
    }