# RevenueDailySummaryController.java

    package cloud.wconnect.rateshop.controller.revenue;

    import cloud.wconnect.commonlib.annotation.ApiId;
    import cloud.wconnect.commonlib.component.SessionContext;
    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.CommonErrorI18nConstant;
    import cloud.wconnect.commonlib.cons.CommonFieldI18nConstant;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.service.PropertyInternalService;
    import cloud.wconnect.commonlib.service.UserInternalService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.rateshop.cons.rateshop.RateShopFieldI18nConstant;
    import cloud.wconnect.rateshop.cons.revenue.DailyRevenueUpdateFieldEnum;
    import cloud.wconnect.rateshop.entity.rateshop.Hotel;
    import cloud.wconnect.rateshop.pojo.dto.revenue.DailySummaryDTO;
    import cloud.wconnect.rateshop.pojo.query.revenue.HourHotelPriceQuery;
    import cloud.wconnect.rateshop.pojo.vo.revenue.DailySummaryHotelPriceVO;
    import cloud.wconnect.rateshop.pojo.vo.revenue.DailySummaryVO;
    import cloud.wconnect.rateshop.service.rateshop.IHotelService;
    import cloud.wconnect.rateshop.service.rateshop.IPropertyHotelService;
    import cloud.wconnect.rateshop.service.revenue.IRevenueDailySummaryService;
    import com.google.common.collect.Sets;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.util.Assert;
    import org.springframework.web.bind.annotation.*;

    import jakarta.validation.Valid;

    import java.util.*;
    import java.util.stream.Stream;

    /**
     * Revenue Daily Summary 控制层
     *
     * @author lichen
     * @date 2024/3/26
     */
    @RestController
    @RequestMapping("/revenue")
    public class RevenueDailySummaryController {

        @Autowired
        private SessionContext sessionContext;
        @Autowired
        private IHotelService hotelService;
        @Autowired
        private IPropertyHotelService propertyHotelService;
        @Autowired
        private IRevenueDailySummaryService dailySummaryService;
        @Autowired
        private PropertyInternalService propertyInternalService;
        @Autowired
        private UserInternalService userInternalService;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;

        /**
         * 指定日期的目标酒店当日BAR房价信息
         *
         * @param property 资产
         * @param date     日期
         * @param symbol   酒店标识
         * @return java.util.List<cloud.wconnect.rateshop.pojo.vo.revenue.DailySummaryVO>
         * @author lichen
         * @date 2024/3/26
         */
        @ApiId(1105)
        @GetMapping("/{date}/hotel/{symbol}/bar-rate/current-day")
        public List<DailySummaryHotelPriceVO> listDailySummaryBrandHotelPrice(String property, @PathVariable String date, @PathVariable String symbol,
                                                                              @Valid HourHotelPriceQuery hourHotelPriceQuery) {
            //校验日期格式
            isValidDateFormat(date);
            //资产
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyInternalService.getOne(propertyId);
            //校验酒店是否存在 且 状态正常
            Hotel hotel = hotelService.checkHotel(symbol);
            //校验酒店是否资产自身酒店
            propertyHotelService.checkPropertySelfHotel(propertyId, hotel.getId());
            //目标日期
            Integer targetDate = Integer.valueOf(date.replace("-", ""));
            //查询房价
            List<DailySummaryHotelPriceVO> dailySummaryHotelPriceVOS = dailySummaryService.listPropertySelfHourBARRate(targetDate, propertyDTO, hotel, hourHotelPriceQuery);

            //查询用户名称
            List<Integer> updateIds = dailySummaryHotelPriceVOS.stream().map(DailySummaryHotelPriceVO::getUpdateId).toList();
            Map<Integer, String> userId2Name = userInternalService.getNameMapByIds(propertyDTO.getTenantId(), updateIds);
            //设置用户名称
            dailySummaryHotelPriceVOS.forEach(item -> item.setUpdateName(userId2Name.get(item.getUpdateId())));
            return dailySummaryHotelPriceVOS;
        }

        /**
         * 查询每小时的汇总信息
         *
         * @param property 资产标识
         * @param date     查询日期
         * @return java.util.List<cloud.wconnect.rateshop.pojo.vo.revenue.HourSummaryVO>
         * @author lichen
         * @date 2024/3/26
         */
        @ApiId(1118)
        @GetMapping("/daily-summary/{date}")
        public List<DailySummaryVO> listDailySummary(String property, @PathVariable String date) {
            //校验日期格式
            isValidDateFormat(date);
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            //转化成时间戳
            long targetDate = DateTimeUtils.dateStrToEpochSecond(date, BaseConstant.DATE_FORMAT_YYYY_MM_DD, propertyDTO.getTimezone());

            List<DailySummaryVO> dailySummaryVOS = dailySummaryService.listDailySummary(propertyDTO, targetDate);
            //更新人集合
            List<Integer> updateIds = dailySummaryVOS.stream()
                    .flatMap(item -> Stream.of(item.getRoomsAvailableUpdateId(), item.getTotalRoomsSoldUpdateId(),
                            item.getTaUpdateId(), item.getOccUpdateId(), item.getTransientPickUpUpdateId(),
                            item.getGroupPickUpUpdateId(), item.getOooRoomsUpdateId(), item.getNoShowUpdateId(),
                            item.getCancelledUpdateId(), item.getAdrUpdateId(), item.getMepsGroupTotalUpdateId()))
                    .filter(Objects::nonNull).toList();
            Map<Integer, String> userId2Name = userInternalService.getNameMapByIds(propertyDTO.getTenantId(), updateIds);
            //设置用户名称
            dailySummaryVOS.forEach(dailySummaryVO -> {
                dailySummaryVO.setRoomsAvailableUpdateName(userId2Name.get(dailySummaryVO.getRoomsAvailableUpdateId()));
                dailySummaryVO.setTotalRoomsSoldUpdateName(userId2Name.get(dailySummaryVO.getTotalRoomsSoldUpdateId()));
                dailySummaryVO.setTaUpdateName(userId2Name.get(dailySummaryVO.getTaUpdateId()));
                dailySummaryVO.setOccUpdateName(userId2Name.get(dailySummaryVO.getOccUpdateId()));
                dailySummaryVO.setTransientPickUpUpdateName(userId2Name.get(dailySummaryVO.getTransientPickUpUpdateId()));
                dailySummaryVO.setGroupPickUpUpdateName(userId2Name.get(dailySummaryVO.getGroupPickUpUpdateId()));
                dailySummaryVO.setOooRoomsUpdateName(userId2Name.get(dailySummaryVO.getOooRoomsUpdateId()));
                dailySummaryVO.setNoShowUpdateName(userId2Name.get(dailySummaryVO.getNoShowUpdateId()));
                dailySummaryVO.setCancelledUpdateName(userId2Name.get(dailySummaryVO.getCancelledUpdateId()));
                dailySummaryVO.setAdrUpdateName(userId2Name.get(dailySummaryVO.getAdrUpdateId()));
                dailySummaryVO.setMepsGroupTotalUpdateName(userId2Name.get(dailySummaryVO.getMepsGroupTotalUpdateId()));
            });
            return dailySummaryVOS;
        }

        /**
         * 手动编辑Daily Summary信息
         *
         * @param property 资产
         * @param date     日期yyyy-MM-dd
         * @param hour     小时数
         * @return java.util.Map
         * @author lichen
         * @date 2024/3/27
         */
        @ApiId(1106)
        @PutMapping("/{date}/daily-summary/{hour:\\d+}")
        public Map manualSave(String property, @PathVariable String date, @PathVariable Integer hour,
                              @Valid @RequestBody DailySummaryDTO dailySummaryDTO) {
            List<Integer> updateFieldList = Arrays.stream(dailySummaryDTO.getUpdateFields().split(",")).map(Integer::valueOf).toList();
            //校验更新的字段不能重复
            if (updateFieldList.size() != Sets.newHashSet(updateFieldList).size()) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_CANNOT_REPEAT,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("updateFieldList"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The updateFields cannot repeat; updateFieldList: " + updateFieldList);
            }
            //校验更新的字段ID是否正确
            DailyRevenueUpdateFieldEnum.checkValid(updateFieldList);

            //房价非空时，平台ID也非空
            if (updateFieldList.contains(DailyRevenueUpdateFieldEnum.PRICE.getFieldId())
                    && Objects.nonNull(dailySummaryDTO.getPrice()) && Objects.isNull(dailySummaryDTO.getPlatformId())) {
                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_EMPTY,
                        i18nMessageUtils.getErrorParamMapNeedTranslate(RateShopFieldI18nConstant.PLATFORM),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The platformId cannot be null when update price; updateFieldList: " + updateFieldList);
            }

            //校验日期格式
            isValidDateFormat(date);
            //校验小时数
            Assert.isTrue(hour >= 0 && hour <= 24, "hour must between in [0~24]");
            //资产
            int propertyId = sessionContext.getPropertyId(property);
            PropertyDTO propertyDTO = propertyI18nRedisService.get(propertyId);
            //手动维护Daily Summary运营参数
            dailySummaryService.manualSave(propertyDTO, date, hour, dailySummaryDTO, sessionContext.getLoginUserId());
            return Collections.emptyMap();
        }

        /**
         * 校验日期格式是否正确
         *
         * @param date 日期字符串
         * @return void
         * @author lichen
         * @date 2024/3/26
         */
        private void isValidDateFormat(String date) {
            // 定义日期格式的正则表达式
            String regex = "\\d{4}-\\d{2}-\\d{2}";
            if (!date.matches(regex)) {
                LinkedHashMap<String, Boolean> map = new LinkedHashMap<>();
                map.put(CommonFieldI18nConstant.DATE, true);
                map.put(BaseConstant.DATE_FORMAT_YYYY_MM_DD, false);
                throw new BadRequestException(CommonErrorI18nConstant.FORMAT_ERROR,
                        i18nMessageUtils.getErrorParamMap(map),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The date format error, date:" + date);
            }
        }

    }