Commit 5fbba8ae by Antonio Rueda

Añadido endpoint para obtener las reservas en un periodo dado de un

usuario o totales
parent 48eaf4ef
...@@ -167,7 +167,7 @@ public class Hotel { ...@@ -167,7 +167,7 @@ public class Hotel {
* @return la lista de reservas * @return la lista de reservas
*/ */
public List<Reserva> reservasEntre(LocalDate fechaInicio, LocalDate fechaFin) { public List<Reserva> reservasEntre(LocalDate fechaInicio, LocalDate fechaFin) {
return reservas.stream().filter(r -> r.fechaInicio().isBefore(fechaFin) return reservas.stream().filter(r -> (r.fechaInicio().isBefore(fechaFin))
&& r.fechaFin().isAfter(fechaInicio)).toList(); && r.fechaFin().isAfter(fechaInicio)).toList();
} }
......
...@@ -6,7 +6,6 @@ import static es.ujaen.dae.reservahoteles.util.UtilString.normalizar; ...@@ -6,7 +6,6 @@ import static es.ujaen.dae.reservahoteles.util.UtilString.normalizar;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import jakarta.persistence.LockModeType; import jakarta.persistence.LockModeType;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CacheEvict;
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
package es.ujaen.dae.reservahoteles.rest; package es.ujaen.dae.reservahoteles.rest;
import es.ujaen.dae.reservahoteles.entidades.Hotel; import es.ujaen.dae.reservahoteles.entidades.Hotel;
import es.ujaen.dae.reservahoteles.entidades.Reserva;
import es.ujaen.dae.reservahoteles.entidades.Usuario; import es.ujaen.dae.reservahoteles.entidades.Usuario;
import es.ujaen.dae.reservahoteles.excepciones.HotelNoRegistrado; import es.ujaen.dae.reservahoteles.excepciones.HotelNoRegistrado;
import es.ujaen.dae.reservahoteles.excepciones.NoDisponibilidadReserva; import es.ujaen.dae.reservahoteles.excepciones.NoDisponibilidadReserva;
...@@ -13,8 +14,10 @@ import es.ujaen.dae.reservahoteles.rest.dto.DHotel; ...@@ -13,8 +14,10 @@ import es.ujaen.dae.reservahoteles.rest.dto.DHotel;
import es.ujaen.dae.reservahoteles.rest.dto.DReserva; import es.ujaen.dae.reservahoteles.rest.dto.DReserva;
import es.ujaen.dae.reservahoteles.rest.dto.DUsuario; import es.ujaen.dae.reservahoteles.rest.dto.DUsuario;
import es.ujaen.dae.reservahoteles.rest.dto.Mapeador; import es.ujaen.dae.reservahoteles.rest.dto.Mapeador;
import es.ujaen.dae.reservahoteles.seguridad.ServicioCredencialesUsuario;
import es.ujaen.dae.reservahoteles.servicios.ServicioReservas; import es.ujaen.dae.reservahoteles.servicios.ServicioReservas;
import jakarta.validation.ConstraintViolationException; import jakarta.validation.ConstraintViolationException;
import java.security.Principal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -43,6 +46,9 @@ public class ControladorReservas { ...@@ -43,6 +46,9 @@ public class ControladorReservas {
@Autowired @Autowired
ServicioReservas servicioReservas; ServicioReservas servicioReservas;
@Autowired
ServicioCredencialesUsuario servicioCredencialesUsuario;
// Definir un mapeado global para cualquier excepción de validación de beans // Definir un mapeado global para cualquier excepción de validación de beans
@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY) @ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
@ExceptionHandler(ConstraintViolationException.class) @ExceptionHandler(ConstraintViolationException.class)
...@@ -94,7 +100,7 @@ public class ControladorReservas { ...@@ -94,7 +100,7 @@ public class ControladorReservas {
List<Hotel> hoteles; List<Hotel> hoteles;
if (nombre != null) { if (nombre != null) {
hoteles = servicioReservas.buscarHotel(nombre, localidad).stream() hoteles = servicioReservas.buscarHotel(nombre, localidad).stream()
.filter(h -> h.disponible(desdeFinal, hastaFinal, numHabSimple, numHabDoble)).toList(); .filter(h -> servicioReservas.disponible(h, desdeFinal, hastaFinal, numHabSimple, numHabDoble)).toList();
} }
else { else {
hoteles = servicioReservas.buscarHotelesDisponiblesPorLocalidad(localidad, desdeFinal, hastaFinal, numHabSimple, numHabDoble); hoteles = servicioReservas.buscarHotelesDisponiblesPorLocalidad(localidad, desdeFinal, hastaFinal, numHabSimple, numHabDoble);
...@@ -103,11 +109,11 @@ public class ControladorReservas { ...@@ -103,11 +109,11 @@ public class ControladorReservas {
return ResponseEntity.ok(hoteles.stream().map(h -> mapeador.dto(h)).toList()); return ResponseEntity.ok(hoteles.stream().map(h -> mapeador.dto(h)).toList());
} }
@GetMapping("/hoteles/{id}") @GetMapping("/hoteles/{idHotel}")
public ResponseEntity<DHotel> buscarHotel(@PathVariable int id) { public ResponseEntity<DHotel> buscarHotel(@PathVariable int idHotel) {
try { try {
Hotel hotel = servicioReservas.buscarHotel(id).orElseThrow(HotelNoRegistrado::new); Hotel hotel = servicioReservas.buscarHotel(idHotel).orElseThrow(HotelNoRegistrado::new);
return ResponseEntity.ok(mapeador.dto(hotel)); return ResponseEntity.ok(mapeador.dto(hotel));
} }
catch(HotelNoRegistrado e) { catch(HotelNoRegistrado e) {
...@@ -115,26 +121,26 @@ public class ControladorReservas { ...@@ -115,26 +121,26 @@ public class ControladorReservas {
} }
} }
@GetMapping("/hoteles/{id}/disponibilidad") @GetMapping("/hoteles/{idHotel}/disponibilidad")
public ResponseEntity<DDisponibilidad> verDisponibilidadHotel(@PathVariable int id, public ResponseEntity<DDisponibilidad> verDisponibilidadHotel(@PathVariable int idHotel,
@RequestParam LocalDate desde, @RequestParam LocalDate desde,
@RequestParam LocalDate hasta) { @RequestParam LocalDate hasta) {
final var desdeFinal = desde != null ? desde : LocalDate.now(); final var desdeFinal = desde != null ? desde : LocalDate.now();
final var hastaFinal = hasta != null ? hasta : LocalDate.MAX; final var hastaFinal = hasta != null ? hasta : LocalDate.MAX;
try { try {
Hotel hotel = servicioReservas.buscarHotel(id).orElseThrow(HotelNoRegistrado::new); Hotel hotel = servicioReservas.buscarHotel(idHotel).orElseThrow(HotelNoRegistrado::new);
return ResponseEntity.ok(mapeador.dto(hotel.disponibilidad(desdeFinal, hastaFinal))); return ResponseEntity.ok(mapeador.dto(servicioReservas.disponibilidad(hotel, desdeFinal, hastaFinal)));
} }
catch(HotelNoRegistrado e) { catch(HotelNoRegistrado e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
} }
} }
@PostMapping("/hoteles/{id}/reservas") @PostMapping("/hoteles/{idHotel}/reservas")
public ResponseEntity<DReserva> reserva(@PathVariable int id, @RequestBody DReserva reserva) { public ResponseEntity<DReserva> reserva(@PathVariable int idHotel, @RequestBody DReserva reserva) {
try { try {
Hotel hotel = servicioReservas.buscarHotel(id).orElseThrow(HotelNoRegistrado::new); Hotel hotel = servicioReservas.buscarHotel(idHotel).orElseThrow(HotelNoRegistrado::new);
Usuario usuario = servicioReservas.buscarUsuario(reserva.emailUsuario()).orElseThrow(UsuarioNoRegistrado::new); Usuario usuario = servicioReservas.buscarUsuario(reserva.emailUsuario()).orElseThrow(UsuarioNoRegistrado::new);
return ResponseEntity.status(HttpStatus.CREATED).body(mapeador.dto(servicioReservas.reserva( return ResponseEntity.status(HttpStatus.CREATED).body(mapeador.dto(servicioReservas.reserva(
...@@ -156,4 +162,34 @@ public class ControladorReservas { ...@@ -156,4 +162,34 @@ public class ControladorReservas {
return ResponseEntity.status(HttpStatus.CONFLICT).build(); return ResponseEntity.status(HttpStatus.CONFLICT).build();
} }
} }
@GetMapping("/hoteles/{idHotel}/reservas")
public ResponseEntity<List<DReserva>> verReservas(@PathVariable int idHotel,
@RequestParam(required=false) LocalDate desde,
@RequestParam(required=false) LocalDate hasta,
Principal usuarioAutenticado) {
final var desdeFinal = desde != null ? desde : LocalDate.now();
final var hastaFinal = hasta != null ? hasta : LocalDate.MAX;
List<Reserva> reservas;
try {
Hotel hotel = servicioReservas.buscarHotel(idHotel).orElseThrow(HotelNoRegistrado::new);
var esDireccion = servicioCredencialesUsuario.loadUserByUsername(usuarioAutenticado.getName())
.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("DIRECCION"));
if (esDireccion)
reservas = servicioReservas.verReservas(hotel, desdeFinal, hastaFinal);
else {
var usuario = servicioReservas.buscarUsuario(usuarioAutenticado.getName()).get();
reservas = servicioReservas.verReservas(hotel, desdeFinal, hastaFinal, usuario);
}
}
catch(HotelNoRegistrado e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
return ResponseEntity.ok(reservas.stream().map(reserva -> mapeador.dto(reserva)).toList());
}
} }
package es.ujaen.dae.reservahoteles.servicios; package es.ujaen.dae.reservahoteles.servicios;
import es.ujaen.dae.reservahoteles.excepciones.OperacionDeDireccion;
import es.ujaen.dae.reservahoteles.entidades.Usuario; import es.ujaen.dae.reservahoteles.entidades.Usuario;
import es.ujaen.dae.reservahoteles.entidades.Hotel; import es.ujaen.dae.reservahoteles.entidades.Hotel;
import es.ujaen.dae.reservahoteles.entidades.Reserva; import es.ujaen.dae.reservahoteles.entidades.Reserva;
...@@ -10,7 +9,6 @@ import es.ujaen.dae.reservahoteles.repositorios.RepositorioHoteles; ...@@ -10,7 +9,6 @@ import es.ujaen.dae.reservahoteles.repositorios.RepositorioHoteles;
import es.ujaen.dae.reservahoteles.repositorios.RepositorioUsuarios; import es.ujaen.dae.reservahoteles.repositorios.RepositorioUsuarios;
import es.ujaen.dae.reservahoteles.util.UtilString; import es.ujaen.dae.reservahoteles.util.UtilString;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Future; import jakarta.validation.constraints.Future;
import jakarta.validation.constraints.FutureOrPresent; import jakarta.validation.constraints.FutureOrPresent;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
...@@ -69,6 +67,11 @@ public class ServicioReservas { ...@@ -69,6 +67,11 @@ public class ServicioReservas {
return repositorioClientes.buscar(email).filter(cliente -> cliente.clave().equals(clave)); return repositorioClientes.buscar(email).filter(cliente -> cliente.clave().equals(clave));
} }
*/ */
/**
* Devolver el usuario asociado al e-mail dado
* @param email el e-mail del usuario
* @return un optional con el usuario asociado al e-mail
*/
public Optional<Usuario> buscarUsuario(String email) { public Optional<Usuario> buscarUsuario(String email) {
if (email.equals(direccion.email())) if (email.equals(direccion.email()))
return Optional.of(direccion); return Optional.of(direccion);
...@@ -146,6 +149,27 @@ public class ServicioReservas { ...@@ -146,6 +149,27 @@ public class ServicioReservas {
hotel = repositorioHoteles.actualizar(hotel); hotel = repositorioHoteles.actualizar(hotel);
return hotel.disponibilidad(fechaInicio, fechaFin); return hotel.disponibilidad(fechaInicio, fechaFin);
} }
/**
* Indica si el hotel está disponible en las fechas indicadas
* @param hotel hotel donde se compreuba la disponibilidad
* @param fechaInicio fecha de inicio de la reserva
* @param fechaFin fecha de final de la reserva
* @param numHabSimple número de habitaciones simples solicitadas
* @param numHabDoble número de habitaciones dobles solicitadas *
* @return true si el hotel está disponible en las fechas indicadas; false en caso contrario
*/
@Transactional
public boolean disponible(Hotel hotel,
@FutureOrPresent LocalDate fechaInicio,
@FutureOrPresent LocalDate fechaFin,
@PositiveOrZero int numHabSimple,
@PositiveOrZero int numHabDoble) {
hotel = repositorioHoteles.actualizar(hotel);
var disponibilidad = hotel.disponibilidad(fechaInicio, fechaFin);
return disponibilidad.numHabSimple() >= numHabSimple
&& disponibilidad.numHabDoble() >= numHabDoble;
}
/** /**
* Realiza una reserva en un hotel. La reserva debe ser correcta y haber disponibilidad. * Realiza una reserva en un hotel. La reserva debe ser correcta y haber disponibilidad.
...@@ -205,6 +229,32 @@ public class ServicioReservas { ...@@ -205,6 +229,32 @@ public class ServicioReservas {
return reserva; return reserva;
} }
/**
* Devuelve las reservas del hotel indicado entre dos fechas
* @param hotel el hotel a consultar
* @param fechaInicio fecha de inicio
* @param fechaFin fecha final
* @return una lista con las reservas del hotel en el periodo indicado
*/
@Transactional
public List<Reserva> verReservas(Hotel hotel, LocalDate fechaInicio, LocalDate fechaFin) {
hotel = repositorioHoteles.actualizar(hotel);
return hotel.reservasEntre(fechaInicio, fechaFin);
}
/**
* Devuelve las reservas en el hotel del usuario indicado entre dos fechas
* @param hotel el hotel a consultar
* @param fechaInicio fecha de inicio
* @param fechaFin fecha final
* @param usuario el usuario que realiza la reserva
* @return una lista con las reservas del usuario en el hotel y en el periodo indicado
*/
@Transactional
public List<Reserva> verReservas(Hotel hotel, LocalDate fechaInicio, LocalDate fechaFin, Usuario usuario) {
return verReservas(hotel, fechaInicio, fechaFin).stream().filter(reserva -> reserva.cliente().equals(usuario)).toList();
}
@Transactional @Transactional
@Scheduled(cron="0 0 0 1 * ?") @Scheduled(cron="0 0 0 1 * ?")
public void eliminarReservasAntiguas() { public void eliminarReservasAntiguas() {
......
...@@ -226,4 +226,51 @@ public class TestControladorReservas { ...@@ -226,4 +226,51 @@ public class TestControladorReservas {
assertThat(respuestaReserva.getStatusCode()).isEqualTo(HttpStatus.CREATED); assertThat(respuestaReserva.getStatusCode()).isEqualTo(HttpStatus.CREATED);
} }
}
@Test
@DirtiesContext
void testConsultaReservasHotel() {
var hotel = new DHotel(0, "Bed and Breakfast Almería", "Almería", "Almería", "04001", 2, 2, 60, 100);
restTemplate.withBasicAuth("direccion@hotelxyz.es", "SeCrEtO").postForEntity(
"/hoteles",
hotel,
DHotel.class
);
var usuario = new DUsuario("Pedro", "Jaén Jaén", "611203025", "pjaen@gmail.com", "miClAvE");
restTemplate.postForEntity(
"/usuarios",
usuario,
Void.class
);
var hotelGuardado = restTemplate.getForEntity(
"/hoteles?nombre={nombre}&localidad={localidad}",
DHotel[].class,
"bed and breakfast",
" almeria"
).getBody()[0];
var reserva = new DReserva(0,
LocalDate.now().plusDays(7),
LocalDate.now().plusDays(10), 0, 1,
usuario.email());
restTemplate.withBasicAuth(usuario.email(), usuario.clave()).postForEntity(
"/hoteles/{id}/reservas",
reserva,
DReserva.class,
hotelGuardado.id()
);
var respuestaConsultaReservas = restTemplate.withBasicAuth(usuario.email(), usuario.clave()).getForEntity(
"/hoteles/{id}/reservas",
DReserva[].class,
hotelGuardado.id()
);
assertThat(respuestaConsultaReservas.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(respuestaConsultaReservas.getBody()).hasSize(1);
assertThat(respuestaConsultaReservas.getBody()[0].numHabDoble()).isEqualTo(1);
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment