# IWMRevenueManualImportReportHandleService.java

    package cloud.wconnect.rateshop.service.weeklymonthlyrevenue;

    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.CommonErrorI18nConstant;
    import cloud.wconnect.commonlib.cons.CommonFieldI18nConstant;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.rateshop.cons.weeklymonthlyrevenue.MonthlyRevenueI18nConstant;
    import cloud.wconnect.rateshop.pojo.dto.weeklymonthlyrevenue.WeeklyMonthlyRevenueImportReportDTO;
    import jakarta.annotation.Nullable;
    import org.springframework.web.multipart.MultipartFile;

    import java.text.MessageFormat;
    import java.time.LocalDate;
    import java.time.ZoneId;
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Objects;

    /**
     * Monthly Revenue功能手动导入报告处理接口，包括：非解决异常时手动导入报告、解决异常时手动导入报告
     *
     * @author lichen
     * @date 2025/10/31
     */
    public interface IWMRevenueManualImportReportHandleService {

        /**
         * 根据来源和分类判断是否支持此报告
         *
         * @param reportType 报告分类
         * @return boolean
         * @author lichen
         * @date 2025/10/31
         */
        boolean supportsByReportType(int reportType);

        /**
         * 校验文件内容是否合法
         *
         * @param propertyDTO 资产
         * @param source      来源
         * @param file        文件
         * @author lichen
         * @date 2025/10/31
         */
        void checkFile(PropertyDTO propertyDTO, String source, MultipartFile file);

        /**
         * 校验日期参数，包括：versionDate，startDate，endDate
         *
         * @param propertyDTO 资产
         * @param reportDTO   报告
         * @author lichen
         * @date 2025/10/31
         */
        void checkDate(PropertyDTO propertyDTO, String source, WeeklyMonthlyRevenueImportReportDTO reportDTO);

        /**
         * 处理数据
         *
         * @param propertyDTO 资产
         * @param file        文件
         * @param dateRange   报告数据日期范围(yyyyMMdd)
         * @param category    0:全部 1:历史 2:未来
         * @param versionDate 版本日期（yyyyMMdd）
         * @param operatorId  操作人 id
         * @param source      来源
         * @param importLogId 导入日志 id
         * @author lichen
         * @date 2025/10/31
         */
        void handleData(PropertyDTO propertyDTO, MultipartFile file, List<Long> dateRange,
                        int category, @Nullable Long versionDate, int operatorId,
                        String source, @Nullable Long importLogId);

        /**
         * 上传未来日期的报告时，校验日期参数
         *
         * @param reportDTO        报告
         * @param i18nMessageUtils 国际化消息工具
         * @author lichen
         * @date 2025/10/31
         */
        static void checkDateForForecast(WeeklyMonthlyRevenueImportReportDTO reportDTO, I18nMessageUtils i18nMessageUtils) {
            // category 为 forecast 时，versionDate 不能为空
            if (Objects.isNull(reportDTO.getVersionDate())) {
                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_EMPTY,
                        i18nMessageUtils.getErrorParamMapNeedTranslate(MonthlyRevenueI18nConstant.VERSION_DATE),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The versionDate cannot be blank when category is forecast.");
            }

            LocalDate startLocalDate = DateTimeUtils.strToLocalDate(reportDTO.getStartDate().toString(),
                    BaseConstant.DATE_FORMAT_YYYYMMDD);
            LocalDate endLocalDate = DateTimeUtils.strToLocalDate(reportDTO.getEndDate().toString(),
                    BaseConstant.DATE_FORMAT_YYYYMMDD);
            LocalDate versionLocalDate = DateTimeUtils.strToLocalDate(reportDTO.getVersionDate().toString(),
                    BaseConstant.DATE_FORMAT_YYYYMMDD);

            // startDate 不能小于 versionDate
            if (startLocalDate.isBefore(versionLocalDate)) {
                String targetDate = DateTimeUtils.localDateToStr(versionLocalDate, BaseConstant.DATE_FORMAT_YYYY_MM_DD);

                LinkedHashMap<String, Boolean> map = new LinkedHashMap<>();
                map.put(CommonFieldI18nConstant.START_DATE, true);
                map.put(targetDate, false);

                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_LESS_THAN,
                        i18nMessageUtils.getErrorParamMap(map),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        MessageFormat.format("The startDate cannot less than {0}.", targetDate));
            }
            // endDate 最大为 versionDate 加100天
            if (endLocalDate.isAfter(versionLocalDate.plusDays(100))) {
                String targetDate = DateTimeUtils.localDateToStr(versionLocalDate.plusDays(100), BaseConstant.DATE_FORMAT_YYYY_MM_DD);

                LinkedHashMap<String, Boolean> map = new LinkedHashMap<>();
                map.put(CommonFieldI18nConstant.END_DATE, true);
                map.put(targetDate, false);

                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_GREATER_THAN,
                        i18nMessageUtils.getErrorParamMap(map),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        MessageFormat.format("The endDate cannot greater than {0}.", targetDate));
            }

            //校验startDate不能大于endDate
            checkStartDateIsAfterEndDate(startLocalDate, endLocalDate, i18nMessageUtils);
        }

        /**
         * 上传历史日期报告时，校验日期参数
         *  VersionDate<=当前日期、endDate<versionDate、startDate<endDate
         *
         * @param propertyDTO      资产DTO
         * @param reportDTO        报告DTO
         * @param i18nMessageUtils 国际化消息工具
         * @author lichen
         * @date 2025/10/31
         */
        static void checkDateForHistory(PropertyDTO propertyDTO, WeeklyMonthlyRevenueImportReportDTO reportDTO, I18nMessageUtils i18nMessageUtils) {
            String timezone = propertyDTO.getTimezone();

            LocalDate versionLocalDate = DateTimeUtils.strToLocalDate(reportDTO.getVersionDate().toString(),
                    BaseConstant.DATE_FORMAT_YYYYMMDD);
            LocalDate endLocalDate = DateTimeUtils.strToLocalDate(reportDTO.getEndDate().toString(),
                    BaseConstant.DATE_FORMAT_YYYYMMDD);
            LocalDate startLocalDate = DateTimeUtils.strToLocalDate(reportDTO.getStartDate().toString(),
                    BaseConstant.DATE_FORMAT_YYYYMMDD);
            LocalDate currentDate = LocalDate.now(ZoneId.of(timezone));

            //校验versionDate不能大于当前日期
            checkVersionDateCannotAfterCurrentDate(versionLocalDate, currentDate, i18nMessageUtils);

            //校验endDate必须小于versionDate
            checkEndDateIsLessThanTargetDate(endLocalDate, versionLocalDate, i18nMessageUtils);

            //校验startDate不能大于endDate
            checkStartDateIsAfterEndDate(startLocalDate, endLocalDate, i18nMessageUtils);
        }

        /**
         * 校验endDate必须小于指定日期
         *
         * @param endLocalDate     结束日期
         * @param targetLocalDate  目标日期
         * @param i18nMessageUtils 国际化消息工具
         * @author lichen
         * @date 2025/10/31
         */
        static void checkEndDateIsLessThanTargetDate(LocalDate endLocalDate, LocalDate targetLocalDate, I18nMessageUtils i18nMessageUtils) {
            if (!endLocalDate.isBefore(targetLocalDate)) {
                String targetDate = DateTimeUtils.localDateToStr(targetLocalDate, BaseConstant.DATE_FORMAT_YYYY_MM_DD);

                LinkedHashMap<String, Boolean> map = new LinkedHashMap<>();
                map.put(CommonFieldI18nConstant.END_DATE, true);
                map.put(targetDate, false);

                throw new BadRequestException(CommonErrorI18nConstant.MUST_LESS_THAN,
                        i18nMessageUtils.getErrorParamMap(map),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        MessageFormat.format("The endDate must less than {0}.", targetDate));
            }
        }

        /**
         * 校验开始日期不能大于结束日期
         *
         * @param startLocalDate   开始日期
         * @param endLocalDate     结束日期
         * @param i18nMessageUtils 国际化消息工具
         * @author lichen
         * @date 2025/10/31
         */
        static void checkStartDateIsAfterEndDate(LocalDate startLocalDate, LocalDate endLocalDate, I18nMessageUtils i18nMessageUtils) {
            if (startLocalDate.isAfter(endLocalDate)) {
                String targetDate = DateTimeUtils.localDateToStr(endLocalDate, BaseConstant.DATE_FORMAT_YYYY_MM_DD);

                LinkedHashMap<String, Boolean> map = new LinkedHashMap<>();
                map.put(CommonFieldI18nConstant.START_DATE, true);
                map.put(targetDate, false);

                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_GREATER_THAN,
                        i18nMessageUtils.getErrorParamMap(map),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        MessageFormat.format("The startDate cannot greater than {0}.", targetDate));
            }
        }

        /**
         * 校验VersionDate不能大于当前日期
         *
         * @param versionLocalDate 版本日期
         * @param currentLocalDate 当前日期
         * @param i18nMessageUtils 国际化消息工具
         * @author lichen
         * @date 2025/12/15
         */
        static void checkVersionDateCannotAfterCurrentDate(LocalDate versionLocalDate, LocalDate currentLocalDate, I18nMessageUtils i18nMessageUtils) {
            if (versionLocalDate.isAfter(currentLocalDate)) {
                String targetDate = DateTimeUtils.localDateToStr(currentLocalDate, BaseConstant.DATE_FORMAT_YYYY_MM_DD);

                LinkedHashMap<String, Boolean> map = new LinkedHashMap<>();
                map.put(MonthlyRevenueI18nConstant.VERSION_DATE, true);
                map.put(targetDate, false);

                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_GREATER_THAN,
                        i18nMessageUtils.getErrorParamMap(map),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        MessageFormat.format("The versionDate cannot greater than {0}.", targetDate));
            }
        }
    }