Documentation pour la conception de base de données
Comment pouvons-nous vous aider ?
Recherche intégrale du site

Moteur de flux de travail JavaScript

Tous les formulaires peuvent déclencher le moteur de flux de travail JavaScript côté serveur de Ragic pour exécuter une logique métier complexe, comme le calcul des coûts et la mise à jour des soldes d'inventaire. De fait, toute logique métier complexe que vous souhaitez exécuter mais qui n'est pas couverte par les fonctions existantes peut être prise en charge par le scripting côté serveur.

Le moteur de script est basé sur le moteur de script JavaScript standard Nashorn inclus dans la plateforme Java. Nashorn prennant en charge ECMAScript 5.1, il est donc conseillé d'éviter la syntaxe ECMAScript 6.

Que fait un flux de travail Javascript ?

L'interface de conception de feuille de calcul de Ragic offre une solution efficace pour la gestion courante des données, notamment la création, la modification et l'interrogation des enregistrements. Cependant, la maintenance manuelle des données peut s'avérer chronophage et répétitive à long terme. Il devient alors pertinent d'envisager l'automatisation de ces processus.

Ragic intègre un puissant moteur de script permettant l'exécution de code JavaScript côté serveur. Cette fonctionnalité permet de manipuler les données présentes dans votre feuille de calcul, d'effectuer des modifications et de générer de multiples enregistrements en une seule opération. Parmi les applications courantes, on peut citer la mise à jour des stocks, la génération d'enregistrements dérivés (tels que la création d'une commande client à partir d'un devis ou d'un contact à partir d'un prospect commercial), ainsi que la validation d'enregistrements basée sur les données existantes dans la base.

Il y a 5 principales façon d'exécuter un flow Javascript :

  1. Bouton d'action
  2. Flux de post-exécution
  3. Flux de pré-exécution
  4. Flux de travail quotidien
  5. Flux de travail d'approbation

Et il y a aussi un Flux de travail global où vous pouvez placer des définitions de fonctions JavaScript communes partagées par plusieurs de vos scripts.

Bouton d'action

C'est la méthode la plus courante et la plus propre pour exécuter un flux de travail Javascript, et généralement celle que nous recommandons. Vous pouvez écrire votre script dans laportée de la feuille installée de votre feuille, et configurer un bouton d'action pour exécuter le script lorsque l'utilisateur clique sur le bouton qui s'affichera dans le panneau "Actions" en bas à droite.

Pour ajouter un script dans une feuille installée, il vous suffit de faire un clic droit sur une feuille, puis de sélectionner Flux de travail JavaScript:

Et choisir Installed sheet scope (portée de la feuille installée) dans le menu déroulant du haut :

Vous pouvez ensuite accéder à la page formulaire de votre design de feuille, ajouter un bouton d'action de type Flux de travail JavaScript, et faire référence à la fonction JavaScript que vous avez écrite.

Vous pouvez passer l'identifiant de l'enregistrement actuel en utilisant {id} dans l'argument de l'appel de fonction, en faisant comme ceci :

setStatus({id})

Nous reviendrons plus en détail sur la manière d'écrire ces fonctions dans les sections suivantes

Flux de post-exécution (post-workflow)

Les flux de post-exécution sont exécutés après la sauvegarde d'un enregistrement. Avec le flux de post-exécution, il est très facile d'automatiser les modifications que vous souhaitez apporter à l'enregistrement que vous venez d'enregistrer et qui ne peuvent pas être effectuées avec des formules. Autrement, vous pouvez également apporter des modifications aux enregistrements sur d'autres feuilles liées, comme la mise à jour du solde des stocks.

Pour ajouter un flux de post-exécution, vous devez faire un clic droit sur une feuille, puis sélectionner Flux de travail JavaScript:

Et choisir Flux de post-exécution dans le menu déroulant du haut.

Un flux de post-exécution typique ressemble à :

var recordId = param.getNewNodeId(key_field_id_of_form);
var query = db.getAPIQuery(path_to_form);
var record = query.getAPIEntry(id);

// do what you would like to do with the record retrieved 

Consultez nos références API et les autres sections de ce document pour la liste des actions que vous pouvez effectuer.

De même, il faut souligner qu'un flux de post-exécution ne sera pas exécuté si vous modifiez des entrées sur la page liste.

Flux de pré-exécution (pre-workflow)

Les flux de pré-exécution interviennent avant la sauvegarde d'un enregistrement, constituant ainsi une méthode de validation des données saisies par rapport au contenu de la base de données. La majorité des validations peut être réalisée via les contrôles d'expressions régulières côté client ou en activant l'option d'unicité pour les champs de texte libre. Néanmoins, pour des vérifications plus complexes nécessitant un traitement côté serveur, le recours à un flux de pré-exécution peut s'avérer indispensable.

Pour ajouter un flux pré-exécution, vous devew faire un clic droit sur une feuille et sélectionner Flux de travail Javascript:

Et de choisir Flux pré-exécution dans le menu déroulant du haut.

Voici un exemple simple :

Admettons que nous ayons une liste,

et nous voulons nous assurer que le prix voulu ne soit pas négatif.

/**

 * Key Field: 1000004

 * Field Name    Field Id
 * - - - - - - - - - - - --------
 * ID           : 1000001
 * Price        : 1000002
 * Name         : 1000003
 * Available ?  : 1000005

 */
function log(str) {
  // set status 'INVALID' or 'ERROR' to cancel the saving.
  response.setStatus('INVALID');
  response.setMessage(str);
}

function ifThePriceIsNegative() {
    // get the price we trying to save.
    var newPrice = param.getNewValue(1000002);
    // change the newPrice string to integer.
    if(parseInt(newPrice) < 0) {
      return true;
    }
}

// if the price is negative, don't save it.
if(ifThePriceIsNegative()) {
  log('Price is negative !!');
}

Maintenant, lorsque nous essayons de sauvegarder un prix négatif, nous obtenons :

Il est important de noter que nous ne pouvons pas utiliser entry.getFieldValue lors de l'écriture d'un flux pré-exécution (car Ragic ne l'a pas encore enregistré). Essayez plutôt d'utiliser param pour obtenir l'ancienne valeur et la nouvelle valeur.

Flux de travail quotidien (daily workflow)

Le flux de travail quotidien s'exécute quotidiennement. Il est utile pour effectuer des modifications qui doivent être actualisées chaque jour, comme la mise à jour des résultats des formules en fonction de la date actuelle.

Pour ajouter un flux de travail quotidien, il suffit de faire un clic droit sur un onglet et sélectionnez Flux de travail JavaScript global:

Et de choisir Flux de travail quotidien dans le premier menu déroulant du haut.

Par défaut, le flux de travail quotidien s'exécute à 19h00 UTC. Vous pouvez modifier l'heure d'exécution et le fuseau horaire dans les Paramètres d'organisation:

1. Accédez à Configuration du compte

2. Cliquez sur Paramètres d'organisation

3. Sélectionnez Fuseau horaire local de l'entreprise et Heure d'exécution par défaut des tâches planifiées puis sauvegardez.

Si vos Paramètres d'organisation n'ont pas Fuseau horaire local de l'entreprise et Heure d'exécution par défaut des tâches planifiées, veuillez s'il vous plaît nous contacter pour que nous mettions à jour vos flux de travail.

Flux de travail d'approbation

Les flux de travail d'approbation sont exécutés immédiatement après qu'une approbation est créée, rejetée, annulée ou finalisée.

Pour ajouter un flux de post-exécution, il suffit de faire un clic droit sur une feuille et de sélectionner flux de travail Javascript:

Et de choisir Flux de travail d'approbation depuis le menu déroulant du haut.

Vous pouvez obtenir l'identifiant d'un enregistrement avec:

var recordId = approvalParam.getEntryRootNodeId();

approvalParam is a predefined variable in the approval workflow scope.


Et vous pouvez récupérer l'action d'approbation avec :

var action = approvalParam.getApprovalAction();

Après avoir obtenu les données ci-dessus, vous pouvez personnaliser vos demandes de la manière suivante :

var query = db.getAPIQuery(path_to_form);
var entry = query.getAPIEntry(id);
if (action === 'CANCEL') {
    entry.setFieldValue(STATUS_FIELD, "approval is canceled!");
}
if (action === 'FINISH') {
    entry.setFieldValue(STATUS_FIELD, "approval is completed!");
}

Flux de travail global

Le flux de travail global est un espace où vous pouvez rédiger des modules de flux de travail en JavaScript que d'autres fonctions de flux de travail peuvent utiliser en référence. Il ne s'exécute pas seul, mais peut être référencé dans n'importe quel type de workflow mentionné précédemment. C'est un espace idéal pour regrouper des scripts que vous pourriez avoir besoin de réutiliser sur plusieurs feuilles.

Pour ajouter un flux de travail global, il vous suffit de faire un clic droit sur un onglet, puis de choisir Flux de travail JavaScript global:

Obtenir un enregistrement

Il existe deux façons différentes d'obtenir l'enregistrement actuel que l'utilisateur est en train de visualiser (pour les boutons d'action) ou que l'utilisateur vient de sauvegarder (pour les flux pré-exécution et les flux post-exécution).

Bouton d'action

Sur la page formulaire, le bouton d'action fonctionne en configurant un bouton pour appeler une fonction que vous avez définie dans la portée de la feuille d'installation. Lorsque vous définissez cette fonction, vous pouvez passer un paramètre {id} qui correspond à l'identifiant de l'enregistrement sur lequel vous cliquez pour déclencher le bouton d'action dans le flux de travail.

Vous pouvez consulter l'exemple dans Flux de travail et bouton d'action.

Flux de pré-exécution

Vous pouvez obtenir l'identifiant de l'enregistrement en :

var recordId = param.getNewNodeId(key_field_id_of_form);

Param est une variable pré-définie que vous pouvez utiliser dans les pré-flux de travail et les post-flux de travail.


Après avoir obtenu l'identifiant de l'enregistrement, voici comment vous obtenez l'enregistrement (entrée) :

var query = db.getAPIQuery(path_to_form);
var entry = query.getAPIEntry(id);

Flux post-exécution

Pour les flux post-exécution, vous pouvez d'abord utilisez la méthode décrite ci-dessus pour les flux pré-exécution. Mais il existe aussi une autre manière assez pratique de récupérer un enregistrement venant d'être sauvegardé :

var entry=param.getUpdatedEntry();

Si des champs sont masqués sur la page formulaire, vous obtiendrez par défaut des valeurs masquées. Vous pouvez obtenir les valeurs non masquées en :

var query = db.getAPIQuery(path_to_form);
query.setUpdateMode();
query.setIgnoreAllMasks(true); // Unmask all masked fields.
var entry = query.getAPIEntry(id);

Vous pouvez utiliser query.addIgnoreMaskDomain(identifiant_du_champ_masqué) au lieu de query.setIgnoreAllMasks(true) pour démasquer des champs spécifiés.

La section suivante vous montrera des informations détaillées sur la mise à jour des enregistrements.

Si vous souhaitez filtrer plusieurs enregistrements, veuillez vous référer à la section sur le filtrage.

Faire une requête pour un ensemble d'enregistrements

Si vous souhaitez obtenir plus d'un enregistrement en filtrant :

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];
  // ...
}

Vous pouvez ajouter des filtres à la requête avec addFilter(identifiant_du_champ, opérateur, valeur), puis appeler getAPIResultList() pour obtenir la liste des enregistrements.

Voici la liste des opérateurs que vous pouvez utiliser :

Nom de l'opérateur Valeur de l'opérateur
Egal =
Expression régulière regex
Supérieur ou égal
Inférieur ou égal <=
Supérieur
Inférieur <</td>
Contiens like

Veuillez noter que quand vous filtrer par date ou heure, ces valeurs doivent être saisies selon les formats:aaaa/MM/jj ou aaaa/MM/jj HH:mm:ss

Vous pouvez également utiliser une recherche en texte intégral comme filtre de requête en appelant setFullTextSearch(String queryTerm) au lieu de addFilter().

Mettre à jour des enregistrements

Lien vers l'exemple

Commençons par un exemple simple consistant à récupérer l'enregistrement actuel sous forme d'objet, mettre à jour sa valeur avec un bouton, puis à le sauvegarder dans la base de données. Voici à quoi ressemble le formulaire de démonstration :

Nous voulons créer des boutons qui changeront la valeur de notre champ statut avec un simple clic, en exécutant un flux de travail JavaScript côté serveur. Voici le code derrière le bouton :

/**

 * AP_Name:wfdemo
 * Key Field: 1000013

 * Name             ID
 * - - - - - - - - - - - --------
 * No.            : 1000011
 * Status         : 1000012

 */
function setStatus(recordId, status) {

  var STATUS_FIELD = 1000012;	//field id of the status field
  var query = db.getAPIQuery("/workflow-demo/2");	//get the query object for a sheet with path to sheet
  var entry = query.getAPIEntry(recordId);	//get the record object for the current record

  //set the status value for the current record to the object
  if (status) {
	entry.setFieldValue(STATUS_FIELD, status);
  }
  else {//for switching
    var newStatus = entry.getFieldValue(STATUS_FIELD) == 'On' ? 'Off' : 'On';	//get the current value of a field
	entry.setFieldValue(STATUS_FIELD, newStatus);
  }

  //save the record back to the database
  entry.save();
}

Lors de l'écriture d'un flux de travail JavaScript, la variable db est prédéfinie et vous pouvez y faire référence n'importe où. En général, nous utilisons la méthode getAPIQuery(pathName) pour récupérer l'objet de requête d'une feuille.

Ensuite, vous pouvez récupérer un enregistrement avec son identifiant d'enregistrement sur l'objet de feuille avec getAPIEntry(identifiantEnregistrement), et appelersetFieldValue(identifiantChamp,valeur) pour définir la valeur d'un champ, ou getFieldValue(identifiantChamp) pour récupérer la valeur d'un enregistrement.

Veuillez noter que lors de l'ajout de valeurs de date, elles doivent être dans l'un des formats suivants :

aaaa/MM/jj

aaaa/MM/jj HH:mm:ss

HH:mm:ss

Si vous récupérez une valeur d'un champ de sélection multiple qui, par définition, peut héberger avoir plusieurs valeurs, utilisez getFieldValues(identifiantChamp) pour récupérer toutes les valeurs dans un tableau. Vous pouvez également appeler setFieldValue(identifiantChamp, valeur, vrai) avec un argument Vrai supplémentaire à la fin pour spécifier que vous "ajoutez" une option à la liste actuelle des valeurs, sans écraser celles existantes. Notez que ces opérations ne conviennent qu'aux champs de sélection multiples.

Si vous souhaitez copier la valeur d'un champ de sélection multiple et écraser la valeur dans un autre champ de sélection multiple, vous ne pouvez pas utiliser getFieldValues(identifiantChamp) et setFieldValue(identifiantChamp, valeur, true). Voici le code auquel vous devez vous référer :


var multipleSelectionFieldValue = entry.getFieldValues(1013251); // 1013251 is a mutiple selection field 

var targetMultipleSelectionField = "";

for (var i = 0; i < multipleSelectionFieldValue.length; i++) {  
  
        if (i == 0) {
          
          targetMultipleSelectionField = targetMultipleSelectionField + multipleSelectionFieldValue[i];
          
        } 
  
        else {
        
          targetMultipleSelectionField = targetMultipleSelectionField + "|" + multipleSelectionFieldValue[i];
          
        }
        
}

entry.setFieldValue(1013252, targetMultipleSelectionField, false); // 1013251 is another mutiple selection field 

Remarquez qu'il est nécessaire de récupérer chaque option et de formater ces options avec un caractère de barre verticale (|), comme vous le feriez lors de l'importation de données existantes à partir de fichiers Excel ou CSV.

Si vous définissez des valeurs pour un champ de téléchargement de fichier, vous pouvez utiliser setFieldFile(int identifiantChamp, String nomFichier, String contenuFichier) pour créer un fichier avec le nomFichier et avec le contenuFichier que vous avez fourni. Ragic enregistrera ensuite ce fichier dans ce champ afin que le fichier soit disponible en téléchargement dans l'interface utilisateur.

Une fois que vous avez terminé, appelez simplement sauvegarder() sur l'objet d'enregistrement pour le sauvegarder dans la base de données.

Création d'enregistrements

La création d'enregistrements est similaire à la mise à jour d'enregistrements. Au lieu d'appeler query.getAPIEntry(), il faut appelerquery.insertAPIEntry(). Comme pour getAPIEntry(), cela renverra un enregistrement sur lequel vous pouvez utiliser setFieldValue pour ajouter des valeurs de champ. L'enregistrement sera créé après l'appel à record.save().

Une simple modification de la démonstration de mise à jour d'enregistrement créera à la place un nouvel enregistrement :

/**

 * AP_Name:wfdemo
 * Key Field: 1000013

 * Name             ID
 * - - - - - - - - - - - --------
 * No.            : 1000011
 * Status         : 1000012

 */
function setStatus(recordId, status) {

  var STATUS_FIELD = 1000012; //field id of the status field
  var query = db.getAPIQuery("/workflow-demo/2"); //get the query object for a sheet with the path to sheet
  var entry = query.insertAPIEntry();  //create a new record object

  //create the new record to the database
  entry.save();
}

Sous-tables

Lien vers l'exemple

Si vous avez une sous-table dans votre feuille, vous pouvez également utiliser notre API pour récupérer des données ou apporter des modifications comme dans l'exemple suivant. Le formulaire ressemble alors à ceci :

Le flux de travail parcourera chaque ligne de la sous-table pour trouver le montant total de cette année (selon le champ de date dans le sous-tableau), le total pour l'année avec le montant le plus élevé, et identifiera quelle année a le total le plus élevé. Cela est conçu comme un flux post-exécution, donc les trois champs en lecture seule seront remplis par le flux de travail après la sauvegarde de l'enregistrement.

/**

 * 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();

L'idée fondamentale est d'utiliser getSubtableSize(identifiantSousTable) pour obtenir le nombre de lignes pour un enregistrement, et d'utiliser getSubtableFieldValue(identifiantSousTable, indiceLigneSousTable, identifiantChampSousTable) pour récupérer leurs valeurs. Vous devriez pouvoir trouver l'identifiant de la sous-table et l'identifiant du champ dans les commentaires auto-générés lorsque vous commencez à modifier les scripts du flux de travail.

Vous pouvez également utiliser setSubtableFieldValue(identifiantChampSousTable, identifiantRacineSousTable, valeur) pour définir des valeurs dans un sous-tableau. L'identifiantRacineSousTable est utilisé pour spécifier la ligne de sous-table à laquelle vous faites référence. Pour trouver un identifiantRacineSousTable pour une ligne de sous-table existante, vous pouvez utiliser l'appel suivant getSubtableRootNodeId(identifiantSousTable, indiceLigneSousTable) qui renverra un entier contenant l'identifiantRacineSousTable.

Si vous avez besoin d'ajouter une ligne à votre sous-table, vous pouvez utiliser un identifiant de racine de sous-table négatif comme -100. De cette manière, toutes les valeurs définies avec le même identifiant de racine de sous-table négatif seront appliquées à la même nouvelle ligne de sous-table. Les valeurs définies avec un identifiant de racine de sous-table négatif différent, comme -101, créeront une autre ligne dans la sous-table avec cet ensemble de valeurs différent.

Flux de pré-exécution et flux de post-exécution

Si vous souhaitez obtenir des valeurs dans les flux de pré-exécution et ceux de post-exécution, il suffit de suivre cet exemple :

var list = param.getSubtableEntry(AMOUNT_SUBTABLE_ID);
var arr = list.toArray();
response.setStatus('WARN');
for (var i = 0; i < arr.length; i++) {
  response.setMessage('Date : '+arr[i].getNewValue(DATE_FIELD)+', Amount : '+arr[i].getNewValue(AMOUNT_FIELD)+'\r\n');
}

Copier des enregistrements

Liens vers les exemples : Copier depuis et Copier vers

La copie d'enregistrements est l'un des programmes de flux de travail les plus courants. Nous avons donc écrit une fonction pour simplifier ce type d'opération. Supposons que nous voulions voir un enregistrement sur cette feuille :

En cliquant simplement sur le bouton, vous pouvez générer un enregistrement sur cette feuille :

Voici le code pour le bouton d'action :

/**

 * 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);
}

Ici, vous pouvez voir que nous pouvons effectuer la copie avec un simple appel de fonction entryCopy. entryCopy prend une chaîne JSON comme paramètre. Il suffit de spécifier la feuille source, la feuille cible, l'enregistrement que nous copions, et surtout, quel champ doit être associé à quel champ. Lorsque la correspondance est complète, vous pouvez créer facilement des boutons d'action pour copier des enregistrements d'une feuille à l'autre.

Prenons maintenant un autre exemple.

Ici, nous voulons copier Lin de "Copier depuis" à "Copier vers" et définir le statut sur "nouveau". De plus, nous voulons également enregistrer la date de création (veuillez dans cet exemple ignorer l'utilisation du champ $DATE).

/**
 * field name      field id
 * - - - - - - - - - - - --------
 * From-ID        : 1000001
 * From-Name      : 1000002
 * To-ID          : 1000004
 * To-Name        : 1000005
 * Status         : 1000007
 * RegisterDate   : 1000008
 */

function copyEntry(nodeId) {
  db.entryCopier(JSON.stringify({
    THIS_PATH:"/entrycopier/1",
    THIS_NODEID:nodeId,
    NEW_PATH:"/entrycopier/2",
    COPY:{
      //       to  :  from
      1000004:1000001,   
      1000005:1000002,   
    }
  }),response);
  //get the rootNodeId of the entry we copied before.
  var newEntryRootNodeId = response.getRootNodeId();
  //we need to create an ApiQuery to search the '/entrycopier/2'
  var toApiQuery = db.getAPIQuery('/entrycopier/2');
  //get the entry we copied before
  var newEntry = toApiQuery.getAPIEntry(newEntryRootNodeId);
  newEntry.setFieldValue(1000007, "New");
  var current = new Date();
  newEntry.setFieldValue(1000008, current.getFullYear()+'/' + (current.getMonth()+1) + '/' + current.getDate());
  newEntry.save();
}

Ensuite, configurez le bouton d'action et enregistrez-le.

Après, cliquez simplement sur le bouton d'action pour afficher le résultat.

Vérification des droits d'accès de l'utilisateur

Vous pouvez effectuer un traitement conditionnel basé sur les groupes auxquels appartient l'utilisateur qui exécute le script. Un utilisateur peut être membre de plusieurs groupes d'utilisateurs, donc nous utilisons habituellement un appel user.isInGroup(groupName) pour déterminer si l'utilisateur est ou n'est pas dans ce groupe. Voici un exemple typique : le code suivant est conçu pour être un flux pré-exécution, mais un objet utilisateur et un appel à isInGroup peuvent être utilisés dans tous les types de flux de travail, à l'exception du flux de travail quotidien déclenché par le système.

if(!user.isInGroup('SYSAdmin')){//check if the user is a SYSAdmin
  response.setStatus('INVALID');//if they are not, do not save the record
  response.setMessage('You do not have the access right to do this.');//and display a message
}

Envoi de notifications par e-mail

Dans certains cas, vous voulez envoyer des notifications par e-mail en fonction d'un ensemble de conditions, ou personnaliser le contenu de vos messages de notification. Pour cela, vous pouvez rédiger un flux de travail JavaScript côté serveur. Voici le script que vous utiliserez pour envoyer un e-mail, c'est très 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();

Si vous souhaitez envoyer un e-mail à plusieurs destinataires, il vous suffit de séparer chaque adresse e-mail par des virgules.

Pour les pièces jointes, vous pouvez utiliser mailer.attach(monURL); pour attacher un enregistrement sur Ragic en utilisant l'URL de l'enregistrement. Pour illustrer, voici une URL d'enregistrement sur Ragic (ignorez toujours l'URL après le dièse) :

https://www.ragic.com/wfdemo/workflow-demo/2/9

Voici l'URL en version imprimable HTML :

https://www.ragic.com/wfdemo/workflow-demo/2/9.xhtml

Voici l'URL en version Excel :

https://www.ragic.com/wfdemo/workflow-demo/2/9.xlsx

Vous pouvez également utiliser une URL de publipostage similaire à celle-ci. Le cid représente l'identifiant de publipostage, que vous pouvez trouver dans l'URL lorsque vous essayez de télécharger le document de publipostage :

https://www.ragic.com/wfdemo/workflow-demo/2/9.custom?rn=9&cid=1

Nous devons limiter le nombre d'e-mails que vous pouvez envoyer. Il suffit de rester raisonnable ! Si vous avez des questions sur les quotas d'envoi d'e-mails, envoyez-nous un e-mail à l'adresse support@ragic.com.

Créer et annuler une approbation

Vous pouvez démarrer ou annuler l'approbation d'un enregistrement en ajoutant le script post-exécution à votre feuille.

Il faut d'abord configurer l'étape d'approbation dans le mode design.

puis configurer les détails de l'approbation dans le flux post-exécution.

function autoStartApprover() {
  var signers = [];
  signers.push({
    'stepIndex':'0',
    'approver':'kingjo@ragic.com',
    'stepName':'START'
  });
  signers.push({
    'stepIndex':'1',
    'approver':'HR0000@hr.hr',
    'stepName':'HR'
  });
  
  approval.create(JSON.stringify(signers));
}

autoStartApprover();

Résultat

{
    'stepIndex':'0',
    'approver':'kingjo@ragic.com',
    'stepName':'START'
}

est le format de paramètre que vous devez fournir.

stepIndex :

Utilisé pour savoir quelle étape d'approbation définir, en partant de zéro.

approver :

Utilisé pour savoir qui doit signer cette étape d'approbation.

stepName :

Utilisé pour définir le nom de l'étape d'approbation.

Votre approbation ne serait pas créée s'il y a des erreurs dans le format des paramètres ou si les approbateurs que vous avez fournis ne suivaient pas la règle que vous avez définie dans le mode de design.

Dans cet exemple, si vous fournissez le paramètre de la deuxième étape de la manière suivante :

{
    'stepIndex':'1',
    'approver':'kingjo@ragic.com',
    'stepName':'HR'
}

Si c'est le cas, l'exemple va échouer car kingjo@ragic.com n'est pas dans le groupe HR.

Nous vous proposons également trois formats spéciaux pour décider dynamiquement vos approbateurs en fonction de de l'arborescence de votre organisation.

Vous pouvez consulter ce document pour plus d'information.

$DS :

Le superviseur direct de l'utilisateur sera défini comme approbateur.

$SS :

Le superviseur du superviseur de l'utilisateur sera défini comme approbateur.

$DSL :

Le superviseur de l'approbateur précédent sera défini comme approbateur.

Le format du paramètre est :

{
    'stepIndex':'1',
    'approver':'$DSL',
    'stepName':''
}

Vous n'avez pas besoin de fournir un nom d'étape non-vide lorsque vous utilisez ces formats spéciaux.

Remarque : dans un format spécial, si l'utilisateur ne suit pas la règle que vous avez définie dans le mode design, cet approbateur ne sera pas créé.

Envoyer des notifications sur l'application mobile

En plus des notifications par e-mail, vous avez également la possibilité d'envoyer des notifications vers l'application mobile. Celles-ci seront transmises à l'utilisateur si l'application iOS ou Android est installée sur son appareil. L'e-mail est associé à l'adresse e-mail de l'utilisateur enregistrée dans votre compte Ragic. Par exemple :

mailer.sendAppNotification("mike@example.com","test mobile notification");

Si vous souhaitez que l'utilisateur soit redirigé vers l'enregistrement spécifié lorsqu'il clique sur cette notification, vous devez fournir un chemin vers le formulaire vers lequel vous souhaitez rediriger (par exemple : /forms/1) et l'identifiant de l'enregistrement. L'appel ressemblera à :

mailer.sendAppNotification("mike@example.com","test mobile notification","/forms/1",12);

Approbateur et autres informations concernant un enregistrement

Vous pouvez d'abord exécuter la commande suivante sur l'objet de requête que vous obtenez de db.getAPIQuery pour inclure toutes les informations sur l'enregistrement :

query.setIfIncludeInfo(true);

et ensuite vous pouvez obtenir les informations sur l'approbation pour un enregistrement :

entry.getFieldValue('_approve_status');//getting status of current approval
entry.getFieldValue('_approve_next');//getting the next person who should sign this record
entry.getFieldValue('_create_date');//getting the create date of the record
entry.getFieldValue('_create_user');//getting the create user e-mail of the record

Le statut d'approbation sera F si approuvé, REJ pour rejeté et P pour en cours de traitement.

Afficher un message

Vous pouvez afficher un message dans une fenête pop-up comme ci-après. Veuillez noter que le message ne s'affichera que lorsque le statut de réponse sera "WARN". Par défaut, le message à l'intérieur de l'objet de réponse ne sera pas affiché car il n'est généralement pas utile pour les utilisateurs finaux.

response.setStatus('WARN');
response.setMessage(message);

La pagination

Dans cette section, nous avons un exemple qui illustre comment utiliser setLimitSize et setLimitFrom. Dans cet exemple, nous avons un total de 20 entrées, voulons prendre 6 pour chaque compte et afficher le message.

/**

 * Field Name    Field Id
 * - - - - - - - - - - - --------
 * ID           : 1000009
 * Money        : 1000010

 */
function limitFromExample() {
    var apiQuery = db.getAPIQuery('/entrycopier/3');
    // remember the offset
    var fromNumber = 0;
    apiQuery.setLimitFrom(fromNumber);
    // take 6 for each count
    apiQuery.setLimitSize(6);
    var resultList = apiQuery.getAPIResultList();
  
    while(resultList.length > 0) {
        var msg = ''; 
        for(var i = 0;i < resultList.length; i++) {
            var entry = resultList[i];
            msg += entry.getFieldValue(1000009);
            if(i != resultList.length -1)  msg += ',';
        }
        response.setMessage(msg);
        // update offset
        fromNumber += resultList.length;
        // refresh apiQuery
        apiQuery = db.getAPIQuery('/entrycopier/3');
        apiQuery.setLimitSize(6);
        apiQuery.setLimitFrom(fromNumber);
        resultList = apiQuery.getAPIResultList();
    }
    response.setStatus('WARN');
}

Entrées

Résultat

Envoyer une requête HTTP

Vous pouvez envoyer une requête HTTP GET/POST/DELETE/PUT à une URL et obtenir le résultat renvoyé suivant :

util.getURL(String urlstring)  
util.postURL(String urlstring,String postBody)
util.deleteURL(String urlstring)
util.putURL(String urlstring,String putBody)

La variable util est prédéfinie.

De même, vous pouvez appeler util.setHeader(String name,String value) pour définir des en-têtes HTTP et util.removeHeader(String name) pour supprimer des en-têtes.

Références API

Les variables globales système prédéfinies répertoriées ici sont accessibles directement sans qu'il soit nécessaire de les définir.

db.getAPIQuery

MéthodeDéscription
getAPIResult()Obtenir la première entrée lors de l'itération sur la requête
getAPIResultList()Obtenir un tableau d'entrées de la requête
getAPIEntry(int rootNodeId)Obtenir l'entrée par l'ID du noeud (node)
getKeyFieldId()Récupérer l'identifiant du champ clé de la feuille sur laquelle se trouve cette requête
getFieldIdByName(String fieldName)Obtenir l'identifiant du champ d'un nom spécifié. S'il existe plus d'un champ du même nom, le premier identifiant de champ indépendant sera renvoyé.
insertAPIEntry()Insérer une nouvelle entrée dans la requête, et la méthode renvoie la nouvelle entrée
addFilter(int fieldId, String operand, String value)Filtrer les entrées selon une condition spécifiée
setIfIgnoreFixedFilter(boolean ifIgnoreFixedFilter)Définir si vous souhaitez ignorer le filtre fixe de la feuille cible
setOrder(int orderField, int orderDir)Trier les entrées de la requête par l'identifiant de champ spécifié et la direction de tri. Le paramètre orderDir est défini sur 1 pour un tri croissant, sur 2 pour un tri décroissant, sur 3 pour un second tri croissant et sur 4 pour un second tri décroissant.
deleteEntry(int nodeId)Supprimer l'entrée par l'ID de noeud
deleteEntryToRecycleBin(int nodeId)Supprimer l'entrée par l'ID du nœud pour la mettre dans la corbeille
setLimitSize(int limitSize)Par défaut, ScriptAPIQuery renvoie 1000 enregistrements par requête. Vous pouvez utiliser setLimitSize pour modifier le nombre d'enregistrements renvoyés par requête. Cependant, nous ne recommandons pas de renvoyer un trop grand nombre d'enregistrements par requête car cela peut consommer trop de mémoire et avoir des conséquences sur les performances de votre base de données. Nous vous recommandons plutôt d'utiliser la méthode setLimitFrom pour la pagination.
setLimitFrom(int limitFrom)Cette méthode vous permet de parcourir tous les enregistrements d'une ScriptAPIQuery étape par étape. En spécifiant une limite initiale (limitFrom), vous indiquez à ScriptAPIQuery de commencer à renvoyer les enregistrements à partir d'un certain décalage. Cela vous permet de naviguer à travers tous les enregistrements de ScriptAPIQuery. Par défaut, ScriptAPIQuery renvoie 1000 enregistrements par requête. Vous devez vérifier sur la page suivante si le nombre d'enregistrements retournés est égal à la taille de la liste retournée.
setGetUserNameAsSelectUserValue(boolean b)Une fois défini sur false (faux), la requête récupérera l'e-mail de l'utilisateur pour les champs utilisateur sélectionnés au lieu du nom de l'utilisateur.

Voici la liste des opérandes que vous pouvez utiliser :

Nom de l'opérande Valeur de l'opérande
Egal =
Expression régulière regex
Supérieur ou égal
Inférieur ou égal <=
Supérieur
Inférieur <</td>
Contient like

Veuillez noter que lorsque vous filtrez par date ou date/heure, celles-ci doivent être dans le format suivant : aaaa/MM/jj or aaaa/MM/jj HH:mm:ss

Vous pouvez également utiliser une recherche en texte intégral comme filtre de requête en appelant setFullTextSearch(String queryTerm) au lieu de addFilter().

db.getAPIQuery records

MéthodeDescription
getFieldValue(int fieldId)Obtenir la valeur du champ par son identifiant de champ. Les champs de sous-table ne sont pas inclus
getFieldIdByName(String fieldName)Obtenir l'identifiant du champ d'un nom spécifié. Si plusieurs champs ont le même nom, le premier identifiant de champ indépendant sera retourné
getKeyFieldId()Récupérer l'identifiant du champ clé de cette feuille
getFieldValueByName(String fieldName)Obtenir la valeur du champ par son nom de champ. Les champs de sous-table ne sont pas inclus. S'il existe plusieurs champs du même nom, la valeur du premier champ sera retournée
getFieldValues(int fieldId)Obtenir toutes les valeurs de champ d'un champ de sélection multiple sous forme de tableau. Les champs de sous-table ne sont pas inclus
getRootNodeId()Obtenir l'identifiant du nœud racine de l'entrée
getRootfieldId()Obtenir l'identifiant du champ racine de l'entrée
getSubtableSize(int subtableRootfieldId)Obtenir la taille de la sous-table, spécifiée par l'identifiant du champ racine de la sous-table
getSubtableRootNodeId(int subtableRootfieldId, int rowNumber)Obtenir l'identifiant du nœud racine de la sous-table, spécifié par son identifiant de champ racine et le numéro de ligne dans la sous-table
getJSON()Obtenir une représentation JSON de l'intégralité de l'enregistrement
setFieldValue(int fieldId, String value)Définir la valeur du champ spécifié. Pour un champ de sous-table, vous devez employer setSubtableFieldValue()
setFieldValue(int fieldId, String value, boolean appendValue)Définir la valeur d'un champ qui est un champ de sélection multiple. Le paramètre appendValue doit être true. Pour les champs de sous-table, vous devez utiliser setSubtableFieldValue()
setFieldFile(int fieldId, String fileName, String fileContent)

Uniquement pour les champs de téléchargement de fichier ou de graphiques. Un fichier portant le nom et le contenu de fichier que vous avez fourni seront créés en tant que téléchargement de fichier et enregistrés dans le champ spécifié. Pour les champs de sous-table, vous devez utiliser setSubtableFieldFile()

setSubtableFieldValue(int fieldId, int subtableRootNodeId,String value)Définir la valeur d'un champ de sous-table. Vous pouvez obtenir le paramètre subtableRootNodeId avec la méthode getSubtableRootNodeId.
setSubtableFieldValue(int fieldId, int subtableRootNodeId, String value, boolean appendValue) Définir la valeur d'un champ de sous-table qui est un champ de sélection multiple. Le paramètre appendValue doit être true
deleteSubtableRowByRowNumber(int subtableRootfieldId, int rowNumber)Supprimer la ligne de sous-table par son identifiant de champ racine et son numéro de ligne dans la sous-table.
deleteSubtableRowAll(int subtableRootfieldId)Supprimer chaque ligne dans la sous-table spécifiée
deleteSubtableRow(int subtableRootfieldId, int subtableRootNodeId)Supprimer la ligne de la sous-table par l'identifiant du champ racine et l'identifiant du nœud racine de la sous-table
loadAllLinkAndLoad()Télécharger la valeur de tous les champs chargés dans un lien et télécharger la configuration dans l'entrée
recalculateAllFormulas()Recalculer chaque champ qui contient une formule dans l'entrée
recalculateFormula(int fieldId)Recalculer la formule de champ spécifié.
Remarque : si deux champs ou plus partagent le même identifiant de champ, veuillez à la place utiliser recalculateFormula(int fieldId, String cellName).
recalculateFormula(int fieldId, String cellName)Recalculer la formule d'un champ spécifié en utilisant le paramètre cellName pour déterminer l'emplacement de la cellule du champ (comme A1, C2, H21, etc.). Cette méthode est utilisée sur les feuilles avec deux champs ou plus ayant le même identifiant de champ
loadAllDefaultValues(ScriptUser user)Charger la valeur de chaque champ qui est défini avec une valeur par défaut. Le paramètre user est prédéfini.
loadDefaultValue(int fieldId, ScriptUser user)Charger la valeur par défaut du champ spécifié. Le paramètre userest prédéfini
lock()Vérrouiller l'entrée
unlock()Déverrouiller l'entrée
save()Sauvegarder une entrée
setCreateHistory(boolean createHistory)Définir si l'entrée doit créer un historique
isCreateHistory()Indique si l'entrée est configurée pour créer un historique
setIfExecuteWorkflow(boolean executeWorkflow)Définir si l'exécution du flux de travail (flux pré comme post-exécution) de l'entrée est nécessaire
setIgnoreEmptyCheck(boolean ignoreEmptyCheck)Définir si la vérification des champs non vides doit être ignorée
setRecalParentFormula(boolean recalParentFormula)Si cette feuille est générée à partir d'une sous-table d'une autre feuille, ou est référencée par une autre feuille, ce qui signifie que cette feuille a une feuille parente, alors vous pouvez appeler cette méthode pour définir une recalculation sur la feuille parente
setIfDoLnls(boolean)Lorsque vous avez une feuille source et une feuille qui lui est liée, la synchronisation des valeurs chargées sera déclenchée sur la feuille liée à partir de la feuille source. Vous devriez toujours ajouter cette méthode à la feuille source pour déclencher la synchronisation sur l'autre feuille.

réponse

MéthodeDescription
getStatus()Obtenir le statut de la réponse, soit SUCCESS, WARN, CONFIRM, INVALID, ERROR
setStatus(String status)Définir le statut de la réponse, soit SUCCESS, WARN, CONFIRM, INVALID, ERROR
setMessage(String plainMessage)Définit un message à afficher lors de l'exécution du script. Cette fonction peut être appelée plusieurs fois et tous les messages qui ont été définis seront affichés en même temps
numOfMessages()Renvoie le nombre de messages qui ont été définis
setOpenURL(String url)Uniquement dans le cadre de la portée de la feuille installée. Redirige l'utilisateur vers l'URL spécifiée après avoir enregistré la modification
setOpenURLInNewTab(boolean b)Configure si le navigateur ouvre un nouvel onglet lors de l'ouverture d'une URL. Par défaut, configuré sur vrai.

user

MéthodeDescription
getEmail()Obtenir l'adresse e-mail de l'utilisateur
getUserName()Obtenir le nom complet de l'utilisateur
isInGroup(String groupName)Renvoie si l'utilisateur est dans ce groupe avec le nom de groupName

mailer

MéthodeDescription
compose(String to, String cc, String from, String fromPersonal, String subject, String content)Compose un message e-mail à envoyer. Les paramètres to et cc peuvent contenir plusieurs adresses e-mail. Elles doivent simplement être séparées par des virgules.

send()Envoyer le message qui vient d'être écrit.
sendAsync()Envoyer le message qui vient d'être composé de manière asynchrone. Notez que sendAsync ne peut être appelé qu'une seule fois par exécution de script.
attach(String url)Attacher un fichier au message. L'URL doit être une URL complète avec https://
setSendRaw(boolean b)Définir si le contenu ne doit pas être converti en HTML. Définir cette valeur sur true lorsque votre contenu est déjà en HTML.
sendAppNotification(String email,String message)Envoyer une notification à l'application mobile à cet utilisateur si l'utilisateur a installé une application Ragic iOS ou Android.
sendAppNotification(String email,String message,String pathToForm,int nodeId)Envoie une notification à l'application mobile à cet utilisateur si l'utilisateur a installé une application Ragic iOS ou Android. L'utilisateur sera redirigé vers l'enregistrement spécifié lorsqu'il cliquera sur cette notification. "pathToForm" doit être au format "/forms/1", sans inclure le nom du compte, incluant le dossier d'onglets et l'index de la feuille.

util

MéthodeDescription
getURL(String urlstring)Appelle une URL avec la méthode GET
postURL(String urlstring,String postBody)Appelle URL avec la méthode POST
deleteURL(String urlstring)Appelle une URL avec la méthode DELETE
putURL(String urlstring,String putBody)Appelle une URL avec la méthode PUT
setHeader(String name,String value)Définit un en-tête HTTP qui sera utilisé dans les appels URL suivants
removeHeader(String name)Supprime un en-tête HTTP pour ne plus être utilisé dans les appels URL suivants
logWorkflowError(String text)Enregistre un message de journal de texte sous forme de chaîne dans le journal de flux de travail que vous pouvez trouver dans la page de maintenance de la base de données

account

Purge tout le cache lié au compte lorsque le script se termine et que le rechargement de la page est terminé

MéthodeDescription
getUserName(String email)Obtient le nom complet d'un utilisateur spécifié par l'adresse e-mail
getUserEmail(String userName)Obtient l'adresse e-mail pour le nom d'utilisateur spécifié
reset()
getTimeZoneOffset()Obtient le décalage de fuseau horaire de ce compte en millisecondes
getTimeZoneOffsetInHours()Obtient le décalage de fuseau horaire de ce compte en heures

param

C'est l'objet de requête utilisateur soumis par l'utilisateur avant que la requête ne soit enregistrée dans la base de données. Particulièrement utile lors de l'écriture de scripts de flux pré-exécution.

MéthodeDescription
getUpdatedEntry()Uniquement post-exécution. Renvoie l'enregistrement qui vient d'être créé ou mis à jour.
getNewNodeId(int fieldId)Renvoie l'identifiant du nœud (int) du champ donné après l'écriture d'une nouvelle valeur.
getOldNodeId(int fieldId)Renvoie l'identifiant du noed (int) du champ donné avant l'écriture d'une nouvelle valeur.
getNewValue(int fieldId)Renvoie la valeur du champ donné après l'écriture d'une nouvelle valeur.
getOldValue(int fieldId)Renvoie la valeur du champ donné avant l'écriture d'une nouvelle valeur.
getNewValues(int fieldId)Similaire à getNewValue, mais peut accéder à plusieurs valeurs en même temps, ce qui est utile lors du traitement de champs à sélection multiple.
getOldValues(int fieldId)Similaire à getOldValue, mais peut accéder à plusieurs valeurs en même temps, ce qui est utile lors du traitement de champs à sélection multiple.
getSubtableEntry(int fieldId)Renvoie une liste de paramètres qui peuvent manipuler chaque enregistrement dans la sous-table.
isCreateNew()Retourne si l'entrée est nouvellement créée.

approbation

MéthodeDescription
create(String[] wfSigner)

Seulement pour les flux post-exécution.

wfSigner est un tableau contenant des objets au format JSON spécifique.

{

'stepIndex' : position de l'étape dans l'approbation - commençant par 0,

'approver' : email de l'approbateur

'stepName' : nom de l'approbateur ou titre

}

Exemple pour "étape avec un approbateur unique" :

wfSigner push({

'stepIndex':'1',

'approver':'kingjo@ragic.com',

'stepName':'Jo'

})

Soulignons que wfSigner doit satisfaire l'approbation que vous avez définie dans le mode design.

Par exemple, s'il n'y a qu'un seul candidat "HR00@gmail.com" à l'étape 2, vous devez fournir un JSON avec approbateur : HR00@gmail.com et stepIndex : 1.

cancel()Seulement pour les flux post-exécution. Annuler l'approbation dans l'entrée.

ParamApprobation

MéthodeDescription
getEntryRootNodeId()Obtenir l'identifiant du nœud racine de l'entrée
getApprovalAction()Obtenir l'action de l'approbateur, soit CREATE, FINISH, CANCEL, REJECT

Haut de page Table des matières

Essayer Ragic gratuitement

Connectez-vous avec Google