package com.mgm.mcrm.roomcalendar.services; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.mgm.mcrm.basesetting.property.models.CfgProperties; import com.mgm.mcrm.basesetting.property.repositories.PropertyDao; import com.mgm.mcrm.basesetting.room.models.CfgRooms; import com.mgm.mcrm.basesetting.room.repositories.RoomDao; import com.mgm.mcrm.common.dtos.http_util.HttpResponseResult; import com.mgm.mcrm.common.services.MGMEsbApiService; import com.mgm.mcrm.roomcalendar.dtos.RoomCalendarQualification; import com.mgm.mcrm.roomcalendar.dtos.response.GetPropertyRoomTypeListResponse; import com.mgm.mcrm.roomcalendar.dtos.response.GetPropertyRoomTypeResponse; import com.mgm.mcrm.roomcalendar.dtos.response.RoomCalendarApiResponse; import com.mgm.mcrm.roomcalendar.dtos.response.RoomType; import com.mgm.mcrm.roomcalendar.repositories.RoomCalendarRoomProjection; import jakarta.annotation.Resource; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import java.util.*; @Service public class RoomCalendarService { @org.springframework.beans.factory.annotation.Value("${calendar.data-mock-enabled:false}") private boolean calendarDataMockEnabled; @Resource private MGMEsbApiService mgmEsbApiService; @Resource private PropertyDao propertyDao; @Resource private RoomDao roomDao; public RoomCalendarApiResponse> getRoomCalendar(Map params) throws Exception { RoomCalendarApiResponse> result = new RoomCalendarApiResponse<>(); String playerId; String property; String roomType; String startDate; String endDate; try { playerId = getOptionalString(params, "playerId", "PlayerId"); property = getRequiredString(params, "property", "Property"); roomType = getRequiredString(params, "roomType", "RoomType"); startDate = getRequiredString(params, "startDate", "StartDate"); endDate = getRequiredString(params, "endDate", "EndDate"); } catch (IllegalArgumentException ex) { result.setSuccess(false); result.setMessage(ex.getMessage()); return result; } if (calendarDataMockEnabled) { try { result.setData(CalendarMockData.records(playerId, property, roomType, startDate, endDate)); result.setSuccess(true); result.setCode("200"); result.setMessage("CALENDAR_MOCK_DATA"); } catch (java.time.DateTimeException | IllegalArgumentException ex) { result.setSuccess(false); result.setMessage(ex.getMessage()); } return result; } CalendarVisibilityCheck visibility = validateCalendarVisibility(property, roomType); if (visibility.errorCode != null) { result.setSuccess(false); result.setMessage(visibility.errorMessage); result.setCalendarErrorCode(visibility.errorCode); result.setData(new ArrayList<>()); return result; } List allRecords = new ArrayList<>(); boolean anySuccess = false; if (StringUtils.isNotBlank(visibility.operaProperty) && StringUtils.isNotBlank(visibility.operaRoomType)) { try { HttpResponseResult response = mgmEsbApiService.invokeRequestRoomCalendar( playerId, visibility.operaProperty, visibility.operaRoomType, startDate, endDate, 0); if (response.getStatusCode() == 200) { allRecords.addAll(parseRoomCalendarResponse(response.getResponseContent())); anySuccess = true; } } catch (Exception ignored) { } } if (StringUtils.isNotBlank(visibility.daylightProperty) && StringUtils.isNotBlank(visibility.daylightRoomType)) { try { HttpResponseResult response = mgmEsbApiService.invokeRequestRoomCalendar( playerId, visibility.daylightProperty, visibility.daylightRoomType, startDate, endDate, 1); if (response.getStatusCode() == 200) { allRecords.addAll(parseRoomCalendarResponse(response.getResponseContent())); anySuccess = true; } } catch (Exception ignored) { } } if (StringUtils.isNotBlank(visibility.otherProperty) && StringUtils.isNotBlank(visibility.otherRoomType)) { try { HttpResponseResult response = mgmEsbApiService.invokeRequestRoomCalendar( playerId, visibility.otherProperty, visibility.otherRoomType, startDate, endDate, 0); if (response.getStatusCode() == 200) { allRecords.addAll(parseRoomCalendarResponse(response.getResponseContent())); anySuccess = true; } } catch (Exception ignored) { } } if (!anySuccess) { result.setSuccess(false); result.setMessage("RequestRoomCalendar failed"); result.setData(new ArrayList<>()); return result; } result.setData(allRecords); result.setSuccess(true); result.setCode("200"); return result; } private CalendarVisibilityCheck validateCalendarVisibility(String property, String roomType) { List propertyNames = parseDelimitedValues(property); List roomTypeNames = parseDelimitedValues(roomType); List properties = propertyDao.findByCalendarNameIn(propertyNames); List visibleProperties = new ArrayList<>(); for (String propertyName : propertyNames) { CfgProperties cfgProperty = findByCalendarName(properties, propertyName); if (isShowCalendar(cfgProperty)) { visibleProperties.add(cfgProperty); } } if (visibleProperties.isEmpty()) { return CalendarVisibilityCheck.failure("PROPERTYNOSHOW", "Property no show in calendar"); } List propertyIds = new ArrayList<>(); for (CfgProperties cfgProperty : visibleProperties) { propertyIds.add(String.valueOf(cfgProperty.getId())); } List rooms = roomDao.findByPropertyIdInAndCalendarNameIn(propertyIds, roomTypeNames); String operaProperty = ""; String operaRoomType = ""; String daylightProperty = ""; String daylightRoomType = ""; String otherProperty = ""; String otherRoomType = ""; List operaIds = new ArrayList<>(); List operaCodes = new ArrayList<>(); List daylightIds = new ArrayList<>(); List daylightCodes = new ArrayList<>(); List otherIds = new ArrayList<>(); List otherCodes = new ArrayList<>(); for (CfgProperties cfgProperty : visibleProperties) { String category = cfgProperty.getCategory(); if (StringUtils.equalsIgnoreCase(category, "OPERA")) { operaIds.add(String.valueOf(cfgProperty.getId())); operaCodes.add(cfgProperty.getCode()); } else if (StringUtils.equalsIgnoreCase(category, "DAYLIGHT")) { daylightIds.add(String.valueOf(cfgProperty.getId())); daylightCodes.add(cfgProperty.getCode()); } else if (StringUtils.equalsIgnoreCase(category, "OTHER")) { otherIds.add(String.valueOf(cfgProperty.getId())); otherCodes.add(cfgProperty.getCode()); } } if (!operaIds.isEmpty()) { List visibleOperaRoomTypes = filterVisibleRoomTypes(roomTypeNames, rooms, operaIds); if (!visibleOperaRoomTypes.isEmpty()) { operaProperty = StringUtils.join(operaCodes, ","); operaRoomType = StringUtils.join(visibleOperaRoomTypes, ","); } } if (!daylightIds.isEmpty()) { List visibleDaylightRoomTypes = filterVisibleRoomTypes(roomTypeNames, rooms, daylightIds); if (!visibleDaylightRoomTypes.isEmpty()) { daylightProperty = StringUtils.join(daylightCodes, ","); daylightRoomType = StringUtils.join(visibleDaylightRoomTypes, ","); } } if (!otherIds.isEmpty()) { List visibleOtherRoomTypes = filterVisibleRoomTypes(roomTypeNames, rooms, otherIds); if (!visibleOtherRoomTypes.isEmpty()) { otherProperty = StringUtils.join(otherCodes, ","); otherRoomType = StringUtils.join(visibleOtherRoomTypes, ","); } } if (StringUtils.isBlank(operaRoomType) && StringUtils.isBlank(daylightRoomType) && StringUtils.isBlank(otherRoomType)) { return CalendarVisibilityCheck.failure("ROOMTYPENOSHOW", "Room type no show in calendar"); } return CalendarVisibilityCheck.success(operaProperty, operaRoomType, daylightProperty, daylightRoomType, otherProperty, otherRoomType); } public GetPropertyRoomTypeListResponse getPropertyRoomType() { if (calendarDataMockEnabled) return CalendarMockData.metadata(); GetPropertyRoomTypeListResponse response = new GetPropertyRoomTypeListResponse(); List properties = propertyDao.findAll(); Map> roomsByPropertyId = buildCalendarRoomsByPropertyId(properties); List propertyList = new ArrayList<>(); List otherProperties = new ArrayList<>(); properties.sort(Comparator.comparing(RoomCalendarService::getPropertyCalendarOrder)); for (CfgProperties property : properties) { if (!isShowCalendar(property)) { continue; } List roomTypes = buildRoomTypes(property, roomsByPropertyId); String calendarName = StringUtils.defaultIfBlank(property.getCalendarName(), property.getName()); if (StringUtils.equalsIgnoreCase(property.getCategory(), "OPERA") || StringUtils.equalsIgnoreCase(property.getCategory(), "DAYLIGHT")) { propertyList.add(buildPropertyRoomTypeResponse(calendarName, calendarName, null, roomTypes)); } else if (StringUtils.equalsIgnoreCase(property.getCategory(), "OTHER")) { otherProperties.add(buildPropertyRoomTypeResponse( calendarName, calendarName, StringUtils.defaultIfBlank(property.getName(), property.getCalendarName()), roomTypes)); } } if (!otherProperties.isEmpty()) { GetPropertyRoomTypeResponse otherGroup = buildPropertyRoomTypeResponse( "OTHER", "Other Property", null, new ArrayList<>()); otherGroup.setDefaultRoomTypes(buildDefaultProperties(otherProperties)); otherGroup.setOtherProperties(otherProperties); propertyList.add(otherGroup); } response.setPropertyList(propertyList); response.setSuccess(true); response.setCode("200"); return response; } private Map> buildCalendarRoomsByPropertyId(List properties) { List propertyIds = new ArrayList<>(); for (CfgProperties property : properties) { if (isShowCalendar(property) && property.getId() != null) { propertyIds.add(String.valueOf(property.getId())); } } Map> roomsByPropertyId = new HashMap<>(); if (propertyIds.isEmpty()) { return roomsByPropertyId; } for (RoomCalendarRoomProjection room : roomDao.queryCalendarRoomsByPropertyIds(propertyIds)) { if (room == null || StringUtils.isBlank(room.getPropertyId())) { continue; } roomsByPropertyId.computeIfAbsent(room.getPropertyId(), key -> new ArrayList<>()).add(room); } return roomsByPropertyId; } private static List buildRoomTypes( CfgProperties property, Map> roomsByPropertyId) { List rooms = new ArrayList<>( roomsByPropertyId.getOrDefault(String.valueOf(property.getId()), new ArrayList<>())); rooms.sort(Comparator.comparing(RoomCalendarService::getRoomCalendarOrder)); List roomTypes = new ArrayList<>(); for (RoomCalendarRoomProjection room : rooms) { String calendarName = StringUtils.defaultIfBlank(room.getCalendarName(), room.getName()); if (StringUtils.isBlank(calendarName)) { continue; } RoomType existing = findRoomType(roomTypes, calendarName); if (existing != null) { if (isDefaultShowCalendar(room.getDefaultShowCalendar())) { existing.setDefaultShowCalendar(1); } continue; } RoomType item = new RoomType(); item.setCode(calendarName); item.setLabel(calendarName); item.setDefaultShowCalendar(isDefaultShowCalendar(room.getDefaultShowCalendar()) ? 1 : 0); roomTypes.add(item); } return roomTypes; } private static GetPropertyRoomTypeResponse buildPropertyRoomTypeResponse( String code, String name, String displayName, List roomTypes) { GetPropertyRoomTypeResponse item = new GetPropertyRoomTypeResponse(); item.setCode(StringUtils.defaultString(code)); item.setName(StringUtils.defaultString(name)); item.setDisplayName(displayName); item.setRoomTypes(roomTypes); item.setDefaultRoomTypes(buildDefaultRoomTypes(roomTypes)); return item; } private static List buildDefaultRoomTypes(List roomTypes) { List defaults = new ArrayList<>(); for (RoomType roomType : roomTypes) { if (defaults.size() >= 3) { break; } if (isDefaultShowCalendar(roomType.getDefaultShowCalendar()) && StringUtils.isNotBlank(roomType.getCode())) { defaults.add(roomType.getCode()); } } return defaults; } private static List buildDefaultProperties(List properties) { List defaults = new ArrayList<>(); for (GetPropertyRoomTypeResponse property : properties) { if (defaults.size() >= 3) { break; } if (property.getDefaultRoomTypes() != null && !property.getDefaultRoomTypes().isEmpty() && StringUtils.isNotBlank(property.getCode())) { defaults.add(property.getCode()); } } return defaults; } static List parseRoomCalendarResponse(String responseContent) { JSONObject resultObj = JSONObject.parseObject(responseContent); if (!StringUtils.equals("OK", resultObj.getString("StatusCode"))) { throw new IllegalArgumentException(StringUtils.defaultIfBlank( resultObj.getString("StatusDescription"), "RequestRoomCalendar failed")); } JSONArray records = resultObj.getJSONArray("Records"); List result = new ArrayList<>(); if (records == null) { return result; } for (int i = 0; i < records.size(); i++) { JSONObject item = records.getJSONObject(i); RoomCalendarQualification record = new RoomCalendarQualification(); record.setProperty(item.getString("Property")); record.setRoomType(item.getString("RoomType")); record.setDate(normalizeDate(item.getString("Date"))); record.setRoomCriteria(item.getString("RoomCriteria")); record.setRoomCount(item.getInteger("RoomCount")); record.setPropertyLeader(item.getString("PropertyLeader")); record.setBookingDateQualificationFlag(item.getInteger("BookingDateQualificationFlag")); result.add(record); } return result; } private static List filterVisibleRoomTypes(List requestedNames, List rooms, List propertyIds) { Set propertyIdSet = new LinkedHashSet<>(propertyIds); Set visible = new LinkedHashSet<>(); for (String requestedName : requestedNames) { for (CfgRooms room : rooms) { if (StringUtils.equals(requestedName, room.getCalendarName()) && isShowCalendar(room) && propertyIdSet.contains(room.getPropertyId())) { visible.add(requestedName); break; } } } return new ArrayList<>(visible); } private static CfgProperties findByCalendarName(List properties, String name) { for (CfgProperties property : properties) { if (StringUtils.equals(property.getCalendarName(), name)) { return property; } } return null; } private static RoomType findRoomType(List roomTypes, String code) { for (RoomType roomType : roomTypes) { if (StringUtils.equals(roomType.getCode(), code)) { return roomType; } } return null; } private static List parseDelimitedValues(String value) { List values = new ArrayList<>(); for (String item : StringUtils.split(StringUtils.defaultString(value), ",")) { if (StringUtils.isNotBlank(item)) { values.add(StringUtils.trim(item)); } } return values; } private static String getRequiredString(Map params, String lowerKey, String upperKey) { Object value = params.get(lowerKey); if (value == null) { value = params.get(upperKey); } if (value == null || StringUtils.isBlank(String.valueOf(value))) { throw new IllegalArgumentException("Missing parameter: " + lowerKey); } return String.valueOf(value); } private static String getOptionalString(Map params, String lowerKey, String upperKey) { Object value = params.get(lowerKey); if (value == null) { value = params.get(upperKey); } return value == null || StringUtils.isBlank(String.valueOf(value)) ? "" : String.valueOf(value); } private static String normalizeDate(String value) { if (StringUtils.isBlank(value)) { return ""; } return value.length() >= 10 ? value.substring(0, 10) : value; } private static boolean isShowCalendar(CfgProperties property) { return property != null && Integer.valueOf(1).equals(property.getShowCalendar()); } private static boolean isShowCalendar(CfgRooms room) { return room != null && Integer.valueOf(1).equals(room.getShowCalendar()); } private static boolean isDefaultShowCalendar(Integer value) { return Integer.valueOf(1).equals(value); } private static Integer getPropertyCalendarOrder(CfgProperties property) { return property == null || property.getCalendarOrder() == null ? Integer.MAX_VALUE : property.getCalendarOrder(); } private static Integer getRoomCalendarOrder(RoomCalendarRoomProjection room) { return room == null || room.getCalendarOrder() == null ? Integer.MAX_VALUE : room.getCalendarOrder(); } private static final class CalendarVisibilityCheck { private final String errorCode; private final String errorMessage; private final String operaProperty; private final String operaRoomType; private final String daylightProperty; private final String daylightRoomType; private final String otherProperty; private final String otherRoomType; private CalendarVisibilityCheck(String errorCode, String errorMessage, String operaProperty, String operaRoomType, String daylightProperty, String daylightRoomType, String otherProperty, String otherRoomType) { this.errorCode = errorCode; this.errorMessage = errorMessage; this.operaProperty = operaProperty; this.operaRoomType = operaRoomType; this.daylightProperty = daylightProperty; this.daylightRoomType = daylightRoomType; this.otherProperty = otherProperty; this.otherRoomType = otherRoomType; } private static CalendarVisibilityCheck success(String operaProperty, String operaRoomType, String daylightProperty, String daylightRoomType, String otherProperty, String otherRoomType) { return new CalendarVisibilityCheck(null, null, operaProperty, operaRoomType, daylightProperty, daylightRoomType, otherProperty, otherRoomType); } private static CalendarVisibilityCheck failure(String errorCode, String errorMessage) { return new CalendarVisibilityCheck(errorCode, errorMessage, null, null, null, null, null, null); } } }