Escribir una regla de negocio
Objetivo
Hacer que un formulario responda a lo que hace la persona que lo rellena: mostrar el campo Responsable solo en gastos de más de 100 £, deshabilitar Fecha de cierre hasta que se gane la oportunidad, tomar la Moneda predeterminada de la cuenta.
Requisitos previos
- Ha iniciado sesión como creador, con la solución de la tabla abierta.
- La tabla tiene los campos de los que habla la regla y, si quiere vincular la regla a un formulario concreto, ese formulario existe.
Qué es una regla de negocio y qué no es
Una regla de negocio se ejecuta en el navegador, en el formulario, y cambia cómo se comporta el formulario. Tiene cuatro verbos: mostrar u ocultar un campo, habilitarlo o deshabilitarlo, hacerlo obligatorio o no, y establecer un valor.
No decide qué se puede guardar. Alguien puede desactivar una regla, usar otra pantalla o llamar directamente a la API, y el registro se guarda igualmente. Todo lo que deba ser cierto de los datos corresponde a un paso de complemento de servidor, que se ejecuta haga lo que haga el navegador. Use una regla de negocio para que un formulario sea agradable; use un paso de complemento para que una regla sea real. Es normal querer ambas cosas, y se escriben por separado a propósito.
Pasos
-
Abra el formulario al que se destina la regla (la tabla, luego Formularios y luego el formulario) y seleccione Eventos en su barra de herramientas. La lista muestra todas las reglas que se ejecutan en este formulario, incluidas las vinculadas a todos los formularios de la tabla.
-
Seleccione Nuevo. Se abre el diseñador de reglas.
-
Escriba un nombre para mostrar. El nombre lógico se rellena solo, con el prefijo de su editor, y queda fijo una vez guardada la regla.
-
Compruebe el formulario. Ya es el formulario desde el que llegó, lo que casi siempre es lo correcto: una regla habla de campos, y los campos de los que habla son los que tiene delante. Cámbielo a Todos los formularios para algo que deba cumplirse allí donde se muestre la tabla, como «ocultar esto salvo que el estado sea Aprobado». Una regla vinculada a todos los formularios sigue apareciendo en la lista Eventos de cada formulario, marcada como tal.
-
Elija cuándo se ejecuta, un evento por regla:
- Al abrir el formulario aplica la regla cuando se muestra el registro.
- Al cambiar un campo muestra un selector de campos. Elija un campo y aparecerá como una etiqueta; agregue tantos como necesite la regla y quite uno con la ✕ de su etiqueta.
- Al guardar el formulario ejecuta la regla entre la pulsación y la escritura, de modo que
puede rellenar algo o detener el guardado con
cancelSave, más abajo.
Una regla sin desencadenador nunca se ejecuta, así que Guardar permanece deshabilitado hasta que una regla de cambio de campo tenga al menos un campo.
Un evento por regla es deliberado. Cuando lo mismo tiene que ocurrir en dos momentos (el caso habitual, «mostrar esto cuando el estado sea rechazado», que debe ser correcto al abrir el formulario y cada vez que cambia el estado), escriba dos reglas que importen un mismo script de solución, cada una de dos líneas. La lógica se escribe una vez; donde los dos momentos realmente difieren, el script consulta
eventType()y decide por sí mismo. Varios desencadenadores en una misma regla no pondrían esa decisión en ningún sitio: nada en la pantalla diría qué mitad del script corresponde a qué evento. -
Escriba el script en el editor. Subraya los errores mientras escribe, completa las funciones de la plataforma y muestra los argumentos de cada una al escribir el paréntesis de apertura. El ojo de la esquina superior del editor abre Qué puede llamar un script sobre el código.
-
Deje marcada Habilitada, o desmárquela para conservar la regla sin ejecutarla.
-
Seleccione Guardar.
Qué puede llamar un script
| Llamada | Qué hace |
|---|---|
getValue(field) | El valor actual del campo en el formulario. |
setValue(field, value) | Establece un campo en el formulario. |
setVisible(field, visible) | Muestra u oculta un campo. |
setDisabled(field, disabled) | Hace que un campo sea de solo lectura, o no. |
setRequired(field, required) | Hace que un campo sea obligatorio, o no. |
eventType() | "OnLoad", "OnChange" u "OnSave": qué evento se está ejecutando. |
changedField() | El campo cuyo cambio desencadenó un OnChange; en otro caso, "". |
isNewRecord() | true hasta que el registro se ha guardado una vez. Úselo para bloquear un campo que se elige una vez y luego no cambia, como el tipo de una actividad. |
cancelSave(message) | Solo al guardar: detiene el guardado de este formulario y muestra el mensaje. |
isEmpty(value) | Si un valor está sin rellenar. El texto en blanco y la ausencia de valor están vacíos; 0 y false son valores que alguien eligió. |
Un campo se nombra por su nombre lógico (par_amount), no por su nombre para mostrar.
Un campo sin nada se lee como texto vacío, así que getValue("par_currency") == "" es la
comprobación de «todavía sin rellenar»; así funciona el ejemplo de la moneda más abajo. Para un
número, una fecha o una búsqueda no hay texto vacío con el que comparar, así que use en su lugar
isEmpty(getValue("par_due")). Usa la misma definición de vacío que la comprobación de
obligatoriedad del propio formulario, por eso una regla no puede dar un valor predeterminado a un
campo que el formulario acaba de aceptar como relleno.
getValue y setValue se escriben y se comportan exactamente igual que en un paso de complemento
de servidor, así que la lógica que elabore una vez se lee igual en ambos lados.
Un campo numérico se lee como número (1200.5, no "1200.5"), incluso mientras se está
escribiendo, y uno sin rellenar se sigue leyendo como vacío. Eso importa en cuanto escribe una
función propia: func needsApproval(amount: number) no aceptará un texto, y el error es
Function overload for needsApproval not found. en lugar de algo sobre tipos. Así que declare un
importe como number, no como int (una columna Decimal contiene 1200.50, y un parámetro de
número entero lo rechaza), y ponga un cero en lugar de un cuadro vacío antes de hacer aritmética con
él:
func claimAmount(): number {
var raw = getValue("par_amount");
if (isEmpty(raw)) { return 0; }
return raw;
}
…y todo lo que exporta un script de solución. Cuando las mismas pocas líneas empiezan a
aparecer en varias reglas, muévalas a un script de solución e
impórtelo escribiendo import 'par_expense_helpers'; al principio de la regla: el editor completa
el nombre y, a partir de ahí, sabe lo que exporta el módulo.
Opciones, y mostrar una sección para una de ellas
Una opción se lee como su número, el valor que se dio a la opción (110000001), tanto si el
formulario se acaba de abrir como si alguien acaba de elegirla. Así que compárela con un número, no
con un texto:
if (getValue("pw_type") == 110000001) { setVisible("pw_to", true); }
Antes, una opción que alguien acababa de elegir se leía como texto ("110000001"), y la
comparación anterior dejaba de funcionar discretamente tras la primera elección. A una regla que
comparaba con un texto entre comillas hay que quitarle las comillas.
Para mostrar una sección solo para una opción, oculte los campos que contiene. Una sección cuyos campos están todos ocultos desaparece, con título incluido, y vuelve cuando una regla muestra de nuevo uno de ellos. Así es como el formulario de actividades de Sales muestra una sección de correo electrónico para un correo y una sección de llamada telefónica para una llamada.
Para que un campo se pueda elegir una sola vez, deshabilítelo cuando el registro no sea nuevo:
setDisabled("pw_type", !isNewRecord());
Cuando se guarda un registro nuevo, las reglas que se ejecutan al abrir vuelven a ejecutarse, así que el campo queda bloqueado de inmediato. Como toda regla, esto solo detiene al formulario. Para impedir que la API o una importación cambien también el campo, escriba además un paso de complemento de servidor.
Detener un guardado
Una regla que se ejecuta al guardar el formulario puede rechazar el guardado:
if (getValue("par_status") == "rejected" && getValue("par_reason") == "") {
cancelSave("Give a reason before rejecting this claim.");
}
El guardado se detiene, su mensaje aparece en la parte superior del formulario y no se pierde nada: el formulario sigue abierto con todo lo escrito.
Esto sigue sin ser una imposición. Detiene este formulario, en este navegador: la API, una importación, una aplicación personalizada y cualquier otro formulario sin la regla guardan el registro de todos modos. Existe porque «no me dejes enviar esto a medio rellenar» merece decirse en el formulario, pero si algo debe ser cierto de los datos, escriba además un paso de complemento de servidor.
Un ejemplo
Mostrar el campo del responsable, y hacerlo obligatorio, solo en gastos de más de 100, al abrir y cada vez que cambie el importe:
var over = getValue("par_amount") > 100;
setVisible("par_manager", over);
setRequired("par_manager", over);
Observe que indica lo que debe ser cierto en ambos sentidos. Una regla que solo muestra un campo lo dejará en pantalla cuando el importe vuelva a bajar, porque nada pidió que se ocultara de nuevo.
Dos reglas en un mismo formulario
Se ejecutan todas las reglas habilitadas que coinciden con el formulario y el evento, por orden de nombre lógico, cada una con sus propias variables. Comparten los valores del formulario, así que las reglas posteriores ven lo que establece una regla. Si dos reglas hablan del mismo campo, gana la última, lo cual es estable, pero es una coincidencia y no un diseño, así que es preferible una regla por campo.
Una regla no puede ejecutarse para siempre
Cada regla se ejecuta con un presupuesto, y una regla que lo supera se detiene y se notifica con su propio nombre. Hay tres límites, y cada uno detecta un error distinto:
| Detiene | Cuando |
|---|---|
| un bucle que nunca termina | while (true), o una condición que nunca llega a cumplirse |
| una regla que simplemente hace demasiado | sigue en marcha pasado medio segundo |
| una función que se llama a sí misma sin fin | lleva cien llamadas de profundidad sin final a la vista |
El formulario sigue funcionando, la persona conserva lo que estuviera escribiendo y el mensaje
nombra la regla y la línea. Envolver el bucle en un try no sirve: el presupuesto no es algo que un
script pueda capturar.
No se lo encontrará por accidente: la regla más grande de cualquier ejemplo usa mucho menos de una
centésima parte de lo permitido. Si se lo encuentra, la regla tiene un error, casi siempre un
while cuya condición nunca cambia el cuerpo.
Una nota sobre la comparación de valores. == compara dentro de un mismo tipo: dos números, dos
textos, dos valores verdadero/falso. Dos tipos distintos nunca son iguales (1 == "1" es falso),
y nada es igual a nada, así que un campo sin establecer no es igual a "". Por eso un campo sin
valor se lee como texto vacío, y por eso existe isEmpty() para números y fechas.
Solución de problemas
- Una regla que parece no ejecutarse nunca. Compruebe que está habilitada, que su vinculación a un formulario coincide con el formulario que está mirando y que su desencadenador incluye el campo que está cambiando.
- «BS Lang script is invalid: …» al guardar — el script no se puede analizar. El editor subraya el mismo error; el mensaje nombra la línea.
- «Form '…' was not found on '…'.» — la regla está vinculada a un formulario que la tabla no tiene. Elija uno de la lista o vincúlela a todos los formularios.
- Un mensaje rojo en la parte superior de un formulario en la aplicación, que nombra una regla. La regla generó un error al ejecutarse. El formulario sigue funcionando; la regla se detuvo donde falló.
- Subrayados bajo
getValue— el editor ya no indica que las funciones propias de la plataforma no están definidas. Si ve esto, el script está llamando a algo que no está en la lista anterior.
Escenarios relacionados
- Crear un formulario.
- Hacer que un campo sea obligatorio o de solo lectura: la versión fija de la misma idea, para cuando la respuesta nunca depende del registro.