Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package com.aponia.aponia_hotel.controller.reservas;

import com.aponia.aponia_hotel.controller.reservas.dto.ReservaHabitacionRequest;
import com.aponia.aponia_hotel.controller.reservas.dto.ReservaHabitacionResponse;
import com.aponia.aponia_hotel.entities.reservas.Reserva;
import com.aponia.aponia_hotel.service.reservas.ReservaService;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
Expand Down Expand Up @@ -73,6 +77,23 @@ public double total(@PathVariable String id) {
return service.calcularTotalReserva(id);
}

@PostMapping("/cliente/{clienteId}/habitaciones")
@Operation(summary = "Permite a un cliente crear una reserva para un tipo de habitación")
public ResponseEntity<ReservaHabitacionResponse> reservarHabitacion(
@PathVariable String clienteId,
@RequestBody ReservaHabitacionRequest request) {
Reserva reserva = service.crearReservaCliente(
clienteId,
request.tipoHabitacionId(),
request.entrada(),
request.salida(),
request.numeroHuespedes(),
request.notas()
);
return ResponseEntity.status(HttpStatus.CREATED)
.body(ReservaHabitacionResponse.fromReserva(reserva));
}

// ===== Mutaciones =====

@PostMapping("/add")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.aponia.aponia_hotel.controller.reservas.dto;

import java.time.LocalDate;

public record ReservaHabitacionRequest(
String tipoHabitacionId,
LocalDate entrada,
LocalDate salida,
Integer numeroHuespedes,
String notas
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.aponia.aponia_hotel.controller.reservas.dto;

import com.aponia.aponia_hotel.entities.reservas.Estancia;
import com.aponia.aponia_hotel.entities.reservas.Reserva;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

public record ReservaHabitacionResponse(
String reservaId,
String codigo,
LocalDateTime fechaCreacion,
Reserva.EstadoReserva estado,
LocalDate entrada,
LocalDate salida,
Integer numeroHuespedes,
String tipoHabitacionId,
String tipoHabitacionNombre,
BigDecimal precioPorNoche,
BigDecimal totalEstadia,
BigDecimal totalReserva
) {
public static ReservaHabitacionResponse fromReserva(Reserva reserva) {
if (reserva == null) {
throw new IllegalArgumentException("La reserva no puede ser nula");
}
List<Estancia> estancias = reserva.getEstancias();
if (estancias == null || estancias.isEmpty()) {
throw new IllegalArgumentException("La reserva no contiene estancias asociadas");
}
Estancia estancia = estancias.get(0);
BigDecimal totalReserva = null;
if (reserva.getResumenPago() != null && reserva.getResumenPago().getTotalReserva() != null) {
totalReserva = reserva.getResumenPago().getTotalReserva();
} else if (estancia.getTotalEstadia() != null) {
totalReserva = estancia.getTotalEstadia();
}

return new ReservaHabitacionResponse(
reserva.getId(),
reserva.getCodigo(),
reserva.getFechaCreacion(),
reserva.getEstado(),
estancia.getEntrada(),
estancia.getSalida(),
estancia.getNumeroHuespedes(),
estancia.getTipoHabitacion() != null ? estancia.getTipoHabitacion().getId() : null,
estancia.getTipoHabitacion() != null ? estancia.getTipoHabitacion().getNombre() : null,
estancia.getPrecioPorNoche(),
estancia.getTotalEstadia(),
totalReserva
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ public class ResumenPago {
@Column(name = "ultima_actualizacion", nullable = false)
private LocalDateTime ultimaActualizacion;

public void setReserva(Reserva reserva) {
this.reserva = reserva;
if (reserva != null) {
this.reservaId = reserva.getId();
}
}

@PrePersist
@PreUpdate
public void validate() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ public class Estancia {
private String id;

@Column(name = "check_in", nullable = false)
private Boolean checkIn;
private Boolean checkIn = Boolean.FALSE;

@Column(name = "check_out", nullable = false)
private Boolean checkOut;
private Boolean checkOut = Boolean.FALSE;

@Column(name = "entrada", nullable = false)
private LocalDate entrada;
Expand Down Expand Up @@ -83,6 +83,7 @@ public void validate() {
throw new IllegalStateException("El total de la estadía debe ser no negativo");
}
if (tipoHabitacion == null) {
throw new IllegalStateException("El tipo de habitación es requerido");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import lombok.AllArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import java.time.LocalDateTime;
import java.util.List;
Expand All @@ -32,6 +33,7 @@ public class Reserva {

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "cliente_id", nullable = false)
@JsonIgnoreProperties({"passwordHash", "empleadoPerfil", "clientePerfil", "hibernateLazyInitializer", "handler"})
private Usuario cliente;

@CreationTimestamp
Expand All @@ -57,7 +59,7 @@ public class Reserva {
@JsonIgnore
private List<Pago> pagos;

@OneToOne(mappedBy = "reserva", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@OneToOne(mappedBy = "reserva", fetch = FetchType.LAZY)
@JsonIgnore
private ResumenPago resumenPago;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ AND NOT EXISTS (
FROM Estancia e
WHERE e.habitacionAsignada.id = h.id
AND e.reserva.estado = 'CONFIRMADA'
AND (e.salida <= :entrada AND e.salida >= :entrada)
AND (e.entrada < :salida AND e.salida > :entrada)
)
ORDER BY h.numero
""")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public interface EstanciaRepository extends JpaRepository<Estancia, String> {
@Query("SELECT COUNT(DISTINCT e.habitacionAsignada) FROM Estancia e " +
"WHERE e.tipoHabitacion.id = :tipoHabitacionId " +
"AND e.reserva.estado = 'CONFIRMADA' " +
"AND ((e.checkIn <= :checkOut AND e.checkOut >= :checkIn))")
"AND (e.entrada < :checkOut AND e.salida > :checkIn)")
long contarHabitacionesOcupadas(
@Param("tipoHabitacionId") String tipoHabitacionId,
@Param("checkIn") LocalDate checkIn,
Expand All @@ -24,7 +24,7 @@ long contarHabitacionesOcupadas(
@Query("SELECT e FROM Estancia e " +
"WHERE e.habitacionAsignada.id = :habitacionId " +
"AND e.reserva.estado = 'CONFIRMADA' " +
"AND ((e.checkIn <= :checkOut AND e.checkOut >= :checkIn))")
"AND (e.entrada < :checkOut AND e.salida > :checkIn)")
List<Estancia> findOverlappingStays(
@Param("habitacionId") String habitacionId,
@Param("checkIn") LocalDate checkIn,
Expand All @@ -33,15 +33,15 @@ List<Estancia> findOverlappingStays(
@Query("SELECT e FROM Estancia e " +
"WHERE e.tipoHabitacion.id = :tipoHabitacionId " +
"AND e.reserva.estado = 'CONFIRMADA' " +
"AND e.checkIn = :fecha")
"AND e.entrada = :fecha")
List<Estancia> findCheckinsByTipoHabitacionAndFecha(
@Param("tipoHabitacionId") String tipoHabitacionId,
@Param("fecha") LocalDate fecha);

@Query("SELECT e FROM Estancia e " +
"WHERE e.tipoHabitacion.id = :tipoHabitacionId " +
"AND e.reserva.estado = 'CONFIRMADA' " +
"AND e.checkOut = :fecha")
"AND e.salida = :fecha")
List<Estancia> findCheckoutsByTipoHabitacionAndFecha(
@Param("tipoHabitacionId") String tipoHabitacionId,
@Param("fecha") LocalDate fecha);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@ public List<Estancia> buscarConflictosFechas(String habitacionId, LocalDate chec
}

private void validarEstancia(Estancia estancia) {
if (estancia.getCheckIn() == null || estancia.getCheckOut() == null) {
throw new IllegalArgumentException("Las fechas de check-in y check-out son requeridas");
if (estancia.getEntrada() == null || estancia.getSalida() == null) {
throw new IllegalArgumentException("Las fechas de entrada y salida son requeridas");
}
if (!estancia.getSalida().isAfter(estancia.getEntrada())) {
throw new IllegalArgumentException("La fecha de check-out debe ser posterior a la de check-in");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ public interface ReservaService {
public void completarReserva(String id);
public boolean verificarDisponibilidad(String tipoHabitacionId, LocalDate entrada, LocalDate salida, int numeroHuespedes);
public double calcularTotalReserva(String id);
Reserva crearReservaCliente(String clienteId, String tipoHabitacionId, LocalDate entrada, LocalDate salida, Integer numeroHuespedes, String notas);
}
Loading