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.
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 :
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.
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
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.
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.
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.
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!"); }
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:
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).
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.
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);
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.
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().
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.
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(); }
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.
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'); }
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.
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 }
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.
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éé.
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);
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.
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);
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
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.
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.
Méthode | Dé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().
Méthode | Description |
---|---|
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. |
Méthode | Description |
---|---|
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. |
Méthode | Description |
---|---|
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 |
Méthode | Description |
---|---|
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. |
Méthode | Description |
---|---|
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 |
Méthode | Description |
---|---|
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() | Purge tout le cache lié au compte lorsque le script se termine et que le rechargement de la page est terminé|
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 |
Méthode | Description |
---|---|
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. |
Méthode | Description |
---|---|
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. |
Méthode | Description |
---|---|
getEntryRootNodeId() | Obtenir l'identifiant du nœud racine de l'entrée |
getApprovalAction() | Obtenir l'action de l'approbateur, soit CREATE, FINISH, CANCEL, REJECT |