# MorSalesSourceOperatingStatisticsDailyTask.java

    package cloud.wconnect.workperformance.businesstask.mor.sales;

    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.cons.ReportImportResultCons;
    import cloud.wconnect.commonlib.pojo.dto.NotifyDTO;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.pojo.dto.scheduler.JobParameterDTO;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.service.NotifyInternalService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.InternationalizationUtils;
    import cloud.wconnect.commonlib.util.JobParameterUtils;
    import cloud.wconnect.commonlib.util.JsonUtils;
    import cloud.wconnect.workperformance.entity.mor.MorScheduler;
    import cloud.wconnect.workperformance.entity.mor.SalesImportLog;
    import cloud.wconnect.workperformance.entity.mor.SalesOperatingStatistics;
    import cloud.wconnect.workperformance.pojo.dto.mor.sales.SalesImportReportDTO;
    import cloud.wconnect.workperformance.service.mor.ISalesImportLogService;
    import cloud.wconnect.workperformance.service.mor.ISalesOperatingStatisticsService;
    import cloud.wconnect.workperformance.service.mor.ISalesSendNotifyService;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import jakarta.annotation.Resource;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Component;

    import java.time.LocalDate;
    import java.util.Map;
    import java.util.Objects;

    /**
     * 定时任务：Sales sources Operating Statistics Daily
     *
     * @author zc
     * @date 2024/6/3
     */
    @Slf4j
    @Component
    public class MorSalesSourceOperatingStatisticsDailyTask {
        @Resource
        private ISalesOperatingStatisticsService salesOperatingStatisticsService;
        @Resource
        private ISalesImportLogService importLogService;
        @Resource
        private ISalesSendNotifyService sendNotifyService;
        @Resource
        private PropertyI18nRedisService propertyI18nRedisService;
        @Resource
        private NotifyInternalService notifyInternalService;
        @Resource
        private ObjectMapper objectMapper;

        /**
         * 检查上个月的报告数据是否缺失
         *
         * <p>
         * 检查报告缺失：每月月初 01:00:00
         * </p>
         *
         * @param schedulerJob 调度数据
         * @author zc
         * @date 2024/6/3
         */
        @Async
        public void dataMissingCheck(MorScheduler schedulerJob) {
            log.info("MorSalesSourceOperatingStatisticsDailyTask.dataMissingCheck start...");

            int propertyId = schedulerJob.getPropertyId();
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            if (!propertyDTO.getStatus()) {
                log.warn("MorSalesSourceOperatingStatisticsDailyTask.dataMissingCheck end... the property is closed, no processing required");
                return;
            }

            JobParameterDTO jobParameterDTO = JsonUtils.convertStringToObject(objectMapper,
                    schedulerJob.getParameters(), JobParameterDTO.class);
            // 获取报告日期范围
            Map<String, Long> dateRange = getDateRange(jobParameterDTO, propertyDTO.getTimezone());

            // 根据日期范围检查是否有数据
            if (checkDataExist(propertyDTO, dateRange)) {
                log.info("MorSalesSourceOperatingStatisticsDailyTask.dataMissingCheck end... data is empty");
                return;
            }

            // 记录报告缺失日志
            saveImportLog(propertyId, dateRange);

            // 获取通知配置
            String reportName = "Operating Statistics Daily";
            String missDate = getMissDate(propertyDTO, dateRange);
            NotifyDTO notify = sendNotifyService.getNotifyDTO(propertyDTO, reportName, missDate, schedulerJob.getCategory());
            if (Objects.isNull(notify)) {
                log.info("MorSalesSourceOperatingStatisticsDailyTask.dataMissingCheck end... notifyDTO is null");
                return;
            }

            // 发送通知
            notifyInternalService.sendNotify(notify);

            log.info("MorSalesSourceOperatingStatisticsDailyTask.dataMissingCheck end...");
        }

        /**
         * 记录报告缺失日志
         *
         * @param propertyId 资产 id
         * @param dateRange  日期范围
         * @author zc
         * @date 2024/6/3
         */
        private void saveImportLog(int propertyId, Map<String, Long> dateRange) {
            importLogService.save(SalesImportLog.builder()
                    .propertyId(propertyId)
                    .reportType(SalesImportReportDTO.REPORT_TYPE_OPERATING)
                    .theDate(Long.parseLong(DateTimeUtils.localDateToStr(LocalDate.now(),
                            BaseConstant.DATE_FORMAT_YYYYMMDD)))
                    .startDate(dateRange.get(JobParameterDTO.START_DATE))
                    .endDate(dateRange.get(JobParameterDTO.END_DATE))
                    .importResult(ReportImportResultCons.IMPORT_RESULT_MISSED)
                    .url("")
                    .createdBy(BaseConstant.ZERO)
                    .createdTime(DateTimeUtils.nowTimestamp())
                    .resolvedBy(BaseConstant.ZERO)
                    .resolvedTime(BaseConstant.LONG_ZERO)
                    .build());
        }

        /**
         * 获取报告日期范围
         *
         * @param jobParameterDTO 调度参数 DTO
         * @param timezone        时区
         * @return 日期范围
         * @author zc
         * @date 2024/6/3
         */
        private Map<String, Long> getDateRange(JobParameterDTO jobParameterDTO, String timezone) {
            Map<String, Long> dateRange = JobParameterUtils.parseDateRange(jobParameterDTO.getDateRange(),
                    jobParameterDTO.getDateRangeUnit(), timezone, null);
            long startDate = Long.parseLong(DateTimeUtils.localDateToStr(DateTimeUtils.longToLocalDate(dateRange.get(JobParameterDTO.START_DATE),
                    timezone), BaseConstant.DATE_FORMAT_YYYYMMDD));
            long endDate = Long.parseLong(DateTimeUtils.localDateToStr(DateTimeUtils.longToLocalDate(dateRange.get(JobParameterDTO.END_DATE),
                    timezone), BaseConstant.DATE_FORMAT_YYYYMMDD));
            return Map.of(JobParameterDTO.START_DATE, startDate, JobParameterDTO.END_DATE, endDate);
        }

        /**
         * 根据日期范围检查是否有数据
         *
         * @param propertyDTO 资产
         * @param dateRange   日期范围（时间戳）
         * @return true：有数据 false：无数据
         * @author zc
         * @date 2024/6/3
         */
        private boolean checkDataExist(PropertyDTO propertyDTO, Map<String, Long> dateRange) {
            long count = salesOperatingStatisticsService.count(new QueryWrapper<SalesOperatingStatistics>().lambda()
                    .eq(SalesOperatingStatistics::getPropertyId, propertyDTO.getId())
                    .between(SalesOperatingStatistics::getTheDate, dateRange.get(JobParameterDTO.START_DATE),
                            dateRange.get(JobParameterDTO.END_DATE)));
            return count > BaseConstant.LONG_ZERO;
        }

        /**
         * 获取报告缺失日期
         *
         * @param propertyDTO 资产
         * @param dateRange   日期范围（时间戳）
         * @return 缺失日期
         * @author zc
         * @date 2024/6/3
         */
        private String getMissDate(PropertyDTO propertyDTO, Map<String, Long> dateRange) {
            String language = propertyDTO.getLanguage();
            String pattern = propertyDTO.getInternationalization().getDateTime().getLongDate();
            String startDateStr = InternationalizationUtils.formatYearMonthDate(dateRange.get(JobParameterDTO.START_DATE),
                    pattern, language);
            String endDateStr = InternationalizationUtils.formatYearMonthDate(dateRange.get(JobParameterDTO.END_DATE),
                    pattern, language);
            return startDateStr + " ~ " + endDateStr;
        }
    }