Room Type Module of Hotel Booking Application

Implementing Room Type Module of Hotel Booking Application

In this article, I will discuss implementing the Room Type Module of a Hotel Booking Application. Please read our previous article discussing How to Implement the User Module of a Hotel Booking Application.

How to Implement Room Type Module of Hotel Booking Application

Let us implement the Room Type Module. Let us create the Stored Procedures, Model classes, DTOS, a Repository class, and RoomType Controller for adding, updating, and deleting Room Type, Fetching the Room Details by Room Type ID, Fetching all Room Details, etc.

Create Stored Procedures for Room Types and Rooms

We will start by creating the necessary stored procedures in SQL Server to Manage the Room Type Data in the database. Please execute the following Script on the HotelDB database that we are working with so far.

-- Create Room Type
CREATE PROCEDURE spCreateRoomType
    @TypeName NVARCHAR(50),
    @AccessibilityFeatures NVARCHAR(255),
    @Description NVARCHAR(255),
    @CreatedBy NVARCHAR(100),
    @NewRoomTypeID INT OUTPUT,
    @StatusCode INT OUTPUT,
    @Message NVARCHAR(255) OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRY
        BEGIN TRANSACTION
            IF NOT EXISTS (SELECT 1 FROM RoomTypes WHERE TypeName = @TypeName)
            BEGIN
                INSERT INTO RoomTypes (TypeName, AccessibilityFeatures, Description, CreatedBy, CreatedDate)
                VALUES (@TypeName, @AccessibilityFeatures, @Description, @CreatedBy, GETDATE())

                SET @NewRoomTypeID = SCOPE_IDENTITY()
                SET @StatusCode = 0 -- Success
                SET @Message = 'Room type created successfully.'
            END
            ELSE
            BEGIN
                SET @StatusCode = 1 -- Failure due to duplicate name
                SET @Message = 'Room type name already exists.'
            END
        COMMIT TRANSACTION
    END TRY
    BEGIN CATCH
        ROLLBACK TRANSACTION
        SET @StatusCode = ERROR_NUMBER() -- SQL Server error number
        SET @Message = ERROR_MESSAGE()
    END CATCH
END
GO

-- Update Room Type
CREATE PROCEDURE spUpdateRoomType
    @RoomTypeID INT,
    @TypeName NVARCHAR(50),
    @AccessibilityFeatures NVARCHAR(255),
    @Description NVARCHAR(255),
    @ModifiedBy NVARCHAR(100),
    @StatusCode INT OUTPUT,
    @Message NVARCHAR(255) OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRY
        BEGIN TRANSACTION
            -- Check if the updated type name already exists in another record
            IF NOT EXISTS (SELECT 1 FROM RoomTypes WHERE TypeName = @TypeName AND RoomTypeID <> @RoomTypeID)
            BEGIN
                IF EXISTS (SELECT 1 FROM RoomTypes WHERE RoomTypeID = @RoomTypeID)
                BEGIN
                    UPDATE RoomTypes
                    SET TypeName = @TypeName,
                        AccessibilityFeatures = @AccessibilityFeatures,
                        Description = @Description,
                        ModifiedBy = @ModifiedBy,
                        ModifiedDate = GETDATE()
                    WHERE RoomTypeID = @RoomTypeID

                    SET @StatusCode = 0 -- Success
                    SET @Message = 'Room type updated successfully.'
                END
                ELSE
                BEGIN
                    SET @StatusCode = 2 -- Failure due to not found
                    SET @Message = 'Room type not found.'
                END
            END
            ELSE
            BEGIN
                SET @StatusCode = 1 -- Failure due to duplicate name
                SET @Message = 'Another room type with the same name already exists.'
            END
        COMMIT TRANSACTION
    END TRY
    BEGIN CATCH
        ROLLBACK TRANSACTION
        SET @StatusCode = ERROR_NUMBER() -- SQL Server error number
        SET @Message = ERROR_MESSAGE()
    END CATCH
END
GO

-- Delete Room Type By Id
CREATE PROCEDURE spDeleteRoomType
    @RoomTypeID INT,
    @StatusCode INT OUTPUT,
    @Message NVARCHAR(255) OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRY
        BEGIN TRANSACTION
   
            -- Check for existing rooms linked to this room type
            IF NOT EXISTS (SELECT 1 FROM Rooms WHERE RoomTypeID = @RoomTypeID)
            BEGIN
                IF EXISTS (SELECT 1 FROM RoomTypes WHERE RoomTypeID = @RoomTypeID)
                BEGIN
                    DELETE FROM RoomTypes WHERE RoomTypeID = @RoomTypeID
                    SET @StatusCode = 0 -- Success
                    SET @Message = 'Room type deleted successfully.'
                END
                ELSE
                BEGIN
                    SET @StatusCode = 2 -- Failure due to not found
                    SET @Message = 'Room type not found.'
                END
            END
            ELSE
            BEGIN
                SET @StatusCode = 1 -- Failure due to dependency
                SET @Message = 'Cannot delete room type as it is being referenced by one or more rooms.'
            END
        COMMIT TRANSACTION
    END TRY
    BEGIN CATCH
        ROLLBACK TRANSACTION
        SET @StatusCode = ERROR_NUMBER() -- SQL Server error number
        SET @Message = ERROR_MESSAGE()
    END CATCH
END
GO

-- Get Room Type By Id
CREATE PROCEDURE spGetRoomTypeById
    @RoomTypeID INT
AS
BEGIN
    SET NOCOUNT ON;
    SELECT RoomTypeID, TypeName, AccessibilityFeatures, Description, IsActive FROM RoomTypes WHERE RoomTypeID = @RoomTypeID
END
GO

-- Get All Room Type
CREATE PROCEDURE spGetAllRoomTypes
 @IsActive BIT = NULL  -- Optional parameter to filter by IsActive status
AS
BEGIN
    SET NOCOUNT ON;
    -- Select users based on active status
    IF @IsActive IS NULL
    BEGIN
        SELECT RoomTypeID, TypeName, AccessibilityFeatures, Description, IsActive FROM RoomTypes
    END
    ELSE
    BEGIN
        SELECT RoomTypeID, TypeName, AccessibilityFeatures, Description, IsActive FROM RoomTypes WHERE IsActive = @IsActive;
    END
END
GO

-- Activate/Deactivate RoomType
CREATE PROCEDURE spToggleRoomTypeActive
    @RoomTypeID INT,
    @IsActive BIT,
    @StatusCode INT OUTPUT,
    @Message NVARCHAR(255) OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRY
        -- Check user existence
        IF NOT EXISTS (SELECT 1 FROM RoomTypes WHERE RoomTypeID = @RoomTypeID)
        BEGIN
             SET @StatusCode = 1 -- Failure due to not found
             SET @Message = 'Room type not found.'
        END

        -- Update IsActive status
        BEGIN TRANSACTION
            	UPDATE RoomTypes SET IsActive = @IsActive WHERE RoomTypeID = @RoomTypeID;
                SET @StatusCode = 0 -- Success
            	SET @Message = 'Room type activated/deactivated successfully.'
        COMMIT TRANSACTION

    END TRY
    -- Handle exceptions
    BEGIN CATCH
        ROLLBACK TRANSACTION
        SET @StatusCode = ERROR_NUMBER() -- SQL Server error number
        SET @Message = ERROR_MESSAGE()
    END CATCH
END;
GO
Explanation of Each Stored Procedure:
  • spCreateRoomType: Creates a new room type in the RoomTypes table. To avoid duplicates, it checks if a room type with the same name already exists. If successful, it inserts the new room type with the provided details and returns the new room type ID, a success status code, and a success message. If the room type name already exists, it returns an error message and status code indicating failure.
  • spUpdateRoomType: Updates the details of an existing room type identified by its ID. It ensures that the new type name does not exist for another record and that the specified room type exists before updating. Success or failure is communicated through a status code and message, indicating whether the update was successful, a duplicate was found, or the room type was not found.
  • spDeleteRoomType: Deletes a room type from the RoomTypes table based on the provided room type ID. It first checks if any rooms are still linked to this room type to prevent deleting a type that is in use. It deletes the room type and returns a success message if no dependencies are found. If dependencies exist or the room type is not found, appropriate failure messages and status codes are returned.
  • spGetRoomTypeById: Retrieves details of a specific room type by its ID. This procedure fetches the type name, accessibility features, description, and active status of a room type, allowing for detailed viewing of a single room type’s information.
  • spGetAllRoomTypes: Fetches all room types from the RoomTypes table, optionally filtered by their active status. This procedure supports viewing all room types or filtering them based on whether they are currently active or inactive.
  • spToggleRoomTypeActive: This procedure toggles the active status of a specific room type. It can activate or deactivate a room type, which is useful for managing whether it should be available for new bookings. Success or failure is communicated through a status code and message.
Creating Room Type DTOs:

Next, we need to create the DTOs required for performing operations on Room Types. Controllers and Repositories will use these DTOs to manage Operations and Data Transformation effectively. Please create a folder called RoomTypeDTOs inside the DTOs folder, where we will add all the DTOs related to managing Room Types.

RoomTypeDTO

Create a class file named RoomTypeDTO.cs within the RoomTypeDTOs folder, and then copy and paste the following code. This DTO will only include the properties required to return the Room Type information.

namespace HotelBookingAPI.DTOs.RoomTypeDTOs
{
    public class RoomTypeDTO
    {
        public int RoomTypeID { get; set; }
        public string TypeName { get; set; }
        public string AccessibilityFeatures { get; set; }
        public string Description { get; set; }
        public bool IsActive { get; set; }
    }
}
CreateRoomTypeDTO

Create a class file named CreateRoomTypeDTO.cs within the RoomTypeDTOs folder, and then copy and paste the following code. This class will only include the properties required to create a new Room Type.

using System.ComponentModel.DataAnnotations;

namespace HotelBookingAPI.DTOs.RoomTypeDTOs
{
    public class CreateRoomTypeDTO
    {
        [Required]
        public string TypeName { get; set; }
        public string AccessibilityFeatures { get; set; }
        [Required]
        public string Description { get; set; }
    }
}
CreateRoomTypeResponseDTO

Create a class file named CreateRoomTypeResponseDTO.cs within the RoomTypeDTOs folder, and then copy and paste the following code. Once the room type is created, this class will only include the properties we send.

namespace HotelBookingAPI.DTOs.RoomTypeDTOs
{
    public class CreateRoomTypeResponseDTO
    {
        public int RoomTypeId { get; set; }
        public string Message { get; set; }
        public bool IsCreated { get; set; }
    }
}
DeleteRoomTypeResponseDTO

Create a class file named DeleteRoomTypeResponseDTO.cs within the RoomTypeDTOs folder, and then copy and paste the following code. This class will only include the properties that we are sending once the Room Type is deleted.

namespace HotelBookingAPI.DTOs.RoomTypeDTOs
{
    public class DeleteRoomTypeResponseDTO
    {
        public string Message { get; set; }
        public bool IsDeleted { get; set; }
    }
}
UpdateRoomTypeDTO

Create a class file named UpdateRoomTypeDTO.cs within the RoomTypeDTOs folder and copy and paste the following code. This DTO will only include the properties required to update an existing room type.

using System.ComponentModel.DataAnnotations;

namespace HotelBookingAPI.DTOs.RoomTypeDTOs
{
    public class UpdateRoomTypeDTO
    {
        [Required]
        public int RoomTypeID { get; set; }
        [Required]
        public string TypeName { get; set; }
        public string AccessibilityFeatures { get; set; }
        [Required]
        public string Description { get; set; }
    }
}
UpdateRoomTypeResponseDTO

Create a class file named UpdateRoomTypeResponseDTO.cs within the RoomTypeDTOs folder, and then copy and paste the following code. Once the room type is updated, this DTO class will only include the properties we send.

namespace HotelBookingAPI.DTOs.RoomTypeDTOs
{
    public class UpdateRoomTypeResponseDTO
    {
        public int RoomTypeId { get; set; }
        public string Message { get; set; }
        public bool IsUpdated { get; set; }
    }
}

Creating Room Type Repository:

Next, we need to create the RoomTypeRepository class, where we will implement the business and data access logic. This class will consume the Room Type Related Stored Procedures and DTOs for the operations that we have created so far. So, create a class file named RoomTypeRepository.cs within the Repository folder and copy and paste the following code.

using HotelBookingAPI.Connection;
using HotelBookingAPI.DTOs.RoomTypeDTOs;
using HotelBookingAPI.Models;
using Microsoft.Data.SqlClient;
using System.Data;

namespace HotelBookingAPI.Repository
{
    public class RoomTypeRepository
    {
        private readonly SqlConnectionFactory _connectionFactory;

        public RoomTypeRepository(SqlConnectionFactory connectionFactory)
        {
            _connectionFactory = connectionFactory;
        }

        public async Task<List<RoomTypeDTO>> RetrieveAllRoomTypesAsync(bool? IsActive)
        {
            using var connection = _connectionFactory.CreateConnection();

            var command = new SqlCommand("spGetAllRoomTypes", connection)
            {
                CommandType = CommandType.StoredProcedure
            };
            command.Parameters.AddWithValue("@IsActive", (object)IsActive ?? DBNull.Value);

            await connection.OpenAsync();

            using var reader = await command.ExecuteReaderAsync();

            var roomTypes = new List<RoomTypeDTO>();

            while (reader.Read())
            {
                roomTypes.Add(new RoomTypeDTO
                {
                    RoomTypeID = reader.GetInt32("RoomTypeID"),
                    TypeName = reader.GetString("TypeName"),
                    AccessibilityFeatures = reader.GetString("AccessibilityFeatures"),
                    Description = reader.GetString("Description"),
                    IsActive = reader.GetBoolean("IsActive")
                });
            }

            return roomTypes;
        }

        public async Task<RoomTypeDTO> RetrieveRoomTypeByIdAsync(int RoomTypeID)
        {
            using var connection = _connectionFactory.CreateConnection();

            var command = new SqlCommand("spGetRoomTypeById", connection)
            {
                CommandType = CommandType.StoredProcedure
            };

            command.Parameters.AddWithValue("@RoomTypeID", RoomTypeID);

            await connection.OpenAsync();

            using var reader = await command.ExecuteReaderAsync();


            if (!reader.Read())
            {
                return null;
            }

            var roomType = new RoomTypeDTO
            {
                RoomTypeID = RoomTypeID,
                TypeName = reader.GetString("TypeName"),
                AccessibilityFeatures = reader.GetString("AccessibilityFeatures"),
                Description = reader.GetString("Description"),
                IsActive = reader.GetBoolean("IsActive")
            };

            return roomType;
        }

        public async Task<CreateRoomTypeResponseDTO> CreateRoomType(CreateRoomTypeDTO request)
        {
            CreateRoomTypeResponseDTO createRoomTypeResponseDTO = new CreateRoomTypeResponseDTO();

            using var connection = _connectionFactory.CreateConnection();
            var command = new SqlCommand("spCreateRoomType", connection)
            {
                CommandType = CommandType.StoredProcedure
            };
            command.Parameters.Add(new SqlParameter("@TypeName", request.TypeName));
            command.Parameters.Add(new SqlParameter("@AccessibilityFeatures", request.AccessibilityFeatures));
            command.Parameters.Add(new SqlParameter("@Description", request.Description));
            command.Parameters.Add(new SqlParameter("@CreatedBy", "System"));
            var outputId = new SqlParameter("@NewRoomTypeID", SqlDbType.Int) { Direction = ParameterDirection.Output };
            var statusCode = new SqlParameter("@StatusCode", SqlDbType.Int) { Direction = ParameterDirection.Output };
            var message = new SqlParameter("@Message", SqlDbType.NVarChar, 255) { Direction = ParameterDirection.Output };

            command.Parameters.Add(outputId);
            command.Parameters.Add(statusCode);
            command.Parameters.Add(message);

            try
            {
                await connection.OpenAsync();
                await command.ExecuteNonQueryAsync();

                if ((int)statusCode.Value == 0)
                {
                    createRoomTypeResponseDTO.Message = message.Value.ToString();
                    createRoomTypeResponseDTO.IsCreated = true;
                    createRoomTypeResponseDTO.RoomTypeId = (int)outputId.Value;
                    return createRoomTypeResponseDTO;
                }

                createRoomTypeResponseDTO.Message = message.Value.ToString();
                createRoomTypeResponseDTO.IsCreated = false;
                
                return createRoomTypeResponseDTO;
            }
            catch (SqlException ex)
            {
                createRoomTypeResponseDTO.Message = ex.Message;
                createRoomTypeResponseDTO.IsCreated = false;
                return createRoomTypeResponseDTO;
            }
        }

        public async Task<UpdateRoomTypeResponseDTO> UpdateRoomType(UpdateRoomTypeDTO request)
        {
            UpdateRoomTypeResponseDTO updateRoomTypeResponseDTO = new UpdateRoomTypeResponseDTO()
            {
                RoomTypeId = request.RoomTypeID
            };

            using var connection = _connectionFactory.CreateConnection();
            var command = new SqlCommand("spUpdateRoomType", connection)
            {
                CommandType = CommandType.StoredProcedure
            };
            command.Parameters.Add(new SqlParameter("@RoomTypeID", request.RoomTypeID));
            command.Parameters.Add(new SqlParameter("@TypeName", request.TypeName));
            command.Parameters.Add(new SqlParameter("@AccessibilityFeatures", request.AccessibilityFeatures));
            command.Parameters.Add(new SqlParameter("@Description", request.Description));
            command.Parameters.Add(new SqlParameter("@ModifiedBy", "System"));
            var statusCode = new SqlParameter("@StatusCode", SqlDbType.Int) 
            { 
                Direction = ParameterDirection.Output 
            };
            var message = new SqlParameter("@Message", SqlDbType.NVarChar, 255) 
            { 
                Direction = ParameterDirection.Output 
            };
            command.Parameters.Add(statusCode);
            command.Parameters.Add(message);
           
            try
            {
                await connection.OpenAsync();
                await command.ExecuteNonQueryAsync();
                updateRoomTypeResponseDTO.Message = message.Value.ToString();
                updateRoomTypeResponseDTO.IsUpdated = (int)statusCode.Value == 0;
                
                return updateRoomTypeResponseDTO;
            }
            catch (SqlException ex)
            {
                updateRoomTypeResponseDTO.Message = ex.Message;
                updateRoomTypeResponseDTO.IsUpdated = false;

                return updateRoomTypeResponseDTO;
            }
        }

        public async Task<DeleteRoomTypeResponseDTO> DeleteRoomType(int RoomTypeID)
        {
            DeleteRoomTypeResponseDTO deleteRoomTypeResponseDTO = new DeleteRoomTypeResponseDTO();

            using var connection = _connectionFactory.CreateConnection();

            //If you want to Delete the Record Permanentlt, then use spDeleteRoomType Stored Procedure

            var command = new SqlCommand("spToggleRoomTypeActive", connection)
            {
                CommandType = CommandType.StoredProcedure
            };
            command.Parameters.Add(new SqlParameter("@RoomTypeID",RoomTypeID));
            command.Parameters.AddWithValue("@IsActive", false);
            var statusCode = new SqlParameter("@StatusCode", SqlDbType.Int) 
            { 
                Direction = ParameterDirection.Output 
            };
            var message = new SqlParameter("@Message", SqlDbType.NVarChar, 255) 
            { 
                Direction = ParameterDirection.Output 
            };

            command.Parameters.Add(statusCode);
            command.Parameters.Add(message);

            try
            {
                await connection.OpenAsync();
                await command.ExecuteNonQueryAsync();
                deleteRoomTypeResponseDTO.Message = "Room Type Deleted Successfully";
                deleteRoomTypeResponseDTO.IsDeleted = (int)statusCode.Value == 0;

                return deleteRoomTypeResponseDTO;
            }
            catch (SqlException ex)
            {
                deleteRoomTypeResponseDTO.Message = ex.Message;
                deleteRoomTypeResponseDTO.IsDeleted = false;

                return deleteRoomTypeResponseDTO;
            }
        }

        public async Task<(bool Success, string Message)> ToggleRoomTypeActiveAsync(int RoomTypeID, bool IsActive)
        {
            using var connection = _connectionFactory.CreateConnection();
            using var command = new SqlCommand("spToggleRoomTypeActive", connection)
            {
                CommandType = CommandType.StoredProcedure
            };
            command.Parameters.Add(new SqlParameter("@RoomTypeID", RoomTypeID));
            command.Parameters.AddWithValue("@IsActive", IsActive);
            var statusCode = new SqlParameter("@StatusCode", SqlDbType.Int)
            {
                Direction = ParameterDirection.Output
            };
            var message = new SqlParameter("@Message", SqlDbType.NVarChar, 255)
            {
                Direction = ParameterDirection.Output
            };

            command.Parameters.Add(statusCode);
            command.Parameters.Add(message);

            await connection.OpenAsync();
            await command.ExecuteNonQueryAsync();

            var ResponseMessage = message.Value.ToString();
            var success = (int)statusCode.Value == 0;

            return (success, ResponseMessage);
        }
    }
}
Explanation of Each Method:
Constructor (RoomTypeRepository)
  • Input Parameters: SqlConnectionFactory connectionFactory
  • Objective: Initialize the repository with a SqlConnectionFactory to facilitate database connections.
  • Outcome: The repository is configured to use the provided SqlConnectionFactory for database operations.
RetrieveAllRoomTypesAsync
  • Input Parameters: bool? IsActive (optional parameter to filter active/inactive room types)
  • Stored Procedure: spGetAllRoomTypes
  • Objective: Retrieves all room types from the database, optionally filtered by their active status.
  • Outcome: Returns a list of RoomTypeDTO objects representing each room type fetched from the database.
RetrieveRoomTypeByIdAsync
  • Input Parameters: int RoomTypeID (ID of the room type to retrieve)
  • Stored Procedure: spGetRoomTypeById
  • Objective: Fetches a single room type by its ID.
  • Outcome: Returns a RoomTypeDTO object containing the room type details if found or null if not found.
CreateRoomType
  • Input Parameters: CreateRoomTypeDTO request (contains the details of the new room type to be created)
  • Stored Procedure: spCreateRoomType
  • Objective: Create a new room type based on the provided details in the database.
  • Outcome: Returns a CreateRoomTypeResponseDTO indicating the success or failure of the creation, the message from the database, and the ID of the newly created room type.
UpdateRoomType
  • Input Parameters: UpdateRoomTypeDTO request (contains the updated details for an existing room type)
  • Stored Procedure: spUpdateRoomType
  • Objective: Updates an existing room type with new details provided in the request.
  • Outcome: Returns an UpdateRoomTypeResponseDTO indicating whether the update was successful, along with a message detailing the operation’s outcome.
DeleteRoomType
  • Input Parameters: int RoomTypeID (ID of the room type to “delete” by setting IsActive to false)
  • Stored Procedure: spToggleRoomTypeActive (used to “soft delete” by deactivating the room type)
  • Objective: Soft deletes a room type by setting its IsActive status to false.
  • Outcome: Returns a DeleteRoomTypeResponseDTO indicating whether the delete operation was successful, along with a message.
ToggleRoomTypeActiveAsync
  • Input Parameters: int RoomTypeID, bool IsActive (ID of the room type and the new active status)
  • Stored Procedure: spToggleRoomTypeActive
  • Objective: Toggles the active status of a room type, enabling or disabling it.
  • Outcome: This function returns a tuple (bool Success, string Message) indicating the operation’s success and providing a relevant message.
Register the Repository:

Next, we need to register the RoomTypeRepository into the dependency injection container so that the framework can inject the object wherever we need this repository instance, mostly in the Controller class. So, please add the following code to the Program.cs class file:

builder.Services.AddScoped<RoomTypeRepository>();

Creating Room Type Controller:

Let us create the Room Type Controller and use the methods defined in the above RoomTypeRepository class. So, create a new Empty API Controller named RoomTypeController within the Controllers folder and copy and paste the following code.

using HotelBookingAPI.DTOs.RoomTypeDTOs;
using HotelBookingAPI.Models;
using HotelBookingAPI.Repository;
using Microsoft.AspNetCore.Mvc;
using System.Net;

namespace HotelBookingAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class RoomTypeController : ControllerBase
    {
        private readonly RoomTypeRepository _roomTypeRepository;
        private readonly ILogger<RoomTypeController> _logger;

        public RoomTypeController(RoomTypeRepository roomTypeRepository, ILogger<RoomTypeController> logger)
        {
            _roomTypeRepository = roomTypeRepository;
            _logger = logger;
        }

        [HttpGet("AllRoomTypes")]
        public async Task<APIResponse<List<RoomTypeDTO>>> GetAllRoomTypes(bool? IsActive = null)
        {
            _logger.LogInformation($"Request Received for GetAllRoomTypes, IsActive: {IsActive}");
            try
            {
                var users = await _roomTypeRepository.RetrieveAllRoomTypesAsync(IsActive);

                return new APIResponse<List<RoomTypeDTO>>(users, "Retrieved all Room Types Successfully.");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error Retriving all Room Types");
                return new APIResponse<List<RoomTypeDTO>>(HttpStatusCode.InternalServerError, "Internal server error: " + ex.Message);
            }
        }

        [HttpGet("GetRoomType/{RoomTypeID}")]
        public async Task<APIResponse<RoomTypeDTO>> GetRoomTypeById(int RoomTypeID)
        {
            _logger.LogInformation($"Request Received for GetRoomTypeById, RoomTypeID: {RoomTypeID}");
            try
            {
                var roomType = await _roomTypeRepository.RetrieveRoomTypeByIdAsync(RoomTypeID);
                if (roomType == null)
                {
                    return new APIResponse<RoomTypeDTO>(HttpStatusCode.NotFound, "RoomTypeID not found.");
                }

                return new APIResponse<RoomTypeDTO>(roomType, "RoomType fetched successfully.");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting Room Type by ID {RoomTypeID}", RoomTypeID);
                return new APIResponse<RoomTypeDTO>(HttpStatusCode.BadRequest, "Error fetching Room Type .", ex.Message);
            }
        }
        
        [HttpPost("AddRoomType")]
        public async Task<APIResponse<CreateRoomTypeResponseDTO>> CreateRoomType([FromBody] CreateRoomTypeDTO request)
        {
            _logger.LogInformation("Request Received for CreateRoomType: {@CreateRoomTypeDTO}", request);

            if (!ModelState.IsValid)
            {
                _logger.LogInformation("Invalid Data in the Request Body");
                return new APIResponse<CreateRoomTypeResponseDTO>(HttpStatusCode.BadRequest, "Invalid Data in the Requrest Body");
            }

            try
            {
                var response = await _roomTypeRepository.CreateRoomType(request);
                _logger.LogInformation("CreateRoomType Response From Repository: {@CreateRoomTypeResponseDTO}", response);

                if (response.IsCreated)
                {
                    return new APIResponse<CreateRoomTypeResponseDTO>(response, response.Message);
                }
                return new APIResponse<CreateRoomTypeResponseDTO>(HttpStatusCode.BadRequest, response.Message);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error adding new Room Type with Name {TypeName}", request.TypeName);
                return new APIResponse<CreateRoomTypeResponseDTO>(HttpStatusCode.InternalServerError, "Room Type Creation Failed.", ex.Message);
            }
        }

        [HttpPut("Update/{RoomTypeId}")]
        public async Task<APIResponse<UpdateRoomTypeResponseDTO>> UpdateRoomType(int RoomTypeId, [FromBody] UpdateRoomTypeDTO request)
        {
            _logger.LogInformation("Request Received for UpdateRoomType {@UpdateRoomTypeDTO}", request);
            if (!ModelState.IsValid)
            {
                _logger.LogInformation("UpdateRoomType Invalid Request Body");
                return new APIResponse<UpdateRoomTypeResponseDTO>(HttpStatusCode.BadRequest, "Invalid Request Body");
            }
            if (RoomTypeId != request.RoomTypeID)
            {
                _logger.LogInformation("UpdateRoomType Mismatched Room Type ID");
                return new APIResponse<UpdateRoomTypeResponseDTO>(HttpStatusCode.BadRequest, "Mismatched Room Type ID.");
            }
            try
            {
                var response = await _roomTypeRepository.UpdateRoomType(request);

                if (response.IsUpdated)
                {
                    return new APIResponse<UpdateRoomTypeResponseDTO>(response, response.Message);
                }
                return new APIResponse<UpdateRoomTypeResponseDTO>(HttpStatusCode.BadRequest, response.Message);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error Updating Room Type {RoomTypeId}", RoomTypeId);
                return new APIResponse<UpdateRoomTypeResponseDTO>(HttpStatusCode.InternalServerError, "Update Room Type Failed.", ex.Message);
            }
        }

        [HttpDelete("Delete/{RoomTypeId}")]
        public async Task<APIResponse<DeleteRoomTypeResponseDTO>> DeleteRoomType(int RoomTypeId)
        {
            _logger.LogInformation($"Request Received for DeleteRoomType, RoomTypeId: {RoomTypeId}");
            try
            {
                var roomType = await _roomTypeRepository.RetrieveRoomTypeByIdAsync(RoomTypeId);
                if (roomType == null)
                {
                    return new APIResponse<DeleteRoomTypeResponseDTO>(HttpStatusCode.NotFound, "RoomType not found.");
                }

                var response = await _roomTypeRepository.DeleteRoomType(RoomTypeId);
                if (response.IsDeleted)
                {
                    return new APIResponse<DeleteRoomTypeResponseDTO>(response, response.Message);
                }
                return new APIResponse<DeleteRoomTypeResponseDTO>(HttpStatusCode.BadRequest, response.Message);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error deleting RoomType {RoomTypeId}", RoomTypeId);
                return new APIResponse<DeleteRoomTypeResponseDTO>(HttpStatusCode.InternalServerError, "Internal server error: " + ex.Message);
            }
        }

        [HttpPost("ActiveInActive")]
        public async Task<IActionResult> ToggleActive(int RoomTypeId, bool IsActive)
        {
            try
            {
                var result = await _roomTypeRepository.ToggleRoomTypeActiveAsync(RoomTypeId, IsActive);
                if (result.Success)
                    return Ok(new { Message = "RoomType activation status updated successfully." });
                else
                    return BadRequest(new { Message = result.Message });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error toggling active status for RoomTypeId {RoomTypeId}", RoomTypeId);
                return StatusCode(500, "An error occurred while processing your request.");
            }
        }
    }
}
Explanation of the Controller’s Functions:
GetAllRoomTypes

Retrieves all room types, optionally filtered by their active status.

  • Input Parameters: bool? IsActive (optional) to filter room types based on their active status.
  • Outcome: Returns a list of RoomTypeDTO objects wrapped in an APIResponse with a success message or an error message in case of failure.
GetRoomTypeById

Fetches a specific room type by its ID.

  • Input Parameters: int RoomTypeID to specify which room type to retrieve.
  • Outcome: Returns a single RoomTypeDTO object wrapped in an APIResponse, or an error/not found message if no room type is found.
CreateRoomType

Creates a new room type using the details provided in the request.

  • Input Parameters: CreateRoomTypeDTO request containing the new room type’s details.
  • Outcome: Returns a CreateRoomTypeResponseDTO wrapped in an APIResponse indicating whether the room type was successfully created, along with a relevant message.
UpdateRoomType

Updates details of an existing room type.

  • Input Parameters: int RoomTypeId as the URL parameter to identify the room type and UpdateRoomTypeDTO request containing the updated details.
  • Outcome: Returns UpdateRoomTypeResponseDTO wrapped in an APIResponse indicating whether the room type was successfully updated, along with a relevant message.
DeleteRoomType

Deletes (or deactivates) a room type identified by ID.

  • Input Parameters: int RoomTypeId to specify which room type to delete.
  • Outcome: Returns a DeleteRoomTypeResponseDTO wrapped in an APIResponse, indicating whether the room type was successfully deleted, along with a relevant message.
ToggleActive

Toggles the active status of a room type.

  • Input Parameters: int RoomTypeId to specify the room type, and bool IsActive to set the desired active status.
  • Outcome: Returns a JSON response indicating success with a success message or a BadRequest with an error message if the operation fails.
Testing User Functionalities:

Run the application and test each functionality; it should work as expected.

In this article, I explain the Room Type Module of the Hotel Booking Application. I hope you enjoy this implementation of the Room Type Module of a Hotel Booking Application article. Please take a few minutes to give your valuable feedback about this article. Your feedback means a lot to me and motivates me to give better examples and explanations.

What Next? Implementing the Room Module of the Hotel Booking Application.

Leave a Reply

Your email address will not be published. Required fields are marked *