# CbCaseEmailConfigServiceImpl.java

    package cloud.wconnect.finance.service.chargeback.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.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.service.UserInternalService;
    import cloud.wconnect.commonlib.service.UsergroupInternalService;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.finance.cons.chargeback.ChargebackNotifyEnum;
    import cloud.wconnect.finance.entity.chargeback.CbCaseEmailConfig;
    import cloud.wconnect.finance.entity.chargeback.CbCaseEmailTarget;
    import cloud.wconnect.finance.mapper.chargeback.CbCaseEmailConfigMapper;
    import cloud.wconnect.finance.pojo.dto.chargeback.CbCaseEmailConfigDTO;
    import cloud.wconnect.finance.pojo.dto.chargeback.CbCaseEmailTargetDTO;
    import cloud.wconnect.finance.service.chargeback.ICbCaseEmailConfigService;
    import cloud.wconnect.finance.service.chargeback.ICbCaseEmailTargetService;
    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.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.i18n.LocaleContextHolder;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.util.*;
    import java.util.stream.Collectors;

    /**
     * <p>
     * case 邮件配置表 服务实现类
     * </p>
     *
     * @author yyt
     * @since 2023-08-22
     */
    @Service
    @DS("finance")
    public class CbCaseEmailConfigServiceImpl extends ServiceImpl<CbCaseEmailConfigMapper, CbCaseEmailConfig> implements ICbCaseEmailConfigService {

        @Autowired
        private ICbCaseEmailTargetService cbCaseEmailTargetService;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;
        @Autowired
        private UsergroupInternalService usergroupInternalService;
        @Autowired
        private UserInternalService userInternalService;
        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;

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

            Integer configId = config.getId();

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

            List<CbCaseEmailTarget> targets = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(configDTO.getToList())) {
                targets.addAll(configDTO.getToList().stream().map(item -> beanMapper.map(item, CbCaseEmailTarget.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, CbCaseEmailTarget.class,
                        target -> {
                            target.setTargetType(EmailConfigCons.TARGET_TYPE_CC);
                            target.setPropertyId(propertyId);
                            target.setConfigId(configId);
                        })).toList());
            }
            if (CollectionUtils.isNotEmpty(targets)) {
                cbCaseEmailTargetService.saveBatch(targets);
            }

            return configId;
        }

        /**
         * 获取邮件通知默认主题
         *
         * @param propertyName 资产名称
         * @param type         邮件配置类型(1：报告缺失，2：超期 replay by 通知，3：初始阶段审批通知主题配置，4：酒店表态阶段审批通知主题配置，
         *                     5：overdue 阶段审批通知主题配置，6：portal 阶段审批通知主题配置，7：loss-adj 阶段审批通知主题配置，8：last 阶段审批通知主题配置)
         * @param locale       多语言
         * @return 默认主题
         * @author yyt
         * @date 2024/12/4
         **/
        @Override
        public String getDefaultSubject(String propertyName, Integer type, Locale locale) {
            return i18nMessageUtils.message(ChargebackNotifyEnum.getI18nCode(type), locale,
                    i18nMessageUtils.message(FunctionCons.CHARGE_BACK, locale), propertyName);
        }

        /**
         * 获取邮件通知默认主题
         *
         * @param propertyId 资产 id
         * @param type       邮件配置类型(1：报告缺失，2：超期 replay by 通知，3：初始阶段审批通知主题配置，4：酒店表态阶段审批通知主题配置，
         *                   5：overdue 阶段审批通知主题配置，6：portal 阶段审批通知主题配置，7：loss-adj 阶段审批通知主题配置，8：last 阶段审批通知主题配置)
         * @return 默认主题
         * @author yyt
         * @date 2024/12/4
         **/
        @Override
        public String getDefaultSubject(Integer propertyId, int type) {
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            String language = propertyDTO.getLanguage();
            return i18nMessageUtils.message(ChargebackNotifyEnum.getI18nCode(type), language,
                    i18nMessageUtils.message(FunctionCons.CHARGE_BACK, language), propertyDTO.getName());
        }

        /**
         * 查询邮件配置
         *
         * @param propertyId 资产 id
         * @param type       邮件配置类型(1：报告缺失，2：超期 replay by 通知，3：初始阶段审批通知主题配置，4：酒店表态阶段审批通知主题配置，
         *                   5：overdue 阶段审批通知主题配置，6：portal 阶段审批通知主题配置，7：loss-adj 阶段审批通知主题配置，8：last 阶段审批通知主题配置)
         * @return 邮件配置
         * @author yyt
         * @date 2024/12/4
         **/
        @Override
        public CbCaseEmailConfig get(Integer propertyId, int type) {
            return getOne(new QueryWrapper<CbCaseEmailConfig>().lambda()
                    .eq(CbCaseEmailConfig::getPropertyId, propertyId)
                    .eq(CbCaseEmailConfig::getType, type));
        }

        /**
         * 查询邮件配置
         *
         * @param propertyId 资产 id
         * @param type       邮件配置类型(1：报告缺失，2：超期 replay by 通知，3：初始阶段审批通知主题配置，4：酒店表态阶段审批通知主题配置，
         *                   5：overdue 阶段审批通知主题配置，6：portal 阶段审批通知主题配置，7：loss-adj 阶段审批通知主题配置，8：last 阶段审批通知主题配置)
         * @param status     状态（false：关闭，true：开启）
         * @return 邮件配置
         * @author yyt
         * @date 2024/12/4
         **/
        @Override
        public CbCaseEmailConfig get(Integer propertyId, int type, boolean status) {
            return getOne(new QueryWrapper<CbCaseEmailConfig>().lambda()
                    .eq(CbCaseEmailConfig::getPropertyId, propertyId)
                    .eq(CbCaseEmailConfig::getType, type)
                    .eq(CbCaseEmailConfig::getStatus, status));
        }

        /**
         * 根据 case stage 获取邮件类型
         *
         * @param stage case stage
         * @return 邮件类型
         * @author yyt
         * @date 2025/1/18
         **/
        @Override
        public int getTypeForStage(Integer stage) {
            // 阶段：1：初始阶段，2：酒店表态阶段，3：overdue 阶段，4：portal 阶段，5：loss-adj 阶段，6：last 阶段
            // 类型：3：初始阶段审批通知主题配置，4：酒店表态阶段审批通知主题配置，5：overdue 阶段审批通知主题配置，6：portal 阶段审批通知主题配置，7：loss-adj 阶段审批通知主题配置，8：last 阶段审批通知主题配置
            return stage + 2;
        }

        /**
         * 检查是否发送通知
         *
         * @param propertyId 资产 id
         * @param type       配置类型
         * @return true：发送通知，false：不发送
         * @author yyt
         * @date 2025/1/18
         **/
        @Override
        public boolean checkNotify(Integer propertyId, int type) {
            // 未配置通知时，默认发送通知
            CbCaseEmailConfig config = get(propertyId, type);
            if (Objects.isNull(config)) {
                return true;
            }

            // 配置通知后，若关闭，则不发送通知
            return config.getStatus();
        }

        /**
         * 获取邮件配置
         *
         * @param tenantId   租户 id
         * @param propertyId 资产 id
         * @param type       类型
         * @return 邮件配置
         * @author yyt
         * @date 2026/1/19
         **/
        @Override
        public CbCaseEmailConfigDTO getEmailConfigDTO(int tenantId, int propertyId, int type) {
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            Locale locale = LocaleContextHolder.getLocale();
            String defaultSubject = getDefaultSubject(propertyDTO.getName(), type, locale);

            CbCaseEmailConfig config = get(propertyId, type);
            if (Objects.isNull(config)) {
                return new CbCaseEmailConfigDTO(defaultSubject);
            }

            List<CbCaseEmailTarget> emailTargets = cbCaseEmailTargetService.list(config.getId());

            List<Integer> userIds = emailTargets.stream().filter(item -> item.getSource() == EmailConfigCons.SOURCE_USER)
                    .map(CbCaseEmailTarget::getIdentityId).distinct().toList();
            List<Integer> userGroupIds = emailTargets.stream().filter(item -> item.getSource() == EmailConfigCons.SOURCE_USERGROUP)
                    .map(CbCaseEmailTarget::getIdentityId).distinct().toList();
            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<CbCaseEmailTarget>> targetsByTargetType = emailTargets.stream()
                    .collect(Collectors.groupingBy(CbCaseEmailTarget::getTargetType));

            CbCaseEmailConfigDTO configDTO = beanMapper.map(config, CbCaseEmailConfigDTO.class);
            configDTO.setDefaultSubject(defaultSubject);
            configDTO.setToList(beanMapper.mapList(targetsByTargetType.get(EmailConfigCons.TARGET_TYPE_TO), CbCaseEmailTargetDTO.class));
            configDTO.setCcList(beanMapper.mapList(targetsByTargetType.get(EmailConfigCons.TARGET_TYPE_CC), CbCaseEmailTargetDTO.class));
            return configDTO;
        }

    }