# PropertyHotelServiceImpl.java

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

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.CommonErrorI18nConstant;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.rateshop.cons.rateshop.HotelTypeEnum;
    import cloud.wconnect.rateshop.cons.rateshop.RateShopCons;
    import cloud.wconnect.rateshop.cons.rateshop.RateShopErrorI18nConstant;
    import cloud.wconnect.rateshop.entity.rateshop.Hotel;
    import cloud.wconnect.rateshop.entity.rateshop.PropertyHotel;
    import cloud.wconnect.rateshop.mapper.rateshop.PropertyHotelMapper;
    import cloud.wconnect.rateshop.pojo.dto.rateshop.hotel.PropertyHotelDTO;
    import cloud.wconnect.rateshop.pojo.dto.revenue.HotelDTO;
    import cloud.wconnect.rateshop.service.rateshop.IHotelService;
    import cloud.wconnect.rateshop.service.rateshop.IPropertyHotelService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import org.apache.commons.collections.CollectionUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Lazy;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.text.MessageFormat;
    import java.util.*;
    import java.util.function.Function;
    import java.util.stream.Collectors;

    /**
     * <p>
     * 服务实现类
     * </p>
     *
     * @author lichen
     * @since 2023-06-07
     */
    @DS("rate_shop")
    @Service
    public class PropertyHotelServiceImpl extends ServiceImpl<PropertyHotelMapper, PropertyHotel> implements IPropertyHotelService {

        @Autowired
        @Lazy
        private IHotelService hotelService;
        @Autowired
        private BeanMapper beanMapper;

        /**
         * 校验酒店是否和资产有关系
         *
         * @param hotelId    酒店id
         * @param propertyId 资产id
         * @return cloud.wconnect.rateshop.entity.rateshop.PropertyHotel
         * @author lichen
         * @date 2023/6/9
         */
        @Override
        public PropertyHotel checkAffiliation(Integer hotelId, Integer propertyId) {
            PropertyHotel propertyHotel = getOne(new LambdaQueryWrapper<PropertyHotel>()
                    .eq(PropertyHotel::getPropertyId, propertyId)
                    .eq(PropertyHotel::getHotelId, hotelId));
            if (Objects.isNull(propertyHotel)) {
                throw new BadRequestException(RateShopErrorI18nConstant.HOTEL_NOT_BELONG_PROPERTY,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "Hotel not belong to property; hotelId: " + hotelId + ",propertyId: " + propertyId);
            }
            return propertyHotel;
        }

        /**
         * 校验酒店是否和资产有关系
         *
         * @param hotelIds   酒店 id
         * @param propertyId 资产 id
         * @author yyt
         * @date 2024/4/9
         **/
        @Override
        public void checkAffiliation(List<Integer> hotelIds, Integer propertyId) {
            List<PropertyHotel> propertyHotels = list(new LambdaQueryWrapper<PropertyHotel>()
                    .eq(PropertyHotel::getPropertyId, propertyId)
                    .in(PropertyHotel::getHotelId, hotelIds));
            if (propertyHotels.size() != hotelIds.size()) {
                throw new BadRequestException(RateShopErrorI18nConstant.HOTEL_NOT_BELONG_PROPERTY,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "Hotel not belong to property; hotelIds: " + hotelIds + ",propertyId: " + propertyId);
            }
        }

        /**
         * 查询资产配置的酒店集合
         *
         * @param propertyIds 资产id集合
         * @return java.util.List<cloud.wconnect.rateshop.pojo.dto.hotel.PropertyHotelDTO>
         * @author lichen
         * @date 2023/6/10
         */
        @Override
        public List<PropertyHotelDTO> listByPropertyIds(List<Integer> propertyIds) {
            //查询资产配置的酒店集合
            List<PropertyHotel> propertyHotels = list(new LambdaQueryWrapper<PropertyHotel>().in(PropertyHotel::getPropertyId, propertyIds));
            if (CollectionUtils.isEmpty(propertyHotels)) return Collections.emptyList();

            return packagePropertyHotelDTO(propertyHotels);
        }

        /**
         * 查询资产配置的酒店集合，并排序
         *
         * @param propertyId 资产id
         * @return 酒店集合
         * @author yyt
         * @date 2023/6/10
         */
        @Override
        public List<PropertyHotelDTO> listSortDTOByPropertyId(Integer propertyId) {
            //查询资产配置的酒店集合
            List<PropertyHotel> propertyHotels = list(new LambdaQueryWrapper<PropertyHotel>().eq(PropertyHotel::getPropertyId, propertyId)
                    .orderByAsc(PropertyHotel::getSort));
            if (CollectionUtils.isEmpty(propertyHotels)) return Collections.emptyList();

            return packagePropertyHotelDTO(propertyHotels);
        }

        /**
         * 封装 PropertyHotelDTO
         *
         * @param propertyHotels 资产酒店关联关系
         * @return PropertyHotelDTO
         * @author yyt
         * @date 2024/4/9
         **/
        private List<PropertyHotelDTO> packagePropertyHotelDTO(List<PropertyHotel> propertyHotels) {
            //查询酒店集合
            Set<Integer> hotelIds = propertyHotels.stream().map(PropertyHotel::getHotelId).collect(Collectors.toSet());
            List<Hotel> hotels = hotelService.listByIds(hotelIds);
            Map<Integer, Hotel> hotelId2Hotel = hotels.stream().collect(Collectors.toMap(Hotel::getId, Function.identity()));

            //List<PropertyHotel> -> List<PropertyHotelDTO>
            return beanMapper.mapList(propertyHotels, PropertyHotelDTO.class, (entity, dto) -> {
                Hotel hotel = hotelId2Hotel.get(dto.getHotelId());
                // 默认显示 酒店别名，没有设置别名时，显示酒店全名
                dto.setName(StringUtils.isEmpty(entity.getAliasName()) ? hotel.getName() : entity.getAliasName());
                // 设置酒店的采集URL
                dto.setUrls(hotel.getUrls());
            });
        }

        /**
         * 根据 资产 、酒店，查询 资产、酒店关联关系
         *
         * @param propertyId 资产 id
         * @param hotelIds   酒店
         * @return 资产、酒店关联关系
         * @author yyt
         * @date 2024/3/27
         **/
        @Override
        public List<PropertyHotel> listByPropertyIdAndHotelIds(Integer propertyId, List<Integer> hotelIds) {
            return list(new QueryWrapper<PropertyHotel>().lambda()
                    .eq(PropertyHotel::getPropertyId, propertyId)
                    .in(Objects.nonNull(hotelIds), PropertyHotel::getHotelId, hotelIds));
        }

        /**
         * 根据酒店ID、币种、销售地区查询酒店关联的资产信息
         *
         * @param hotelId    酒店ID
         * @param currencyId 币种ID
         * @param pos        销售地区
         * @return java.util.List<cloud.wconnect.rateshop.entity.rateshop.PropertyHotel>
         * @author lichen
         * @date 2024/3/25
         */
        @Override
        public List<PropertyHotel> getByHotelIdAndCurrencyIdAndPos(Integer hotelId, Integer currencyId, String pos) {
            return list(new LambdaQueryWrapper<PropertyHotel>()
                    .eq(PropertyHotel::getHotelId, hotelId)
                    .eq(PropertyHotel::getCurrencyId, currencyId)
                    .eq(PropertyHotel::getPos, pos));
        }

        /**
         * 校验酒店是否资产自身酒店
         *
         * @param propertyId 资产ID
         * @param hotelId    酒店ID
         * @return void
         * @author lichen
         * @date 2024/3/26
         */
        @Override
        public void checkPropertySelfHotel(Integer propertyId, Integer hotelId) {
            PropertyHotel propertyHotel = getOne(new LambdaQueryWrapper<PropertyHotel>()
                    .eq(PropertyHotel::getPropertyId, propertyId)
                    .eq(PropertyHotel::getHotelId, hotelId)
                    .eq(PropertyHotel::getType, HotelTypeEnum.OWN.getType()));
            if (Objects.isNull(propertyHotel)) {
                throw new BadRequestException(RateShopErrorI18nConstant.HOTEL_NOT_SELF_HOTEL,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        MessageFormat.format("The hotel is not the property itself; propertyId:{0},hotelId:{1}",
                                propertyId, hotelId));
            }
        }

        /**
         * 获取资产自身酒店
         *
         * @param propertyId 资产ID
         * @return cloud.wconnect.rateshop.entity.rateshop.PropertyHotel
         * @author lichen
         * @date 2024/3/28
         */
        @Override
        public PropertyHotel getPropertySelfHotel(Integer propertyId) {
            return getOne(new LambdaQueryWrapper<PropertyHotel>()
                    .eq(PropertyHotel::getPropertyId, propertyId)
                    .eq(PropertyHotel::getType, HotelTypeEnum.OWN.getType()));
        }

        /**
         * 查询酒店在指定币种指定销售地区的关联关系
         *
         * @param hotelIds   酒店 id
         * @param currencyId 币种ID
         * @param pos        销售地区
         * @return 资产、酒店关联关系
         * @author yyt
         * @date 2024/4/4
         **/
        @Override
        public List<PropertyHotel> listByHotelIdsAndCurrencyId(Collection<Integer> hotelIds, Integer currencyId, String pos) {
            return list(new QueryWrapper<PropertyHotel>().lambda()
                    .in(PropertyHotel::getHotelId, hotelIds)
                    .eq(PropertyHotel::getCurrencyId, currencyId)
                    .eq(PropertyHotel::getPos, pos));
        }

        /**
         * 查询资产、酒店关联关系，并排序
         *
         * @param propertyId 资产 id
         * @return 资产、酒店关联关系
         * @author yyt
         * @date 2024/4/9
         **/
        @Override
        public List<PropertyHotel> listSortByPropertyId(Integer propertyId) {
            return list(new QueryWrapper<PropertyHotel>().lambda().eq(PropertyHotel::getPropertyId, propertyId)
                    .orderByAsc(PropertyHotel::getSort));
        }

        /**
         * 修改酒店信息
         *
         * @param propertyId 资产 id
         * @param hotels     酒店 id
         * @author yyt
         * @date 2024/4/9
         **/
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void update(Integer propertyId, List<HotelDTO> hotels) {
            baseMapper.updateBatch(hotels.stream()
                    .map(item -> new PropertyHotel().setPropertyId(propertyId).setHotelId(item.getHotelId())
                            .setAliasName(item.getAliasName()).setSort(item.getSort()))
                    .collect(Collectors.toList()));
        }

        /**
         * 获取酒店作为自身对应的资产ID
         *
         * @param hotelId 酒店ID
         * @return java.lang.Integer
         * @author lichen
         * @date 2025/4/2
         */
        @Override
        public Integer getPropertyIdBySelfHotelId(Integer hotelId) {
            PropertyHotel propertyHotel = getOne(new LambdaQueryWrapper<PropertyHotel>()
                    .eq(PropertyHotel::getHotelId, hotelId)
                    .eq(PropertyHotel::getType, HotelTypeEnum.OWN.getType()));
            if (Objects.nonNull(propertyHotel)) {
                return propertyHotel.getPropertyId();
            }
            return null;
        }

        /**
         * 查询资产配置的酒店DTO
         *
         * @param propertyId 资产id
         * @return java.util.List<cloud.wconnect.rateshop.pojo.dto.revenue.HotelDTO>
         * @author lichen
         * @date 2025/5/16
         */
        @Override
        public List<HotelDTO> listHotelDTOByPropertyId(Integer propertyId) {
            //排序查询资产配置的酒店集合
            List<PropertyHotel> propertyHotels = listSortByPropertyId(propertyId);
            if (CollectionUtils.isEmpty(propertyHotels)) {
                return Collections.emptyList();
            }

            //查询酒店信息
            Map<Integer, String> hotelNameById = hotelService.listByIds(propertyHotels.stream().map(PropertyHotel::getHotelId).toList())
                    .stream().collect(Collectors.toMap(Hotel::getId, Hotel::getName));

            return propertyHotels.stream().map(item -> {
                HotelDTO hotel = beanMapper.map(item, HotelDTO.class);
                hotel.setHotelName(hotelNameById.get(item.getHotelId()));
                return hotel;
            }).toList();
        }

    }