# AdjReportController.java

    package cloud.wconnect.frontoffice.controller.adjustment;

    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.pojo.dto.group.Edition;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.frontoffice.entity.adjustment.AdJournalLog;
    import cloud.wconnect.frontoffice.parsereport.adjustment.IParseJournalByCashierAndTransactionCodeService;
    import cloud.wconnect.frontoffice.pojo.dto.adjustment.AdjImportReportDTO;
    import cloud.wconnect.frontoffice.pojo.group.Addition;
    import cloud.wconnect.frontoffice.pojo.query.adjustment.ImportLogQuery;
    import cloud.wconnect.frontoffice.pojo.vo.adjustment.AdjImportLogVO;
    import cloud.wconnect.frontoffice.service.adjustment.IAdJournalLogService;
    import com.google.common.collect.Lists;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.ApplicationContext;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.multipart.MultipartFile;

    import jakarta.validation.Valid;

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

    /**
     * @author lichen
     * @description adjustment模块异常前端控制器
     * @date 2023/4/5 11:26
     */
    @Slf4j
    @RestController
    @RequestMapping("/adjustment/import-report-log")
    public class AdjReportController {

        @Autowired
        private IAdJournalLogService adJournalLogService;
        @Autowired
        private SessionContext sessionContext;
        @Autowired
        private ApplicationContext applicationContext;
        @Value("${file-max-size.import-report.adjustment}")
        private long importReportFileMaxSize;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;

        /**
         * 查询导入记录
         *
         * @param property 资产标识
         * @param query    查询条件
         * @return cloud.wconnect.commonlib.pojo.dto.ListPagedDTO<cloud.wconnect.frontoffice.pojo.vo.adjustment.AdjImportLogVO>
         * @author lichen
         * @date 2023/9/28
         */
        @ApiId(279)
        @GetMapping
        public ListPagedDTO<AdjImportLogVO> page(String property, @Valid ImportLogQuery query) {
            int propertyId = sessionContext.getPropertyId(property);
            Integer tenantId = sessionContext.getTenantSymbolBO().getId();

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

        /**
         * 导入报告
         *
         * @param property           资产
         * @param adjImportReportDTO 导入DTO
         * @return java.util.Map
         * @author lichen
         * @date 2023/9/28
         */
        @ApiId(775)
        @PostMapping("/import")
        public Map<String, String> importReport(String property, @Validated(Addition.class) AdjImportReportDTO adjImportReportDTO) {
            PropertyDTO propertyDTO = propertyI18nRedisService.get(sessionContext.getPropertyId(property));

            // 校验最多选择1天的数据
            Long startDate = adjImportReportDTO.getStartDate();
            Long endDate = adjImportReportDTO.getEndDate();
            long interval = DateTimeUtils.dateDiffOfDays(startDate, endDate, propertyDTO.getTimezone());
            if (interval > 0) {
                throw new BadRequestException(CommonErrorI18nConstant.SELECT_DATE_LIMIT,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate(1),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The selected date exceeds the limit");
            }

            //校验source是否符合预期
            checkSource(propertyDTO, adjImportReportDTO.getSource());

            MultipartFile file = adjImportReportDTO.getFile();
            //校验文件大小
            checkFileSize(file);

            //获取解析的类集合
            Collection<IParseJournalByCashierAndTransactionCodeService> parserList = applicationContext.getBeansOfType(IParseJournalByCashierAndTransactionCodeService.class).values();
            for (IParseJournalByCashierAndTransactionCodeService parser : parserList) {
                if (parser.supports(adjImportReportDTO.getSource())) {
                    //校验文件后缀、内容是否满足需求
                    parser.checkFile(file, propertyDTO);

                    //插入一条处理中的导入记录
                    long logId = adJournalLogService.insertInProgress(propertyDTO, adjImportReportDTO, sessionContext.getLoginUserId());

                    //处理文件数据
                    parser.handleData(propertyDTO, file, adjImportReportDTO.getStartDate(),
                            adjImportReportDTO.getEndDate(), logId, sessionContext.getLoginUserId());
                    break;
                }
            }
            return Collections.emptyMap();
        }

        /**
         * 解决异常的日志
         *
         * @param logId              日志id
         * @param property           资产标识
         * @param adjImportReportDTO 导入报告DTO
         * @return java.util.Map
         * @author lichen
         * @date 2023/9/29
         */
        @ApiId(280)
        @PutMapping("/{id:\\d+}/resolved")
        public Map resolve(@PathVariable(name = "id") long logId, String property,
                           @Validated(Edition.class) AdjImportReportDTO adjImportReportDTO) {
            PropertyDTO propertyDTO = propertyI18nRedisService.get(sessionContext.getPropertyId(property));
            //校验source是否符合预期
            checkSource(propertyDTO, adjImportReportDTO.getSource());

            MultipartFile file = adjImportReportDTO.getFile();
            //校验文件大小
            checkFileSize(file);

            //检查是否存在 且 归属于当前资产
            AdJournalLog oriJournalLog = checkExistAndBelongProperty(logId, propertyDTO.getId());
            //校验状态是否合法
            if (!Lists.newArrayList(ReportImportResultCons.IMPORT_RESULT_FAIL, ReportImportResultCons.IMPORT_RESULT_MISSED)
                    .contains(oriJournalLog.getStatus())) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_INTEGRATION_ONLY_HANDLE_EXCEPTION,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "Cannot operate status is not importResultFail or importResultMissed log");
            }

            //获取解析的类集合
            Collection<IParseJournalByCashierAndTransactionCodeService> parserList = applicationContext.getBeansOfType(IParseJournalByCashierAndTransactionCodeService.class).values();
            for (IParseJournalByCashierAndTransactionCodeService parser : parserList) {
                if (parser.supports(adjImportReportDTO.getSource())) {
                    //校验文件后缀、内容是否满足需求
                    parser.checkFile(file, propertyDTO);

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

                    //处理文件数据
                    parser.handleData(propertyDTO, file, oriJournalLog.getStartDate(),
                            oriJournalLog.getEndDate(), oriJournalLog.getId(), sessionContext.getLoginUserId());
                    break;
                }
            }
            return Collections.emptyMap();
        }

        /**
         * 忽略Journal by Cashier and Transaction Code/service 导入异常
         *
         * @param property 资产标识
         * @param logId    日志id
         * @return java.util.Map
         * @author lichen
         * @date 2023/9/29
         */
        @ApiId(774)
        @PutMapping("{id:\\d+}/ignore-exception")
        public Map ignoreException(String property, @PathVariable(name = "id") Long logId) {
            int propertyId = sessionContext.getPropertyId(property);
            AdJournalLog adJournalLog = checkExistAndBelongProperty(logId, propertyId);
            //可以忽略的状态
            List<Integer> canIgnoreStatus = Lists.newArrayList(ReportImportResultCons.IMPORT_RESULT_FAIL, ReportImportResultCons.IMPORT_RESULT_MISSED);
            if (!canIgnoreStatus.contains(adJournalLog.getStatus())) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_INTEGRATION_ONLY_HANDLE_EXCEPTION,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "Cannot operate status is not importResultFail or importResultMissed log");
            }
            //设置为忽略
            adJournalLog.setStatus(ReportImportResultCons.IMPORT_RESULT_IGNORE);
            adJournalLog.setResolvedBy(sessionContext.getLoginUserId());
            adJournalLog.setResolvedTime(DateTimeUtils.nowTimestamp());
            //更新
            adJournalLogService.updateById(adJournalLog);
            return Collections.emptyMap();
        }

        /**
         * 检查是否存在 且 归属于当前资产
         *
         * @param id         日志id
         * @param propertyId 资产id
         * @return cloud.wconnect.frontoffice.entity.adjustment.AdJournalLog
         * @author lichen
         * @date 2023/9/29
         */
        private AdJournalLog checkExistAndBelongProperty(Long id, Integer propertyId) {
            AdJournalLog byId = adJournalLogService.getById(id);
            if (Objects.isNull(byId)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_FOUND,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "Adjustment Requests journal log not found, id = " + id);
            }
            if (byId.getPropertyId().compareTo(propertyId) != 0) {
                throw new ForbiddenException(BaseErrorCodeEnum.DATA_FORBIDDEN.getI18nCode(),
                        BaseErrorCodeEnum.DATA_FORBIDDEN.getCode(),
                        MessageFormat.format("Adjustment Requests journal log not belong current property, journalLogId:{0}, " +
                                "journalLogBelongPropertyId:{1}, currentPropertyId:{2}", id, byId.getPropertyId(), propertyId));
            }
            return byId;
        }

        /**
         * 校验文件大小
         *
         * @param file 文件
         * @return void
         * @author lichen
         * @date 2024/2/22
         */
        private void checkFileSize(MultipartFile file) {
            if (file.getSize() > importReportFileMaxSize) {
                throw new BadRequestException(CommonErrorI18nConstant.FILE_SIZE_ERROR,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The fileSize max is " + importReportFileMaxSize);
            }
        }

        /**
         * 校验source是否符合预期
         *
         * @param propertyDTO 资产DTO
         * @param source      来源
         * @return void
         * @author lichen
         * @date 2025/7/26
         */
        private void checkSource(PropertyDTO propertyDTO, String source) {
            String pmsType = propertyDTO.getPmsType();
            //校验source是否符合预期
            if (!Lists.newArrayList(pmsType, SystemPlatformEnum.OTHER.getDesc()).contains(source)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_INTEGRATION_SOURCE_SYSTEM_NOT_SUPPORTED,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The source must be in:" + pmsType + "|" + SystemPlatformEnum.OTHER.getDesc());
            }
        }

    }