Saltar a contenido

Manual del Programador

Ejemplos de soluciones a problemas cotidianos de implementación

Como imprimir mensajes durante la ejecución de un post-proceso en la vista previa pero no en producción, para validar el funcionamiento de un post-proceso

Cuando se ejecuta la vista previa la variable $ef_test es verdadera.

Importante, existen dos vistas previas

  • Durante la creación del folio electrónico. En esta vista previa solo se pueden verificar las validaciones de javascript y ver la distribución del formulario en general, pero no se puede ejecutar una actualización para validar páginas personales o post-procesos.

  • Durante la asignación que campos visibles o editables por estación. En este caso no se cuenta con los siguientes datos de información (que si se tienen en tiempo de ejecución) : $in{'folio'} y los valores de los campos del folio, a menos que en la vista previa sean editables y se llenen antes de ejecutar la actualización.

sub main1 {
    if ($ef_test) {
        print "*Estoy en vista previa ejecutando main1*";
        print "*Inicializo folio a 1 para tener un valor válido*";
        $in{'folio'} = *1*;
    }
    # El código siguiente se ejecuta en vista previa y en producción
}

sub main2 {
    if ($ef_test) {
        print "*Estoy en vista previa ejecutando main2*";
    }
}

1;

Notificaciones por correo electrónico a personal externo a la empresa

Problema Quiero que hacer notificaciones especiales por correo electrónico a usuarios no involucrados en el proceso o usuarios adicionales a los parametrizados, mis clientes, proveedores, asesores, etc.

use Eflow::Libs;

sub main1 {
}

sub main2 {
    my $lib = Libs->new();
    my $rsx = Pg_VB->new();
    my $mensaje;
    my %datos;
    my $destino;

    # Leo los datos de mi folio
    $rsx->connectdb("dbname=workflow");
    $rsx->execute("select * from obj$in{'obj_id'} where folio=$in{'folio'}");
    %datos = $rs->getHash;
    $rsx->connectdb("dbname=workflow");
    $rsx->execute("select name from station where process=$in{'process'} and id=$in{'opt_station'}");
    $destino = $rs->itemvalue('name');
    # Construyo mi mensaje de correo
    # Sustituir cada ??? por el número correcto del campo asignado en el diseñador al dato que quiere
    # Recuperar del folio que se está procesando.
    $mensaje = qq¡
    Estimado $datos{'ff???'},
    Le notificamos que su folio número $in{'process'}-$in{'folio'}
    Referente a su Garantía, a pasado a la etapa $destino.
    Datos de su tramite
    Nombre del cliente : $datos{'ff???'}
    Telefonos : $datos{'ff???'}
    Tipo tramite : $datos{'ff???'}

    Atentamente
    Nuestra empresa.
    ¡;

    # Se debe obtener el correo del destinatario de alguna fuente,
    # en este caso se asume que de alguna forma se tienen en la variable $para.
    $lib->email_user($para,'Título de notificación',$mensaje);
}

1;

Si su mensaje de correo electrónico está codificado con HTML, para poder enviar imágenes y un formato mas amigable, reemplace la última línea por :

$lib->email_user_html($para,'Título de notificación',$ruta_archivo);

En este caso la variable ruta_archivo contiene un la ruta en el disco duro de un documento en formato HTML, las imágenes son ligas al portal de donde se descargaran al momento que el cliente abre el mensaje en su cliente de correos.

Validar que los campos capturados en la forma del documento electrónico sean validos de acuerdo a mis parámetros

  1. Para realizar validaciones lo más rápido posible se recomienda que los valores sean editables en la forma para recibirlos al momento de procesar el formulario. Si el campo solo es de lectura, habilitar que se envía el campo como oculto para tener el dato disponible.
use Eflow::Libs;

sub main1 {
    my $lib = Libs->new();
    if ($in{'ff???'} ne '*mi valor*') {
        $lib->Alert("El campo fulano debe tener el valor <b>mi valor</b> para ser válido.",1);
    } elsif (($in{'ff???'} == *8*) && ($in{'ff???'} eq '*UNI*')) {
        $lib->Alert("La combinación de campos no es válida");
    }
}

sub main2 {
}

1;

Si considera que sus usuarios puedan ser agresivos o su entorno de trabajo poco confiable. Tendrá que cargar los datos con un query en lugar de enviarlos en la forma para evitar que se hayan alterados los valores ocultos por el usuario.

Ejemplo :

$rs->execute("Select * from obj## where folio = $in{'folio'}");
%data = $rs->getHash;

Enviar el folio a una etapa diferente de la parametrizada en el diseñador cuando se cumpla alguna condición

sub main1 {
    if (!$in{'opt_station'}) {
        # Actualizando comentarios no hacer nada
        return 0;
    } elsif ($in{'opt_station'} == -1) {
        # Se está terminando el folio, hacer algo?
        return 0;
    } elsif ($in{'ff???'} == *valor*) {
        # Cambiar destino seleccionado por el este.
        $in{'opt_station'} = 6;
        return 0;
    }
}

sub main2 {
}

1;

Decidir a quien le asigno el folio sin utilizar los algoritmos de eFlow

sub main1 {
    if (!$in{'opt_station'}) {
        # Actualizando comentarios no hacer nada
        return 0;
    } elsif ($in{'opt_station'} == -1) {
        # Se está terminando el folio, hacer algo?
        return 0;
    } elsif ($in{'ff???'} == *valor*) {
        # Asignar el usuario que debe recibir el folio.
        $ef_user = *6*;
        return 0;
        #IMPORTANTE, el número es el de la plaza del usuario, no el número del usuario.
    }
}

sub main2 {
}

1;

Salvar datos capturados en el proceso en alguna tabla de los sistemas de mi empresa

use Eflow::Libs;

sub main1 {
    my $lib = Libs->new();
    my $dbh;
    my $sth;
    my $rsx;
    # Validaciones requeridas para garantizar que datos son correctos.
    # Antes de mover el folio a la siguiente etapa.
    ...
    if (!$in{'opt_station'}) {
        # Actualizando comentarios no hacer nada
        return 0;
    }
    $dbh = DBI->connect("string de conexion a su base de datos") or
    $lib->Error($DBI::errstr);
    # Prepare sus datos para la transacción que corresponda.
    $dbh->do("*insert into TABLA () values ()*") or
    $lib->Error($DBI::errstr);
    $dbh->do("*update TABLA set ... where ...*") or
    $lib->Error($DBI::errstr);
}

sub main2 {
}

1;

Quiero regresar el folio al usuario que actualizó una etapa en particular

OPCIÓN 1:

Para esto se requieren dos pasos:

  1. Salvar el usuario que actualiza en la etapa correcta.
  2. Recuperar el usuario salvado cuando se quiera regresar el folio a esta persona.

Post Proceso en la etapa donde quiero salvar al usuario que actualiza.

Utilizando un campo del folio electrónico, designado para esta operación. No se requieren de conexiones adicionales a bases de datos.

sub main1 {
    $in{'ff???'} = "$user,$ruser";
}

sub main 2{
}

1;

Post Proceso en la etapa de recuperación del usuario salvado.

Utilizando un campo del folio electrónico, designado para esta operación. Se supone que el campo aparece como campo oculto en la forma que se está actualizando.

sub main1 {
    ($ef_user,$ef_ruser) = split/,/,$in{'ff???'};
}

sub main2 {
}

1;

OPCIÓN 2

Función getNextUser()

Genérico para cualquier proceso. En la etapa que quiero regresar el folio, creo tipo de asignación getNextUser(); Se requieren hacer conexiones adicionales a bases de datos.

sub getNextUser {
    my $rs = Pg_VB->new();
    my $station = '???';
    $rs->connectdb("dbname=workflow");
    $rs->execute("select u.id,u.ruser_id from log_update$in{'process'} l, users u where l.station=$station and l.folio$in{'folio'} and l.user_id=u.id");
    return ($rs->itemvalue('id'),$rs->itemvalue('ruser_id'));
}

Quiero desplegar 2 combos en una estación, pero la selección del primer combo determina los valores del segundo combo

  • Primera opción. Solución Web 1. Las estaciones solo se van a acceder desde un navegador de PC.

En el folio electrónico creamos 5 campos con las siguientes configuraciones (no se crean los dos combos que se quieren crear).

  • Campo texto sin límite, para almacenar la descripción del valor del primer combo. (ff1)
  • Campo texto sin límite, para almacenar el valor del primer combo. (ff2)
  • Campo texto sin límite, para almacenar la descripción del valor del segundo combo. (ff3)
  • Campo texto sin límite, para almacenar el valor del segundo combo. (ff4)

Campo liga de texto a una aplicación

En la etapa donde se va a realizar la selección de estos valores, debe de quedar configurada de la siguiente forma :

  • ff1 : Ver
  • ff2 : Ver -- Oculto
  • ff3 : Ver
  • ff4 : Ver -- Oculto

Por último, en la aplicación de la liga se va a ejecutar un script que el programador puede desarrollar con plena libertad para desplegar y seleccionar los dos combos como mejor le parezca desarrollar esta parte.

Lo importante es que al finalizar la selección de los dos combos la aplicación debe ejecutar el siguiente código al final, supongamos que una ves que se han seleccionado ambos combos y se actualiza la página se ejecuta la subrutina "salva" :

sub salva {
    my $rs = Pg_VB->new();
    $rs->connectdb("dbname=workflow");
    $rs->execute("update obj?? set *ff1*='$in{'*combo1*'},*ff2*={'*valor1*'},*ff3*='$in{'*combo2*'},*ff4*={'*valor2*'} where folio=$in{'folio'}");
    print qq|
    <html>
    <body>
    <script languaje="JavaScript">
    top.opener.location.reload();
    self.close();
    </script>
    </body>
    </html>
    |;
}

En conclusión, el problema se resuelve seleccionado los valores de los combos por medio de una ventana emergente y posteriormente transfiriendo los valores a los campos del folio y recargando la forma para que el formulario de la etapa muestre los valores seleccionados en los combos de la ventana emergente.

  • Segunda opción. Usando Web 2.0. JavaScript y uso del DOM. JQuery.

Cree una página personalizada

  • En main_page3: Cargue las librerías de JavaScript que requiera e interactúe con el DOM para crear el efecto que desee en los elementos deseados.
  • Utilice el código fuente HTML generado en la navegador para que conozca los ids y nombres de las variables de los combos u otros elementos con los que desee interactuar.
our $combo1;

sub main_page {
}

sub main_page2 {
}

sub main_page3 {
    print qq¡
    <script>
    // JavaScript con instrucciones para manipular los elementos.
    </script>
    ¡;
}

sub main_value {
    return 0;
}

Estación. Quiero jalar un dato de mi ERP a eFlow justo en el momento en que se despliega el folio, ya que este valor cambia frecuentemente en mi ERP (ejemplos : tipo de cambio, número de lote de producción, etc.)

Agregar en el parámetro "Pagina Personal" un programa .pl y crear el siguiente código:

use DBI;
use Eflow::Libs;

sub main_page {
    if ($ef_test) {
        print "Ejecutando MAIN PAGE<br>";
    }
}

sub main_page2 {
    if ($ef_test) {
        print "Ejecutando MAIN PAGE2<br>";
    }
}

sub main_page3 {
    if ($ef_test) {
        print "Ejecutando MAIN PAGE3<br>";
    }
}

sub main_value {
    my $lib = Libs->new();
    my $dbh;
    my $sth;
    my $rsx;

    if ($data{'id'} == ??) {
        if ($ef_test) {
            print "Traer valor actual del ERP <br>";
        }
        $dbh = DBI->connect("*string de conexion a su base de datos*") or
        $lib->Error(DBI::errstr);
        $dbh->prepare("*select válido para traer el valor de su base de datos*") or $lib->Error(DBI::errstr);
        $dbh->execute or $lib->Error(DBI::errstr);
        $rsx = $sth->fetchrow_hashref;
        $val{'ff???'} = $$rsx*{'nombre del campo'};*
    }
    return 0;
}

Estación. Tengo varios campos editables por el usuario en una estación

Uno de ellos es una llave con varios datos asociados en una base de datos externa (ejemplo : número de cliente, que tiene asociados, nombre, dirección teléfonos, rfc, etc.). Quiero que el usuario capture la llave y si el dato existe en la base externa que se llenen los campos relacionados con los datos existentes y que estos no se puedan editar por el usuario. Si el número no existe, que se dé de alta el nuevo registro con los campos que el usuario capture, en este caso los datos relacionados sí se pueden editar.

Cuando uno ve problemas como el anterior y ha programado durante mucho tiempo en Windows, lo primero que se le ocurre a uno es como habilitar o inhabilitar los campos en caso de que se de alguno de los dos eventos: encontrado o no encontrado. A continuación vamos a presentar dos soluciones al problema, la primera al estilo Web y la segunda al estilo Windows.

1) El método sencillo, simple y directo al estilo Web 1.0

Hacer que los campos no sean editables sino que de solo vista (los campos que requieran ser procesados en un post-proceso, además se activan como hidden). Al iniciar el folio van a estar todos vacíos. Se tiene un campo de tipo Link que abre una ventana emergente para buscar el campo llave, se hace el query de búsqueda a la base de datos externa y los resultados pueden ser :

a) Se encuentra la llave. Entonces se jalan todos los datos relacionados y se actualizan con un update en la tabla objNN correspondiente.

$rs->execute("update objNN set ffNN='valor',ffNN='valor',... where folio=$in{'folio'}");

posteriormente se termina imprimiendo la siguiente página HTML :

<html>
<body>
<script>
top.opener.location.reload();
self.close();
</script>
</body>
</html>

Esto hace que la ventana de eFlow, recargue y como ya se ingresaron los datos con el update anterior, los datos están disponibles en el WorkFlow, al recargarse la ventana los datos vacíos ahora aparecen llenos y se auto cierra la ventana.

b) No encuentras la llave. Entonces despliega una forma de captura con todos los datos relacionados. Cuando el usuario termine de capturar, envía la forma. Se insertan los datos en la tabla externa. Se actualizan los datos en la tabla del folio como en el paso anterior y se imprime nuevamente la misma página HTML del paso anterior.

2) Usando técnicas de Web 2.0

Todos los campos son editables en la forma de la estación.

  • Se agrega un programa.pl a la estación en el renglón "Pagina Personal", como si fuera un post-proceso, leer la sección station.cgi para entender el concepto.
  • En main_page3: Cargue las librerías de JavaScript que requiera e interactúe con el DOM para crear el efecto que desee en los elementos deseados.
  • Utilice el código fuente HTML generado en la navegador para que conozca los ids y nombres de las variables de los combos u otros elementos con los que desee interactuar.
sub main_page {
}

sub main_page2 {
}

sub main_page3 {

print qq|
    <script>
    document.MyForm.ffnnn.readOnly=true;
    document.MyForm.ffnnn.readOnly=true;
    ...
    </script>
    |;
}

sub main_value {
}

1;

Esto va a hacer que este código se imprima justo después de imprimir los campos y los va a inhabilitar todos. es una línea por campo que quieras deshabilitar. Se deben escribir los ff reales de su página. Se crea nuevamente un campo tipo Liga para abrir una ventana emergente. Y en ella se localiza la llave en la base externa. Posibles resultados

a) Se localiza la llave. Con javascript se copian todos los datos de al los campos de la forma de eFlow que se encuentran como readonly. Y se auto cierra la ventana.

<html>
<body>
<script>
top.opener.document.MyForm.ffpredial.value='valor predial';
top.opener.document.MyForm.ffnnn.value='valor';
top.opener.document.MyForm.ffnnn.value='valor';
...
self.close();
</script>
</body>
</html>

b) No se encuentra la llave. Se pasan con javascript la llave al campo solo lectura del formulario de eFlow. Y se habilitan para escritura los campos bloqueados :

<html>
<body>
<script>
top.opener.document.MyForm.ffLLAVEl.value='valor predial';
top.opener.document.MyForm.ffnnn.readOnly=false;
top.opener.document.MyForm.ffnnn.readOnly=false;
...
top.opener.document.MyForm.ffnnn.focus();
self.close();
</script>
</body>
</html>

Habilita todos los campos para que los puedan escribir. El único que no es el de la llave para que no busquen una y escriban otra.

Se tiene que agregar un post-proceso para insertar los nuevos valores en la base de datos externa.

Quiero desplegar un campo en forma especial en el formulario de "station", dependiendo si la vista es en un dispositivo móvil o es en una PC. El campo contiene una cadena de caracteres que deseo aparezcan arreglados en una tabla

Supongamos que hemos extraído un grupo de datos de nuestro ERP, y hemos concatenado los valores con "pipes", para el ejemplo es el detalle de los renglones de una compra. Los datos del detalle se almacenaron en un campo texto del folio con el siguiente formato :

descripción|cantidad|unidad|precio unitario|total|almacen de compra|obra|centro de costos
descripción|cantidad|unidad|precio unitario|total|almacen de compra|obra|centro de costos
descripción|cantidad|unidad|precio unitario|total|almacen de compra|obra|centro de costos
descripción|cantidad|unidad|precio unitario|total|almacen de compra|obra|centro de costos

Las líneas se encuentran en la variable ff35 (para este ejemplo). Al entrar al folio en eFlow queremos presentar los valores en una tabla amplia si el acceso es desde una PC, pero en un formato diferente si es de una BlackBerry, con un display angosto y HTML limitado.

sub main_page {
}

sub main_page2 {
}

sub main_page3 {
}

sub main_value {
    my $det;
    if ($data{'id'} == 35) {
        if ($BB) {
            my @lines;
            my $line;
            my $desc; my $cant; my $unid; my $precio; my $alm; my $obra; my $const; my $total;
            my $bgcolor;
            my $i=0;
            @lines = split /n/,$val{'ff447'};
            print qq|
            <tr>
            <td class='label' width=20% valign='top'>Detalle</td></tr>
            <tr>
            <td class='value' valign='top'>
            <table border=0 cellspacing=0 style='font-size: 6pt' width="100%">
            |;
            foreach $line (@lines) {
                ($desc,$cant,$unid,$precio,$total,$alm,$obra,$const) = split /|/,$line;
                $i++;
                print qq|
                <tr class='title'><td colspan="2" width="100%">Partida $i</td></tr>
                <tr bgcolor="white"><td width="35%" valign="top"><b>Descr</b> </td><td width="65%" valign="top">$desc</td></tr>
                <tr bgcolor="white"><td width="35%" valign="top"><b>Cant</b> </td><td width="65%">$cant $unid <b>P.U.</b>$$precio</td></tr>
                <tr bgcolor="white"><td width="35%" valign="top"><b>Total</b> </td><td width="65%">$$total</td></tr>
                <tr bgcolor="white"><td width="35%" valign="top"><b>Almac</b> </td><td width="65%">$alm</td></tr>
                <tr bgcolor="white"><td width="35%" valign="top"><b>Obra</b> </td><td width="65%">$obra</td></tr>
                <tr bgcolor="white"><td width="35%" valign="top"><b>CECOS</b> </td><td width="65%">$const</td></tr>
                |;
            }
            print qq|
            </table>
            </td></tr>
            |;
        } else {
            $det = $val{'ff447'};
            $det =~ s/|/</td><td bgcolor='white'>/g;
            $det =~ s/n/</td></tr>n<tr><td bgcolor='white'>/g;
            print qq|
            <tr><td class='label' width=20% valign='top'>Detalle</td>
            <td class='value' valign='top'>
            <table border=0 cellspacing=1 style='font-size: 8pt' bgcolor="#888888">
            <tr class='title'>
            <td>Descripción</td>
            <td>Cantidad</td>
            <td>Unidad</td>
            <td>Precio</td>
            <td>Monto</td>
            <td>Almacén</td>
            <td>Obra</td>
            <td>Centro Costos</td>
            </tr>
            <tr><td bgcolor='white'>$det</td></tr>
            </table>
            </td>
            <td valign='top' width='20%'></td>
            |;
        }
        return 1;
    }
    return 0;
}

1;

El resultado se vería como en las dos imágenes que siguen:

Imagen en PC

BlackBerry

Quiero crear un folio cuando se cree un evento en mi ERP, CRM u otro sistema

Este tipo de problemas se resuelve utilizando un servicio de cron. En el siguiente ejemplo, vamos a crear un folio cuando en el ERP (En este caso Navision) se cree una compra nueva. El folio va a ser enviado a un autorizador, la autorización se escala a un director y posteriormente se envía a compras cuando este es autorizado. Para crear el folio se crea un programa que se ejecuta con cron cada 2 minutos. El programa que valida que en Navision existe una nueva compra e inserta el folio en eFlow es el siguiente. Para este ejemplo en Navision se creó una nueva entrada en la tabla de compras para que el usuario indique cuando la compra está lista para ser autorizada.

Línea de cron:

*/2 * * * * /home/eflow/cron/compras_nav/carga_compras.pl

carga_compras.pl

#!/usr/bin/perl

carga_nuevas_compras();

# Rutina para cargar las compras

sub carga_nuevas_compras {
    my $qry;
    my $sth; my $rs;
    my $sth2; my $rs2;
    my %ph;
    my %fd;
    my $st;
    my $ok;

    conectaNavision($SERVIDOR,2);
    # Buscar todas las compras que tienen una version 1 creada
    $qry = qq|select * FROM [dbo].[VISE$Purchase Header] where Status=1 and "Status Flow"=0 and "Document Type"=1|;
    $sth = $dbN->prepare($qry) or sqlError("$qrynn$DBI::errstr");
    $sth->execute() or sqlError("$qrynn$DBI::errstr");
    while ($rs = $sth->fetchrow_hashref) {
         %ph = %$rs;
         %fd = ();
        $st = carga_informacion(%ph,%fd);
        if ($st) {
            $ok = alta_folio(%fd);
            if ($ok) {
                marca_tomado($$rs{'No_'},$$rs{'Posting Description'});
            }
        }
    }
}

# Esta rutina inserta el nuevo folio en eFlow

sub alta_folio {
    my $fd = shift;
    my $folio;
    my $label;
    my $key;

    $rsw->execute("begin");
    $rsw->execute("LOCK TABLE process IN SHARE ROW EXCLUSIVE MODE");
    $rsw->execute("update process set folio=folio+1 where id=$PROCESS");
    $rsw->execute("select folio from process where id=$PROCESS");
    $folio = $rsw->itemvalue('folio');
    $rsw->execute('commit');
    if (($OBJ > 0) && ($folio)) {
        $$fd{'folio'} = $folio;
        $rsf->insert("obj$OBJ",$fd);
    } else {
        return 0;
    }
    $label = "$$fd{'ff440'}";
    $rsw->execute("insert into folio$PROCESS (id,label,status,user_folio,user_new,date_created,time_created,acc_cost,date_finished,obj_folio) values ...");
    $rsw->execute("insert into folio_station$PROCESS (folio,station,user_id,date_station,time_station) values ...");
    return 1;
}

    # Esta rutina extrae los datos de Navision y los pasa al folio en eFlow

sub carga_informacion {
    my $ph = shift;
    my $fd = shift;
    $$fd{'ff440'} = $$ph{'No_'};
    $$fd{'ff491'} = $$ph{'Tipo pago'};
    $$fd{'ff442'} = $$ph{'Pay-to Name'};
    $$fd{'ff441'} = $Sdate;
    $$fd{'ff455'} = $$ph{'Purchaser Code'};
    $$fd{'ff457'} = "$$ph{'Id Solicitante'},$super,$gerente,$esol,$esup";
    ($$fd{'ff445'},$$fd{'ff450'}) = getUsuario($$ph{'Id Solicitante'});
    ...
    if ($errores) {
        return 0;
    }
    ...
    return 1;
}

### Esta rutina marca compra como tomada por eFlow

sub marca_tomado {
    my $no_doc = shift;
    my $qry;
    $qry = qq|update [dbo].[VISE$Purchase Header] set "Status Flow" = 1 where "no_"='$no_doc'|;
    $dbN2->do($qry) or sqlError("$qrynn$DBI::errstr");
}

Quiero configurar el eFlow para que autentifique a los usuarios por medio de certificados digitales

Configurar eflow.conf del servidor apache.

<Directory "/home/eflowweb/cgi-bin">
AllowOverride None
Options None
Order allow,deny
Allow from all
SSLOptions +StdEnvVars +OptRenegotiate
SSLVerifyClient require
SSLVerifyDepth 1
</Directory>

<Directory "/home/eflowweb/html">
AllowOverride None
Options None
Order allow,deny
Allow from all
SSLVerifyClient require
SSLVerifyDepth 1
</Directory>

<VirtualHost *:8043>
DirectoryIndex index.htm
AddCharset utf-8 htm html
ServerAdmin ...
ServerName mi.eflow.com.mx
DocumentRoot /home/eflowweb/html
ErrorLog /home/eflowweb/log/error_log
ScriptAlias /cgi-bin/ "/home/eflowweb/cgi-bin/"
SSLCACertificateFile ...../ca_CA.crt
SSLCertificateFile ..../myserver.cer
SSLCertificateKeyFile ..../myserver.key
SSLEngine on
</VirtualHost>

Quiero hacer una cola de documentos

En una etapa recibo cientos de documentos. Estos documentos se pueden quedar indefinidamente en este punto esperando a que el cliente se presente a continuar el trámite o que se les entregue la documentación final. Los clientes se presentan con un recibo que contiene el número de folio de eFlow. Quiero que cualquiera de los usuarios de esta etapa pueda tramitar el documento.

La mejor solución en este caso es crear un usuario llamado "cola de espera", por ejemplo. Con su usuario cola espera y un password que nadie va a utilizar.

Los documentos son asignados a este usuario ficticio en la etapa donde se acumulan los documentos.

En la misma etapa se da permiso de apoyo al grupo de usuarios que va a estar atendiendo a los clientes conforme llegan.

El usuario, toma el recibo del cliente, selecciona buscar folio por medio de la página de búsqueda de folios. Escribe el número de folio, y si el documento se encuentra en la etapa de la cola, le aparecerá para que realice el trámite en eFlow.

Las ventajas de resolver el problema de esta forma son :

  • Si los usuarios intervienen en varias etapas, no tienen que estar viendo esta gran lista de documentos que se procesa de forma muy indefinida. Permanecen "ocultos" por así decirlo.
  • La etapa al estar asignada a un usuario ficticio no le acumula tiempo a ningún usuario real, ya que el proceso en este caso depende de que un cliente se presente cuando tenga tiempo.
  • El procedimiento para localizar el documento es mucho más rápido.
  • Cualquier otro algoritmo de asignación va a designar el trabajo a personal que no necesariamente lo va a atender llegado el momento que el cliente se presente, por esta razón no conviene asignar el trámite a nadie en especial.

Deseo crear unas etapas con escalamiento entre usuarios si uno no puede resolver en un tiempo determinado

Creamos la etapa que realiza la actividad principal. Y la configuramos como "Manual / Automática". Y le damos como destino la etapa "2 -- Escalamiento Nivel 1", para este ejemplo.

Configuramos la etapa 2 como "Manual / Automática". Y nuevamente configuramos para que se desplace el folio a el "Nivel 3".

Si el usuario actualiza personalmente va a avanzar el documento a la etapa "4". Pero si el tiempo de la estación se vence, el documento sube al siguiente nivel de escalamiento.

Incluso si la etapa "3" la configuramos como "Manual / Automática" y creamos como destino predefinido la etapa "1", vamos a crear al efecto de que el documento va a estar saltando entre los posibles integrantes que le puedan dar una solución, hasta que alguno tome el folio y lo procese.

OPCIÓN ALTERNATIVA (con programación)

Creamos una sola etapa como "Manual / Automática" (la primer etapa de la actividad). Y agregamos el siguiente post-proceso a la etapa, con la lógica descrita en el ejemplo.

sub main1 {
    if ($AUTOMATIC) {
        $in{'opt_station'} = $in{'station'};
        $ef_user = *nextUser()*;
        $in{'alarm'} = *{ minutos para siguiente escalamiento }*;
        $in{'ef_time'} = *60*;
        return 0;
    }
}

sub main2 {
}

sub nextUser {
    *{ función que regresa siguiente usuario en el escalamiento }*
}

1;

Deseo que clientes o ciudadanos externos den de alta trámites desde Internet

Cuando uno se plantea este servicio cara a clientes, proveedores o ciudadanos, la primer pregunta es si uno debe asignarles una cuenta y password de eFlow para que entren al sistema.

La respuesta corta es "Depende".

  • Si con pocos usuarios y los deseamos integrar dentro de nuestros procesos. Si se puede hacer.
  • Cuando los usuarios van a ser miles o cientos de miles. Y lo que queremos es ofrecer la posibilidad de iniciar los trámites desde sus oficinas o en sus hogares. Lo mejor es crear un portal que recopile y controle la información que se requiere para el trámite y cuando ya se tenga correctamente requisitada, internamente abrir un folio de seguimiento en eFlow y darle únicamente la referencia al cliente externo. Con otro portal se puede realizar un reporte de seguimiento que sea tan explícito y detallado con la información que deseamos pueda consultar. Beneficios de esta aproximación.
  • Si el portal de acceso se realiza en un servidor diferente, internamente el volumen no va a afectar las operaciones internas de los usuarios. Probablemente el servicio es de atención a ciudadanos y se reciben miles de trámites diarios, pero se tiene un equipo pequeño para eFlow porque internamente el proceso es atendido por 20 usuarios. Lo que distribuye mejor la carga de accesos al servidor.
  • Se aísla el servidor de trámites de la recepción y acceso abierto, lo que incrementa la seguridad porque los usuarios externos no tienen acceso directo al servidor de procesos.
  • Me permite por medio de reportes personalizados definir que información deseo que vean en el seguimiento, ya que internamente la información que se parametriza en eFlow contiene datos sensibles que no deben de verse en el historial por el solicitante externo. Igualmente no deseamos dar información de contacto de la persona que tiene el trámite en ese momento para que no lo molesten o intenten presionarlo para liberar un trámite.
  • Se puede implementar el control de acceso a usuarios más adecuado para los usuarios. Cuentas y passwords, certificados digitales, acceso libre, etc. Sin comprometer el sistema interno de eFlow para ello.

Quiero que un folio ubicado en una estación automática se mueva considerando otros eventos no solo el vencimiento del folio en la estación

Cree un post-proceso como el siguiente y evalúe su expresión, si esta es verdadera el documento avanza de lo contrario se queda sin avanzar.

sub main1 {
    if ($AUTOMATIC) {
        $flg = __*calcular evento;__*
        if ($flg) {
            # has más cosas
        } else {
            $in{'opt_station'} = '';
            return 0;
        }
    }
    # Esto se ejecuta tanto en automático como manual
}

sub main2 {
}

1;

Quiero incrementar la seguridad de acceso a la base de datos de PostgreSQL

No deseo que otros programas locales tengan acceso sin cuenta y contraseña a la base de datos de eFlow.

  1. Edite pg_hba.conf para que solicite autenticación md5 en conexiones locales.
  2. Edite Pg_VB.pm, y fieje $user y password al usuario de eflow. Puede dejar los valores fijos o que se den por omisión si no se especifica alguno. Ejemplo :

pg_hba.conf

local all all md5

Pg_VB.pm

sub connectdb {
    my $user = @_ ? shift : 'eflow';
    my $passwd = @_ ? shift : '*passwd*';
}

PostgreSQL va a correr en un servidor diferente a donde se instala eFlow

  1. Configurar permisos de acceso remoto en pg_hba.conf en el servidor de postgresql
  2. Igual al ejemplo previo, pero adicionamos la conexión al servidor remoto en Pg_VB.pm

pg_hba.conf

local all all md5

Pg_VB.pm

sub connectdb {
    my $user = @_ ? shift : 'eflow';
    my $passwd = @_ ? shift : 'passwd';
    $self->{'dbh'} = DBI->connect("dbi:Pg:$db;__*host=$host;port=$port__*",$user,$passwd);
}

Uso de librería print_doc.pl o print_doc.cgi

print_doc.pl se utiliza cuando se desea imprimir una forma después de actualizar un folio. En este caso llamándola desde el post-proceso2. Cuando se configura en un post-proceso, se debe adicionar en el renglón parámetros : ruta_al documento, estación_valida,[0 si se va a realizar una captura y después impresión, 1 si se va a imprimir sin capturar algo antes]. Ejemplo :

/home/eflowweb/cgi-bin/formatos/mi_formato.htm,1,0

/home/eflowweb/cgi-bin/formatos/mi_formato.htm,1,1

print_doc.cgi se utiliza cuando se desea imprimir una forma en una ventana emergente, llamando la rutina desde una liga en el formulario de la estación. Se debe configurar en el diseñador la ruta al documento en la variable doc. Ejemplo:

/cgi-bin/eflow/lib/print_doc.cgi?doc=/home/eflowweb/cgi-bin/docs/mi_forma.htm&cmd=[0 o 1]

El formato del documento, debe ser HTML, y dentro del formato se deben de insertar etiquetas que van a realizar diferentes funciones al ser desplegado el documento.

El formato general de las etiquetas es : Instrucciones:opciones:parámetros

Las posibles instrucciones y su resultado se explican en la siguiente tabla.

Instrucción Opciones Acción Ejemplo
SYS Nombre variable global de PERL Imprime el valor [[SYS:Sdate]
IN Nombre campo formulario Imprime valor $in{'campo'} [[IN:folio]
FOLIO campos_folio+:formato Despliega uno o más datos concatenados [[FOLIO:ff45 ff46 ff77]]
dateL (fecha) Presenta en formato fecha [[FOLIO:ff88:dateL]]
DBSEL Consulta a BD Despliega campo [[DBSEL:tabla:id:nombre]]
SEL Lista fija Despliega combo [[SEL:Primaria|Secundaria|Prepa]]
EXEC Carga una programa y ejecuta rutina [[EXEC:mi_prog.pl:rutinax]
TEXTAREA Despliega área de texto [[TEXTAREA:Leyenda inicial:45]]
Cualquier nombre campo texto Despliega un campo texto [[mi_texto:Leyenda:20]]