From ab75c2cc77d8b333328d0dfa51d8cb2516e9b739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20de=20Le=C3=B3n=20Fern=C3=A1ndez?= Date: Thu, 26 Mar 2026 17:18:58 +0000 Subject: [PATCH] [ADD] Bookings date editing --- pms/forms.py | 10 +++++ pms/templates/edit_booking_date.html | 15 +++++++ pms/templates/home.html | 2 +- pms/tests.py | 64 +++++++++++++++++++++++++++- pms/urls.py | 3 +- pms/views.py | 32 +++++++++++++- 6 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 pms/templates/edit_booking_date.html diff --git a/pms/forms.py b/pms/forms.py index f1bc68d08..7e1a05e49 100644 --- a/pms/forms.py +++ b/pms/forms.py @@ -56,3 +56,13 @@ class Meta: 'total': forms.HiddenInput(), 'state': forms.HiddenInput(), } + +class EditBookingDatesForm(forms.ModelForm): + class Meta: + model = Booking + fields = ['checkin','checkout'] + widgets = { + 'checkin': forms.DateInput(attrs={'type': 'date', 'class':'form-control'}), + 'checkout': forms.DateInput(attrs={'type': 'date', 'class':'form-control'}) + } + diff --git a/pms/templates/edit_booking_date.html b/pms/templates/edit_booking_date.html new file mode 100644 index 000000000..83d43e07f --- /dev/null +++ b/pms/templates/edit_booking_date.html @@ -0,0 +1,15 @@ +{% extends "main.html"%} {% block content %} +

Editar fecha de la reserva: {{ booking.code }}

+
+ {% if messages %} {% for message in messages %} +
{{message}}
+ {% endfor %} {% endif %} + +
+ {% csrf_token %} {{ form.as_p }} + + Cancelar +
+
+ +{% endblock content%} diff --git a/pms/templates/home.html b/pms/templates/home.html index 1e61b8024..d6ef78d19 100644 --- a/pms/templates/home.html +++ b/pms/templates/home.html @@ -68,7 +68,7 @@

Reservas Realizadas

Editar datos de contacto
- + Editar fecha de la reserva
diff --git a/pms/tests.py b/pms/tests.py index 7ce503c2d..cba92d4dd 100644 --- a/pms/tests.py +++ b/pms/tests.py @@ -1,3 +1,65 @@ -from django.test import TestCase +from django.test import TestCase, override_settings +from django.urls import reverse +from .models import Room, Room_type, Booking, Customer +import datetime # Create your tests here. + +@override_settings(STATICFILES_STORAGE='django.contrib.staticfiles.storage.StaticFilesStorage') +class EditBookingDatesTest(TestCase): + def setUp(self): + self.room_type = Room_type.objects.create(name='Simple', price=20, max_guests=1) + self.room = Room.objects.create(room_type=self.room_type, name='Room 7.1', description='descripcion') + self.customer = Customer.objects.create(name="Cliente1", email="cliente1@test.com", phone="123123123") + + self.booking1 = Booking.objects.create( + state='NEW', + checkin=datetime.date(2026, 7, 10), + checkout=datetime.date(2026, 7, 12), + room=self.room, + guests=1, + customer=self.customer, + total=40, + code='B1' + ) + + self.booking2 = Booking.objects.create( + state='NEW', + checkin=datetime.date(2026, 7, 15), + checkout=datetime.date(2026, 7, 20), + room=self.room, + guests=1, + customer=self.customer, + total=100, + code='B2' + ) + + """Valida que se realiza el cambio de fecha correctamente.""" + def test_succesful_date_change(self): + url = reverse('edit_booking_date', kwargs={'pk': self.booking2.id}) + + data = { + 'checkin': '2026-12-26', + 'checkout': '2026-12-30' + } + + response = self.client.post(url, data) + + self.booking2.refresh_from_db() + self.assertEqual(self.booking2.checkin, datetime.date(2026, 12, 26)) + self.assertRedirects(response, reverse('home')) + + """Valida que si se solapan las fechas con otra reserva, de error.""" + def test_overlap_validation_error(self): + url = reverse('edit_booking_date', kwargs={'pk': self.booking2.id}) + + data = { + 'checkin': '2026-7-11', + 'checkout': '2026-7-15' + } + + response = self.client.post(url, data) + self.assertContains(response, "No hay disponibilidad para las fechas seleccionadas.") + self.booking2.refresh_from_db() + self.assertEqual(self.booking2.checkin, datetime.date(2026, 7, 15)) + diff --git a/pms/urls.py b/pms/urls.py index c18714abf..984307ef5 100644 --- a/pms/urls.py +++ b/pms/urls.py @@ -11,5 +11,6 @@ path("booking//delete", views.DeleteBookingView.as_view(), name="delete_booking"), path("rooms/", views.RoomsView.as_view(), name="rooms"), path("room//", views.RoomDetailsView.as_view(), name="room_details"), - path("dashboard/", views.DashboardView.as_view(), name="dashboard") + path("dashboard/", views.DashboardView.as_view(), name="dashboard"), + path("booking//edit-dates/", views.EditBookingDatesView.as_view(), name="edit_booking_date") ] diff --git a/pms/views.py b/pms/views.py index f38563933..3ff6a3ed1 100644 --- a/pms/views.py +++ b/pms/views.py @@ -1,8 +1,9 @@ from django.db.models import F, Q, Count, Sum -from django.shortcuts import render, redirect +from django.shortcuts import render, redirect, get_object_or_404 from django.utils.decorators import method_decorator from django.views import View from django.views.decorators.csrf import ensure_csrf_cookie +from django.contrib import messages from .form_dates import Ymd from .forms import * @@ -244,3 +245,32 @@ def get(self, request): 'rooms': rooms } return render(request, "rooms.html", context) + + +class EditBookingDatesView(View): + def get(self, request, pk): + booking = get_object_or_404(Booking, id=pk) + form = EditBookingDatesForm(prefix="booking", instance=booking) + return render(request, "edit_booking_date.html", {'form': form, 'booking': booking}) + + def post(self, request, pk): + booking = get_object_or_404(Booking, id=pk) + form = EditBookingDatesForm(request.POST, instance=booking) + + if form.is_valid(): + new_checkin = form.cleaned_data['checkin'] + new_checkout = form.cleaned_data['checkout'] + + overlap = Booking.objects.filter( + room=booking.room, state='NEW' + ).exclude(id=pk).filter(Q(checkin__lt=new_checkout, checkout__gt=new_checkin) + ).exists() + + if overlap: + messages.error(request, "No hay disponibilidad para las fechas seleccionadas.") + return render(request, "edit_booking_date.html", {'form': form, 'booking': booking}) + + form.save() + return redirect("home") + + return render(request, "edit_booking_date.html", {'form': form, 'booking': booking}) \ No newline at end of file