v5.0-v6.0

Para migrar desde versiones superiores o iguales a 5.0, se deberá ir directamente a la versión 6.0. No está soportado migrar a versiones intermedias. A continuación, se detallan consideraciones a tener en cuenta según la versión de Qflow desde la cual se migra. Estas consideraciones son incrementales, o sea, si por ejemplo se migra desde 5.0, se deberán tener en cuenta las consideraciones de 5.0, y luego las consideraciones de 5.1.1, y así sucesivamente.

Consideraciones de migración desde Qflow 5.0

Versión de Servidor de Base de datos SQL

A partir de esta versión, es necesario SQL Server 2016 o superior para instalar y trabajar con bases de datos de Qflow. Además, no se dará más soporte para Oracle.

Consideraciones de migración desde Qflow 5.1.1

Cambio en la firma de métodos en los controladores Flow y Attachment

En la versión 5.2 varias firmas del controlador Flow y Attachment fueron cambiadas a llamadas asincrónicas. De esta forma en lugar de retornar un objeto T se retornará un objeto Task<T>. Se debe tener especial cuidado en los custom forms desarrollados ya que al cambiar las dlls por las de la nueva versión pueden necesitar algún ajuste.

La lista de métodos cambiados en el controlador Flow es la siguiente:
  • Start

  • Edit

  • DisplayTask

  • StartFlow

  • StartFlowAndGetSimpleData

  • EditFlow

  • RespondTask

La lista de métodos cambiados en el controlador Attachment es la siguiente:
  • UploadAttachment

  • AddFlowAttachment

  • Download

Sesión unificada en los sitios

En la versión 5.2 de Qflow, los sitios pueden tener una sesión unificada, es decir, que cuando un usuario se loguea en Qflow Design y tiene permisos en Qflow Team, al acceder a Qflow Team va directo al home sin pasar por el login. Si se quiere evitar este comportamiento en algún sitio, simplemente hay que agregar dos appsettings al web.config correspondiente.

Estos son:
  • UseUnifiedSession: en caso de que no se quiera utilizar debe tener el valor “false”

  • OwinCookieName: este es el nombre de la cookie que usará el sitio, se le puede asignar cualquier valor distinto al valor de la cookie usada para la sesión unificada (QflowAuth). Ejemplo: QflowDesignerAuth, QflowTeamAuth, etc.

Nuevos parámetros de sistema

Se agregaron una serie de parámetros de sistema en esta versión que cambian el comportamiento de Qflow. Se deberá revisar el valor de cada uno de estos para verificar que todo funciona correctamente.

Los parámetros son los siguientes:
  • QflowBPMWebLink/QflowOMMLink/QflowSAMWebLink/QflowWebSiteLink: Estos parámetros deben ajustarse a los urls que usan las distintas herramientas de Qflow. Sin ellos no funcionará correctamente la navegación entre sitios que se puede encontrar en la sección derecha de los cabezales.

  • NotifyUserOnCreation: Si este parámetro es Verdadero, Qflow le enviará un mail de bienvenida a la casilla de correo del usuario creado.

  • UserWelcomeLink: Es el link que se le envía a los nuevos usuarios si el parámetro NotifyUserOnCreation está habilitado. Si se quiere usar deberá ajustarse a la url del sitio deseado. Se recomienda usar el url de Qflow Access.

  • Logo/LogoLightVersion/TaskMiniLogo/TaskLogo: Se han agregado distintos parámetros correspondientes a los logos de las herramientas. Ahora el parámetro Logo corresponde al logo de Qflow y será mostrado en el login de cada herramienta, así como también en la parte superior izquierda de Qflow Access. Si se quiere cambiar el logo de Qflow Task, ahora se deberá cambiar el parámetro TaskLogo.

Consideraciones de migración desde Qflow 5.2

Cambios en formularios personalizados

Métodos asincrónicos de formularios personalizados

Muchos de los métodos usados para invocar acciones, como por ejemplo, obtener el formulario de inicio de un proceso, responder una tarea o editar un proceso fueron cambiados a métodos asíncronos, esto quiere decir que hay que hacer cambios en los formularios que los utilizan para que funcionen.

Advertencia

Dado estos cambios, es importante tener en cuenta que de acuerdo a como este implementado, los métodos pueden no dar errores a nivel de compilación. Los usuarios que desarrollan formularios pueden no percatarse de problemas, sin embargo, puede que ocurran efectos no deseados si no se agregan las instrucciones await donde corresponde.

Puede ver estos cambios reflejados en la sección de controladores del manual de diseño de formularios personalizados.

Soporte de inicio de procesos y tareas anónimas/externas en formularios personalizados

Ahora es posible utilizar formularios personalizados en inicio o respuesta de tareas anónimas/externas. Para que sigan funcionando los formularios personalizados existentes en este tipo de acciones, tendrá que hacer modificaciones a los formularios de inicio de proceso y respuesta de tarea.

Lo primero que se debería hacer es actualizar el archivo ViewStart con los cambios necesarios para este tipo de formularios. Esto implica agregar la condición del nuevo layout, CustomFormsGuestLayout, a este archivo. Este archivo debe quedar de la siguiente manera:

{
    if (Qframework.Web.Mvc.SessionManagement.SessionManagerHelper.GetSessionManager<Qflow.Web.Mvc.SessionManagement.QflowSessionManager>().IsGuest)
    {
        Layout = "~/Views/Shared/_CustomFormsGuestLayout.cshtml";
    }
    else if (Request.QueryString["useEmptyLayout"] == null || Request.QueryString["useEmptyLayout"] !="True")
    {
        Layout = "~/Views/Shared/_CustomFormsLayout.cshtml";
    }
    else
    {
        Layout = "~/Views/Shared/_CustomFormsEmptyLayout.cshtml";
    }
}

Tanto para los formularios de inicio y respuesta, se debe incluir la referencia a la librería Qflow.Mvc.Multitenancy en sus vistas. Podemos hacerlo agregando la siguiente línea a la lista de usings que se encuentra al principio del archivo de la vista:

@using Qflow.Mvc.Multitenancy

Para las vistas de formularios de inicio de proceso, reemplazar lo siguiente:

@using (Html.BeginForm(null, null, new { templateId = Model.TemplateId, useEmptyLayout = Request.QueryString["useEmptyLayout"] },
FormMethod.Post, new { id = "submitForm", enctype = "multipart/form-data" }))

por el código a continuación:

@using (Html.BeginForm(null, null, new { templateId = Model.TemplateId, useEmptyLayout = Request.QueryString["useEmptyLayout"],
tenantId = TenantResolver.GetRequestTenantIdOrDefault() }, FormMethod.Post, new { id = "submitForm", enctype = "multipart/form-data" }))

Para las vistas de formularios de respuesta de tarea, reemplazar lo siguiente:

if (Request.QueryString["DisplayLinks"] == null || bool.Parse(Request.QueryString["DisplayLinks"]))
{
    ViewBag.Links = ModelHelper.GetPageLinks("DisplayTask", Model.FlowId, Guid.Empty, Model.VersionId, Url);
}

por el código a continuación:

var isGuest = Model is GuestTaskModel;
var displayLinks = Request.QueryString["DisplayLinks"] == null || bool.Parse(Request.QueryString["DisplayLinks"]);
if (!isGuest && displayLinks)
{
    ViewBag.Links = ModelHelper.GetPageLinks("DisplayTask", Model.FlowId, Guid.Empty, Model.VersionId, Url);
}

Además, reemplazar:

@using (Html.BeginForm(null, null, new { flowId = Model.FlowId, taskId = Model.FlowStepId,
taskToId = Model.FlowStepToId, useEmptyLayout = Request.QueryString["useEmptyLayout"] }, FormMethod.Post,
new { id = "submitForm", enctype = "multipart/form-data" }))

por lo siguiente:

@using (Html.BeginForm(null, null, new { flowId = Model.FlowId, taskId = Model.FlowStepId,
taskToId = Model.FlowStepToId, useEmptyLayout = Request.QueryString["useEmptyLayout"],
tenantId = TenantResolver.GetRequestTenantIdOrDefault() }, FormMethod.Post,
new { id = "submitForm", enctype = "multipart/form-data" }))

Para los formularios de respuesta de tarea, también debemos incluir el helper QGuest en la vista de la siguiente manera:

@Html.QGuest(Request)

Cambio de permiso «Administrar vínculos»

Dado que en la versión 5.5 se quitó la funcionalidad de «Vínculos» de Qflow Task, reemplazándola por la funcionalidad de «Personalizar el menú lateral». Por lo tanto, se reemplazó también a nivel de instalación el permiso de «Administrar vínculos» por el nuevo permiso de «Administrar el menú lateral». Para aquellos ambientes en donde se use el sitio WebForms, este permiso tendrá que ser agregado nuevamente para que los usuarios puedan seguir usando la funcionalidad de «Vínculos» del sitio WebForms.

Propiedades nulleables de objetos de configuración de cola de trabajo

Las propiedades «ValidFrom» y «ValidTo» de los objetos WorkQueueConfiguration, que son retornados por métodos que devuelven información de nodos organizacionales en los web services, pasan a ser objetos nulleables, por lo que hay que tener en cuenta esta consideración para aquellos usuarios que los utilizan.

Nuevos parámetros de sistema

Se agregaron una serie de parámetros de sistema en esta versión que cambian el comportamiento de Qflow. Se deberá revisar el valor de cada uno de estos para verificar que todo funciona correctamente.

Los parámetros son los siguientes:
  • StartFlowAsGuestLink: Formato de los vínculos al inicio de procesos anónimos/externos. Este parámetro es único por instalación, y no se debería modificar para asegurar su funcionamiento correcto.

  • GuestResponseLink: Formato de vínculo a las respuestas de tareas externas que se despachan a usuarios externos. Se agrega una instancia de este parámetro por cada espacio de trabajo, y no se debería modificar para asegurar su funcionamiento correcto.

Cambios en archivos web.config de sitios y backend API

Los archivos web.config de los sitios y backend API tienen cambios en sus propiedades assemblyBinding. Puede hacer una instalación limpia y ver los archivos instalados para ver cuales son estas propiedades.

Se agregaron nuevas configuraciones que hay que agregar al archivo web.config del sitio de Qflow Task. Estas configuraciones se deben agregar bajo la sección configuration/appSettings del archivo.

  • Configuración de exportación de tablas: se debe incluir la siguiente configuración relacionada a la exportación de tablas en el sitio:

    <!-- Table export config -->
    <add key="ExportFormats" value="csv,html,excel" />
    <add key="ShowTableExportAsButtons" value="false" />
    

    La propiedad ExportFormats nos deja elegir cuáles son los formatos de exportación en que se permite exportar tablas, pudiendo eliminar algunos de los valores que se muestran arriba si queremos deshabilitar la opción de exportar en ese formato. La propiedad ShowTableExportAsButtons permite configurar si las opciones de exportación se muestran como acciones separadas o agrupadas en una lista desplegable.

  • Configuración de reCaptcha para inicio de procesos externos/anónimos: se debe incluir la siguiente configuración para habilitar un desafío reCaptcha para el inicio de procesos externos/anónimos:

    <!-- ReCAPTCHA config -->
    <add key="ReCAPTCHASiteKey" value="" />
    <add key="ReCAPTCHASecretKey" value="" />
    <add key="ReCAPTCHAVerifyUrl" value="https://www.google.com/recaptcha/api/siteverify?secret={{0}}&amp;response={{1}}" />
    <add key="ReCAPTCHARenderUrl" value="https://www.google.com/recaptcha/api.js?onload=onReCaptchaLoad&amp;render=explicit" />
    

    Para habilitar el desafío reCaptcha, debemos completar los valores para las propiedades ReCAPTCHASiteKey y ReCAPTCHASecretKey. Puede leer sobre cómo obtener estos valores aquí.

Se agrega la siguiente propiedad al archivo system.config, encontrado en el directorio de instalación de los backend services de Qflow, en la sección configuration:

<SecurityProperties>
    <TokenEncryptionPepper></TokenEncryptionPepper>
</SecurityProperties>

Lo que se de como valor de esta propiedad, dentro del nodo TokenEncryptionPepper se agrega a los secretos antes de encriptarlos, como una medida de seguridad extra para dificultar su desencriptación.

Consideraciones de migración desde Qflow 5.5

Zona horaria del sistema

Ahora Qflow tiene configurada una zona horaria del sistema, en la cual se almacenarán las fechas. Es necesario configurar correctamente esta zona para que las fechas se muestren correctamente en las distintas herramientas. Tener en cuenta que, una vez configurada, no se podrá cambiar sin realizar una migración de datos de manera manual.

Interfaz de scripting

La interfaz de scripting de C# ha sido actualizada para soportar el nuevo manejo de fechas y zonas horarias. Los métodos preexistentes devuelven las fechas en la zona horaria del sistema y como un objeto DateTime Se recomienda verificar y adaptar los códigos que los utilicen para que se ajusten a este comportamiento.

Biblioteca JavaScript

La biblioteca JavaScript ha sido actualizada para soportar el nuevo manejo de fechas y zonas horarias. Los métodos preexistentes devuelven las fechas en la zona horaria del sistema. Se recomienda verificar y adaptar los códigos que los utilicen para que se ajusten a este comportamiento.

Nuevos sitios para el Diseñador de formularios

La versión 6.0 incorpora nuevos sitios para el Diseñador de formularios, los cuales se incluyen en los instaladores de Qflow. Estos sitios son:

  • Qflow Form: Este sitio es el nuevo diseñador de formularios personalizados. Tiene un backend y frontend propios.

  • Qflow Task Angular: Este sitio es una nueva versión parcial del ya existente sitio Qflow Task. Tiene un backend y frontend separados.

  • Event Hub: Este sitio se encarga de sincronizar eventos entre sitios de Qflow.

Los backends de Qflow Form y Qflow Task Angular, junto con el sitio Event Hub, requieren la configuración de un nuevo application pool con la opción No Managed Code. Cada uno de estos application pools debe ser exclusivo del sitio correspondiente y no compartirse con otros sitios. Además, es necesario que los tres application pools utilicen el mismo usuario que el application pool de Qflow.Backend.API.

Estos nuevos sitios utilizan .NET 8 y node 24. Además, se deberá de disponer de infraestructura para una nueva base de datos SQL Server (se instala junto con la actualización de la base de datos de Qflow).

Almacenamiento de adjuntos

A partir de esta versión, Qflow incorpora nuevas opciones para el almacenamiento de adjuntos, incluyendo la posibilidad de utilizar Amazon S3 y de configurar múltiples bases de datos externas para distribuir la carga de almacenamiento.

Estas nuevas funcionalidades requieren ajustes en la configuración del sistema si ya se utilizaba almacenamiento en una base de datos externa o en Azure Blob Storage. En esos casos, será necesario trasladar a la base de datos de Qflow la configuración previamente definida en el archivo System.config, siguiendo lo indicado en Almacenamiento de adjuntos.

Propiedades deprecadas

Con el objetivo de simplificar la configuración de los pasos de los procesos en Qflow Design, se han deprecado algunas propiedades que tenían un uso limitado. A continuación, se proporcionan consultas SQL que permiten identificar los pasos que utilizan estas propiedades, a fin de que puedan ser revisados y ajustados en caso de ser necesario. Las propiedades deprecadas son Bandera al inicio, Bandera al finalizar, Importancia del proceso y Progreso.

Estas consultas devolverán los pasos de los procesos que utilizan las propiedades deprecadas, junto con información relevante como el identificador y nombre del paso, el identificador y nombre del proceso, el identificador y nombre de la versión, y el identificador del espacio de trabajo. El comportamiento que ofrecían estas propiedades puede replicarse fácilmente mediante el uso de datos de aplicación. Por ejemplo, es posible agregar un dato de aplicación denominado Progreso, cuyo valor se vaya actualizando en los pasos que anteriormente utilizaban la configuración Progreso.

  • Bandera al inicio:

    SELECT
        tsb.TemplateStepID,
        tsb.Name as TemplateStepName,
        tsb.ConfigurationXml,
        t.PackageID as TemplateId,
        t.Name as TemplateName,
        v.PackageID as VersionId,
        v.Name as VersionName,
        tsb.TenantID
    FROM TemplateStepBase tsb
        inner join TemplateStep ts on tsb.TemplateStepID = ts.TemplateStepID and tsb.TenantID = ts.TenantID
        inner join TemplatePackage t on ts.TemplateID = t.PackageID and ts.TenantID = t.TenantID
        inner join TemplatePackage v on ts.VersionID = v.PackageID and ts.TenantID = v.TenantID
    WHERE ConfigurationXml.exist('//*[local-name()="StartFlag" and text() != ""]') = 1;
    
  • Bandera al finalizar:

    SELECT
         tsb.TemplateStepID,
         tsb.Name as TemplateStepName,
         tsb.ConfigurationXml,
         t.PackageID as TemplateId,
         t.Name as TemplateName,
         v.PackageID as VersionId,
         v.Name as VersionName,
         tsb.TenantID
     FROM TemplateStepBase tsb
         inner join TemplateStep ts on tsb.TemplateStepID = ts.TemplateStepID and tsb.TenantID = ts.TenantID
         inner join TemplatePackage t on ts.TemplateID = t.PackageID and ts.TenantID = t.TenantID
         inner join TemplatePackage v on ts.VersionID = v.PackageID and ts.TenantID = v.TenantID
     WHERE ConfigurationXml.exist('//*[local-name()="EndFlag" and text() != ""]') = 1;
    
  • Progreso:

    SELECT
         tsb.TemplateStepID,
         tsb.Name as TemplateStepName,
         tsb.ConfigurationXml,
         t.PackageID as TemplateId,
         t.Name as TemplateName,
         v.PackageID as VersionId,
         v.Name as VersionName,
         tsb.TenantID
     FROM TemplateStepBase tsb
         inner join TemplateStep ts on tsb.TemplateStepID = ts.TemplateStepID and tsb.TenantID = ts.TenantID
         inner join TemplatePackage t on ts.TemplateID = t.PackageID and ts.TenantID = t.TenantID
         inner join TemplatePackage v on ts.VersionID = v.PackageID and ts.TenantID = v.TenantID
     WHERE ConfigurationXml.exist('//*[@Progress and not(@Progress="0")]') = 1;
    
  • Importancia del proceso:

    SELECT
        tsb.TemplateStepID,
        tsb.Name as TemplateStepName,
        tsb.ConfigurationXml,
        t.PackageID as TemplateId,
        t.Name as TemplateName,
        v.PackageID as VersionId,
        v.Name as VersionName,
        tsb.TenantID
    FROM TemplateStepBase tsb
        inner join TemplateStep ts on tsb.TemplateStepID = ts.TemplateStepID and tsb.TenantID = ts.TenantID
        inner join TemplatePackage t on ts.TemplateID = t.PackageID and ts.TenantID = t.TenantID
        inner join TemplatePackage v on ts.VersionID = v.PackageID and ts.TenantID = v.TenantID
    WHERE ConfigurationXml.exist('//*[@Importance and not(@Importance="Empty")]') = 1;