En este Episodio vamos a crear nuestra Aplicación Cliente la cual enviará las peticiones http GET a nuestro Servidor Datasnap para obtener información de los métodos Usuario y Habitaciones.
Escribiremos el código necesario para procesar los dos tipos de RESPONSE que vimos en el Episodio 2.2 y mostraré las diferencias de serializar los objetos JSONObject y FDJSONDataSets. Esto lo haremos en dos aplicaciones independientes que nos servirán de prueba para después implementar el código realizado en la Aplicación Cliente principal.
***En el siguiente video vamos a consumir los métodos Usuario() y Habitaciones() que nos regresarán la clase TJSONObject.
***En el siguiente video vamos a consumir los métodos getUsuario() y getHabitaciones() que nos regresarán la clase TFDJSONDataSets.
Ya vimos como enviar las peticiones GET y consumir los métodos de nuestro Servidor DataSnap y la implementación de los métodos en la Aplicación Cliente se harán con aquellos que nos regresan la clase TJSONObject ya que nos permitirá desarrollar clientes desde cualquier herramienta de programación y no solo desde RAD Studio, sin embargo ustedes podrán decidir cual será su favorito.
Dicho lo anterior, todas las peticiones GET, PUT y POST que se agreguen a partir ahora se escribirán con ResponseTJSONObject y solo haremos un método para las peticiones PUT y POST como ejemplo ilustrativo de la clase TFDJSONDataSets los cuales se consumirá en una pequeña aplicación por separado, los demás métodos se consumirán directamente en nuestra Aplicación Cliente.
***En el siguiente video vamos a implementar los métodos vistos anteriormente en nuestra Aplicación Cliente y se compilará para el Escritorio de Windows (Win10) y para el Escritorio de Linux (Ubuntu).
Con esto terminamos el Episodio 3. En el siguiente Episodio veremos como generar una app Android a partir de nuestra Aplicación Cliente Base.
***Mientras tanto los invito a iniciar sus pruebas con peticiones GET y consumir sus métodos con la opción que mas les interese.
Ya estamos listos para iniciar nuestro Proyecto Multiplataforma y lo primero que vamos a hacer es darle un nombre. En realidad no fue demasiado el tiempo que ocupé pero entre varios nombres que se me ocurrieron he elegido el siguiente:
Ahora, vamos a determinar «el que», «el como» y «el para qué» del proyecto y a partir de ahí crear nuestra base de datos.
Propósito
El sistema debe solicitar el registro del usuario que desea acceder al sistema. (Los perfiles de usuario no los veremos por ahora).
El sistema debe permitir al usuario ver el rack de habitaciones disponibles y ocupadas.
El sistema debe controlar las entradas de huéspedes.
El sistema debe permitir realizar cargos de consumos a la cuenta del huésped.
El sistema debe permitir a los clientes la búsqueda de habitaciones y ver sus detalles; costo, tipo de habitación, fotos, etc…
El sistema debe permitir consultar el estado de cuenta del huésped.
El sistema debe controlar la salida y los pagos de los huéspedes.
Definición
Nuestro sistema deberá contar con la información necesaria para poder controlar las habitaciones, su ocupación, todos los consumos de los huéspedes durante su estancia y la salida y pagos del huésped.
De acuerdo a lo anterior vamos a proceder a definir las tablas y su relación entre ellas, No vamos a profundizar en el diseño de una base de datos compleja ya que no es el objetivo que buscamos con el proyecto.
Tablas de la Base de Datos
Habitaciones
Tabla Catálogo
Esta tabla contendrá las habitaciones del hotel así como la información de precios y disponibilidad.
Tipo Habitación
Tabla Catálogo
Esta tabla contendrá los tipos de habitación y sus detalles.
Reservas
Tabla Operativa
En esta tabla se registrarán las entradas y salidas de las habitaciones del Hotel y nos servirá para mostrar el rack de habitaciones.
Clientes
Tabla Catálogo
Esta tabla contendrá la información de los huéspedes del Hotel
Consumos
Tabla Operativa
En ésta tabla se registrarán todos los cargos por consumos durante la estancia del huésped en el Hotel.
Pagos
Tabla Operativa
En esta tabla se registrarán todos los pagos que realice el huésped.
Empleados
Tabla Catálogo
En esta tabla se registrarán a los usuarios del sistema.
Productos
Tabla Catálogo
Catálogo de productos que el Hotel comercializa.
Relaciones
La Tabla HABITACIONES se relaciona con la Tabla TIPO_HABITACION a través del campo HABITACIONES.TIPO_HAB_ID con el campo TIPO_HABITACION.TIPO_HAB_ID.
La tabla RESERVAS se relaciona con la Tabla HABITACIONES a través del campo RESERVAS.HABITACION_ID con el campo HABITACIONES.HABITACION_ID y también con la Tabla CLIENTES a través del campo RESERVAS.CLIENTE_ID con el campo CLIENTES.CLIENTE_ID.
La Tabla CONSUMOS se relaciona con la Tabla RESERVAS a través del campo CONSUMOS.RESERVA_ID con el campo RESERVAS.RESERVA_ID y con la Tabla PRODUCTOS a través del campo CONSUMOS.PRODUCTO_ID con el campo PRODUCTOS.PRODUCTO_ID.
Por último la Tabla PAGOS se relaciona con la Tabla RESERVAS a través del campo PAGOS.RESERVA_ID con el campo RESERVAS.RESERVA_ID.
Diagrama Entidad Relación
Como pueden observar todas las tablas tienen una relación excepto la tabla EMPLEADOS la cual solo tendrá la función de permitir la entrada de usuarios al sistema.
*** No estamos considerando ningún acceso restringido (privilegios de usuario) ni contraseñas cifradas ya que no es parte del objetivo del proyecto.
Motor de Base de Datos
En mi caso he decidido utilizar el motor de Firebird para generar la Base de Datos del sistema, ustedes pueden elegir la que consideren mejor.
Campos Auto Incrementables
Para la asignación de nuestras llaves primarias como campos auto-incrementables se creó el generador (GEN_CAT_ID) el cual será ejecutado vía disparadores (Triggers) configurados en los eventos Before_Insert de cada una de las Tablas del sistema como se podrá observar en la definición de la base de datos que se muestra a continuación.
/******************************************************************************/
/* Generated by IBExpert 2021.8.1.1 26/08/2021 05:48:13 p. m. */
/******************************************************************************/
SET SQL DIALECT 3;
SET NAMES ISO8859_1;
CREATE DATABASE 'C:\AZTLAN\BASE\AZTLAN.FDB'
USER 'SYSDBA' PASSWORD 'masterkey'
PAGE_SIZE 16384
DEFAULT CHARACTER SET ISO8859_1 COLLATION ISO8859_1;
/******************************************************************************/
/* Generators */
/******************************************************************************/
CREATE GENERATOR GEN_CAT_ID START WITH 0 INCREMENT BY 1;
SET GENERATOR GEN_CAT_ID TO 0;
/******************************************************************************/
/* Tables */
/******************************************************************************/
CREATE TABLE RESERVAS (
RESERVA_ID INTEGER NOT NULL,
HABITACIONES_ID INTEGER NOT NULL,
CLIENTES_ID INTEGER NOT NULL,
FH_RESERVA DATE NOT NULL,
CHECKIN TIMESTAMP NOT NULL,
CHECKOUT TIMESTAMP NOT NULL,
ESTATUS VARCHAR(10) NOT NULL
);
CREATE TABLE CLIENTES (
CLIENTE_ID INTEGER NOT NULL,
NOMBRE VARCHAR(100) NOT NULL,
DIRECCION BLOB SUB_TYPE 1 SEGMENT SIZE 80,
TELEFONO VARCHAR(15),
GENERO VARCHAR(10) NOT NULL,
DNI VARCHAR(100),
ESTATUS VARCHAR(10) NOT NULL
);
CREATE TABLE EMPLEADOS (
EMPLEADO_ID INTEGER NOT NULL,
NOMBRE VARCHAR(30) NOT NULL,
MATERNO VARCHAR(30) NOT NULL,
PATERNO VARCHAR(30),
USUARIO VARCHAR(25) NOT NULL,
CLAVE VARCHAR(100) NOT NULL,
ESTATUS VARCHAR(10) NOT NULL
);
CREATE TABLE PRODUCTOS (
PRODUCTO_ID INTEGER NOT NULL,
TIPO VARCHAR(25) NOT NULL,
NOMBRE VARCHAR(100) NOT NULL,
COSTO DOUBLE PRECISION NOT NULL,
DESCRIPCION BLOB SUB_TYPE 1 SEGMENT SIZE 80 NOT NULL,
ESTATUS VARCHAR(10) NOT NULL
);
CREATE TABLE CONSUMOS (
CONSUMO_ID INTEGER NOT NULL,
PRODUCTOS_ID INTEGER NOT NULL,
RESERVAS_ID INTEGER NOT NULL,
FH_CONSUMO DATE NOT NULL,
CANTIDAD DOUBLE PRECISION NOT NULL,
COSTO DOUBLE PRECISION NOT NULL,
ESTATUS VARCHAR(10) NOT NULL
);
CREATE TABLE PAGOS (
PAGO_ID INTEGER NOT NULL,
RESERVAS_ID INTEGER NOT NULL,
IMPORTE DOUBLE PRECISION NOT NULL,
TIPO VARCHAR(20) NOT NULL,
OBSERVACIONES BLOB SUB_TYPE 1 SEGMENT SIZE 80 NOT NULL,
FH_PAGO DATE NOT NULL,
ESTATUS VARCHAR(10) NOT NULL
);
CREATE TABLE HABITACIONES (
HABITACION_ID INTEGER NOT NULL,
TIPO_HAB_ID INTEGER NOT NULL,
NUMERO VARCHAR(10) NOT NULL,
DETALLES BLOB SUB_TYPE 1 SEGMENT SIZE 80,
ESTATUS VARCHAR(10) NOT NULL
);
CREATE TABLE TIPO_HABITACION (
TIPO_HAB_ID INTEGER NOT NULL,
TIPO VARCHAR(100) NOT NULL,
DESCRIPCION BLOB SUB_TYPE 1 SEGMENT SIZE 80 NOT NULL,
FOTO VARCHAR(100) NOT NULL,
COSTO DOUBLE PRECISION NOT NULL,
ESTATUS VARCHAR(10) NOT NULL
);
/******************************************************************************/
/* Primary keys */
/******************************************************************************/
ALTER TABLE RESERVAS ADD CONSTRAINT PK_RESERVAS PRIMARY KEY (RESERVA_ID);
ALTER TABLE CLIENTES ADD CONSTRAINT PK_CLIENTES PRIMARY KEY (CLIENTE_ID);
ALTER TABLE EMPLEADOS ADD CONSTRAINT PK_EMPLEADOS PRIMARY KEY (EMPLEADO_ID);
ALTER TABLE PRODUCTOS ADD CONSTRAINT PK_PRODUCTOS PRIMARY KEY (PRODUCTO_ID);
ALTER TABLE CONSUMOS ADD CONSTRAINT PK_CONSUMOS PRIMARY KEY (CONSUMO_ID);
ALTER TABLE PAGOS ADD CONSTRAINT PK_PAGOS PRIMARY KEY (PAGO_ID);
ALTER TABLE HABITACIONES ADD CONSTRAINT PK_HABITACIONES PRIMARY KEY (HABITACION_ID);
ALTER TABLE TIPO_HABITACION ADD CONSTRAINT PK_TIPO_HABITACION PRIMARY KEY (TIPO_HAB_ID);
/******************************************************************************/
/* Foreign keys */
/******************************************************************************/
ALTER TABLE RESERVAS ADD CONSTRAINT FK_RESERVAS_1 FOREIGN KEY (HABITACIONES_ID) REFERENCES HABITACIONES (HABITACION_ID);
ALTER TABLE RESERVAS ADD CONSTRAINT FK_RESERVAS_2 FOREIGN KEY (CLIENTES_ID) REFERENCES CLIENTES (CLIENTE_ID);
ALTER TABLE CONSUMOS ADD CONSTRAINT FK_CONSUMOS_1 FOREIGN KEY (PRODUCTOS_ID) REFERENCES PRODUCTOS (PRODUCTO_ID);
ALTER TABLE CONSUMOS ADD CONSTRAINT FK_CONSUMOS_2 FOREIGN KEY (RESERVAS_ID) REFERENCES RESERVAS (RESERVA_ID);
ALTER TABLE PAGOS ADD CONSTRAINT FK_PAGOS_1 FOREIGN KEY (RESERVAS_ID) REFERENCES RESERVAS (RESERVA_ID);
ALTER TABLE HABITACIONES ADD CONSTRAINT FK_HABITACIONES_1 FOREIGN KEY (TIPO_HAB_ID) REFERENCES TIPO_HABITACION (TIPO_HAB_ID);
/******************************************************************************/
/* Triggers */
/******************************************************************************/
SET TERM ^ ;
/******************************************************************************/
/* Triggers for tables */
/******************************************************************************/
/* Trigger: RESERVAS_BI */
CREATE TRIGGER RESERVAS_BI FOR RESERVAS
ACTIVE BEFORE INSERT POSITION 0
as
begin
if (new.reserva_id is null) then
new.reserva_id = gen_id(gen_cat_id,1);
end
^
/* Trigger: CLIENTES_BI */
CREATE TRIGGER CLIENTES_BI FOR CLIENTES
ACTIVE BEFORE INSERT POSITION 0
as
begin
if (new.cliente_id is null) then
new.cliente_id = gen_id(gen_cat_id,1);
end
^
/* Trigger: EMPLEADOS_BI */
CREATE TRIGGER EMPLEADOS_BI FOR EMPLEADOS
ACTIVE BEFORE INSERT POSITION 0
as
begin
if (new.empleado_id is null) then
new.empleado_id = gen_id(gen_cat_id,1);
end
^
/* Trigger: PRODUCTOS_BI */
CREATE TRIGGER PRODUCTOS_BI FOR PRODUCTOS
ACTIVE BEFORE INSERT POSITION 0
as
begin
if (new.producto_id is null) then
new.producto_id = gen_id(gen_cat_id,1);
end
^
/* Trigger: CONSUMOS_BI */
CREATE TRIGGER CONSUMOS_BI FOR CONSUMOS
ACTIVE BEFORE INSERT POSITION 0
as
begin
if (new.consumo_id is null) then
new.consumo_id = gen_id(gen_cat_id,1);
end
^
/* Trigger: PAGOS_BI */
CREATE TRIGGER PAGOS_BI FOR PAGOS
ACTIVE BEFORE INSERT POSITION 0
as
begin
if (new.pago_id is null) then
new.pago_id = gen_id(gen_cat_id,1);
end
^
/* Trigger: HABITACIONES_BI */
CREATE TRIGGER HABITACIONES_BI FOR HABITACIONES
ACTIVE BEFORE INSERT POSITION 0
as
begin
if (new.habitacion_id is null) then
new.habitacion_id = gen_id(gen_cat_id,1);
end
^
/* Trigger: TIPO_HABITACION_BI */
CREATE TRIGGER TIPO_HABITACION_BI FOR TIPO_HABITACION
ACTIVE BEFORE INSERT POSITION 0
as
begin
if (new.tipo_hab_id is null) then
new.tipo_hab_id = gen_id(gen_cat_id,1);
end
^
SET TERM ; ^
El siguiente paso es inicializar algunas tablas para poder construir los métodos de nuestro Servidor DataSnap.
Tipo de Habitación
INSERT INTO TIPO_HABITACION (TIPO_HAB_ID, TIPO, DESCRIPCION, FOTO, COSTO, ESTATUS)
VALUES (NULL, 'SENCILLA', 'Habitación Sencilla una cama Matrimonial', 'C:\AZTLAN\FOTOS\SENCILLA.JPG', 1200, 'DISPONIBLE');
INSERT INTO TIPO_HABITACION (TIPO_HAB_ID, TIPO, DESCRIPCION, FOTO, COSTO, ESTATUS)
VALUES (NULL, 'DOBLE', 'Habitación Doble dos camas Matrimoniales', 'C:\AZTLAN\FOTOS\DOBLE.JPG', 1800, 'DISPONIBLE');
INSERT INTO TIPO_HABITACION (TIPO_HAB_ID, TIPO, DESCRIPCION, FOTO, COSTO, ESTATUS)
VALUES (NULL, 'JUNIOR SUITE', 'Habitación Junior Suite una cama Queen Size', 'C:\AZTLAN\FOTOS\JUNIORSUITE.JPG', 2800, 'DISPONIBLE');
INSERT INTO TIPO_HABITACION (TIPO_HAB_ID, TIPO, DESCRIPCION, FOTO, COSTO, ESTATUS)
VALUES (NULL, 'MASTER SUITE', 'Habitación Master Suite una cama King Size', 'C:\AZTLAN\FOTOS\MASTERSUITE.JPG', 4500, 'DISPONIBLE');
INSERT INTO TIPO_HABITACION (TIPO_HAB_ID, TIPO, DESCRIPCION, FOTO, COSTO, ESTATUS)
VALUES (NULL, 'TEMATICA', 'Habitación Temática una cama Queen Size', 'C:\AZTLAN\FOTOS\TEMATICA.JPG', 1500, 'DISPONIBLE');
COMMIT WORK;
Habitaciones
INSERT INTO HABITACIONES (HABITACION_ID, TIPO_HAB_ID, NUMERO, DETALLES, ESTATUS)
VALUES (NULL, 1, '100', 'Pantalla plana, Internet, Cafetera', 'LIMPIA');
INSERT INTO HABITACIONES (HABITACION_ID, TIPO_HAB_ID, NUMERO, DETALLES, ESTATUS)
VALUES (NULL, 2, '101', 'Pantalla plana, Internet, Servibar, Cafetera', 'LIMPIA');
INSERT INTO HABITACIONES (HABITACION_ID, TIPO_HAB_ID, NUMERO, DETALLES, ESTATUS)
VALUES (NULL, 3, '111', 'Pantalla plana, Internet, Servibar, Escritorio, Cafetera', 'LIMPIA');
INSERT INTO HABITACIONES (HABITACION_ID, TIPO_HAB_ID, NUMERO, DETALLES, ESTATUS)
VALUES (NULL, 4, '120', 'Pantalla plana, Internet, Servibar, Escritorio, Balcón, Cafetera', 'LIMPIA');
INSERT INTO HABITACIONES (HABITACION_ID, TIPO_HAB_ID, NUMERO, DETALLES, ESTATUS)
VALUES (NULL, 5, '430', 'Pantalla Plana, Cafetera', 'LIMPIA');
COMMIT WORK;
Con esto hemos terminado de diseñar nuestra Base de Datos que por supuesto nada tiene que ver con un ERP Hotelero, sin embargo, nos servirá perfectamente para los fines de éste proyecto multiplataforma.
En el siguiente episodio comenzaremos a construir los métodos REST de nuestro Back-End.
*** Mientras tanto los invito a publicar sus comentarios y/o sugerencias acerca de esta entrada.
Vamos a ver en varias entradas los cambios que se han hecho con el lanzamiento de RAD Studio XE7 pero específicamente los cambios hechos a FireMonkey.
En XE6 se tenía que elegir entre tres tipos de aplicaciones FireMonkey, aplicaciones de escritorio, Aplicaciones Metrópolis y aplicaciones móviles como lo podemos observar en el IDE de XE6.
En RAD Studio XE7 se ha creado una sóla opción donde se puede elegir tanto aplicaciones de escritorio como aplicaciones móviles, de hecho permite la creación de todas las plataformas soportadas, a ésta nueva forma de crear aplicaciones se le ha llamado «Multi-Device Aplication» y otra donde podemos crear aplicaciones Metrópolis.
Ésta característica Multi-Device está soportada en dos de las tres grandes bibliotecas de RAD Studio, FireMonkey y la RTL, la VCL no está soportada en ésta característica.
Personalmente me ha gustado mucho la nueva forma de acceder a las aplicaciones FireMonkey con la Multi-Device com lo podemos ver en las siguientes imágenes.
Como podemos ver, contamos con las 4 grandes plataformas Windows, OSX, iOS y Android y dentro de ellas podemos destacar la gran variedad de dispositivos incluyendo Google Glass.
Lo dicho, me gusta mucho ésta nueva versión de RAD Studio que cuenta con muchas mejoras y muchas cosas nuevas que iremos viendo poco a poco.
Nos leemos 🙂
Ésta entrada y cualquier código fuente publicado en ésta bitácora, son libres para su uso y publicación, lo único que te pido, si te parece justo, es mencionar la fuente de donde se obtuvo.