# TaCreditCardServiceImpl.java

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

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.exception.ListenerException;
    import cloud.wconnect.commonlib.exception.ParseReportException;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    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.mapper.ta.TaCreditCardMapper;
    import cloud.wconnect.finance.pojo.bo.ta.creditcard.TaCreditCardListBO;
    import cloud.wconnect.finance.pojo.dto.ta.manualrecords.TaCreditCardManualDTO;
    import cloud.wconnect.finance.service.ta.ITaCreditCardService;
    import cloud.wconnect.finance.service.ta.creditcard.ITaCreditCardParseService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    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.context.ApplicationContext;
    import org.springframework.stereotype.Service;
    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-07
     */
    @Service
    @DS("finance")
    public class TaCreditCardServiceImpl extends ServiceImpl<TaCreditCardMapper, TaCreditCard> implements ITaCreditCardService {
        @Resource
        private BeanMapper beanMapper;
        @Resource
        private ApplicationContext applicationContext;

        /**
         * 保存手动创建的 Credit Card 数据
         *
         * @param propertyId     资产 id
         * @param creditCardList Credit Card
         * @return Credit Card id 集合
         * @author zc
         * @date 2023/7/14
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public List<Long> addManual(int propertyId, List<TaCreditCardManualDTO> creditCardList) {
            List<TaCreditCard> taCreditCardList = beanMapper.mapList(creditCardList, TaCreditCard.class, (dto, creditCard) -> {
                creditCard.setPropertyId(propertyId);
                creditCard.setCardNo(dto.getLastFourDigits());
                creditCard.setDataDate(BaseConstant.LONG_ZERO);
                creditCard.setCreatedTime(DateTimeUtils.nowTimestamp());
                creditCard.setInfoSign(DigestUtils.sha256Hex(StringUtils.join(creditCard.getRoomNo(),
                        creditCard.getName(), creditCard.getArrivalDate(), creditCard.getDepartureDate(),
                        creditCard.getCardType(), creditCard.getCardNo(), creditCard.getRoomRevenue(),
                        creditCard.getFbRevenue(), creditCard.getNonRevenue(), creditCard.getTotalCharged())));
            });
            saveBatch(taCreditCardList);

            return taCreditCardList.stream().map(TaCreditCard::getId).toList();
        }

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

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

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

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

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

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

            baseMapper.insertOrUpdateBatchByUnique(list);
        }
    }