En este caso práctico vamos a añadir un botón que muestre una ventana que nos posibilite cambiar la descripción de un artículo. Es importante tener en cuenta que se trata de un ejemplo genérico. Si lo quieres implementar en tu entorno debes asegurarte de que estás obteniendo los datos deseados.


A rasgos generales, vamos a necesitar:

  • Un modelo que muestre y modifique la información
  • Subproceso que muestre el modelo --> un proceso para encapsularlo --> un menú para llamarlo
  • Subproceso que llame al procedimiento almacenado que devuelva los datos deseados --> un proceso para encapsularlo --> un menú para llamarlo
  • Subproceso que llame al procedimiento almacenado que actualice los datos --> un proceso para encapsularlo -->  un menú para llamarlo
  • Menú que agrupe los dos procesos anteriores


Antes de comenzar con el personalizador, crearemos los procedimientos almacenados en la base de datos. Para continuar, debemos asegurarnos de que el resultado es el deseado. Así, luego será más fácil comprobar que nuestra personalización es correcta.


El primer procedimiento almacenado devuelve la descripción del artículo seleccionado.


-- Crea el procedimiento almacenado que traerá la descripción de la base de datos
CREATE PROCEDURE [dbo].[pPers_TPV_DameDescrip]
  @iXML XML,
  @oXML XML OUTPUT
AS
-- =============================================
-- #AUTHOR:  
--      rmarti
-- #NAME:
---      [pPers_TPV_DameDescrip]
-- #CREATION: 
--      
-- #CLASIFICATION:
--      TPV
-- #DESCRIPTION:
--      Muestra descrip artículos
-- #PARAMETERS:
--      @iXML: 
--        IdArticulo:  Id del artículo a editar
--        
--        
--      @oXML:      descrip del artículo buscado, o mensaje de error
-- #OBSERVATIONS: 
--
-- #CHANGES:    select * from articulos
--    
-- #EXAMPLE: 
--      DECLARE @iXML xml
--      DECLARE @oXML XML
--
--      SET @iXML = '<data>
--              <IdArticulo>TRIMESTRES_SEGURO</IdArticulo>       
--            </data>'
--      EXEC [pPers_TPV_DameDescrip] @iXML, @oXML OUTPUT
--      SELECT @oXML
-- =============================================

-- Parámetros

DECLARE @IdArticulo  T_Id_Articulo
DECLARE @Descrip  varchar(255)




BEGIN TRY
  BEGIN TRAN

  -- Obtener parámetros de entrada
  ;WITH Datos AS (
    SELECT 
      IdArticulo = T.C.value('IdArticulo[1]', 'VARCHAR(50)')
    FROM @iXML.nodes('./data') T(C)
  )
  SELECT 
    @IdArticulo = D.IdArticulo
    
  FROM Datos D
    
    
  select @Descrip= descrip from articulos where IdArticulo= @IdArticulo  

  SELECT @oXML = '<Resultado>
            <Respuesta>
              <Estado>ok</Estado>
              <Mensaje>Artículo encontrado: ' + @IdArticulo + '</Mensaje>
            </Respuesta>
            <data>
              <Descrip>' + @Descrip + '</Descrip>
            </data>
            <view />
          </Resultado>'
  ------------------------------------------------------------------------------------------------
  COMMIT TRAN
  RETURN -1
END TRY     

BEGIN CATCH
  IF @@TRANCOUNT>0 ROLLBACK TRAN

  DECLARE @CatchError NVARCHAR(MAX)  
  SET @CatchError = CASE 
            WHEN ERROR_NUMBER()=3609 OR ERROR_NUMBER()=266 THEN '' 
            ELSE dbo.funImprimeError(ERROR_MESSAGE(), ERROR_NUMBER(), ERROR_PROCEDURE(), @@PROCID, ERROR_LINE())
          END

  SELECT @oXML = '<Resultado>
            <Respuesta>
              <Estado>error</Estado>
              <Mensaje>' + @CatchError + '</Mensaje>
            </Respuesta>
            <data />
            <view />
          </Resultado>'
  RETURN -1
END CATCH

GO


-- Asigna permisos al procedimiento almacenado que acabas de crear
zpermisos 'pPers_TPV_DameDescrip'
GO


-- Inserta un registro en la tabla API_EXEC con el procedimiento almacenado  que acabas de crear para que se pueda llamar desde el TPV
If Exists (select * from API_EXEC where ProcName = 'pPers_TPV_DameDescrip')
DELETE FROM API_EXEC WHERE ProcName = 'pPers_TPV_DameDescrip'
GO
INSERT INTO API_EXEC (ProcName)
  SELECT 'pPers_TPV_DameDescrip'
GO


El segundo procedimiento almacenado guarda la descripción modificada.



CREATE PROCEDURE [dbo].[pPers_TPV_Artic_Guardar]
  @iXML XML,
  @oXML XML OUTPUT
AS
-- =============================================
-- #AUTHOR:  
--      rmarti
-- #NAME:
---      pPers_TPV_Artic_Guardar
-- #CREATION: 
--      
-- #CLASIFICATION:
--      TPV
-- #DESCRIPTION:
--      Modifica descrip artículos
-- #PARAMETERS:
--      @iXML: 
--        IdArticulo:  Id del artículo a editar
--        Descrip:  descripción nueva      
--      @oXML:      Resultado y código de artículo editado o mensaje de error
-- #OBSERVATIONS: 
--
-- #CHANGES:    select * from articulos
--    
-- #EXAMPLE: 
--      DECLARE @iXML xml
--      DECLARE @oXML XML
--
--      SET @iXML = '<data>
--              <IdArticulo>TRIMESTRES_SEGURO</IdArticulo> 
--              <Descrip>Artic modificado</Descrip>  
--            </data>'
--      EXEC pPers_TPV_Artic_Guardar @iXML, @oXML OUTPUT
--      SELECT @oXML
-- =============================================

-- Parámetros

DECLARE @IdArticulo  T_Id_Articulo
DECLARE @Descrip  varchar(255)




BEGIN TRY
  BEGIN TRAN

  -- Obtener parámetros de entrada

    SELECT 
      @IdArticulo = T.C.value('IdArticulo[1]', 'VARCHAR(50)'),
      @Descrip = T.C.value('Descrip[1]', 'VARCHAR(255)')
    FROM @iXML.nodes('./data') T(C)


  IF @Descrip ='' begin 
  RAISERROR('No se puede actualizar un artículo sin descripción',12,1)
  end
  
  
  UPDATE Articulos set Descrip = @Descrip where IdArticulo = @IdArticulo
    
    

  SELECT @oXML = '<Resultado>
            <Respuesta>
              <Estado>ok</Estado>
              <Mensaje>Artículo guardado correctamente: ' + @IdArticulo + '</Mensaje>
            </Respuesta>
            <data>
              <IdArticulo>' + @IdArticulo + '</IdArticulo>
            </data>
            <view />
          </Resultado>'

          
  ------------------------------------------------------------------------------------------------
  COMMIT TRAN
  RETURN -1
END TRY     

BEGIN CATCH
  IF @@TRANCOUNT>0 ROLLBACK TRAN

  DECLARE @CatchError NVARCHAR(MAX)  
  SET @CatchError = CASE 
            WHEN ERROR_NUMBER()=3609 OR ERROR_NUMBER()=266 THEN '' 
            ELSE dbo.funImprimeError(ERROR_MESSAGE(), ERROR_NUMBER(), ERROR_PROCEDURE(), @@PROCID, ERROR_LINE())
          END

  SELECT @oXML = '<Resultado>
            <Respuesta>
              <Estado>error</Estado>
              <Mensaje>' + @CatchError + '</Mensaje>
            </Respuesta>
            <data />
            <view />
          </Resultado>'
  RETURN -1
END CATCH



GO



-- Asigna permisos al procedimiento almacenado que acabas de crear
zpermisos 'pPers_TPV_Artic_Guardar'
GO


-- Inserta un registro en la tabla API_EXEC con el procedimiento almacenado  que acabas de crear para que se pueda llamar desde el TPV
If Exists (select * from API_EXEC where ProcName = 'pPers_TPV_Artic_Guardar')
DELETE FROM API_EXEC WHERE ProcName = 'pPers_TPV_Artic_Guardar'
GO
INSERT INTO API_EXEC (ProcName)
  SELECT 'pPers_TPV_Artic_Guardar'
GO


El siguiente paso es crear el modelo. Necesitamos un modelo de tipo petición de datos.




Ahora, vamos a diseñar el formulario. No nos vamos a detener demasiado en este punto, ya que depende mucho del gusto y necesidades personales. En nuestro caso, tenemos el siguiente esquema pero, por ejemplo, el menú de la cabecera y las secciones de datos(no así sus componentes) se podrían eliminar.


 


En cuanto al tamaño de los componentes del modelo, casi todos los componentes tienen unos tamaños de 0px o 100%, esto quiere decir que el componente se adaptará a la sección que lo contiene

  • Frame flotante: Ancho = 500 px
  • Sección Pie de página: Alto = 100 px


Como queremos que la lista desplegable muestre todos los artículos que tenemos en la base de datos, indicaremos el nombre de la tabla en origen de datos. Si queremos que los datos sean de una vista, tendremos que modificar el origen de datos para indicar la vista deseada. 


Además, como vamos a necesitar saber qué artículo está seleccionado, en valor indicamos {{IdArticulo}}, es importante respetar las mayúsculas, ya que será el parámetro que se le pase luego a los procedimientos de consulta y modificación



Por otra parte, necesitamos obtener la descripción del procedimiento almacenado, para ello, necesitamos un componente de tipo input con los siguientes parámetros. Este campo será el que utilizaremos para guardar la nueva descripción



Por último necesitamos un menú, que no tenemos todavía creado, por lo tanto, el siguiente paso es crear el menú que vamos a poner en el pie del modelo para obtener y guardar la descripción del artículo. 

Para ello, necesitamos crear un menú con 3 procesos: consultar, guardar y cerrar. El proceso de cerrar, reutilizaremos el estándar, por lo que vamos a ver la creación de los otros dos.


En proceso de obtener la descripción se compone de dos subprocesos, ya que, además de obtener la descripción, debe cargarla en el modelo. 


El primer subproceso será el que obtenga la descripción del procedimiento almacenado. El parámetro de entrada lo obtiene del modelo y el parámetro de salida lo devolverá a éste. Sin embargo, cabe recordar en este punto que dicha información en esta ventana es opcional e informativa. Los datos importantes en este paso son:

  • Tipo: Proceso
  • Función post ejecución: modelosCerrarContinuar
  • Origen de datos: Descripcion articulo


El origen de datos mencionado arriba no existe todavía, así que tendremos que crearlo.



El segundo subproceso será el que recargue la ventana con la descripción del artículo. En este caso, vamos a poder reutilizar el subproceso que utilizaremos para llamar al modelo la primera vez.

  • Tipo: Vista personalizador
  • Modelo: seleccionaremos de la lista el modelo que acabamos de crear




Con estos dos subprocesos creados, vamos a crear el proceso para obtener la descripción. Se trata de un proceso del Área de Formulario, de ejecución online y sin condiciones. Además, debemos guardarlo activado. Arrastraremos del árbol de la derecha los dos subprocesos que acabamos de crear.



El otro proceso que necesitamos es el que guardará la nueva descripción. En este caso, solamente está compuesto de un subproceso. Los datos importantes en este paso son:

  • Tipo: Guardado de formularios
  • Función post ejecución: modelosContinuar
  • Origen de datos: Pers Articulo guardar



De nuevo, el origen de datos habrá que crearlo



Por lo tanto, el proceso tendrá la siguiente configuración:


Para acabar con este paso, vamos a crear el menú que se verá en el pie del formulario. Como hemos comentado antes, va a estar compuesto de 2 procesos personalizados y el proceso estándar de cerrar formulario. Esto se puede observar a simple vista por el color de los iconos.



Ahora, vamos a volver al modelo para indicar que el menú recién creado es el que vamos a ver en el pie del formulario. En nuestro caso, queremos que se muestre únicamente el texto, por lo que los iconos indicados en los procesos no tienen cabida aquí. Si se quiere mostrar el icono, se debe seleccionar la opción correspondiente en el desplegable Tipo. Además, hemos marcado Enfocable, para poder acceder a los botones a través del teclado.



Por último, necesitamos un botón en un menú para llamar al modelo. La ubicación e icono, queda a criterio del desarrollador. Como el subproceso para mostrar el modelo lo hemos creado antes, ahora necesitamos un proceso que lo llame.




Y, por último, añadir dicho modelo al menú deseado. Por ejemplo el menú de acceso rápido de la barra de navegación.



Como se puede ver en la captura lo hemos usado para otras personalizaciones.



Tras cerrar sesión de TPV y volver a entrar, podemos ver nuestra personalización.





Tras seleccionar un artículo de la lista desplegable, podemos:

  • Consultar la descripción, lo que mostrará la descripción en el campo. Este paso no es obligatorio, es una ayuda para traer la descripción actual.
  • Guardar el artículo, lo que guardará en la base de datos la descripción indicada.
  • Cerrar: cerrará el modelo.