# ReportImportLogController.java

    package cloud.wconnect.rateshop.controller.rateshop;

    import cloud.wconnect.commonlib.annotation.ApiId;
    import cloud.wconnect.commonlib.component.SessionContext;
    import cloud.wconnect.commonlib.cons.*;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.exception.ForbiddenException;
    import cloud.wconnect.commonlib.pojo.dto.ListPagedDTO;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.rateshop.cons.rateshop.RateShopCons;
    import cloud.wconnect.rateshop.cons.rateshop.RateShopNotifyConfigTypeEnum;
    import cloud.wconnect.rateshop.entity.rateshop.ReportImportLog;
    import cloud.wconnect.rateshop.pojo.dto.rateshop.ReportImportDTO;
    import cloud.wconnect.rateshop.pojo.dto.rateshop.ResolveReportExceptionDTO;
    import cloud.wconnect.rateshop.pojo.query.rateshop.RateShopImportLogQuery;
    import cloud.wconnect.rateshop.pojo.vo.rateshop.ReportImportLogVO;
    import cloud.wconnect.rateshop.service.rateshop.IReportImportLogService;
    import cloud.wconnect.rateshop.service.rateshop.grouppickup.IRateShopGroupPickupService;
    import cloud.wconnect.rateshop.service.rateshop.historyandforecast.IRateShopHistoryAndForecastService;
    import com.google.common.collect.Lists;
    import jakarta.validation.Valid;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.multipart.MultipartFile;

    import java.text.MessageFormat;
    import java.util.*;

    /**
     * <p>
     * 前端控制器
     * </p>
     *
     * @author lichen
     * @since 2023-12-04
     */
    @RestController
    @RequestMapping("/rate-shop/import-log")
    public class ReportImportLogController {

        @Autowired
        private SessionContext sessionContext;
        @Autowired
        private IReportImportLogService importLogService;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;
        @Autowired
        private ApplicationContext applicationContext;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;

        /**
         * 导入记录
         *
         * @param property 资产标识
         * @param query    查询对象
         * @return cloud.wconnect.commonlib.pojo.dto.ListPagedDTO<cloud.wconnect.rateshop.pojo.vo.rateshop.ImportLogVO>
         * @author lichen
         * @date 2023/12/4
         */
        @ApiId(940)
        @GetMapping
        public ListPagedDTO<ReportImportLogVO> listImportLog(String property, @Valid RateShopImportLogQuery query) {
            int propertyId = sessionContext.getPropertyId(property);
            Integer tenantId = sessionContext.getTenantSymbolBO().getId();
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);

            if(Objects.nonNull(query.getReportType())){
                //校验reportType是否符合预期
                checkReportType(propertyDTO.getPmsType(), query.getReportType());
            }

            return importLogService.pageList(tenantId, propertyId, query);
        }

        /**
         * 手动导入报告
         *
         * @param property        资产标识
         * @param reportImportDTO 导入DTO
         * @return java.util.Map
         * @author zc
         * @date 2024/3/23
         */
        @ApiId(941)
        @PostMapping
        public Map<Object, Object> importReport(String property, @Valid ReportImportDTO reportImportDTO) {
            PropertyDTO propertyDTO = propertyI18nRedisService.get(sessionContext.getPropertyId(property));
            String pmsType = propertyDTO.getPmsType();
            int loginUserId = sessionContext.getLoginUserId();

            //校验source是否符合预期
            if (!Lists.newArrayList(pmsType, SystemPlatformEnum.OTHER.getDesc()).contains(reportImportDTO.getSource())) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_INTEGRATION_SOURCE_SYSTEM_NOT_SUPPORTED,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The source must be in:" + pmsType + "|" + SystemPlatformEnum.OTHER.getDesc());
            }

            //校验reportType是否符合预期
            checkReportType(pmsType, reportImportDTO.getReportType());

            //上传的文件
            MultipartFile file = reportImportDTO.getFile();

            if (reportImportDTO.getReportType() == RateShopNotifyConfigTypeEnum.HISTORY_AND_FORECAST_REPORT_MISSED.getType()) {
                Collection<IRateShopHistoryAndForecastService> values = applicationContext.getBeansOfType(IRateShopHistoryAndForecastService.class).values();
                for (IRateShopHistoryAndForecastService parser : values) {
                    if (parser.supports(reportImportDTO.getSource())) {
                        //校验文件
                        parser.checkFile(file);

                        //保存进行中的记录
                        ReportImportLog reportImportLog = importLogService.saveInProgress(propertyDTO, reportImportDTO, loginUserId);

                        //处理文件
                        parser.handleData(propertyDTO, file, reportImportLog.getStartDate(), reportImportLog.getEndDate(),
                                reportImportLog.getId(), loginUserId);
                        break;
                    }
                }
            } else {
                Collection<IRateShopGroupPickupService> values = applicationContext.getBeansOfType(IRateShopGroupPickupService.class).values();
                for (IRateShopGroupPickupService parser : values) {
                    if (parser.supports(reportImportDTO.getSource())) {
                        //校验文件
                        parser.checkFile(file);

                        //保存进行中的记录
                        ReportImportLog reportImportLog = importLogService.saveInProgress(propertyDTO, reportImportDTO, loginUserId);

                        //处理文件
                        parser.handleData(propertyDTO, file, reportImportLog.getStartDate(), reportImportLog.getEndDate(),
                                reportImportLog.getId(), loginUserId);
                        break;
                    }
                }
            }
            return Collections.emptyMap();
        }

        /**
         * 解决异常
         *
         * @param logId                     异常日志ID
         * @param property                  资产标识
         * @param resolveReportExceptionDTO 解决报告异常DTO
         * @return java.util.Map
         * @author zc
         * @date 2024/3/23
         */
        @ApiId(942)
        @PutMapping("/{id:\\d+}/resolve")
        public Map<Object, Object> resolve(@PathVariable(name = "id") long logId, String property, ResolveReportExceptionDTO resolveReportExceptionDTO) {
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);

            //检查是否存在 且 归属于当前资产
            ReportImportLog oriReportImportLog = checkExistAndBelongProperty(logId, propertyDTO.getId());
            //校验是否是失败、缺失记录
            checkImportResult(oriReportImportLog.getStatus());

            int loginUserId = sessionContext.getLoginUserId();

            if (Objects.isNull(resolveReportExceptionDTO.getFile())) {
                //更新为忽略
                ReportImportLog updateContent = new ReportImportLog();
                updateContent.setId(logId);
                updateContent.setResolvedBy(loginUserId);
                updateContent.setResolvedTime(DateTimeUtils.nowTimestamp());
                updateContent.setStatus(ReportImportResultCons.IMPORT_RESULT_IGNORE);
                importLogService.updateById(updateContent);
                return Collections.emptyMap();
            }

            //校验source是否符合预期
            String pmsType = propertyDTO.getPmsType();
            if(StringUtils.isBlank(resolveReportExceptionDTO.getSource())){
                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_EMPTY,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate(CommonFieldI18nConstant.DATA_INTEGRATION_SOURCE),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The source cannot be blank");
            }
            if (!Lists.newArrayList(pmsType, SystemPlatformEnum.OTHER.getDesc()).contains(resolveReportExceptionDTO.getSource())) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_INTEGRATION_SOURCE_SYSTEM_NOT_SUPPORTED,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The source must be in:" + pmsType + "|" + SystemPlatformEnum.OTHER.getDesc());
            }

            //获取文件
            MultipartFile file = resolveReportExceptionDTO.getFile();

            if (oriReportImportLog.getReportType() == RateShopNotifyConfigTypeEnum.HISTORY_AND_FORECAST_REPORT_MISSED.getType()) {
                Collection<IRateShopHistoryAndForecastService> values = applicationContext.getBeansOfType(IRateShopHistoryAndForecastService.class).values();
                for (IRateShopHistoryAndForecastService parser : values) {
                    if (parser.supports(resolveReportExceptionDTO.getSource())) {
                        //校验文件
                        parser.checkFile(file);

                        //更新为修复中
                        importLogService.updateById(new ReportImportLog().setId(logId).setStatus(ReportImportResultCons.IMPORT_RESULT_REPAIRING));

                        //处理文件
                        parser.handleData(propertyDTO, file, oriReportImportLog.getStartDate(), oriReportImportLog.getEndDate(),
                                logId, loginUserId);
                        break;
                    }
                }
            } else {
                Collection<IRateShopGroupPickupService> values = applicationContext.getBeansOfType(IRateShopGroupPickupService.class).values();
                for (IRateShopGroupPickupService parser : values) {
                    if (parser.supports(resolveReportExceptionDTO.getSource())) {
                        //校验文件
                        parser.checkFile(file);

                        //更新为修复中
                        importLogService.updateById(new ReportImportLog().setId(logId).setStatus(ReportImportResultCons.IMPORT_RESULT_REPAIRING));

                        //处理文件
                        parser.handleData(propertyDTO, file, oriReportImportLog.getStartDate(), oriReportImportLog.getEndDate(),
                                logId, loginUserId);
                        break;
                    }
                }
            }
            return Collections.emptyMap();
        }

        /**
         * 校验是否是失败、缺失记录
         *
         * @param importResult 导入结果
         * @author zc
         * @date 2024/6/13
         */
        private void checkImportResult(int importResult) {
            if (importResult != ReportImportResultCons.IMPORT_RESULT_FAIL
                    && importResult != ReportImportResultCons.IMPORT_RESULT_MISSED) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_INTEGRATION_ONLY_HANDLE_EXCEPTION,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "Cannot operate status is not importResultFail or importResultMissed log");
            }
        }

        /**
         * 检查是否存在 且 归属于当前资产
         *
         * @param id         日志id
         * @param propertyId 资产id
         * @return cloud.wconnect.rateshop.entity.rateshop.ReportImportLog
         * @author lichen
         * @date 2023/12/4
         */
        private ReportImportLog checkExistAndBelongProperty(Long id, Integer propertyId) {
            ReportImportLog byId = importLogService.getById(id);
            if (Objects.isNull(byId)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_FOUND,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "Rate shop report log not found, id = " + id);
            }
            if (byId.getPropertyId().compareTo(propertyId) != 0) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(),
                        BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(),
                        MessageFormat.format("Rate shop report log not belong current property, logId:{0}, " +
                                "logBelongPropertyId:{1}, currentPropertyId:{2}", id, byId.getPropertyId(), propertyId));
            }
            return byId;
        }

        /**
         * 校验报告类型是否符合预期
         *
         * @param pmsType    当前资产配置的PMS Type
         * @param reportType 报告类型
         * @return void
         * @author lichen
         * @date 2025/7/5
         */
        private void checkReportType(String pmsType, Integer reportType) {
            List<Integer> validReportTypes;
            if (SystemPlatformEnum.OPERA.getDesc().equals(pmsType)) {
                validReportTypes = RateShopCons.OPERA_PMS_REPORT_TYPE_LIST;
            } else {
                validReportTypes = RateShopCons.SHIJI_PMS_REPORT_TYPE_LIST;
            }
            if (!validReportTypes.contains(reportType)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_INTEGRATION_REPORT_TYPE_NOT_SUPPORTED,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The reportType must be in:" + validReportTypes);
            }
        }
    }