# HotelKpiEmailConfigServiceImpl.java

    package cloud.wconnect.workperformance.service.hotelkpi.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.service.UserInternalService;
    import cloud.wconnect.commonlib.service.UsergroupInternalService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.workperformance.cons.hotelkpi.HotelKpiNotifyTypeEnum;
    import cloud.wconnect.workperformance.entity.hotelkpi.HotelKpiEmailConfig;
    import cloud.wconnect.workperformance.entity.hotelkpi.HotelKpiEmailTarget;
    import cloud.wconnect.workperformance.mapper.hotelkpi.HotelKpiEmailConfigMapper;
    import cloud.wconnect.workperformance.pojo.dto.hotelkpi.notification.HotelKpiEmailConfigDTO;
    import cloud.wconnect.workperformance.pojo.dto.hotelkpi.notification.HotelKpiEmailTargetDTO;
    import cloud.wconnect.workperformance.service.hotelkpi.IHotelKpiEmailConfigService;
    import cloud.wconnect.workperformance.service.hotelkpi.IHotelKpiEmailTargetService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.google.common.collect.Lists;
    import jakarta.annotation.Resource;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.context.i18n.LocaleContextHolder;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.util.Collections;
    import java.util.List;
    import java.util.Map;
    import java.util.Objects;
    import java.util.stream.Collectors;

    /**
     * <p>
     * Hotel KPI email config 服务实现类
     * </p>
     *
     * @author zc
     * @since 2024-06-24
     */
    @Service
    @DS("work_performance")
    public class HotelKpiEmailConfigServiceImpl extends ServiceImpl<HotelKpiEmailConfigMapper, HotelKpiEmailConfig> implements IHotelKpiEmailConfigService {
        @Resource
        private IHotelKpiEmailTargetService emailTargetService;
        @Resource
        private UserInternalService userInternalService;
        @Resource
        private UsergroupInternalService usergroupInternalService;
        @Resource
        private I18nMessageUtils i18nMessageUtils;
        @Resource
        private BeanMapper beanMapper;

        /**
         * 保存邮件配置信息
         *
         * @param propertyId     资产 id
         * @param operatorId     操作人 id
         * @param emailConfigDTO 邮件配置信息
         * @return 邮件配置 id
         * @author zc
         * @date 2024/11/13
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public int save(int propertyId, int operatorId, HotelKpiEmailConfigDTO emailConfigDTO) {
            HotelKpiEmailConfig emailConfig = beanMapper.map(emailConfigDTO, HotelKpiEmailConfig.class, config -> {
                config.setPropertyId(propertyId);
                config.setUpdateBy(operatorId);
                config.setUpdateTime(DateTimeUtils.nowTimestamp());
            });
            baseMapper.insertOrUpdateByUnique(emailConfig);

            // 删除原有数据
            emailTargetService.removeByConfigId(emailConfig.getId());

            List<HotelKpiEmailTarget> emailTargetList = Lists.newArrayList();
            emailTargetList.addAll(convert(propertyId, EmailConfigCons.TARGET_TYPE_TO, emailConfig.getId(), emailConfigDTO.getToList()));
            emailTargetList.addAll(convert(propertyId, EmailConfigCons.TARGET_TYPE_CC, emailConfig.getId(), emailConfigDTO.getCcList()));
            emailTargetService.saveBatch(emailTargetList);

            return emailConfig.getId();
        }

        /**
         * 转换为实体类对象
         *
         * @param propertyId property id
         * @param targetType 邮件类型
         * @param configId   邮件配置 id
         * @param list       EmailTargetDTO 数据
         * @return EmailTarget 集合
         * @author zc
         * @date 2024/11/13
         */
        private List<HotelKpiEmailTarget> convert(int propertyId, int targetType, int configId, List<HotelKpiEmailTargetDTO> list) {
            if (CollectionUtils.isEmpty(list)) {
                return Collections.emptyList();
            }
            return list.stream().map(item -> beanMapper.map(item, HotelKpiEmailTarget.class, target -> {
                target.setPropertyId(propertyId);
                target.setConfigId(configId);
                target.setTargetType(targetType);
                // 用户来源是 manual 时，用户 id 记录为 0，保存用户名
                if (target.getSource() == EmailConfigCons.USER_SOURCE_MANUAL) {
                    target.setIdentityId(EmailConfigCons.ZERO);
                    target.setUsername(item.getIdentityName());
                } else {
                    target.setUsername(null);
                    target.setEmail(null);
                }
            })).collect(Collectors.toList());
        }

        /**
         * 获取邮件配置DTO
         *
         * @param propertyDTO 资产 DTO
         * @param type        邮件类型
         * @return 邮件配置DTO
         * @author zc
         * @date 2024/11/13
         */
        @Override
        public HotelKpiEmailConfigDTO getEmailConfigDTO(PropertyDTO propertyDTO, int type) {
            String defaultSubject = generateDefaultSubject(type, propertyDTO.getName());
            HotelKpiEmailConfig emailConfig = getEmailConfig(propertyDTO.getId(), type);
            if (Objects.isNull(emailConfig)) {
                HotelKpiEmailConfigDTO emailConfigDTO = new HotelKpiEmailConfigDTO();
                emailConfigDTO.setType(type);
                emailConfigDTO.setDefaultSubject(defaultSubject);
                return emailConfigDTO;
            }
            // 获取接收人、抄送人
            List<HotelKpiEmailTarget> emailTargetList = emailTargetService.listByConfigId(emailConfig.getId());

            Map<Integer, List<Integer>> source2IdentityIdList = emailTargetList.stream()
                    .collect(Collectors.groupingBy(HotelKpiEmailTarget::getSource,
                            Collectors.mapping(HotelKpiEmailTarget::getIdentityId, Collectors.toList())));
            // 用户
            Map<Integer, UserDTO> userId2UserDTO = userInternalService.getUserMapByIds(propertyDTO.getTenantId(),
                    source2IdentityIdList.getOrDefault(EmailConfigCons.SOURCE_USER, Collections.emptyList()));
            // 用户组
            Map<Integer, String> userGroupId2Name = usergroupInternalService.getUserGroupNameByIds(propertyDTO.getTenantId(),
                    propertyDTO.getId(), source2IdentityIdList.getOrDefault(EmailConfigCons.SOURCE_USERGROUP, Collections.emptyList()));

            // 通知对象按照通知类型分组
            Map<Integer, List<HotelKpiEmailTargetDTO>> targetsByTargetType = beanMapper.mapList(emailTargetList,
                    HotelKpiEmailTargetDTO.class, (entity, dto) -> {
                        int source = dto.getSource();
                        int 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(HotelKpiEmailTargetDTO::getTargetType));
            return beanMapper.map(emailConfig, HotelKpiEmailConfigDTO.class, dto -> {
                dto.setDefaultSubject(defaultSubject);
                dto.setToList(targetsByTargetType.get(EmailConfigCons.TARGET_TYPE_TO));
                dto.setCcList(targetsByTargetType.get(EmailConfigCons.TARGET_TYPE_CC));
            });
        }

        /**
         * 生成邮件默认主题
         *
         * @param type         邮件类型
         * @param propertyName 资产名称
         * @return java.lang.String
         * @author zc
         * @date 2024/11/12
         */
        private String generateDefaultSubject(int type, String propertyName) {
            String language = LocaleContextHolder.getLocale().toString();
            String functionName = i18nMessageUtils.message(FunctionCons.HOTEL_KPI, language);
            return i18nMessageUtils.message(HotelKpiNotifyTypeEnum.getDefaultSubjectI18nCode(type), language, functionName, propertyName);
        }

        /**
         * 获取邮件配置
         *
         * @param propertyId 资产 id
         * @param type       邮件类型
         * @return 邮件配置
         * @author zc
         * @date 2024/6/29
         */
        @Override
        public HotelKpiEmailConfig getEmailConfig(int propertyId, int type) {
            return getOne(new QueryWrapper<HotelKpiEmailConfig>().lambda()
                    .eq(HotelKpiEmailConfig::getPropertyId, propertyId)
                    .eq(HotelKpiEmailConfig::getType, type));
        }
    }