# NotifyOccSnapshotForTheNextNDaysTask.java

    package cloud.wconnect.rateshop.businesstask.rateshop;

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.cons.FunctionCons;
    import cloud.wconnect.commonlib.cons.SchedulerCons;
    import cloud.wconnect.commonlib.pojo.dto.NotifyDTO;
    import cloud.wconnect.commonlib.pojo.dto.NotifyIdentityDTO;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.pojo.dto.internationalization.InternationalizationDTO;
    import cloud.wconnect.commonlib.pojo.dto.internationalization.InternationalizationDateTimeDTO;
    import cloud.wconnect.commonlib.pojo.dto.internationalization.InternationalizationNumberDTO;
    import cloud.wconnect.commonlib.pojo.dto.scheduler.JobParameterDTO;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.service.NotifyInternalService;
    import cloud.wconnect.commonlib.util.*;
    import cloud.wconnect.rateshop.cons.FunctionPointEnum;
    import cloud.wconnect.rateshop.cons.PrecisionCons;
    import cloud.wconnect.rateshop.cons.rateshop.RateShopNotifyConfigTypeEnum;
    import cloud.wconnect.rateshop.cons.rateshop.RateTypeEnum;
    import cloud.wconnect.rateshop.cons.revenue.RevenueCons;
    import cloud.wconnect.rateshop.entity.rateshop.*;
    import cloud.wconnect.rateshop.pojo.dto.rateshop.LatestHotelPriceDTO;
    import cloud.wconnect.rateshop.pojo.dto.rateshop.NotifyRuleJSONDTO;
    import cloud.wconnect.rateshop.pojo.dto.rateshop.RateConfigDTO;
    import cloud.wconnect.rateshop.pojo.dto.rateshop.occforcast.OccForcastNotifyDTO;
    import cloud.wconnect.rateshop.pojo.dto.rateshop.occforcast.OccForecastDTO;
    import cloud.wconnect.rateshop.pojo.query.rateshop.LatestHotelPriceQuery;
    import cloud.wconnect.rateshop.service.rateshop.*;
    import com.alibaba.fastjson.JSONObject;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.google.common.collect.Lists;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.collections.CollectionUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Component;
    import org.thymeleaf.TemplateEngine;
    import org.thymeleaf.context.Context;

    import java.math.BigDecimal;
    import java.text.MessageFormat;
    import java.time.ZonedDateTime;
    import java.time.format.DateTimeFormatter;
    import java.util.*;
    import java.util.function.Function;
    import java.util.stream.Collectors;

    /**
     * Occ Snapshot for the next N Days 通知
     *
     * @author lichen
     * @date 2024/6/20
     */
    @Slf4j
    @Component
    public class NotifyOccSnapshotForTheNextNDaysTask {

        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;
        @Autowired
        private IRateShopEmailConfigService emailConfigService;
        @Autowired
        private IRateShopEmailTargetService emailTargetService;
        @Autowired
        private IRateShopNotifyRuleService notifyRuleService;
        @Autowired
        private ObjectMapper objectMapper;
        @Autowired
        private IPropertyHotelService propertyHotelService;
        @Autowired
        private ILatestBARRateService latestBARRateService;
        @Autowired
        private ILatestRateService latestRateService;
        @Autowired
        private ISettingService settingService;
        @Autowired
        private IRateShopOccForecastService rateShopOccForecastService;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;
        @Autowired
        private TemplateEngine templateEngine;
        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private NotifyInternalService notifyInternalService;
        @Value("${here.link.rate-shop}")
        private String hereLink;
        //百分号单位
        private static final String unitStr = " %";

        /**
         * 执行通知
         *
         * @param scheduler 调度任务
         * @return void
         * @author lichen
         * @date 2024/6/20
         */
        @Async
        public void notifyOccForecast(RateShopScheduler scheduler) {
            log.info("NotifyOccSnapshotForTheNextNDays.notify start...");
            Integer propertyId = scheduler.getPropertyId();
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);

            //查询邮件配置
            RateShopEmailConfig emailConfig = emailConfigService.getByPropertyIdAndType(propertyId, scheduler.getCategory());
            if (Objects.isNull(emailConfig)) {
                log.info("NotifyOccSnapshotForTheNextNDays.notify, email config is null");
                return;
            }
            if (!emailConfig.getStatus()) {
                log.info("NotifyOccSnapshotForTheNextNDays.end, email config status is false, propertyId:{},schedulerJobId:{},type:{}",
                        propertyDTO.getId(), scheduler.getId(), scheduler.getCategory());
                return;
            }
            List<RateShopEmailTarget> emailTargets = emailTargetService.listByConfigIds(Collections.singletonList(emailConfig.getId()));
            if (CollectionUtils.isEmpty(emailTargets)) {
                log.info("NotifyOccSnapshotForTheNextNDays.notify, email targets is empty");
                return;
            }

            //查询通知规则
            RateShopNotifyRule notifyRule = notifyRuleService.getByPropertyIdAndTypeOrDefault(propertyId, RateShopNotifyConfigTypeEnum.OCC_SNAPSHOT_FOR_THE_NEXT_N_DAYS.getType());
            NotifyRuleJSONDTO notifyRuleJSONDTO = JsonUtils.convertStringToObject(objectMapper, notifyRule.getRule(), NotifyRuleJSONDTO.class);
            //比对n天（包含当天）, 所以通知的天数需要减一
            notifyRuleJSONDTO.setNumberOfDays(notifyRuleJSONDTO.getNumberOfDays() - 1);

            //当前时刻
            ZonedDateTime zonedDateTime = DateTimeUtils.dateTimeNow(propertyDTO.getTimezone());
            //获取任务的对比时刻
            JobParameterDTO jobParameterDTO = JsonUtils.convertStringToObject(objectMapper, scheduler.getParameters(), JobParameterDTO.class);
            //获取比较时刻
            int compareHour = Integer.parseInt(JSONObject.parseObject(jobParameterDTO.getCustomBusiness()).get(SchedulerCons.HOUR).toString());

            //查询Occ
            List<OccForcastNotifyDTO> occForcastNotifyDTOS = listOccForcast(zonedDateTime, compareHour, notifyRuleJSONDTO.getNumberOfDays(), propertyDTO);

            //设置房价数据
            setRate(occForcastNotifyDTOS, propertyDTO, zonedDateTime, notifyRuleJSONDTO);

            //执行通知
            doNotifyOccForecast(zonedDateTime, compareHour, emailConfig, emailTargets, propertyDTO, occForcastNotifyDTOS, notifyRuleJSONDTO);
        }

        /**
         * 执行通知
         *
         * @param zonedDateTime        当前时间
         * @param compareHour          对比时刻
         * @param emailConfig          邮件配置
         * @param emailTargets         邮件通知人
         * @param propertyDTO          资产DTO
         * @param occForcastNotifyDTOS 通知的OCC数据
         * @param notifyRuleJSONDTO    通知规则
         * @return void
         * @author lichen
         * @date 2024/6/21
         */
        private void doNotifyOccForecast(ZonedDateTime zonedDateTime, int compareHour, RateShopEmailConfig emailConfig, List<RateShopEmailTarget> emailTargets,
                                         PropertyDTO propertyDTO, List<OccForcastNotifyDTO> occForcastNotifyDTOS, NotifyRuleJSONDTO notifyRuleJSONDTO) {
            String functionName = i18nMessageUtils.message(FunctionCons.RATE_SHOP_FUNCTION, propertyDTO.getLanguage());
            String link = hereLink + MessageFormat.format("?property={0}&tenant={1}", propertyDTO.getAbbr(), propertyDTO.getTenantSymbol());

            InternationalizationDateTimeDTO dateTimeDTO = propertyDTO.getInternationalization().getDateTime();

            //当前时刻
            String nowMoment = InternationalizationUtils.formatDateTime(zonedDateTime.withMinute(0).toEpochSecond(), dateTimeDTO.getLongDate(),
                    dateTimeDTO.getHourClock(), propertyDTO.getTimezone(), propertyDTO.getLanguage());

            //对比时刻
            ZonedDateTime compareZonedDateTime = zonedDateTime;
            if (compareHour >= zonedDateTime.getHour()) {
                //对比时刻为前一天的版本
                compareZonedDateTime = zonedDateTime.minusDays(1).withHour(compareHour);
            }
            String compareMoment = InternationalizationUtils.formatDateTime(compareZonedDateTime.withHour(compareHour).withMinute(0).toEpochSecond(), dateTimeDTO.getLongDate(),
                    dateTimeDTO.getHourClock(), propertyDTO.getTimezone(), propertyDTO.getLanguage());

            //生成邮件内容
            Context context = new Context();
            context.setVariable("propertyName", propertyDTO.getName());
            context.setVariable("functionName", functionName);
            //通知天数增加1的原因：查询数据时，由于数据包含当天，所以查询范围是 当天 ~ 比对天数减1。此处需要再加回来。
            context.setVariable("numberOfDays", notifyRuleJSONDTO.getNumberOfDays() + 1);
            context.setVariable("rateTypeStr", i18nMessageUtils.message(RateTypeEnum.getI18nCode(notifyRuleJSONDTO.getRateType()), propertyDTO.getLanguage()));
            context.setVariable("nowMoment", nowMoment);
            context.setVariable("compareMoment", compareMoment);
            context.setVariable("occForcastNotifyDTOS", occForcastNotifyDTOS);
            context.setVariable("hereLink", link);
            String mailBody = templateEngine.process("rateshop/rateshop-occ_" + propertyDTO.getLanguage(), context);

            //通知主题
            String defaultSubjectI18nCode = RateShopNotifyConfigTypeEnum.getDefaultSubjectI18nCode(emailConfig.getType());
            String defaultSubject = i18nMessageUtils.message(defaultSubjectI18nCode, propertyDTO.getLanguage(), functionName,
                    notifyRuleJSONDTO.getNumberOfDays() + 1, propertyDTO.getName());
            //自定义主体优先，其次默认主题
            String subject = StringUtils.isNotBlank(emailConfig.getSubject()) ? emailConfig.getSubject() : defaultSubject;

            //通知DTO
            NotifyDTO notifyDTO = new NotifyDTO();
            notifyDTO.setPropertyId(propertyDTO.getId());
            notifyDTO.setFunctionPoint(FunctionPointEnum.RATE_SHOP_OCC_SNAPSHOT.getFunctionPoint());
            notifyDTO.setSubject(subject);
            notifyDTO.setIdentityList(beanMapper.mapList(emailTargets, NotifyIdentityDTO.class));
            notifyDTO.setEmailContent(EmailUtil.getFullEmailContent(defaultSubject, mailBody, propertyDTO.getLanguage()));
            //不进行line通知
            notifyDTO.setLineContent(Collections.emptyList());
            notifyInternalService.sendNotify(notifyDTO);
        }

        /**
         * 设置房价数据
         *
         * @param occForcastNotifyDTOS occ数据
         * @param propertyDTO          资产DTO
         * @param zonedDateTime        当前时间
         * @param notifyRuleJSONDTO    通知规则
         * @return void
         * @author lichen
         * @date 2024/6/21
         */
        private void setRate(List<OccForcastNotifyDTO> occForcastNotifyDTOS, PropertyDTO propertyDTO, ZonedDateTime zonedDateTime,
                             NotifyRuleJSONDTO notifyRuleJSONDTO) {
            //资产国际化配置
            InternationalizationDTO internationalization = propertyDTO.getInternationalization();
            String currency = internationalization.getNumber().getCurrency();
            String calculationRule = internationalization.getNumber().getCalculationRule();
            String language = propertyDTO.getLanguage();

            //查询房价数据
            List<LatestHotelPriceDTO> latestHotelPriceDTOS = listRate(zonedDateTime, notifyRuleJSONDTO, propertyDTO);

            //No Data
            String noDataMsg = i18nMessageUtils.message(RevenueCons.I18N_NO_DATA, language);
            //Sold out
            String soldOutMsg = i18nMessageUtils.message(RevenueCons.I18N_SOLD_OUT, language);

            //房价数据
            Map<Long, String> theDate2RateStr = latestHotelPriceDTOS.stream().collect(Collectors.toMap(
                    item -> Long.parseLong(item.getDate().replace("-", "")),
                    item -> {
                        BigDecimal price = item.getPrice();
                        if (Objects.isNull(price)) {
                            return noDataMsg;
                        } else {
                            if (price.compareTo(BigDecimal.ZERO) == 0) {
                                return soldOutMsg;
                            } else {
                                return InternationalizationUtils.formatAmountViewValue(price, calculationRule, currency);
                            }
                        }
                    }));

            //设置房价数据
            for (OccForcastNotifyDTO occForcastNotifyDTO : occForcastNotifyDTOS) {
                Long theDate = occForcastNotifyDTO.getTheDate();
                occForcastNotifyDTO.setRateStr(theDate2RateStr.getOrDefault(theDate, noDataMsg));
            }
        }

        /**
         * 获取未来日期的Occ数据
         *
         * @param currentZonedDateTime 当前时间
         * @param compareHour          对比时刻
         * @param numberOfDays         获取的未来天数
         * @param propertyDTO          资产DTO
         * @return java.util.List<cloud.wconnect.rateshop.pojo.dto.rateshop.occforcast.OccForcastNotifyDTO>
         * @author lichen
         * @date 2024/6/20
         */
        private List<OccForcastNotifyDTO> listOccForcast(ZonedDateTime currentZonedDateTime, int compareHour, Integer numberOfDays, PropertyDTO propertyDTO) {
            //获取国际化配置
            InternationalizationDTO internationalization = propertyDTO.getInternationalization();
            String longDateFormat = internationalization.getDateTime().getLongDate();
            InternationalizationNumberDTO numberDTO = internationalization.getNumber();
            String calculationRule = numberDTO.getCalculationRule();

            //当前时刻key(yyyyMMddHH)
            String currentKey = DateTimeUtils.parseToLong(currentZonedDateTime, BaseConstant.DATE_FORMAT_YYYYMMDDHH).toString();

            /**
             * 对比时刻key(yyyyMMddHH)
             * 对比时刻 >= 当前时刻，则对比日期是前一天；否则为当天；
             */
            String compareKey;
            if (compareHour >= currentZonedDateTime.getHour()) {
                compareKey = DateTimeUtils.parseToLong(currentZonedDateTime.minusDays(1).withHour(compareHour), BaseConstant.DATE_FORMAT_YYYYMMDDHH).toString();
            } else {
                compareKey = DateTimeUtils.parseToLong(currentZonedDateTime.withHour(compareHour), BaseConstant.DATE_FORMAT_YYYYMMDDHH).toString();
            }
            ArrayList<String> keys = Lists.newArrayList(currentKey, compareKey);

            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(BaseConstant.DATE_FORMAT_YYYYMMDD);
            long endDate = Long.parseLong(currentZonedDateTime.plusDays(numberOfDays).format(dateTimeFormatter));
            //开始时间等于当前时间减去一天的原因：当对比时刻大于当前时刻时，对比的前一天数据，所以查询的日期需要往前查一天
            long startDate = Long.parseLong(currentZonedDateTime.minusDays(1).format(dateTimeFormatter));
            //查询营业日的数据
            List<RateShopOccForecast> occForecastList = rateShopOccForecastService.listByDateRange(startDate, endDate, propertyDTO.getId());
            //key等于营业日，value等于当前时刻和对比时刻的occ数据集合
            Map<Long, List<OccForecastDTO>> theDate2OccForecastDTOList = occForecastList.stream().collect(Collectors.toMap(RateShopOccForecast::getTheDate, rateShopOccForecast ->
                    JsonUtils.convertStringToList(objectMapper, rateShopOccForecast.getValues(), OccForecastDTO.class).stream()
                            .filter(occForecastDTO -> keys.contains(occForecastDTO.getKey())).toList()
            ));

            ArrayList<OccForcastNotifyDTO> occForcastNotifyDTOS = Lists.newArrayListWithCapacity(numberOfDays);
            //开始日期 ~ 结束日期
            for (ZonedDateTime zonedDateTime = currentZonedDateTime; !zonedDateTime.isAfter(currentZonedDateTime.plusDays(numberOfDays));
                 zonedDateTime = zonedDateTime.plusDays(1)) {
                Long itemDate = Long.parseLong(zonedDateTime.format(dateTimeFormatter));

                //通知的Occ数据
                OccForcastNotifyDTO occForcastNotifyDTO = new OccForcastNotifyDTO();
                occForcastNotifyDTO.setTheDate(itemDate);
                occForcastNotifyDTO.setI18nDate(InternationalizationUtils.formatDateTime(zonedDateTime.toEpochSecond(),
                        longDateFormat, StringUtils.EMPTY, propertyDTO.getTimezone(), propertyDTO.getLanguage()));

                //营业日的occ数据集合
                List<OccForecastDTO> occForecastDTOS = theDate2OccForecastDTOList.get(itemDate);
                if (CollectionUtils.isNotEmpty(occForecastDTOS)) {
                    //按照版本分组
                    Map<String, OccForecastDTO> key2OccForecastDTO = occForecastDTOS.stream().collect(Collectors.toMap(OccForecastDTO::getKey, Function.identity()));

                    //当前时刻的pcOcc和scOcc
                    OccForecastDTO occForecastDTO = key2OccForecastDTO.get(currentKey);
                    BigDecimal pcOccNowBigDecimal = null;
                    BigDecimal scOccNowBigDecimal = null;
                    if (Objects.nonNull(occForecastDTO)) {
                        pcOccNowBigDecimal = occForecastDTO.getPcOcc();
                        scOccNowBigDecimal = occForecastDTO.getScOcc();
                    }
                    //设置pcOcc
                    String pcOccNow = Objects.nonNull(pcOccNowBigDecimal) ? InternationalizationUtils.formatViewValue(pcOccNowBigDecimal, PrecisionCons.RATE_SHOP_PRECISION, calculationRule, null) + unitStr
                            : null;
                    occForcastNotifyDTO.setPcOccNow(pcOccNow);
                    //设置scOcc
                    String scOccNow = Objects.nonNull(scOccNowBigDecimal) ? InternationalizationUtils.formatViewValue(scOccNowBigDecimal, PrecisionCons.RATE_SHOP_PRECISION, calculationRule, null) + unitStr
                            : null;
                    occForcastNotifyDTO.setScOccNow(scOccNow);

                    //比对时刻的pcOcc和scOcc
                    OccForecastDTO compareOccForecastDTO = key2OccForecastDTO.get(compareKey);
                    BigDecimal comparePcOccBigDecimal = null;
                    BigDecimal compareScOccBigDecimal = null;
                    if (Objects.nonNull(compareOccForecastDTO)) {
                        comparePcOccBigDecimal = compareOccForecastDTO.getPcOcc();
                        compareScOccBigDecimal = compareOccForecastDTO.getScOcc();
                    }
                    //设置pcOcc
                    String comparePcOcc = Objects.nonNull(comparePcOccBigDecimal) ? InternationalizationUtils.formatViewValue(comparePcOccBigDecimal, PrecisionCons.RATE_SHOP_PRECISION, calculationRule, null) + unitStr
                            : null;
                    occForcastNotifyDTO.setComparePcOcc(comparePcOcc);
                    //设置scOcc
                    String compareScOcc = Objects.nonNull(compareScOccBigDecimal) ? InternationalizationUtils.formatViewValue(compareScOccBigDecimal, PrecisionCons.RATE_SHOP_PRECISION, calculationRule, null) + unitStr
                            : null;
                    occForcastNotifyDTO.setCompareScOcc(compareScOcc);

                    //比较pcOcc
                    if (Objects.nonNull(pcOccNowBigDecimal) && Objects.nonNull(comparePcOccBigDecimal)) {
                        //计算pcOcc的差值
                        BigDecimal subtractByPcOcc = pcOccNowBigDecimal.subtract(comparePcOccBigDecimal);

                        //设置pcOcc的差值
                        occForcastNotifyDTO.setPcOccPickUp(InternationalizationUtils.formatViewValue(subtractByPcOcc, PrecisionCons.RATE_SHOP_PRECISION, calculationRule, null) + unitStr);

                        //设置pcOcc是否提高
                        occForcastNotifyDTO.setPcOccIsUp(subtractByPcOcc.compareTo(BigDecimal.ZERO) >= 0);
                    }

                    //比较scOcc
                    if (Objects.nonNull(scOccNowBigDecimal) && Objects.nonNull(compareScOccBigDecimal)) {
                        //计算scOcc的差值
                        BigDecimal subtractByScOcc = scOccNowBigDecimal.subtract(compareScOccBigDecimal);

                        //设置scOcc的差值
                        occForcastNotifyDTO.setScOccPickUp(InternationalizationUtils.formatViewValue(subtractByScOcc, PrecisionCons.RATE_SHOP_PRECISION, calculationRule, null) + unitStr);

                        //设置scOcc是否提高
                        occForcastNotifyDTO.setScOccIsUp(subtractByScOcc.compareTo(BigDecimal.ZERO) >= 0);
                    }
                }

                occForcastNotifyDTOS.add(occForcastNotifyDTO);
            }

            return occForcastNotifyDTOS;
        }

        /**
         * 查询房价
         *
         * @param zonedDateTime     当前时刻
         * @param notifyRuleJSONDTO 通知规则
         * @param propertyDTO       资产DTO
         * @return java.util.List<cloud.wconnect.rateshop.pojo.dto.rateshop.LatestHotelPriceDTO>
         * @author lichen
         * @date 2024/6/20
         */
        private List<LatestHotelPriceDTO> listRate(ZonedDateTime zonedDateTime, NotifyRuleJSONDTO notifyRuleJSONDTO, PropertyDTO propertyDTO) {
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(BaseConstant.DATE_FORMAT_YYYYMMDD);
            ZonedDateTime endZonedDateTime = zonedDateTime.plusDays(notifyRuleJSONDTO.getNumberOfDays());

            //资产的rateShop配置
            Setting setting = settingService.getByPropertyId(propertyDTO.getId());

            //房价参数配置
            List<RateConfigDTO> rateConfigDTOS = JsonUtils.convertStringToList(objectMapper, setting.getRateConfig(), RateConfigDTO.class);

            //判断资产是否配置对应的房价类型
            Set<Integer> rateTypeSets = rateConfigDTOS.stream().map(RateConfigDTO::getRateType).collect(Collectors.toSet());
            if (!rateTypeSets.contains(notifyRuleJSONDTO.getRateType())) {
                return Collections.emptyList();
            }

            //获取资产自身酒店
            PropertyHotel propertySelfHotel = propertyHotelService.getPropertySelfHotel(propertyDTO.getId());

            //构建查询条件
            LatestHotelPriceQuery latestHotelPriceQuery = new LatestHotelPriceQuery();
            latestHotelPriceQuery.setFromDate(Long.parseLong(zonedDateTime.format(dateTimeFormatter)));
            latestHotelPriceQuery.setToDate(Long.parseLong(endZonedDateTime.format(dateTimeFormatter)));
            latestHotelPriceQuery.setPlatformId(notifyRuleJSONDTO.getPlatformId());
            latestHotelPriceQuery.setDatasourceId(notifyRuleJSONDTO.getDatasourceId());
            latestHotelPriceQuery.setRoomIds(Collections.emptyList());

            if (notifyRuleJSONDTO.getRateType().equals(RateTypeEnum.BEST_AVAILABLE_RATE.getRateType())) {
                return latestBARRateService.listLowestBARHotelPrice(Collections.singletonList(propertySelfHotel.getHotelId()), setting.getCurrencyId(),
                        setting.getContainTaxFlag(), latestHotelPriceQuery, rateConfigDTOS, setting.getPos());
            } else {
                return latestRateService.listLowestEBRHotelPrice(Collections.singletonList(propertySelfHotel.getHotelId()), setting.getCurrencyId(),
                        setting.getContainTaxFlag(), latestHotelPriceQuery, rateConfigDTOS, setting.getPos());
            }
        }
    }