# ItticketNotificationServiceImpl.java

    package cloud.wconnect.it.service.itrequest.impl;

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.*;
    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.internationalization.InternationalizationDateTimeDTO;
    import cloud.wconnect.commonlib.pojo.dto.line.PublicFlexMsgParm;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.service.PropertyInternalService;
    import cloud.wconnect.commonlib.service.UserInternalService;
    import cloud.wconnect.commonlib.service.UsergroupInternalService;
    import cloud.wconnect.commonlib.util.*;
    import cloud.wconnect.it.cons.itrequest.*;
    import cloud.wconnect.it.entity.itrequest.*;
    import cloud.wconnect.it.mapper.itrequest.ItticketNotificationMapper;
    import cloud.wconnect.it.pojo.dto.itrequest.ExpansionDTO;
    import cloud.wconnect.it.pojo.dto.itrequest.ItticketNotificationDTO;
    import cloud.wconnect.it.pojo.dto.itrequest.ItticketNotificationTargetDTO;
    import cloud.wconnect.it.pojo.vo.itrequest.ItticketCommentEmailVO;
    import cloud.wconnect.it.pojo.vo.itrequest.ItticketEmailVO;
    import cloud.wconnect.it.pojo.vo.itrequest.ItticketOperationLogVO;
    import cloud.wconnect.it.service.itrequest.*;
    import com.alibaba.fastjson.JSONObject;
    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.fasterxml.jackson.databind.ObjectMapper;
    import com.google.common.collect.Lists;
    import com.google.common.collect.Maps;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.i18n.LocaleContextHolder;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import jakarta.annotation.Nullable;
    import jakarta.annotation.Resource;
    import java.util.*;
    import java.util.stream.Collectors;

    /**
     * <p>
     *  服务实现类
     * </p>
     *
     * @author yyt
     * @since 2023-03-25
     */
    @DS("it_manage")
    @Service
    public class ItticketNotificationServiceImpl extends ServiceImpl<ItticketNotificationMapper, ItticketNotification> implements IItticketNotificationService {

        @Autowired
        private IItticketNotificationTargetService itticketNotificationTargetService;
        @Autowired
        private IItticketCategoryService itticketCategoryService;
        @Autowired
        private IItticketPriorityService itticketPriorityService;
        @Resource
        private IItticketOperationLogService itticketOperationLogService;
        @Autowired
        private PropertyInternalService propertyInternalService;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;
        @Autowired
        private UserInternalService userInternalService;
        @Autowired
        private UsergroupInternalService usergroupInternalService;
        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private LineMessageUtil lineMessageUtil;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;
        @Autowired
        private ObjectMapper objectMapper;

        @Value("${here.link.it-request.detail}")
        private String itticketDetailPage;

        /**
         * 获取通知
         *
         * @param propertyId 资产 id
         * @param type       类型
         * @return 通知
         * @author yyt
         * @date 2023/3/25
         */
        public ItticketNotification getItticketNotification(Integer propertyId, int type) {
            return getOne(new QueryWrapper<ItticketNotification>().lambda().eq(ItticketNotification::getPropertyId, propertyId)
                    .eq(ItticketNotification::getType, type));
        }

        /**
         * 创建 line msg
         *
         * @param itticket   Itticket
         * @param operation 操作（create、update、accept、resolve、comment）
         * @return line msg
         * @author yyt
         * @date 2023/11/29
         */
        @Override
        public JSONObject generateLineMsg(Itticket itticket, int operation) {
            LinkedHashMap<String, String> map = Maps.newLinkedHashMapWithExpectedSize(3);
            map.put("NO", itticket.getId().toString());
            map.put("Service Provider Ticket # (or SR#)", itticket.getServiceVendorTicket());
            map.put("Contact Phone Number", itticket.getContactInfo());

            PropertyDTO propertyDTO = propertyI18nRedisService.get(itticket.getPropertyId());
            String language = propertyDTO.getLanguage();
            String title = ItRequestLineNotifyTitleEnum.getI18nCode(operation);
            return lineMessageUtil.generatePublicFlexMsg(new PublicFlexMsgParm(propertyDTO.getName(), propertyDTO.getId(),
                    i18nMessageUtils.message(FunctionCons.IT_REQUEST, language),
                    title, itticketDetailPage + "?id=" + itticket.getId() + "&property=" + propertyDTO.getAbbr() +
                    "&tenant=" + propertyDTO.getTenantSymbol(), map));
        }

        /**
         * 封装 it 详情 邮件内容
         *
         * @param itticket  itticket
         * @return 详情信息邮件内容
         * @author yyt
         * @date 2023/3/25
         */
        @Override
        public ItticketEmailVO packageItDetailEmailContent(Itticket itticket) {
            ItticketEmailVO emailVO = new ItticketEmailVO();
            emailVO.setId(itticket.getId());

            ItticketCategory category = itticketCategoryService.getById(itticket.getCategory());
            emailVO.setCategory(category.getName());

            PropertyDTO propertyDTO = propertyInternalService.getOne(itticket.getPropertyId());
            emailVO.setPropertyName(propertyDTO.getName());
            emailVO.setFunctionName(i18nMessageUtils.message(FunctionCons.IT_REQUEST, propertyDTO.getLanguage()));

            Integer userId = itticket.getUserId();
            List<Integer> userIds = Lists.newArrayList(userId);
            Integer dutyUser = itticket.getDutyUser();
            if(dutyUser > BaseConstant.ZERO){
                userIds.add(dutyUser);
            }
            Map<Integer, String> userNameById = userInternalService.getNameMapByIds(propertyDTO.getTenantId(), userIds);
            emailVO.setCreateName(userNameById.get(userId));
            InternationalizationDateTimeDTO dateTime = propertyDTO.getInternationalization().getDateTime();
            String longDate = dateTime.getLongDate();
            String hourClock = dateTime.getHourClock();
            String timezone = propertyDTO.getTimezone();
            String language = propertyDTO.getLanguage();
            emailVO.setCreateTimeStr(InternationalizationUtils.formatDateTime(itticket.getTicketCreateTime(), longDate, hourClock, timezone, language));

            String ccemail = itticket.getCcemail();
            emailVO.setCcemail(StringUtils.isNotEmpty(ccemail) ? ccemail : "--");
            emailVO.setDutyUserName(userNameById.getOrDefault(dutyUser, "--"));

            Long resolveTime = itticket.getResolveTime();
            emailVO.setResolutionTime(Objects.nonNull(resolveTime) && resolveTime > BaseConstant.ZERO ?
                    InternationalizationUtils.formatDateTime(resolveTime, longDate, hourClock, timezone, language) : "--");
            Integer ticketStatus = itticket.getTicketStatus();
            emailVO.setStatus(i18nMessageUtils.message(ItRequestStatusEnum.getI18nCode(ticketStatus), language));
            emailVO.setStatusInt(ticketStatus);

            String serviceVendorTicket = itticket.getServiceVendorTicket();
            emailVO.setServiceVendorTicket(StringUtils.isEmpty(serviceVendorTicket) ? "--" : serviceVendorTicket);

            Long problemStartsOn = itticket.getProblemStartsOn();
            emailVO.setProblemStartsOnStr(Objects.nonNull(problemStartsOn) && problemStartsOn > BaseConstant.ZERO ?
                    InternationalizationUtils.formatDateTime(problemStartsOn, longDate, hourClock, timezone, language) : "");

            emailVO.setPriority(itticketPriorityService.getById(itticket.getPriority()).getName());
            emailVO.setContactInfo(itticket.getContactInfo());
            emailVO.setComments(StringUtils.isEmpty(itticket.getComments()) ? "--" : EmailUtil.changeLine(itticket.getComments()));
            emailVO.setHereLink(itticketDetailPage + "?id=" + itticket.getId() + "&property=" + propertyDTO.getAbbr() +
                    "&tenant=" + propertyDTO.getTenantSymbol());
            return emailVO;
        }

        /**
         * 新增 notification
         *
         * @param propertyId      资产 id
         * @param notificationDTO 配置内容
         * @param userId          操作人
         * @return 通知 id
         * @author yyt
         * @date 2023/3/28
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public Integer saveNotification(int propertyId, ItticketNotificationDTO notificationDTO, Integer userId) {
            ItticketNotification notification = beanMapper.map(notificationDTO, ItticketNotification.class);
            notification.setPropertyId(propertyId);
            notification.setUpdateBy(userId);
            notification.setUpdateTime(DateTimeUtils.nowTimestamp());
            baseMapper.saveOrUpdate(notification);

            if (Objects.nonNull(notificationDTO.getId())) {
                itticketNotificationTargetService.clearNotificationTarget(notification.getId());
            }

            itticketNotificationTargetService.saveBatch(notification.getId(), propertyId, notificationDTO);

            return notification.getId();
        }

        /**
         * 校验通知存在
         *
         * @param id 通知 id
         * @return 通知
         * @author yyt
         * @date 2023/3/28
         */
        @Override
        public ItticketNotification checkExist(int id) {
            ItticketNotification notification = getById(id);
            if (Objects.isNull(notification)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_FOUND,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the itticketNotification is not found;id:" + id);
            }
            return notification;
        }

        /**
         * 封装 it 备注信息 邮件内容
         *
         * @param comment it comment
         * @return 备注信息邮件内容
         * @author yyt
         * @date 2024/4/15
         **/
        @Override
        public ItticketCommentEmailVO packageItCommentEmailContent(@Nullable ItticketComment comment) {
            if (Objects.isNull(comment)) {
                return null;
            }

            ItticketCommentEmailVO commentEmailVO = new ItticketCommentEmailVO();
            commentEmailVO.setCommentType(comment.getCommentType());
            commentEmailVO.setComment(comment.getCommentType() == ItticketComment.TYPE_TEXT ? EmailUtil.changeLine(comment.getContent()) : comment.getContent());

            PropertyDTO propertyDTO = propertyI18nRedisService.get(comment.getPropertyId());
            UserDTO user = userInternalService.getOne(propertyDTO.getTenantId(), comment.getCreateId());
            commentEmailVO.setCreateName(user.getName());

            InternationalizationDateTimeDTO dateTime = propertyDTO.getInternationalization().getDateTime();
            commentEmailVO.setCreateTime(InternationalizationUtils.formatDateTime(comment.getCreateTime(),
                    dateTime.getLongDate(), dateTime.getHourClock(), propertyDTO.getTimezone(), propertyDTO.getLanguage()));
            return commentEmailVO;
        }

        /**
         * 获取邮件通知默认主题
         *
         * @param propertyName 资产名称
         * @param type         类型（1.new it request notify，2.it request change）
         * @param locale       多语言
         * @return 默认主题
         * @author yyt
         * @date 2024/11/14
         **/
        @Override
        public String getDefaultSubject(String propertyName, int type, Locale locale) {
            return i18nMessageUtils.message(ItRequestNotifyTypeEnum.getI18nCode(type), locale,
                    i18nMessageUtils.message(FunctionCons.IT_REQUEST, locale), propertyName);
        }

        /**
         * 根据操作类型，获取邮件通知默认主题
         *
         * @param propertyId 资产id
         * @param operation  多语言
         * @return 默认主题
         * @author yyt
         * @date 2024/11/14
         **/
        @Override
        public String getDefaultSubject(Integer propertyId, int operation) {
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            String language = propertyDTO.getLanguage();
            return i18nMessageUtils.message(ItRequestNotifyEnum.getI18nCode(operation), language,
                    i18nMessageUtils.message(FunctionCons.IT_REQUEST, language), propertyDTO.getName());
        }
        /**
         * 获取某个操作下最新的 logVO
         *
         * @param propertyDTO 资产
         * @param id          it request id
         * @param operation   操作
         * @return logVO
         * @author yyt
         * @date 2024/11/14
         **/

        @Override
        public ItticketOperationLogVO getLastOperationLogVO(PropertyDTO propertyDTO, Integer id, int operation) {
            ItticketOperationLog lastLog = itticketOperationLogService.getLastLog(id, operation);
            UserDTO user = userInternalService.getOne(propertyDTO.getTenantId(), lastLog.getCreatedBy());

            InternationalizationDateTimeDTO dateTime = propertyDTO.getInternationalization().getDateTime();

            ItticketOperationLogVO itticketOperationLogVO = new ItticketOperationLogVO();
            itticketOperationLogVO.setOperationName(user.getName());
            itticketOperationLogVO.setOperationTime(InternationalizationUtils.formatDateTime(lastLog.getCreatedTime(),
                    dateTime.getLongDate(), dateTime.getHourClock(), propertyDTO.getTimezone(), propertyDTO.getLanguage()));

            String expansionJson = lastLog.getExpansionJson();
            if (StringUtils.isNotEmpty(expansionJson)) {
                itticketOperationLogVO.setOperationContent(JsonUtils.convertStringToObject(objectMapper, expansionJson, ExpansionDTO.class).getComment());
            } else {
                itticketOperationLogVO.setOperationContent("--");
            }

            return itticketOperationLogVO;
        }

        /**
         * 获取通知列表
         *
         * @param propertyId 资产 id
         * @param type       类型
         * @return 列表
         * @author yyt
         * @date 2026/7/19
         */
        @Override
        public ItticketNotificationDTO listNotificationDTO(int propertyId, Integer type) {
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            Locale locale = LocaleContextHolder.getLocale();
            String defaultSubject = getDefaultSubject(propertyDTO.getName(), type, locale);
            ItticketNotification notification = getItticketNotification(propertyId, type);
            if (Objects.isNull(notification)) {
                return new ItticketNotificationDTO(defaultSubject);
            }

            List<ItticketNotificationTarget> notificationTargets = itticketNotificationTargetService.listByNotificationIds(notification.getId());

            List<Integer> userIds = notificationTargets.stream().filter(item -> item.getSource() == EmailConfigCons.SOURCE_USER)
                    .map(ItticketNotificationTarget::getIdentityId).distinct().toList();
            List<Integer> userGroupIds = notificationTargets.stream().filter(item -> item.getSource() == EmailConfigCons.SOURCE_USERGROUP)
                    .map(ItticketNotificationTarget::getIdentityId).distinct().toList();
            Integer tenantId = propertyDTO.getTenantId();
            Map<Integer, UserDTO> userById = userInternalService.getUserMapByIds(tenantId, userIds);
            Map<Integer, String> userGroupNameById = usergroupInternalService.getUserGroupNameByIds(tenantId, propertyId, userGroupIds);
            notificationTargets.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<ItticketNotificationTarget>> targetsByTargetType = notificationTargets.stream()
                    .collect(Collectors.groupingBy(ItticketNotificationTarget::getTargetType));
            ItticketNotificationDTO configDTO = beanMapper.map(notification, ItticketNotificationDTO.class);
            configDTO.setDefaultSubject(defaultSubject);
            configDTO.setToList(beanMapper.mapList(targetsByTargetType.get(EmailConfigCons.TARGET_TYPE_TO), ItticketNotificationTargetDTO.class));
            configDTO.setCcList(beanMapper.mapList(targetsByTargetType.get(EmailConfigCons.TARGET_TYPE_CC), ItticketNotificationTargetDTO.class));
            return configDTO;
        }

    }