# NotifyDailySummaryApprovingTask.java

    package cloud.wconnect.frontoffice.businesstask.adjustment;

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.FunctionCons;
    import cloud.wconnect.commonlib.pojo.dto.NotifyDTO;
    import cloud.wconnect.commonlib.pojo.dto.NotifyIdentityDTO;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.pojo.dto.internationalization.InternationalizationNumberDTO;
    import cloud.wconnect.commonlib.pojo.dto.line.PublicFlexMsgParm;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.service.MailInternalService;
    import cloud.wconnect.commonlib.service.NotifyInternalService;
    import cloud.wconnect.commonlib.util.*;
    import cloud.wconnect.frontoffice.cons.FunctionPointEnum;
    import cloud.wconnect.frontoffice.cons.I18nConstant;
    import cloud.wconnect.frontoffice.cons.adjustment.AdjNotifyConfigTypeEnum;
    import cloud.wconnect.frontoffice.entity.adjustment.AdRequest;
    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.pojo.vo.adjustment.AdjDailyCountVO;
    import cloud.wconnect.frontoffice.service.adjustment.IAdRequestService;
    import cloud.wconnect.frontoffice.service.adjustment.IAdjEmailConfigService;
    import cloud.wconnect.frontoffice.service.adjustment.IAdjEmailTargetService;
    import com.alibaba.fastjson.JSONObject;
    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.math.BigDecimal;
    import java.text.MessageFormat;
    import java.time.LocalDate;
    import java.util.*;
    import java.util.stream.Collectors;

    /**
     * @author lichen
     * @description 每天邮件通知各个资产的Sales待审批Adj的数量统计
     * @date 2023/4/3 16:20
     */
    @Slf4j
    @Component
    public class NotifyDailySummaryApprovingTask {

        @Autowired
        private IAdjEmailConfigService emailConfigService;
        @Autowired
        private IAdjEmailTargetService emailTargetService;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;
        @Autowired
        private IAdRequestService adRequestService;
        @Autowired
        private TemplateEngine templateEngine;
        @Autowired
        private NotifyInternalService notifyInternalService;
        @Autowired
        private LineMessageUtil lineMessageUtil;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;
        @Autowired
        private BeanMapper beanMapper;
        @Value("${here.link.adjustment-requests}")
        private String hereLink;
        @Autowired
        private MailInternalService mailInternalService;

        /**
         * 邮件通知资产每日调账待审批的数据
         *
         * @param schedulerJob 调度任务
         * @author lichen
         * @date 2024/3/15
         */
        @Async
        public void notifyDailySummaryApproving(SchedulerJob schedulerJob) {
            try {
                PropertyDTO propertyDTO = propertyI18nRedisService.get(schedulerJob.getPropertyId());
                if (!propertyDTO.getStatus()) return;

                //查询邮件配置信息
                AdjEmailConfig emailConfig = emailConfigService.getByPropertyIdAndType(schedulerJob.getPropertyId(), schedulerJob.getCategory());
                if (Objects.isNull(emailConfig)) return;
                if (!emailConfig.getStatus()) {
                    log.info("NotifyAdjustmentApproveingTask.end, email config status is false, propertyId:{},schedulerJobId:{},type:{}",
                            propertyDTO.getId(), schedulerJob.getId(), schedulerJob.getCategory());
                    return;
                }

                List<AdjEmailTarget> emailTargets = emailTargetService.listByConfigId(Lists.newArrayList(emailConfig.getId()));
                if (CollectionUtils.isEmpty(emailTargets)) return;
                Map<Integer, List<AdjEmailTarget>> requestType2EmailTargets = emailTargets.stream().collect(Collectors.groupingBy(AdjEmailTarget::getRequestType));

                //查询审批中的调账数据集合
                List<AdRequest> adRequests = adRequestService.listApproving(propertyDTO.getId());
                if (CollectionUtils.isEmpty(adRequests)) return;

                Map<Integer, List<AdRequest>> adRequestsByRequestBy = adRequests.stream().collect(Collectors.groupingBy(AdRequest::getRequestType));
                adRequestsByRequestBy.forEach((requestType, adjList) -> {
                    // 获取指定类型的通知对象
                    List<AdjEmailTarget> emailTargetsByRequestType = requestType2EmailTargets.getOrDefault(requestType, Collections.emptyList());
                    if (CollectionUtils.isEmpty(emailTargetsByRequestType)) return;
                    // 转换数据
                    List<AdjDailyCountVO> voList = convert(propertyDTO, adjList);
                    // 发送通知
                    sendNotify(propertyDTO, voList, emailConfig, emailTargetsByRequestType, schedulerJob.getCategory(), requestType);
                });
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                String alertEmailContent = MessageFormat.format("<p>propertyId:{0}</p>", schedulerJob.getPropertyId()) +
                        "<p>Exception occurred when notify daily summary approving.</p>" +
                        e.getMessage();
                String alertEmailSubject = "[Warning] - Approving Daily Summary Adjustment";
                mailInternalService.sendAlertEmail(alertEmailSubject, alertEmailContent);
            }
        }

        /**
         * 发送通知
         *
         * @param propertyDTO  资产DTO
         * @param resultList   sales adj每日待审批数量集合
         * @param emailConfig  通知配置
         * @param emailTargets 通知对象集合
         * @param notifyType   通知类型
         * @param requestType  调账类型
         * @return void
         * @author lichen
         * @date 2023/11/22
         */
        private void sendNotify(PropertyDTO propertyDTO, List<AdjDailyCountVO> resultList, AdjEmailConfig emailConfig, List<AdjEmailTarget> emailTargets, int notifyType, int requestType) {
            String language = propertyDTO.getLanguage();
            //功能名称
            String functionName = i18nMessageUtils.message(FunctionCons.ADJUSTMENT_REQUESTS, language);

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

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

            NotifyDTO notifyDTO = new NotifyDTO();
            notifyDTO.setPropertyId(propertyDTO.getId());
            notifyDTO.setFunctionPoint(FunctionPointEnum.ADJ_APPROVING_SALES_COUNT.getFunctionPoint());
            notifyDTO.setSubject(subject);
            notifyDTO.setIdentityList(beanMapper.mapList(emailTargets, NotifyIdentityDTO.class));

            //是否显示更多（超过10个才显示更多）
            boolean moreDays = false;
            if (resultList.size() > 10) {
                moreDays = true;
                // resultList最多11条数据，删除最后一天的数据，只保留前10天的数据
                resultList.remove(10);
            }
            //生成邮件通知内容
            String urlParams = MessageFormat.format("?fromPage=email&property={0}&tenant={1}&requestTypeList={2}&queryStatusList=2",
                    propertyDTO.getAbbr(), propertyDTO.getTenantSymbol(), requestType);
            String link = hereLink + urlParams;
            Context context = new Context();
            context.setVariable("propertyName", propertyDTO.getName());
            context.setVariable("functionName", functionName);
            context.setVariable("adjDailyCountVOList", resultList);
            context.setVariable("moreDays", moreDays);
            context.setVariable("hereLink", link);
            String mailBody = templateEngine.process("adjustment/adjustment-statistics_" + language, context);
            notifyDTO.setEmailContent(EmailUtil.getFullEmailContent(defaultSubject, mailBody, language));

            //生成line通知内容
            BigDecimal totalAmount = resultList.stream().map(AdjDailyCountVO::getTotalAmount)
                    .reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
            InternationalizationNumberDTO number = propertyDTO.getInternationalization().getNumber();
            //格式化金额显示形式
            String totalAmountStr = InternationalizationUtils.formatAmountViewValue(totalAmount, number.getCalculationRule(), number.getCurrency());

            LinkedHashMap<String, String> businessMap = new LinkedHashMap<>();
            businessMap.put(i18nMessageUtils.message(I18nConstant.I18N_TOTAL, language), resultList.size() + "");
            businessMap.put(i18nMessageUtils.message(I18nConstant.I18N_TOTAL_AMOUNT, language), totalAmountStr);

            PublicFlexMsgParm publicFlexMsgParm = PublicFlexMsgParm.builder()
                    .propertyName(propertyDTO.getName())
                    .propertyId(propertyDTO.getId())
                    .functionName(functionName)
                    .title("Wait for approval statistics")
                    .link(link)
                    .businessMap(businessMap)
                    .build();
            JSONObject lineContent = lineMessageUtil.generatePublicFlexMsg(publicFlexMsgParm);
            notifyDTO.setLineContent(Lists.newArrayList(lineContent));

            notifyInternalService.sendNotify(notifyDTO);
        }

        /**
         * 转换调账数据
         *
         * @param propertyDTO 资产DTO
         * @param adRequests  调账数据集合
         * @return java.util.List<cloud.wconnect.frontoffice.pojo.vo.adjustment.AdjDailyCountVO>
         * @author lichen
         * @date 2026/1/28
         */
        private List<AdjDailyCountVO> convert(PropertyDTO propertyDTO, List<AdRequest> adRequests) {
            InternationalizationNumberDTO number = propertyDTO.getInternationalization().getNumber();
            String longDate = propertyDTO.getInternationalization().getDateTime().getLongDate();

            //按照创建日期分组
            Map<LocalDate, List<AdRequest>> createDate2List = adRequests.stream().collect(Collectors.groupingBy(item ->
                    DateTimeUtils.longToLocalDate(item.getCreateTime(), propertyDTO.getTimezone())
            ));
            List<LocalDate> sortLocalDateList = createDate2List.keySet().stream().sorted().toList();

            ArrayList<AdjDailyCountVO> resultList = Lists.newArrayListWithExpectedSize(12);

            for (int i = 0; i < sortLocalDateList.size(); i++) {
                LocalDate localDate = sortLocalDateList.get(i);
                List<AdRequest> adRequestsByDate = createDate2List.get(localDate);

                // 日期
                String createDateStr = InternationalizationUtils.formatDateTime(
                        DateTimeUtils.localDateToLong(localDate, propertyDTO.getTimezone()),
                        longDate, StringUtils.EMPTY, propertyDTO.getTimezone(), propertyDTO.getLanguage());

                // 总金额
                BigDecimal totalAmount = adRequestsByDate.stream().map(AdRequest::getAdjustedDollar).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
                //格式化金额显示形式
                String totalAmountStr = InternationalizationUtils.formatAmountViewValue(totalAmount, number.getCalculationRule(), number.getCurrency());

                AdjDailyCountVO adjDailyCountVO = new AdjDailyCountVO();
                adjDailyCountVO.setCreateDateStr(createDateStr);
                adjDailyCountVO.setTotal(adRequestsByDate.size());
                adjDailyCountVO.setTotalAmount(totalAmount);
                adjDailyCountVO.setTotalAmountStr(totalAmountStr);
                resultList.add(adjDailyCountVO);

                if (i == 11) {
                    break;
                }
            }
            return resultList;
        }

    }