# RevenueRoomTypeRoomsServiceImpl.java

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

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.rateshop.entity.revenue.RevenueRoomTypeRooms;
    import cloud.wconnect.rateshop.mapper.revenue.RevenueRoomTypeRoomsMapper;
    import cloud.wconnect.rateshop.pojo.bo.revenue.RoomTypeRoomsBO;
    import cloud.wconnect.rateshop.pojo.dto.revenue.RoomTypeRoomsDTO;
    import cloud.wconnect.rateshop.pojo.vo.revenue.RoomTypeRoomVO;
    import cloud.wconnect.rateshop.service.revenue.IRevenueRoomTypeRoomsService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.google.common.collect.Lists;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;

    /**
     * <p>
     * 不同房型的可用房间数 服务实现类
     * </p>
     *
     * @author yyt
     * @since 2025-02-11
     */
    @Service
    @DS("rate_shop")
    public class RevenueRoomTypeRoomsServiceImpl extends ServiceImpl<RevenueRoomTypeRoomsMapper, RevenueRoomTypeRooms> implements IRevenueRoomTypeRoomsService {

        @Autowired
        private BeanMapper beanMapper;

        /**
         * 获取不同房型的房间数
         *
         * @param propertyId 资产 id
         * @param date       指定日期
         * @return 房间数
         * @author yyt
         * @date 2025/2/11
         **/
        @Override
        public List<RevenueRoomTypeRooms> list(Integer propertyId, long date) {
            List<RevenueRoomTypeRooms> list = list(new QueryWrapper<RevenueRoomTypeRooms>().lambda()
                    .eq(RevenueRoomTypeRooms::getPropertyId, propertyId)
                    .eq(RevenueRoomTypeRooms::getTheDate, date));

            // total 排在第一位
            int targetIndex = -1;
            for (int i = 0; i < list.size(); i++) {
                if (list.get(i).getRoomType().equalsIgnoreCase("total")) {
                    targetIndex = i;
                    break;
                }
            }
            if (targetIndex != -1) {
                // 两元素位置交换
                Collections.swap(list, 0, targetIndex);
            }
            return list;
        }

        /**
         * 获取不同房型的房间数
         *
         * @param propertyId 资产 id
         * @param date       指定日期
         * @return 房间数
         * @author yyt
         * @date 2025/2/11
         **/
        @Override
        public List<RoomTypeRoomsDTO> listDTO(Integer propertyId, long date) {
            return beanMapper.mapList(list(propertyId, date), RoomTypeRoomsDTO.class);
        }

        /**
         * 保存不同房型的房间数
         *
         * @param propertyId           资产 id
         * @param date                 指定日期
         * @param roomTypeRoomsDTOList 房间数
         * @param userId               操作人
         * @author yyt
         * @date 2025/2/11
         **/
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void save(Integer propertyId, long date, List<RoomTypeRoomsDTO> roomTypeRoomsDTOList, int userId) {
            long now = DateTimeUtils.nowTimestamp();
            baseMapper.saveOrUpdateBatch(roomTypeRoomsDTOList.stream().map(roomTypeRoomsDTO -> {
                RevenueRoomTypeRooms revenueRoomTypeRooms = beanMapper.map(roomTypeRoomsDTO, RevenueRoomTypeRooms.class);
                revenueRoomTypeRooms.setPropertyId(propertyId);
                revenueRoomTypeRooms.setTheDate(date);
                revenueRoomTypeRooms.setUpdatedBy(userId);
                revenueRoomTypeRooms.setUpdatedTime(now);
                return revenueRoomTypeRooms;
            }).sorted(Comparator.comparing(RevenueRoomTypeRooms::getTheDate).thenComparing(RevenueRoomTypeRooms::getTargetDate)
                    .thenComparing(RevenueRoomTypeRooms::getRoomType)).toList());
        }

        /**
         * 获取不同房型的房间数
         *
         * @param propertyDTO 资产
         * @param theDate     指定日期
         * @return 房间数
         * @author yyt
         * @date 2025/2/11
         **/
        @Override
        public List<RoomTypeRoomVO> listRoomTypeRooms(PropertyDTO propertyDTO, Long theDate) {
            List<RevenueRoomTypeRooms> roomTypeRooms = list(propertyDTO.getId(), theDate);
            if (CollectionUtils.isEmpty(roomTypeRooms)) return null;

            List<RoomTypeRoomVO> roomTypeRoomVOs = Lists.newArrayListWithExpectedSize(14);

            // 未来14天 所有的房型
            List<String> allRoomTypes = roomTypeRooms.stream().map(RevenueRoomTypeRooms::getRoomType).distinct().toList();

            // 未来14天
            String timezone = propertyDTO.getTimezone();
            List<Long> next14Days = DateTimeUtils.listNextDays(DateTimeUtils.toZonedDateTime(theDate, timezone), 14);

            // 房间数以房型分组
            Map<String, Map<Long, RevenueRoomTypeRooms>> roomsByRoomType = roomTypeRooms.stream().collect(Collectors.groupingBy(RevenueRoomTypeRooms::getRoomType,
                    Collectors.toMap(RevenueRoomTypeRooms::getTargetDate, v-> v)));

            // 循环设置每个房型 未来14天的房间数
            for (String roomType : allRoomTypes) {
                RoomTypeRoomVO roomTypeRoomVO = new RoomTypeRoomVO();
                roomTypeRoomVO.setRoomType(roomType);

                Map<Long, RevenueRoomTypeRooms> roomsByDate = roomsByRoomType.getOrDefault(roomType, Collections.emptyMap());
                roomTypeRoomVO.setRooms(next14Days.stream().map(date -> roomsByDate.getOrDefault(date, new RevenueRoomTypeRooms()).getRooms()).toList());
                roomTypeRoomVOs.add(roomTypeRoomVO);
            }

            return roomTypeRoomVOs;
        }

        /**
         * 保存不同房型的房间数
         *
         * @param propertyDTO      资产
         * @param theDate          指定日期
         * @param roomTypeRoomsBOS 不同房型的房间数
         * @param userId           操作人
         * @author yyt
         * @date 2025/2/12
         **/
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void save(PropertyDTO propertyDTO, Long theDate, List<RoomTypeRoomsBO> roomTypeRoomsBOS, Integer userId) {
            Integer propertyId = propertyDTO.getId();

            // 先清除，再保存
            remove(new QueryWrapper<RevenueRoomTypeRooms>().lambda()
                    .eq(RevenueRoomTypeRooms::getPropertyId, propertyId)
                    .eq(RevenueRoomTypeRooms::getTheDate, theDate));

            if (CollectionUtils.isNotEmpty(roomTypeRoomsBOS)) {
                long now = DateTimeUtils.nowTimestamp();
                baseMapper.saveOrUpdateBatch(roomTypeRoomsBOS.stream().map(roomTypeRoomsBO -> {
                    RevenueRoomTypeRooms revenueRoomTypeRooms = beanMapper.map(roomTypeRoomsBO, RevenueRoomTypeRooms.class);
                    revenueRoomTypeRooms.setPropertyId(propertyId);
                    revenueRoomTypeRooms.setTheDate(theDate);
                    revenueRoomTypeRooms.setUpdatedBy(userId);
                    revenueRoomTypeRooms.setUpdatedTime(now);
                    return revenueRoomTypeRooms;
                }).sorted(Comparator.comparing(RevenueRoomTypeRooms::getTheDate).thenComparing(RevenueRoomTypeRooms::getTargetDate)
                        .thenComparing(RevenueRoomTypeRooms::getRoomType)).toList());
            }
        }

    }