En el primer caso de uso veremos la posibilidad de solicitar un código postal, el país y unas observaciones antes del cobro y el posterior guardado de la información recogida en la tabla temporal de tickets y en la de pedidos.


En primer lugar, debemos añadir los campos configurables necesarios para el funcionamiento de la personalización. Para ello iremos al Admon de Ahora-ERP y en en el apartado campos configurables seleccionaremos el objeto Ticket e indicaremos "Conf_Tickets" como valor en el campo Tabla. Posteriormente añadiremos los campos necesarios para la personalización: Pers_Pais, Pers_CP, Pers_Observaciones.  


Indicamos los siguientes valores en la configuración de los campos:



Después tendremos que repetir el mismo procedimiento con el objeto Pedido. Añadiremos los campos necesarios: Pers_Pais, Pers_CP, Pers_Observaciones  y "Conf_Pedidos_Cli" como valor en el Campo Tabla con la siguiente configuración:



Cuando tengamos configurados todos los campos debemos crear la ventana que solicitará el código postal antes del cobro. Para ello debemos abrir el Personalizador Ahora-TPV y seleccionar el apartado de Diseñador -> Modelos  en el menú superior derecha de la aplicación.


Abrimos el desplegable de datos del modelo e introducimos los datos necesarios de la ventana. En este caso introduciremos los siguientes valores.

  • Botón de radio de activación: Activado
  • Tipo: Ventana de petición de datos.
  • Descripción: Solicitud de código postal
  • Descripción extendida: Ventana de solicitud del código postal del cliente antes del cobro.
  • El campo Origen de datos, al no ser necesario para la personalización, lo dejamos en blanco.



Posteriormente vamos a configurar los elementos de la pantalla. Abrimos el desplegable de Componentes y añadimos un frame flotante que hará la función de marco principal de la ventana.



Y nos añadirá el elemento en la parte izquierda de la pantalla en el apartado de visualización.



Vamos a indicar que el frame haga un reparto de las secciones verticalmente a lo largo del espacio disponible para que el título se coloque arriba, los campos en el centro y la botonera abajo.


Para ello, teniendo seleccionado el Frame desplegamos Diseño -> Distribución y seleccionamos dirección Horizontal y justificado entre: 




Después, también en el apartado de Componentes, desplegamos la opción de "Sección" y añadimos 3 secciones que conformarán el cuerpo de la ventana (Podemos editar en el campo descripción en el desplegable de Parametría las descripciones de las secciones, en nuestro caso se llamarán topBar, midBar y botBar):

  • La parte superior que contendrá el título de la ventana y un botón de cerrar la propia ventana.
  • La parte media que contendrá los campos a rellenar.
  • La parte inferior que contendrá el botón de guardado de la ventana.

Cuando tengamos las 3 secciones creadas podemos verificar que las secciones están correctamente creadas desplegando la opción Esquema del modelo y comprobando que existen 3 secciones creadas dentro del marco principal. Es importante volver al frame antes de añadir cada sección, para evitar que se creen unas dentro de otras. 


Empezamos por la sección superior dando una altura a la sección. Seleccionamos la topBar y abrimos el desplegable de Diseño y el de Tamaño y fuente.



Vamos a indicar que la sección tenga una altura de 50 píxeles y un ancho del 100% de la ventana y con esto tendremos configurado el espacio de la sección superior. También vamos a darle  espacio de separación entre el título y el botón de cerrar ventana: desplegamos Diseño -> Distribución y en Justificado seleccionamos la opción Entre:





Pasamos ahora a crear un título y un botón para cerrar la ventana en la sección superior. En primer lugar seleccionamos la topBar haciendo click sobre la sección correspondiente en el panel de visualización izquierdo o haciendo click sobre el nodo de la topBar en el Esquema del modeloSeleccionada la sección, abrimos el desplegable de Componentes -> componente para seleccionar un título:



Una vez añadido nos aparecerá en el panel izquierdo:



Posteriormente vamos a editar el tamaño del título abriendo el desplegable de Diseño -> Tamaño y fuente  y le indicaremos que tiene un alto y ancho del 100%:




También vamos a indicar el valor del título desplegando Parametría y escribiendo en el campo valor Solicitud de código postal: 



Vamos a dotar al título de un color de fondo desplegando Diseño -> Tamaño y fuente y seleccionando la opción de Fuente & Fondo. Para mantener la línea de colores, la fuente será de color blanco y el fondo uno de los azules predeterminados #26517e


Después de añadir el título vamos a añadir el botón de cerrar la ventana. Para insertarlo, debemos volver a seleccionar la sección y, a continuación, abrir el desplegable de Componentes -> componente y seleccionar un Ahora menú. Para comprobar que se ha añadido correctamente vamos a darle un tamaño abriendo el desplegable Diseño -> Tamaño y fuente e indicando valores de 50 píxeles en el ancho y el alto. 



Podemos ver que ahora hay un cuadrado bordeado que es la representación del menú en la esquina opuesta al título:




Para configurar los datos/parámetros del menú abrimos el desplegable Parametría e indicamos la siguiente configuración:





Hay que prestar atención al campo Menú que es el campo que hará referencia al menú seleccionado. Debemos desplegar la lista y seleccionar el deseado, según haga referencia al pie de página, línea... En este caso necesitamos el Menú estándar de cerrar una ventana que está clasificado dentro de Formulario.




Con esta configuración ya tendremos lista la sección superior de la ventana y quedaría un aspecto similar a : 



Pasamos a la sección que contendrá los campos necesarios para la personalización: Desplegable países, código postal y observaciones.


Abrimos el esquema del modelo y seleccionamos la segunda sección:





Después desplegamos Componentes -> Componentes y seleccionamos Desplegable con filtro:


Abrimos Parametría e indicamos los siguientes valores:

  • Check Requerido marcado
  • Descripción : Desplegable países.
  • Name: Nombre que hemos indicado en la definición de los campos al inicio de la personalización, en este caso Pers_Pais
  • Valor: como queremos que españa sea el páis por defecto le indicaremos ES como valor
  • Label: Países
  • Origen de datos: tabla o vista de donde obtendremos la información: Geo_Paises
  • Filtro: vacío
  • Campos: IdPais,Pais. Sin las comillas dobles.



Pasamos a añadir el campo de Código Postal: volvemos a seleccionar la sección y desplegamos  Componentes -> Componente y seleccionamos Input:



Después desplegamos Parametría e indicamos los siguientes valores:

  • Check Requerido activado
  • Descripción: Input código postal
  • Name: Pers_CP (El nombre que le habíamos dado al campo en definición previa)
  • Valor: vacío (no queremos ninguno preseleccionado)
  • Label C.Postal
  • Tipo: Texto


Por último, vamos a añadir el campo restante de Observaciones: seleccionamos la sección de nuevo y volvemos a añadir un input como hemos hecho con el Código postal.  En el apartado Diseño > Tamaño y fuente, le asignamos una anchura de 600px. Después vamos a editar su Parametría con los siguientes valores:

  • Check Requerido No activado
  • Descripción: Input observaciones
  • Name: Pers_Observaciones
  • valor: vacío
  • Label : Observaciones
  • Tipo: Texto


Con los 3 campos creados debería quedar una disposición tal que así:




Antes de continuar, vamos a guardar el modelo, pues el paso siguiente implica cambiar de ventana.


Para finalizar la ventana necesitamos un botón de guardado y uno de cancelar la ventana. Para ello vamos a crear un nuevo Menú que contenga los botones. El proceso de Cancelar viene definido de forma estándar pero sí debemos crear un proceso de guardado del formulario personalizado. Primeramente necesitamos crear un Subproceso con las siguientes opciones:



  • Tipo: Guardado de formulario.
  • Descripción: Guardar código postal
  • Descripción extendida: Subproceso que guarda el código postal
  • Función post ejecución: seleccionar de la lista modelosCerrarContinuar y dejar los parámetros que vienen por defecto


  • Origen de datos: Será necesario crearlo (Más abajo tendremos el código de creación del procedimiento "pPers_GuardaCPTicketVenta" ):


  • Parámetros: Hará falta añadir el parámetro IdTicket ya que es esperado por el procedimiento: pulsamos el botón "añadir propiedad".




Esto nos creará el parámetro correspondiente y lo podremos configurar para que la propiedad sea "IdTicket" y el valor "@Ticket.IdTicket". A partir de la versión 4.4.2400.52, el valor será "{{Ticket.IdTicket}}".



Ahora necesitamos crear un Proceso para asignarle el Subproceso que acabamos de crear. Para ello abrimos la opción de Procesos en el menú superior derecha y creamos un proceso con las siguientes características:


  • Área: Formulario
  • Descripción: Guardar CP
  • Etiqueta: Guardar CP
  • Refresca: "NADA"
  • Activado: Activado
  • Ayuda: Proceso que guarda el código postal
  • Icono: pulsar con el botón segundario del ratón y asignar el icono deseado En el ejemplo vamos a usar solo texto, por lo que no influye.


Ahora vamos a asignar el subproceso al proceso abriendo el desplegable Guardado de formularios en el panel lateral derecho (El área donde creamos el subproceso) y arrastramos al cuadro de Componentes del proceso el subproceso Guardar código postal:



Tras guardar el proceso, únicamente falta crear un Menú que contenga los procesos de guardado y cancelación de la ventana.  Abrimos el desplegable superior derecha y seleccionamos la opción de Menú con las siguientes opciones:



  • Área: Formulario
  • Descripción: Botonera ventana petición código postal. Este será el nombre que seleccionaremos posteriormente en el modelo.
  • Ayuda: Descripción que queramos del menú
  • Activado: Activado

Ahora vamos a asignar los procesos de Guardar y Cancelar. Para el de guardar debemos abrir el desplegable Formulario y el proceso Guardar del panel de la derecha y arrastrarlo a Componentes del menú. Para el de Cancelar haríamos lo mismo pero con el proceso de Cancelar situado en la misma área que el de guardar.




Cuando ya tengamos el menú configurado pulsamos guardar y podemos continuar con el modelo.


Volviendo a la creación de la ventana, seleccionamos la tercera sección en el esquema del modelo y en el desplegable de Diseño -> Tamaño y fuente indicamos que tenga 100% de ancho y 60 px de alto.



Con el estilo de la sección definido vamos a abrir el desplegable de Componentes -> Componente y seleccionamos un Ahora menú  el cual le indicaremos en Diseño -> Tamaño y fuente  un 100% de alto y un 100% de ancho para que ocupe el mismo espacio que el componente de la sección.




Definido el estilo del menú, vamos a pasar a definir la Parametría con estas opciones:


  • Descripción: Botonera inferior
  • Name: BotoneraInferior
  • Menú: Aquí seleccionamos el menú que acabamos de crear, dentro de la sección Formulario.
  • Alineación: seleccionamos centro  para que los botones queden alineados en el centro del menú
  • Tipo: Solo texto




Con esto ya tendríamos finalizada la creación del Modelo o ventana de la solicitud de código postal y ahora debemos asignar esta nueva ventana a la acción previa del cobro.


Para ello necesitamos crear un Subproceso que contenga la ventana que hemos creado.


En la edición de subprocesos creamos uno con las siguientes opciones:


  • Tipo: Modelo (hace referencia a los modelos personalizados)
  • Descripción: Proceso de petición de código postal pre cobro
  • Descripción extendida: Proceso de petición de código postal pre cobro
  • Modelo: seleccionar de la lista el modelo recién creado, 'Solicitud de código postal'.


Guardamos el subproceso y pasamos a la edición de procesos para crear un proceso que contenga el subproceso de la vista que acabamos de crear. Para ello, seleccionaremos el proceso estándar  Pre-ejecución > Antes del cobro


Descripción: Antes del cobro con CP

Marcar Activado

Y en componentes del proceso asignamos el subproceso de la ventana que hemos creado arrastrándolo al cuadro.



Después de guardar el Proceso nos quedaría algo así:


Con esto, ya tendríamos asociada la ventana al proceso de antes del cobro.


Antes de visualizar esta ventana, vamos a darle un poco de estilo:


Al botón de cerrar le cambiamos el color de fuente a blanco, y el color de fondo al mismo que tenga el título, en este caso, #26517e.



Vamos a seleccionar el frame flotante, y  en el apartado de Diseño -> Tamaño y fuente le vamos a dar un 50% de ancho y un 0% de alto (automático).



Ahora, vamos a ponerle un poco de relleno a la sección midBar. Se puede aplicar un relleno general, que colocaría en todos los lados, pero en este caso, vamos a poner 0,5rem más en la parte de abajo.



Al selector de país y el input de C. Postal, les vamos a poner un 45% de ancho y 50px de alto.



Y finalmente, al input de observaciones, un 90% de ancho y 50px de alto.



Para poder probar esta nueva funcionalidad será necesario salir de Ahora TPV y volver a entrar. Según la configuración de pantalla y si se han seguido o no todos los pasos de Diseño, obtendremos una ventana similar a la siguiente:





Cuando tengamos creada la ventana creada y estructurada a nivel de relaciones de procesos y subprocesos, necesitamos crear un procedimiento almacenado en la base de datos que se encargue de recoger los nuevos campos y los inserte en la tabla de tickets correspondiente: utilizaremos el nombre procedure  que le hemos indicado al subproceso de guardar creado previamente pPers_GuardaCPTicketVenta 



IF OBJECT_ID('pPers_GuardaCPTicketVenta', 'P') IS NOT NULL 
  DROP PROCEDURE pPers_GuardaCPTicketVenta
GO

CREATE PROCEDURE [dbo].[pPers_GuardaCPTicketVenta]
  @iXML xml,
  @oXML xml OUTPUT
AS

DECLARE @VRET INT

BEGIN TRY
  
  DECLARE @IdTicket int
  DECLARE @Pais varchar(2)
  DECLARE @CP varchar(20)
  DECLARE @Observaciones varchar(500)

  SELECT @iXML =CAST(REPLACE(REPLACE(REPLACE(CAST(@iXML AS VARCHAR(MAX)), '"', ''), '&lt;', '<'), '&gt;', '>') AS XML)

  BEGIN TRAN

  SELECT 
    @IdTicket = T.C.value('IdTicket[1]', 'varchar(50)'),
    @Pais = T.C.value('Pers_Pais[1]', 'varchar(2)'),
    @CP = T.C.value('Pers_CP[1]', 'varchar(20)'),
    @Observaciones = T.C.value('Pers_Observaciones[1]', 'varchar(500)')
  FROM @iXML.nodes('./data') T(C)

  IF ISNULL(@Pais, '') = '' SET @Pais = 'ES'

  UPDATE Conf_Tickets SET 
    Pers_Pais = @Pais,
    Pers_CP = @CP,
    Pers_Observaciones = @Observaciones
  WHERE IdTicket = @IdTicket

  SET @oXML = 
    (SELECT
      (SELECT 
        'ok' AS Estado
        --,'Resultado: ' + CONVERT(varchar(50), @IdTicket) + ' ' + ISNULL(@Pais,'NADA') + ' ' + ISNULL(@CP,'NADA') + ' ' + ISNULL(@Observaciones,'NADA') as Mensaje
        , 'Resultado: Datos adicionales de ticket guardado correctamente'
      FOR XML PATH('Respuesta'), ELEMENTS, TYPE),
      (SELECT  
        'Datos adicionales de ticket guardado correctamente'
        --@IdTicket as IdTicket, @Pais as Pers_Pais, @CP as Pers_CP, @Observaciones as Pers_Observaciones
      FOR XML PATH('data'), ELEMENTS, TYPE),
      (SELECT  
        NULL
      FOR XML PATH('view'), ELEMENTS, TYPE)
    FOR XML PATH('Resultado'), ELEMENTS, TYPE)

  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

  SET @oXML = 
    (SELECT
      (SELECT 
        'error' As Estado,
        @CatchError as Mensaje
      FOR XML PATH('Respuesta'), ELEMENTS, TYPE),
      (SELECT        
        NULL
      FOR XML PATH('data'), ELEMENTS, TYPE),
      (SELECT  
        NULL
      FOR XML PATH('view'), ELEMENTS, TYPE)
    FOR XML PATH('Resultado'), ELEMENTS, TYPE)
  RETURN -1
END CATCH
GO

zpermisos 'pPers_GuardaCPTicketVenta'
GO

----------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------


DELETE FROM API_EXEC WHERE ProcName = 'pPers_GuardaCPTicketVenta'
GO
INSERT INTO API_EXEC (ProcName)
  SELECT 'pPers_GuardaCPTicketVenta'
GO
DELETE FROM API_List_Column WHERE ObjectName = 'Geo_Paises' AND (ObjectColumn = 'IdPais' OR ObjectColumn = 'Pais')
GO
DELETE FROM API_List WHERE ObjectName = 'Geo_Paises'
GO

INSERT INTO API_List (ObjectName, FilterRequired)
  VALUES ('Geo_Paises', 0)
GO

INSERT INTO API_List_Column (ObjectName, ObjectColumn)
  VALUES  ('Geo_Paises', 'IdPais')
      ,('Geo_Paises', 'Pais')
GO

Por último, necesitamos un procedimiento post necesario para insertar los datos temporales del ticket en el pedido:


ALTER PROCEDURE [dbo].[TPV_Genera_Documentos_Desde_Ticket_Personalizado_Post]
  @IdTicket T_Id_Pedido,
  @IdApertura int,
  @IdAlbaran T_Id_Albaran,
  @IdContrato int,
  @NoGeneraMov bit
AS
-- =============================================
-- #AUTOR:
--        CEESI
-- #NAME:
--        TPV_Genera_Documentos_Desde_Ticket_Personalizado_Post
-- #CREATION:
--        04/05/2020
-- #CLASIFICATION:
--        002-GESTION COMPRAS y VENTAS
-- #DESCRIPTION:
--        Personalizado post de TPV_Genera_Documentos_Desde_Ticket
-- #PARAMETERS:
--        @IdTicket:
--        @IdApertura:
--        @IdAlbaran:
--        @IdContrato:
--        @NoGeneraMov:
-- #OBSERVATIONS:
--        
-- #CHANGES:
--
-- #EXAMPLE:
--        
-- =============================================
BEGIN TRY

  DECLARE @IdPedido as T_Id_Pedido
  DECLARE @Pais varchar(2)
  DECLARE @CP varchar(20)
  DECLARE @Observaciones varchar(500)

  IF NOT ISNULL(@IdTicket, 0) = 0 BEGIN

    SELECT 
      @Pais = Pers_Pais,
      @CP = Pers_CP,
      @Observaciones = Pers_Observaciones
    FROM Conf_Tickets 
    WHERE IdTicket = @IdTicket

    -- Obtenemos el IdPedido a modificar
    SELECT @IdPedido = IdPedido FROM Pedidos_Cli_Lineas WHERE IdAlbaran = @IdAlbaran

    IF ISNULL(@IdPedido, 0) <> 0 BEGIN
      UPDATE Conf_Pedidos_Cli SET 
        Pers_Pais = @Pais,
        Pers_CP = @CP,
        Pers_Observaciones = @Observaciones
      WHERE IdPedido = @IdPedido

    END
    --FROM Albaranes_Cli_Cab WHERE IdAlbaran = @IdAlbaran 
  END

  RETURN -1

END TRY

BEGIN CATCH
  IF @@TRANCOUNT >0 BEGIN
    ROLLBACK TRAN 
  END

  DECLARE @CatchError NVARCHAR(MAX)
  SET @CatchError=dbo.funImprimeError(ERROR_MESSAGE(),ERROR_NUMBER(),ERROR_PROCEDURE(),@@PROCID ,ERROR_LINE())
  RAISERROR(@CatchError,12,1)

  RETURN 0

END CATCH