Conector de Integración entre Bases de Datos


El conector de base de datos se instala como un servicio, y para su correcto funcionamiento es necesario configurar 2 ficheros:

Xone ITF Advanced.exe.config

Este fichero es el primero que lee el ejecutable, y se utiliza para decirle cual es el fichero de configuración de datos principales, asi como el nombre.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="Application Name" value="XOne ITF Advanced" />
    <add key="Configuration Path" value="C:\Archivos de programa\XOne\XOne ITF Advanced\ITF Config.xml" />
    <!-- Activar Seguridad SSL en el envio de correo -->
    <add key="mailSettings.EnableSsl" value="true" />
    <!-- Tiempo estipulado en segundos para reenviar un mensaje que ya ha sido enviado -->
    <add key="mailSettings.RetrySend" value="300" />
  </appSettings>
  <system.net>
    <mailSettings>
      <smtp from="">
        <network host="" userName="" password="" />
      </smtp>
    </mailSettings>
  </system.net>
</configuration>



ITF Config.xml

Fichero con el que programamos nuestra interface. Hay que indicar como apunte importante, que un mismo ejecutable permite dispones de varios sistemas funcionando al mismo tiempo, de tal forma que podremos tener varias integraciones que corren contra base de datos distintas con un solo ejecutable. También se suele utilizar para separar la subida con la bajada de datos a movilizar.

<xml>
	<!-- IMPORTANTE MANTENER COMO ESTAN LAS MAYUSCULAS O MINUSCULAS PARA LOS SETTINGS DE LA APLICACION -->
        <!-- Descripción Atributos:
           name: nombre de la interface
           versión: versión de la interface para su mejor visión en el visor de sucesos
           disabled: con este parametro activaremos o desactivaremos la interface
 
        -->
	<itf name="ITF 1" version="1.0" disabled="false">
                <!-- Para controlar el intervalo con el que se ejecuta la aplicación, tenemos dos opciones: Interval o cron-expression.-->
                <!-- Solo se debe de quedar activo uno de los dos nodos. Si estan los dos, predomina el Interval. -->
                <!-- El Interval da el tiempo en segundos. Tiene la limitación de 21600 segundos -->
		<item name="Interval" value="1"/>	
                <!-- El cron es mucho mas amplio y es el que se debe utilizar, ya que tienes un control total del tiempo. -->
                <!-- Mirar este enlace para documentarse: 
                 http://www.xoneisp.com/xonewiki/doku.php?id=f.-herramientas:f02.-xonemonitor:start#anexo_i_expresiones_cron              
                -->
                <item name="cron-expression" value="0 0/30 7-20 ? * *"/>
		<!-- ruta donde se encuentra el xml de configuracion de aplicacion-->
		<item name="XML Path" value="C:\Archivos de Programa\XOne\itf\itf1.xml"/>		
		<!-- Valor maximo de valores cacheados. Los valores que cachea son los filtros a buscar en el mapval -->
	        <item name="MaxCacheValues" value="15000"/>    
		<!-- Valor del MID con el que escribiremos en la base de datos -->
		<item name="MID" value="999"/>		
		<!-- Cuenta de correo a donde queremos que reporte los errores y advertencias que aparezcan -->
		<item name="Mail To" value="correo1@xone.es"/>
		<item name="Mail To 2" value="correo2@hotmail.com"/>
		<item name="Mail To 3" value="correo3@gmail.com"/>
                <!-- Creacion por defecto de la tabla interclient_sync_tables en caso de no existir en la base de datos, para control de cambios -->
		<item name="Inter Sync Create" value="CREATE TABLE interclient_sync_tables (ID int(11) NOT NULL Identity(1,1),   OBJECTNAME varchar(150) NULL,LASTMODIFIED datetime NULL, PRIMARY KEY (ID))"/>
 
                <!-- Parametros de conexion de tabla de eventos. 
                     Si queremos pasar el log a Base de datos en lugar de hacerlo en el visor de sucesos.
                     Habría que poner el nodo itflog en cada itf que queramos guardar log en base de datos.
                     En la siguiente línea, name especifica el nombre de la tabla de log.
                -->
		<itflog name="ITFLOG" provider="System.Data.OracleClient" connstring="Data Source=BASEDATOS;User id=USUARIOQUESEA;Password=CLAVEQUESEA"/>
 
		<!--  Estructura de la tabla ITFLOG:
 
				Nombre       Nulo     Tipo           
				------------ -------- -------------- 
				ID           NOT NULL NUMBER(11)     
				APPNAME               VARCHAR2(50)   
				APPVERSION            VARCHAR2(50)   
				EVENTDATE             VARCHAR2(50)   
				EVENTTYPE             NUMBER(4)      
				TRANSFORM             VARCHAR2(50)   
				EVENTMESSAGE          VARCHAR2(4000)
 
		-->
	</itf>
 
	<itf name="ITF 2" version="1.5" disabled="false">
		<item name="Interval" value="1"/>
		<item name="XML Path" value="C:\archivos de programa\XOne\itf\itf2.xml"/>
		<item name="MaxCacheValues" value="1000"/>
		<item name="MID" value="777"/>
	</itf>
	<!--
	...
	<itf>
	...
	</itf>
	...
	-->	
</xml>


Puedes consultar las diferentes configuraciones de CRON, para programar la fecha y hora a la que se desean realizar las distintas tareas: Aquí.


Fichero de configuración donde se va a realizar la integración propiamente dicha entre el sistema origen, el sistema del cliente, y el sistema XOne.


El funcionamiento básico de la interface es el siguiente:

  1. En cada cada transform hay un nodo coll con un atributo source-table y dest-table, que nos indicarán la tabla o vista de origen de los datos y la tabla de destino de los mismos.
  2. Hay un atributo “SQL” que nos define la consulta que vamos a lanzar sobre el origen que nos va a delimitar los datos que vamos a intentar traspasar a la tabla destino. (Es conveniente limitar esta consulta para que si hay muchos registros, estos se traspasen en grupos de por ejemplo 1000 registros, añadiendo la cláusula LIMIT, TOP, ROWNUM ó la que corresponda al DBMS que estemos utilizando)
  3. En los campos que vamos a traspasar, debemos poner un atributo key=“true” en aquellos campos que nos vayan a definir un registro como único, que bien pudiera ser un campo que ya tengamos como clave única o puede ser la combinación de varios campos que finalmente la conjunción de estos, hacen que el registro pueda localizarse de forma unívoca. Junto con el atributo key=“true” en los diferentes campos, hay un atributo a nivel de COLL que permite a la maquinaria ir quedándose con las claves de los registros que entran dentro de la transformación. Este atributo es: saved-source=“true” y saved-dest=“true” para quedarnos con las claves de los registros del origen y del destino respectivamente. Estos dos atributos rellenan de valor a las macros ##SOURCEKEYVALUES## y ##DESTKEYVALUES##.
  4. Una vez tenemos el campo o campos clave (Los que tienen el atributo key=“true” definido), la interface mira en el destino para ver si ya existe un registro con dichos valores, en caso de no existir se hace un INSERT, y si estos valores existieran ya en el destino, se realiza un UPDATE de aquellos campos que cambien de valor en la transformación.
  5. Finalmente, por regla general, querremos marcar en el origen los registros que hemos procesado, poniéndolos con alguna marca para saber que dichos registros ya los tenemos “sincronizados” en el destino. Para ello se hace uso de un nodo “after action” en el cual pondremos el UPDATE sobre el origen de datos para poner dichos registros “marcados” como procesados.


Nodos
<?xml versión >=“1.0” encoding=“ISO-8859-1”?> Nodo que se pone en la parte superior del fichero. Sirve para que se pueda utilizar la codificación ISO-8859-1, y admita, entre otras cosas, los acentos. OPTATIVO.
<xml> Nodo principal, es el padre de todos los nodos, y todo fichero tiene que tener este nodo, en el que irá todo lo demás. OBLIGATORIO.
<interface> Nodo hijo del nodo xml, dentro de este irán el resto de opciones. OBLIGATORIO.


APP

Nodo en el que se define quienes son las bases de datos origen y destino para poder realizar la Interfase. OBLIGATORIO. Dicho nodo, tiene varios atributos, que son:

Atributos Descripción
NAME “INTERFASE”: nombre de la aplicación
LOGOPER “true”: para activar el LOG, mostrando todo lo que hace el CGInterclientXone, en el Visor de Sucesos de Windows
SQLFIELDNAME la aplicación cuando pasa los datos desde una base de datos hacia otra, también escribe en la cola de réplica. Dicha tabla, tiene un campo SQL, que en el que se introducen los SQL de la réplica. Bien, pues ese nombre de ese campo es palabra reservada en algunos sistemas de base de datos, como el MYSQL 5.0. Lo que hay que hacer es crear la cola de réplica, y cambiar el nombre SQL por otro cualquiera, y posteriormente se pone este nombre en dicho atributo, para que el programa sepa el cambio que hay.
TBL-QUEUE si queremos rellenar o no el valor del campo TBL en la tabla master_replica_queue. Tomará valores true o false
SLASH atributo que le podemos decir que no se duplique el carácter “\”. El programa lo duplica automáticamente, pero hay algunos sistemas de base de datos, que no hace falta duplicarlo, poniendo a false dicho atributo. Lo de duplicar es porque hay en sistemas, que ese atributo es una palabra reservada, y para decirle que no queremos que haga nada, pues lo duplicamos, posteriormente el sistema quita el duplicado.
ROWIDFIELDNAME Atributo para cambiar el valor del campo obligatorio ROWID. Esto se suele utilizar cuando la base de datos de replica es en ORACLE, ya que la palabra ROWID es reservada para dicho sistema. Solo para la base de datos del Servidor
ROWIDFIELDNAMEDEST Atributo para cambiar el valor del campo obligatorio ROWID. Esto se suele utilizar cuando la base de datos de rÉplica es en ORACLE, ya que la palabra ROWID es reservada para dicho sistema. Solo para la base de datos de los Dispositivos.
ORACLE-SESSION modificar la sesión de oracle en la que entre otras opciones podemos cambiar el formato de fecha con el que queramos trabajar en la ITF, se ejecuta sobre cada conexión provider OracleClient, por defecto ALTER SESSION SET NLS_DATE_FORMAT='DD/MM/YYYY HH24:MI:SS'


Connection

Nodo en el que están las llamadas a las base de datos con las que interactúa la interface. Está formado por nodos hijos, con las llamadas a las base de datos.

Nodos Descripción
client Nodo que tiene la llamada a la base de datos origen, la base de datos a movilidad, que siempre será la base de datos del cliente
source Nodo que tiene la llamada a la base de datos destino, la base de datos de XOne
optional Es una conexión con una base de datos opcional (auxiliar) pudiendo ser la misma que la que existe en los nodos client o source, o puede tratarse de una conexión diferente. Se pueden poner todos los nodos optional que hagan falta, no se limita a 1. Se llaman haciendo referencia a su name (se explica posteriormente en DATA-SOURCE, DATA-DEST)



Provider Connstring
MYSQL connstring=“Persist Security Info=False;database=salesdemo;server=IPSERVIDORBD;user id=user;Password=pass”
SQLSERVER connstring=“Data Source=IPSERVIDORBD;Initial Catalog=beltranprod;Persist Security Info=True;User ID=user;Password=pass”
ORACLE connstring=“Data Source=CGS;Persist Security Info=True;User ID=user;Password=pass;Unicode=True”
ODBC DSN=nombredsnsistema;uid=usuario;pwd=clave
OLeDB provider=ej.[SQLOLEDB.1,MSDAORA…];data source=DATASOURCE;user id=USER;password=PWD..



Código de ejemplo del nodo APP. Están especificadas cada una de las conexiones que se pueden identificar.

<app name="ITF_PRUEBA" logoper="false" rowidfieldname="CGSROWID"  sqlfieldname="SQL" oracle-session="ALTER SESSION SET NLS_DATE_FORMAT='DD/MM/YYYY HH24:MI:SS'">
   <!--
     logoper - deja log de todas las operaciones que realiza la interface, por defecto es false
     rowidfieldname - nombre del campo ROWID, por defecto es ROWID pudiendo cambiarse para gestores como ORACLE
     rowidfieldnamedest - nombre que va a tomar el campo ROWID en el SQL del Queue, pudiendo ser diferente al rowidfieldname, por defecto es ROWID
     tbl-queue - si queremos rellenar o no el valor del campo TBL. Por defecto **true**
     sqlfieldname - nombre del campo en el que vamos a introducir el insert, update o delete ejecutados en el queue, siendo por defecto SQL
     oracle-session - modificar la sesión de oracle en la que entre otras opciones podemos cambiar el formato de fecha con el que queramos trabajar en la ITF, se ejecuta sobre cada conexión provider OracleClient, por defecto ALTER SESSION SET NLS_DATE_FORMAT='DD/MM/YYYY HH24:MI:SS'
   -->
   <connection>
	<!--
	provider: especificamos el provider de la conexión, interpretando SqlClient, OracleClient, MySQLClient, SQLServerCE, 
	OleDB y ODBC. Por defecto es ODBC.
	connstring: cadena de conexión de la base de datos
        -->
	<client name="NOMBRE1" provider="System.Data.PROVIDER" connstring="Data Source=ORACLESRC;Persist Security Info=False;User ID=CGSOFT;password=CGSOFT;Unicode=True"/>
	<source name="NOMBRE2" provider="System.Data.PROVIDER" connstring="Data Source=CGSOFTBD;Persist Security Info=False;User ID=CGSOFT_ITF;password=CGSOFT_ITF;Unicode=True"/>
	<optional name="NOMBRE3" provider="System.Data.PROVIDER" connstring="......."/>
	<!--
	Se pueden definir todas las conexiones optinal que se deseen (conexion auxiliar), se llaman seleccionando 
	su "name" en data-source o data-dest dependiento de si se usan como source o dest en la transformación, 
	dentro del nodo coll
	-->
	<!-- Conexiones de ejemplo 
	**ODBC**:  dsn=nombredsnsistema;uid=usuario;pwd=clave
	**OleDB**: provider=ej.[SQLOLEDB.1,MSDAORA...];data source=DATASOURCE;user id=USER;password=PWD..
	**System.Data.SqlClient**: User ID=USER;Password=PWD;Initial Catalog=BD;Data Source=DATASOURCE...
	**MySql.Data.MySqlClient**:Database=[NOMBRE BD];Data Source=[SERVIDOR{localhost...}];User Id=[USER];Password=[PASSWORD]
	**System.Data.OracleClient**: Data Source=[datasource{tns service name}];Persist Security Info=False;User ID=[user];Password=[password];Unicode=True 
	-->
    </connection>
</app>




TRANSFORMS

Nodo que define la dirección de envio de los datos, decidiendo que conexión es el origen y cual el destino, pudiendo variar entre client-to-source o source-to-client

TIPO DE DIRECCIÓN DESCRIPCION
client-to-source Definición de la tabla origen la conexion del nodo client y como destino la conexion source. Esta conexión es la que se utiliza para replicar la información a los dispositivos, ya que inserta las sentencias SQL en la tabla master_replica_queue.
source-to-client Definición de la tabla origen la conexion del nodo source y como destino la conexion client. Con esta opción no se escribe nada en ninguan tabla adicional, solo en la que se definen a que tabla van los datos de destino.





Una vez que se ha decidido en que orden se traspasan los datos, se empiezan a definir cada unos de los nodos transform, que son los que realizan el traspaso de datos de una tabla a otra.

TRANSFORM

Nodo que define el paso de datos a realizar. Cada transform es para una o varias tablas que sean dependientes unas de otras, y solo tiene un atributo, name, el cual debe ser único para todo el fichero xml de configuración del interface. Si existe algún error, el log mostrará el nombre de la transforma donde está y donde ha dado el posible error.

Es importante resaltar que si existe un fallo al ejecutar el transform activo, saltará al siguiente nodo transform, de forma que las tablas dependientes unas de otras, tienen que ir en el mismo nodo transform de forma consecutiva. Por lo tanto, las tablas no dependientes, o en las que sí se produce un error en la anterior se pueda continuar con ella, deben ir en diferentes nodo transform.



Transformación con solo un nodo coll, de tal forma que la tabla no depende de otras tablas.

<transform name="tabla_sin_dependencias">
       <coll dest-table="GEN_DETTARIFA" source-table="
	SELECT a.*,trim(a.TARIFA) || replace(a.SECUENCIA,' ','-') AS CODSEC,b.ID
	FROM TARIFAS a,CARGA_PARCIAL b,ARTICULOS a2
	WHERE b.ARTICULO=a2.ARTICULO AND a.ARTICULO=b.ARTICULO AND a.TARIFA=b.TARIFA AND a.SECUENCIA=b.SECUENCIA
	AND b.TABLA='TARIFAS' AND b.ESTADO='B'">
	<prop source-name="ID" dest-name="IDTARIFA" key="true" saved-source="true" type="N" saved-dest="false">
		</prop>
	<prop source-name="CODSEC" dest-name="IDTARIFA" key="true" type="N" saved-dest="true">
	    <oper type="mapval" source="gen_tarifas" targetfld="ID">
		<prop mapfld="CODSEC" mapvalue="##SELF##"/>
    	    </oper>
	</prop>
	<prop source-name="SECUENCIA" dest-name="SECUENCIA" key="true" type="T" saved-dest="true">
		<oper type="copy"/>
	</prop>
	<delete>
	        <action name="delete-conditional" delete-dest-table="gen_DetTarifa" use-saved-dest="true"/>
	</delete>		
	<after-action>
		<action name="execute-query">
			<param name="source" value="delete from carga_parcial	WHERE ##SOURCEKEYVALUES##"/>
		</action>
	</after-action>
	</coll>
</transform>


Transform con dos nodos coll, que se han insertado en el mismo transform, porque son tablas dependientes una de la otra, y si no pasan los datos de la primera, no deben insertarse la segunda.

<transform name="gen_dettarifacgs_cparcial"> 
	<coll dest-table="GEN_DETTARIFA" source-table="
	SELECT a.*,trim(a.TARIFA) || replace(a.SECUENCIA,' ','-') AS CODSEC
	FROM TARIFAS_CGS a,ARTICULOS_CGS a2
	WHERE a.ARTICULO=a2.ARTICULO AND a.CG_ESTADO IN(7)">
	<prop source-name="ID" dest-name="IDTARIFA" key="true" saved-source="true" type="N" saved-dest="false">
		</prop>
	<prop source-name="CODSEC" dest-name="IDTARIFA" key="true" type="N">
		<oper type="mapval" source="gen_tarifas" targetfld="ID">
			<prop mapfld="CODSEC" mapvalue="##SELF##"/>
		</oper>
	</prop>
	<prop dest-name="UTARREM" type="N">
			<oper type="setval" value="9"/>
	</prop>
	<prop source-name="U_TAR_REM" dest-name="UTARREM" type="N">
			<oper type="copy"/>
	</prop>
	<after-action>
		<action name="execute-query">
			<param name="source" value="UPDATE TARIFAS_CGS SET CG_ESTADO=5 WHERE ##SOURCEKEYVALUES##"/>
		</action>
	</after-action>
	</coll>
	<coll dest-table="GEN_DETTARIFA" source-table="
	SELECT a.*,trim(a.TARIFA) || replace(a.SECUENCIA,' ','-') AS CODSEC,b.ID
	FROM TARIFAS a,CARGA_PARCIAL b,ARTICULOS a2
	WHERE b.ARTICULO=a2.ARTICULO AND a.ARTICULO=b.ARTICULO AND a.TARIFA=b.TARIFA AND a.SECUENCIA=b.SECUENCIA
	AND b.TABLA='TARIFAS' AND b.ESTADO='B'">
	<prop source-name="ID" dest-name="IDTARIFA" key="true" saved-source="true" type="N" saved-dest="false">
	</prop>
	<prop source-name="CODSEC" dest-name="IDTARIFA" key="true" type="N" saved-dest="true">
		<oper type="mapval" source="gen_tarifas" targetfld="ID">
			<prop mapfld="CODSEC" mapvalue="##SELF##"/>
		</oper>
	</prop>
	<prop source-name="SECUENCIA" dest-name="SECUENCIA" key="true" type="T" saved-dest="true">
		<oper type="copy"/>
	</prop>
	<after-action>
		<action name="execute-query">
			<param name="source" value="UPDATE TARIFAS_CGS SET CG_ESTADO=5 WHERE ##SOURCEKEYVALUES##"/>
		</action>
	</after-action>
	</coll>
</transform>




Nodo en el que se toman las tablas origen y destino de los datos a integrar.
Los atributos del nodo son:

ATRIBUTO DESCRIPCION
dest-table Nombre de la tabla destino
source-table Selección a partir de una consulta los datos que sen a a integrar desde el origen en el destino
rows-limit DEPRECATED. Si se quiere limitar el número de registros que se procesan habría que apoyarse en las funciones del DBMS que estemos utilizando (TOP, LIMIT, ROWNUM, etc).
norowid Su valor por defecto es false. Con valor true no rellenaría el campo ROWID de la tabla DEST-TABLE.
type-not-allowed Puede coger valores 1 y 3, de manera que si el valor es 1, no ejecutará inserts y con valor 3 no ejecutará updates.
extrainfo Por defecto true. Con valor false no dejaría registro en la tabla master_replica_queue
data-source Atributo que admite el nombre(name) de cualquier conexión <optional> sobre la que queramos obtener el origen de los datos de la coll, si queremos que sea diferente a la que se configuró por defecto en el nodo client o nodo source en interface/app/connection.
data-dest Atributo que admite el nombre(name) de cualquier conexión <optional> sobre la que queramos obtener el destino de los datos de la coll, si queremos que sea diferente a la que se configuro por defecto en el nodo client o nodo source en interface/app/connection.
always-insert Atributo que si se va a realizar un update por cambio en los datos que se pasan, realmente en la cola de réplica, master_replica_queue, lo pone como un insert.
repeat-until-end Con valor a true (false por defecto) repetirá esa transformación hasta que la query deje de devolver resultados.
continue-on-error Con valor a true (false por defecto) continuará con el resto de transformaciones, aunque la actual esté dando errores.



Dentro del nodo coll, se pondran todos y cada uno de los campos que se tienen que traspasar de una tabla a otra. Para ello se van poniendo distintos nodos prop, que serán los que tendrán el nombre del campo origen y el nombre del campo destino. Posteriormente se pondrán varios atributos definiendo el tipo o que tipo de acción se tiene que realizar.

Nodo en el que se definen que campo se traspasa y que acción se realiza en la tabla de destino.
Los atributos que tiene dicho nodo son:

ATRIBUTO DESCRIPCION
source-name Nombre del campo origen
dest-name Nombre del campo de destino.
type Atributo para decirle el tipo de datos del campo que se va a pasar. Las opciones son: T(campo tipo texto). Nx:(campo númerico. La x significa que se le puede poner el número de decimales que tiene. Variara entre no poner nada, N, o poner el número de decimales que van a pasar, N2, N3, N4, etc.) D:(Campo de tipo fecha.) X:(Para pasar datos que van a ser claves.)
key Para decirle que el campo es clave primaria o no en la tabla destino. Por este campo se realizan las búsquedas de si existe el registro en la tabla destino. La clave por supuesto puede ser múltiple, por lo que puede existir más de un campo que sea la clave primaria del registro. Este campo es obligatorio que como mínimo en uno de los “prop” que tiene la “coll”, tenga este atributo a true.
saved-source Atributo que va a guardar el valor que tiene el campo source-name en una macro, para posteriormente realizar operaciones sobre los campos que cumplen la condición que guarda la macro. La macro es ##SOURCEKEYVALUES##.
saved-dest Atributo que guarda los valores que tiene el campo dest-name en una macro, para posteriormente operar con los registros que cumplen la condición. La macro ##DESTKEYVALUES##.
not-replicate Atributo para indicar que si la operación de este campo se inserta o no en las operaciones de la master_replica_queue. Si es true no se inserta dicho valor, si no existe o es false, se inserta en la operaciones de réplica.
always-update Si el atributo está a true le estamos obligando a que en la cola de réplica, “master_replica_queue”, se le inserte un update aunque su valor no cambie.



Una vez definido que campo es origen y el campo destino, con sus características individuales, se tiene que definir la acción a realizar, la cual estará definida dentro de un nodo oper dentro del nodo prop.

Tipos de operaciones que se pueden realizar con los campos que se quieren pasar de una tabla a otra, en el nodo prop.

Acción SETVAL


En esta operación lo que se hace es poner un valor dado en el campo destino. Por eso, el nodo prop, solo tiene el tipo del campo, type, y el nombre del campo que es el destino, dest-name.

En el ejemplo, se puede ver que en el campo IDPADRE de la tabla destino, que es de tipo numérico, N, se va a guardar el valor 1.

<prop dest-name="IDPADRE" type="N">
	<oper type="setval" value="1"/>
</prop>

En este otro ejemplo ponemos el valor “xone” en el campo destino NOMBRE, que es de tipo texto.

<prop dest-name="NOMBRE" type="T">
	<oper type="setval" value="xone"/>
</prop>

Acción COPY

Operación para copiar el valor de un campo origen a un campo destino.

Ejemplo donde se ve como se va a copiar el valor del campo “delegación” al campo “ETIQUETA”. Dicho campo es de tipo texto. También se puede ver como es clave primaria, por lo que para buscar si existe dicho registro en el destino, lo realizará buscando por el valor de este campo. También se le está diciendo que guarde el valor del origen en la macro ##SOURCEKEYVALUES##, y que guarde el valor del destino en la macro ##DESTKEYVALUES##.

<prop source-name="delegación" dest-name="ETIQUETA" key="true" type="T" saved-source="true" saved-dest="true">
		<oper type="copy"/>
</prop>

Nodo que pasa el valor del campo “PASSWORD_E” al campo PWD. Como vemos tiene el tipo X, por lo que se le está indicando que es un campo contraseña, y su valor lo guarda encriptado. La encriptación es la que soporta la Plataforma XOne, para que posteriormente los usuarios puedan entrar en la aplicación.

<prop source-name="PASSWORD_E" dest-name="PWD" type="X">
           <oper type="copy"/>
</prop>	

Nodo que pasa el valor del campo “DESCPTE” al campo “INCIDENCIA”. El mismo es de tipo texto. También vemos que tiene el atributo “always-update”, por lo que le estamos obligando a que en la cola de réplica, “master_replica_queue”, se le inserte un update aunque su valor no cambie.

<prop source-name="DESCPTE" dest-name="INCIDENCIA" key="false" type="T" always-update="true">
	<oper type="copy"/>
</prop>	

Nodo que pasa el valor del campo “FECCARGA” al campo “FECHA”. El campo es de tipo fecha. También se puede ver un nodo nuevo, format, nodo que se utiliza dentro de los nodos prop, y que sirve para formatear el valor en el destino con las características que se le diga en el atributo value. En el ejemplo, al ponerlo, le estamos diciendo que en el destino la fecha se tiene que insertar de modo día/mes/año.

<prop source-name="FECCARGA" dest-name="FECHA" type="D">				
  <oper type="copy"/>
  <format name="dest-name" value="dd/mm/yyyy"/>
</prop>	

Nodo que pasa los datos del campo “CODAVISO” al campo “TIPOPARTE”, y vemos que es de tipo texto. También se puede ver que está el nodo format. Aquí se puede ver que tiene un atributo nuevo, trim. Dicho atributo lo que hace es eliminar o no los espacios en blanco que llegan del origen en el destino. El atributo si no se define esta a “true”, es decir, elimina los espacios en blanco. Para que funcione, es necesario poner en el atributo “value”, el valor “NULL”.

<prop source-name="CODAVISO" dest-name="TIPOPARTE" type="T">
	<oper type="copy"/>
	<format value="NULL" trim="false"/>
</prop>	

Nodo que pasa los datos del campo “PRETAR” al campo “PRECIO”. Es de tipo numérico, y en concreto con 5 decimales. Para que la copia se haga bien, se le ha puesto el nodo format, poniendo exactamente el número de decimales que se le va a poner.

<prop source-name="PRETAR" dest-name="PRECIO" type="N5">
	<oper type="copy"/>
	<format name="dest-name" value="0.00000"/>
</prop>

Acción MAPVAL

Operación para pasar datos de campos relacionados con valores que hay en otras tablas. Lo que sería en el mappings campos de tipo IDEMPRESA o IDUSUARIO. Para ello, lo que se hace es coger el valor del campo origen, y buscarlo en una tabla, cuando encuentra el valor, pone el valor de un campo que le decimos de esa tabla en el campo destino del principio.

En el ejemplo que se ve, se coge el valor del campo “delegacion”, y se compara con el campo “ETIQUETA”, que se pone en el atributo mapfld, que existe en la tabla “Gen_Empresa”, definido en el atributo source. Si existe un registro que tenga ese valor, que solo tiene que existir uno, ya que el campo por el que se realiza la búsqueda en la tabla “Gen_Empresa”, tiene que ser la clave primaria del mismo, coge el valor del campo que se define en el atributo targetfld, “ID” para este caso, y lo pone en el campo dest-name, campo “IDEMPRESA”.

En SQL: IDEMPRESA=SELECT ID FROM Gen_Empresa WHERE ETIQUETA=delegacion

<prop source-name="delegacion" dest-name="IDEMPRESA" type=”N”>
	<oper type="mapval" source="Gen_Empresa" targetfld="ID">
		<prop mapfld="ETIQUETA" mapvalue="##SELF##"/>
	</oper>
</prop>	

En este caso se pueden utilizar varios prop dentro de el mismo oper, que es para aquellos casos en los que la clave primera del registro que estamos buscando está definido por varios campos, en este caso “COMPANY_ID” y “CAMPO2”. Ejemplo:

<oper type="mapval" source="gen_usuarios" targetfld="ID" history="true">
     <prop mapfld="COMPANY_ID" mapvalue="##SELF##"/>
     <prop mapfld="CAMPO2" mapvalue="##FLD_PROPIEDAD##"/>
</oper>  
<!-- El atributo history es para que procese el registro asociado por si no lo tuviesemos previamente, mete una operación de cambio en el campo de enlace -->

Acción MAIL

Si queremos que se envie un determinado correo electrónico con campos rescatados en la query de la coll, utilizaremos el oper type=“mail”.

Por otro lado, en el atributo mailfield, les especificaremos que tipo de valor se le va a pasar, pudiendo tomar los valores: To, Subject, Message y File.

En último término, está el atributo value, que es el que le pasa el valor escogido en el SQL.

La interface intentará enviar un correo siempre y cuando esté definido el oper con valor To.

<prop source-name="DESTINO" type="T">
	<oper type="mail" mailfield="To" value="##SELF##"/>
</prop>
<prop source-name="ASUNTO" type="T">
	<oper type="mail" mailfield="Subject" value="##SELF##"/>
</prop>
<prop source-name="MENSAJE" type="T">
	<oper type="mail" mailfield="Message" value="##SELF##"/>
</prop>
<prop source-name="FICHERO" type="T">
	<oper type="mail" mailfield="File" value="##SELF##"/>
</prop>

Nodo que se ejecuta al terminar de realizar el traspaso de datos desde una tabla a otra.

Acción EXECUTE-QUERY

Ejecuta un SQL. Esto es bastante útil para poner una campo de la tabla origen con un valor, para indicar que ya se ha pasado ese valor a la tabla destino.

En el ejemplo dado, vemos que tiene dos nodos param, en lo que se le dice que SQL se va a ejecutar, en el atributo value. También en que base de datos, el atributo name, se le pone “dest”, que es la base de datos destino, y “source”, que es la base de datos origen.

También se puede ver que utiliza las macros ##SOURCEKEYVALUES## y ##DESTKEYVALUES##, que han sido rellenadas mientras se traspasan los datos de una base de datos hacia otra.

<action name="execute-query">
<param name="source" value="Update Gen_DetDocumento SET ACTUALIZADO=1 WHERE ##SOURCEKEYVALUES##"/>
<param name="dest" value="UPDATE Gen_Documentos  SET ACTUALIZADO=1  WHERE ID IN (SELECT IDDOCUMENTO FROM GEN_DETDOCUMENTO WHERE ##DESTKEYVALUES##)"/>	
</action>
 
<!-- Este action ejecuta un fichero .bat tras la ejecución del transform -->
<action name="execute-file" value="C:\system\XOneProduccion\ProcesoCarga.bat"/>

Nodo que se ejecuta antes de empezar el traspaso de datos. Se pueden utilizar todas las operaciones que existen en el nodo after-action

Nodo para realizar un borrado de los datos que se le dicen. Puede borrar tanto del origen como del destino.

En los ejemplos que vemos abajo, solo vemos el nodo “delete”, pero hay que tener en cuenta que se tiene que hacer un nodo “coll” como si fuéramos a pasar datos de una tabla a otra, por lo que tiene que tener como mínimo un nodo “prop” que tenga el atributo “key” igual a “true”.


Hay varios tipos de operaciones “delete” que se pueden realizar, que son:

Acciones del Nodo DELETE DESCRIPCION
delete-conditional Este es para realizar el borrado de los datos que coinciden con los datos que se buscan en el origen, a partir del campo o campos que coinciden con la clave primaria que hemos definido.
delete-sql Esta operación sirve para realizar el borrado tanto en el cliente, como en la base de datos de Xone, para que además de borrar de la tabla normal, inserta el borrado en la cola de réplica.
delete-fichero Operación que sirve para realizar el borrado de un fichero.

DELETE-CONDITIONAL


Éste es para realizar el borrado de los datos que coinciden con los datos que se buscan en el origen, a partir del campo o campos que coinciden con la clave primaria que hemos definido.

Ejemplo de uso

<delete>
	/* En el ejemplo se realiza el borrado en la tabla “gen_sat” y "gen_usuarios, de la base de datos de destino, 
	   por utilizar el atributo “delete-dest-table”, de aquellos datos que coinciden con la macro ##DESTKEYVALUES##. */
 
	<action name="delete-conditional" delete-dest-table="gen_sat" use-saved-dest="true"/>
	<action name="delete-conditional" delete-dest-table="gen_usuarios" use-saved-dest="true"/>
 
 
	/* Con este ejemplo se realiza el borrado en la base de datos origen. 
	   Para indicar una tabla de origen se utiliza el atributo “delete-source-table”, 
	   con este atributo se utiliza la macro ##SOURCEKEYVALUES##. */
 
	<action name="delete-conditional" delete-source-table="EVUSUA" use-saved-source="true"/>
</delete>

DELETE-SQL


Esta operación sirve para realizar el borrado tanto en el cliente, como en la base de datos de XOne, para que además de borrar de la tabla normal, inserta el borrado en la cola de réplica.

Atributos
where Es la condición de borrado. Se pueden utilizar las macros ##SOURCEKEYVALUES## y ##DESTKEYVALUES##.
delete-dest-table Atributo para indicar en qué tabla se quiere realizar el borrado. Si no se pone dicho atributo, se coge el valor que hay en el atributo del nodo “coll”, “dest”. Realiza el borrado de los registros que tienen el ROWID que cumplen la condición que se pone en el atributo “where”.
select-dest-table Atributo para realizar la búsqueda de los registros que se quieren borrar. Puede ser cualquier tabla, pero hay que tener en cuenta, que se realiza la búsqueda de valores en dicha tabla, cogiendo el ROWID de los registros que cumplen el atributo “where”, y de esos ROWID se realiza el borrado. Si no se pone nada, se coge el valor que hay en el atributo del nodo “coll”, “dest”.
alias-dest-table Alias de la tabla de la que se realiza la búsqueda, y posteriormente el borrado.
source-table Para decir de que tabla origen queremos realizar el borrado.
delete-source Si se declara dicho atributo, y además está declarado el atributo “source-table”, realiza el borrado en tabla origen también, con la condición que se pone en el atributo “where”.



Ejemplo de uso:

<delete>
	/* 1.- Se realiza la búsqueda de en la base de datos de destino, en la tabla “gen_colla”(select-dest-table) de los ROWID 
	   que cumplen la condición del “where”(where), con el alias “c”(alias-dest-table). 
 
	   SELECT c.ROWID FROM Gen_Colla WHERE ESTADO=1
 
	   2.- Si hay valores con esa condición, los borra de la tabla “gen_colla”( delete-dest-table).
	   3.- Si se encontró algún registro con el punto 1, existe el atributo delete-source=”true”, el atributo “source-table” 
	       con un nombre de tabla y hay una condición, se realiza el borrado en la tabla “Gen_USUARIOS”( source-table), con la condición
 	       que hay en el atributo “where”. */
 
	<action name="delete-sql" source-table="Gen_USUARIOS" delete-source="true" where="ESTADO=1" delete-dest-table="Gen_Colla" 
	 select-dest-table="Gen_Colla" alias-dest-table="c"/>
</delete>			

DELETE-FICHERO

Operación que sirve para realizar el borrado de un fichero.

Ejemplo de uso:

<delete>
	/* Realiza el borrado del fichero que existe en el atributo “PATH”, con lugar y nombre del mismo. */
 
	<action name="delete-fichero" path="C:\Archivos de programa\CGSoft\CGInterclient\Captura\Ficheros\ESPPDA.TXT"/>
</delete>


Para control de cambios.

Para ello se pondrá dentro el nodo client, con type=“##LASTMODIFIED##“, en la que introducirá al terminar la transformación, en la tabla interclient_sync_tables, los valores definidos en el data-condition donde ##LASTMODIFIEDDATETIME## es la fecha y hora al comenzar la transformación.

<data-condition>
	<client type="##LASTMODIFIED##">
		<param name="FECHA" value="##LASTMODIFIEDDATETIME##">
			<format value="MM-dd-yyyy"/>
		</param>
		<param name="HORAINI" value="##LASTMODIFIEDDATETIME##">
			<format value="HH:mm:ss"/>
		</param>
		<param name="HORAFIN" value="##NOW##">
			<format value="HH:mm:ss"/>
		</param>
	</client>
</data-condition>

Dentro del nodo client, se pondrá el nodo param, que tiene los atributos:

Atributos nodo PARAM
name campo destino de interclient_sync_tables.
value valor que va a tomar el campo.



Se pueden utilizar macros como valores auxiliares, tanto a nivel de source-table dentro del nodo coll, como para efectuar un action.

Dentro del atributo source-table, a nivel de coll.

<coll name="COLL_PASAR" source-table="SELECT t.* FROM Tabla1 t WHERE t.CAMPO='Valor1' and t.FECHA>='##MACRO##'" ...

Aquí se muestra el nodo macro, que estará dentro del nodo coll.

<macro name="##MACRO##" source-table="XONEPIMAUX" sql="SELECT TIMESTAMP AS X FROM INTERCLIENT_SYNC_TABLES WHERE OBJECTNAME='gen_contactos'" field="X" type="T">
	<format value="yyyy-MM-dd HH:mm:ss"/>
</macro>

Los atributos del nodo macro son:

Atributos Descripción
name Nombre que se va a utilizar para llamar a la macro que creemos.
source-table Conexión sobre la que vamos a llamar a la macro, siendo obligatorio que se trate de una conexión optional.
sql Query para escoger los valores con los que se va a reemplazar la macro. Cogerá en caso de devolverse más de 1 registro, el primer registro devuelto. En caso de devolver más de 1 campo el primer campo obtenido, siempre que no lo especifique el atributo field.
field Campo de la query que vamos a devolver, por defecto será la primera que existe en caso de no estar FIELD.
type Atributo que nos devuelve el tipo de datos, siendo posibles los mismos tipos que existen en los nodos props que se detallarán a continuación.

Es un código de ejemplo de como quedaría un archivo intercliente.xml.

<xml>
	<interface>
		<app name="ITF_PRUEBA" logoper="true" rowidfieldname="CGSROWID"  sqlfieldname="SQL" oracle-session="ALTER SESSION SET NLS_DATE_FORMAT='DD/MM/YYYY HH24:MI:SS'">
			<connection>
				<client name="NOMBRE1" provider="System.Data.PROVIDER" connstring="Data Source=ORACLESRC;Persist Security Info=False;User ID=CGSOFT;password=CGSOFT;Unicode=True"/>
				<source name="NOMBRE2" provider="System.Data.PROVIDER" connstring="Data Source=CGSOFTBD;Persist Security Info=False;User ID=CGSOFT_ITF;password=CGSOFT_ITF;Unicode=True"/>
				<optional name="NOMBRE3" provider="System.Data.PROVIDER" connstring="......."/>				
			</connection>
		</app>
		<transforms type="client-to-source">
			<transform name="gen_usuarios_cp">
				<coll dest-table="GEN_USUARIOS"
				source-table="SELECT a.*, 1 AS IDEMPRESA,trim(TARIFA) || '-' AS CODSEC FROM DELEGADOS_CGS a
				WHERE a.CG_ESTADO IN(7)">
					<prop source-name="DELEGADO" dest-name="LOGIN" key="true" saved-source="true">
						<oper type="copy"/>
					</prop>					
					<prop source-name="NOMBRE" dest-name="NOMBRE" type="T">
						<oper type="copy"/>
					</prop>													
					<prop source-name="CODSEC" dest-name="IDTARIFA" type="T">
						<oper type="mapval" source="gen_tarifas" targetfld="ID">
							<prop mapfld="CODSEC" mapvalue="##SELF##"/>
						</oper>
					</prop> 
					<prop source-name="TARIFA_ESPECIALISTA_SN" dest-name="TARIFA_ESPECIALISTA_SN" type="N">
						<oper type="copy"/>
					</prop> 
					<prop  dest-name="TIPO" type="N">
						<oper type="setval" value="1"/>
					</prop>	
					<after-action>
						<action name="execute-query">
							<param name="source" value="UPDATE DELEGADOS_CGS SET CG_ESTADO=5 WHERE ##SOURCEKEYVALUES##"/>
						</action>
					</after-action>	
				</coll>
			</transform>
			<transform name="gen_dettarifacgs_cparcial"> 
				<coll dest-table="GEN_DETTARIFA" source-table="
				SELECT a.*,trim(a.TARIFA) || replace(a.SECUENCIA,' ','-') AS CODSEC
				FROM TARIFAS_CGS a,ARTICULOS_CGS a2
				WHERE a.ARTICULO=a2.ARTICULO AND a.CG_ESTADO IN(7)">
				<data-condition>
						<client type="##LASTMODIFIED##">
							<param name="FECHA" value="##LASTMODIFIEDDATETIME##">
								<format value="MM-dd-yyyy"/>
							</param>
						 	<param name="HORAINI" value="##LASTMODIFIEDDATETIME##">
							 	<format value="HH:mm:ss"/>
							</param>
							<param name="HORAFIN" value="##NOW##">
							 	<format value="HH:mm:ss"/>
							</param>
						</client>
					</data-condition>
					<prop source-name="ID" dest-name="IDTARIFA" key="true" saved-source="true" type="N" saved-dest="false">
					</prop>
					<prop source-name="CODSEC" dest-name="IDTARIFA" key="true" type="N">
						<oper type="mapval" source="gen_tarifas" targetfld="ID">
							<prop mapfld="CODSEC" mapvalue="##SELF##"/>
						</oper>
					</prop>
					<prop source-name="ARTICULO" dest-name="IDARTICULO" key="true" type="N">
						<oper type="mapval" source="gen_articulos" targetfld="ID">
							<prop mapfld="REFERENCIA1" mapvalue="##SELF##"/>
						</oper>
					</prop>
					<prop source-name="SECUENCIA" dest-name="SECUENCIA" key="true" type="T">
						<oper type="copy"/>
					</prop>			
					<prop source-name="U_MAXIMA" dest-name="CANTMAX" type="N">
						<oper type="copy"/>
					</prop>
					<after-action>
						<action name="execute-query">
							<param name="source" value="UPDATE TARIFAS_CGS SET CG_ESTADO=5 WHERE ##SOURCEKEYVALUES##"/>
						</action>
					</after-action>
				</coll>
			</transform>
			<transform name="gen_dettarifacgs_cparcial"> 
				<coll dest-table="GEN_DETTARIFA" source-table="
				SELECT a.*,trim(a.TARIFA) || replace(a.SECUENCIA,' ','-') AS CODSEC
				FROM TARIFAS_CGS a,ARTICULOS_CGS a2
				WHERE a.ARTICULO=a2.ARTICULO AND a.CG_ESTADO IN(7)">
				<prop source-name="ID" dest-name="IDTARIFA" key="true" saved-source="true" type="N" saved-dest="false">
					</prop>
				<prop source-name="CODSEC" dest-name="IDTARIFA" key="true" type="N">
					<oper type="mapval" source="gen_tarifas" targetfld="ID">
						<prop mapfld="CODSEC" mapvalue="##SELF##"/>
					</oper>
				</prop>
				<prop dest-name="UTARREM" type="N">
						<oper type="setval" value="9"/>
				</prop>
				<prop source-name="U_TAR_REM" dest-name="UTARREM" type="N">
						<oper type="copy"/>
				</prop>
				<after-action>
					<action name="execute-query">
						<param name="source" value="UPDATE TARIFAS_CGS SET CG_ESTADO=5 WHERE ##SOURCEKEYVALUES##"/>
					</action>
				</after-action>
				</coll>
				<coll dest-table="GEN_DETTARIFA" source-table="
				SELECT a.*,trim(a.TARIFA) || replace(a.SECUENCIA,' ','-') AS CODSEC,b.ID
				FROM TARIFAS a,CARGA_PARCIAL b,ARTICULOS a2
				WHERE b.ARTICULO=a2.ARTICULO AND a.ARTICULO=b.ARTICULO AND a.TARIFA=b.TARIFA AND a.SECUENCIA=b.SECUENCIA
				AND b.TABLA='TARIFAS' AND b.ESTADO='B'">
				<prop source-name="ID" dest-name="IDTARIFA" key="true" saved-source="true" type="N" saved-dest="false">
				</prop>
				<prop source-name="CODSEC" dest-name="IDTARIFA" key="true" type="N" saved-dest="true">
					<oper type="mapval" source="gen_tarifas" targetfld="ID">
						<prop mapfld="CODSEC" mapvalue="##SELF##"/>
					</oper>
				</prop>
				<prop source-name="SECUENCIA" dest-name="SECUENCIA" key="true" type="T" saved-dest="true">
					<oper type="copy"/>
				</prop>
				<after-action>
					<action name="execute-query">
						<param name="source" value="UPDATE TARIFAS_CGS SET CG_ESTADO=5 WHERE ##SOURCEKEYVALUES##"/>
					</action>
				</after-action>
				</coll>
			</transform>
		</transforms>
		<transforms type="source-to-client">
			<transform name="clientes_ent_cgs">
				<coll dest-table="CLIENTES_ENT_CGS" 
				source-table="SELECT c.*,
				SUBSTR(c.CP,1,5) AS CP,SYSDATE AS MAP_FMODIF,
				SUBSTR(replace(replace(c.CUENTABANC,'-',''),' ',''),1,20) AS MAP_CUENTABANC,u.LOGIN AS DELEGADO,t.CODIGO AS TARIFA,g.CODIGO AS GRUPO_COMPRAS,p.CODIGO AS POTENCIAL_MERCADO,
				NVL(c.FORMAPAGO,'_') AS MAP_FORMAPAGO
				FROM ((((Gen_Clientes_Mod c
				LEFT OUTER JOIN Gen_Usuarios u ON c.IDUSUARIO=u.ID)
				LEFT OUTER JOIN Gen_Tarifas t ON c.IDTARIFA=t.ID)
				LEFT OUTER JOIN Gen_GruposCompra g ON c.IDGRUPOCOMPRA=g.ID)
				LEFT OUTER JOIN Gen_PotencialMercado p ON c.IDPOTMERCADO=p.ID)
				WHERE (c.MODIFICADO=1 or c.MODIFICADO=3) AND u.LOGIN IS NOT NULL AND c.EXPEDIENTE IS NOT NULL AND c.EXPEDIENTE&lt;&gt;''
				">
					<prop source-name="EXPEDIENTE" dest-name="CLIENTE" type="N" key="true">
						<oper type="copy"/>
					</prop>
					<prop source-name="DELEGADO" dest-name="DELEGADO" key="true" type="T">
						<oper type="copy"/>
					</prop>		
					<prop source-name="TIPO" dest-name="TIPO_CLIENTE" type="N">
						<oper type="copy"/>
					</prop>					
					<prop source-name="ACCIONISTA" dest-name="ACCIONISTA" type="N">
						<oper type="copy"/>
					</prop>
					<prop source-name="MAP_FMODIF" dest-name="F_MODIF" key="true" type="T">
						<oper type="copy"/>
						<format name="dest-name" value="dd/MM/yyyy HH:mm:ss"/>   
					</prop>																																												
				</coll>
			</transform>
		</transforms>		
	</interface>
</xml>