# TaOtaServiceImpl.java

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

    import cloud.wconnect.commonlib.exception.ListenerException;
    import cloud.wconnect.commonlib.exception.ParseReportException;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.finance.entity.ta.TaCreditCard;
    import cloud.wconnect.finance.entity.ta.TaOta;
    import cloud.wconnect.finance.mapper.ta.TaOtaMapper;
    import cloud.wconnect.finance.pojo.bo.ta.ota.TaOtaListBO;
    import cloud.wconnect.finance.service.ta.ITaOtaService;
    import cloud.wconnect.finance.service.ta.ota.ITaOtaParseService;
    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.context.ApplicationContext;
    import org.springframework.stereotype.Service;

    import jakarta.annotation.Resource;
    import org.springframework.transaction.annotation.Transactional;

    import java.io.InputStream;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;

    /**
     * <p>
     * 服务实现类
     * </p>
     *
     * @author zc
     * @since 2023-07-19
     */
    @Service
    @DS("finance")
    public class TaOtaServiceImpl extends ServiceImpl<TaOtaMapper, TaOta> implements ITaOtaService {
        @Resource
        private ApplicationContext applicationContext;

        /**
         * 根据目标日期获取 OTA 数据
         *
         * @param propertyId 资产 id
         * @param targetDate 目标日期
         * @return TaOta 集合
         * @author zc
         * @date 2023/7/19
         */
        @Override
        public List<TaOta> listByDataDate(int propertyId, long targetDate) {
            return list(new QueryWrapper<TaOta>().lambda()
                    .eq(TaOta::getPropertyId, propertyId)
                    .eq(TaOta::getDataDate, targetDate));
        }

        /**
         * 获取 Credit Card 对应的 OTA 数据
         *
         * @param taCreditCardListByReport Credit Card 数据
         * @return TaOta 集合
         * @author zc
         * @date 2023/7/26
         */
        @Override
        public List<TaOta> listByCreditCardList(List<TaCreditCard> taCreditCardListByReport) {
            if (CollectionUtils.isEmpty(taCreditCardListByReport)) {
                return Collections.emptyList();
            }
            return baseMapper.listByCreditCardList(taCreditCardListByReport);
        }

        /**
         * 解析 OTA 报告
         *
         * @param propertyDTO 资产
         * @param source      数据源平台
         * @param in          文件
         * @return TaOtaListBO 集合
         * @author zc
         * @date 2023/7/27
         */
        @Override
        public List<TaOtaListBO> parseReport(PropertyDTO propertyDTO, String source, InputStream in) throws ParseReportException {
            Collection<ITaOtaParseService> parserList = applicationContext.getBeansOfType(ITaOtaParseService.class).values();
            for (ITaOtaParseService parser : parserList) {
                if (parser.supports(source)) {
                    return parser.parse(propertyDTO, in);
                }
            }
            throw new ListenerException("Not found report parser");
        }

        /**
         * 根据签名查询数据
         *
         * @param propertyId   资产 id
         * @param infoSignList 签名集合
         * @return TaOta 集合
         * @author zc
         * @date 2023/11/20
         */
        @Override
        public List<TaOta> listByInfoSign(int propertyId, List<String> infoSignList) {
            if (CollectionUtils.isEmpty(infoSignList)) {
                return Collections.emptyList();
            }
            return list(new QueryWrapper<TaOta>().lambda()
                    .eq(TaOta::getPropertyId, propertyId)
                    .in(TaOta::getInfoSign, infoSignList));
        }

        /**
         * 批量保存数据
         *
         * @param list 数据
         * @author zc
         * @date 2026/1/27
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void insertOrUpdateBatchByUnique(List<TaOta> list) {
            if (CollectionUtils.isEmpty(list)) {
                return;
            }
            // 按唯一索引字段排序，避免死锁
            list.sort(Comparator.comparing(TaOta::getPropertyId)
                    .thenComparing(TaOta::getInfoSign));

            baseMapper.insertOrUpdateBatchByUnique(list);
        }
    }