diff --git a/angular/RestClient/src/app/app.component.spec.ts b/angular/RestClient/src/app/app.component.spec.ts index ab77de0d1b761c50efffa4c4fcbc31e301eb01a0..360bd69b802b5865ce5bb94b3a5ed758dbc09b26 100644 --- a/angular/RestClient/src/app/app.component.spec.ts +++ b/angular/RestClient/src/app/app.component.spec.ts @@ -1,10 +1,11 @@ import { TestBed } from '@angular/core/testing'; import { AppComponent } from './app.component'; +import { ReactiveFormsModule } from '@angular/forms'; describe('AppComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [AppComponent], + imports: [AppComponent, ReactiveFormsModule], }).compileComponents(); }); diff --git a/angular/RestClient/src/app/app.config.ts b/angular/RestClient/src/app/app.config.ts index dc3614c9ac6a9b89317d989095a23560c91dd442..90d16a2680995da9bfe69cc6236811df872c23ad 100644 --- a/angular/RestClient/src/app/app.config.ts +++ b/angular/RestClient/src/app/app.config.ts @@ -7,13 +7,19 @@ import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; import { provideHttpClient, withFetch } from '@angular/common/http'; import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; +import { ReactiveFormsModule } from '@angular/forms'; // Added import for ReactiveFormsModule +import { provideNativeDateAdapter } from '@angular/material/core'; import { FormsModule } from '@angular/forms'; import { CommonEngine } from '@angular/ssr'; + export const appConfig: ApplicationConfig = { providers: [ + provideNativeDateAdapter(), + provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideClientHydration(), provideHttpClient(withFetch()), provideAnimationsAsync(), - ], + ReactiveFormsModule + ] }; diff --git a/angular/RestClient/src/app/app.routes.ts b/angular/RestClient/src/app/app.routes.ts index 00900bcfc57688240219148d5ed9b2eb24b5ba51..2dd95b52261263abe4e4110f1025bec2b5d36e4c 100644 --- a/angular/RestClient/src/app/app.routes.ts +++ b/angular/RestClient/src/app/app.routes.ts @@ -1,5 +1,7 @@ import { Routes } from '@angular/router'; import { HotelListComponent } from './hotel-list/hotel-list.component'; +import { BookingComponent } from './booking/booking.component'; +import { BookingListComponent } from './booking-list/booking-list.component'; import { HotelRegisterComponent } from './hotel-register/hotel-register.component'; import { MainPageComponent } from './main-page/main-page.component'; @@ -8,6 +10,14 @@ export const routes: Routes = [ path: '', // Ruta principal component: MainPageComponent, // Componente de la página principal }, + { + path: 'booking/search', + component: BookingListComponent, + }, + { + path: 'hotels', + component: HotelListComponent, + }, { path: 'hotels/new', component: HotelRegisterComponent, @@ -21,4 +31,8 @@ export const routes: Routes = [ redirectTo: '', pathMatch: 'full', }, -]; + { + path: 'booking', // Añade la ruta para el componente de reservas + component: BookingComponent, + } +] \ No newline at end of file diff --git a/angular/RestClient/src/app/booking-list/booking-list.component.css b/angular/RestClient/src/app/booking-list/booking-list.component.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/angular/RestClient/src/app/booking-list/booking-list.component.html b/angular/RestClient/src/app/booking-list/booking-list.component.html new file mode 100644 index 0000000000000000000000000000000000000000..653fb3a73614955a1d731766f9b0aaed7cad5665 --- /dev/null +++ b/angular/RestClient/src/app/booking-list/booking-list.component.html @@ -0,0 +1,51 @@ +<div> + <mat-form-field> + <mat-label>Enter a date range</mat-label> + <mat-date-range-input [rangePicker]="picker"> + <input + matStartDate + placeholder="Start date" + (dateInput)="updateStart($event)" + (dateChange)="updateStart($event)" + /> + <input + matEndDate + placeholder="End date" + (dateInput)="updateEnd($event)" + (dateChange)="updateEnd($event)" + /> + </mat-date-range-input> + <mat-hint>MM/DD/YYYY – MM/DD/YYYY</mat-hint> + <mat-datepicker-toggle matIconSuffix [for]="picker"></mat-datepicker-toggle> + <mat-date-range-picker #picker></mat-date-range-picker> + </mat-form-field> + <mat-form-field> + <mat-label>Hotel</mat-label> + <mat-select [(value)]="hotelSelected"> + @for (hotel of hotels; track hotel.id) { + <mat-option [value]="hotel.id">{{ hotel.name }}</mat-option> + } + </mat-select> + </mat-form-field> + <mat-form-field> + <mat-label>Room Type</mat-label> + <mat-select [(value)]="roomTypeSelected" (selectionChange)="updateRooms()"> + @for (type of roomTypes; track type) { + <mat-option [value]="type">{{ type }}</mat-option> + } + </mat-select> + </mat-form-field> + <button + [disabled]="!this.start || !this.end || this.hotelSelected == -1" + mat-raised-button + color="primary" + (click)="search()" + > + Search + </button> + @for (room of trateRooms; track $index) { + <button (click)="bookingRoom(room.id)"> + {{ room.id }} {{ room.type }} {{ room.roomNumber }} + </button> + } +</div> diff --git a/angular/RestClient/src/app/booking-list/booking-list.component.spec.ts b/angular/RestClient/src/app/booking-list/booking-list.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..f6b1910a567d3ff00efa491436359519ee52632d --- /dev/null +++ b/angular/RestClient/src/app/booking-list/booking-list.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { BookingListComponent } from './booking-list.component'; + +describe('BookingListComponent', () => { + let component: BookingListComponent; + let fixture: ComponentFixture<BookingListComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [BookingListComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(BookingListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/angular/RestClient/src/app/booking-list/booking-list.component.ts b/angular/RestClient/src/app/booking-list/booking-list.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..41d5976b734d93abfa3d2e0457af80f6e2c09c5b --- /dev/null +++ b/angular/RestClient/src/app/booking-list/booking-list.component.ts @@ -0,0 +1,88 @@ +import { Component } from '@angular/core'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { + MatDatepickerInputEvent, + MatDatepickerModule, +} from '@angular/material/datepicker'; +import { FormsModule } from '@angular/forms'; +import { MatInputModule } from '@angular/material/input'; +import { MatSelectChange, MatSelectModule } from '@angular/material/select'; +import { Hotel, Room, RoomType, roomTypeArray } from '../../types'; +import { ClienteApiRestService } from '../shared/cliente-api-rest.service'; +import { Router } from '@angular/router'; + +type SelectableRoomType = 'All' | RoomType; +const selectableRoomTypeArray: SelectableRoomType[] = ['All', ...roomTypeArray]; + +@Component({ + selector: 'app-booking-list', + standalone: true, + imports: [ + MatFormFieldModule, + MatDatepickerModule, + MatFormFieldModule, + MatSelectModule, + MatInputModule, + FormsModule, + ], + templateUrl: './booking-list.component.html', + styleUrl: './booking-list.component.css', +}) +export class BookingListComponent { + start?: Date; + end?: Date; + hotels!: Hotel[]; + hotelSelected: number = -1; + roomTypeSelected?: SelectableRoomType; + roomTypes = selectableRoomTypeArray; + rooms: Room[] = []; + trateRooms: Room[] = []; + + constructor(private router: Router, private client: ClienteApiRestService) {} + + ngOnInit() { + this.getHotels(); + } + + getHotels() { + this.client.getAllHotels().subscribe({ + next: (resp) => { + if (resp.body != null) this.hotels = [...resp.body]; + }, + error(err) { + console.log('Error al traer la lista: ' + err.message); + throw err; + }, + }); + } + + updateStart(event: MatDatepickerInputEvent<Date>) { + this.start = event.value!; + } + + updateEnd(event: MatDatepickerInputEvent<Date>) { + this.end = event.value!; + } + + search() { + this.client + .getRoomsAvailableInDateRange(this.hotelSelected, this.start!, this.end!) + .subscribe({ + next: (resp) => { + this.rooms = resp; + this.updateRooms(); + }, + }); + } + + updateRooms() { + this.trateRooms = + this.roomTypeSelected && this.roomTypeSelected !== 'All' + ? this.rooms.filter((room) => room.type === this.roomTypeSelected) + : this.rooms; + } + + bookingRoom(roomId: number) { + this.router.navigateByUrl(`/booking?room=${roomId}`); + } +} diff --git a/angular/RestClient/src/app/booking/booking.component.css b/angular/RestClient/src/app/booking/booking.component.css new file mode 100644 index 0000000000000000000000000000000000000000..34f19bda870b7fe9ab1df89627e400529a8b543f --- /dev/null +++ b/angular/RestClient/src/app/booking/booking.component.css @@ -0,0 +1,26 @@ +.container { + max-width: 600px; + margin: auto; + padding: 20px; + border: 1px solid #ccc; + border-radius: 5px; + background-color: #f9f9f9; + } + + h2 { + text-align: center; + margin-bottom: 20px; + } + + .form-group { + margin-bottom: 15px; + } + + label { + font-weight: bold; + } + + .btn { + width: 100%; + } + \ No newline at end of file diff --git a/angular/RestClient/src/app/booking/booking.component.html b/angular/RestClient/src/app/booking/booking.component.html new file mode 100644 index 0000000000000000000000000000000000000000..fba44008cc32e506e7ff27ca1d3ad0051b3c068a --- /dev/null +++ b/angular/RestClient/src/app/booking/booking.component.html @@ -0,0 +1,36 @@ +<div class="container"> + <h2>Crear Reserva</h2> + <form [formGroup]="bookingForm" (ngSubmit)="submitBooking()"> + <div class="form-group"> + <label for="userId">ID del Usuario:</label> + <input type="number" id="userId" formControlName="userId" class="form-control" /> + </div> + <div class="form-group"> + <label for="hotelId">ID del Hotel:</label> + <input type="number" id="hotelId" formControlName="hotelId" class="form-control" /> + </div> + + <div class="form-group"> + <label for="roomType">Tipo de Habitación:</label> + <select id="roomType" formControlName="roomType" class="form-control"> + <option value="">Seleccione</option> + <option value="single">Individual</option> + <option value="double">Doble</option> + <option value="suite">Suite</option> + </select> + </div> + + <div class="form-group"> + <label for="startDate">Fecha de Inicio:</label> + <input type="date" id="startDate" formControlName="startDate" class="form-control" /> + </div> + + <div class="form-group"> + <label for="endDate">Fecha de Fin:</label> + <input type="date" id="endDate" formControlName="endDate" class="form-control" /> + </div> + + <button type="submit" class="btn btn-primary">Reservar</button> + </form> + </div> + \ No newline at end of file diff --git a/angular/RestClient/src/app/booking/booking.component.spec.ts b/angular/RestClient/src/app/booking/booking.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..486d21fb8c300bbcef700c5d53a5d3d84bcb68f9 --- /dev/null +++ b/angular/RestClient/src/app/booking/booking.component.spec.ts @@ -0,0 +1,56 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ReactiveFormsModule } from '@angular/forms'; +import { BookingComponent } from './booking.component'; +import { BookingService } from '../shared/booking.service'; +import { of } from 'rxjs'; + +class MockBookingService { + createBooking() { + return of({}); // Simula una respuesta exitosa + } +} + +describe('BookingComponent', () => { + let component: BookingComponent; + let fixture: ComponentFixture<BookingComponent>; + let bookingService: BookingService; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [BookingComponent], + imports: [ReactiveFormsModule], + providers: [{ provide: BookingService, useClass: MockBookingService }], + }).compileComponents(); + + fixture = TestBed.createComponent(BookingComponent); + component = fixture.componentInstance; + bookingService = TestBed.inject(BookingService); + fixture.detectChanges(); + }); + + it('should create the component', () => { + expect(component).toBeTruthy(); + }); + + it('should have a valid form when all fields are filled', () => { + component.bookingForm.controls['userId'].setValue(1); + component.bookingForm.controls['hotelId'].setValue(1); + component.bookingForm.controls['roomType'].setValue('single'); + component.bookingForm.controls['startDate'].setValue('2024-10-01'); + component.bookingForm.controls['endDate'].setValue('2024-10-05'); + + expect(component.bookingForm.valid).toBeTrue(); + }); + + it('should submit booking when form is valid', () => { + spyOn(bookingService, 'createBooking').and.callThrough(); + component.bookingForm.controls['userId'].setValue(1); + component.bookingForm.controls['hotelId'].setValue(1); + component.bookingForm.controls['roomType'].setValue('single'); + component.bookingForm.controls['startDate'].setValue('2024-10-01'); + component.bookingForm.controls['endDate'].setValue('2024-10-05'); + + component.submitBooking(); + expect(bookingService.createBooking).toHaveBeenCalled(); + }); +}); diff --git a/angular/RestClient/src/app/booking/booking.component.ts b/angular/RestClient/src/app/booking/booking.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..9636e65609448ce2df6cf698da2186627c937722 --- /dev/null +++ b/angular/RestClient/src/app/booking/booking.component.ts @@ -0,0 +1,61 @@ +import { Component, OnInit } from '@angular/core'; +import { + ReactiveFormsModule, + FormGroup, + FormBuilder, + Validators, +} from '@angular/forms'; +interface BookingRequest { + userId: number; // ID del usuario que realiza la reserva + hotelId: number; // ID del hotel en el que se realiza la reserva + roomType: string; // Tipo de habitación (single, double, suite) + startDate: string; // Fecha de inicio de la reserva + endDate: string; // Fecha de fin de la reserva// Asegúrate de ajustar la ruta +} +import { BookingService } from '../shared/booking.service'; // Asegúrate de que el servicio exista + +@Component({ + standalone: true, + imports: [ReactiveFormsModule], + selector: 'app-booking', + templateUrl: './booking.component.html', + styleUrls: ['./booking.component.css'], +}) +export class BookingComponent implements OnInit { + bookingForm: FormGroup; + + constructor(private fb: FormBuilder, private bookingService: BookingService) { + // Inicialización del formulario con validaciones + this.bookingForm = this.fb.group({ + userId: ['', Validators.required], + hotelId: ['', Validators.required], + roomType: ['', Validators.required], + startDate: ['', Validators.required], + endDate: ['', Validators.required], + }); + } + + ngOnInit(): void {} + + submitBooking() { + if (this.bookingForm.valid) { + const bookingRequest: BookingRequest = this.bookingForm.value; + + // Llama al servicio para crear una nueva reserva + this.bookingService.createBooking(bookingRequest).subscribe( + (response) => { + console.log('Reserva creada con éxito', response); + // Aquí puedes redirigir al usuario o mostrar un mensaje de éxito + this.bookingForm.reset(); // Opcional: resetea el formulario después de una reserva exitosa + }, + (error) => { + console.error('Error al crear la reserva', error); + // Manejo de errores + } + ); + } else { + console.warn('El formulario no es válido'); + // Puedes mostrar un mensaje al usuario sobre la validez del formulario + } + } +} diff --git a/angular/RestClient/src/app/shared/booking.service.spec.ts b/angular/RestClient/src/app/shared/booking.service.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..3992ef555abf9021f683a3b7fd42344842c4d6ed --- /dev/null +++ b/angular/RestClient/src/app/shared/booking.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { BookingService } from './booking.service'; + +describe('BookingService', () => { + let service: BookingService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(BookingService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/angular/RestClient/src/app/shared/booking.service.ts b/angular/RestClient/src/app/shared/booking.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..3a4db3fc8c30952e5d240e43027138009b3ac000 --- /dev/null +++ b/angular/RestClient/src/app/shared/booking.service.ts @@ -0,0 +1,47 @@ +// booking.service.ts +import { Injectable } from '@angular/core'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Observable } from 'rxjs'; +interface BookingRequest { + userId: number; // ID del usuario que realiza la reserva + hotelId: number; // ID del hotel en el que se realiza la reserva + roomType: string; // Tipo de habitación (single, double, suite) + startDate: string; // Fecha de inicio de la reserva + endDate: string; // Fecha de fin de la reserva +} +import { Booking } from '../../types/Booking'; // Ajusta la ruta a tu modelo Booking + +@Injectable({ + providedIn: 'root', // Esto hace que el servicio esté disponible en toda la aplicación +}) +export class BookingService { + private apiUrl = 'http://localhost:8080/api/bookings'; + + constructor(private http: HttpClient) {} + + // Método para crear una nueva reserva + createBooking(bookingRequest: BookingRequest): Observable<Booking> { + return this.http.post<Booking>(this.apiUrl, bookingRequest, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json', + }), + }); + } + + // Método para obtener todas las reservas + getAllBookings(): Observable<Booking[]> { + return this.http.get<Booking[]>(this.apiUrl); + } + + // Método para obtener una reserva por ID + getBookingById(id: number): Observable<Booking> { + return this.http.get<Booking>(`${this.apiUrl}/${id}`); + } + + // Método para eliminar una reserva + deleteBooking(id: number): Observable<void> { + return this.http.delete<void>(`${this.apiUrl}/${id}`); + } + + // Agrega más métodos según sea necesario +} diff --git a/angular/RestClient/src/app/shared/cliente-api-rest.service.ts b/angular/RestClient/src/app/shared/cliente-api-rest.service.ts index 3a481555d86a917c379af0c5cd6a578195ccf62c..901197fd57be961b0d2546a15688fea828f02631 100644 --- a/angular/RestClient/src/app/shared/cliente-api-rest.service.ts +++ b/angular/RestClient/src/app/shared/cliente-api-rest.service.ts @@ -1,6 +1,7 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { Hotel } from '../../types'; +import { Observable } from 'rxjs'; +import { Hotel, Booking, Room } from '../../types'; import { Observable } from 'rxjs'; import { User } from '../../types'; @@ -52,6 +53,18 @@ export class ClienteApiRestService { ); } + createBooking(bookingRequest: Booking): Observable<any> { + return this.http.post('http://localhost:8080/bookings', bookingRequest); + } + + getRoomsAvailableInDateRange(hotelId: number, start: Date, end: Date) { + const startStr = start.toISOString().split('T')[0]; + const endStr = end.toISOString().split('T')[0]; + return this.http.get<Room[]>( + `${ClienteApiRestService.HOTEL_URI}/${hotelId}/rooms?start=${startStr}&end=${endStr}` + ); + } + getAllUsers(): Observable<User[]> { return this.http.get<User[]>('http://localhost:8080/users', { observe: 'body' }); } diff --git a/angular/RestClient/src/index.html b/angular/RestClient/src/index.html index 189053197993efde89b3e56b3debb06775363007..55c5530803842faa15de37607c2c916d5bd4f068 100644 --- a/angular/RestClient/src/index.html +++ b/angular/RestClient/src/index.html @@ -1,15 +1,29 @@ -<!doctype html> +<!DOCTYPE html> <html lang="en"> -<head> - <meta charset="utf-8"> - <title>RestClient</title> - <base href="/"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <link rel="icon" type="image/x-icon" href="favicon.ico"> - <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet"> - <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> -</head> -<body> - <app-root></app-root> -</body> + <head> + <meta charset="utf-8" /> + <title>RestClient</title> + <base href="/" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <link rel="icon" type="image/x-icon" href="favicon.ico" /> + <link + href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" + rel="stylesheet" + /> + <link + href="https://fonts.googleapis.com/icon?family=Material+Icons" + rel="stylesheet" + /> + <link + rel="stylesheet" + href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css" + /></head + ><!-- compiled and minified CSS --> + <!-- jQuery library --> + <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> + <!-- compiled JavaScript --> + <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script> + <body> + <app-root></app-root> + </body> </html> diff --git a/angular/RestClient/src/types/Room.d.ts b/angular/RestClient/src/types/Room.d.ts index d15b5148c018da01fb1d08d2cc0477c4dd66dbf8..0c54fdcbfee2f4da7aa34f3727dd21421acbb048 100644 --- a/angular/RestClient/src/types/Room.d.ts +++ b/angular/RestClient/src/types/Room.d.ts @@ -1,7 +1,7 @@ +export type RoomType = 'SINGLE' | 'DOUBLE' | 'SUITE'; export interface Room { id: number; roomNumber: String; - // type: "single" | "double" | "suite"; - type: 'SINGLE' | 'DOUBLE' | 'SUITE'; + type: RoomType; available: boolean; } diff --git a/angular/RestClient/src/types/index.ts b/angular/RestClient/src/types/index.ts index 8ec625599a2be411714cc097745fc0357cd5b229..b974a05f55ecc2a2b9a6e953882d7cc526689ab6 100644 --- a/angular/RestClient/src/types/index.ts +++ b/angular/RestClient/src/types/index.ts @@ -1,5 +1,9 @@ +import { RoomType } from './Room'; + export type * from './User'; export type * from './Address'; export type * from './Hotel'; export type * from './Room'; +export const roomTypeArray: RoomType[] = ['SINGLE', 'DOUBLE', 'SUITE']; +export type * from './Booking'; export type * from './User'; diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/BookingController.java b/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/BookingController.java index b3b78e3543d2dd533c1423d27c5e2e291552a729..c5bd2cbd629e28aae1a037ddbe248a507271f1dd 100644 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/BookingController.java +++ b/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/BookingController.java @@ -35,8 +35,24 @@ public class BookingController { @PostMapping public Booking createBooking(@RequestBody Booking booking) { - User user = userRepository.findById(booking.getUserId().getId()).orElseThrow(); - Room room = roomRepository.findById(booking.getRoomId().getId()).orElseThrow(); + User user = userRepository.findById(booking.getUserId().getId()) + .orElseThrow(() -> new RuntimeException("User not found")); + Room room = roomRepository.findById(booking.getRoomId().getId()) + .orElseThrow(() -> new RuntimeException("Room not found")); + + // Validar el tipo de habitación + if (!room.getType().equals(booking.getRoomId().getType())) { + throw new RuntimeException("Room type does not match the requested type"); + } + + // Verificar disponibilidad + List<Booking> existingBookings = bookingRepository.findByRoomIdAndDateRange( + room.getId(), booking.getStartDate(), booking.getEndDate()); + + if (!existingBookings.isEmpty()) { + throw new RuntimeException("Room is not available for the selected dates"); + } + booking.setUserId(user); booking.setRoomId(room); return bookingRepository.save(booking); @@ -46,4 +62,6 @@ public class BookingController { public void deleteBooking(@PathVariable Integer id) { bookingRepository.deleteById(id); } + + } diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/HotelController.java b/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/HotelController.java index eea12ebe70ad54c0095629223d90c5e459a82bcd..587c57014ea64272b3be49cbed0706800bef484b 100644 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/HotelController.java +++ b/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/HotelController.java @@ -61,15 +61,15 @@ public class HotelController { @GetMapping("/{hotelId}/rooms") public ResponseEntity<List<Room>> getRoomsFromHotel( @PathVariable int hotelId, - @RequestParam(required = false) LocalDate date1, - @RequestParam(required = false) LocalDate date2) { + @RequestParam(required = false) LocalDate start, + @RequestParam(required = false) LocalDate end) { List<Room> rooms; - if (date1 != null && date2 != null) { - if (!date1.isBefore(date2)) { + if (start != null && end != null) { + if (!start.isBefore(end)) { throw new InvalidDateRangeException("La fecha de inicio debe ser anterior a la fecha de fin"); } - rooms = roomRepository.findAvailableRoomsByHotelAndDates(hotelId, date1, date2); + rooms = roomRepository.findAvailableRoomsByHotelAndDates(hotelId, start, end); } else { rooms = roomRepository.findAllByHotelId(hotelId); } diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/BookingRepository.java b/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/BookingRepository.java index 121da32b226cdb31dcd79f3c91dec26e8f207497..a010a3a19ccfbb0fafd588c4fb7a52cb530897d9 100644 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/BookingRepository.java +++ b/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/BookingRepository.java @@ -2,7 +2,17 @@ package com.uva.roomBooking.Repositories; import com.uva.roomBooking.Models.Booking; + +import java.time.LocalDate; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface BookingRepository extends JpaRepository<Booking, Integer> { + + @Query("SELECT b FROM Booking b WHERE b.roomId.id = ?1 AND b.startDate < ?2 AND b.endDate > ?3") + List<Booking> findByRoomIdAndDateRange(@Param("roomId") int roomId, @Param("startDate") LocalDate startDate, + @Param("endDate") LocalDate endDate); }