Update Calendar Max Stay API
Technical documentation for the method that updates maximum stay values for room rate plans by date.
Description
This endpoint updates the maxStay value in the calendar for a specific room and rate plan. It receives roomId and ratePlanId as request parameters and a list of MaxStayData objects in the request body.
For every date received, the method checks whether RoomAvailability already exists. If it exists, it updates or creates the related RateRoomAvailability entry for the selected rate plan. If it does not exist, it creates both RoomAvailability and RateRoomAvailability records.
At the end, all changed entities are saved and the derived price recalculation logic is triggered for the selected rate plan.
Endpoint
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| roomId | Long | Yes | The ID of the room whose availability calendar must be updated. |
| ratePlanId | Long | Yes | The ID of the rate plan that belongs to the room and whose maxStay must be updated. |
Request
Request parameters: roomId and ratePlanId. Content-Type: application/json
Authorization: Bearer <token>
| Field | Type | Description |
|---|---|---|
| roomId | Long | Room identifier |
| ratePlanId | Long | Rate plan identifier |
| date | Date | Date to update |
| maxStay | Integer | Maximum-stay value for that date |
| propertyName | String | Property name supplied in the payload |
POST /updateCalendarMaxStay?roomId=12&ratePlanId=4
[
{"date": "2026-03-10T00:00:00.000+00:00", "maxStay": 5, "propertyName": "Hotel Example"},
{"date": "2026-03-11T00:00:00.000+00:00", "maxStay": 7, "propertyName": "Hotel Example"}
Process
- The method first checks whether maxStayDataList is null or empty.
- If the list is empty, it sends an email about the Channel Manager problem and returns an error message.
- It loads the room from the database using roomId.
- If the room is not found, it sends a notification email and returns a room-not-found message.
- It searches inside room.getRatePlans() for the rate plan with the given ratePlanId.
- If the rate plan is not found, it returns a rate-plan-not-found message.
- It converts all received dates into LocalDate values.
- It loads existing RoomAvailability records for the room and those dates, including related rate data.
- It builds a map by date so each calendar day can be processed efficiently.
- For each MaxStayData entry, it updates the existing RateRoomAvailability maxStay value or creates a new RateRoomAvailability if missing.
- If no RoomAvailability exists for that date, it creates a new RoomAvailability with default values and links a new RateRoomAvailability to it.
- It saves all changed RoomAvailability records.
- It saves all changed or newly created RateRoomAvailability records.
- It triggers derivedPriceService.processRatePlanChange(ratePlanId, false).
- It returns a success message when the operation completes.
Responses Returned
The method returns a plain String response. Depending on the situation, one of the following messages is returned:
| Condition | Returned Response |
|---|---|
| maxStayDataList is null or empty | maxStay is received as empty list {roomId} |
| Room not found in database | Room with ID: {roomId} not exist in db, check room id {roomId} in allbookers |
| Rate plan not found for the room | Rate plan with ID: {ratePlanId} not found for room ID: {roomId} |
| Update completed successfully | maxStay is successfully updated |
Notes
- The method is annotated with @Transactional, so all database changes are committed together.
- The date conversion uses ZoneId.systemDefault(), which means results depend on the server time zone.
- When a new RateRoomAvailability is created, price is initialized to 0.0.
- When a new RoomAvailability is created, totalRooms and occupiedRooms are initialized to 0 and closed is set to false.
- The derived price logic is triggered even though the main update here is maxStay, not direct price.