Mostrando entradas con la etiqueta Desarrollo. Mostrar todas las entradas
Mostrando entradas con la etiqueta Desarrollo. Mostrar todas las entradas

miércoles, 7 de enero de 2015

Trasformar un WebService REST en uno SOAP

Hace poco en un cliente me pidieron leer un WebService de tipo REST desde PeopleNet.

Sin saber demasiado de que iba todo este mundo pregunté en Soporte y me indicaron que PeopleNet trabaja como consumidor de WebServices SOAP pero no REST, aunque si lo puede ser proveedor de ambos tipos.

Primera pregunta ¿Qué diferencias hay entre REST y SOAP?... encontré este artículo que explica de forma sencilla las diferencias más importantes: "REST vs SOAP al servicio de la web". Ahora el problema residía en cómo iba a conseguir leer desde PeopleNet ese tipo de WebService.

Lo primero que quiero que quede claro es que no soy ningún experto en Java y que buscando cosas por internet conseguí que el WebService que me proveían (REST) lo pudiera invocar desde PeopleNet. Seguro que existen mil problemas en hacerlo como muestro y no sé si servirá para todos. (Lo expertos en Java sabrán perdonarme [Espero])

Lo que hice fue crear, con Netbeans, un WebService SOAP al que yo le pasaba una serie de parámetros y éste invocara al WebService REST. Lo que hago, basicamente, es componer una llamada XML y lanzarla a la URL que me indicaban.

La clase completa está aquí; NewRequest.java

Ahora intento explicar el código

1ª Parte: definición del WebService
@WebMethod(operationName = "GetData") 
    public String GetData(@WebParam(name = "param1") String param1, @WebParam(name = "usr") String usr,@WebParam(name = "pwd") String pwd) { 

Esta parte simplemente prepara el encabezado del WebService o cómo invocarlo.

2ª Parte: composición de llamada XML
sParameters = "\r\n"; 
sParameters += "\r\n"; 
sParameters += "\r\n"; 
sParameters += ""+param1+"\r\n";
sParameters += ""+usr+"\r\n"; 
sParameters += ""+pwd+"\r\n"; 
sParameters += "\r\n"; 
sParameters += "\r\n"; 

Esta parte deja en una variable sParameters la solicitud al WebService REST, donde me exigen un código de una persona, un usuario y una contraseña.


3ª Parte: envío de la solicitud

URL uri = new URL("http://www.dominio.com/services/Dataservices.php"); 
HttpURLConnection connection  = (HttpURLConnection) uri.openConnection(); 
connection.setDoInput(true); 
connection.setDoOutput(true); 
connection.setRequestMethod("POST"); 
connection.setRequestProperty("Content-type", "text/xml"); 
            
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream()); 
writer.write(sParameters); 
writer.flush(); 

Esta parte enlaza una llamada POST a la URL que me habían proporcionado a través de un objeto OutputStreamWriter (writer) sobre una HttpURLConnection

4ª Parte: recepción de la información del WebService REST y retorno del WebService SOAP
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); 
            
StringBuilder builder = new StringBuilder(); 
for (String line = null; (line = reader.readLine()) != null;) { 
     builder.append(line).append("\n"); 
}
            
writer.close(); 
reader.close(); 
            
return( builder.toString()); 

Esta parte genera un String que posteriormente retorno para mi código LN4 (Regla de un método meta4)

Una vez compilado y subido como war a un Tomcat por ejemplo, podremos generar el WSDL que PeopleNet necesita.

¿Simple? Sí, puede ser...
¿Efectivo? Para mi problema sí
¿Mejorable? Sí, supongo que mucho


Espero que a alguno os pueda servir
Hasta la próxima y perdón por no escribir tanto como me gustaría.

PD. Feliz 2015 a todos

lunes, 21 de noviembre de 2011

Ejecución de Meta4Objects planificados en el Job Scheduler II

Hace tiempo que no escribía post de desarrollo. La verdad es que he estado bastante liado con un motón de cosas y simplemente hacía referencia a noticias del mundo Meta4. Mis disculpas.

Retomo en este caso un post antiguo para ampliarlo. El post era Ejecución de Meta4Objects planificados en el Job Scheduler y trataba de como planificar la ejecución de Meta4Objects desde código LN4.

Ese post tenía la limitación de no dejar al usuario elegir el modo de planificación. Recordemos que tenemos: Inmediato, Cíclico, Plan anual o Lista de fechas.


En esta ocasión nos valdremos de un objeto de presentación, un Action_bp con una tarea específica: JSForPresentations, que nos ayudará en este propósito.

Lo que haré será primero desde un botón invocar la ejecución de un método que informa una propiedad (de ámbito nodo y tipo Long en este ejemplo) que luego se pasa a presentación y se incluye en un parámetro de la tarea JSForPresentations. Este código concatena una llamada LN4 por in-dirección a través del método clcExecuteLN4JIT

El código de este método que llamaré CXX_PLANIFICACION_PROCESO es:

MsT3 = "MI_M4OBJ"
MsNodo = "MI_NODO de MI_M4OBJ"
MsMetodo = "CXX_PROCESO"
MsAlias = "MI_ALIAS"

MsDQ = CHR(Double_quote)

PRP_LN4_CODE = "{·Execute LN4 Code·,LN4_CODE,·"
PRP_LN4_CODE = PRP_LN4_CODE + "DefineInstanceEx(" + MsDQ + MsAlias + MsDQ + "," + MsDQ + MsT3 + MsDQ + ", M4_AUTOLOAD_OFF, M4_INSTANCE_NOT_SHARED, " + MsDQ + MsDQ + ", M4_ORGANIZATION_L2_TYPE_ANY):"
PRP_LN4_CODE = PRP_LN4_CODE + "sCode = " + MsDQ + MsAlias + "!" + MsNodo + "." + MsMetodo + "()"+ MsDQ + ":"
PRP_LN4_CODE = PRP_LN4_CODE + "clcExecuteLN4JIT(sCode)·}"

Return (M4_SUCCESS)

Es importante el caracter "punto" ("·", tecla shift + 3)

Realmente estamos haciendo: MI_ALIAS!CXX_PROCESO() una vez hubiéramos declarado el Alias de Meta4Object.

Aparte de esto, en una presentación, crearé dentro de un botón y su evento click el siguiente código:

 BEGIN Button bttXXXX

  Idchannel = "CXX_XXXX"
  Idnode = "CXX_XXXX"
  Text = "Planificación desde Presentación"
  BEGIN Evclick Evclick1
    BEGIN Action_method amthdCXX_PLANIFICACION_PROCESO
      Iditem = "CXX_PLANIFICACION_PROCESO"
    END
    BEGIN Action_set asBoxName
      Set = "*C*BOXNAME := 'Planificación del proceso XXX'"
    END
    BEGIN Action_set asBoxList
      Set = "*C*BOXLIST := [PRP_LN4_CODE]

    END
    BEGIN Action_bp bpJobScheduler
      Idbp = "JSForPresentations"
      Load = False
      Localcontext = False
    END

  END
END


Al pulsarse, este botón, se ejecuta el método CXX_PLANIFICACION_PROCESO que genera el contenido de la propiedad PRP_LN4_CODE para después pasarlo al parámetro BOXLIST que hará que se incluya en la tarea JSForPresentations y así poder gestionarse la planificación sin las "ataduras" del anterior post.

Espero que os sirva!!

jueves, 9 de septiembre de 2010

Solución en la llamada al Gestor Documental de Meta4 desde Firefox en el ESS/MSS

En un cliente hemos tenido un problema a la hora de desplegar la página que permite ver documentos almacenados en el Gestor Documental de Meta4 en navegadores Firefox.

Concretamente al llamar a la página "sse_g0/ssco_view_document.jsp" se retorna desde un Meta4Object una URL que usa el servlet download_blob:

server:port/servlet/download_blob?task=SSCO_VIEW_DOCUMENT&item=SSCO_VIEW_DOCUMENT!SSCO_VIEW_DOCUMENT[0].PRP_LOAD_DOC&no-cache=true


La dirección parece correcta pero si os fijais, aparecen unos caracteres "#38;" justo después de cada "&". Bueno, pues esa serie de caracteres hacen que la página no despliegue el documento, dejandola en blanco y sin dar error alguno.

Lo que hemos hecho para que se pueda desplegar es añadir un "replace" vía javascript a la URL de la siguiente forma:

[...]
urlDoc = "";
//SIC; Solución al error al levantar con FireFox la nueva página
urlDoc = urlDoc.replace(/#38;/g,"");
[...]

Quizás no sea la forma más sencilla pero, de esta forma funciona, y si alguien sabe una forma mejor, estaré encantado de saber cómo.

Nota: que decir tiene que Meta4 no tiene certifcado el ESS/MSS en la versión en la que estamos por lo que si disponeis del nuevo Look&Feel del ESS/MSS no tengais este problema.

Nota2: en Internet Explorer no se reproduce este problema

miércoles, 25 de agosto de 2010

m4:executereportsec

En varios post he hablado de cómo generar reports en el ESS mediante el uso del tag m4:executereport. Esta forma genera un report en la ruta "temp" de los m4webservices, añadiendo un usuario, la sesión, el nombre del report como ruta al report en PDF que Meta4 genera, como se puede ver en la siguiente imagen:


Cuando generamos un informe en el ESS con este tag podemos ver la ruta en la barra de dirección:


La ruta es: https://xxxxxxxx/temp/SICDAVID_34589BAEC222C212B9FDAE65A1310EC260963EA355BB3EC92F69B88F8486FD77/reports/CSL_RP_GNRAL_EVALUACION/CSL_RP_GNRAL_EVALUACION.pdf

Esta forma de generar un report tiene una seríe de problemas:

  1. Si la sesión no finaliza correctamente no se borran los informes

  2. Ocupa espacio en disco físico

  3. Si el nombre de usuario tiene caracteres especiales (espacios, "ñ"'s,...) , en UNIX/AIX, no se permite la impresión del informe porque el File System es incapaz de localizarlos.

  4. Poco seguro, si no se borran los ficheros alguien podría tener acceso a ellos y ver un Recibo de nómina, un Certificado de Haberes, informes personales de evaluaciones,...
Por ello y desde hace algún tiempo, a los informes/reports en el SSE los llamo usando el tag m4:executereportsec, cuya llamada es exactamente igual, pero evito que se generen en una ruta del servidor.


La ejecución de esto informes se guarda en base de datos y, como se puede ver en la siguiente imagen, en la barra de dirección del browser (navegador) aparece una ruta un poco menos explícita ya que se utiliza el servlet download_blob:



La ruta es:
https://xxxxxxxx/servlet/download_blob?task=REPORTS&item=SRP_HTML!HTML_RPT[FIRST].HTTP_DATA_FILE&no-cache=true

Retomando un poco los problemas del tag m4:executereport
  1. si la sesión no finaliza correctamente no se borran los informes; ahora, como no se guardan en disco no hay que borrarlos.
  2. Ocupa espacio en disco físico; ahora, como no se guardan en disco no se ocupa nada.
  3. Si el nombre de usuario tiene caracteres especiales (espacios, "ñ"'s,...) , en UNIX/AIX, no se permite la impresión del informe porque el File System es incapaz de localizarlos; ahora, como no se guardan en disco no hay problemas de generación de rutas en disco.
  4. Poco seguro, si no se borran los ficheros alguien podría tener acceso a ellos y ver un Recibo de nómina, un Certificado de Haberes, informes personales de evaluaciones,... ahora, la ejecución es totalmente segura y nadie verá nada que no pueda o deba ver.
Espero que os haya servido!

lunes, 10 de mayo de 2010

Calcular responsable y su mail

Desde hace ya un tiempo los clientes me piden que, tras ciertas acciones de un empleado en el Portal del Empleado (SSE), se remita un correo de cortesía a su responsable avisando de esta acción. [Obviamente cuando son procesos fuera de los flujos estándar]

Bueno el tema podría ser realizar una pequeña carga de un nodo con la Unidad a la que el empleado pertenece, revisar su responsable, los emails de ambos y lanzar el mail, pero vamos a "simplificarlo" usando el Meta4Object estándar SSE_VALIDADORES.

Primero es necesario generar dos alias de Meta4Object, uno para el SSE_VALIDADORES y otro obviamente para el Meta4Object MAIL:

MAIL:


SSE_VALIDADORES:

Después crearemos un método, conectado, por ejemplo antes del PERSIST_TREE() con un código semejante a este:

SSE_VALIDADORES!SSE_VALIDADORES.BEGIN()
MsIdPersona = [campo del ID de la Persona i.e. STD_ID_HR]
SSE_VALIDADORES!SSE_VALIDADORES.SSE_CALC_EMAIL(MsIdPersona,"SSE_EMAIL")

MsMailEmpleado = SSE_VALIDADORES!SSE_VALIDADORES.SSE_EMAIL
MsEmpleado = SSE_VALIDADORES!SSE_VALIDADORES.SCO_GB_NAME
SSE_VALIDADORES!SSE_VALIDADORES.ID_HR_PAR = MsIdPersona
SSE_VALIDADORES!SSE_VALIDADORES.SSE_CALC_RESPONSABLE("WORKUNIT10")
MsIdPersonaResp = SSE_VALIDADORES!SSE_VALIDADORES.SSE_ID_PERSON_RESP
MsMailResponsable = SSE_VALIDADORES!SSE_VALIDADORES.SSE_EMAIL_RESP

Este código nos deja en:

  • MsEmpleado el Nombre del empleado
  • MsMailEmpleado el email del empleado
  • MsIdPersonaResp el ID del responsable
  • MsMailResponsable el email del responsable

Luego con generar un mail ya estaría:

MAIL!MAIL.COMPOSE()
MAIL!MAIL.FROM = MsMailEmpleado
MAIL!MAIL.CC = MsMailEmpleado
MAIL!MAIL.DESTINATION = MsMailResponsable
MAIL!MAIL.SUBJECT = "Aviso de cambio en ...."
MAIL!MAIL.BODY = "Este correo electrónico se remite de forma automática desde el Portal del Empleado para avisarte de que " + MsEmpleado + " ha realizado ..."
MAIL!MAIL.SENDALL()



Espero que os sirva!!

martes, 29 de diciembre de 2009

As Button Generator

Intentando cambiar algunos botones del ESS me he encontrado "googleando" [como me gusta este verbo] un generador on-line gratuito de botones: As Button Generator

As Button Generator tiene herramientas para definir tamaño, color y forma del botón, efectos en brillos y textos, relieves, sombras, tipo de fuente… miles de combinaciones para hacer un botón único listo para guardarlo en formato PNG y usarlo en vuestro proyecto.

Una excelente alternativa para los que no quieren pelearse con un editor de imágenes más complejo.

Espero que le podais sacar partido!!

viernes, 14 de agosto de 2009

[Colaboración de Dailos Herrera Bencomo - General de Software de Canarias (GSC) - Grupo Microfusión] Número a letra desde Ln4

Dailos Herrera Bencomo de General de Software de Canarias (GSC) - Grupo Microfusión (http://www.gsc.es), me ha enviado la información necesaria para crear un post que creo que os resultará muy interesante. Se trata de poder transformar un campo moneda (número) a letra desde LN4.

Exite en la aplicación un formato que se puede usar en reports/informes que permite el cambio número a letra, pero sólo se puede usar desde allí. ¿Qué pasa si queremos sacarlo en un Word, en un Excel o incluso en una presentación? Pues bien, Dailos ha buscado la forma y me ha permitido publicarlo en blog:

En un access adjunto (7.1Sp2), podeis encontrar los objetos y los transfer necesarios:

Meta4Object: CGC_MONEDA_A_LETRAS
Estructura de Nodo: CGC_MONEDA_A_LETRAS

Métodos:

  1. CGC_NUM_A_LETRA: Hace el cambio de moneda a letra
  2. CONVERTIR_A_LETRA: Hace la llamada al método anterior y formatea la salida según los argumentos:
  • ARG_MONEDA: Moneda a convertir
  • ARG_CASE: "U" o "L" formatea la salida en Mayúsculas o Minísculas, respectivamente, "U" por defecto
  • ARG_CURR: "1" o "0" muestra o no la palabra "EURO/S - CENTIMO/S", respectivamente, "0" por defecto (Si se elije mostrar EUROS/CENTIMOS acaba en "UN" y si se elije NO mostrar EUROS/CENTIMOS acaba en "UNO")
  • ARG_SIGNO: "1" o "0" muestra o no la palabra "MENOS", respectivamente, si se trata de un número negativo, "0" por defecto.
Aquí teneis el enlace al Fichero de MsAccess

Espero que os sea útil.

jueves, 25 de junio de 2009

Descubrir elementos de sesión sin definir Alias

¿Cuantas veces has tenido que crearte un Alias y su resolución para poder acceder al valor de otro Meta4Object?

Aquí os dejo un "truco" para hacerlo en 3 líneas; en este caso se obtiene el ID_PERSON del usuario logado, pero se pueden hacer muchas más cosas...

DefineInstance("SCH_SESSION","SCH_SESSION", 0, 3)
Code ="return(SCH_SESSION!ROOT_SESSION.ID_PERSON)"
sIdPerson = ClcExecuteLN4JIT(Code)


Espero que os sirva

sábado, 20 de junio de 2009

Asignación masiva de valores del Periodo de RH

He tenido que realizar este desarrollo que quizás alguien necesite, ya que se necesitaba cargar información en la base de datos, por ejemplo el sueldo de los empleados, en la tabla de Valores del Periodo de RH.




A partir de la versión 7 existe ya una carga másiva de Incidencias del Periodo de RH, pero son eso "incidencias" para una paga en concreto no para dar valores desde una fecha en adelante.




Necesitais descargar un fichero access (ASIGNACION_MASIVA_VALORES.rar) y ejecutar las siguientes sentencias, através de la RAMDL (Ojo el MDB está en versión V7.1Sp2 con HF6, si estais por delante os servirá subiendolo de verisión, si estais por detrás tendreis que subir la versión del entorno)




Es necesario disponer ya de la versión 7 de las tablas de valor ya que se basa en ellas para hacer la carga.




Sentencias:



TRANSFER "NODE STRUCTURE"."SRCSL_PY_VT_DATA_HR_PERIOD_VAL" FROM ORIGIN TO DESTINATION\
TRANSFER "META4OBJECT"."CSL_PY_VT_HR_PERIOD_VAL_MASS" FROM ORIGIN TO DESTINATION\
TRANSFER "PRESENTATION"."CSL_PY_VT_HR_PERIOD_VAL_MASS" FROM ORIGIN TO DESTINATION\
TRANSFER "MENU OPTION"."MN_CSL_PY_VT_HR_PERIOD_VAL_MAS" FROM ORIGIN TO DESTINATION\
TRANSFER "BUSINESS PROCESS"."BP_CSL_PY_VT_HR_PERIOD_VAL_MAS" FROM ORIGIN TO DESTINATION\





Este proceso debería generarte una nueva opción de menú en: Nómina \ Tablas de Valor \ Valores del periodo de RH \ Entrada masiva de valores del Periodo de RH que se puede ver en la siguiente imagen:

¡¡¡¡¡ NOTA IMPORTANTE !!!!!
Para el caso que he tenido que realizar ha funcionando correctamente pero no se ha realizado un plan de pruebas exhaustivo y no puedo asegurar al 100% que funcione en todos los casos... tomadlo como una ayuda

Espero que os sirva!!

jueves, 18 de junio de 2009

Capas de los menus del ESS/MSS en FireFox

Cuando desde un FireFox accedemos al ESS/MSS, no se despliegan las capas de los menú.
Para arreglar esto es necesario modificar dos cosas en los ficheros: default\libreria\menus_ess_esp.js y default\libreria\menus_mss_esp.js


  1. Esto creo que es un bug de Meta4: busca un literal que dice “odivmenu” y cambialo por “capa_menu”

  2. Esto ya es es para que la capa se dibuje un pelo más abajo de donde sale: busca un literal que dice “oparent.offsetTop + oparent.offsetHeight” y cambia esa línea:

}else{m4elemento(capa).style.top =(oparent.offsetTop + oparent.offsetHeight ) +"px";}
Por
}else{m4elemento(capa).style.top =(oparent.offsetTop + oparent.offsetHeight + 66) +"px";}
Ya está… el ESS/MSS listo para funcionar con el FireFox…

Nota: Meta4 aún no ha certificado FireFox, esto hace que la capas funcionen y por lo que he probado yo no hay mayor problema por cambiar de navegador…, pero es eso… lo que digo yo
Espero que os sirva!!

domingo, 26 de octubre de 2008

[Colaboración de Jaime González de Zárate - SIC S.A.] Invocación a servicio SOAP externo a Meta4

Mi compañero Jaime González de Zárate de SIC S.A. (http://www.sicsa.es/), me ha enviado la información necesaria para crear un post que creo que os resultará muy interesante. Se trata de poder invocar Web Services a través de SOAP.

El objetivo de este post es mostrar cómo la aplicación Meta4 también puede funcionar como un cliente SOAP que realiza peticiones a un determinado servicio SOAP y traspasa los datos requeridos a los Meta4Objects ya definidos.

Meta4 como cliente SOAP tiene algunas restricciones, ya que no es capaz de consumir todos los servicios SOAP que existen descritos por un WSDL cualquiera. Esto es así, porque Meta4 no puede convertir una estructura de datos arbitraria en un Meta4Object, solamente soporta un subconjunto de tipos.

Meta4 como cliente SOAP es capaz de interpretar los tipos básicos más significativos de SOAP http://www.w3.org/tr/xmlschema-0/ , así como un subconjunto de tipos complejos.

Los tipos complejos que Meta4 puede consumir deben ser estructuras mixtas o vectores de una dimensión de estructuras mixtas. Se define estructura mixta como un objeto compuesto por tipos básicos, estructuras simples (compuestas únicamente por tipos básicos) u otras estructuras mixtas.

Esto significa que Meta4 no es capaz de consumir matrices multidimensionales o vectores de tipos básicos.

Con respecto a los ficheros, Meta4 no los consume. Pero existe una excepción: si los ficheros provienen de una implementación concreta (Axis DataHandler), Meta4 los consume sin ningún problema, tanto de entrada como de salida.

Principalmente hay dos tipos de servicios:
  • rpc/encoded
  • document/literal

Por el momento Meta4 no consume servicios Document/Literal.

Para realizar el ejemplo que se desarrollará en este documento utilizaremos una arquitectura que consta de los siguientes componentes atendiendo a la Guía de Certificaciones:

  • Contenedor Web: Tomcat 5.0.28
  • Motor SOAP: AXIS 1.1
  • Java Virtual Machine: j2sdk1.4.2

Además utilizaremos un “TCPMonitor” (ver punto 4 del documento) que es una utilidad que escucha en un puerto y monitoriza todo lo que se reciba y se mande por él, y lo redirecciona automáticamente al puerto correcto.

Como el documento es largo en vez de añadirlo como Post lo adjunto. Link

Como podreis ver no resulta tan sencillo como aparece en la documentación de Meta4. Si alguien lo ha conseguido de otra forma y quiere compartirla estaré encantado de escribirlo en el blog... así como conseguir que sea Meta4 PeopleNet quien provea de estos Web Services (SOAP).

Espero que sea útil.
SEGURO QUE LO ES... Muchas gracias Jaime!!

miércoles, 22 de octubre de 2008

[Colaboración de Lucas Gutiérrez Jaramillo - Ceiba Software House] Cambiar el color de las celdas de Excel desde PeopleNet

Lucas Gutiérrez Jaramillo de Ceiba Software House (http://www.ceiba.com.co/), me ha enviado la información necesaria para crear un post que creo que os resultará muy interesante. Se trata de poder cambiar propiedades de celdas de un Excel desde una regla LN4 de Meta4 PeopleNet, en este caso el color.

Antes de empezar es muy recomendable que leais también el post Macros Excel en LN4.

Lo primero consiste en heredar el objeto de Excel, para no trabajar sobre el original, luego se creará una nueva estructura de nodo para obtener el objeto "Interior" de la celda a la que queremos colorear. Esta estructura estará ubicada dentro de un nodo hijo del nodo EXCEL_CELLS, ya que este dependerá de la celda seleccionada. Esta estructura se llamará CCB_EXCEL_INTERIOR.


Estructura final, con métodos y propiedades


La nueva estructura debe conectarse con las su padre de la siguiente manera para que las referencias sean correctas.


Conectores

Las estructuras deben tener una propiedad para apuntar a cada nivel según su jerarquía en el árbol del objeto por cada nivel se agrega un grandparent (abuelo) mas.

Una vez teniendo la estructura correctamente se crean los métodos para la obtención del objeto "Interior". Estos dos métodos son: GETINTERIOR y GETINTERIORINT

GETINTERIOR es un metodo del tipo LN4, que crea un nuevo registro y luego llama al método GETINTERIORINT que es el que realmente hace el llamado al objeto de Excel. A continuación se ilustra como es este método:


Método GETINTERIOR


Código de GETINTERIOR

GETINTERIORINT es el wrapper (envolvente) del método de la dll que hace el verdadero llamado a Excel para obtener el objeto Interior. Este método hace el llamado a la función GetObjectFromProperty. Esta función obtiene el objeto Interior de la propiedad Interior (Llevan el mismo nombre) del objeto Range, el cual es el tipo de objeto que se obtiene desde PeopleNet al llamar el metodo EXCEL_CELLS.GetCell(x,y) del objeto Excel. Según esto, primero se debe llamar obtener la celda (Objeto Range en Excel) y luego obtener el interior de la celda (Objeto Interior en Excel).

Método GETINTERIORINT

Código de GETINTERIORINT

Por último el método COLORINDEX, este método es el wrapper del método de la dll que cambia la propiedad ColorIndex del objeto Inerior. Este método en la dll se llama OLE_Property, este hace el llamado a la propiedad según el nombre del método, por eso el método debe llamarse igual que la propiedad que se desea modificar (No es case sensitive). Si se deseara modificar otra propiedad de este objeto simplemente se crea el método con el nombre de la propiedad que se desea modificar. Se debe tener en cuenta que si esta propiedad es un objeto, debe obtenerse el objeto de la misma manera que se obtiene el objeto Interior, y no puede asignarse directamente.

Método COLORINDEX

Código de COLORINDEX

Por último, Lucas comenta: "mucho de lo que se dice en este post son conclusiones obtenidas sobre la marcha al momento de implementar esta funcionalidad, todas basadas en mi trabajo anterior en interacciones con Excel desde otras aplicaciones, y en como hasta ahora he visto que se trabaja en PeopleNet. Es así como pueden estar erróneas y si es del caso estoy abierto a que cualquiera que conozca el verdadero funcionamiento me corrija.

Espero que les sea útil."
SEGURO QUE LO ES... Mucha gracias Lucas

miércoles, 17 de septiembre de 2008

Macros Excel en LN4

(Sacado del CSS de Meta4 y ampliado)

El número de métodos del objeto Excel es muy limitado, por lo que en ocasiones, se puede requerir la utilización de nuevos métodos de EXCEL accesibles vía OLE, a través de la OLEEXEC.DLL.

El Meta4Object Excel instancia un objecto aplicación en el nodo raíz y una colección Workbooks en el nodo hijo. En esa colección no se soportan más que unos pocos métodos (Add, close ...), dado que los métodos de operaciones con hojas de cálculo, no están implementados a nivel de colección, sino a nivel de instancia, la cual sin embargo no está accesible.

Así pues lo primero, tras una llamada de la colección a "Add", que es cuando se crea la nueva hoja de cálculo, es cuando se puede obtener el handle de objeto Workbook instanciado dentro de la colección Workbooks. Como no se tiene referencia directa, se puede obtener, por ejemplo, utilizando la jerarquía de clases de Excel, utilizando la propiedad "ActiveWorkbook" de la clase "Application", para obtener el Handle de la hoja de cálculo. Si hacemos llamadas en el nodo raíz, nos devolvería el Handle en la misma propiedad que donde se ha almacenado el handle propio de la clase aplicación, y se perdería. 

  • Créate un Meta4Object nuevo, CSL_EXCEL que herede del Meta4Object EXCEL estándar. (Podrías tocar el propio Meta4Object EXCEL estándar pero mejor hacerlo así)
  • Mapealo y colocalo en el arbol de ejecución, para que las llamadas a EXCEL se hagan siempre contra tu Meta4Object.
  • Crea un nuevo nodo nodo y su estructura de nodo, que se debe crear a la misma altura que EXCEL_WORKBOOKS, por ejemplo ACTIVE_WORKBOOK. Se añaden las propiedades ERRORS, InterfacePointer y ParentInterfacePointer como en el nodo EXCEL_WORKBOOKS. En la tercera, se almacena el puntero del nodo padre a través del conector, conectando con la propiedad InterfacePointer del nodo raíz para leer el handle de la clase Application (nodo EXCEL).


  • Para implantar la llamada a la propiedad "ActiveWorkbook", debe llamarse a la función GetObjectFromProperty. Para ello, se crea un método (por ejemplo GET) de tipo DLL que referencie el recurso "OleExec.dll", método "GetObjectFromProperty", con un parámetro.
  • Para realizar la llamada, crea un método  (por ejemplo INICIALIZAR) de tipo ln4 en el mismo nodo, realizar el siguiente código; 
AddRegister()
MoveTo(Count()-1)
Get("ActiveWorkbook")
  • Sobre éste nodo, con el valor de InterfacePointer conseguido, se pueden realizar llamadas a los métodos de la clase "WorkBook", creando un método que ejecute la llamada "SaveAs". El método debe llamarse EXACTAMENTE IGUAL que la función que se quiera invocar a través de OLE. En este caso SAVEAS, con código DLL, y recurso "OleExec.dll", método "OLE_Execute" (se llama a la ejecución OLE del método cuyo nombre venga determinado por el identificador del item). Se debe indicar que tenga un parámetro que será la ruta de grabación. Posteriormente podrá ser invocado de la siguiente manera:

EXCEL!ACTIVE_WORKBOOK.INICIALIZAR()
EXCEL!ACTIVE_WORKBOOK.SAVEAS(“c:\MiArchivoExcel.xls”)

Adjunto la definición de los métodos creados:
Método GET:

Método INICIALIZAR:
Método SAVEAS:




Espero que os sirva...

lunes, 8 de septiembre de 2008

Planificación de ejecución de Meta4Objects

Sois bastantes los que me habéis preguntado cómo se puede delegar en el Planificador de Tareas (Job Scheduler) la ejecución de métodos de un Meta4Object.

Aquí redacto una forma de hacerlo. Esta forma no permite al usuario "final" la planificación de tareas de forma sencilla... necesita tener un poco de conocimiento. De todas formas para permitir a un usuario planificar ejecuciones contra el Planificador de Tareas desde un método Ln4, puedes consultar este post "Ejecución de Meta4Objects planificados en el Job Scheduler"

Imaginemos que disponemos de un Meta4Object llamado CXX_MI_META4OBJECT que en su nodo principal, CXX_MI_NODO, dispone de un método CXX_GESTION que realiza la carga del nodo y si hay información resultante de la carga envía un mail. Queremos que se ejecute todos los días a las 00:00 para controlar cierta información.

Nota: Haz click en las imagenes para verlas más grandes

a) Accederemos, inicialmente al Planificador de Tareas:



b) Pulsaremos en "Nuevo" para crear una nueva Tarea:


c) Rellenaremos todos los datos de la primera pestaña de la definición:

Son:
  • Planificación: Crearemos un ID Planificación nuevo: (i.e.) CXX_PLANIFICACION
  • Descripción: Crearemos una descripción que nos inforque que es lo que hace
  • Prioridad: En general "Normal" pero en función de tus necesidades puedes cambiarlo ("No urgente","Urgente"  o "Muy urgente")
  • Cola de ejecución: Podemos elegir entre los M4AppServers conectados a nuestra Base de Datos para decidir quien lo debe ejecutar. Podemos elegir, por ejemplo, un M4AppServer que corra sobre una máquina Windows para ejecutar exportaciones a Excel que una máquina UNIX o AIX sería imposible.

d) Rellenaremos todos los datos de la segunda pestaña de la definición:


Modificaremos:
  • Modo: "Inmediato" para una única ejecución, "Cíclico" hasta 500 ejecuciones que sigan algun patrón (todos los días, todos los martes,...), "Plan Anual" para ejecuiones que sigan planes anuales (1er, o último día meses pares, primer lunes de cada mes, cada 25 de cada mes,...) o "Lista de fechas" planficiaciones hechas para fechas concretas sin seguir patrón.
  • En cada uno de los casos existe diferentes opciones de planificación.
e) Rellenaremos todos los datos de la tercera pestaña de la definición, donde elegiremos una tarea llamada "Execute LN4 Code":



f) Rellenaremos todos los datos de la cuarta pestaña de la definición: 


Haz click en el campo de texto "Valor / Fuente" y pegaremos el siguiente código (link):




g) Rellenaremos todos los datos de la quinta pestaña de la definición, donde podremos indicar para que Sociedad se debe ejecutar este método (en mi caso sólo tengo una): 


h) Por último, inidicaremos en la sexta pestaña de la definición si deseamos, o no, estadísticas de la ejecución.  


Pulsaremos en "Finalizar" y PeopleNet nos avisará de la planificación de esta tarea


Ya está... espero que sea interesante.

jueves, 29 de mayo de 2008

Ejecución de Meta4Objects planificados en el Job Scheduler

Un truco que quizás ya sepais pero que viene bien tenerlo en cuenta. Se trata de poder ejecutar un método de un Meta4Object usando el Job Scheduler.


1er Caso: Ejecución de un método a través de una tarea


Este es el sencillo, creamos una tarea con código LN4 y le añadimos el código:


'Proceso:
Code = ""
MsT3 = "MI_M4OBJ"
MsNodo = "MI_NODO de MI_M4OBJ"
MsMetodo = "MI_METODO de MI_NODO de MI_M4OBJ"
DefineInstance(MsT3,MsT3,0,1)
Code=MsT3 + "!" + MsNodo + "." + MsMetodo + "()"
X=clcExecuteLN4JIT(Code)
Return(X)


De esta forma se ejecuta el método ID_ITEM del nodo ID_NODE del Meta4Object ID_CHANNEL. Planificamos luego con el Job Scheduler la ejecución de esta tarea como necesitemos.


Como podeis ver el método de este ejemplo no tiene parámetros.

Para añadir parámetros:
'Parámetros:
MsIDHR = MsDQ + STD_ID_HR + MsDQ
'Proceso:
MsDQ = CHR(Double_quote)
Code = ""
MsT3 = "MI_M4OBJ"
MsNodo = "MI_NODO de MI_M4OBJ"
MsMetodo ="MI_METODO de MI_NODO de MI_M4OBJ"
DefineInstance(MsT3,MsT3,0,1)
Code= MsT3 + "!" + MsNodo + "." + MsMetodo + "("+ MsIDHR + ")"
X=clcExecuteLN4JIT(Code)
Return(X)

Nota: Puedes consultar el post "Planificación de ejecución de Meta4Objects" para ver cómo se puede planificar este tipo de tareas en el Job Scheduler.

2º Caso: Ejecución de un método introducciendo valores desde un Meta4Object


Este caso me encanta y lo uso mucho... se trata de meter código en un Meta4Object y que se ejecute mediante el Job Scheduler. Por ejemplo lo uso para la generación de informes a texto muy grandes (contabilidad, nómina) y que los envíe a una dirección de correo electrónico que le indico (podría valer para Excel pero el servidor debe disponer de Ms Officce instalado):

'Parámetros:

MsMaildondeEnviar = "oscar.lopezgrandmontagne@gmail.com"
MsFechaCalculo = ToString(DT_PAYMENT,0)

'Proceso:
MsT3 = "MI_M4OBJ"
MsNodo = "MI_NODO de MI_M4OBJ"
MsMetodo = "MI_METODO de MI_NODO de MI_M4OBJ"

MsAlias = "NEW_" + MsT3
MsDQ = CHR(Double_quote)
MsCodeJS = "DefineInstance(" + MsDQ + MsAlias + MsDQ + "," + MsDQ + MsT3 + MsDQ + ", 0, 1):"
MsCodeJS = MsCodeJS + "MsDate = " + MsDQ + MsFechaCalculo + MsDQ + ":"
MsCodeJS = MsCodeJS + "MsMail = " + MsDQ + MsMaildondeEnviar + MsDQ + ":"
MsCodeJS = MsCodeJS + "MsCode = " + MsDQ + MsAlias + "!" + MsNodo + "." + MsMetodo + "(MvDate,MvMail)"+ MsDQ +":"
MsCodeJS = MsCodeJS + "MsReturn = clcExecuteLN4JIT(MsCode," + MsDQ + "MvDate" + MsDQ + ",MsDate," + MsDQ + "MvMail" + MsDQ + ",MsMail):"
MsCodeJS = MsCodeJS + "Return(MsReturn)"
MsTarea = JOB_SCHEDULER!N_JOB_GROUP_DEFS.SUBMIT_JOB("EJECUCION MI INFORME", MsCodeJS ,"ASAP")
SetLog(0,16,110,11,ToString(Format(MsTarea ,0)))
Return (M4_SUCCESS)


Hay que definir un Alias de Meta4object "JOB_SCHEDULER", para poder planificar la tarea.
Espero que os sirva de ayuda


martes, 27 de mayo de 2008

Ejecución de un script SQL desde Meta4

Usando el método EXECUTEREALSQL que ya definimos en otro post, es posible usar un método que lance un script de SQL como si de un TOAD se tratara.

Haremos lo siguiente:

  • En un método (ambito cliente), primero abriremos un fichero de texto (scipt.sql) y, segundo, dejaremos el contenido en la variable MsScript:


MsFile = "C:\temp\script.sql"
OpenFile(MsFile,handle)
ReadFile(handle, chr(0), MsScript)

  • Leeremos el fichero que separa las sentencias por ";" y las ejecutaremos usando el método EXECUTEREALSQL:

MsRest = MsScript
While length(MsRest )>0
MnSeparador = indexof(MsRest,";",0)
If MnSeparador <> M4_ERROR Then
MsToExec = Mid(MsRest ,0,MnSeparador )
MsRest = Mid(MsRest,MnSeparador + 1, length(MsRest)-MnSeparador -1)
EXECUTEREALSQL = MsToExec
MnRdo = EXECUTEREAL(0)
If MnRdo = M4_ERROR Then MessageBox("ERROR",MsToExec)
Else
EXECUTEREAL = MsScript + ";"
MnRdo = EXECUTEREALSQL (0)
If MnRdo = M4_ERROR Then MessageBox("ERROR",MsToExec)
EndIf
WEnd

Return M4_SUCCESS

Espero que os sirva

lunes, 5 de mayo de 2008

EXECUTEREALSQL

La ejecución del Método EXECUTEREALSQL permite interactuar directamente con la Base de Datos física, para, por ejemplo, ejecución de PL/SQL o sentencias directatas contra objetos tales como INSERT, UPDATE y DELETE.

Para ello hay que crear un concepto llamado EXECUTEREALSQL de ámbito Nodo, Tipo Long. En las propiedades avanzadas ponemos “Argumentos variables” a “”. Como regla creamos una de tipo CPP y en su método le indicamos que vamos a usar es: “executerealsql”. Creamos un argumento llamado ID_CONN de tipo número y tamaño 4.

En un método aparte creamos una sentencia a lanzar contra la base de datos y lo ejecutamos de la siguiente forma:

MsSQL = "INSERT INTO NUESTRA_TABLA (PK,CAMPO1,CAMPO2,CAMPO3) VALUES ('" + STD_ID_PERSON+"','" + STD_N_FAMILY_NAME_1 + "," + STD_N_FIRST_NAME + "'," + ToString(EDAD,0) + ",'" + MsDate + "')"

EXECUTEREALSQL = MsSQL
MsRdo = EXECUTEREALSQL(0)


En este ejemplo metemos en una tabla un valor numérico: “EDAD” y una fecha como cadena “MsDate”; para componer la fecha podemos usar:

MdDate = Today()
MsDay = ToString(DxDay(MdDate),0)
MsMonth = ToString(DxMonth(MdDate),0)
MsYear = ToString(DxYear(MdDate),0)
MsDate = MsDay + "/" + MsMonth + "/" + MsYear


Si queremos usar varias sentencias seguidas podemos encapsularlas en un PL y entonces la llamada será:

MsSQL = "BEGIN NUESTRO_PL ('" + ARGUMENTO1+"', '" + ARGUMENTO2+"','");END;"

EXECUTEREALSQL = MsSQL
MsRdo = EXECUTEREALSQL(0)

O podemos hacer varias llamadas enlacadas:

MsSQL = "DELETE NUESTRA_TABLA"

EXECUTEREALSQL = MsSQL
MsRdo = EXECUTEREALSQL(0)

If MsRdo <> M4_ERROR Then
MsSQL = "INSERT INTO NUESTRA_TABLA (PK,CAMPO1,CAMPO2,CAMPO3) VALUES ('" + STD_ID_PERSON+"','" + STD_N_FAMILY_NAME_1 + "," + STD_N_FIRST_NAME + "'," + ToString(EDAD,0) + ",'" + MsDate + "')"

EXECUTEREALSQL = MsSQL
MsRdo = EXECUTEREALSQL(0)
EndIf
Tiene un problema y es que las cosas que controla la Base de Datos Lógica, digase, completitud, datos "no null", fechas,... las debemos controlar nosotros. Además sino lo hacemos nosotros los campos de control de ID_SECUSER, ID_APPROLE o DT_LAST_UPDATE no se actualizan.
Ojo con usarla de "mala manera" con entornos con AUDITORIA ya que tampoco se actualiza.

viernes, 28 de marzo de 2008

CXX_AUX_ITEMS para Estructuras de Nodo con Herencia

En el post dedicado a la exportación genérica a Excel (link) o a texto (link), no me fijé en un pequeño detalle, y es que la sentencia de la estructura de nodo,CXX_AUX_ITEMS, que recupera los items a exportar de una estructura de nodo no funciona de forma correcta cuando ésta ha sido heredada.


Aquella era:

mientras que debería ser para cualquier estructura de nodo (heredada o no):

Los cambios residen en:

  • Añadir la tabla lógica "SCH_TIS_INHERIT" (usando una relación personalizada sin unión, de momento entre ningún campo)
  • Cambiar el filtro para que: "A.ID_TI = @ARG_ID_TI" pase a ser: "( A.ID_TI = @ARG_ID_TI Or ( A.ID_TI = B.ID_TI_BASE And B.ID_TI = @ARG_ID_TI ))"

Espero que os sirva. Yo ya la usé el pasado lunes :-)

martes, 25 de marzo de 2008

Filtro dinámico desde una presentación

En el nodo donde necesites tener un filtro dinámico pero no quieres que se "levante" cuando cargas el Meta4Object, crea una propiedad "CXX_DYN_FILTER" de ámbito nodo, tipo "Long" y tipo interno 34 - Sentencia lógica del filtro dinámico.

Luego, en un botón de una presentación pon el siguiente código:


BEGIN Button btnEjecutar
    Idchannel = "CXX_MI_M4OBJ"
    Idnode = "CXX_MI_NODO"
    Left = 468
    Top = 408
    Width = 105
    Height = 38
    Text = "&Ejecutar"
    BEGIN Evclick Ejecucion
        BEGIN Action_dialog EjecucionFiltro
            Idnode = "CXX_MI_NODO_A_FILTRAR"
            Dialog = "Filter"
            Oncancel = "acFinal"
        END

        BEGIN Action_call acFinal
        END
    END
END
Yo lo suelo usar en consultas en pantalla para que el usuario pueda filtrar a su gusto la población que desea.
Espero que os sea de ayuda!!

sábado, 1 de marzo de 2008

WebServices y Meta4 (SOAP)

Esta vez no voy a publicar una "ayuda" sino que la voy a pedir... :-(

Según la documentación de Meta4, PeopleNet es capaz de proveer y consumir WebServices, siento decir que "según la documentación" por que lo estamos intentando hacer y no hay manera.

Si alguien ha trabajado con WebServices y Meta4 (SOAP) por favor, que se ponga en contacto conmigo: oscar.lopezgrandmontagne@gmail.com, para que nos ayude, ya que lamentablemente desde soporte de Meta4 no pueden hacerlo... Es algo URGENTE porque tengo al cliente esperando.

MUCHAS GRACIAS!!!