# TaCompareOtaServiceImpl.java

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

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.BaseConstant;
    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.entity.ta.TaRecordsStatus;
    import cloud.wconnect.finance.pojo.bo.ta.ota.TaOtaBO;
    import cloud.wconnect.finance.pojo.bo.ta.ota.TaOtaListBO;
    import cloud.wconnect.finance.service.ta.*;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.google.common.collect.Lists;
    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 java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;

    /**
     * @author zc
     * @date 2023/11/18
     */
    @Service
    @DS("finance")
    public class TaCompareOtaServiceImpl implements ITaCompareOtaService {
        @Resource
        private ITaCompareReportCommonService compareReportCommonService;
        @Resource
        private ITaRecordsStatusService recordsStatusService;
        @Resource
        private ITaCreditCardService creditCardService;
        @Resource
        private ITaPortalService portalService;
        @Resource
        private ITaOtaService otaService;
        @Resource
        private BeanMapper beanMapper;

        /**
         * 处理对比逻辑 for OTA
         *
         * @param property 资产
         * @param taOta    OTA 数据
         * @author zc
         * @date 2023/11/19
         */
        @Override
        public void handleOtaReport(PropertyDTO property, TaOtaBO taOta) {
            // 目标日期
            long targetDate = DateTimeUtils.dateStrToEpochSecond(taOta.getDataDate(),
                    BaseConstant.DATE_FORMAT_YYYY_MM_DD, property.getTimezone());
            // OTA 报告数据
            List<TaOta> taOtaListByReport = formatOtaList(property, targetDate, taOta.getList());

            // 前置处理
            preprocessingForOta(property, targetDate, taOtaListByReport);
            if (CollectionUtils.isEmpty(taOtaListByReport)) {
                return;
            }

            // 获取 OTA 对应的 Credit Card 数据
            List<TaCreditCard> creditCardListByDb = creditCardService.listByOtaList(taOtaListByReport);
            if (CollectionUtils.isEmpty(creditCardListByDb)) {
                return;
            }

            // 获取 Credit Card 对应的 Portal 数据
            List<TaPortal> portalList = portalService.listByOtaList(taOtaListByReport);

            // 获取指定日期范围的比对记录数据
            long startArrivalDate = creditCardListByDb.stream().map(TaCreditCard::getArrivalDate).min(Long::compareTo).get();
            long endArrivalDate = creditCardListByDb.stream().map(TaCreditCard::getArrivalDate).max(Long::compareTo).get();
            List<TaRecordsStatus> recordsStatusList = recordsStatusService.listByArrivalDateRange(property.getId(), startArrivalDate, endArrivalDate);
            // 组装 Records 关联的 CreditCard 数据
            recordsStatusService.relateWithCreditCards(recordsStatusList);

            // 需要保存的比对记录数据
            List<TaRecordsStatus> needSaveRecordsList = Lists.newArrayList();

            // Credit Card 比对 Portal 数据
            compareReportCommonService.creditCardComparePortal(property, creditCardListByDb,
                    portalList, recordsStatusList, needSaveRecordsList);

            // 处理 Portal 合约价
            compareReportCommonService.handlePortalContractPrice(property, targetDate,
                    creditCardListByDb, recordsStatusList, needSaveRecordsList);

            // Credit Card 比对 OTA 数据，处理 OTA 合约价
            compareReportCommonService.creditCardCompareOta(property, targetDate, creditCardListByDb,
                    taOtaListByReport, recordsStatusList, needSaveRecordsList);

            // 保存比对数据
            if (CollectionUtils.isNotEmpty(needSaveRecordsList)) {
                long nowTimestamp = DateTimeUtils.nowTimestamp();
                needSaveRecordsList.forEach(item -> item.setUpdateTime(nowTimestamp));
                recordsStatusService.saveOrUpdateBatch(needSaveRecordsList);
            }

            // 更新 Credit Card CanChoose
            compareReportCommonService.updateCreditCardCanChoose(needSaveRecordsList);
        }

        /**
         * 格式化 OTA 数据
         *
         * @param property   资产
         * @param targetDate 目标日期
         * @param taOtaList  需要格式化的数据
         * @return TaOta
         * @author zc
         * @date 2023/11/19
         */
        private List<TaOta> formatOtaList(PropertyDTO property, long targetDate,
                                          List<TaOtaListBO> taOtaList) {
            // 转换日期字段
            long nowTimestamp = DateTimeUtils.nowTimestamp();
            List<TaOta> otaList = beanMapper.mapList(taOtaList, TaOta.class, (bo, item) -> {
                item.setPropertyId(property.getId());
                item.setArrivalDate(DateTimeUtils.dateStrToEpochSecond(bo.getArrivalDay(),
                        BaseConstant.DATE_FORMAT_YYYY_MM_DD, property.getTimezone()));
                item.setDepartureDate(DateTimeUtils.dateStrToEpochSecond(bo.getDepartureDay(),
                        BaseConstant.DATE_FORMAT_YYYY_MM_DD, property.getTimezone()));
                item.setDataDate(targetDate);
                item.setCreatedTime(nowTimestamp);
                item.setInfoSign(DigestUtils.sha256Hex(StringUtils.join(item.getName(),
                        item.getArrivalDate(), item.getDepartureDate())));
            });
            return otaList.stream().distinct().collect(Collectors.toList());
        }

        /**
         * 比对 OTA 数据的前置处理
         *
         * @param property        资产
         * @param targetDate      目标日期
         * @param otaListByReport OTA By Report
         * @author zc
         * @date 2023/11/19
         */
        private void preprocessingForOta(PropertyDTO property, long targetDate,
                                         List<TaOta> otaListByReport) {
            List<TaOta> otaListByDb = otaService.listByDataDate(property.getId(), targetDate);
            List<String> infoSignListByDb = otaListByDb.stream().map(TaOta::getInfoSign).toList();

            // 获取相同的 Ota By Report 数据签名
            List<String> sameInfoSignList = otaListByReport.stream().map(TaOta::getInfoSign)
                    .filter(infoSignListByDb::contains).toList();
            // 移除已存在的数据
            otaListByReport.removeIf(taPortal -> sameInfoSignList.contains(taPortal.getInfoSign()));
            if (CollectionUtils.isNotEmpty(otaListByReport)) {
                // 保存报告中剩余的数据
                otaService.insertOrUpdateBatchByUnique(otaListByReport);
                // 查询 id
                Map<String, Long> infoSign2OtaId = otaService.listByInfoSign(property.getId(),
                                otaListByReport.stream().map(TaOta::getInfoSign).toList()).stream()
                        .collect(Collectors.toMap(TaOta::getInfoSign, TaOta::getId));
                otaListByReport.forEach(item ->
                        item.setId(infoSign2OtaId.get(item.getInfoSign())));
            }
        }
    }