scieee AI-readable full text Open interactive document viewer

Repositorio Institucional de Documentos

Abstract

El alquiler de vehículos tradicional está en declive. La necesidad de mantener personas físicas en cada una de las oficinas donde haya vehículos, sumada a las esperas por parte del cliente mientras toman sus datos y escanean sus documentos de identidad, más la imposibilidad de reservar menos de 24h, hacen que la alternativa, el denominado “Car Sharing”, esté en auge. Con este sistema, desde una aplicación web se llevan a cabo las verificaciones de identidad que permiten dar de alta un usuario, que después podrá realizar reservas en menos de un minuto y conducir de inmediato. Además, se puede reservar el tiempo deseado: sólo se paga por lo que se conduce. El coche recibe la orden a través de su router 3G, y permite que el usuario, con su tarjeta magnética, abra el vehículo a la hora adecuada. Este proyecto emprendedor de la empresa de innovación tecnológica FringesCT ha cubierto el análisis, diseño e implementación de una aplicación web completa para poner en funcionamiento este nuevo paradigma de alquiler de vehículos en nuestro país. La implementación se ha realizado usando el framework para PHP Symfony (en su versión 2.0), que facilita el modelo vista controlador y el desarrollo modular, poniendo a tu disposición múltiples herramientas como Twig: un lenguaje generador de plantillas que facilitan la interacción con la base de datos. Doctrine, que acerca las entidades de la base de datos al modelo, de modo que las sentencias SQL son generadas a partir de funciones DQL en PHP. Symfony2 también aleja los ficheros de configuración, parámetros y aspectos de la seguridad y control de acceso del resto de la aplicación en ficheros YAML o XML. La aplicación es completa y autosuficiente para controlar toda la parte software del sistema carsharing (el hardware instalado en los vehículos no forma parte de este proyecto). La base de datos diseñada consta de 18 tablas, y se ha implementado utilizando MySQL. De cara a un administrador, la aplicación ofrece un back-end para interaccionar con las distintas entidades de la base de datos con las restricciones impuestas por los requisitos. De cara al usuario, éste puede realizar las funciones que se podrían esperar de un front-end, como registrarse, realizar búsquedas de vehículos en las localizaciones que desee y reservarlos, modificar y cancelar reservas cuando se le permita, gestionar sus datos, abrir incidencias... La aplicación también genera las facturas de los clientes dependiendo de la forma de pago elegida (domiciliación bancaria o tarjeta de crédito), la tarifa escogida por el usuario (normal, premium, ...), la categoría del vehículo (deportivo, familiar, económico, ...), la duración de reserva y distancia recorrida. Las facturas generadas son almacenadas en el servidor y enviadas por email a los clientes. También se mandan emails a los administradores para advertir de múltiples eventos, como nuevos usuarios registrados, incidencias abiertas por usuarios, adjuntos de un permiso de conducción subidos por un usuario para que se le valide y se le deje hacer reservas... Resumiendo, el proyecto se ha basado en los siguientes puntos: diseño, implementación, e instalación en el servidor de la aplicación web en PHP que permite una funcionalidad completa y automatizada del sistema de carsharing descrito. Velilla Alegre, David; Lema Camean, Paula; Bermejo Ruiz, José Manuel

Full text

    !"  # $%&'()  &*+' ,-" ./01 Aplicación web PHP completa y automatizada para alquiler de vehículos RESUMEN El alquiler de vehículos tradicional está en declive. La necesidad de mantener personas físicas en cada una de las oficinas donde haya vehículos, sumada a las esperas por parte del cliente mientras toman sus datos y escanean sus documentos de identidad, más la imposibilidad de reservar menos de 24h, hacen que la alternativa, el denominado “Car Sharing”, esté en auge. Con este sistema, desde una aplicación web se llevan a cabo las verificaciones de identidad que permiten dar de alta un usuario, que después podrá realizar reservas en menos de un minuto y conducir de inmediato. Además, se puede reservar el tiempo deseado: sólo se paga por lo que se conduce. El coche recibe la orden a través de su router 3G, y permite que el usuario, con su tarjeta magnética, abra el vehículo a la hora adecuada. Este proyecto emprendedor de la empresa de innovación tecnológica FringesCT ha cubierto el análisis, diseño e implementación de una aplicación web completa para poner en funcionamiento este nuevo paradigma de alquiler de vehículos en nuestro país. La implementación se ha realizado usando el framework para PHP Symfony (en su versión 2.0), que facilita el modelo vista controlador y el desarrollo modular, poniendo a tu disposición múltiples herramientas como Twig: un lenguaje generador de plantillas que facilitan la interacción con la base de datos. Doctrine, que acerca las entidades de la base de datos al modelo, de modo que las sentencias SQL son generadas a partir de funciones DQL en PHP. Symfony2 también aleja los ficheros de configuración, parámetros y aspectos de la seguridad y control de acceso del resto de la aplicación en ficheros YAML o XML. La aplicación es completa y autosuficiente para controlar toda la parte software del sistema carsharing (el hardware instalado en los vehículos no forma parte de este proyecto). La base de datos diseñada consta de 18 tablas, y se ha implementado utilizando MySQL. De cara a un administrador, la aplicación ofrece un back-end para interaccionar con las distintas entidades de la base de datos con las restricciones impuestas por los requisitos. De cara al usuario, éste puede realizar las funciones que se podrían esperar de un front-end, como registrarse, realizar búsquedas de vehículos en las localizaciones que desee y reservarlos, modificar y cancelar reservas cuando se le permita, gestionar sus datos, abrir incidencias... La aplicación también genera las facturas de los clientes dependiendo de la forma de pago elegida (domiciliación bancaria o tarjeta de crédito), la tarifa escogida por el usuario (normal, premium, ...), la categoría del vehículo (deportivo, familiar, económico, ...), la duración de reserva y distancia recorrida. Las facturas generadas son almacenadas en el servidor y enviadas por email a los clientes. También se mandan emails a los administradores para advertir de múltiples eventos, como nuevos usuarios registrados, incidencias abiertas por usuarios, adjuntos de un permiso de conducción subidos por un usuario para que se le valide y se le deje hacer reservas... Resumiendo, el proyecto se ha basado en los siguientes puntos: diseño, implementación, e instalación en el servidor de la aplicación web en PHP que permite una funcionalidad completa y automatizada del sistema de carsharing descrito. I II Índice general I. Memoria 1. Introducción. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3 1.1 El “Car Sharing” como nuevo modelo de transporte . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.2 Herramientas a utilizar durante el proyecto. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.3 Responsables del proyecto. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.4 Objetivos del proyecto. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.5 Estructura del documento. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2. Marco de trabajo: Symfony. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.1 Symfony: aprendizaje del framework. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.2 Modelo Vista Controlador con Symfony. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .8 2.3 Esqueleto de una aplicación construida sobre Symfony. . . . . . . . . . . . . . . . . . . . . . . . 8 2.4 Doctrine y los repositorios de entidades. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.4.1. Creación de la base de datos a partir de la consola de Symfony. . . . . . . . . . . . . . . . . 10 2.4.2. Creación de tablas a partir de meta-datos en las entidades php. . . . . . . . . . . . . . . . . . 10 2.4.3. DQL: Repositorios de entidades. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 3. Diseño de entidades y sus relaciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 3.1 Esquema de la base de datos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 3.2 Entidades. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 3.2.1. Grupo administrativo (AdminGroup). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 3.2.2. Factura (Bill). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 3.2.3. Reserva (Booking). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 3.2.4. Coche (Car). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 3.2.5. Tarjeta de crédito/débito (Card). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 3.2.6. Grupo de coches (CarGroup). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.2.7. Posición de un coche (CarPosition). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.2.8. Cliente registrado (Client). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.2.9. Conductor (Driver). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 3.2.10. Tarifa (Fare). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 3.2.11. Multa (Fine). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 3.2.12. Incidencia (Incident). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 3.2.13. Seguro (Insurance). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 3.2.14. Administrador de grupo (Manager). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 3.2.15. Ubicación de vehículos (Place) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 3.2.16. Promoción (Promotion) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 4. Enrutamiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 4.1 Resolución de URL (routing) en Symfony . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 4.2 Rutas públicas (de usuario no registrado) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 4.3 Rutas de cliente registrado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 4.4 Rutas de administrador de grupo (manager) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 4.5 Rutas de administrador general (super-admin) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 4.6 Rutas de acceso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 5. Seguridad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 5.1 Autenticación de usuarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 5.2 Autorización (control de acceso) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 III 5.3 Cifrado de conexiones: HTTPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 6. Controladores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 6.1 Estructura básica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 6.2 Formularios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 6.2.1. Constructor de formularios. Clases Type.php . . . . . . . . . . . . . . . . . . . . . . . . . . 32 6.2.2. Trabajo con formularios en los controladores . . . . . . . . . . . . . . . . . . . . . . . . . . 33 6.3 Traducciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 6.4 Subida de ficheros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 6.5 Históricos de cambios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 7. Plantillas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .37 7.1 El lenguaje Twig . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 7.2 Estructura multinivel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 7.3 Formularios en las plantillas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 7.4 Traducciones y filtros en plantillas Twig . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 7.5 Plantillas de facturas y correos electrónicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 7.6 Javascripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 8. Conclusiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 8.1 Resultados obtenidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 8.2 Desarrollos futuros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 II. Anexos Anexo A. Requisitos del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 A.1 Hardware de los vehículos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .47 A.2 Grupos administrativos y grupos de coches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 A.3 Usuarios no registrados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 A.4 Registro de usuarios y tipos de usuarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 A.5 Reservas de vehículos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 A.6 Manager de grupo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 A.7 Facturas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 A.8 Alertas por email . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 A.9 Producto final . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 A.10 Documentación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 Anexo B. Capturas de pantalla de la aplicación. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 B.1 Búsqueda de vehículos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 B.2 Pantalla de carga “Estamos buscando” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 B.3 Formulario de contacto. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 B.4 Nueva reserva. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 B.5 Elección del tipo de usuario al registrarse. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 B.6 Elección de tarifa al registrarse. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 B.7 Registro de usuario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 B.8 Registro de usuario (forma de pago: domiciliación). . . . . . . . . . . . . . . . . . . . . . . . .58 B.9 Login (formulario de acceso). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 B.10 Mapa de vehículos de un grupo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 B.11 Mapa: vehículos de una ubicación. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 B.12 Filtros del mapa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 IV B.13 Reserva de vehículos desde el mapa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 B.14 Formulario de alta de conductor. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 B.15 Filtro de facturas del usuario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 B.16 Promociones del usuario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .62 B.17 Información de la cuenta del usuario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 B.18 Gestión de una incidencia en la interfaz de usuario. . . . . . . . . . . . . . . . . . . . . . . . . 63 B.19 Gestión de tarjetas de un usuario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 B.20 Modificación de reserva por un usuario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 B.21 Filtro de reservas de un administrador. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 B.22 Categorías de los vehículos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 B.23 Listado de vehículos de un grupo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 B.24 Email de confirmación de usuario. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .66 B.25 Factura (página 1). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 B.26 Factura (página 2). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 Índice de figuras 1. Esquema de la base de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 2. Entidad grupo administrativo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 3. Entidad factura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14 4. Entidad reserva . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 5. Entidad coche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 6. Entidad tarjeta de crédito/débito . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 7. Entidad grupo de coches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 8. Entidad posición de un coche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 9. Entidad cliente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .17 10. Entidad conductor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 11. Entidad tarifa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 12. Entidad multa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .19 13. Entidad incidencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 14. Entidad seguro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .19 15. Entidad manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 16. Entidad ubicación de vehículos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .20 17. Entidad promoción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 18. Código del formulario de acceso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 19. Autenticación en security.yml . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 20. Proveedores de usuarios para el proceso de autenticación . . . . . . . . . . . . . . . . . . . . . . . 28 21. Control de acceso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 22. Directorio de subidas de ficheros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 V VI Parte I MEMORIA 1 sistemas gestores de bases de datos. Para poder probar de inmediato los conceptos aprendidos de la documentación de Symfony y entender mejor el MVC, se procedió a descargar el curso “deSymfony” [4], una serie de ponencias realizadas anualmente en España sobre el uso de Symfony que facilitan enormemente el entendimiento del mismo realizando paso a paso una aplicación sencilla pero completa. 2.2 Modelo Vista Controlador con Symfony Como ya se ha mencionado, Symfony facilita el uso del MVC al desarrollador. A continuación se va a explicar brevemente cómo trabaja desde que recibe una petición HTTP hasta que da una respuesta, generalmente en forma de página web. El motor de Symfony recoge las rutas de las peticiones (request) que le llegan al servidor, y las compara con su tabla de rutas, que se sitúa en ficheros de routing. Si detecta un patrón que encaja con una ruta reconocida, ejecuta la función del 'Controlador' correspondiente a esa ruta. El controlador es una función php cuyo objetivo final (su return) es devolver una respuesta HTTP a la petición recibida. Ésta respuesta suele contener simplemente una página web, que tendrá que ser renderizada a partir de una plantilla. Aquí entra en juego la 'Vista', que a su vez podría necesitar de información de la base de datos. Por ejemplo, si el usuario le pide al servidor que le muestre su información personal, preferencias de su cuenta, etc. Éste sería el 'Modelo'. Una vez explicadas estas nociones, se puede ver que una aplicación web enmarcada en Symfony consta de construir cuantas entidades sean requeridas por el modelo la base de datos, más la jerarquía de rutas y los controladores que las atenderán, más las plantillas a renderizar. De querer ampliar la aplicación, basta con añadir nuevas rutas, controladores y plantillas. 2.3 Esqueleto de una aplicación construida sobre Symfony En el siguiente apartado se va a indicar qué va dónde en el esqueleto facilitado por Symfony. De esta manera cuando más adelante en el documento se hable de que “se ha introducido una nueva ruta que ha llamado a cierto controlador”, se podrá entender mejor qué es lo que se está haciendo realmente, y sobre qué ficheros en particular podrían encontrarse estos cambios. CarSharing - Directorio raíz de la aplicación. app cache - Cache de la aplicación. Symfony la gestiona. Config security.yml - Fichero de seguridad. Autenticación y permisos. parameters.ini - Parámetros definidos (mailer, motor de la base de datos...) logs - Logs de la aplicación. Symfony los gestiona. Resources - En nuestra aplicación, utilizada para almacenar uploads. bin nbproject src - Contiene todo el código fuente, agrupado en bundles. CarSharingBundle - Bundle único de la aplicación. Controller - Controladores... BookingController.php - ...de rutas de reservas (e.g: /booking/list-all, /booking/new) 8 CarController.php - ...de rutas de coches (e.g: /admin/car/edit/Z1234BM) ClientController.php … Entity - Entidades (muchas de ellas con mapeo directo en la bb.dd) Booking.php - Clase, sus atributos y métodos, y metadata para la bb.dd. Car.php Client.php … Extension - Funciones PHP para Twig usadas en varias plantillas. Form - Formularios que se mostrarán en las distintas plantillas newBookingType.php adminEditBookingType.php - e.g: permite editar cualquier atributo de una reserva clientEditBookingType.php - e.g: sólo edita los campos “fecha inicio” y “fecha fin” … (un cliente no ha de poder modificar más cosas) Repository - Repositorios de funciones de acceso a bb.dd de cada Entidad BookingRepository.php CarRepository.php ClientRepository.php Resources config - Archivos de rutas routing.yml routing_booking.yml routing_car.yml … translations - Ficheros de textos mostrados en las plantillas messages.en.yml - Todos los textos de la aplicación, en inglés messages.es.yml views - Plantillas... Booking - ...referentes a reservas. edit.html.twig new.html.twig list.html.twig show.html.twig Car -...referentes a coches. edit.html.twig … … vendor - Bundles de terceros, como Doctrine, Twig, Swiftmailer... doctrine twig swiftmailer … web - Recursos web css - Hojas de estilos (CSS: Cascading Style Sheet) img - Imágenes públicas js - Scripts (javascript, jQuery, ...) Este es el esqueleto de Symfony en el caso particular de la nuestra aplicación. La estructura de carpetas, de cuyos direccionamientos internos se ocupa el motor de Symfony, permite abstraerse de problemas que no sean el desarrollo mismo de la aplicación cumpliendo requisito a requisito. 9 2.4 Doctrine y los repositorios de entidades Doctrine es un conjunto de librerías PHP centradas en proporcionar servicios de persistencia. Sus principales proyectos son ORM (Object Relational Mapper), y el nivel de abstracción de la base de datos sobre el que está construido[9]. El primero permite generar el SQL necesario para la creación de una base de datos con todas sus tablas y relaciones a partir de la información de mapeo de las entidades. El segundo, realizar consultas a la base de datos utilizando DQL (Doctrine Query Language) en lugar de SQL, el cual está más orientado a objetos, y que ofrece la ventaja de permitir portabilidad entre sistemas gestores de bases de datos sin que haya que adaptar todo el SQL. 2.4.1 Creación de la base de datos a partir de la consola de Symfony Para crear una base de datos desde la consola de Symfony necesitaremos tener configurado el fichero “app/config/parameters.ini” con el controlador, host, puerto, y credenciales del sistema gestor de bases de datos deseado. A continuación la configuración que se utilizó durante el desarrollo en local. (Nota: dicho fichero se excluyó del control de versiones Subversion, de manera que el servidor tuviera su propia configuración de la base de datos y no hubiera que reconfigurarlo tras cada commit/update). database_driver="pdo_mysql" database_host="localhost" database_port="" database_name="CarSharing" database_user="root" database_password="********" Con este fichero listo, se ejecuta el siguiente comando de la consola de Symfony desde el directorio raíz del proyecto (aquél que contiene app, src, vendors... consultar capítulo 1.3 para más información): app/console doctrine:database:create 2.4.2 Creación de tablas a partir de meta-datos en las entidades php El siguiente fragmento de código muestra una pequeña parte de la entidad Coche. De las entidades y cómo se ha llegado a su diseño se hablará con más detalle en el capítulo 3.2. Lo que pueden parecer simples comentarios sobre código php, son en realidad meta-datos utilizados por Doctrine para la generación de la base de datos. /**@ORM\Table(name="car") * @ORM\Entity * @ORM\Entity(repositoryClass="FringesCT\CarSharingBundle\Repository\CarRepository") */ class Car { /**@ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="IDENTITY") */ protected $id; /**@ORM\ManyToOne(targetEntity="AdminGroup", inversedBy="cars") * @ORM\JoinColumn(name="idAdminGroup", referencedColumnName="id") */ protected $adminGroup; /**@ORM\Column(type="string", length="20") */ protected $category; 10 /**@ORM\Column(type="date") */ protected $next_ITV; /**@ORM\Column(type="integer", nullable="true") * @Assert\Min(0) * @Assert\Max(100) */ protected $fuelLevel = NULL; […] } Resumiendo, se le está diciendo a Doctrine que cree una tabla llamada “car” mapeada por esta entidad, que tendrá las funciones de consulta en el fichero CarRepository. Su identificador será el atributo “id”, de tipo entero “integer”, tendrá una columna de tipo texto con capacidad máxima para 20 caracteres llamada “category”, otra columna de tipo fecha “date” llamada “next_ITV”, y otra de tipo entero que tendrá que estar comprendido entre 0 y 100, y que podrá ser NULL. Además, y esto es lo más potente que ofrece Doctrine de cara a la programación orientada a objetos, la entidad tendrá una relación N→1 hacia la entidad AdminGroup, invertida por el atributo “cars”. Es decir, se podrá obtener el objeto “grupo administrativo” con un simple método get, que no te devolverá el identificador del grupo (lo que se almacena realmente en la base de datos y que sirve para referenciar), sino que devolverá el objeto entero. De igual manera, cualquier objeto “AdminGroup” podrá hacer un get sobre su atributo “cars” y conseguir un vector con todos los objetos “Car” que lo tengan como grupo administrativo. Para decir a la consola de Symfony que cree las tablas de la base de datos a partir de los meta-datos, hay que escribir desde la ruta raíz de la aplicación el siguiente comando: app/console doctrine:schema:create 2.4.3 DQL: Repositorios de entidades La mejor forma de ver lo que aporta el DQL (Doctrine Query Language) a la aplicación es estudiar una función del repositorio BookingRepository, la función php que devuelve todas las reservas del grupo administrativo introducido desde la fecha $from hasta la fecha $to. Como se puede ver, la consulta es una string muy similar a la sintaxis SQL [10], a la que le introducimos los parámetros “grupo”, “desde” y “hasta” con funciones PHP sobre los placeholders introducidos en la cadena como palabras precedidas por dos puntos ( : ) En lugar de utilizar nombres de columnas de las tablas, gracias a Doctrine podemos abstraernos por completo de esa capa y utilizar entidades PHP y sus atributos. La llamada a “createQuery” convertirá la consulta en el SQL requerido por el sistema gestor de bases de datos que utilices, y “getResult” lanzará esa consulta, y te devolverá los resultados como un array de objetos de la clase entidad que estás buscando. public function findBookingsBetweenDates($group, $from, $to) { $em = $this->getEntityManager(); $consulta = 'SELECT x FROM CarSharingBundle:Booking x,CarSharingBundle:Car y, CarSharingBundle:Driver z, CarSharingBundle:Client w, CarSharingBundle:Place p WHERE x.car = y AND x.driver = z AND z.client = w AND y.place = p AND y.adminGroup = :group AND x.startDateTime >= :from AND x.startDateTime <= :to ORDER BY x.startDateTime DESC'; $query = $em->createQuery($consulta) ->setParameter('group', $group) ->setParameter('from', $from)->setParameter('to', $to); return $query->getResult();} 11 12 Capítulo 3 Diseño de entidades y sus relaciones 3.1 Esquema de la base de datos A partir de los requisitos se tenía una idea del problema en su conjunto, y la mejor forma de poner sobre el papel esta idea era en forma de un esquema de base de datos. Tras varios diagramas en sucio sobre las entidades necesarias y las relaciones entre ellas, se llegó al modelo relacional que se puede apreciar en la figura 1. La notación seguida refleja el identificador de cada entidad en negrita. Por orden alfabético, las entidades resultantes son: AdminGroup (grupo administrativo), Bill (factura), Booking (reserva), Car (coche), CarPosition (posición gps de un coche), Card (tarjeta de crédito/débito), Client (cliente, usuario registrado), Driver (conductor), Fare (tarifa), Fine (multa), Incident (incidencia), IncidentNote (comentario de una incidencia), Manager (administrador), Promotion (promoción). Se pueden contar un total de 17 entidades. Como se verá más adelante, finalmente se decidieron implementar los históricos de cambios de la aplicación en una tabla de la base de datos, por su sencillez a la hora de buscar y filtrar sucesos. Con ello, al final la base de datos cuenta con 18 tablas. 13 Figura 1: Esquema de la base de datos 3.2 Entidades Las entidades pensadas para la base de datos tienen su correspondencia directa con una clase php con su nombre. Es más: como se ha mencionado en el capítulo introductorio de Symfony, un comando de la consola de éste permite la creación de las sentencias SQL para la formación de la base de datos sólo a partir de las clases entidad en php. A continuación se listan los atributos de cada una de las entidades, describiendo las razones que han llevado a su diseño, con énfasis en aquellas que no sean tan intuitivas de ver. 3.2.1 Grupo administrativo (AdminGroup) Los grupos administrativos tendrán, aparte de su propio identificador, un grupo de coches. Varios grupos administrativos pueden tener el mismo grupo de coches. Esto será útil en el caso de que se quiera permitir, por ejemplo, tanto a usuarios de “Zaragoza” y “Huesca” ver y reservar coches de ambos grupos manteniendo las tarifas, managers, etc, independientes. Aparte del atributo groupName, el nombre del grupo, i.e “Zaragoza”, el resto son atributos necesarios para la facturación. Cada grupo constituye una entidad independiente, que necesita una razón social, teléfono, dirección, cuenta bancaria y el banco al que pertenece. 3.2.2 Factura (Bill) Las facturas deben estar mantenidas por motivos legales un mínimo de 5 años en la base de datos. Primero se pensó en que cuando se generase físicamente una factura, es decir, se extrajese la información de reservas y se crease un excel/pdf/el formato que se pensase, almacenar tan sólo el mismo fichero. Después pensamos que no costaba nada crear una entidad adicional y almacenar parte de esta información, para que los managers pudieran llevar el control de cuándo una factura había sido pagada y cuando no. Los atributos precedidos por una circunferencia blanca en lugar de un punto negro relleno, significan que pueden ser nulos. En este caso, idCard puede ser nulo si la reserva no se ha pagado con una tarjeta sino con cuenta corriente. El resto de atributos pueden ser nulos si no se ha generado todavía realmente la factura. Esto sucede en el caso de pago por tarjeta. Cuando se hace una reserva, con “tarjeta” como forma de pago, se crea también una entidad Factura, y la reserva queda enlazada a ella. Entonces, la entidad Factura es enlazada con la entidad Tarjeta que realizará el pago una vez finalice la reserva y se genere la factura “física”. 14 Figura 2: Grupo Administrativo Figura 3: Factura 3.2.3 Reserva (Booking) La entidad Reserva es una de las más relevantes en la aplicación, como cabe esperar en una aplicación web de reservas de vehículos. Se compone, como se puede apreciar en el diagrama de la base de datos (figura 1), de un Conductor (que a su vez estará en una cuenta de usuario registrado), un Coche, una Factura (generada posteriormente a la reserva), una Tarifa aplicada, y opcionalmente una Promoción. La tarifa (fare) es necesaria para persistir en el tiempo la reserva sin perder información. La tarifa aplicada a una reserva dependerá de si el cliente pertenece al mismo grupo administrativo que el coche (se pone la tarifa del cliente), o el coche pertenece a otro AdminGroup, que por tener el mismo CarGroup que el AdminGroup del Cliente, se le está mostrando también y por tanto ha podido reservarlo. En este caso, se aplica la tarifa por defecto “default fare” del AdminGroup del coche reservado. Si el usuario tenía alguna promoción activa a la hora de realizar la reserva, se aplica también en ésta. Las fechas de inicio y fin de reserva (start y endDateTime) son las seleccionadas por el usuario al reservar. ActualReturnDateTime es la fecha/hora a la que el conductor realmente devuelve el coche. Se utilizará para facturar al cliente si devuelve el coche pronto o tarde. BillingEndDateTime es la hora hasta la que se facturará. Sirve para que si el cliente ha reducido el tiempo de reserva cuando faltaba menos de media hora para el final, se le siga facturando toda como penalización por un cambio tan tardío que no permite a otros usuarios tener tiempo de poder reservar ese vehículo. Existen unos atributos necesarios para facturación, como los cargos por devolver el vehículo en un lugar distinto al punto de devolución estipulado, por dejar el depósito de combustible a menos de 1/3 de su capacidad, por envío a una dirección de recogida en particular (véase un aeropuerto), y otros posibles extras. De cancelar la reserva, podría tener que aplicarse un cargo por hacerse con poca antelación (los requisitos exactos se marcaron en las múltiples reuniones mantenidas a lo largo del desarrollo), y entonces habrá que registrarlo en la entidad Reserva. StartKm y EndKm marcan el kilometraje del vehículo al comienzo y al final de la reserva, lo cual se lee de los vehículos cuando sea posible, o se computa a partir de las posiciones GPS almacenadas cada poco tiempo del vehículo, para trazar la ruta seguida y poder facturar por kilómetros (ver “Hardware de los vehículos”, anexo A.1). El parámetro isActive indica si la reserva está activa, es decir, si se ha mandado ya la orden al coche de que se abra al usuario correspondiente cuando éste pase su tarjeta magnética por el lector. 15 Figura 4: Reserva 3.2.4 Coche (Car) El número de atributos a registrar de un coche es elevado. Como referencias a otras entidades están el grupo administrativo al que pertenece, el lugar (Place) donde está ubicado, y su seguro. Los siguientes atributos: marca (brand), modelo (model), color, matrícula (carPlateNumber), categoría (category), combustible (fuelType), fechas de las próximas ITV, cambios de ruedas y mantenimiento (inspection, wheelChange y revision), y fechas y resultados las anteriores. La IP es estática, y por lo tanto se puede almacenar como un atributo. Servirá para poder conectarnos al coche y leer su kilometraje (km) y el nivel de combustible del depósito (fuelLevel). El campo isActive permite deshabilitar un coche sin tener que borrarlo de la base de datos, y dejaría de ser mostrado a los clientes. Útil para darlo de baja o para llevarlo un día al taller. Los campos feat_ son características: si lleva o no aire acondicionado, el tipo de transmisión, nº de plazas y puertas, capacidad del maletero, emisiones CO2, y GPS. Los últimos 3 atributos, “en reserva activa”, “última latitud” y “última longitud” no fueron inicialmente diseñados, y sirven para agilizar la carga del servidor en una serie de procesos que se ejecutan cada pocos minutos sobre todos los coches de la aplicación. 3.2.5 Tarjeta de crédito/débito (Card) La entidad “Tarjeta de crédito/débito” tiene su número, cliente, tipo (crédito o débito), caducidad (expiry date), cvc, y nombre y dirección completa del titular. Frequent indica si se muestra la tarjeta al escoger forma de pago en reservas entre sus “tarjetas frecuentes” para ahorrarse introducir los detalles de nuevo. Y por último el atributo “guardada” (saved) indica si la tarjeta está permanentemente almacenada en la base de datos, o si se va a borrar en cuanto termine la reserva que está pagando y se cobre. Esto permite al usuario tener la seguridad de que no se va a almacenar información de sus tarjetas sin su consentimiento. 16 Figura 5: Coche Figura 6: Tarjeta de crédito/débito 3.2.6 Grupo de coches (CarGroup) Un grupo de coches es una entidad de muy alto nivel. No posee referencias a otras entidades. Los únicos atributos son su nombre, que tan sólo sirve como ayuda al administrador para no tratar con un simple identificador numérico; y los campos latitud, longitud y zoom, que marcan el punto exacto donde se centrará, y el zoom inicial con el que se mostrará el mapa de coches de la aplicación. 3.2.7 Posición de un coche (CarPosition) La entidad “Posición de un coche” registra dónde ha estado (latitud y longitud) un coche (idCar) en un determinado instante (dateTime). Posteriormente al diseño inicial se añadió el atributo “idBooking”, que se rellena con el identificador de una reserva en ese instante el coche estaba en una. Así, a la hora de recopilar todas las posiciones gps de un vehículo en una reserva para calcular los km que facturar, se podrán buscar todas las posiciones de esa reserva mucho más rápidamente. 3.2.8 Cliente registrado (Client) El cliente tiene como identificador su email, que a su vez sirve para que haga login en la aplicación, junto con su contraseña (password). Se comprueba que el email haya sido validado (email_isChecked). Se registra una referencia a su grupo administrativo (idAdminGroup), a su tarifa escogida (idFare) y a una promoción si la tiene suscrita (idPromotion). Se guarda también si es una empresa o no (isCompany), y en caso afirmativo, el nombre de ésta. El nombre y apellidos (firstName y lastName) son los del cliente, en caso de individual, o del responsable en caso de empresa. Se registra el DNI o VAT (u otro documento oficial si se es extranjero, de ahí el nombre genérico national_ID). Asimismo, todos los datos de contacto: dirección (address), código postal (postCode), ciudad (city), país (country), teléfonos (phoneNumber), fax. Se registra si el cliente quiere recibir o no las facturas por email (sendBillsToEmail), el tipo de pago escogido (paymentType), y su nº de cuenta, de ser pago por domiciliación bancaria. Si es pago por tarjeta, habrá una o más entidades tarjeta de crédito ligadas al Cliente. El idioma escogido (language), será en el que se le manden los emails, y el que se muestre por defecto al hacer login. Se guardará su número de tarjeta magnética RFID, y si ésta ha sido activada o no (card_isActive, por seguridad hay que asegurarse de que el cliente la reciba y lo confirme antes de activar una tarjeta que puede abrir vehículos). Como al usuario se le permiten dos cambios de tarifa (configurable) libres de cargo, 17 Figura 7: Grupo de coches Figura 8: Posición de coche Figura 9: Cliente web que acaban renderizando los controladores de todas las rutas expuestas tienden a estar más trabajadas que las de manager. Éste era un requisito del sistema: que las pantallas mostradas a un usuario no administrador fuesen especialmente atractivas visualmente (al fin y al cabo hay que captar nuevos usuarios). 4.4 Rutas de administrador de grupo (manager) Para evitar llenar innecesariamente el presente documento con rutas repetitivas, se empleará la terminología CRUD para las rutas de administración -el back-end- que son aproximadamente cuatro veces más numerosas que las del front-end (usuario no registrado y cliente registrado juntos). Las siglas CRUD indican Create, Read, Update, Delete (Crear, Leer, Actualizar, Borrar), las cuatro funciones básicas de administración que realizar sobre una entidad. •C – Create: Crear nuevo objeto de la entidad. (e.g: manager da de alta un vehículo) •R – Read: Mostrar un objeto existente de la entidad. (e.g: manager ve una reserva) •U – Update: Editar algún atributo de un objeto (e.g: manager aprueba a un conductor) •D – Delete: Eliminar objeto (e.g: manager borra a un usuario fraudulento no autorizado) /admin/index - Página inicial de manager. /admin/bill/list/{m1}-{y1}_{m2}-{y2} - Lista facturas entre dos fechas. /admin/bill/show/{id} - Descarga la factura {id}. (Anexo B.25, B.26) /admin/bill/changestate/{id} (AJAX) - Cambia el estado de la factura. Nota: el cambio de estado {pagado ←→ no pagado} se realiza de manera asíncrona para evitar un formulario sólo para este campo, por medio de una petición AJAX a través de jQuery [16]. /admin/booking/RUD - Ver, editar o borrar Reservas.(Anexo B.21) /admin/card/RUD - Ver, editar o borrar Tarjetas de crédito/débito. /admin/client/RUD - Ver, editar o borrar Clientes. /admin/driver/RUD - Ver, editar o borrar Conductores. /admin/fare/CRUD - Crear, ver, editar o borrar Tarifas. /admin/fine/CRUD - Crear, ver, editar o borrar Multas. /admin/incident/CRUD - Crear, ver, editar o borrar Incidencias. /admin/insurance/CRUD - Crear, ver, editar o borrar Seguros. /admin/place/CRUD - Crear, ver, editar o borrar Ubicaciones. /admin/promotion/CRUD - Crear, ver, editar o borrar Promociones. /admin/car/CRUD - Crear, ver, editar o borrar Coches. (Anexo B.23) /admin/car/category/list - Muestra las categorías de vehículos. (Anexo B.22) /admin/car/category/upload/{category} - Sube una nueva imagen de una categoría. 4.5 Rutas de administrador general (super-admin) /superadmin/index - Página inicial del administrador general /superadmin/manager/CRUD - Crear, ver, editar o borrar Administradores de grupos. /superadmin/admingroup/CRUD - Crear, ver, editar o borrar Grupos administrativos. 24 4.6 Rutas de acceso /access/login - Muestra el formulario de login. (Anexo B.9) /access/logout-redirect - Escoge página a la que redireccionarte tras hacer logout. /access/goto_group - Ruta redireccionada por Symfony en caso de login correcto. Carga - del idioma preferido y el grupo del usuario que ha iniciado sesión. /access/check - Ruta de seguridad de Symfony para la comprobación del login. /access/logout - Ruta de seguridad de Symfony para salir de la sesión. /access/denied - Ruta redireccionada por Symfony de no pasar el control de acceso. /access/remember-password - Ruta que muestra el formulario de recuperación de contraseña. /access/remember-check (post) - Controla el envío del formulario de recuperación de pass. /access/es - Cambia a locale: español. /access/en - Cambia a locale: inglés. 25 26 Capítulo 5 Seguridad Al final del capítulo 4 podíamos ver listadas las rutas de acceso. Algunas de estas rutas son algo especiales: no hay que capturarlas con ningún controlador, sino que se indica a Symfony en su fichero de seguridad que debe ocuparse de gestionarlas. La seguridad de una aplicación web Symfony se realiza en dos pasos, autenticación y autorización [2]. Primero, se verifica que seas quien dices ser (login), y después se decide si tienes permiso para acceder a un recurso (control de acceso). 5.1 Autenticación de usuarios El primer paso comienza por enviar el formulario con tus credenciales. Si observamos la figura 18, el formulario de acceso tiene como destino (action) la ruta de nombre “login_check”, y los inputs son “_username” “_password” y “_remember_me”. Lo que hay entre llaves es el lenguaje propio del generador de plantillas Twig. Cuando el controlador renderiza esta plantilla, busca la ruta llamada “login_check” y sustituye {{ path(“login_check”) }} por el pattern de la ruta, en este caso “/access/check”. Si nos fijamos en la figura 19 (un fragmento del fichero de seguridad) vemos que /access/check es el check path del login, así que Symfony capturará esta ruta y pondrá en marcha la autenticación. Además, '_username' y '_password' son los campos que espera recibir en el formulario, y que utilizará en el proceso. Entonces, comprobará si son válidos 27 Figura 18: Formulario de acceso (tanto para clientes como managers) Figura 19: Autenticación en security.yml (seguridad de Symfony) comparándolos a pares (usuario, contraseña) extraídos de sus entidades proveedoras de usuarios (figura 20, otro fragmento del fichero de seguridad), en este caso las que definimos como client_db y manager_db, entidades Client y Manager a través de su identificador, el email. De ser válidos, te lleva a la ruta /access/goto_group, la cual es capturada por el controlador que hemos escrito a tal efecto, que entre otras cosas comprueba el atributo “language” del cliente o manager que ha iniciado sesión, y cambia el locale (idioma actual en que se muestra la aplicación) al suyo. En la figura 19 también se observa que se define la ruta de logout de la aplicación como /access/logout, con lo que tampoco habrá que escribir un controlador que responda a esa ruta. Tras un logout la aplicación te lleva a la ruta /access/logout-redirect. El controlador de tal ruta se limita a mandarte de vuelta a la página inicial de tu grupo administrativo. 5.2 Autorización (control de acceso) La primera declaración que veíamos en la figura 19 es “login_path: /access/login”. Esa ruta es registrada como la de control de acceso para toda la aplicación. Esto significa que cada vez que un usuario intente acceder a una ruta protegida por el control de acceso (figura 21, otro fragmento más del fichero de seguridad), se comprobará si tiene los roles necesarios para que se le permita. Como se puede apreciar (figura 21), todas las rutas bajo la rama /user requieren del rol “ROLE_USER”. Las clases proveedoras de usuarios, Client y Manager, tendrán que estar definidas como “implements UserInterface”, y construir la función “getRoles()”. En el caso de Client, la función “getRoles()” devuelve: “array('ROLE_USER'); ”, en el caso de Manager devolverá rol de admin o de superadmin dependiendo de si tiene grupo administrativo (se tomó la decisión de que el administrador general o superadmin sería almacenado en la base de datos como cualquier manager, pero con la peculiaridad de que tendría nulo el atributo “idAdminGroup”). Si un cliente intenta acceder a una ruta bajo la rama /admin, como muestra la figura 21, el control de acceso comprobará que no tiene el rol necesario, y te llevará a la ruta definida en la figura 19 como: “access_denied_url: /access/denied”. La dicha ruta es capturada por un controlador que sí se ha escrito y que renderiza una plantilla con un sencillo mensaje del tipo: “No tiene los permisos necesarios para acceder aquí”. 28 Figura 20: Proveedores de usuarios para el proceso de autenticación Figura 21: Control de acceso 5.3 Cifrado de conexiones: HTTPS Lo último a remarcar de la figura 21 es el “requieres_channel: https”. Esto fuerza a que todas las rutas bajo esa rama usen el protocolo HTTPS (Protocolo de Transferencia de Hipertexto Seguro), es decir, vayan cifradas. Todo enlace de la aplicación generado a partir del motor de plantillas Twig: {{ path('nombre-ruta') }} cuya ruta esté bajo una rama que fuerce el https automáticamente utilizará este protocolo. Cabe destacar que para que esto funcione, el servidor deberá ser capaz de trabajar con el protocolo SSL (Secure Socket Layer). Las primeras pruebas realizadas en localhost no permitieron trabajar con el cifrado activo, pero tras el deploy en el servidor, que tenía instalado SSL, los dueños del hosting comenzaron a tramitar la obtención de un certificado digital por medio de una Autoridad de Certificación. Para más información sobre HTTPS[6], SSL[7] y certificados digitales y autoridades de certificación[8], consultar las referencias. 29 30 Capítulo 6 Controladores A lo largo de la memoria se ha utilizado el término controlador, definido como la función que ejecuta la aplicación cuando captura una petición con un patrón reconocido entre los archivos de enrutamiento. Este capítulo tratará de presentar la estructura de un controlador de la aplicación, y los diferentes elementos envueltos en él. 6.1 Estructura básica La estructura que sigue un controlador es la siguiente: fichero PHP que reúne funciones públicas que se ocupan de responder ante las rutas de una determinada rama. Por ejemplo, vamos a centrarnos en CarController, el controlador de las rutas de manager relacionadas con gestión de coches: /admin/car/CRUD (consultar el capítulo 4.4 para más información sobre rutas y CRUD). use Symfony\Bundle\FrameworkBundle\Controller\Controller; use FringesCT\CarSharingBundle\Entity\Car; use FringesCT\CarSharingBundle\Form\CarType; class CarController extends Controller { public function indexAction() {…} /admin/car/index →Lista coches public function showAction($id) {…} /admin/car/show/{id} →Detalles del coche {id} public function newAction() {…} /admin/car/new →Muestra form. de creación public function createAction() {…} /admin/car/create → Gestiona envío del form. public function editAction($id) {…} /admin/car/edit →Formulario de edición de {id} public function updateAction($id) {…} /admin/car/update →Envío del form. de {id} public function deleteAction($id) {} /admin/car/delete → Elimina el coche {id} } La consola de Symfony tiene un comando que genera la CRUD más básica posible para una entidad. Por ejemplo en este caso, simplemente escribiría estas tres líneas para indexAction: $em = $this->getDoctrine()->getEntityManager(); $entities = $em->getRepository('CarSharingBundle:Car')->findAll(); return $this->render('CarSharingBundle:Car:index.html.twig', array('entities' =>$entities)); Es decir, cuando un manager accediese a la ruta /admin/car/index, el servidor ejecutará el controlador indexAction, que no recibe parámetros, y extrae todos los coches de la base de datos a través de una función definida en el repositorio de “coche”. Los almacena sobre una variable ($entities), y pasa ésta como parámetro a la función “render”. Ésta renderizará la plantilla index.html.twig para a continuación formar una respuesta HTTP con la página web html formada. Dicha web será lo único que el navegador del manager a la espera reciba. Por desgracia esta aplicación tiene un importante requisito que nos impide generar todas las 31 CRUDs de forma automática: la separación de grupos administrativos. Un manager, pese a contar con el rol requerido por una ruta /admin, no deberá poder listar coches de grupos administrativos diferentes al suyo. Esto se soluciona leyendo de la sesión el nombre de usuario, y buscándolo en la base de datos, para extraer el objeto completo “Manager”. Mediante él, podemos acceder a su grupo administrativo, y pasarlo a una nueva función que definiremos en el repositorio CarRepository, que realizará una búsqueda de coches sólo en el grupo introducido. $username = $this->get('security.context')->getToken()->getUsername(); $manager = $em->getRepository('CarSharingBundle:Manager')->find($username); $group = $manager->getAdminGroup(); $entities = $em->getRepository('CarSharingBundle:Car')->findAllInGroup($group); 6.2 Formularios 6.2.1 Constructor de formularios. Clases Type.php Los formularios en Symfony funcionan a través de los archivos que terminan en Type.php (consultar el capítulo 2.3: esqueleto de una aplicación). Una entidad podrá tener múltiples formularios. Por ejemplo para el caso de las reservas, “Booking”, habrá un formulario de creación de nueva reserva (UserNewBookingType.php) para clientes registrados, los cuales podrán escoger el coche a reservar, conductor, fechas de inicio y fin, si contratar una reducción de franquicia para el seguro del vehículo,etc. Pero en cambio el formulario de edición (UserEditBookingType.php) sólo tendrá la posibilidad de cambiar la fecha de inicio y la de final de reserva. Un último formulario, el de managers (BookingType.php) contendrá todos los atributos de la entidad reserva, puesto que los administradores de un grupo están autorizados para cambiar cualquier atributo de una reserva sobre un coche de su grupo administrativo. A continuación se muestra un fragmento de esta clase. use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilder; class BookingType extends AbstractType{ protected $client, $translator; public function __construct($client, $translator){ $this->client = $client; $this->translator = $translator; } public function buildForm(FormBuilder $builder, array $options){ $builder ->add('driver', 'entity', array( 'label' => $this->translator->trans('form.booking.driver'), 'class'=>'\Entity\Driver', 'query_builder'=>function(\DriverRepository $repository) use ($this->client){ return $repository->createQueryBuilder('s') ->where('s.client = ?1') ->andwhere('s.removed = ?2') ->setParameter(1, $this->client ) ->setParameter(2, FALSE); } )) ->add('startDateTime', 'datetime', array( 'label' => $this->translator->trans('form.booking.start'), 'minutes' => array('00','10','20','30','40','50') )) } public function getName(){ return 'bookingform'; } } 32 Resumiendo, la clase ha de extender AbstractType, al constructor hay que pasarle las variables que necesitemos utilizar dentro, getName devuelve el atributo html nombre (“name”) con el que se mostrará el formulario una vez se renderice, y la función buildForm creará el formulario añadiendo los atributos de la entidad reserva que queramos. Se añaden dos atributos. El primero es el conductor, “driver”, de tipo “entity” de la clase “\Entity\Driver”. En el formulario html se mostrará un selector con tantas opciones como salgan de la consulta a la base de datos allí descrita. En la consulta se utiliza el parámetro “client”, por eso hay que pasarlo al constructor de la clase. Es decir, cuando el manager edita una reserva, tendrá un elemento donde seleccionar al conductor de entre la lista de conductores del cliente que no hayan sido dados de baja. También tendrá un conjunto de selects para la fecha y hora de inicio de la reserva, que limitará las opciones para el select “minutos” a slots de 10 min. La cantidad de opciones que permiten los ficheros de generación de formularios Type.php es muy elevada. Toda la información al respecto se puede encontrar en la documentación de Symfony, sección formularios [11]. 6.2.2 Trabajo con formularios en los controladores A continuación se muestra un fragmento del controlador de reservas para “editAction($id)”. Previo al código mostrado, se realizaría la búsqueda en base de datos del Manager a partir del username de la sesión, y se extraería su grupo a la variable $group. $booking = $em->getRepository('CarSharingBundle:Booking')->findInGroup($id,$group); $editForm = $this->createForm(new BookingType($booking->getDriver()->getClient(), $this->get('translator')), $booking); return $this->render('CarSharingBundle:Booking:edit.html.twig', array( 'booking'=>$booking, 'edit_form'=>$editForm->createView() )); Es decir, se busca en la base de datos la reserva que se pretender editar, y se utiliza para crear una instancia de formulario junto con el traductor de mensajes de la aplicación (ver apartado 6.3) y la entidad encontrada en la base de datos $booking en sí misma. Esto permitirá que el formulario de edición renderizado en el html aparezca relleno con los valores actuales de la reserva que se quiere editar. Si en vez de estar modificando una reserva se quisiera crear una de cero, en lugar de buscar la reserva a editar por su ID en la base de datos, y pasar esta entidad a “createForm”, le pasaríamos una nueva instancia de la entidad: “$booking = new Booking()”. Una vez el usuario de la aplicación ha rellenado un formulario y pulsa submit, vuelven a entrar en juego los controladores, esta vez atendiendo peticiones POST. En estos casos su estructura será la siguiente: 1. Comprobar que el usuario tiene permiso para interaccionar con esa entidad: mismo caso que el del manager intentando acceder a coches de un grupo administrativo distinto al suyo. 2. Comprobar que el formulario sea válido: “if($form->isValid())”. Si un atributo de la entidad no puede ser nulo, deberá aparecer en el formulario, y con el tipo adecuado. En el proceso de validación de formularios entran en juego las aserciones (Assert) de los metadatos de las entidades (ver en el capítulo 2.4.2 los comentarios sobre el atributo “fuelLevel”) 3. Ligar la entidad que se quiere crear (create) o editar (update) al formulario recibido: 33 Los correos electrónicos también están en formato HTML. Por ser tan numerosos (todas las diferentes alertas a administradores, los envíos de facturas a clientes...) se ha optado por diseñar una plantilla base de la que extiendan todos, email.html.twig, con estilos optimizados para los distintos navegadores y aplicaciones frecuentes. En el anexo B.24 se puede apreciar un correo electrónico de confirmación de usuario visualizado en Mozilla Thunderbird. 7.6 Javascripts Javscript es un lenguaje de programación del lado del cliente que permite, entre otras muchas cosas, que el navegador web que recibe el trozo de código o “script” pueda dar lugar a cambios en el contenido de la página, comunicarse asíncronamente con el servidor e interaccionar con el usuario [12]. A efectos de este proyecto, las antes listadas son las características del lenguaje de las que se hace uso. Las diferentes plantillas que generen html pueden tener códigos javascript embebidos. Se ha optado por destinar un bloque vacío en la plantilla base para que lo extiendan las plantillas que necesiten colocar ahí sus scripts, de manera que queden ordenados y sean fáciles de consultar. Tener javascript habilitado es obligatorio para el correcto funcionamiento del sitio web. La aplicación también hace uso de la popular librería jQuery [13], de ahí que se incluya en todas las plantillas web a través de la base. Algunos javascript son relativamente sencillos, como por ejemplo hacer que unas pestañas muestren u oculten una sección de una página web. Otros dominan el comportamiento entero de esa página web con el papel que desempeñan. Algunos ejemplos, en complejidad creciente: •En el mapa de coches podemos mostrar los filtros o volver al mapa mediante las pestañas superiores. (Ilustración en el Anexo B.10, B.12) •En el formulario de registro, si has escogido “particular” en vez de empresa, y eliges una tarifa que no tenga componente mensual, tendrán que generarse dinámicamente (condiciones controladas del lado del servidor mediante Twig) dos radio-buttons que permitan el pago por tarjeta (y por consiguiente mostrar el formulario de creación de una tarjeta), o por cuenta corriente (con su correspondiente input para introducirla). Además dependiendo de la opción escogida tendrá que ponerse o quitarse de algunos campos del formulario el atributo html5 required [14]. (Anexo B.7, B.8) •En el mapa, al introducir una dirección y pulsar el botón correspondiente o la tecla intro se realiza una serie de tratamiento sobre la cadena de caracteres introducida, añadiéndole el nombre del grupo administrativo si procede, o el país. Después, se manda ese texto a Google para que devuelva las coordenadas encontradas, y se pinta un “pin” sobre el mapa en dicho punto, centrándolo además sobre él. •Al pinchar sobre un pin que representa una ubicación de vehículos sobre el mapa, se genera en la barra lateral una sección con todos los coches del lugar, con sus formularios correspondientes para poderlos reservar. (Anexo B.11) •Cuando se intenta reservar un coche desde el citado mapa, se muestra una pantalla en la que si estás registrado como usuario te aparecerá una tabla para seleccionar gráficamente el intervalo de tiempo de la reserva, con un código de colores para cada 10 minutos que mostrará si el coche está libre u ocupado para ese intervalo. Esto ha requerido numerosos cómputos temporales para asegurar una cómoda usabilidad por parte del usuario, que pueda 40 seleccionar el intervalo a la inversa (primero la hora final y luego la inicial), aparte de trabajo con las hojas de estilos, y generación dinámica de URLs. (Anexo B.13). •En las búsquedas de coches, se realiza desde el servidor para ahorrar tiempos de espera una carga de todos los disponibles que cumplan los parámetros de la búsqueda, y después se paginan con javascript, dependiendo de las variables: nºcoches resultantes de la búsqueda, nºcoches por página. Los mismos índices cambian dependiendo de la página en que te encuentres. (Anexo B.1). •En las búsquedas de vehículos se han incorporado calendarios selectores de fechas (datepickers). Se han utilizado los de la librería jQueryUI, para lo cual se ha tenido que realizar una precarga de librerías, y un script de inicialización con las opciones de configuración deseadas. Además, era necesario traducir manualmente los nombres de los meses a la hora de realizar la internacionalización (i18n) de la aplicación [15]. •El “select” de la búsqueda de localizaciones (también el del filtro de reservas del manager) se ha sustituido por medio de un script por un combo-box de jQueryUI, que además de la flecha (dropdown) que muestra todas las opciones del selector, permite escribir para que se filtren. •Las esperas en las búsquedas de coches y su posterior reserva podían llegar a alargarse un poco debido a que el servidor tiene que realizar comprobaciones en la base de datos con grandes volúmenes de registros. Por ello, se puso en marcha una pantalla “Estamos buscando...” para que el usuario no se cansase de esperar y quizá pulsase “atrás”. Para que dichas pantallas se mantuviesen en todos los navegadores, fue necesario realizar el envío del formulario de forma asíncrona. Gracias a las funciones de soporte para AJAX de jQuery[16], esto fue mucho más rápido y no se tuvo que rediseñar ningún controlador, sólo incorporar los cambios en algunas plantillas. (Anexo B.2). 41 42 Capítulo 8 Conclusiones 8.1 Resultados obtenidos Se puede concluir que los resultados obtenidos son satisfactorios, habiéndose cubierto cada punto del listado de requisitos del que se partió. En la introducción se describía un resumen de éste, siendo el listado completo el que se ha adjuntado al presente documento en el anexo A. Dichos requisitos han podido ser modificados a lo largo del desarrollo conforme ha sido necesario, para adaptarse a las necesidades cambiantes que implica un proyecto de un año de duración. El gran volumen del software desarrollado ha imposibilitado una explicación más detallada de las diferentes decisiones tomadas cada vez que se presentaba un problema durante el proyecto. Las aproximadamente 700 horas invertidas han producido más de 50.000 líneas de código y 156 plantillas para renderizar páginas web diferentes bajo más de 200 rutas y otros tantos controladores. Una selección de imágenes ilustrativas de la aplicación se ha adjuntado al presente documento en el anexo B. Además del código, era requisito preparar una documentación que detalla cómo se llevó a cabo la instalación (deploy) del producto en el hosting preparado para tal efecto por la empresa. Aquí se deja constancia de cómo bajarse el código desde el repositorio de Subversion con el que se fue trabajando para guardar los avances en sucesivos commits. También se explican conceptos de configuración: cómo cambiar el mailer de la aplicación, cómo instalar nuevos grupos de coches o administrativos, nuevos idiomas, cómo cambiar el zoom por defecto con el que se muestra el mapa de Google de un grupo administrativo, etc. Al contener información privada del acceso a servidor y bases de datos no se ha podido incluir como anexo a la presente memoria 8.2 Desarrollos futuros El desarrollo de ésta aplicación deja abierto un camino hacia su constante mejora. Los más evidentes y sencillos añadidos que se pueden llevar a cabo sobre la aplicación: incluir nuevos idiomas (que ya es un trabajo costoso de por sí, dados los varios miles de líneas que ocupa cada fichero contenedor de los textos en un idioma). Algunos de éstos posibles nuevos desarrollos: •Nuevas funcionalidades, atajos para el administrador. •Trabajar más sobre la API de Google utilizada para los Maps para incluir opciones como trazar gráficamente la ruta seguida por un vehículo, para estudios estadísticos de hábitos de consumo (rutas más frecuentes donde podría interesar colocar más vehículos). •Ver en tiempo real la ubicación cambiante de los vehículos. •Implementación de algoritmos de búsqueda más rápidos. •Desarrollo de una web más sencilla para los dispositivos móviles con opciones reducidas. 43 44 Parte 2 ANEXOS 45 46 Anexo A Requisitos del sistema A.1 Hardware de los vehículos El hardware que se instalará en los coches se compondrá de los siguientes elementos: (NOTA: Este proyecto no comprende la instalación del hardware en los coches, este apartado es meramente informativo para ayudar a la comprensión del sistema que se desea desarrollar). •Router 3G con IP fija. •Lector de tarjetas de proximidad al que se accede a través del router. •Opcional: botón de fin de reserva (lo pulsaría el usuario al finalizar la misma). NOTA: Configuraremos una variable adicional booleana que se active o no con este botón. •Opcional: señal de bloqueo de puertas (se envía desde la app en remoto – se programará por si alguien deja el coche abierto, forma parte del SDK del lector de tarjetas; simplemente configuramos una variable booleana con esta acción, la forma de enviarla se configurará una vez estudiado el SDK). Simplemente corresponderá a un atributo de cada coche, que será booleano y tendrá un click desde los interfaces de manager. El método al que llamará quedará vacío con un comentario de cuál es el motivo (indicar dónde está en la documentación). •Señal del cuentakilómetros, cuando se pueda recoger del coche, nos permitirá el calculo de los kilómetros de cada reserva. •GPS, se utilizará la localizar el coche en cada momento y para calcular los km de las reservas si la señal de cuentakilómetros no está disponible. A.2 Grupos administrativos y grupos de coches •Un grupo administrativo es un grupo de usuarios, coches, tarifas y promociones (y todas las correspondientes variables secundarias derivadas de su funcionalidad) identificados por un código de grupo administrativo, e independiente del resto de grupos. •Cada grupo administrativo es gestionado por uno o varios managers. •Un manager puede gestionar un único grupo administrativo. •Los usuarios, coches, promociones, etc. nunca cambiarán de grupo administrativo a lo largo de la vida de la aplicación. •Adicionalmente se definen los grupos de coches (CarGroup). Cada coche tendrá un idCarGroup (identificador de grupo de coches), y un idAdminGroup (del grupo administrativo). •A lo largo de la vida de la aplicación, es posible modificar el grupo de coches de un grupo administrativo actuando directamente sobre la bb.dd (especificar los objetos que es 47 necesario cambiar en la documentación). •El parámetro idCarGroup indica los coches puede visualizar (define los posibles valores del desplegable LUGAR DE RECOGIDA) un usuario no registrado que accede a la Web en el portal de un grupo en particular. •Si un usuario registrado escoge un coche que no pertenece a su grupo administrativo, se le asignará la tarifa por defecto de ese grupo administrativo (será un atributo de AdminGroup). La idea de la dualidad de grupos administrativos y grupos de coches es el poder ampliar ubicaciones de vehículos en una nueva ciudad, sin que sean visibles para un usuario de otro grupo. Por ejemplo, si hay un grupo “Madrid”, y la empresa comienza a hacer pruebas de expansión a “Guadalajara”, se crea un nuevo grupo administrativo, transparente a los viejos usuarios, con distintas tarifas. Si llegado el momento los gestores deciden que ambos grupos puedan ver y reservar coches tanto de una como de otra ciudad, se crearía un nuevo “grupo de coches”. Todos los coches de ambas ubicaciones cambiarían su idCarGroup al nuevo grupo común. De esta manera, los usuarios, coches y tarifas seguirían siendo administradas por separado por sus managers, distintos e independientes, pero los usuarios tendrían visibilidad y posibilidad de realizar reservas sobre todos los vehículos. Si un usuario de Madrid hace una reserva sobre un coche de Guadalajara, se aplicaría la tarifa “por defecto” de Guadalajara. A.3 Usuarios no registrados •Un usuario no registrado podrá ver los coches (de igual modo que un usuario registrado) pero, cuando este usuario pulsa el botón reservar, el sistema le mostrará dos opciones: Login y Aún no estás registrado? •Se mostrará un mapa con las ubicaciones de los vehículos, donde se podrá ver sus características y pasar a reservarlos, previo login o registro. •Cuando un usuario no registrado accede, su pantalla principal será de modo similar a Hertz: verá una pestaña desplegable donde aparecen las posibles ubicaciones a elegir, fecha y hora de inicio, fecha y hora final, o tiempo total de reserva (intervalos de 10 min), código de promoción. •Una vez elegidos estos parámetros, se mostrará un listado de coches (con los intervalos horarios disponibles, cambiando de color el intervalo elegido –leyenda) con este orden: 1º. Coches disponibles en el lugar elegido y de la categoría elegida. 2º. Coches disponibles en el lugar elegido de otras categorías (del más barato al más caro). 3º. Coches disponibles en el lugar más cercano al lugar elegido y de la categoría elegida. 4º. Coches disponibles en el lugar más cercano al lugar elegido de otras categorías. 5º. Coches disponibles del segundo elegido y de la categoría elegida. ... (Hasta el cuarto lugar más cercano). •Habrá un código de colores para indicar el estado de los intervalos temporales. La documentación debe incluir cómo y dónde cambiar estos colores. A.4 Registro de usuarios y tipos de usuarios •Aparecerá una pantalla preguntando si es empresa o particular. •Los particulares pueden dar de alta un conductor adicional y las empresas a todos los que quiera. Cada vez que se dé de alta a un conductor adicional es necesario que nos llegue una notificación para comprobar la documentación. 48 •Para enviar el formulario de registro, el usuario debe aceptar las condiciones del contrato (un clic sin marcar por defecto). •Si hay algún error de formato en el formulario o algún campo obligatorio vacío, el usuario vuelve al formulario y puede ver marcado en rojo el error. (Extensible a cualquier formulario de la aplicación). •Si el formulario se ha rellenado correctamente, se mostrará un mensaje que indicará al usuario que recibirá un email de confirmación en unos minutos. •El correo electrónico enviado al usuario permitirá a la aplicación verificar que el email introducido es correcto. Pinchar en el enlace dispuesto en tal correo activará la cuenta del usuario. •También se envía notificación de aviso al administrador de grupo, para que compruebe los datos del usuario y lo valide definitivamente. •En el formulario de registro siempre se comprueban los formatos y, en caso de error, aparecen los mensajes de ayuda correspondientes. Esto se extiende a cualquier formulario de la aplicación. •Al finalizar el registro, se comprueba la tarifa elegida. Si el valor de la cuota mensual es igual a cero, podrá escoger entre dar su número de cuenta para domiciliar los pagos o utilizar la pasarela de pago con tarjeta. Si hay una cuota mensual, la única forma de pago será domiciliación bancaria. •En caso de domiciliación, aparecerá un adjunto para que suba un recibo de la cuenta en la que quiere domiciliar los pagos. A.5 Reservas de vehículos •Los slots temporales están divididos en 10 minutos. Es decir, un usuario puede reservar un coche a en punto, y diez, y veinte, y media, menos veinte o menos diez. Éste será un parámetro configurable. Añadir en la documentación cómo cambiarlo. •Cada reserva deja inutilizado el intervalo de 10 minutos siguientes. De este modo, evitamos que las reservas solapen. •Cada reserva tiene 10 min de cortesía: 5 min antes y 5 min después, en los que la reserva no contará como “devuelta tarde”, y por tanto no se cargará un plus. •La reserva mínima es de 10 minutos. No se puede reservar menos tiempo ya que es el intervalo mínimo. •Se permitirá al usuario escoger el conductor que llevará el vehículo (un usuario tipo empresa puede tener muchos conductores registrados bajo la misma cuenta). •Se permitirá contratar una reducción de franquicia del seguro del vehículo, con 2 opciones: una pequeña cuota sólo para ésta reserva, o una contratación para 1 año de reducción de franquicia en todas sus reservas. •Si no hay domiciliación, sale la pasarela de pago y un mensaje indicando que si quiere cambiar la forma de pago vaya a sus datos. A.6 Manager de grupo •La interfaz de manager permitirá modificar cualquier parámetro de las reservas de los usuarios de su grupo, ver las facturas de éstos y marcarlas como pendientes de pago o pagadas; dar de alta, de baja o modificar parámetros de sus coches, promociones, tarifas y usuarios; revisar permisos de conducción de nuevos conductores para autorizarlos, así como 49 B.5 Elección de tipo de usuario al registrarse B.6 Elección de tarifa al registrarse 56 B.7 Registro de usuario 57 B.8 Registro de usuario (forma de pago: domiciliación) B.9 Login (formulario de acceso) 58 B.10 Mapa de vehículos de un grupo B.11 Mapa: vehículos de una ubicación 59 B.12 Filtros del mapa B.13 Reserva de vehículos desde el mapa 60 B.14 Formulario de alta de conductor B.15 Filtro de facturas del usuario 61 B.16 Promociones del usuario B.17 Información de la cuenta del usuario 62 B.18 Gestión de una incidencia en la interfaz de usuario B.19 Gestión de tarjetas de un usuario 63 B.20 Modificación de reserva por un usuario B.21 Filtro de reservas de un administrador 64 B.22 Categorías de los vehículos B.23 Listado de vehículos de un grupo 65