Skip to main content
The ServicioAdicional entity represents optional services that guests can add to their reservations, such as spa treatments, tours, meals, or amenities. Services can be configured to be available only during specific seasons.

Overview

ServicioAdicional manages service definitions and their seasonal availability. Services maintain a list of seasons in which they are offered, enabling flexible service availability based on demand, weather, or operational capacity. Namespace: SGRH.Domain.Entities.Servicios Source: ~/workspace/source/SGRH.Domain/Entities/Servicios/ServicioAdicional.cs

Properties

ServicioAdicionalId
int
required
Unique identifier for the additional service (primary key).
NombreServicio
string
required
Name of the service (e.g., “Spa Treatment”, “Airport Transfer”). Maximum length: 50 characters.
TipoServicio
string
required
Service category or type (e.g., “Wellness”, “Transportation”, “Dining”). Maximum length: 50 characters.
TemporadaIds
IReadOnlyCollection<int>
required
Read-only collection of season IDs where this service is available. Empty collection means available year-round.

Constructor

public ServicioAdicional(string nombreServicio, string tipoServicio)
Creates a new additional service.

Parameters

  • nombreServicio: Service name (max 50 chars, required)
  • tipoServicio: Service type/category (max 50 chars, required)

Validations

  • Both parameters validated with Guard.AgainstNullOrWhiteSpace
  • Maximum length enforced (50 characters each)

Initial State

  • Empty TemporadaIds collection (available year-round by default)

Example

var spaService = new ServicioAdicional(
    nombreServicio: "Masaje Relajante",
    tipoServicio: "Spa"
);

Methods

HabilitarEnTemporada

public void HabilitarEnTemporada(int temporadaId)
Enables the service for a specific season. Parameters:
  • temporadaId: Valid season ID (must be > 0)
Validations:
  • Season ID must be greater than 0
  • Cannot add duplicate season (throws ConflictException)
Example:
// Enable winter sports package only in winter season
var winterSports = new ServicioAdicional("Ski Pass", "Deportes");
winterSports.HabilitarEnTemporada(temporadaId: 3); // Winter season

DeshabilitarEnTemporada

public void DeshabilitarEnTemporada(int temporadaId)
Removes the service from a specific season. Parameters:
  • temporadaId: Season ID to remove
Validations:
  • Season must exist in collection (throws NotFoundException if not found)
Example:
// Remove service from low season
servicio.DeshabilitarEnTemporada(temporadaId: 1);

EstaDisponibleEn

public bool EstaDisponibleEn(int? temporadaId)
Checks if the service is available during a given season. Parameters:
  • temporadaId: Season ID to check (nullable)
Logic:
  • If temporadaId is null, returns true (no season = always available)
  • If season list is empty, returns true (available year-round)
  • Otherwise, returns whether the season is in the collection
Example:
if (servicio.EstaDisponibleEn(temporadaId: 2))
{
    // Service can be added to reservation
}

Actualizar

public void Actualizar(string nombreServicio, string tipoServicio)
Updates service information. Parameters:
  • nombreServicio: Updated service name (max 50 chars)
  • tipoServicio: Updated service type (max 50 chars)
Example:
servicio.Actualizar(
    nombreServicio: "Masaje Terapéutico Premium",
    tipoServicio: "Spa Premium"
);

Seasonal Availability Patterns

Year-Round Services

Services with empty TemporadaIds are available in all seasons:
var breakfastService = new ServicioAdicional("Desayuno Continental", "Alimentos");
// No seasons added - available year-round

Seasonal Services

Services restricted to specific seasons:
var poolBar = new ServicioAdicional("Bar de Piscina", "Bebidas");
poolBar.HabilitarEnTemporada(temporadaId: 2); // High season only
poolBar.HabilitarEnTemporada(temporadaId: 4); // Holiday season

Seasonal Transitions

var outdoorDining = new ServicioAdicional("Cena al Aire Libre", "Alimentos");

// Enable for summer
outdoorDining.HabilitarEnTemporada(summerSeasonId);

// Later, extend to spring
outdoorDining.HabilitarEnTemporada(springSeasonId);

// Remove from winter due to weather
outdoorDining.DeshabilitarEnTemporada(winterSeasonId);

Usage in Reservations

Adding Services to Reservations

When adding a service to a reservation:
// From Reserva.AgregarServicio()
var temporadaId = policy.GetTemporadaId(FechaEntrada);
policy.EnsureServicioDisponibleEnTemporada(servicioAdicionalId, temporadaId);
The policy validates availability:
// Policy implementation
var servicio = await _repository.GetServicioById(servicioAdicionalId);

if (!servicio.EstaDisponibleEn(temporadaId))
    throw new BusinessRuleViolationException(
        $"El servicio {servicio.NombreServicio} no está disponible en esta temporada.");

Service Pricing

Services are priced through ServicioCategoriaPrecio entity:
public sealed class ServicioCategoriaPrecio
{
    public int ServicioCategoriaPrecioId { get; private set; }
    public int ServicioAdicionalId { get; private set; }
    public int CategoriaHabitacionId { get; private set; }
    public decimal Precio { get; private set; }
}
Pricing Rule: Service price varies by room category (higher categories = higher service prices).

Price Determination

From reservation policy:
// Get MAX price across all room categories in the reservation
decimal GetPrecioServicioAplicado(int reservaId, int servicioAdicionalId)
{
    var categorias = GetCategoriasInReserva(reservaId);
    var precios = GetPreciosByCategoria(servicioAdicionalId, categorias);
    return precios.Max();
}

Business Rules

  • Services are validated against season availability when added to reservations
  • If a reservation’s dates change to a different season, service availability is re-validated
  • Services with no season restrictions are always available
  • Empty TemporadaIds = available in all seasons
  • Cannot add the same season twice to a service (throws ConflictException)
  • Ensures data integrity and prevents confusion
  • Cannot remove a season that isn’t in the collection (throws NotFoundException)
  • Ensures operations are meaningful and prevent silent failures
From Reserva entity:
  • Services can only be added to reservations with at least one room
  • Ensures proper pricing calculation based on room categories

Common Scenarios

Scenario: Beach activities only in summer
var beachService = new ServicioAdicional(
    "Alquiler de Kayak",
    "Deportes Acuáticos"
);

beachService.HabilitarEnTemporada(summerSeasonId);
beachService.HabilitarEnTemporada(springSeasonId);
Scenario: Breakfast available year-round, priced by room category
var breakfast = new ServicioAdicional("Desayuno Buffet", "Alimentos");
// No seasons added - available always

// Pricing by category
var precioStandard = new ServicioCategoriaPrecio(
    breakfast.ServicioAdicionalId,
    standardCategoryId,
    precio: 15.00m
);

var precioSuite = new ServicioCategoriaPrecio(
    breakfast.ServicioAdicionalId,
    suiteCategoryId,
    precio: 25.00m
);
Scenario: Move outdoor service indoors for winter
var outdoorYoga = await repository.GetServicio(yogaServiceId);
outdoorYoga.DeshabilitarEnTemporada(winterSeasonId);

var indoorYoga = new ServicioAdicional("Yoga en Gimnasio", "Bienestar");
indoorYoga.HabilitarEnTemporada(winterSeasonId);

Service Types Examples

Service NameTipo ServicioSeasonal?
Desayuno BuffetAlimentosNo (Year-round)
Cena RománticaAlimentosNo
MasajeSpaNo
Tour de PlayaExcursionesYes (Summer only)
Ski PassDeportesYes (Winter only)
Transfer AeropuertoTransporteNo
Bar de PiscinaBebidasYes (High season)
Cena al Aire LibreAlimentosYes (Spring/Summer)
  • ReservaServicioAdicional: Links services to reservations with quantity and pricing
  • ServicioCategoriaPrecio: Defines service pricing by room category
  • Temporada: Defines seasonal periods

Build docs developers (and LLMs) love