miércoles, 17 de diciembre de 2014

Llamar a Web-Services de Navision desde Navision


PAra consumir los webservices de un servidor de Navision desde otro servidor de Navision tenemos que montar una petición httpRequest pasándole un XML bien formado y recuperar la respuesta para saber que es lo que ha ocurrido en el servidor de destino.

Para ello primero declaramos las variables:
NameDataTypeSubtypeLength
XmlHttpRequest Automation'Microsoft XML, v4.0'.XMLHTTP 
XmlDocAutomation'Microsoft XML, v4.0'.DOMDocument 
XmlStringText 1024
BTSoapBigText  
BTValoresBigText    


Creamos un BigText y le añadimos la cabecera de la petición:

BTPasado.ADDTEXT('<?xml version="1.0" encoding="utf-8"?>');
BTPasado.ADDTEXT('<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">');
BTPasado.ADDTEXT('<soap:Body>');
BTPasado.ADDTEXT(STRSUBSTNO('<%1 xmlns="urn:microsoft-dynamics-schemas/codeunit/%2">','MiFuncion','MiCodeUnit'));

BTValores.ADDTEXT('<nombre_parametro_que_espera_MiCodeunit_MiFuncion>');
BTValores.ADDTEXT('MI-VALOR');
BTValores.ADDTEXT('</nombre_parametro_que_espera_MiCodeunit_MiFuncion>');

BTPasado.ADDTEXT(STRSUBSTNO('</%1>','MiFuncion'));

BTPasado.ADDTEXT('</soap:Body>');
BTPasado.ADDTEXT('</soap:Envelope>');


Como veis es bien sencillo montar la petición de nuestro httprequest.
Ahora hacemos la llamada:

NameDataType         Subtype

XmlDocPasado              Automation'Microsoft XML, v4.0'.DOMDocument

IF (ISCLEAR(XmlHttpRequest)) THEN
  CREATE(XmlHttpRequest);

XmlHttpRequest.open('POST','http://servidor:7047/DynamicsNAV/WS/empresa/Codeunit/MiCodeunit',FALSE,'DOMINIO\usuario','password');
XmlHttpRequest.setRequestHeader('Host', 'localhost');
XmlHttpRequest.setRequestHeader('Content-Type', 'text/xml; charset=utf-8');
XmlHttpRequest.setRequestHeader('Content-Length', FORMAT(BTPasado.LENGTH));
XmlHttpRequest.setRequestHeader('SOAPAction','MiFuncion');
XmlHttpRequest.send(BTPasado);
XmlDocPasado := XmlHttpRequest.responseXML;


Con esto obtendríamos en XmlDocPasado un XML con el resultado.

viernes, 28 de noviembre de 2014

Convertir líneas a columna en una consulta sql

Se puede pasar un resultado de una consulta sql de líneas a un varchar que representaría una columna con la función: COALESCE siempre que no contenga ningún null el resultado de la consulta.

Ejemplo:
DECLARE @valores VARCHAR(1000)
SELECT @valores= COALESCE(@valores + ',', '') + valor FROM MiConsulta-Tabla

Valor es uno de los campos de MiConsulta-Tabla.
El resultado es un varchar concatenado por comas.
Tenemos la limitación de la longitud del varchar (Aunque lo definamos con MAX) pero nos puede ser útil para salir del paso.

viernes, 21 de noviembre de 2014

Crear un informe Recursivo con Reporting Services

Crear un informe recursivo es extremadamente fácil con Reporting Services.
Supongamos un listado que muestra los siguientes datos:
  1. Primera Línea Padre
    1. Primera Línea Hija Primera Línea Padre
    2. Segunda Línea Hija Primera Línea Padre
      1. Primera Línea HijaSegunda Línea Hija Primera Línea Padre
    3. Tercera Línea Hija Primera Línea Padre
  2. Segunda Línea Padre
  3. Tercera Línea Padre
  4. ....
Tenemos un ID que identifica la línea y un ID_PADRE que identifica la línea padre de la línea actual. En Repoting iríamos a la línea y le definiríamos un grupo:
 
En el grupo ponemos como campo de grupo el ID que identifica la línea.

En propiedades avanzadas indicamos cual es el campo recursivo de cada línea, es decir, el campo que identifica cual es su padre.
Y ya esta, ya tenemos nuestro informe recursivo.
Para que visualmente quede mas bonito se cambia el padding del campo para que vaya indentando las líneas y quede así:

También se puede cambiar la visualización del grupo para poder plegarlo o desplegarlo:

jueves, 10 de abril de 2014

Obtener la lista de informes cuanto cuestan de sacar en tiempo

Esta consulta muestra una lista de los informes que mas cuestan de sacar por tiempo. Con esto podemos determinar que informes son los más pesados e intentar optimizarlos.


SELECT EL.UserNAme,Name Informe, b.path Ruta, Parameters Parametros,

FORMAT Formato,TimeStart Inicio, TimeEnd Fin, ByteCount,

(TimedataRetrieval+Timeprocessing+TimeRendering)/1000 AS Seg_TiempoTotal

FROM

[ReportServer].[dbo].[ExecutionLog] EL

JOIN [ReportServer].[dbo].[CATALOG] b

ON EL.reportid = b.itemid

--WHERE Name =@INFORME

ORDER BY (TimedataRetrieval+Timeprocessing+TimeRendering)/1000 DESC

jueves, 3 de abril de 2014

Leer active directory desde SQL

Para acceder desde SQL al LDAP hay que linkar nuestro servidor del Active directory con el servidor de SQL donde queremos hacer la consulta.
La lista de campos disponibles desde el LDAP la podeis encontrar en el siguiente link: lista de campos

Lo primero es linkar el servidor de la siguiente manera_
Exec
 sp_addlinkedserver 'ADSI'
, 'Active Directory Service Interfaces'
, 'ADSDSOObject'
, 'adsdatasource'

Le ponemos un usuario del dominio para que tenga acceso, bien con la instrucción:
EXEC sp_addlinkedsrvlogin 'ADSI', 'false', NULL, 'UsuarioDominio'
O desde las propiedades de la conexión creada (Servidores Vinculados)

En caso de que tengas el "Ad Hoc Distributed Queries" desabilitado, entonces corre esto para habilitarlo:
 sp_configure 'show advanced options'
, 1
reconfigure
go
sp_configure 'Ad Hoc Distributed Queries'
, 1
reconfigure
go



Para ejcutar las consultas, se hace utilizando OpenQuery y de la siguiente manera:
SELECT * FROM OpenQuery(ADSI, 'SELECT   physicalDeliveryOfficeName,sAMAccountName,cn,Name,displayName, sn,givenName,initials,moniker, personalTitle,generationQualifier ,userPrincipalName ,distinguishedName ,adsPath FROM ''LDAP://DC=mi-dominio,DC=local'' WHERE objectCategory=''user'' '

jueves, 27 de marzo de 2014

Imagenes externas en Reporting Services

En una red corporativa, podemos definir en los informes de reporting las imágenes como externas y darles la ruta donde se encuentran para que el servidor de informes las renderice, se hace de la siguiente manera:
file://datos/ImagenesProductos/Historico/imagen.jpg

jueves, 20 de marzo de 2014

Split en Reporting Services

Para utilizar la función de Split en Reporting Services y combinar así nuestra función de Web Services con Reportin Services, es muy útil la función Split de Reporting Services cuya definicón es la siguiente:
CDec(Split(Fields!RESULTADO.Value,"|")(1))

jueves, 13 de marzo de 2014

Arreglo de la funcion pasar filtros de navision a SQL

Utilizando la función pasar filtros de navision a SQL he detectado algunas deficiencias.
Donde pone :

SET @From = substring(@parFilter, @IndexToRead + 2, @NextIndexToRead - (@IndexToRead + 1))







Poner :

if LEN(@parFilter) = @NextIndexToRead
BEGIN
     SET @From = substring(@parFilter, @IndexToRead + 2, @NextIndexToRead - (@IndexToRead + 1))
END
ELSE
BEGIN
    SET @From = substring(@parFilter, @IndexToRead + 2, @NextIndexToRead - (@IndexToRead + 2))
END

jueves, 27 de febrero de 2014

Pasar BigText a XML en Navision

¡La de problemas que me he encontrado para trabajar con los BigText en Navision!.
Su manejo no es intuitivo y se necesita de un poco de conocimiento previo a la hora de utilizarlo.
En particular, mi necesidad de las variables del tipo BigText surgen en un proyecto en el que desde un servidor de navision consumia los web services de otro servidor de Navision. En futuros posts comentare los pormenores de este proyecto, pero el post actual es para comentar uno de los quebraderos de cabeza que mas amargado me ha tenido.
En un determinado momento y por necesidades varias, me veo en el plan de transformar un BigText a XML. Sencillo, ¿No? aqui por ejemplo hay una solucion para leer bigtext y pasarlo a XML.
Pues bien, así utilice mi variable BigText, poniendo FORMAT() para que me leyese el contenido y en principio me funciono estupendamente.
Pero no podia ser tan bonito, si leemos la definicion de la funcion format vemos que indica que es para variables de tipo simple ysi leemos la definicion del tipo de datos BIGTEXT vemos que es compleja. Por lo que en teoria no deberia de funcionar, pero funciona!!!.
ERROR!!!!!!!!
No funciona!!!!!!!!!!
Bueno, para ser correctos, funciona cuando el BigText no contiene muchos caracteres, el error que da es el de Excedido el tamaño del bufer.

Por lo que la única solución correcta es la de utilizar InStream y OutStream.
Por lo que en realidad se deberia hacer así:
XmlDocPasado.async := FALSE;
TempBlob.HTML.CREATEOUTSTREAM(ostream);
BTPasado.WRITE(ostream);
TempBlob.CALCFIELDS(HTML);
TempBlob.HTML.CREATEINSTREAM(istream);
XmlDocPasado.load(istream);

Ocurre exactamento lo mismo con la variable Automation 'Navision Attain Hash 1.0'.BSTRConverter y su metodo BSTR. PArece que con este metodo nos va a devolver un bonito chorro de carácteres para pasar a nuesto XML y idem de idem, Excedido el tamaño del bufer.

jueves, 20 de febrero de 2014

Saber si una columna concreta existe en una tabla

Estoy trabajando en un proyecto que pretende ser adaptable a varias bases de datos. En el, surge la necesidad de saber en una consulta de SQL si un campo existe en una tabla concreta o no existe.La consulta para averiguarlo es así: SELECTCASE WHEN (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = 'Empresa$Tabla' AND
COLUMN_NAME
= 'Columna') = 0 THEN 'NO TIENE COLUMNA Columna' ELSE 'SI TIENE COLUMNA Columna' END

Para averiguar si la Tabla existe sería así:
SELECTCASE WHEN (SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES
WHERE
TABLE_NAME = 'Empresa$Tabla') = 0 THEN 'NO TIENE TABLA Empresa$Tabla' ELSE 'SI TIENE TABLA Empresa$Tabla' END

jueves, 13 de febrero de 2014

Cómo volver a mostrar la ventana de datos de informes en Reporting Services

El otro día cerre el Reporting Services, y al volverlo a abrir me habia desaparecido la ventana Datos del Informe. No es la primera vez que me pasaba, pero no recordaba como se voliva a mostrar. Como tampoco recordaba su nombre no era capaz de encontrar la manera.
Buscando en internet ayuda, encontre en esta web la solución.

La opción está en el menú Ver-Datos de Informe.
O darle a Ctrl + Alt + D

jueves, 6 de febrero de 2014

Cambiar los captions de un formulario de Navision en tiempo de ejecucion

Para poder cambiar los captions de un formulario, utilizaremos la propiedad CaptionClass del campo.
En el formulario seleccionamos el campo que deseamos cambiar el caption.

 
En las propiedades seleccionamos CaptionClass y ponemos '1,1,,' + NuestroCaption.
 
 
NuestroCaption puede ser perfectamente un parámetro que cambiemos en el openform por ejemplo, o una funcion como en el ejemplo anterior.
El CaptionClass utiliza de la Codeunit 1 la funcion DimCaptionClassTranslate

jueves, 30 de enero de 2014

Campos MEMO en Navision

En este post vamos a ver un ejemplo de como crear un campo memo y grabar y leer datos en este campo.
Lo primero que hay que hacer, es definir un campo de tipo BLOB y luego, en propiedades seleccionar el SubTipo MEMO.



 
 
Para grabar hariamos lo siguiente:
 
Var Name  DataType Length
Memo  BigText  
Texto  Text  1024
i  integer  
ISLector  InStream  
OSEscritor  OutStream  
 
//ESCRIBIR
Memo.ADDTEXT('Mi texto');
Memo.ADDTEXT('Mas');
...
MiTabla.CuerpoLargo.CREATEOUTSTREAM(OSEscritor);
Memo.WRITE(OSEscritor);
MiTabla.INSERT

//LEER
CLEAR(Memo);
MiTabla.CALCFIELDS(CuerpoLargo);
MiTabla.CuerpoLargo.CREATEINSTREAM(ISLector);
Memo.READ(ISLector);
i := 1;
WHILE i <= Memo.LENGTH DO BEGIN
      Memo.GETSUBTEXT(Texto,i,MAXSTRLEN(Texto));
      i:=i+MAXSTRLEN(Texto);
      MESSAGE('%1',Texto);
END;

jueves, 23 de enero de 2014

Instalar los WEB SERVICES de Navision en un servidor

En este post explicaremos como instalar el servicio de Navision de la capa de Web Services.
Ejecutamos el instalador de la carpeta del CD ServiceTier/Microsoft Dynamics Nav Service.msi
y seguimos los pasos.

Una vez instalado, en los 2 servicios de windows creados poner un usuario y contraseña que tenga permisos y roles en navision. Por lo que ponemos un usuario que sea super.

Hay que tener en cuenta,para los que vais a acceder desde php, que por defecto viene la autenticación NTLM desactivada. Es necesario que este activada para acceder con php.
Para activarla, buscamos el archivo CustomSeting.config que suele estar en
C:\Program Files (x86)\Microsoft Dynamics NAV\60\Service\CustomSeting.config y en la entrada <add key="WebServicesUseNTLMAuthentication" value="false"></add> le ponemos true.

jueves, 16 de enero de 2014

Abrir cliente de Navision desde Reporting Services

Crear un link en Reporting Services que nos abra nuestro cliente de navision en una pantalla determinada con unos filtros definidos se hace de la siguiente manera:
  1. En reporting, seleccionamos las propiedades del elemento que va a tener incrustado el link. 
  2.  
  3. En la direccion URL ponemos el link de la siguiente manera ="mi_link"
     
El link se escribe de la siguiente manera:
navision://client/run?
servername=MI_NOMBRE_SERVIDOR
&
database=MI_BASE_DE_DATOS
&
company=MI_EMPRESA
&
target=Form NUMERO_DE_FORM
&
view=SORTING(Field1)
WHERE(Field41=CONST(Rojo),
      Field40=CONST(Alto))
&
position=
&
servertype=MSSQL

La definición de los campos se hace poniendo Field+id del campo.
Si el cliente está abierto, abre un formulario nuevo con nuestra petición. Si no esta abierto, abre el cliente clásico y después el formulario deseado.

jueves, 9 de enero de 2014

Incrustar imagenes en un correo HTML

Se pueden mandar correos por smtp en navision utilizando la codeunit SMTP Mail y el objeto Automation 'Microsoft Navision Mail'.SmtpMessage que viene con la instalacion del navision clásico.
El cuerpo de los correos se puede mandar en html indicandolo en una de las propiedades que tiene el objeto. Si queremos enviar imágenes incrustadas dentro del mensaje en esta web tenemos la
explicacion de los requisitos necesarios para que nuestra imagen este bien formada.

Con esta otra web que convierte imagenes a base64, podemos convertir cualquiera de nuestras imágenes a texto html necesario.
Si agregamos el texto resultante al cuerpo de nuestro mensaje tendremos una imagen incrustada. Pero no vamos a dejar el post aqui, lo que yo propongo, consiste en guardar este resultado en un archivo de texto y leerlo cuando vayamos a utilizarlo para incorporarlo a nuesto correo.Es una de las opciones, tambien se puede guardar en un campo MEMO de la base de datos (Lo explicaremos en un próximo post) o simplemente ponerlo a piñon en una variable de texto.

Las variables:
Name DataType Subtype Length
btResultado BigText    
NombreFichero Text   1024
Fichero File    
ISLector InStream    
CuerpoHTML BigText    
Texto Text   1024
i Integer    

//Abrimos el fichero, lo recorremos y lo guardamos en un BigText
IF EXISTS(NombreFichero) THEN BEGIN
    IF Fichero.OPEN(NombreFichero) THEN BEGIN
       CLEAR(CuerpoHTML);
       Fichero.TEXTMODE := TRUE;
       Fichero.CREATEINSTREAM(ISLector);
       CuerpoHTML.READ(ISLector);
       i := 1;
       WHILE i <= CuerpoHTML.LENGTH DO BEGIN
          CuerpoHTML.GETSUBTEXT(Texto,i,MAXSTRLEN(Texto));
          i:=i+MAXSTRLEN(Texto);
          btResultado.ADDTEXT(Texto);
       END;
    END;
END;

jueves, 2 de enero de 2014

Error al ejecutar un Informe por limitacion de filas en el combobox

Con la actualización de seguridad MS11-100 de Microsoft, se limita el numero máximo de filas del parámetro de tipo combobox de Reporting Services a 1000. Si el parámetro contiene más de 1000 filas da un error la ejcución. Esto se soluciona especificando en los archivos de configuración de Reporting Services el número de registros.
Dentro de la carpeta ReportService y dentro de ReportManager en los archivos web.config hay que añadir lo siguiente:
<appSettings>
<add key="aspnet:MaxHttpCollectionKeys" value="30000" />
<add key="aspnet:MaxJsonDeserializerMembers" value="30000" />
</appSettings>
Todo esto se añade justamente detrás del tag <system.web> y si ya existe el tag <appSettings> ponemos nuestras dos líneas dentro.
Es decir, quedaría así;
</system.web>
<appSettings>
<add key="aspnet:MaxHttpCollectionKeys" value="30000" />
<add key="aspnet:MaxJsonDeserializerMembers" value="30000" />
</appSettings>