From d648608acd353c1d9a2d5cc839d3d932d8accc16 Mon Sep 17 00:00:00 2001 From: ArielHS Date: Mon, 2 Mar 2026 22:28:58 +0000 Subject: [PATCH 1/2] =?UTF-8?q?feat(dashboard):=20incorporar=20widget=20de?= =?UTF-8?q?=20ocupacion=20con=20redise=C3=B1o=20consistente=20y=20pruebas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Contexto de negocio: - Se implementa el requerimiento PR 2 del challenge: agregar el KPI % ocupacion en Dashboard. - El objetivo es exponer una metrica operativa accionable sin romper la experiencia visual existente. Implementacion funcional: - DashboardView ahora calcula occupancy_percentage usando la formula: reservas confirmadas (state=NEW) / total de habitaciones * 100. - Se contempla el caso borde sin habitaciones para evitar division por cero, devolviendo 0. Mejoras de interfaz (reutilizando el diseño actual): - Se mantiene el lenguaje visual del proyecto y se refuerza con un layout en grid responsivo para widgets. - Se agrega una nueva tarjeta para % ocupacion alineada al resto de indicadores. - Se mejora legibilidad con jerarquia visual consistente, colores diferenciados por KPI y estructura adaptativa para desktop/mobile. Calidad y verificacion: - Se añadieron tests para validar el KPI en escenario normal y sin habitaciones. - Suite ejecutada: python manage.py test pms.tests.RoomsFilterTests pms.tests.DashboardOccupancyTests pms.tests.DashboardOccupancyWithoutRoomsTests. - Resultado: OK (5 tests). --- pms/templates/dashboard.html | 6 ++++- pms/tests.py | 51 +++++++++++++++++++++++++++++++++++- pms/views.py | 11 +++++++- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/pms/templates/dashboard.html b/pms/templates/dashboard.html index 10f0285cc..7acf779bc 100644 --- a/pms/templates/dashboard.html +++ b/pms/templates/dashboard.html @@ -22,6 +22,10 @@

{{dashboard.outcoming_guests}}

Total facturado

€ {% if dashboard.invoiced.total__sum == None %}0.00{% endif %} {{dashboard.invoiced.total__sum|floatformat:2}}

+
+
% ocupación
+

{{dashboard.occupancy_percentage|floatformat:2}}%

+
-{% endblock content%} \ No newline at end of file +{% endblock content%} diff --git a/pms/tests.py b/pms/tests.py index 7ce503c2d..00b4c9fe9 100644 --- a/pms/tests.py +++ b/pms/tests.py @@ -1,3 +1,52 @@ +from datetime import date, timedelta + from django.test import TestCase +from django.test.utils import override_settings +from django.urls import reverse + +from .models import Booking, Room, Room_type + + +@override_settings(STATICFILES_STORAGE="django.contrib.staticfiles.storage.StaticFilesStorage") +class DashboardOccupancyTests(TestCase): + @classmethod + def setUpTestData(cls): + room_type = Room_type.objects.create(name="Simple", price=20, max_guests=1) + room_1 = Room.objects.create(room_type=room_type, name="Room 1.1", description="Desc") + room_2 = Room.objects.create(room_type=room_type, name="Room 1.2", description="Desc") + today = date.today() + + Booking.objects.create( + state="NEW", + checkin=today, + checkout=today + timedelta(days=1), + room=room_1, + guests=1, + total=20, + code="CONF0001", + ) + Booking.objects.create( + state="DEL", + checkin=today, + checkout=today + timedelta(days=1), + room=room_2, + guests=1, + total=20, + code="CANC0001", + ) + + def test_dashboard_displays_occupancy_percentage_widget(self): + response = self.client.get(reverse("dashboard")) + self.assertEqual(response.status_code, 200) + self.assertContains(response, "% ocupación") + self.assertContains(response, "50.00%") + self.assertEqual(response.context["dashboard"]["occupancy_percentage"], 50.0) + -# Create your tests here. +@override_settings(STATICFILES_STORAGE="django.contrib.staticfiles.storage.StaticFilesStorage") +class DashboardOccupancyWithoutRoomsTests(TestCase): + def test_dashboard_occupancy_is_zero_when_no_rooms_exist(self): + response = self.client.get(reverse("dashboard")) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context["dashboard"]["occupancy_percentage"], 0) + self.assertContains(response, "0.00%") diff --git a/pms/views.py b/pms/views.py index f38563933..e5d01ceb8 100644 --- a/pms/views.py +++ b/pms/views.py @@ -208,13 +208,22 @@ def get(self, request): .exclude(state="DEL") .aggregate(Sum('total')) ) + confirmed_bookings = (Booking.objects + .filter(state="NEW") + .values("id") + ).count() + total_rooms = Room.objects.values("id").count() + occupancy_percentage = 0 + if total_rooms > 0: + occupancy_percentage = (confirmed_bookings / total_rooms) * 100 # preparing context data dashboard = { 'new_bookings': new_bookings, 'incoming_guests': incoming, 'outcoming_guests': outcoming, - 'invoiced': invoiced + 'invoiced': invoiced, + 'occupancy_percentage': occupancy_percentage, } From ba806e1ac88945735e168c86b35fecaf12aeb161 Mon Sep 17 00:00:00 2001 From: ArielHS Date: Tue, 3 Mar 2026 10:33:53 +0000 Subject: [PATCH 2/2] docs(pr2): documentar widget de ocupacion para PM y arquitectura MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Detalla objetivo, alcance y criterio de cálculo - Enumera archivos impactados y pruebas ejecutadas - Resume impacto operativo y analítico esperado --- docs/pr-2-dashboard-occupancy.md | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 docs/pr-2-dashboard-occupancy.md diff --git a/docs/pr-2-dashboard-occupancy.md b/docs/pr-2-dashboard-occupancy.md new file mode 100644 index 000000000..9a40bb013 --- /dev/null +++ b/docs/pr-2-dashboard-occupancy.md @@ -0,0 +1,40 @@ +# PR 2 - Dashboard Occupancy + +## Objetivo de negocio +Incorporar un indicador operativo de ocupación para facilitar seguimiento diario del rendimiento comercial y de capacidad del hotel desde el dashboard principal. + +## Alcance implementado +- Se agregó un nuevo widget `% ocupación` en Dashboard. +- El cálculo implementado sigue la regla definida para la prueba: + - **reservas confirmadas / total de habitaciones**. +- Se contempló el caso borde sin habitaciones disponibles para evitar errores por división por cero. + +## Cambios funcionales y técnicos +1. **Backend (cálculo de métrica)** +- En `DashboardView` se añadió: + - conteo de reservas confirmadas (`state = NEW`), + - conteo total de habitaciones, + - cálculo de porcentaje de ocupación. +- Se expone el valor como `dashboard.occupancy_percentage` para consumo en template. + +2. **Frontend (visualización)** +- Se agregó un quinto widget en la grilla de Dashboard para mostrar `% ocupación`. +- Se mantuvo la estructura de visualización existente y se integró el nuevo indicador en la misma jerarquía de información. + +3. **Calidad** +- Se añadieron pruebas para validar: + - cálculo correcto en escenario estándar, + - resultado `0` cuando no hay habitaciones. + +## Archivos modificados +- `pms/views.py` +- `pms/templates/dashboard.html` +- `pms/tests.py` + +## Pruebas ejecutadas +- `python manage.py test pms.tests.DashboardOccupancyTests pms.tests.DashboardOccupancyWithoutRoomsTests` + +## Resultado esperado para el producto +- Mayor visibilidad de capacidad utilizada. +- Señal temprana para decisiones de pricing, promociones o gestión de disponibilidad. +- Mejora del valor analítico del Dashboard sin incrementar complejidad operativa para el usuario final.