# JournalByCashierAndTransactionCodeServiceTask.java

    package cloud.wconnect.frontoffice.businesstask.adjustment;

    import cloud.wconnect.commonlib.businesstask.CheckReportMissedService;
    import cloud.wconnect.commonlib.businesstask.rule.MissedRuleByThreshold;
    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.FunctionCons;
    import cloud.wconnect.commonlib.cons.PmsReportEnum;
    import cloud.wconnect.commonlib.pojo.dto.*;
    import cloud.wconnect.commonlib.pojo.dto.internationalization.InternationalizationDateTimeDTO;
    import cloud.wconnect.commonlib.pojo.dto.line.ReportMissedMsgParm;
    import cloud.wconnect.commonlib.pojo.dto.scheduler.JobParameterDTO;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.service.PropertyInternalService;
    import cloud.wconnect.commonlib.util.*;
    import cloud.wconnect.frontoffice.cons.BusinessEnum;
    import cloud.wconnect.frontoffice.cons.EventSubjectEnum;
    import cloud.wconnect.frontoffice.cons.FunctionPointEnum;
    import cloud.wconnect.frontoffice.cons.adjustment.AdjNotifyConfigTypeEnum;
    import cloud.wconnect.frontoffice.entity.adjustment.AdjEmailConfig;
    import cloud.wconnect.frontoffice.entity.adjustment.AdjEmailTarget;
    import cloud.wconnect.frontoffice.entity.adjustment.SchedulerJob;
    import cloud.wconnect.frontoffice.service.adjustment.IAdjEmailConfigService;
    import cloud.wconnect.frontoffice.service.adjustment.IAdjEmailTargetService;
    import com.alibaba.fastjson.JSONObject;
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.google.common.collect.Lists;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.collections.CollectionUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Component;
    import org.thymeleaf.TemplateEngine;
    import org.thymeleaf.context.Context;

    import java.text.MessageFormat;
    import java.util.Collections;
    import java.util.List;
    import java.util.Map;
    import java.util.Objects;
    import java.util.concurrent.TimeUnit;

    /**
     * @author lichen
     * @description 定时任务：检查 Journal by Cashier and Transaction Code/service 报告 是否存在数据缺失
     * 报告生成频率是：11:28AM下发昨天的数据，在夏令时的酒店报告生成频率是：11:28AM 和 12:28AM。由于服务器不区分夏令时，所以这两个时间对应的服务器时间都是11:28AM
     * @date 2023/4/4 15:04
     */
    @Slf4j
    @Component
    public class JournalByCashierAndTransactionCodeServiceTask {

        @Autowired
        private CheckReportMissedService checkReportMissedService;
        @Autowired
        private IAdjEmailConfigService emailConfigService;
        @Value("${default.timezone}")
        private String defaultTimezone;
        @Autowired
        private PropertyInternalService propertyInternalService;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;
        @Autowired
        private LineMessageUtil lineMessageUtil;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;
        @Autowired
        private IAdjEmailTargetService emailTargetService;
        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private ObjectMapper objectMapper;
        @Autowired
        private TemplateEngine templateEngine;
        @Value("${here.link.adjustment-requests}")
        private String hereLink;

        /**
         * 业务名称
         */
        private final static String BUSINESS = BusinessEnum.ADJUSTMENT_REQUESTS.getBusiness();
        /**
         * subject
         */
        private final static String SUBJECT = EventSubjectEnum.YESTERDAY_JOURNAL_BY_CASHIER_AND_TRANSACTION_CODE_SERVICE.getSubject();

        /**
         * 检查是否存在数据缺失
         *
         * @param schedulerJob 调度任务
         * @return void
         * @author lichen
         * @date 2024/3/15
         */
        @Async
        public void dataMissingCheck(SchedulerJob schedulerJob) {
            log.info("JournalByCashierAndTransactionCodeServiceTask.start....");
            Integer propertyId = schedulerJob.getPropertyId();
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            if (!propertyDTO.getStatus()) return;

            //查询邮件配置信息
            AdjEmailConfig emailConfig = emailConfigService.getOne(new LambdaQueryWrapper<AdjEmailConfig>()
                    .eq(AdjEmailConfig::getPropertyId, propertyId)
                    .eq(AdjEmailConfig::getType, schedulerJob.getCategory()));
            List<AdjEmailTarget> emailTargets = Collections.emptyList();
            if (Objects.nonNull(emailConfig)) {
                emailTargets = emailTargetService.listByConfigId(Lists.newArrayList(emailConfig.getId()));
            }

            //通知DTO
            NotifyDTO notifyDTO = convertNotifyDTO(propertyDTO, emailConfig, emailTargets, schedulerJob);

            //阈值DTO
            JobParameterDTO jobParameterDTO = JsonUtils.convertStringToObject(objectMapper, schedulerJob.getParameters(), JobParameterDTO.class);
            ThresholdDTO thresholdDTO = new ThresholdDTO(jobParameterDTO.getThreshold(), TimeUnit.MINUTES, defaultTimezone);

            //封装CheckReportMissedDTO对象
            CheckReportMissedDTO job = CheckReportMissedDTO.builder()
                    .business(BUSINESS)
                    .subject(SUBJECT)
                    .ruleClazzList(List.of(MissedRuleByThreshold.class))
                    .propertyDTO(propertyDTO)
                    .notifyDTO(notifyDTO)
                    .thresholdDTO(thresholdDTO)
                    .build();
            checkReportMissedService.doCheck(job);
            log.info("JournalByCashierAndTransactionCodeServiceTask.dataMissingCheck end");
        }

        /**
         * 转化为通知DTO
         *
         * @param propertyDTO  资产DTO
         * @param emailConfig  邮件配置
         * @param emailTargets 邮件通知对象集合
         * @param schedulerJob 调度任务
         * @return cloud.wconnect.commonlib.pojo.dto.NotifyDTO
         * @author lichen
         * @date 2024/3/15
         */
        private NotifyDTO convertNotifyDTO(PropertyDTO propertyDTO, AdjEmailConfig emailConfig, List<AdjEmailTarget> emailTargets, SchedulerJob schedulerJob) {
            if (Objects.isNull(emailConfig)) return null;
            if (!emailConfig.getStatus()) return null;
            if (CollectionUtils.isEmpty(emailTargets)) return null;

            InternationalizationDateTimeDTO dateTime = propertyDTO.getInternationalization().getDateTime();
            String language = propertyDTO.getLanguage();

            //功能名称
            String functionName = i18nMessageUtils.message(FunctionCons.ADJUSTMENT_REQUESTS, language);

            //默认主题的国际化code
            String defaultSubjectI18nCode = AdjNotifyConfigTypeEnum.getDefaultSubjectI18nCode(schedulerJob.getCategory());
            String defaultSubject = i18nMessageUtils.message(defaultSubjectI18nCode, language, functionName, propertyDTO.getName());

            //自定义主体优先，其次默认主题
            String subject = StringUtils.isNotBlank(emailConfig.getSubject()) ? emailConfig.getSubject() : defaultSubject;

            //通知配置DTO
            NotifyDTO notifyDTO = new NotifyDTO();
            notifyDTO.setPropertyId(propertyDTO.getId());
            notifyDTO.setFunctionPoint(FunctionPointEnum.ADJ_PMS_REPORT_MISSED.getFunctionPoint());
            notifyDTO.setSubject(subject);
            notifyDTO.setIdentityList(beanMapper.mapList(emailTargets, NotifyIdentityDTO.class));

            //报告缺失日期
            String missDate = "";
            String parameters = schedulerJob.getParameters();
            if (StringUtils.isNotBlank(parameters) && !parameters.equals("{}")) {
                JobParameterDTO jobParameterDTO = JsonUtils.convertStringToObject(objectMapper, parameters, JobParameterDTO.class);
                Map<String, Long> dataRange = JobParameterUtils.parseDateRange(jobParameterDTO.getDateRange(), jobParameterDTO.getDateRangeUnit(), propertyDTO.getTimezone(), null);
                String startDate = InternationalizationUtils.formatDateTime(dataRange.get(JobParameterDTO.START_DATE),
                        dateTime.getLongDate(), StringUtils.EMPTY, propertyDTO.getTimezone(), propertyDTO.getLanguage());
                String endDate = InternationalizationUtils.formatDateTime(dataRange.get(JobParameterDTO.END_DATE),
                        dateTime.getLongDate(), StringUtils.EMPTY, propertyDTO.getTimezone(), propertyDTO.getLanguage());
                missDate = startDate + " ~ " + endDate;
            }

            // 获取资产配置的 PMS 报告名称
            String reportName = propertyInternalService.getPmsReportConfig(propertyDTO.getId(),
                    propertyDTO.getPmsType(), PmsReportEnum.JOURNAL_BY_CASHIER_AND_TRANSACTION_CODES.getSymbol()).getReportName();

            //跳转链接
            String linkUrl = MessageFormat.format(hereLink + "?fromPage=email&property={0}&tenant={1}", propertyDTO.getAbbr(), propertyDTO.getTenantSymbol());

            Context context = new Context();
            context.setVariable("propertyName", propertyDTO.getName());
            context.setVariable("hereLink", linkUrl);
            context.setVariable("functionName", functionName);
            context.setVariable("reportName", reportName);
            context.setVariable("reportDate", missDate);
            //获取邮件body
            String mailBody = templateEngine.process(EmailUtil.getMissReportTemplateName(language), context);
            //设置邮件通知内容
            notifyDTO.setEmailContent(EmailUtil.getFullEmailContent(defaultSubject, mailBody, language));

            //line通知内容
            ReportMissedMsgParm reportMissedMsgParm = ReportMissedMsgParm.builder()
                    .propertyId(propertyDTO.getId())
                    .propertyName(propertyDTO.getName())
                    .functionName(functionName)
                    .reportName(reportName)
                    .missDate(missDate).build();
            JSONObject lineMsg = lineMessageUtil.generateReportMissedMsg(reportMissedMsgParm);
            notifyDTO.setLineContent(Lists.newArrayList(lineMsg));
            return notifyDTO;
        }
    }