# WMRevenueManualImportGroupPickupHandleService.java

    package cloud.wconnect.rateshop.service.weeklymonthlyrevenue.grouppickup;

    import cloud.wconnect.commonlib.cons.*;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.exception.InternalServerErrorException;
    import cloud.wconnect.commonlib.exception.ParseReportException;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.util.*;
    import cloud.wconnect.rateshop.cons.S3BucketFunctionCons;
    import cloud.wconnect.rateshop.cons.weeklymonthlyrevenue.MonthlyRevenueImportCategoryCons;
    import cloud.wconnect.rateshop.cons.weeklymonthlyrevenue.MonthlyRevenueReportCategoryEnum;
    import cloud.wconnect.rateshop.pojo.bo.weeklymonthlyrevenue.WMRevenueGroupPickupBO;
    import cloud.wconnect.rateshop.pojo.dto.weeklymonthlyrevenue.WeeklyMonthlyRevenueImportReportDTO;
    import cloud.wconnect.rateshop.service.AmazonS3Service;
    import cloud.wconnect.rateshop.service.weeklymonthlyrevenue.IWMRevenueManualImportReportHandleService;
    import cloud.wconnect.rateshop.service.weeklymonthlyrevenue.IWeeklyMonthlyRevenueImportLogService;
    import cloud.wconnect.rateshop.service.weeklymonthlyrevenue.IWeeklyMonthlyRevenueReportService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.google.common.collect.Lists;
    import jakarta.annotation.Nullable;
    import jakarta.annotation.Resource;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.poi.ss.usermodel.Row;
    import org.apache.poi.ss.usermodel.Sheet;
    import org.apache.poi.ss.usermodel.Workbook;
    import org.apache.poi.ss.usermodel.WorkbookFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    import org.springframework.web.multipart.MultipartFile;

    import java.io.IOException;
    import java.io.InputStream;
    import java.time.LocalDate;
    import java.time.format.DateTimeFormatter;
    import java.time.format.DateTimeParseException;
    import java.util.List;
    import java.util.Locale;
    import java.util.Objects;

    /**
     * 手动导入Cancelltion Summary报告处理类
     *
     * @author lichen
     * @date 2025/11/1
     */
    @Slf4j
    @Component
    @DS("rate_shop")
    public class WMRevenueManualImportGroupPickupHandleService implements IWMRevenueManualImportReportHandleService {

        @Resource
        private IWeeklyMonthlyRevenueReportService reportService;
        @Resource
        private AmazonS3Service amazonS3Service;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;
        @Autowired
        private IWeeklyMonthlyRevenueImportLogService importLogService;
        @Value("${aws-s3.third-party.key.weekly-monthly-revenue.group-pickup}")
        private String s3FilePath;
        @Value("${file-max-size.import-report.weekly-monthly-revenue}")
        private long fileMaxSize;

        /**
         * 根据来源和分类判断是否支持此报告
         *
         * @param reportType 报告分类
         * @return boolean
         * @author lichen
         * @date 2025/11/1
         */
        @Override
        public boolean supportsByReportType(int reportType) {
            return reportType == MonthlyRevenueReportCategoryEnum.GROUP_PICKUP.getCategory();
        }

        /**
         * 校验文件内容是否合法
         *
         * @param propertyDTO 资产
         * @param source      来源
         * @param file        文件
         * @author lichen
         * @date 2025/11/1
         */
        @Override
        public void checkFile(PropertyDTO propertyDTO, String source, MultipartFile file) {
            if (SystemPlatformEnum.OPERA.getDesc().equals(source)) {
                checkFileForOpera(file);
            } else if (SystemPlatformEnum.SHI_JI.getDesc().equals(source)) {
                checkFileForShiji(file);
            } else if (SystemPlatformEnum.OTHER.getDesc().equals(source)) {
                checkFileForOther(file);
            }
        }

        /**
         * 校验日期参数，包括：versionDate，startDate，endDate
         *
         * @param propertyDTO 资产
         * @param reportDTO   报告
         * @author lichen
         * @date 2025/11/1
         */
        @Override
        public void checkDate(PropertyDTO propertyDTO, String source, WeeklyMonthlyRevenueImportReportDTO reportDTO) {
            Integer category = reportDTO.getCategory();
            if (category == MonthlyRevenueImportCategoryCons.FORECAST) {
                IWMRevenueManualImportReportHandleService.checkDateForForecast(reportDTO, i18nMessageUtils);
            } else {
                IWMRevenueManualImportReportHandleService.checkDateForHistory(propertyDTO, reportDTO, i18nMessageUtils);
            }
        }

        /**
         * 处理数据
         *
         * @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
         */
        @Override
        public void handleData(PropertyDTO propertyDTO, MultipartFile file, List<Long> dateRange,
                               int category, @Nullable Long versionDate, int operatorId,
                               String source, @Nullable Long importLogId) {
            // 获取报告 S3 Key
            String s3Key = propertyDTO.getTenantSymbol() + "/" + propertyDTO.getAbbr() + "/" + s3FilePath
                    + UploadUtils.getRandomFileName(file.getOriginalFilename());

            boolean importResult = true;
            try (InputStream in = file.getInputStream()) {
                // 上传报告到 S3，用于导入记录下载报告
                amazonS3Service.uploadFile(S3BucketFunctionCons.WEEKLY_MONTHLY_REVENUE_IMPORT_RECORD, file, s3Key);

                // 解析报告
                List<WMRevenueGroupPickupBO> boList = reportService.parseGroupPickupReport(propertyDTO, in, source, dateRange);
                // 处理报告
                reportService.handleGroupPickup(propertyDTO, boList, category, versionDate, operatorId);
            } catch (Exception e) {
                importResult = false;
                throw new ParseReportException(BaseErrorCodeEnum.SYSTEM_ERROR.getI18nCode(),
                        BaseErrorCodeEnum.SYSTEM_ERROR.getCode(),
                        "Handle import Weekly Monthly Revenue Group Pickup report error, source=" + source, e);
            } finally {
                if (importResult) {
                    if (Objects.nonNull(importLogId)) {
                        //解决异常
                        importLogService.manualSolveSuccess(importLogId, operatorId, s3Key);
                    } else {
                        //新增导入记录
                        importLogService.save(propertyDTO, category, versionDate,
                                dateRange, s3Key, ReportImportResultCons.IMPORT_RESULT_SUCCESS,
                                MonthlyRevenueReportCategoryEnum.GROUP_PICKUP.getCategory(), operatorId);
                    }
                }
            }
        }

        /**
         * 校验文件内容
         *
         * @param file 文件
         * @author lichen
         * @date 2025/11/1
         */
        private void checkFileForOpera(MultipartFile file) {
            // 限制文件大小
            FileCheckUtils.checkFileSize(file, fileMaxSize);
            // 校验文件格式
            UploadUtils.checkFileFormat(file, Lists.newArrayList("xml"));
            // 校验文件内容
            try (InputStream inputStream = file.getInputStream()) {
                FileCheckUtils.checkGroupPickup(inputStream);
            } catch (BadRequestException e) {
                throw e;
            } catch (Exception e) {
                throw new InternalServerErrorException(BaseErrorCodeEnum.SYSTEM_ERROR.getI18nCode(),
                        BaseErrorCodeEnum.SYSTEM_ERROR.getCode(),
                        "Check Weekly Monthly Revenue Group Pickup Opera report error", e);
            }
        }

        /**
         * 检查文件
         *
         * @param file 文件
         * @author zc
         * @date 2026/2/7
         */
        private void checkFileForShiji(MultipartFile file) {
            // 限制文件大小
            FileCheckUtils.checkFileSize(file, fileMaxSize);
            // 校验文件格式
            UploadUtils.checkFileFormat(file, Lists.newArrayList("csv"));
            // 校验文件内容
            try (InputStream inputStream = file.getInputStream()) {
                ShijiFileCheckUtils.checkGroupPickup(inputStream);
            } catch (BadRequestException e) {
                throw e;
            } catch (Exception e) {
                throw new InternalServerErrorException(BaseErrorCodeEnum.SYSTEM_ERROR.getI18nCode(),
                        BaseErrorCodeEnum.SYSTEM_ERROR.getCode(),
                        "Check Weekly Monthly Revenue Group Pickup Shiji report error", e);
            }
        }

        /**
         * 校验文件内容
         *
         * @param file 文件
         * @author lichen
         * @date 2025/11/1
         */
        private void checkFileForOther(MultipartFile file) {
            // 限制文件大小
            FileCheckUtils.checkFileSize(file, fileMaxSize);
            // 校验文件格式
            UploadUtils.checkFileFormat(file, Lists.newArrayList("xls", "xlsx"));

            try (InputStream in = file.getInputStream();
                 Workbook workbook = WorkbookFactory.create(in)) {
                Sheet sheet = workbook.getSheetAt(0);
                // 获取最大行数
                int lastRowNum = sheet.getLastRowNum();
                // 若只包含标题，直接返回
                if (lastRowNum < 1) {
                    return;
                }

                // 提取标题
                List<String> titleList = Lists.newArrayList();
                Row titleRow = sheet.getRow(0);
                for (int i = 0; i <= 1; i++) {
                    titleList.add(CellUtils.convertCellStr(titleRow.getCell(i)));
                }

                for (int i = 1; i <= lastRowNum; i++) {
                    Row row = sheet.getRow(i);

                    // 校验 Date
                    String dateStr = CellUtils.convertCellStr(row.getCell(0));
                    if (StringUtils.isBlank(dateStr)) {
                        throw new BadRequestException(CommonErrorI18nConstant.CANNOT_EMPTY,
                                i18nMessageUtils.getErrorParamMapNotNeedTranslate(titleList.get(0)),
                                BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                                "The Date cannot be blank");
                    } else {
                        try {
                            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(BaseConstant.DATE_FORMAT_YYYY_MM_DD, Locale.ENGLISH);
                            LocalDate.parse(dateStr, formatter);
                        } catch (DateTimeParseException e) {
                            throw new BadRequestException(CommonErrorI18nConstant.FORMAT_INCORRECT,
                                    i18nMessageUtils.getErrorParamMapNotNeedTranslate(titleList.get(0), BaseConstant.DATE_FORMAT_YYYY_MM_DD),
                                    BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                                    "The Date format is incorrect, Date = " + dateStr);
                        }
                    }
                    // Group Contracted
                    String groupContractedStr = CellUtils.convertCellStr(row.getCell(1));
                    if (StringUtils.isBlank(groupContractedStr)) {
                        throw new BadRequestException(CommonErrorI18nConstant.CANNOT_EMPTY,
                                i18nMessageUtils.getErrorParamMapNotNeedTranslate(titleList.get(1)),
                                BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                                "The Group Contracted cannot be blank");
                    } else {
                        try {
                            int groupContracted = Integer.parseInt(groupContractedStr);
                            if (groupContracted < 0) {
                                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_LESS_THAN_ZERO,
                                        i18nMessageUtils.getErrorParamMapNotNeedTranslate(titleList.get(1)),
                                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                                        "The Group Contracted cannot be less than 0, Group Contracted = " + groupContractedStr);
                            }
                            if (groupContracted > 1000000) {
                                throw new BadRequestException(CommonErrorI18nConstant.NUMBER_OVERLENGTH,
                                        i18nMessageUtils.getErrorParamMapNotNeedTranslate(titleList.get(1), 6, 0),
                                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                                        "The Group Contracted cannot be greater than 1000000, Group Contracted = " + groupContractedStr);
                            }
                        } catch (NumberFormatException e) {
                            throw new BadRequestException(CommonErrorI18nConstant.MUST_INTEGER,
                                    i18nMessageUtils.getErrorParamMapNotNeedTranslate(titleList.get(1)),
                                    BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                                    "The Group Contracted must integer, Group Contracted = " + groupContractedStr);
                        }
                    }
                }
            } catch (IOException e) {
                throw new InternalServerErrorException(BaseErrorCodeEnum.SYSTEM_ERROR.getI18nCode(),
                        BaseErrorCodeEnum.SYSTEM_ERROR.getCode(),
                        "Handle check Weekly Monthly Revenue Group Pickup Other report error.", e);
            }
        }
    }