Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Antonio Rueda
/
reserva-hoteles
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
f6093cdb
authored
Dec 09, 2024
by
Antonio Rueda
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge branch 'master' of
https://gitlab.ujaen.es/ajrueda/reserva-hoteles
parents
a8cd1c43
fd486b02
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
235 additions
and
43 deletions
src/main/java/es/ujaen/dae/reservahoteles/app/ReservaHoteles.java
src/main/java/es/ujaen/dae/reservahoteles/entidades/Hotel.java
src/main/java/es/ujaen/dae/reservahoteles/excepciones/HotelNoRegistrado.java
src/main/java/es/ujaen/dae/reservahoteles/rest/ControladorReservas.java
src/main/java/es/ujaen/dae/reservahoteles/rest/dto/DDisponibilidad.java
src/main/java/es/ujaen/dae/reservahoteles/rest/dto/Mapeador.java
src/main/java/es/ujaen/dae/reservahoteles/servicios/ServicioReservas.java
src/test/java/es/ujaen/dae/reservahoteles/rest/TestControladorReservas.java
src/main/java/es/ujaen/dae/reservahoteles/app/ReservaHoteles.java
View file @
f6093cdb
...
...
@@ -5,7 +5,10 @@ import org.springframework.boot.SpringApplication;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
import
org.springframework.boot.autoconfigure.domain.EntityScan
;
import
org.springframework.cache.annotation.EnableCaching
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.scheduling.annotation.EnableScheduling
;
import
org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
;
import
org.springframework.security.crypto.password.PasswordEncoder
;
/**
*
...
...
@@ -19,7 +22,12 @@ import org.springframework.scheduling.annotation.EnableScheduling;
@EntityScan
(
basePackages
=
"es.ujaen.dae.reservahoteles.entidades"
)
@EnableScheduling
@EnableCaching
public
class
ReservaHoteles
{
public
class
ReservaHoteles
{
@Bean
PasswordEncoder
passwordEncoder
()
{
return
new
BCryptPasswordEncoder
();
}
public
static
void
main
(
String
[]
args
)
{
SpringApplication
.
run
(
ReservaHoteles
.
class
);
}
...
...
src/main/java/es/ujaen/dae/reservahoteles/entidades/Hotel.java
View file @
f6093cdb
...
...
@@ -24,6 +24,9 @@ import java.util.List;
*/
@Entity
public
class
Hotel
{
public
static
record
Disponibilidad
(
int
numHabSimple
,
int
numHabDoble
)
{}
@Id
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
int
id
;
...
...
@@ -102,36 +105,48 @@ public class Hotel {
}
/**
*
Comprueba si hay
disponibilidad en las fechas indicadas
*
Devuelve la
disponibilidad en las fechas indicadas
* @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 hay disponibilidad, false en caso contrario
* @return la disponibilidad en las fechas indicadas
*/
public
boolean
disponible
(
LocalDate
fechaInicio
,
LocalDate
fechaFin
,
int
numHabSimple
,
int
numHabDoble
)
{
public
Disponibilidad
disponibilidad
(
LocalDate
fechaInicio
,
LocalDate
fechaFin
)
{
// Obtener la fecha máxima donde hay registrada una reserva
final
var
fechaMax
=
reservas
.
stream
()
.
map
(
r
->
r
.
fechaFin
)
.
max
(
LocalDate:
:
compareTo
)
.
map
(
f
->
f
.
isBefore
(
fechaFin
)
?
f
:
fechaFin
)
.
orElse
(
LocalDate
.
now
());
for
(
var
fecha
=
fechaInicio
.
plusDays
(
0
);
fecha
.
isBefore
(
fechaMax
);
fecha
=
fecha
.
plusDays
(
1
))
if
(!
disponible
(
fecha
,
numHabSimple
,
numHabDoble
))
return
false
;
return
true
;
int
numHabSimpleDisponibles
=
numHabSimple
;
int
numHabDobleDisponibles
=
numHabDoble
;
for
(
var
fecha
=
fechaInicio
.
plusDays
(
0
);
fecha
.
isBefore
(
fechaMax
);
fecha
=
fecha
.
plusDays
(
1
))
{
var
disponibilidadDia
=
disponibilidad
(
fecha
);
numHabSimpleDisponibles
=
Integer
.
min
(
numHabSimpleDisponibles
,
disponibilidadDia
.
numHabSimple
);
numHabDobleDisponibles
=
Integer
.
min
(
numHabDobleDisponibles
,
disponibilidadDia
.
numHabDoble
);
}
return
new
Disponibilidad
(
numHabSimpleDisponibles
,
numHabDobleDisponibles
);
}
/**
* Comprueba si hay disponibilidad en un día concreto
* @param fecha día a comprobar
/**
* Indica si el hotel está disponible en las fechas indicadas
* @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 hay disponibilidad, false en caso contrario
* @return true si el hotel está disponible
*/
public
boolean
disponible
(
LocalDate
fechaInicio
,
LocalDate
fechaFin
,
int
numHabSimple
,
int
numHabDoble
)
{
var
disponibilidad
=
disponibilidad
(
fechaInicio
,
fechaFin
);
return
disponibilidad
.
numHabSimple
>=
numHabSimple
&&
disponibilidad
.
numHabDoble
>
numHabDoble
;
}
/**
* Devuelve la disponibilidad en un día concreto
* @param fecha día a comprobar
* @return la disponibilidad en la fecha dada
*/
public
boolean
disponible
(
LocalDate
fecha
,
int
numHabSimple
,
int
numHabDoble
)
{
public
Disponibilidad
disponibilidad
(
LocalDate
fecha
)
{
int
numHabSimpleDisponibles
=
numHabSimple
;
int
numHabDobleDisponibles
=
numHabDoble
;
...
...
@@ -142,9 +157,9 @@ public class Hotel {
}
}
return
n
umHabSimpleDisponibles
>=
numHabSimple
&&
numHabDobleDisponibles
>=
numHabDoble
;
return
n
ew
Disponibilidad
(
numHabSimpleDisponibles
,
numHabDobleDisponibles
)
;
}
/**
* Devolver las reservas que solapan el intervalo dado
* @param fechaInicio fecha de inicio
...
...
src/main/java/es/ujaen/dae/reservahoteles/excepciones/HotelNoRegistrado.java
0 → 100644
View file @
f6093cdb
package
es
.
ujaen
.
dae
.
reservahoteles
.
excepciones
;
/**
*
* @author ajrueda
*/
public
class
HotelNoRegistrado
extends
RuntimeException
{
public
HotelNoRegistrado
()
{
}
}
src/main/java/es/ujaen/dae/reservahoteles/rest/ControladorReservas.java
View file @
f6093cdb
...
...
@@ -3,9 +3,12 @@ package es.ujaen.dae.reservahoteles.rest;
import
es.ujaen.dae.reservahoteles.entidades.Hotel
;
import
es.ujaen.dae.reservahoteles.entidades.Usuario
;
import
es.ujaen.dae.reservahoteles.excepciones.HotelNoRegistrado
;
import
es.ujaen.dae.reservahoteles.excepciones.UsuarioNoRegistrado
;
import
es.ujaen.dae.reservahoteles.excepciones.UsuarioYaRegistrado
;
import
es.ujaen.dae.reservahoteles.rest.dto.DDisponibilidad
;
import
es.ujaen.dae.reservahoteles.rest.dto.DHotel
;
import
es.ujaen.dae.reservahoteles.rest.dto.DReserva
;
import
es.ujaen.dae.reservahoteles.rest.dto.DUsuario
;
import
es.ujaen.dae.reservahoteles.rest.dto.Mapeador
;
import
es.ujaen.dae.reservahoteles.servicios.ServicioReservas
;
...
...
@@ -97,12 +100,60 @@ public class ControladorReservas {
List
<
Hotel
>
hoteles
;
if
(
nombre
!=
null
)
{
hoteles
=
servicioReservas
.
buscarHotel
(
nombre
,
localidad
).
stream
()
.
filter
(
h
->
servicioReservas
.
disponible
(
h
,
desdeFinal
,
hastaFinal
,
numHabSimple
,
numHabDoble
)).
toList
();
.
filter
(
h
->
h
.
disponible
(
desdeFinal
,
hastaFinal
,
numHabSimple
,
numHabDoble
)).
toList
();
}
else
{
hoteles
=
servicioReservas
.
buscarHotelesDisponiblesPorLocalidad
(
localidad
,
desdeFinal
,
hastaFinal
,
numHabSimple
,
numHabDoble
);
}
return
ResponseEntity
.
ok
(
hoteles
.
stream
().
map
(
h
->
mapeador
.
dto
(
h
)).
toList
());
}
}
@GetMapping
(
"/hoteles/{id}"
)
public
ResponseEntity
<
DHotel
>
buscarHotel
(
@PathVariable
int
id
)
{
try
{
Hotel
hotel
=
servicioReservas
.
buscarHotel
(
id
).
orElseThrow
(
HotelNoRegistrado:
:
new
);
return
ResponseEntity
.
ok
(
mapeador
.
dto
(
hotel
));
}
catch
(
HotelNoRegistrado
e
)
{
return
ResponseEntity
.
status
(
HttpStatus
.
NOT_FOUND
).
build
();
}
}
@GetMapping
(
"/hoteles/{id}/disponibilidad"
)
public
ResponseEntity
<
DDisponibilidad
>
verDisponibilidadHotel
(
@PathVariable
int
id
,
@RequestParam
LocalDate
desde
,
@RequestParam
LocalDate
hasta
)
{
final
var
desdeFinal
=
desde
!=
null
?
desde
:
LocalDate
.
now
();
final
var
hastaFinal
=
hasta
!=
null
?
hasta
:
LocalDate
.
MAX
;
try
{
Hotel
hotel
=
servicioReservas
.
buscarHotel
(
id
).
orElseThrow
(
HotelNoRegistrado:
:
new
);
return
ResponseEntity
.
ok
(
mapeador
.
dto
(
hotel
.
disponibilidad
(
desdeFinal
,
hastaFinal
)));
}
catch
(
HotelNoRegistrado
e
)
{
return
ResponseEntity
.
status
(
HttpStatus
.
NOT_FOUND
).
build
();
}
}
@PostMapping
(
"/hoteles/{id}/reservas"
)
public
ResponseEntity
<
DReserva
>
reserva
(
@PathVariable
int
id
,
@RequestBody
DReserva
reserva
)
{
try
{
Hotel
hotel
=
servicioReservas
.
buscarHotel
(
id
).
orElseThrow
(
HotelNoRegistrado:
:
new
);
Usuario
usuario
=
servicioReservas
.
buscarUsuario
(
reserva
.
emailUsuario
()).
orElseThrow
(
UsuarioNoRegistrado:
:
new
);
return
ResponseEntity
.
status
(
HttpStatus
.
CREATED
).
body
(
mapeador
.
dto
(
servicioReservas
.
reserva
(
usuario
,
hotel
,
reserva
.
fechaInicio
(),
reserva
.
fechaFin
(),
reserva
.
numHabSimple
(),
reserva
.
numHabDoble
()
)));
}
catch
(
HotelNoRegistrado
|
UsuarioNoRegistrado
e
)
{
return
ResponseEntity
.
status
(
HttpStatus
.
NOT_FOUND
).
build
();
}
}
}
src/main/java/es/ujaen/dae/reservahoteles/rest/dto/DDisponibilidad.java
0 → 100644
View file @
f6093cdb
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Record.java to edit this template
*/
package
es
.
ujaen
.
dae
.
reservahoteles
.
rest
.
dto
;
/**
*
* @author administrador
*/
public
record
DDisponibilidad
(
int
numHabSimple
,
int
numHabDoble
)
{
}
src/main/java/es/ujaen/dae/reservahoteles/rest/dto/Mapeador.java
View file @
f6093cdb
...
...
@@ -105,5 +105,13 @@ public class Mapeador {
dReserva
.
fechaFin
(),
dReserva
.
numHabSimple
(),
dReserva
.
numHabDoble
());
}
public
DDisponibilidad
dto
(
Hotel
.
Disponibilidad
disponibilidad
)
{
return
new
DDisponibilidad
(
disponibilidad
.
numHabSimple
(),
disponibilidad
.
numHabDoble
());
}
public
Hotel
.
Disponibilidad
objetoValor
(
DDisponibilidad
disponibilidad
)
{
return
new
Hotel
.
Disponibilidad
(
disponibilidad
.
numHabSimple
(),
disponibilidad
.
numHabDoble
());
}
}
src/main/java/es/ujaen/dae/reservahoteles/servicios/ServicioReservas.java
View file @
f6093cdb
...
...
@@ -70,6 +70,10 @@ public class ServicioReservas {
return
repositorioClientes
.
buscar
(
email
).
filter
(
cliente
->
cliente
.
clave
().
equals
(
clave
));
}
public
Optional
<
Usuario
>
buscarUsuario
(
@Email
String
email
)
{
return
repositorioClientes
.
buscar
(
email
);
}
/**
* Búsqueda de hoteles disponibles en una localidad
...
...
@@ -105,6 +109,15 @@ public class ServicioReservas {
}
/**
* Búsqueda de hoteles por id
* @param id el nombre del hotel
* @return El hotel solicitado
*/
public
Optional
<
Hotel
>
buscarHotel
(
int
id
)
{
return
repositorioHoteles
.
buscarPorId
(
id
);
}
/**
* Carga las reservas de un hotel
* @param hotel el hotel cuyas lista de reservas se va a cargar
* @return el hotel con las reservas
...
...
@@ -113,31 +126,26 @@ public class ServicioReservas {
public
Hotel
hotelConReservas
(
Hotel
hotel
)
{
hotel
=
repositorioHoteles
.
actualizar
(
hotel
);
// Usar cualquier operación que acceda a las reservas para que se carguen
hotel
.
disponib
le
(
LocalDate
.
now
(),
1
,
1
);
hotel
.
disponib
ilidad
(
LocalDate
.
now
()
);
return
hotel
;
}
/**
*
Comprueba si hay
disponibilidad en las fechas indicadas
/**
*
Devuelve la
disponibilidad 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 hay disponibilidad, false en caso contrario
* @return la disponibilidad en las fechas indicadas
*/
@Transactional
public
boolean
disponible
(
Hotel
hotel
,
public
Hotel
.
Disponibilidad
disponibilidad
(
Hotel
hotel
,
@FutureOrPresent
LocalDate
fechaInicio
,
@FutureOrPresent
LocalDate
fechaFin
,
@PositiveOrZero
int
numHabSimple
,
@PositiveOrZero
int
numHabDoble
)
{
@FutureOrPresent
LocalDate
fechaFin
)
{
hotel
=
repositorioHoteles
.
actualizar
(
hotel
);
return
hotel
.
disponible
(
fechaInicio
,
fechaFin
,
numHabSimple
,
numHabDoble
);
}
return
hotel
.
disponibilidad
(
fechaInicio
,
fechaFin
);
}
/**
* Realiza una reserva en un hotel. La reserva debe ser correcta y haber disponibilidad.
*
...
...
src/test/java/es/ujaen/dae/reservahoteles/rest/TestControladorReservas.java
View file @
f6093cdb
package
es
.
ujaen
.
dae
.
reservahoteles
.
rest
;
import
es.ujaen.dae.reservahoteles.entidades.Usuario
;
import
es.ujaen.dae.reservahoteles.rest.dto.DHotel
;
import
es.ujaen.dae.reservahoteles.rest.dto.DReserva
;
import
es.ujaen.dae.reservahoteles.rest.dto.DUsuario
;
import
jakarta.annotation.PostConstruct
;
import
java.time.LocalDate
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
import
org.junit.jupiter.api.Test
;
import
org.springframework.boot.test.context.SpringBootTest
;
...
...
@@ -113,14 +116,6 @@ public class TestControladorReservas {
var
hotel1
=
new
DHotel
(
0
,
"Gran Hotel Almería"
,
"Almería"
,
"Almería"
,
"04001"
,
25
,
50
,
100
,
180
);
var
hotel2
=
new
DHotel
(
0
,
"Hotel Infanta Cristina"
,
"Jaén"
,
"Jaén"
,
"23009"
,
30
,
60
,
120
,
200
);
var
respuestaLogin
=
restTemplate
.
getForEntity
(
"/usuarios/{email}?clave={clave}"
,
DUsuario
.
class
,
"direccion@hotelxyz.es"
,
"SeCrEtO"
);
assertThat
(
respuestaLogin
.
getStatusCode
()).
isEqualTo
(
HttpStatus
.
OK
);
var
respuesta
=
restTemplate
.
postForEntity
(
"/hoteles"
,
hotel1
,
...
...
@@ -144,5 +139,86 @@ public class TestControladorReservas {
assertThat
(
respuestaConsulta
.
getStatusCode
()).
isEqualTo
(
HttpStatus
.
OK
);
assertThat
(
respuestaConsulta
.
getBody
()).
hasSize
(
1
);
assertThat
(
respuestaConsulta
.
getBody
()[
0
].
id
()).
isEqualTo
(
1
);
}
@Test
@DirtiesContext
void
testBuscarPorLocalidad
()
{
var
hotel1
=
new
DHotel
(
0
,
"Gran Hotel Almería"
,
"Almería"
,
"Almería"
,
"04001"
,
25
,
50
,
100
,
180
);
var
hotel2
=
new
DHotel
(
0
,
"Hotel Espejo del Mar"
,
"Almería"
,
"Almería"
,
"04001"
,
15
,
35
,
80
,
110
);
var
hotel3
=
new
DHotel
(
0
,
"Hotel Infanta Cristina"
,
"Jaén"
,
"Jaén"
,
"23009"
,
30
,
60
,
120
,
200
);
restTemplate
.
postForEntity
(
"/hoteles"
,
hotel1
,
DHotel
.
class
);
restTemplate
.
postForEntity
(
"/hoteles"
,
hotel2
,
DHotel
.
class
);
restTemplate
.
postForEntity
(
"/hoteles"
,
hotel3
,
DHotel
.
class
);
var
respuestaConsulta
=
restTemplate
.
getForEntity
(
"/hoteles?localidad={localidad}"
+
"&desde={desde}&hasta={hasta}"
+
"&numHabSimple={numHabSimple}&numHabDoble={numHabDoble}"
,
DHotel
[].
class
,
" almeria"
,
LocalDate
.
now
().
plusDays
(
7
),
LocalDate
.
now
().
plusDays
(
9
),
0
,
2
);
assertThat
(
respuestaConsulta
.
getStatusCode
()).
isEqualTo
(
HttpStatus
.
OK
);
assertThat
(
respuestaConsulta
.
getBody
()).
hasSize
(
2
);
assertThat
(
respuestaConsulta
.
getBody
()[
0
].
id
()).
isEqualTo
(
1
);
assertThat
(
respuestaConsulta
.
getBody
()[
1
].
id
()).
isEqualTo
(
2
);
}
@Test
@DirtiesContext
void
testReservaHotel
()
{
var
hotel
=
new
DHotel
(
0
,
"Bed and Breakfast Almería"
,
"Almería"
,
"Almería"
,
"04001"
,
2
,
2
,
60
,
100
);
restTemplate
.
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
());
var
respuestaReserva
=
restTemplate
.
postForEntity
(
"/hoteles/{id}/reservas"
,
reserva
,
DReserva
.
class
,
hotelGuardado
.
id
()
);
assertThat
(
respuestaReserva
.
getStatusCode
()).
isEqualTo
(
HttpStatus
.
CREATED
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment