# CbAdjCommentServiceImpl.java

    package cloud.wconnect.finance.service.chargeback.impl;

    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.CommonErrorI18nConstant;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.util.AttachmentUtil;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.S3Utils;
    import cloud.wconnect.commonlib.util.TransactionUtils;
    import cloud.wconnect.finance.cons.S3BucketFunctionCons;
    import cloud.wconnect.finance.entity.chargeback.CbAdj;
    import cloud.wconnect.finance.entity.chargeback.CbAdjComment;
    import cloud.wconnect.finance.mapper.chargeback.CbAdjCommentMapper;
    import cloud.wconnect.finance.pojo.dto.chargeback.SaveAdjCommentDTO;
    import cloud.wconnect.finance.service.chargeback.ICbAdjCommentService;
    import cloud.wconnect.finance.service.chargeback.ICbAdjSenderService;
    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 org.apache.commons.collections.CollectionUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    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.concurrent.Executor;
    import java.util.stream.Collectors;

    /**
     * <p>
     * 服务实现类
     * </p>
     *
     * @author yyt
     * @since 2023-08-22
     */
    @Service
    @DS("finance")
    public class CbAdjCommentServiceImpl extends ServiceImpl<CbAdjCommentMapper, CbAdjComment> implements ICbAdjCommentService {

        @Value("${aws-s3.region}")
        private String region;
        @Value("#{${aws-s3.function-bucket}}")
        private Map<String, Map<String, Object>> bucketMap;
        @Autowired
        private ObjectMapper objectMapper;
        @Autowired
        private Executor executor;
        @Autowired
        private ICbAdjSenderService cbAdjSenderService;

        /**
         * 校验存在
         *
         * @param id comment id
         * @return 评论
         * @author yyt
         * @date 2023/9/4
         */
        @Override
        public CbAdjComment checkExist(long id) {
            CbAdjComment comment = getById(id);
            if (Objects.isNull(comment)) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_FOUND,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the cbAdjComment is not found;id:" + id);
            }
            return comment;
        }

        /**
         * 保存备注
         *
         * @param propertyId        资产 id
         * @param cbAdj             cb adj
         * @param saveAdjCommentDTO 备注信息
         * @param userId            操作人
         * @return java.lang.Long
         * @author lichen
         * @date 2026/2/13
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public Long save(Integer propertyId, CbAdj cbAdj, SaveAdjCommentDTO saveAdjCommentDTO, int userId) {
            CbAdjComment cbAdjComment = new CbAdjComment().setPropertyId(propertyId)
                    .setCbAdjId(cbAdj.getId())
                    .setContent(saveAdjCommentDTO.getContent())
                    .setAttachments(saveAdjCommentDTO.getAttachments())
                    .setCreatedBy(userId)
                    .setCreatedTime(DateTimeUtils.nowTimestamp());
            save(cbAdjComment);

            TransactionUtils.afterCommitAsyncExecute(executor, () -> {
                // 发送备注消息
                cbAdjSenderService.handleSentAdjCommentEvent(cbAdj);
            });
            return cbAdjComment.getId();
        }

        /**
         * 更新备注
         *
         * @param comment           更新前的备注
         * @param saveAdjCommentDTO 备注信息
         * @param cbAdj             Cb Adj
         * @author yyt
         * @date 2026/1/19
         **/
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void update(CbAdjComment comment, SaveAdjCommentDTO saveAdjCommentDTO, CbAdj cbAdj) {
            CbAdjComment updateComment = new CbAdjComment();
            updateComment.setContent(saveAdjCommentDTO.getContent());
            updateComment.setAttachments(saveAdjCommentDTO.getAttachments());
            updateComment.setCreatedTime(DateTimeUtils.nowTimestamp());
            updateComment.setId(comment.getId());
            updateById(updateComment);

            TransactionUtils.afterCommitAsyncExecute(executor, () -> {
                //修改前的s3Key集合
                List<String> updateBeforeS3Keys = AttachmentUtil.getKeysByAbbrAttachmentArrayJson(comment.getAttachments(), objectMapper);
                //修改后的s3Key集合
                List<String> updateAfterS3Keys = AttachmentUtil.getKeysByAbbrAttachmentArrayJson(saveAdjCommentDTO.getAttachments(), objectMapper);
                //删除的附件 = 修改前的附件集合 - 修改后的附件集合
                List<String> delS3Keys = Lists.newArrayList(updateBeforeS3Keys);
                delS3Keys.removeAll(updateAfterS3Keys);
                S3Utils.batchDeleteFile(region, bucketMap.get(S3BucketFunctionCons.CHARGEBACK), delS3Keys);

                // 发送备注消息
                cbAdjSenderService.handleSentAdjCommentEvent(cbAdj);
            });

        }

        /**
         * 删除备注
         *
         * @param comment 删除的备注
         * @param cbAdj   Cb Adj
         * @author yyt
         * @date 2026/1/19
         **/
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void delete(CbAdjComment comment, CbAdj cbAdj) {
            removeById(comment.getId());

            TransactionUtils.afterCommitAsyncExecute(executor, () -> {
                //删除附件
                List<String> delS3Keys = AttachmentUtil.getKeysByAbbrAttachmentArrayJson(comment.getAttachments(), objectMapper);
                S3Utils.batchDeleteFile(region, bucketMap.get(S3BucketFunctionCons.CHARGEBACK), delS3Keys);
                // 发送备注消息
                cbAdjSenderService.handleSentAdjCommentEvent(cbAdj);
            });

        }

        /**
         * 根据 adj id 获取所有备注
         *
         * @param cbAdjIds adj id
         * @return java.util.List<cloud.wconnect.finance.entity.chargeback.CbAdjComment>
         * @author lichen
         * @date 2026/2/10
         */
        @Override
        public List<CbAdjComment> listByCbAdjIds(List<Long> cbAdjIds) {
            if (CollectionUtils.isEmpty(cbAdjIds)) return Collections.emptyList();
            return list(new QueryWrapper<CbAdjComment>().lambda()
                    .in(CbAdjComment::getCbAdjId, cbAdjIds)
                    .orderByDesc(CbAdjComment::getCreatedTime));
        }

        /**
         * 根据 adj id 删除所有备注
         *
         * @param cbAdjIds adj id集合
         * @author lichen
         * @date 2026/2/12
         */
        @Override
        public void removeByCbAdjIds(List<Long> cbAdjIds) {
            if (CollectionUtils.isEmpty(cbAdjIds)) return;

            remove(new QueryWrapper<CbAdjComment>().lambda()
                    .in(CbAdjComment::getCbAdjId, cbAdjIds));
        }

    }