# TaPortalServiceImpl.java

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

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.JsonUtils;
    import cloud.wconnect.finance.entity.ta.TaCreditCard;
    import cloud.wconnect.finance.entity.ta.TaOta;
    import cloud.wconnect.finance.entity.ta.TaPortal;
    import cloud.wconnect.finance.entity.ta.TaRecordsStatus;
    import cloud.wconnect.finance.mapper.ta.TaPortalMapper;
    import cloud.wconnect.finance.pojo.dto.ta.TaPortalJsonDTO;
    import cloud.wconnect.finance.pojo.dto.ta.manualrecords.TaPortalManualDTO;
    import cloud.wconnect.finance.service.ta.ITaPortalService;
    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 jakarta.annotation.Resource;
    import org.apache.commons.codec.digest.DigestUtils;
    import org.apache.commons.collections.CollectionUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;

    /**
     * <p>
     * 服务实现类
     * </p>
     *
     * @author zc
     * @since 2023-07-07
     */
    @Service
    @DS("finance")
    public class TaPortalServiceImpl extends ServiceImpl<TaPortalMapper, TaPortal> implements ITaPortalService {
        @Resource
        private BeanMapper beanMapper;
        @Resource
        private ObjectMapper objectMapper;

        /**
         * 保存手动创建的 Portal 数据
         *
         * @param propertyId 资产 id
         * @param portal     Portal
         * @return long
         * @author zc
         * @date 2023/7/14
         */
        @Override
        public long addManual(int propertyId, TaPortalManualDTO portal) {
            TaPortal taPortal = beanMapper.map(portal, TaPortal.class, item -> {
                item.setPropertyId(propertyId);
                item.setType(TaRecordsStatus.PLATFORM_TYPE_TA);
                item.setCardNo(portal.getLastFourDigits());
                item.setCreatedTime(DateTimeUtils.nowTimestamp());
                item.setDetails(JsonUtils.convertObjToString(objectMapper,
                        TaPortalJsonDTO.builder()
                                .airline(portal.getAirline())
                                .voucher(portal.getVoucher())
                                .departDate(portal.getDepartureDate())
                                .customerNumber(portal.getCustomerNumber())
                                .build()));
                item.setDataDate(BaseConstant.LONG_ZERO);
                item.setInfoSign(DigestUtils.sha256Hex(StringUtils.join(item.getType(),
                        item.getArrivalDate(), item.getName(), item.getRooms(),
                        item.getCardNo(), item.getRate(), item.getTotalCharged(),
                        item.getNights(), item.getDetails())));
            });

            save(taPortal);

            return taPortal.getId();
        }

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

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

        /**
         * 获取 OTA 对应的 Portal 数据
         *
         * @param taOtaList OTA 数据
         * @return TaPortal 集合
         * @author zc
         * @date 2023/7/31
         */
        @Override
        public List<TaPortal> listByOtaList(List<TaOta> taOtaList) {
            if (CollectionUtils.isEmpty(taOtaList)) {
                return Collections.emptyList();
            }
            return baseMapper.listByOtaList(taOtaList);
        }

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

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

            baseMapper.insertOrUpdateBatchByUnique(list);
        }
    }