Ejecutar Funciones Personalizadas en Workflows de Vtiger

Buen día, espero que se encuentren bien todos los lectores de este blog.

En base a un comentario dentro unos de mis post, me atreví a escribir este relacionado con el uso las funciones personalizadas para ejecución en un Workflow dentro los módulos de Vtiger.

Paso a comentar el código para el registro de dichas funciones y que sean accesibles en la configuración de las tareas de los Workflows.

Primeramente, comentar que realice un pequeño script que me ayuda a registrar gráficamente las funciones

<?php
	include_once('config.php');
	require_once  ('include/CustomFieldUtil.php');
	require_once 'include/utils/utils.php';
	require 'modules/com_vtiger_workflow/VTEntityMethodManager.inc';

        // Lista de Modulos permitidos para agregar Funciones Personalizadas
	$modulesAllowed = array('SalesOrder', 'Invoice', 'Quotes', 'Documents', 'Calendar', 'Contacts', 'Accounts');

        // Directorio por default para los Scripts que contienen funciones personalizadas
	$customFunctionDir = 'include/WorkFlowFunctions/';

	function setCustomFunction($aFunction){
	 	global $adb;
	 	global $customFunctionDir;
		$emm = new VTEntityMethodManager($adb);

		// parametros (Modulo, Nombre de funcion para vtiger, ruta del archivo, nombre de funcion en Script)
		$emm->addEntityMethod($aFunction['Module'], $aFunction['FunctionName'], $customFunctionDir.$aFunction['scriptPath'], $aFunction['FunctionName']);
		return true;
	}

	function validateModule($module){
		global $modulesAllowed;
		if(($module != '') && (in_array($module, $modulesAllowed))) {
			return true;
		}
		return false;
	}

	function validateScript($scriptPath) {
		global $customFunctionDir;
		$filepath = $customFunctionDir.$scriptPath;
		if(is_file($filepath)){
			include($filepath);

			return true;
		}
		return false;
	}

	function validateFunctionName($scriptPath, $function, $validateFnName=true) {
		if(validateScript($scriptPath)){
			if($validateFnName == true && !function_exists($function) ) {
				return false;
			}
			return true;
		}
		return false;
	}

?>
<html>
<head>
<style type="text/css">
		body{
			font-family: "Lucida Grande", "Lucida Sans Unicode", Verdana, Arial, Helvetica, sans-serif;
			font-size:12px;
		}
		p, h1, form, button{border:0; margin:0; padding:0;}
		.spacer{clear:both; height:1px;}
		/* My Form */
		.myform{
			margin:0 auto;
			width:400px;
			padding:14px;
		}

		/* Stylized */
		#stylized{
			border:solid 2px #b7ddf2;
			background:#ebf4fb;
		}
		#stylized h1 {
			font-size:14px;
			font-weight:bold;
			margin-bottom:8px;
		}
		#stylized p{
			font-size:11px;
			color:#666666;
			margin-bottom:20px;
			border-bottom:solid 1px #b7ddf2;
			padding-bottom:10px;
		}
		#stylized label{
			display:block;
			font-weight:bold;
			text-align:right;
			width:140px;
			float:left;
		}
		#stylized .small{
			color:#666666;
			display:block;
			font-size:11px;
			font-weight:normal;
			text-align:right;
			width:140px;
		}
		#stylized input, #stylized select{
			float:left;
			font-size:12px;
			padding:4px 2px;
			border:solid 1px #aacfe4;
			width:200px;
			margin:2px 0 20px 10px;
		}
		#stylized button{
			clear:both;
			margin-left:150px;
			width:125px;
			height:31px;
			background:#666666 url(img/button.png) no-repeat;
			text-align:center;
			line-height:31px;
			color:#FFFFFF;
			font-size:11px;
			font-weight:bold;
		}

		fieldset.error{
			border: 3px solid #FF0000;
		}
		fieldset.success{myworkflowsfunctions
			border: 3px solid green;
		}
	</style>
</head>
<body>
	<div id="stylized" class="myform">
		<form id="form" name="RegFunctionForm" method="post" action="RegistrarFuncion.php">
			<h1>Formulario de Registro de función</h1>
			<p>Registrar funciones personalizadas para los workflows de Vtiger</p>

			<label>Module
				<span class="small">Escribe Nombre del Modulo</span>
			</label>
			<select name="Module" id="Module">
				<?php
					foreach($modulesAllowed as $module) {
						echo '<option value="'.$module.'">'.$module.'</option>';
					}
				?>
			</select>
			<!--<input type="text" name="Module" id="Module" />-->

			<label>Function
				<span class="small">Escribe nombre de la funcion</span>
			</label>
			<input type="text" name="FunctionName" id="FunctionName" value="<?php echo (isset($_POST['FunctionName'])) ? $_POST['FunctionName']: '' ;?>" />

			<label>Script Path
				<span class="small">Escribe ruta del Script de la funcion, los script deben estar en: <?php echo "<b>".$customFunctionDir."</b>"; ?></span>
			</label>
			<input type="text" name="scriptPath" id="scriptPath" value="<?php echo (isset($_POST['FunctionName'])) ? $_POST['FunctionName']: '' ;?>" />

			<button type="submit">Registrar</button>
			<div class="spacer"></div>

		</form>
	</div>
	<div class="myform">
	<?php
		if(isset($_POST['Module'])) {
			if(validateModule($_POST['Module'])) {
				$data['Module'] = $_POST['Module'];
				if(validateFunctionName($_POST['scriptPath'], $_POST['FunctionName'], $validafuncion = true)){
					$data['FunctionName'] 	= $_POST['FunctionName'];
					$data['scriptPath'] 	= $_POST['scriptPath'];
					setCustomFunction($data);
					$msg = "Se agrego correctamente la funcion... Ir a <a href='index.php'>CRM</a>";
					$class = "success";
				}else{
					$msg = 'Error al guardar la funcion: Por favor revise que el archivo especifcado y el nombre de la funcion sean correctos.';
					$class = "error";
				}
			}else{
				$msg = 'Error al guardar la funcion: Por favor revise que el el modulo seleccionado este correcto.';
				$class = "error";
			}
		}else{
			$msg = 'Debe seleccionar el modulo.';
			$class = "error";
		}

		echo '<fieldset class="'.$class.'">'.$msg.'</fieldset>';
		echo "<pre>Valores: ".print_r($_POST,true)."</pre>";
	?>
	</div>
</body>
</html>

Este Script lo colocan en la raíz de su instalación de Vtiger, con el nombre que ustedes quieran ponerle. En mi caso le puse nombre «RegistrarFuncion.php», así que entro de la siguiente manera http://localhost/vtigercrm/RegistrarFuncion.php

registrarFuncionVtiger
En la anterior imagen se puede ver el «Formulario de Registro» de funciones.

El siguiente es la estructura de una función personalizada, la cual en mi caso guardare en un script en la siguiente ruta «include/WorkFlowFunctions/myscript.php»:

<?php
	include_once ('config.php');
	require_once ('include/CustomFieldUtil.php');
	//require_once ('include/tequila_utils/utils.php');

	function CustomFunctionNew($entity)
        {
           // en el objeto $entity tenemos toda la información relacionada con el registro que se esta guardando.

           // Esta linea debe de colocarse siempre para registrar en el Vtiger que ha sido llamada la función
		$entity->focus->called = true;

		$id = $entity->getId();
		$module = $entity->getModuleName();

		/*	El id devuelto por $entity->getId() esta en el formato 1xNNNN en donde NNNN es el ID (en este caso 1x es para el modulo de SalesOrder)
		 *	tomamos la parte que esta a al derecha de la "x" y ese es el correspondiente ID de pedido
		 */
		$x = split("x",$entity->getId());

		// A partir de aquí tu puedes colocar el código que se te ocurra para cumplir con tus necesidades
	}

Despues, utilizando el «Formulario de Registro» daremos de alta nuestra función en el sistema, los datos se rellenan como en la siguiente imagen:
ejemplo-registro-funcion-vtiger

En este caso he agregado la funcion para que se pueda usar en el modulo de SalesOrder, pero pueden seleccionar otro modulo en donde usarse.

El paso siguiente es agregar un flujo de trabajo, o bien, editar uno existente, para agregar una tarea que ejecute la función personalizada creada en el paso anterior.

Para esto debemos ir a «Configuración > Workflow > Flujos de Trabajo »
flujo-de-trabajo-vtiger
Debido a que registre mi funcion en el modulo de SalesOrder, voy a crear mi workflow en «Pedidos». Hacer click en «Crear».
Despues, damos un nombre para nuestro WorkFlow y hacemos click en «Guardar».

Una vez guardado el Workflow, lo que sigue es crear la tarea de tipo «Ejecutar Función», por lo que dando click en «Nueva Tarea» veremos una ventana como la siguiente:
flujo-de-trabajo-crear-tarea
Damos click en «Crear» para que se nos muestre un formulario en donde seleccionar la Funcion que queremos sea ejecutada en la Tarea:

editar-tarea-funcion-personalizada
en la imagen anterior vemos el formulario de la tarea, debemos poner un nombre de la tarea, así como seleccionar el «Method Name» que queremos sea ejecutado, en este caso ya puedo seleccionar la función personalizada que registre con anterioridad.
Ahora solo guardamos la tarea y listo!

Mi función «CustomFunctionNew» será ejecutada cada vez que se ejecute mi Workflow.

Espero que esta información sea de utilidad para todos!

Reciban un cordial Saludo!

31 comentarios en “Ejecutar Funciones Personalizadas en Workflows de Vtiger

  1. Hola chavamm, en mi caso tuve que ingresar la funcion de forma manual, ejecutando el siguiente scripts:

    Para contactos:

    ?>
    require_once ‘include/utils/utils.php’;
    require ‘modules/com_vtiger_workflow/VTEntityMethodManager.inc’;
    $emm = new VTEntityMethodManager($adb);
    $emm->addEntityMethod(«Contacts», «myExample Send Me an Email», «modules/Workflow/myExample.inc», «myExample»);
    echo ‘addEntityMethod complete!’;
    ?>

    1. Hola Hugo, no se si copiaste y pegaste el código de «myscript.php», acabo de editar el post, en la linea 4 del codigo para dicho archivo, ya que yo tenia:
      require_once (‘include/tequila_utils/utils.php’);
      pero dicho archivo no es de vtiger, es de mi instalacion solamente, por lo que te marcaria error.

      Al momento de validar la función se hace un include (ver function validateScript($scriptPath) en el primer código), tal vez eso sea el error.

      Saludos!

      1. Hola chavamm si era exactamente esa linea, muchas gracias, es que en mi php esta desactivado la detencion de errores, no los muestra.

      2. Hola Salvador, si exactamente trabajo con Apache, PHP y MySQL, luego te envio los datos para que interactuemos, en este momento estoy terminando de integrar mi proyecto con vtiger, tengo que entregarlo a mas tardar manana por eso ando apurado, tu ayuda me ha servido ni te imaginas cuanto, yo en esa parte estaba superembolatado. Imagina que para enviar datos desde mi proyecto a vtiger yo no sabia que este ya tenia sus propias libreria asi que habia creado una libreia propia con nusoap para que guardara directamente en la base de datos de vtiger. Pero con tu ayuda vi que todo era mas sencillo. Muchas gracias.

  2. Hola Hugo, me da gusto que ya funciono.

    Cualquier cosa no dudes en comentar.

    Aqui seguire posteando de vez en cuando algun que otro tema, por si puedes estar al pendiente.

    Saludos!
    PD vi tu sistema, se ve muy interesante, te envie un mail, ojala lo puedas leer.

    1. Hola chavamm, ya me funciona, pero ocurre que cuando por ejemplo intento insertar un precontacto, efectivamente me ejecuta la funcion que tengo relacionada, pero el vtiger se queda en blanco, sabes por que ocurre?

      1. Hola Hugo, revisando de nueva cuenta el codigo de Registro de Funcion, agregue la linea 15 y modifique la linea 19, falto concatenar el $customFunctionDir con $aFunction[‘scriptPath’].

        Por lo que si usaste el formulario para registrar tu funcion es por esta razon el error.

        A mi tambien me marcaba error despues de hacer unas pruebas.

        Espero que corrigiendo esto ya te funcione perfectamente.

        Saludos!

      2. Hola chavamm, efectivamente ahora si me funciono de super bien, ya ingreso datos in vtiger en un servidor del cliente que esta USA y me crea los registros en mi proyecto en un servidor que esta en madrid espana. Super bien, muchas gracias, ahorita en una horas te envio unos datos de acceso al sistema de pruebas.

  3. Hola chavamm, tengo un inconveniente con la libreria «vtwsclib», cuando la incluyo en mi proyecto, esta hace que mi sistema no cargue, al parecer esa libreria tiene un error o que podra ser?

    1. Hola Hugo, recuerdo haber tenido alguno problemita con la libreria, pero me ocurria cuando el directorio «vtwsclib» no estaba en la raiz de mi proyecto, el problema era en los «include» o «require», el problema se soluciona colocando el directorio en la raiz de mi proyecto, intenta para ver si se te soluciona el error.

      Comentaste anteriormente que tenias deshabilitado en PHP mostrar los mensajes de error, seria una buena idea que lo habilitaras mientras desarrollas para que asi puedas ver mas o menos de que se trata el problema y darnos una mejor idea para poder ayudarte resolver los problemas con mayor rapidez.

      Espero tu respuesta para ver si te sirvio ese tip!

      Recibe un cordial saludo!

      1. Hola chavamm, gracias por tu repuesta, pero me toco mejor ejecutarlo como una funcion externa, de la siguiente forma:

        exec(«php -f crear_registro_en_vtiger.php argumento1 argumento2 argumento3 argumento4 > /dev/null 2>&1 &»);

        de esa forma no afecta el funcionamiento de mi proyecto, y ya en el archivo crear_registro_en_vtiger.php pongo la infomacion a ejecutar, de esta forma me funciona bien.

        doLogin(‘usuario’,’password’);
        if(!$login) echo ‘Login Failed’;
        else
        {
        $module = ‘Leads’;……………..

  4. Hola chavamm, una pregunta, como se hace para actualizar con la libreria vtwsclib, ya se como se inserta, pero deberia existir una funcion como «doUpdate» por ejemplo, pero no la veo en el manual y no dan mayor informacion para actualizar registros.

    Gracias por tu ayuda.

  5. Hola, lo primero, agradecer que hayas compartido esto, muchas gracias.

    Lo segundo es que he intentado usar lo que me hace falta de lo que has compartido, y me he creado un script tal que como este:

    addEntityMethod(‘Products’, ‘Lanzador’, ‘modules/MyWorkflows/Actualizar.php’, ‘actualizar’);
    echo ‘addEntityMethod complete!’;
    ?>

    Y al añadirlo al workflows de productos no he tenido ningún problema, para comprobar si la función se lanza correctamente el único contenido de la misma es:

    function actualizar($entity){
    echo ‘se lanza la actualización’;
    }

    Al introducirla en workflow entiendo que se lanza pero el resultado es que se me queda la hoja en blanco, no printa el mensaje por pantalla, ni nada. Y me surgen dos preguntas:

    – ¿Que estoy haciendo mal?
    – Que tengo que hacer para que al terminar la función, una vez terminada, y sacada por pantalla si se ha producido con exito, o no, retorne a la posición donde estaba del vtiger.

    Muchas gracias por todo.

    1. Hola unaittwo,
      Tal vez deberias colocar la linea que indica a Vtiger que la función ha sido llamada.

      Podrias intentar por favor lo siguiente:

      function actualizar($entity){
      
           // Esta linea debe de colocarse siempre para registrar en el Vtiger que ha sido llamada la función
              $entity->focus->called = true;
      
              echo ‘se lanza la actualización’;
      }
      

      Por favor comentas el resultado.

      Recibe un cordial saludo!

      1. Hola unaittwo,

        Podrías por favor poner aqui todo el codigo de tu archivo: modules/MyWorkflows/Actualizar.php

        Cuando escribas codigo aqui en los comentarios, lo puedes escribir entre el TAG

        [code language=»php»] // Aqui tu codigo [/code]

        Para asi ver que no sea algún caracter raro que este causando error en dicho archivo, si te queda la pantalla en blanco casi es seguro que sea por eso.

        O bien, una causa podría ser también algún permiso al archivo, nombre mal escrito, y tal vez no lo encuentra.

        ¿Tienes activado que te muestre los errores en PHP?
        Ayudaria mas esto, ya que verías que error esta sucediendo.

        Quedo al pendiente.

        Saludos!

  6. El contenido actualmente de Actualizar.php es el siguiente:

    <?php
    include_once (‘config.php’);
    require_once (‘include/CustomFieldUtil.php’);
    require_once (‘include/utils/utils.php’);
    function actualizar($entity){

    $entity->focus->called = true;
    echo ‘entra’;
    }
    ?>

    Los permisos son son 755, como el resto de archivos, lo de los errores, he puesto las lineas:

    ini_set ("display_errors","1" );
    error_reporting(E_ALL);

    Y no me muestra ninguno, no se si porque no funciona, o porque no tiene errores, lo hago así, porque estoy trabajando sobre un servidor online, donde corren otras cosas, e intento evitar tocar cualquier configuración que no me competa.

    Muchas gracias por tan prontas repuestas, así da gusto.

    1. Hola unaittwo,

      ¿Podrias intentar sin incluir archivo alguno?

      Que el contenido de tu archivo Actualizar.php sea unicamente la función siguiente:

      
      <?php
      	//include_once ("config.php");
      	//require_once ("include/CustomFieldUtil.php");
      	//require_once ("include/utils/utils.php");
      
      	function actualizar($entity){
      
      		global $adb;
      
      		$entity_id = $x = split("x",$entity->getId());
      		$entity_id = $entity_id[1];
      		$tiempo = time();
      
      		$adb->pquery("UPDATE vtiger_products SET website='Actualizadodesdescript.".$tiempo."' WHERE productid=?",array($entity_id));
      
      		$entity->focus->called = true;
      	}
      
      
      

      Intentalo y me comentas.

      Saludos!

    1. Hola Carlos,

      la información del registro guardado va en:

          		// Puedes usar la siguiente linea para ver el contenido completo de $entity
                     //echo "<pre>".print_r($entity, true)."</pre>"; die();
      
                     // en $entity->data esta la información del registro
      	       $data = $entity->data;
      

      Espero que te ayude mi comentario.

      Saludos!

  7. Excelente Post!! muy útil, ya logré crear las funciones, pero como realmente soy nuevo en esto de la programación, mis funciones aún están en blanco, me gustaría saber que tipo de programación necesito saber para crear las funciones, en este momento estoy tratando de añadir una función similar a la de add_days, pero lo que necesito sería añadir un mes con la fecha recibida. Cualquier idea puede ser util. Gracias.

  8. Añadí la siguiente función tratando de añadir el número de meses ingresados en la función, pero no logro que me funciona, al ejecutar la función mi página se queda en blanco.

    //

    function __vt_add_month($arr) {

    if (count($arr) > 1) {
    $baseDate = $arr[0];
    $noOfMonth = $arr[1];
    } else {
    $noOfMonth = $arr[0];
    }
    if($baseDate==null || empty($baseDate)) {
    $baseDate = date(‘Y-m-d’); // Current date
    }
    preg_match(‘/\d\d\d\d-\d\d-\d\d/’, $baseDate, $match);
    $baseDate = strtotime($match[0]);
    $date = strftime(‘%Y-%m-%d’, $baseDate + ($noOfMonth month));
    return $date;
    }

  9. Una pregunta, he copiado la función que has puesto en la raiz del crm y me carga correctamente, pero los modulos que me lista son:

    SalesOrder, Invoice, Quotes, Documents, Calendar, Contacts y Accounts, y si quiero registrar/usar estas funcions en otros módulos????

    Muchas gracias

    1. Hola @unaitwo,

      La verdad, tengo mucho tiempo que ya no usao Vtiger, y que no programo igual. Esa lista de modulo si revisas el codigo, es un array que tiene los elementos de modulos permitidos, tal vez puedes agregar ahi el nombre del modulo.

      Esta practica la hice en su momento para Vtiger 5.x y no se si funcione para la verison nueva de la misma manera, seria que revisaras la guia de Vtiger del WebService.

      Recibe un cordial saludo!

  10. Buenas tardes,
    Me pueden dar un tip por favor, ¿es posible saber la fecha en que las cuentas fueron creadas a partir de un lead, potencial,etc. y a su vez saber la fecha de creacion del lead?
    Con esta informacion pretendo ligar la fecha de creacion del lead con la cuenta creada.
    De antemano muchas gracias.
    Saludos.
    Alberto

  11. Hola Chavamm,
    Excelente aporte en tu blog.
    Me puedes orientar para crear una función personalizada que copie los registros de cada campo de un proyecto en otro proyecto similar, por favor. La idea es que cuando se modifique un registro en el proyecto 1, se replique ese dato en el proyecto 2, que tiene los mismos campos.
    Como no soy muy ducho en programación, sería de gran ayuda tu respuesta. Se que estás algo retirado de este tema, pero te lo pido por favor si me ayudas con esta función.

    Muchas Gracias de antemano.

    Saludos,
    Martin

Replica a chavamm Cancelar la respuesta