# RateShopEmailConfigServiceImpl.java

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

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.CommonErrorI18nConstant;
    import cloud.wconnect.commonlib.cons.EmailConfigCons;
    import cloud.wconnect.commonlib.cons.FunctionCons;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.pojo.dto.UserDTO;
    import cloud.wconnect.commonlib.pojo.dto.UsergroupDTO;
    import cloud.wconnect.commonlib.service.UserInternalService;
    import cloud.wconnect.commonlib.service.UsergroupInternalService;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.rateshop.cons.rateshop.RateShopNotifyConfigTypeEnum;
    import cloud.wconnect.rateshop.entity.rateshop.RateShopEmailConfig;
    import cloud.wconnect.rateshop.entity.rateshop.RateShopEmailTarget;
    import cloud.wconnect.rateshop.mapper.rateshop.EmailConfigMapper;
    import cloud.wconnect.rateshop.pojo.dto.rateshop.emailconfig.RateShopEmailConfigDTO;
    import cloud.wconnect.rateshop.pojo.dto.rateshop.emailconfig.RateShopEmailTargetDTO;
    import cloud.wconnect.rateshop.service.rateshop.IRateShopEmailConfigService;
    import cloud.wconnect.rateshop.service.rateshop.IRateShopEmailTargetService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    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>
     * rate shop功能的邮件配置表 服务实现类
     * </p>
     *
     * @author lichen
     * @since 2023-06-15
     */
    @DS("rate_shop")
    @Service
    public class RateShopEmailConfigServiceImpl extends ServiceImpl<EmailConfigMapper, RateShopEmailConfig> implements IRateShopEmailConfigService {

        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private IRateShopEmailTargetService emailTargetService;
        @Autowired
        private UserInternalService userInternalService;
        @Autowired
        private UsergroupInternalService usergroupInternalService;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;

        /**
         * 查询邮件配置DTO
         *
         * @param propertyDTO 资产DTO
         * @param type        邮件类型
         * @return cloud.wconnect.rateshop.pojo.dto.rateshop.emailconfig.EmailConfigDTO
         * @author lichen
         * @date 2024/3/8
         */
        @Override
        public RateShopEmailConfigDTO getByType(PropertyDTO propertyDTO, int type) {
            //当前上下文语言
            Locale currentThreadLocale = LocaleContextHolder.getLocale();
            //功能名称
            String functionName = i18nMessageUtils.message(FunctionCons.RATE_SHOP_FUNCTION, currentThreadLocale);

            String defaultSubjectI18nCode = RateShopNotifyConfigTypeEnum.getDefaultSubjectI18nCode(type);
            //默认主题
            String defaultSubject;
            if (type == RateShopNotifyConfigTypeEnum.OCC_SNAPSHOT_FOR_THE_NEXT_N_DAYS.getType()) {
                defaultSubject = i18nMessageUtils.message(defaultSubjectI18nCode, currentThreadLocale, functionName, "N", propertyDTO.getName());
            } else {
                defaultSubject = i18nMessageUtils.message(defaultSubjectI18nCode, currentThreadLocale, functionName, propertyDTO.getName());
            }

            RateShopEmailConfig emailConfig = getOne(new LambdaQueryWrapper<RateShopEmailConfig>()
                    .eq(RateShopEmailConfig::getPropertyId, propertyDTO.getId())
                    .eq(RateShopEmailConfig::getType, type));
            if (Objects.isNull(emailConfig)) {
                RateShopEmailConfigDTO rateShopEmailConfigDTO = new RateShopEmailConfigDTO();
                rateShopEmailConfigDTO.setDefaultSubject(defaultSubject);
                rateShopEmailConfigDTO.setType(type);
                return rateShopEmailConfigDTO;
            }

            //查询通知对象
            List<RateShopEmailTarget> emailTargetList = emailTargetService.list(new QueryWrapper<RateShopEmailTarget>()
                    .lambda().eq(RateShopEmailTarget::getConfigId, emailConfig.getId()));

            //按照用户来源分组
            Map<Integer, List<Integer>> source2IdentityIdList = emailTargetList.stream()
                    .collect(Collectors.groupingBy(RateShopEmailTarget::getSource, Collectors.mapping(RateShopEmailTarget::getIdentityId, Collectors.toList())));

            //用户集合
            Map<Integer, UserDTO> userId2UserDTO = userInternalService.getUserMapByIds(propertyDTO.getTenantId(),
                    source2IdentityIdList.getOrDefault(EmailConfigCons.SOURCE_USER, Collections.emptyList()));
            //用户组集合
            Map<Integer, String> usergroupId2Name = usergroupInternalService.getUsergroups(propertyDTO.getTenantId(), propertyDTO.getId(),
                            source2IdentityIdList.getOrDefault(EmailConfigCons.SOURCE_USERGROUP, Collections.emptyList()))
                    .stream().collect(Collectors.toMap(UsergroupDTO::getId, UsergroupDTO::getName));

            //通知对象按照通知类型分组
            Map<Integer, List<RateShopEmailTargetDTO>> targetsByTargetType = beanMapper.mapList(emailTargetList, RateShopEmailTargetDTO.class, (entity, dto) -> {
                Integer source = dto.getSource();
                Integer identityId = dto.getIdentityId();
                switch (source) {
                    case EmailConfigCons.SOURCE_USER:
                        UserDTO userDTO = userId2UserDTO.get(identityId);
                        if (Objects.nonNull(userDTO)) {
                            dto.setIdentityName(userDTO.getName());
                            dto.setEmail(userDTO.getEmail());
                        }
                        break;
                    case EmailConfigCons.SOURCE_USERGROUP:
                        dto.setIdentityName(usergroupId2Name.get(identityId));
                        break;
                    case EmailConfigCons.SOURCE_MANUAL:
                        dto.setIdentityName(entity.getUsername());
                        break;
                    default:
                        break;
                }
            }).stream().collect(Collectors.groupingBy(RateShopEmailTargetDTO::getTargetType));

            RateShopEmailConfigDTO configDTO = beanMapper.map(emailConfig, RateShopEmailConfigDTO.class);
            configDTO.setToList(targetsByTargetType.get(EmailConfigCons.TARGET_TYPE_TO));
            configDTO.setCcList(targetsByTargetType.get(EmailConfigCons.TARGET_TYPE_CC));
            configDTO.setDefaultSubject(defaultSubject);
            return configDTO;
        }

        /**
         * 查询邮件配置
         *
         * @param propertyIds 资产ID集合
         * @param type        邮件配置类型
         * @return java.util.List<cloud.wconnect.rateshop.entity.rateshop.EmailConfig>
         * @author lichen
         * @date 2024/3/8
         */
        @Override
        public List<RateShopEmailConfig> listByPropertyIdAndType(List<Integer> propertyIds, int type) {
            if (CollectionUtils.isEmpty(propertyIds)) return Collections.emptyList();
            return list(new LambdaQueryWrapper<RateShopEmailConfig>()
                    .in(RateShopEmailConfig::getPropertyId, propertyIds)
                    .eq(RateShopEmailConfig::getType, type));
        }

        /**
         * 校验邮件配置是否存在
         *
         * @param id 主键ID
         * @return cloud.wconnect.rateshop.entity.rateshop.RateShopEmailConfig
         * @author lichen
         * @date 2024/3/8
         */
        @Override
        public RateShopEmailConfig checkExist(Integer id) {
            RateShopEmailConfig rateShopEmailConfig = getById(id);
            if (Objects.isNull(rateShopEmailConfig)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_FOUND, BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The Rate Shop email config not find, id=" + id);
            }
            return rateShopEmailConfig;
        }

        /**
         * 校验唯一
         *
         * @param propertyId 资产ID
         * @param type       邮件配置类型
         * @return void
         * @author lichen
         * @date 2024/3/8
         */
        @Override
        public void checkSole(Integer propertyId, Integer type) {
            long count = count(new LambdaQueryWrapper<RateShopEmailConfig>()
                    .eq(RateShopEmailConfig::getPropertyId, propertyId)
                    .eq(RateShopEmailConfig::getType, type));
            if (count > 0) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_ALREADY_EXIST,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("emailConfig"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The property has been configured with email configuration, propertyId = " + propertyId + ", type = " + type);
            }
        }

        /**
         * 保存邮件配置
         *
         * @param propertyDTO 资产DTO
         * @param configDTO   邮件配置DTO
         * @return 配置ID
         * @author lichen
         * @date 2024/3/8
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public Integer save(PropertyDTO propertyDTO, RateShopEmailConfigDTO configDTO) {
            RateShopEmailConfig config = new RateShopEmailConfig()
                    .setId(configDTO.getId())
                    .setSubject(configDTO.getSubject())
                    .setType(configDTO.getType())
                    .setPropertyId(propertyDTO.getId())
                    .setStatus(configDTO.getStatus());
            saveOrUpdate(config);

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

            List<RateShopEmailTarget> targets = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(configDTO.getToList())) {
                targets.addAll(configDTO.getToList().stream().map(item -> beanMapper.map(item, RateShopEmailTarget.class,
                        target -> {
                            target.setTargetType(EmailConfigCons.TARGET_TYPE_TO);
                            target.setPropertyId(propertyDTO.getId());
                            target.setConfigId(config.getId());
                            target.setUsername(item.getIdentityName());
                        })).toList());
            }
            if (CollectionUtils.isNotEmpty(configDTO.getCcList())) {
                targets.addAll(configDTO.getCcList().stream().map(item -> beanMapper.map(item, RateShopEmailTarget.class,
                        target -> {
                            target.setTargetType(EmailConfigCons.TARGET_TYPE_CC);
                            target.setPropertyId(propertyDTO.getId());
                            target.setConfigId(config.getId());
                            target.setUsername(item.getIdentityName());
                        })).toList());
            }

            emailTargetService.saveBatch(targets);
            return config.getId();
        }

        /**
         * 查询邮件配置
         *
         * @param propertyId 资产Id
         * @param type       邮件配置类型
         * @return cloud.wconnect.rateshop.entity.rateshop.RateShopEmailConfig
         * @author lichen
         * @date 2024/3/15
         */
        @Override
        public RateShopEmailConfig getByPropertyIdAndType(Integer propertyId, int type) {
            return getOne(new LambdaQueryWrapper<RateShopEmailConfig>()
                    .eq(RateShopEmailConfig::getPropertyId, propertyId)
                    .eq(RateShopEmailConfig::getType, type));
        }

    }