# RevenueDayHotelPriceHandle.java

    package cloud.wconnect.rateshop.springlistener.revenue;

    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.exception.ListenerException;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.rateshop.entity.rateshop.PropertyHotel;
    import cloud.wconnect.rateshop.entity.revenue.HistoryRatePropertyMapping;
    import cloud.wconnect.rateshop.pojo.dto.revenue.DayHotelPriceDTO;
    import cloud.wconnect.rateshop.pojo.dto.rateshop.consumer.hotelprice.PlatformDTO;
    import cloud.wconnect.rateshop.pojo.dto.rateshop.consumer.hotelprice.PriceDTO;
    import cloud.wconnect.rateshop.pojo.dto.rateshop.consumer.hotelprice.PriceMessage;
    import cloud.wconnect.rateshop.pojo.dto.rateshop.consumer.hotelprice.RoomDTO;
    import cloud.wconnect.rateshop.service.IHistoryRateNextNDaysByRateTypeService;
    import cloud.wconnect.rateshop.service.rateshop.IPropertyHotelService;
    import cloud.wconnect.rateshop.service.revenue.IHistoryRatePropertyMappingService;
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.google.common.collect.Lists;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.stereotype.Component;
    import org.springframework.transaction.annotation.Transactional;

    import java.math.BigDecimal;
    import java.time.LocalDate;
    import java.util.*;
    import java.util.function.Function;
    import java.util.stream.Collectors;

    /**
     * 按天存储房价的处理器
     *
     * @author lichen
     * @date 2024/3/25
     */
    @Component
    public class RevenueDayHotelPriceHandle {

        @Autowired
        private IHistoryRatePropertyMappingService historyRatePropertyMappingService;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;
        @Autowired
        private IPropertyHotelService propertyHotelService;
        @Autowired
        private ApplicationContext applicationContext;

        /**
         * 处理房价消息
         *
         * @param priceMessage 房价消息
         * @return void
         * @author lichen
         * @date 2024/3/25
         */
        @Transactional(rollbackFor = Exception.class)
        public void handle(PriceMessage priceMessage) {
            LocalDate now = LocalDate.now();
            String yesterday = DateTimeUtils.localDateToStr(now.minusDays(1), BaseConstant.DATE_FORMAT_YYYYMMDD);
            String featureDay = DateTimeUtils.localDateToStr(now.plusDays(15), BaseConstant.DATE_FORMAT_YYYYMMDD);
            //获取昨天到未来15天的房价
            List<PriceDTO> priceDTOS = priceMessage.getData().stream().filter(priceDTO -> {
                Long checkInDate = priceDTO.getCheckInDate();
                return checkInDate.compareTo(Long.valueOf(yesterday)) >= 0 && checkInDate.compareTo(Long.valueOf(featureDay)) <= 0;
            }).toList();
            if (CollectionUtils.isEmpty(priceDTOS)) return;

            //获取最新的房价
            List<DayHotelPriceDTO> dayHotelPriceDTOS = Lists.newArrayListWithCapacity(priceDTOS.size());
            for (PriceDTO priceDTO : priceDTOS) {
                List<PlatformDTO> hotelPriceByPlatform = priceDTO.getPlatform();
                for (PlatformDTO platformDTO : hotelPriceByPlatform) {
                    List<RoomDTO> hotelPriceByRoom = platformDTO.getRoom();
                    if (CollectionUtils.isNotEmpty(hotelPriceByRoom)) {
                        //税前最低价
                        BigDecimal beforeTaxMinRate = hotelPriceByRoom.stream().map(RoomDTO::getRate)
                                .filter(Objects::nonNull).min(BigDecimal::compareTo).orElse(null);
                        //税后最低价
                        BigDecimal afterTaxMinRate = hotelPriceByRoom.stream().map(RoomDTO::getAfterTaxRate)
                                .filter(Objects::nonNull).min(BigDecimal::compareTo).orElse(null);
                        //添加到房价集合中
                        dayHotelPriceDTOS.add(new DayHotelPriceDTO()
                                .setCheckInDate(priceDTO.getCheckInDate())
                                .setDatasourceId(priceMessage.getDatasourceId())
                                .setPlatformId(platformDTO.getId())
                                .setPrice(beforeTaxMinRate).setAfterTaxPrice(afterTaxMinRate)
                                .setQueryDate(priceMessage.getQueryDate()));
                    } else {
                        //Sold out
                        dayHotelPriceDTOS.add(new DayHotelPriceDTO()
                                .setCheckInDate(priceDTO.getCheckInDate())
                                .setDatasourceId(priceMessage.getDatasourceId())
                                .setPlatformId(platformDTO.getId())
                                .setPrice(BigDecimal.ZERO).setAfterTaxPrice(BigDecimal.ZERO)
                                .setQueryDate(priceMessage.getQueryDate()));
                    }
                }
            }
            if (CollectionUtils.isEmpty(dayHotelPriceDTOS)) return;

            //查询酒店关联的资产信息
            List<PropertyHotel> propertyHotels = propertyHotelService.getByHotelIdAndCurrencyIdAndPos(priceMessage.getHotelId(),
                    priceMessage.getCurrencyId(), priceMessage.getPos());
            List<Integer> propertyIds = propertyHotels.stream().map(PropertyHotel::getPropertyId).toList();
            Map<Integer, PropertyDTO> propertyId2DTO = propertyI18nRedisService.list(propertyIds).stream()
                    .collect(Collectors.toMap(PropertyDTO::getId, Function.identity()));

            //获取保存房价的处理类
            Long rate14Id = null;
            Collection<IHistoryRateNextNDaysByRateTypeService> historyRateNextNDaysServiceList = applicationContext.getBeansOfType(IHistoryRateNextNDaysByRateTypeService.class).values();
            for (IHistoryRateNextNDaysByRateTypeService historyRateNextNDaysService : historyRateNextNDaysServiceList) {
                if (historyRateNextNDaysService.supports(priceMessage.getRateType())) {
                    //保存房价
                    rate14Id = historyRateNextNDaysService.save(priceMessage.getHotelId(), priceMessage.getCurrencyId(), priceMessage.getQueryDate(),
                            dayHotelPriceDTOS, propertyHotels, priceMessage.getPos());
                }
            }
            if (Objects.isNull(rate14Id)) {
                throw new ListenerException("rate14Id is null, price process class not exist, rateType = " + priceMessage.getRateType());
            }
            Long finalRate14Id = rate14Id;

            //先删除关系
            historyRatePropertyMappingService.remove(new LambdaQueryWrapper<HistoryRatePropertyMapping>()
                    .eq(HistoryRatePropertyMapping::getHotelId, priceMessage.getHotelId())
                    .eq(HistoryRatePropertyMapping::getRate14Id, finalRate14Id)
                    .eq(HistoryRatePropertyMapping::getRateType, priceMessage.getRateType()));
            //保存资产和酒店映射
            List<HistoryRatePropertyMapping> historyRatePropertyMappings = propertyHotels.stream().map(propertyHotel -> {
                PropertyDTO propertyDTO = propertyId2DTO.get(propertyHotel.getPropertyId());
                Integer targetDate = Integer.valueOf(DateTimeUtils.timestampToStr(priceMessage.getQueryDate(),
                        BaseConstant.DATE_FORMAT_YYYYMMDD, propertyDTO.getTimezone()));
                return new HistoryRatePropertyMapping().setTenantId(propertyDTO.getTenantId())
                        .setPropertyId(propertyDTO.getId())
                        .setHotelId(priceMessage.getHotelId())
                        .setTargetDate(targetDate)
                        .setRate14Id(finalRate14Id)
                        .setRateType(priceMessage.getRateType());
            }).toList();
            historyRatePropertyMappingService.saveBatch(historyRatePropertyMappings);
        }
    }