martes, 1 de diciembre de 2015

Eventos en Navision 2016

En la versión 2016 de Navision se ha añadido una funcionalidad nueva para capturar eventos de tablas desde objetos tipo Codeunit al dispararse los diferentes triggers(INSERT, MODIFY, RENAME, VALIDATE). Con esto se consigue que el código estandar no tenga que ser modificado teniendo la posibildad de sacar nuestras modificaciones de codigo a una codeunit y ejecutar este codigo antes o despues de el que ya existe en el trigger de la tabla o del campo de la tabla que lanza el evento.


Ejemplos:
1 Llamar a una función cuando se ejecute una acción en la tabla Item
1-1           En una Codeunit nos creamos una función “DespuesModifyItem"


1-2           En las propiedades pulsamos sobre "event" y seleccionamos "Suscriber" 

1-3            En el campo "EventPublischerObject" seleccionamos la tabla "Item"  

 1-4           Ahora es cuando le decimos cuando queremos que llame a esta función, lo haremos en el campo “EventFunction”. Aquí nos propondra varias opciones:


SI por ejemplo queremos que despues de modificar un registro llame a esta función seleccionaremos “OnAfterModifyEvent”



Si lo que queremos en, llamar a esta función cuando se valide un campo, seleccionaremos la opción de:
    

 ó





En este caso, nos aparecerá un nuevo campo en el que le tendremos que indicar sobre  que campo, queremos que actue, es decir, cuando se ejecute el validate de que campo, queremos que llame Navision a esta función. Pro ejemplo : “No.”


Por lo tanto, cuando desde la tabla Item, se ejecute alguna de las acciones configuradas en estas funciones, que Navision las llamara y ejecutara el código que hay en ellas.

Por ejemplo cuando se lance el OnModify queremos que se controle la descripción, que no esté vacia hariamos los siguiente. Una función con las propiedades:

Funcion "DespuesModifyItem"



Es interesante también documentar de alguna manera en el trigger que lanza el evento si hay un codigo asociado al mismo ya sea antes o despues del que existe en el trigger.



jueves, 26 de noviembre de 2015

Consumir Web Service / Servicio Web SOAP II (RTC)


Hace un tiempo publicamos un post indicando como consumir un web service desde navision(Consumir Web service SOAP ), está funcionalidad se podía utilzar en el cliente clásico y hasta la version 2009. Ahora con el cambio de platafarma y hasta la version 2016 en la que se implementa una funcionalidad específica para realizar esto, la solución que hemos encontrado es la siguiente.

En resumen, lo que se hace es crear el fichero Xml directamente luego lo enviamos al web service y leemos la respuesta. En este caso enviamos dos parámetros y recogemos un valor booleano que nos devuelve una codeunit.


Variables.

Name                  DataType      Length
URL                    Text              250
Metodo               Text              1024
NameSpace         Text              80
NodeList             Automation    'Microsoft XML, v6.0'.IXMLDOMNodeList  
xmlhttp                Automation    'Microsoft XML, v6.0'.XMLHTTP  
xmldoc                Automation    'Microsoft XML, v6.0'.DOMDocument  
soapEnvelope      Automation    'Microsoft XML, v6.0'.IXMLDOMElement  
soapBody            Automation    'Microsoft XML, v6.0'.IXMLDOMElement  
soapMethod        Automation    'Microsoft XML, v6.0'.IXMLDOMElement  
soapAtributo        Automation    'Microsoft XML, v6.0'.IXMLDOMElement  
node                    Automation    'Microsoft XML, v6.0'.IXMLDOMNode  
parametersXmlDoc    Automation    'Microsoft XML, v6.0'.DOMDocument  
xmldoc2               Automation    'Microsoft XML, v6.0'.DOMDocument   


Función LlamarWS(Producto : Code[20];TipoMod : Code[20]) Result : Boolean

Result := FALSE;

//iniciar llamada al web service
URL:='http://localhost:7047/DynamicsNAV/ws/company/Codeunit/nombreCodeunit';
Metodo:='PruebasWS';
NameSpace:='urn:microsoft-dynamics-schemas/codeunit/nombreCodeunit';

// Crear el documento xml
CREATE(xmldoc,TRUE,TRUE);

// Crear el envelope SOAP
soapEnvelope := xmldoc.createElement('Soap:Envelope');
soapEnvelope.setAttribute('xmlns:Soap', 'http://schemas.xmlsoap.org/soap/envelope/');
xmldoc.appendChild(soapEnvelope);

// Crear el cuerpo del SOAP
soapBody := xmldoc.createElement('Soap:Body');
soapEnvelope.appendChild(soapBody);

// Crear el método del body
soapMethod := xmldoc.createElement(Metodo);
soapMethod.setAttribute('xmlns', NameSpace);
soapBody.appendChild(soapMethod);

// Crear los parametros del metodo.
soapAtributo:= xmldoc.createElement('oarametro1');
soapAtributo.text(textoParametro1);
soapMethod.appendChild(soapAtributo);

soapAtributo:= xmldoc.createElement('parametro2');
soapAtributo.text(textoParametro1);
soapMethod.appendChild(soapAtributo);

//Enviar fichero al web service
CREATE(xmlhttp, TRUE, TRUE);
xmlhttp.open('POST', URL, FALSE);
xmlhttp.setRequestHeader('Content-type', 'text/xml; charset=utf-8');
xmlhttp.setRequestHeader('SOAPAction', Metodo);
xmlhttp.send(xmldoc);

//si la respeusta es Ok devuelve valor 200
IF xmlhttp.status=200 THEN
BEGIN
  xmldoc := xmlhttp.responseXML;
  xmldoc.setProperty('SelectionLanguage','XPath');
  xmldoc.setProperty('SelectionNamespaces','xmlns:tns="'+NameSpace+'"');
  NodeList := xmldoc.selectNodes('//tns:'+'return_value');
  Result := TRUE;
  if NodeList.item(0).text = 'true' then
    Exit(TRUE);
End;
Exit(FALSE);


Tambien se podria realizar la lectura del Xml devuelto pero eso ya depende de los gustos de cada uno.

Variables
xmldoc2                Automation    'Microsoft XML, v6.0'.DOMDocument   

IF ISCLEAR(xmldoc2) THEN
  CREATE(xmldoc2,TRUE,TRUE);
xmldoc2.load(xmlhttp.responseXML);
xmldoc2.save('ruta\fichero.xml');

miércoles, 22 de abril de 2015

Envío email a traves de librerias outlook


Con esta función se consigue enviar un correo utilizando las librerias de outlook. existen varias opciones tanto de formato como de tipo de envio ya sea enviado directamente o levantando el cliente Outlook para comprobar antes de enviar. Para ello primero vamos a crear dos variables locales tipo automation asignando librerias de Outlook.

    - OMail Automation 'Microsoft Outlook 9.0 Object ibrary'.MailItem
    - OApp Automation 'Microsoft Outlook 9.0 Object ibrary'.Application



En este caso se ha puesto la versión 9.0 porque es la versión que tengo instalada en mi equipo. Es necesario que todos los equipos desde donde se va lanzar esta función tengan instalada mínimo la misma versión con la que se han definido las variables. No habría problema con los equipos que tengan instalada una versión superior de las librerías ya que leerían las dll perfectamente no asi los equipos con versiones anteriores.


la funcion creada tiene varios parámetros :
eMail - dirección de correo del o de los destinatarios.
RutaPlantilla - Es la ruta al fichero de plantilla con la que abrir el correo.
RutaYFichero - Ruta del documento adjunto.
MostrarCorreo - Es un booleano para determinar si queremos o no levantar el cliente Outlook antes de enviar el correo

IF ISCLEAR(OApp) THEN
  CREATE(OApp,FALSE,TRUE);
//OMail := OApp.CreateItem(0); //Si NO utilizamos plantillas
OMail := OApp.CreateItemFromTemplate(rutaplantilla); //Si se usan plantillas
OMail."To":=eMail;
IF RutayFichero <> '' THEN
  OMail.Attachments.Add(RutayFichero); //Si queremos adjuntar un fichero
OMail.Subject :=Asunto;
//OMail.Body := ‘El cuerpo del mensaje’; //O ponemos este código o el de la plantilla.
//OMail.OriginatorDeliveryReportRequested := TRUE; //Confirmación de recepción.
//OMail.ReadReceiptRequested := TRUE; //Confirmación de lectura.
IF MostrarCorreo=TRUE THEN
  OMail.Display //levanta el cliente correo si no se llama a esta funcion envai el correo                 directamente.
ELSE
OMail.Send;



jueves, 5 de marzo de 2015

Crear Trigger en SQL para insertar un registro en el que algunos campos son de tipo "no null"

Tenemos un proceso para alimentar una tabla de navision directamente desde sql. El proceso unicamente alimenta dos campos que son el campo1 y el campo4 y quieren que se calculen el campo2 y campo3 qeu corresponden a la fecha y hora. la tabla también tiene los 4 campos definidos como no Null por lo que necesitamos que esos campos se cumplimente al insertar sin dar error ya que como hemos mencionado antes dos de los campos los tenemos que calcular, la cuestión es ¿cuando?.

Lo que hemos hecho ha sido utilizar el desencadenante INSTEAD OF INSERT, el desencadenador INSTEAD OF INSERT de una vista o tabla genera una instrucción INSERT en la tabla base mediante los datos de la tabla inserted asi tenemos acceso a los campos del registro que se está insertando, al realizar el insert sobre la tabla real dentro del trigger disponemos (consulta select de la tabla inserte) el valor de los campos insertados los dos que no venian informados los hemos calculado.

Para calcular el time lo que ponemos es la parte de fecha como a 0 pero en sql no puede haber fecha 0 y lo que hacemos es coger la primera fecha disponible "1754-01-01" y cumplimentamos la parte de la hora.  
"CAST('1754-01-01 '+CONVERT(CHAR(8), GETDATE(), 108) AS DATETIME)"

Para calcular la fecha lo que hacemos es poner la fecha de hoy y completamos a 0 la hora.
"CONVERT(CHAR(10),GETDATE(), 120)"

Definición de la tabla TablaEjemplo
Campo1 nvarchar(2)
Campo2 Fecha datetime
Campo3 Time datetime
Campo4 int

ALTER TRIGGER [dbo].[ActualizarFechas]
ON [dbo].[TablaEjemplo]
       INSTEAD OF INSERT
          AS BEGIN
            declare @cpo1 nvarchar(2); declare @cpo2 int;

            SELECT @cpo1= CampoTabla1,@cpo2=CampoTabla4
            FROM inserted
            INSERT INTO [dbo].[TablaEjemplo] ([Maquina],[Fecha],[Hora],[Contador])
            VALUES (@cpo1,
                            CONVERT(CHAR(10),GETDATE(), 120),
                            CAST('1754-01-01 '+CONVERT(CHAR(8), GETDATE(), 108) AS DATETIME),
                           @cpo2)
END

miércoles, 25 de febrero de 2015

Identificar entorno NAV versiones RTC

Exite la posibilidad en RTC de identificar la base de datos en la que nos encontramos, esto permite que en un vistazo veamos la base de datos en la que estamos trabajando ya sea en pruebas o en real en vez de tener que ir a buscar esta información cada vez que queramos comprobar donde estamos. para configurarlo es necesario ir a Información de empresa --> Indicador del sistema
En el indicador del sistema se establece el tipo de indicador, si queremos poner un texto nuestro utilzamos la opción de "texto personalizado". En el campo de enfasis se definen los matices con los que queremos que se refleje el indicador. En texto personalizado definimos el texto del indicador.

Error al exportar objetos "El archivo de objetos no se puede utilizar con esta versión del programa"

En ocasiones al realizar la exportación de un fob a una carpeta surge este error:
La solución más fácil que hemos encontrado es crear una carpeta nueva para que se pueda exportar el fichero o bien borrar los fobs de la versión superior que estén en esa ruta. Lo que hace Navision es realizar una comprobación para ver si un fichero que se ha generado en versiones de la base de datos superiores se ha exportado en esa misma ruta y al ver que si se ha realizado da el error.