# RateShopWidgetServiceImpl.java

    package cloud.wconnect.rateshop.service.rateshop.impl;

    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.InternationalizationUtils;
    import cloud.wconnect.rateshop.entity.rateshop.PropertyOperation;
    import cloud.wconnect.rateshop.pojo.query.rateshop.widget.RateShopAdrWidgetQuery;
    import cloud.wconnect.rateshop.pojo.query.rateshop.widget.RateShopOccWidgetQuery;
    import cloud.wconnect.rateshop.pojo.query.rateshop.widget.RateShopRevParWidgetQuery;
    import cloud.wconnect.rateshop.pojo.vo.rateshop.widget.*;
    import cloud.wconnect.rateshop.service.rateshop.IPropertyOperationService;
    import cloud.wconnect.rateshop.service.rateshop.IRateShopWidgetService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.google.common.collect.Lists;
    import jakarta.annotation.Resource;
    import org.springframework.stereotype.Service;

    import java.math.BigDecimal;
    import java.math.RoundingMode;
    import java.time.ZoneId;
    import java.time.ZonedDateTime;
    import java.util.List;
    import java.util.Map;
    import java.util.Objects;
    import java.util.function.Function;
    import java.util.stream.Collectors;

    /**
     * @author zc
     * @date 2025/06/19
     */
    @Service
    @DS("rate_shop")
    public class RateShopWidgetServiceImpl implements IRateShopWidgetService {

        @Resource
        private IPropertyOperationService propertyOperationService;

        /**
         * 获取各资产 Occ.% 数据
         *
         * @param propertyDTOList 资产集合
         * @param query           查询条件
         * @return RateShopWidgetOccVO 集合
         * @author zc
         * @date 2025/6/19
         */
        @Override
        public List<RateShopWidgetOccVO> listOcc(List<PropertyDTO> propertyDTOList, RateShopOccWidgetQuery query) {
            List<RateShopWidgetOccVO> result = Lists.newArrayList();
            for (PropertyDTO propertyDTO : propertyDTOList) {
                String timezone = propertyDTO.getTimezone();
                ZonedDateTime startZonedDate = DateTimeUtils.strToLocalDate(query.getStartDate().toString(),
                        BaseConstant.DATE_FORMAT_YYYYMMDD).atStartOfDay(ZoneId.of(timezone));
                ZonedDateTime endZonedDate = DateTimeUtils.strToLocalDate(query.getEndDate().toString(),
                        BaseConstant.DATE_FORMAT_YYYYMMDD).atStartOfDay(ZoneId.of(timezone));
                Map<Long, PropertyOperation> targetDate2Operation = propertyOperationService
                        .list(new QueryWrapper<PropertyOperation>().lambda()
                                .eq(PropertyOperation::getPropertyId, propertyDTO.getId())
                                .between(PropertyOperation::getTargetDate, startZonedDate.toEpochSecond(),
                                        endZonedDate.toEpochSecond())).stream()
                        .collect(Collectors.toMap(PropertyOperation::getTargetDate, Function.identity()));
                List<RateShopWidgetOccValueVO> occValues = Lists.newArrayList();
                for (ZonedDateTime date = startZonedDate; !date.isAfter(endZonedDate); date = date.plusDays(1)) {
                    long targetDate = date.toEpochSecond();
                    PropertyOperation operation = targetDate2Operation.getOrDefault(targetDate, new PropertyOperation());
                    RateShopWidgetOccValueVO occValueVO = new RateShopWidgetOccValueVO();
                    occValueVO.setDate(DateTimeUtils.timestampToStr(targetDate,
                            BaseConstant.DATE_FORMAT_YYYY_MM_DD, timezone));
                    occValueVO.setOcc((RateShopRevParWidgetQuery.PC_OCC_TYPE == query.getType()) ?
                            operation.getPcOcc() : operation.getScOcc());

                    occValues.add(occValueVO);
                }
                RateShopWidgetOccVO occVO = new RateShopWidgetOccVO();
                occVO.setPropertyId(propertyDTO.getId());
                occVO.setPropertyName(propertyDTO.getAbbr());
                occVO.setValues(occValues);

                result.add(occVO);
            }
            return result;
        }

        /**
         * 获取各资产 Adr 数据
         *
         * @param propertyDTOList 资产集合
         * @param query           查询条件
         * @return RateShopWidgetAdrVO 集合
         * @author zc
         * @date 2025/6/19
         */
        @Override
        public List<RateShopWidgetAdrVO> listAdr(List<PropertyDTO> propertyDTOList, RateShopAdrWidgetQuery query) {
            List<RateShopWidgetAdrVO> result = Lists.newArrayList();
            for (PropertyDTO propertyDTO : propertyDTOList) {
                String timezone = propertyDTO.getTimezone();
                ZonedDateTime startZonedDate = DateTimeUtils.strToLocalDate(query.getStartDate().toString(),
                        BaseConstant.DATE_FORMAT_YYYYMMDD).atStartOfDay(ZoneId.of(timezone));
                ZonedDateTime endZonedDate = DateTimeUtils.strToLocalDate(query.getEndDate().toString(),
                        BaseConstant.DATE_FORMAT_YYYYMMDD).atStartOfDay(ZoneId.of(timezone));
                Map<Long, PropertyOperation> targetDate2Operation = propertyOperationService
                        .list(new QueryWrapper<PropertyOperation>().lambda()
                                .eq(PropertyOperation::getPropertyId, propertyDTO.getId())
                                .between(PropertyOperation::getTargetDate, startZonedDate.toEpochSecond(),
                                        endZonedDate.toEpochSecond())).stream()
                        .collect(Collectors.toMap(PropertyOperation::getTargetDate, Function.identity()));
                List<RateShopWidgetAdrValueVO> adrValues = Lists.newArrayList();
                for (ZonedDateTime date = startZonedDate; !date.isAfter(endZonedDate); date = date.plusDays(1)) {
                    long targetDate = date.toEpochSecond();
                    PropertyOperation operation = targetDate2Operation.getOrDefault(targetDate, new PropertyOperation());

                    RateShopWidgetAdrValueVO adrValueVO = new RateShopWidgetAdrValueVO();
                    adrValueVO.setDate(DateTimeUtils.timestampToStr(targetDate,
                            BaseConstant.DATE_FORMAT_YYYY_MM_DD, timezone));
                    adrValueVO.setAdr(operation.getAdr());

                    adrValues.add(adrValueVO);
                }
                RateShopWidgetAdrVO adrVO = new RateShopWidgetAdrVO();
                adrVO.setPropertyId(propertyDTO.getId());
                adrVO.setPropertyName(propertyDTO.getAbbr());
                adrVO.setValues(adrValues);

                result.add(adrVO);
            }
            return result;
        }

        /**
         * 获取各资产 Rev.Par 数据
         *
         * @param propertyDTOList 资产集合
         * @param query           查询条件
         * @return RateShopWidgetRevParVO 集合
         * @author zc
         * @date 2025/6/19
         */
        @Override
        public List<RateShopWidgetRevParVO> listRevPar(List<PropertyDTO> propertyDTOList, RateShopRevParWidgetQuery query) {
            List<RateShopWidgetRevParVO> result = Lists.newArrayList();
            for (PropertyDTO propertyDTO : propertyDTOList) {
                String timezone = propertyDTO.getTimezone();
                ZonedDateTime startZonedDate = DateTimeUtils.strToLocalDate(query.getStartDate().toString(),
                        BaseConstant.DATE_FORMAT_YYYYMMDD).atStartOfDay(ZoneId.of(timezone));
                ZonedDateTime endZonedDate = DateTimeUtils.strToLocalDate(query.getEndDate().toString(),
                        BaseConstant.DATE_FORMAT_YYYYMMDD).atStartOfDay(ZoneId.of(timezone));
                Map<Long, PropertyOperation> targetDate2Operation = propertyOperationService
                        .list(new QueryWrapper<PropertyOperation>().lambda()
                                .eq(PropertyOperation::getPropertyId, propertyDTO.getId())
                                .between(PropertyOperation::getTargetDate, startZonedDate.toEpochSecond(),
                                        endZonedDate.toEpochSecond())).stream()
                        .collect(Collectors.toMap(PropertyOperation::getTargetDate, Function.identity()));

                RoundingMode roundingMode = InternationalizationUtils.getRoundingMode(propertyDTO
                        .getInternationalization().getNumber().getCalculationRule());

                List<RateShopWidgetRevParValueVO> revParValues = Lists.newArrayList();
                for (ZonedDateTime date = startZonedDate; !date.isAfter(endZonedDate); date = date.plusDays(1)) {
                    long targetDate = date.toEpochSecond();

                    RateShopWidgetRevParValueVO revParValueVO = new RateShopWidgetRevParValueVO();
                    revParValueVO.setDate(DateTimeUtils.timestampToStr(targetDate,
                            BaseConstant.DATE_FORMAT_YYYY_MM_DD, timezone));

                    PropertyOperation operation = targetDate2Operation.getOrDefault(targetDate, new PropertyOperation());
                    BigDecimal occ = (RateShopRevParWidgetQuery.PC_OCC_TYPE == query.getType()) ?
                            operation.getPcOcc() : operation.getScOcc();
                    revParValueVO.setRevPar((Objects.nonNull(operation.getAdr()) && Objects.nonNull(occ)) ?
                            new BigDecimal(operation.getAdr().toString())
                                    .multiply(new BigDecimal(occ.toString()))
                                    .divide(new BigDecimal("100"), BaseConstant.DATA_PRECISION, roundingMode) : null);

                    revParValues.add(revParValueVO);
                }
                RateShopWidgetRevParVO revParVO = new RateShopWidgetRevParVO();
                revParVO.setPropertyId(propertyDTO.getId());
                revParVO.setPropertyName(propertyDTO.getAbbr());
                revParVO.setValues(revParValues);

                result.add(revParVO);
            }
            return result;
        }
    }