# RevenueEmailConfigServiceImpl.java

    package cloud.wconnect.rateshop.service.revenue.impl;

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.EmailConfigCons;
    import cloud.wconnect.commonlib.cons.FunctionCons;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.pojo.dto.UserDTO;
    import cloud.wconnect.commonlib.pojo.dto.internationalization.InternationalizationDateTimeDTO;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.service.UserInternalService;
    import cloud.wconnect.commonlib.service.UsergroupInternalService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.commonlib.util.InternationalizationUtils;
    import cloud.wconnect.rateshop.cons.revenue.DailyRevenueNotifyTypeEnum;
    import cloud.wconnect.rateshop.entity.revenue.RevenueEmailConfig;
    import cloud.wconnect.rateshop.entity.revenue.RevenueEmailTarget;
    import cloud.wconnect.rateshop.mapper.revenue.RevenueEmailConfigMapper;
    import cloud.wconnect.rateshop.pojo.dto.revenue.RevenueEmailConfigDTO;
    import cloud.wconnect.rateshop.pojo.dto.revenue.RevenueEmailTargetDTO;
    import cloud.wconnect.rateshop.service.revenue.IRevenueEmailConfigService;
    import cloud.wconnect.rateshop.service.revenue.IRevenueEmailTargetService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import org.apache.commons.collections.CollectionUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.i18n.LocaleContextHolder;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.time.LocalDate;
    import java.time.ZonedDateTime;
    import java.time.format.TextStyle;
    import java.util.*;
    import java.util.stream.Collectors;

    /**
     * <p>
     * 邮件配置表 服务实现类
     * </p>
     *
     * @author yyt
     * @since 2023-10-26
     */
    @Service
    @DS("rate_shop")
    public class RevenueEmailConfigServiceImpl extends ServiceImpl<RevenueEmailConfigMapper, RevenueEmailConfig> implements IRevenueEmailConfigService {

        @Autowired
        private IRevenueEmailTargetService revenueEmailTargetService;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;
        @Autowired
        private UserInternalService userInternalService;
        @Autowired
        private UsergroupInternalService usergroupInternalService;
        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;

        /**
         * 保存邮件配置
         *
         * @param propertyId 资产 id
         * @param configDTO  邮件配置
         * @return 配置 id
         * @author yyt
         * @date 2023/10/28
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public Integer save(Integer propertyId, RevenueEmailConfigDTO configDTO) {
            RevenueEmailConfig config = beanMapper.map(configDTO, RevenueEmailConfig.class);
            config.setPropertyId(propertyId);
            saveOrUpdate(config);

            Integer configId = config.getId();

            if (configDTO.getId() > 0) {
                revenueEmailTargetService.remove(new QueryWrapper<RevenueEmailTarget>().lambda()
                        .eq(RevenueEmailTarget::getConfigId, configDTO.getId()));
            }

            List<RevenueEmailTarget> targets = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(configDTO.getToList())) {
                targets.addAll(configDTO.getToList().stream().map(item -> beanMapper.map(item, RevenueEmailTarget.class,
                        target -> {
                            target.setTargetType(EmailConfigCons.TARGET_TYPE_TO);
                            target.setPropertyId(propertyId);
                            target.setConfigId(configId);
                        })).toList());
            }
            if (CollectionUtils.isNotEmpty(configDTO.getCcList())) {
                targets.addAll(configDTO.getCcList().stream().map(item -> beanMapper.map(item, RevenueEmailTarget.class,
                        target -> {
                            target.setTargetType(EmailConfigCons.TARGET_TYPE_CC);
                            target.setPropertyId(propertyId);
                            target.setConfigId(configId);
                        })).toList());
            }
            if (CollectionUtils.isNotEmpty(targets)) {
                revenueEmailTargetService.saveBatch(targets);
            }

            return configId;
        }

        /**
         * 获取邮件配置
         *
         * @param propertyId 资产 id
         * @param notifyType 通知类型
         * @param status     状态（false：关闭，true：开启）
         * @return 邮件配置
         * @author zc
         * @date 2024/11/14
         */
        @Override
        public RevenueEmailConfig getEmailConfig(int propertyId, int notifyType, Boolean status) {
            return getOne(new QueryWrapper<RevenueEmailConfig>().lambda()
                    .eq(RevenueEmailConfig::getType, notifyType)
                    .eq(RevenueEmailConfig::getPropertyId, propertyId)
                    .eq(Objects.nonNull(status), RevenueEmailConfig::getStatus, status));
        }

        /**
         * 获取邮件通知默认主题
         *
         * @param propertyDTO 资产
         * @param type        类型 (1:History and Forecast,2:Business Block,3:Reservation Statistics,4:Reservation Forecast,
         *                    5:Reservation Forecast Next Month,6:History Forecast Next Month,7:History Forecast Last Year,
         *                    8: Reservations Forecast Next 14 days,9:History and Forecast Next 90 days,10:Market Code,
         *                    11:Occ jump alert，12：History and Forecast this month（future），13：History and Forecast next month（future），
         *                    14：History and Forecast the month after next，15：History and Forecast last year next 90 days，
         *                    16：Reservation Forecast next 90 days，17：History and Forecast Business Block next 90 days)
         * @param locale      多语言
         * @return 默认主题
         * @author yyt
         * @date 2024/12/2
         **/
        @Override
        public String getDefaultSubject(PropertyDTO propertyDTO, Integer type, Locale locale) {
            String propertyName = propertyDTO.getName();
            if (Objects.equals(type, DailyRevenueNotifyTypeEnum.OCC_JUMP_ALERT.getType())) {
                return i18nMessageUtils.message(DailyRevenueNotifyTypeEnum.getDefaultSubjectI18nCode(type), locale,
                        i18nMessageUtils.message(FunctionCons.REVENUE, locale), "--", "--", propertyName);
            }

            if(Objects.equals(type, DailyRevenueNotifyTypeEnum.RATE_REVIEW_NOTIFY.getType())) {
                return getDefaultSubjectForRateReviewNotify(propertyDTO, DateTimeUtils.dateNow(propertyDTO.getTimezone()), locale);
            }

            return i18nMessageUtils.message(DailyRevenueNotifyTypeEnum.getDefaultSubjectI18nCode(type), locale,
                    i18nMessageUtils.message(FunctionCons.REVENUE, locale), propertyName);
        }

        /**
         * 获取 rate review notify 邮件通知默认主题
         *
         * @param propertyDTO 资产
         * @param targetDate  指定日期
         * @param locale      多语言
         * @return 默认主题
         * @author yyt
         * @date 2025/2/14
         **/
        @Override
        public String getDefaultSubjectForRateReviewNotify(PropertyDTO propertyDTO, ZonedDateTime targetDate, Locale locale) {
            // 2025.02.04 Tuesday APA Rate Review
            InternationalizationDateTimeDTO dateTime = propertyDTO.getInternationalization().getDateTime();
            LocalDate now = targetDate.toLocalDate();
            String date = InternationalizationUtils.formatLocalDate(now, dateTime.getLongDate(), locale.toString());
            return i18nMessageUtils.message(DailyRevenueNotifyTypeEnum.getDefaultSubjectI18nCode(DailyRevenueNotifyTypeEnum.RATE_REVIEW_NOTIFY.getType()), locale,
                    date, now.getDayOfWeek().getDisplayName(TextStyle.FULL_STANDALONE, locale), StringUtils.upperCase(propertyDTO.getAbbr()));
        }

        /**
         * 获取邮件通知默认主题
         *
         * @param propertyId 资产 id
         * @param type       类型 (1:History and Forecast,2:Business Block,3:Reservation Statistics,4:Reservation Forecast,
         *                   5:Reservation Forecast Next Month,6:History Forecast Next Month,7:History Forecast Last Year,
         *                   8: Reservations Forecast Next 14 days,9:History and Forecast Next 90 days,10:Market Code,
         *                   11:Occ jump alert，12：History and Forecast this month（future），13：History and Forecast next month（future），
         *                   14：History and Forecast the month after next，15：History and Forecast last year next 90 days，
         *                   16：Reservation Forecast next 90 days，17：History and Forecast Business Block next 90 days)
         * @return 默认主题
         * @author yyt
         * @date 2024/12/2
         **/
        @Override
        public String getDefaultSubject(Integer propertyId, int type) {
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            String language = propertyDTO.getLanguage();
            if (Objects.equals(type, DailyRevenueNotifyTypeEnum.OCC_JUMP_ALERT.getType())) {
                return i18nMessageUtils.message(DailyRevenueNotifyTypeEnum.getDefaultSubjectI18nCode(type), language,
                        i18nMessageUtils.message(FunctionCons.REVENUE, language), "--", "--", propertyDTO.getName());
            }
            return i18nMessageUtils.message(DailyRevenueNotifyTypeEnum.getDefaultSubjectI18nCode(type), language,
                    i18nMessageUtils.message(FunctionCons.REVENUE, language), propertyDTO.getName());
        }

        /**
         * 查询邮件配置
         *
         * @param propertyDTO 资产
         * @param type        报告类型
         * @return 邮件配置
         * @author yyt
         * @date 2025/10/31
         **/
        @Override
        public RevenueEmailConfigDTO getDTO(PropertyDTO propertyDTO, int type) {
            Integer propertyId = propertyDTO.getId();
            Locale locale = LocaleContextHolder.getLocale();
            String defaultSubject = getDefaultSubject(propertyDTO, type, locale);

            RevenueEmailConfig config = getEmailConfig(propertyId, type, null);
            if (Objects.isNull(config)) {
                return new RevenueEmailConfigDTO(defaultSubject);
            }

            List<RevenueEmailTarget> emailTargets = revenueEmailTargetService.listByConfigId(config.getId());

            List<Integer> userIds = emailTargets.stream().filter(item -> item.getSource() == EmailConfigCons.SOURCE_USER)
                    .map(RevenueEmailTarget::getIdentityId).distinct().toList();
            List<Integer> userGroupIds = emailTargets.stream().filter(item -> item.getSource() == EmailConfigCons.SOURCE_USERGROUP)
                    .map(RevenueEmailTarget::getIdentityId).distinct().toList();
            Integer tenantId = propertyDTO.getTenantId();
            Map<Integer, UserDTO> userById = userInternalService.getUserMapByIds(tenantId, userIds);
            Map<Integer, String> userGroupNameById = usergroupInternalService.getUserGroupNameByIds(tenantId, propertyId, userGroupIds);
            emailTargets.forEach(item -> {
                if (item.getSource() == EmailConfigCons.SOURCE_USER) {
                    item.setIdentityName(userById.get(item.getIdentityId()).getName());
                    item.setEmail(userById.get(item.getIdentityId()).getEmail());
                }
                if (item.getSource() == EmailConfigCons.SOURCE_USERGROUP) {
                    item.setIdentityName(userGroupNameById.get(item.getIdentityId()));
                }
            });

            Map<Integer, List<RevenueEmailTarget>> targetsByTargetType = emailTargets.stream()
                    .collect(Collectors.groupingBy(RevenueEmailTarget::getTargetType));
            RevenueEmailConfigDTO configDTO = beanMapper.map(config, RevenueEmailConfigDTO.class);
            configDTO.setDefaultSubject(defaultSubject);
            configDTO.setToList(beanMapper.mapList(targetsByTargetType.get(EmailConfigCons.TARGET_TYPE_TO), RevenueEmailTargetDTO.class));
            configDTO.setCcList(beanMapper.mapList(targetsByTargetType.get(EmailConfigCons.TARGET_TYPE_CC), RevenueEmailTargetDTO.class));
            return configDTO;
        }

    }