Todos los formularios pueden activar el motor de workflow en Javascript del lado del servidor para ejecutar lógicas de negocio complejas, tales como calcular costos y mostrar balances de inventarios. Básicamente, cualquier lógica compleja que desees ejecutar pero que no puede realizarse con las funciones actuales de Ragic, puede lograrse a través de scripts del lado del servidor.
El diseño de interfaz de la hoja Ragic puede realizar la mayoría del manejo de datos, tal como crear, editar y realizar querys en registros sin mucho problema. Sin embargo, el mantenimiento manual de los datos puede consumir demasiado tiempo y volverse rutinario después de un tiempo. Este es el momento en el que los usuarios Ragic comienzan a buscar formas de automatizar estos procesos.
Dentro de Ragic, hay un motor de comando donde puedes escribir Javascript que se procesa en el lado del servidor, para recuperar datos de tu hoja, hacer modificaciones o incluso crear muchos registros con un clic. Entre los usos típicos están actualizar inventarios, crear nuevos registros según otros (crear órdenes de ventas desde una cotización, crear contactos desde leads) o validar registros según datos existentes.
Hay varias maneras de activar tu workflow Javascript:
Esta es la forma más común de procesar workflow Javascript, y generalmente nuestra primera recomendación. Puedes escribir tu script en el scope instalado en tu hoja y configurar un botón de acción que se mostrará el panel de “Acciones” en la parte inferior derecha.
Para instalar un scope de hoja, haz clic en una hoja y elige Javascript Workflow:
Y elige scope de hoja desde el menú desplegable:
Puedes ir al formulario de tu diseño de hoja y agregar botón de acción de tipo JS workflow, para referirse a la función Javascript que has escrito.
Puedes pasar el id del registro actual al usar {id} en el argumento para la función llamada como:
setStatus({id})
En las siguientes secciones te contamos más sobre como escribir estas funciones.
Los post workflows son ejecutados inmediatamente después que un registro es guardado. Con el post workflow, es muy conveniente automatizar cambios que desees hacer en el registro que recién has guardado y que son pueden ser realizados con fórmulas. También puedes hacer modificaciones a registros en otras hojas relacionadas, como actualizar un balance de inventario.
Para agregar un post workflow, sólo haz clic en una hoja y elige workflow Java script:
Elige Post workflow desde el menú desplegable.
Los pre-workflows son ejecutados antes de guardar un registro, asique puede usarse como forma de validación para verificar los datos ingresados en contraste con los datos en la base de datos. Generalmente la mayoría de validación puede realizarse con verificaciones de expresiones regulares en la interfaz del usuario (frontend), o las casillas únicas para campo de texto libre. Para verificaciones más complejas en el backend, podrías necesitas pre-workflow.
Para agregar un pre- workflow, sólo haz clic en una hoja y elige Java script workflow.
Y elige Pre-workflow desde el menú desplegable.
El workflow diario se procesas diariamente. Es útil para hacer modificaciones que deben ser actualizadas cada día. Como, actualizar resultados de fórmulas según la fecha actual.
Para agregar un workflow diario, haz clic derecho en una pestaña y elige Javacscript Workflow Global:
Y elige Workflow Diario en el primer menú desplegable.
El workflow global es donde puedes escribir los módulos de workflow Javascript a los cuales otras funciones de workflow se pueden referir. No se ejecutará por sí solo, pero puede ser referenciado en cualquier tipo de workflow descrito anteriormente. Es adecuado para poner scripts que puedas necesitar para duplicar a través de múltiples hojas.
Para agregar un workflow global, solo haz clic derecho en una pestaña y elige Javascript Workflow Global.
Empezaremos con un ejemplo simple el cual obtiene el registro actual como un objeto, actualiza su valor con un botón y luego lo guarda en la base de datos. Así es como se ve el formulario de ejemplo:
Vamos a diseñar algunos botones para cambiar el valor del campo Estado con el clic de un botón al ejecutar un simple workflow Javascript del lado del servidor. Este es el código detrás del botón.
/** * AP_Name:wfdemo * Key Field: 1000013 * Name ID * - - - - - - - - - - - -------- * No. : 1000011 * Status : 1000012 */ función setStatus(recordId, status) { var STATUS_FIELD = 1000012; //id del campo estado var query = db.getAPIQuery("/workflow-demo/2"); //obtener el objeto query para una hoja con ruta a hoja var entry = query.getAPIEntry(recordId); //obtener el objeto del registro para el registro actual //fijar el valor de estado para el registro actual al objeto if (status) { entry.setFieldValue(STATUS_FIELD, status); } else {//for switching var newStatus = entry.getFieldValue(STATUS_FIELD) == 'On' ? 'Off' : 'On'; //obtener el valor actual de un campo entry.setFieldValue(STATUS_FIELD, newStatus); } //guarda el registro nuevamente a la base de datos entry.save(); }
Al escribir workflow Javascript, la variable db es predefinida. Puedes referenciarla donde sea. Generalmente llamamos al método getAPIQuery(pathName) para recuperar el objeto query para una hoja.
Luego puedes recuperar un registro con su id de registro en la hoja objeto con getAPIEntry(recordId) y llamar setFieldValue(fieldId,value) para fijar el valor a un campo o getFieldValue(fieldId) para recuperar el valor de un registro.
Si estas recuperando un valor de un campo de múltiple selección, donde puede haber múltiples valores, usa getFieldValues(fieldId) para recuperar todos los valores en una matriz. También puedes llamar setFieldValue(fieldId,value,true) con un argumento extra al final para especificar que estás “agregando” una opción a la lista actual de valores, no sobrescribiendo los existentes. Nótese que estas operaciones solo son adecuadas para campos de selección.
Al terminar, llama a save() en el asunto del registro para guardarlo nuevamente a la base de datos.
Si tienes subtablas en una hoja, puedes usar nuestra API para recuperar datos de ella o hacer ediciones como en el siguiente ejemplo. El formulario se ve así:
El workflow te guiará a través de cada fila de la subtabla, la cantidad total para ese año (según el campo de fecha en la subtabla), el total máximo para ese año, y el año que tuvo el total más alto. Esto está diseñado como post workflow, asique los tres campos se sólo lectura, serán rellenados por el workflow después que el registro sea guardado.
/** * AP_Name:wfdemo * Key Field: 1000006 * Date subtable key: 1000007 * Field Name Field Id * - - - - - - - - - - - -------- * No. : 1000001 * Name : 1000002 * Date : 1000003 * Amout : 1000004 * Total of This Year : 1000010 * Maximal Total of Year : 1000009 * Year of Maximal Total : 1000008 */ var KEY_FIELD = 1000006; var AMOUNT_SUBTABLE_ID = 1000007; var DATE_FIELD = 1000003; var AMOUNT_FIELD = 1000004; var MAX_YEAR_FIELD = 1000008; var MAX_TOTAL_FIELD = 1000009; var THIS_YEAR_TOTAL_FIELD = 1000010; var query = db.getAPIQuery("/workflow-demo/1"); var entry = query.getAPIEntry(param.getNewNodeId(KEY_FIELD)); var subtableSize = entry.getSubtableSize(AMOUNT_SUBTABLE_ID); var yearTotal = {} for (var i = 0; i < subtableSize; i++) { var year = parseInt(entry.getSubtableFieldValue(AMOUNT_SUBTABLE_ID, i, DATE_FIELD).substr(0, 4)); var amount = parseInt(entry.getSubtableFieldValue(AMOUNT_SUBTABLE_ID, i, AMOUNT_FIELD)); if (year in yearTotal) { yearTotal[year] += amount; } else { yearTotal[year] = amount; } } var maxYear; for (var year in yearTotal) { if (!maxYear || yearTotal[maxYear] < yearTotal[year]) { maxYear = year; } } entry.setFieldValue(MAX_YEAR_FIELD, maxYear); entry.setFieldValue(MAX_TOTAL_FIELD, yearTotal[maxYear]); entry.setFieldValue(THIS_YEAR_TOTAL_FIELD, yearTotal[new Date().getFullYear()]); entry.save();
La idea básica es usar getSubtableSize(subtableId) para obtener el número de filas para un registro y usar getSubtableFieldValue(subtableId,subtableRowIndex,subtableFieldId) para obtener sus valores. Puedes encontrar el id de subtabla y el id campo en los comentarios autogenerados al iniciar la edición del script de workflow.
También puedes usar setSubtableFieldValue(subtableFieldId,subtableRootNodeId,value) para fijar valores a una subtabla. El subtableRootNodeId se usa para especificar a cual fila de subtabla te estás refiriendo. Para encontrar el subtableRootNodeId de una subtabla existente, puedes usar la siguiente llamada getSubtableRootNodeId(subtableId,subtableRowIndex) la cual devolverá un número entero con el subtableRootNodeId.
Si necesitas agregar una fila a la subtabla, puedes usar un subtableRootNodeId negativo como -100, de esta manera todos los valores fijados al mismo subtableRootNodeId negativo serán aplicados a la misma fila de subtabla y los valores negativos diferentes subtableRootNodeId como -101 crearán una fila diferente en la subtabla con un set diferente de valores.
Enlace a ejemplo: Copiar de y Copiar a
Copiar registros es uno de los programas de workflow más comunes. Hemos escrito una función para simplificar este tipo de operación. Supongamos que queremos ver un registro en esta hoja:
Con un el clic de un botón, genera un registro en esta hoja:
Este es el código para esta acción:
/** * AP_Name:wfdemo * Key Field: 1000022 * S1 subtable key: 1000023 * T1 subtable key: 1000029 * Field name Field ID * - - - - - - - - - - - -------- * A : 1000014 * C : 1000015 * B : 1000016 * D : 1000017 * S1 : 1000018 * S2 : 1000019 * S3 : 1000020 * S4 : 1000021 * T1 : 1000024 * T2 : 1000025 * T3 : 1000026 */ function copyEntry(nodeId) { db.entryCopier(JSON.stringify({ THIS_PATH:"/workflow-demo/3", THIS_NODEID:nodeId, NEW_PATH:"/workflow-demo/4", COPY:{ 1000030:1000014, // A 1000031:1000015, // C 1000032:1000018, // S1 1000033:1000020 // S3 } }),response); }
Aquí puedes ver que la copia puede realizarse con una simple función de llamada al entryCopier. El entryCopier toma una cadena JSON como su parámetro. Solo indica la hoja fuente, la hoja destino, el registro que deseas copiar y lo más importante, cuales campos deben ser mapeados a qué campos. Cuando el mapeo esté completo, puedes crear botones de acción para copia los registros de una hoja a otra muy fácilmente.
Algunas veces quizá desees enviar notificaciones por correo según algunas condiciones, o quizá desees personalizar el contenido del mensaje de notificación. Puedes escribir un workflow Javascript en el lado del servidor para lograrlo. Aquí hay un script que puedes usar para enviar notificaciones por correo, muy simple:
//omitted...retrieve record object first var name=entry.getFieldValue(1001426); var email=entry.getFieldValue(1001428); var title=entry.getFieldValue(1001386); mailer.compose( email, //to null, //cc 'support@example.com', //reply to 'Acme, Inc.', //displayed from title, 'Hi '+name+',
we have received your sales order '+ 'and will be processing your order very soon.
'+ 'You can see your order details at https://www.ragic.com/example/1
'+ 'Thanks.
Best Regards,
Sophia, Sales Manager
Acme, Inc.' ); //mailer.attach(myURL); //you can use .attach to attach content from a URL mailer.send();
En cuanto a documentos adjuntos puedes usar mailer.attach(myURL); para adjuntar un registro en Ragic al usar el URL del registro. Por ejemplo, aquí hay un URL de Ragic (siempre ignore el URL después del hash)
https://www.ragic.com/wfdemo/workflow-demo/2/9
Este es el URL print friendly HTML:
https://www.ragic.com/wfdemo/workflow-demo/2/9.xhtml
Este es la versión Excel del URL:
https://www.ragic.com/wfdemo/workflow-demo/2/9.xlsx
También puedes usar la combinación de correspondencia así, el cid es el id de la combinación de correspondencia, puedes obtener el cid en el URL al intentar descargar el documento de combinación de correspondencia:
https://www.ragic.com/wfdemo/workflow-demo/2/9.custom?rn=9&cid=1
Ragic tiene limitaciones de cuantos correos puedes enviar. Si tienes preguntas sobre los límites de correos, contáctenos a support@ragic.com.
Primero puedes enviar el siguiente comando al objeto de query que recibas de db.getAPIQuery para incluir toda la información del registro:
query.setIfIncludeInfo(true);
Y después puedes obtener la información de aprobación para el registro así:
entry.getFieldValue('_approve_status');//Obtiene el estado de la aprobación actual entry.getFieldValue('_approve_next');//Obtiene el siguiente usuario que debe firmar entry.getFieldValue('_create_date');//Obtiene la fecha de creación del registro entry.getFieldValue('_create_user');//Obtiene el correo del usuario quien creó el registro
El estado de aprobación será F si es aprobado, REJ si es rechazado, P para procesando.
Si quieres obtener más de un registro a través de registro:
var query = db.getAPIQuery("/workflow-demo/1"); query.addFilter(1000002, '=', 'Green'); query.addFilter(1000008, '=', '2017'); var results = query.getAPIResultList(); for (var i = 0; i < results.length; i++) { var entry = results[i]; // ... }
Puedes agaregar filtros para buscar addFilter(fieldId, operator, value), y llama a getAPIResultList() para obtener la lista de registros.
Puedes mostrar un mensaje en una ventana emergente.
response.setStatus('WARN'); response.setMessage(message);
Puedes enviar una solicitud HTTP GET/POST para solicitar un URL y obtener el resultado devuelto:
util.getURL(String urlstring) util.postURL(String urlstring,String postBody)
La variable util es predefinida.
Método | Descripción |
---|---|
getAPIResult() | Obtiene el primer registro al iterar sobre el query |
getAPIResultList() | Obtiene una matriz de registros del query |
getAPIEntry(int rootNodeId) | Obtiene el registro por ID de nodo |
insertAPIEntry() | Inserta un nuevo registro al query, el método devuelve el nuevo registro. |
addFilter(int domainId, String operand, String value) | Filtra los registros por una condición específica. |
setOrder(int orderDomain, int orderDir) | Ordena los registros del query por el id de campo especificado y dirección de orden especificado. Parámetro orderDir se fija a 1 para orden ascendente y se fija a 2 para orden descendiente. |
deleteEntry(int nodeId) | Eliminar un registro por ID de nodo |
Método | Descripción |
---|---|
save() | Guarda un registro |
setCreateHistory(boolean createHistory) | Configura si el registro debe crear historial |
isCreateHistory() | Si el registro está configurado para crear historial |
setIfExecuteWorkflow(boolean executeWorkflow) | Configura si ejecutar workflow (pre-workflow y post workflow) del registro es necesario. |
setIgnoreEmptyCheck(boolean ignoreEmptyCheck) | Configura la verificación de campos no vacíos debe ser ignorada |
setRecalParentFormula(boolean recalParentFormula) | Si esta hoja es creada por subtabla de otra hoja, o es referenciada por otra hoja lo cual indica que esta hoja tiene una hoja madre, puedes llamar este método para fijar si deseas recalcular la hoja madre o no. |
setFieldValue(int domainId, String value) | Fija el valor a un campo individual. Para campos de subtabla, necesitas usar setSubtableFieldValue(); |
setFieldValue(int domainId, String value, boolean appendValue) | Fija el valor a un campo de selección múltiple, el parámetro appendValue debe ser true. Para campos de subtabla, necesitas usar setSubtableFieldValue(); |
setSubtableFieldValue(int domainId, int subtableRootNodeId,String value) | Fija el valor a un campo de subtabla, puedes obtener el parámetro subtableRootNodeId a través del método getSubtableRootNodeId. |
setSubtableFieldValue(int domainId, int subtableRootNodeId, String value, boolean appendValue) | Fija el valor a un campo de subtabla de selección múltiple, el parámetro appendValue debe ser true |
getJSON() | Obtiene una representación JSON de todo el registro. |
getFieldValue(int domainId) | Obtiene el valor del campo a través del ID de dominio |
getRootNodeId() | Obtiene el id de nodo del registro |
getRootDomainId() | Obtiene el ID del dominio raíz de un registro |
getSubtableSize(int subtableRootDomainId) | Obtiene el tamaño de subtabla, especificado por la raíz del ID de dominio de subtabla |
getSubtableRootNodeId(int subtableRootDomainId, int rowNumber) | Obtiene el id de nodo root de subtabla, especificado por su id de campo root y número de fila en subtabla. |
deleteSubtableRowByRowNumber(int subtableRootDomainId, int rowNumber) | Elimina una fila de subtabla a través del id de campo root y el número de fila de subtabla. |
deleteSubtableRowAll(int subtableRootDomainId) | Elimina cada fila de la subtabla especificada |
deleteSubtableRow(int subtableRootDomainId, int subtableRootNodeId) | Elimina fila de subtabla a través de id de campo root y nodo root de subtabla |
loadAllLinkAndLoad() | Carga los valores de todos los campos cargados en una configuración de enlazar y cargar en un registro. |
recalculateAllFormulas() | Carga los valores de todos los campos cargados en una configuración de enlazar y cargar en un registro. |
recalculateFormula(int domainId) | Recalcula la fórmula de un campo especificado. |
loadAllDefaultValues(ScriptUser user) | Carga los valores de cada campo que está fijado como valor predeterminado, el parámetro user es predefinido. |
loadDefaultValue(int domainId, ScriptUser user) | Carga el valor predeterminado de un campo especificado, el parámetro user es predefinido |
lock() | Bloquea el registro |
unlock() | Desbloquea el registro |
Método | Descripción |
---|---|
getEmail() | Obtiene la dirección de correo del usuario |
getUserName() | Obtiene el nombre completo del usuario |