Introduction

Ce tutoriel explique comment implémenter un script Groovy qui valide la saisie des données par rapport aux plages autorisées stockées dans un cube d'inducteur.

Contexte

Dans cet exemple, vous allez créer un script qui s'exécute lorsque les utilisateurs enregistrent les mises à jour des salaires et des primes des employés à partir d'un formulaire de saisie de données. Le script charge les données de niveau d'employé (salaire minimum/maximum autorisé et prime minimum/maximum autorisée) d'un cube d'inducteur dans une grille temporaire en mémoire, puis valide les valeurs de salaire et de prime saisies par rapport aux fourchettes autorisées.

Prérequis

Les tutoriels pratiques Cloud EPM peuvent vous obliger à importer un cliché dans votre instance Cloud EPM Enterprise Service. Pour pouvoir importer un instantané de tutoriel, vous devez demander une autre instance Cloud EPM Enterprise Service ou supprimer l'application et le processus métier en cours. L'instantané du tutoriel ne sera pas importé sur votre application ou processus métier existant, ni remplacé ou restauré automatiquement l'application ou le processus métier que vous utilisez actuellement.

Avant de commencer ce tutoriel, vous devez :

  • Demandez à l'administrateur de service d'accéder à une instance Cloud EPM Enterprise Service.
  • Chargez et importez cet instantané dans votre instance Planning. Si vous avez déjà téléchargé le cliché pour un autre tutoriel Groovy, vous pouvez continuer à utiliser le même cliché.

Remarques :

Si vous rencontrez des erreurs de migration lors de l'importation du cliché, réexécutez la migration en excluant le composant HSS-Shared Services, ainsi que les artefacts de sécurité et de préférences utilisateur du composant de base. Pour plus d'informations sur le téléchargement et l'import de clichés, reportez-vous à la documentation Administration de la migration pour Oracle Enterprise Performance Management Cloud.

Conseil :

Les scripts dont vous avez besoin pour ce tutoriel sont liés en tant que fichiers texte dans chaque section.

Création du script

  1. Ouvrez Calculation Manager et créez une règle nommée Groovy Validate Employee Data dans le cube Plan1.
  2. Nouvel objet
  3. Dans l'éditeur de règles, remplacez l'option Designer par Modifier le script et définissez le type de script sur Script Groovy.
  4. Options d'éditeur de règles
  5. Copiez ce script et collez-le dans l'éditeur.
  6. class GradeData {
        Integer Grade
        DataGrid.DataCell minSalary
        DataGrid.DataCell maxSalary
        DataGrid.DataCell minBonus
        DataGrid.DataCell maxBonus
        public String toString() {
            return "minSalary: ${minSalary?.formattedValue}, maxSalary: ${maxSalary?.formattedValue}, minBonus: ${minBonus?.formattedValue}, maxBonus: ${maxBonus?.formattedValue}"
        }
    }
    
    // Create a resource bundle loader containing localized messages needed by this rule.  
    def mbUs = messageBundle( ["validation.missingmember.grade":"No Grades found on the Grid."] )
    def mbl = messageBundleLoader(["en" : mbUs])
    
    Cube lookupCube = operation.application.getCube("Plan1")
    DataGridDefinitionBuilder builder = lookupCube.dataGridDefinitionBuilder()
    builder.addPov(['Years', 'Scenario', 'Currency', 'Period', 'Version', 'Entity'], [['FY16'], ['Current'], ['USD'], ['BegBalance'], 
    
    ['BU Version_1'], ['No Entity']])
    builder.addColumn(['Account'], [ ['Min Salary', 'Max Salary', 'Min Bonus', 'Max Bonus'] ])
    builder.addRow(['Grades'], [ ['ILvl0Descendants("Grades")'] ])
    DataGridDefinition gridDefinition = builder.build()
    
    // Load the data grid from the lookup cube 
    DataGrid dataGrid = lookupCube.loadGrid(gridDefinition, false)
    
    // Create a map of grade data (Min/Max Salary and Bonus) by grade name from the data grid.
    def gradeDataMap = new HashMap()
    if(dataGrid) {
        println("dataGrid is not null")
        dataGrid.dataCellIterator('Min Salary').each {
            def gradeData = new GradeData()
            gradeData.minSalary = it
            gradeData.maxSalary = it.crossDimCell('Max Salary')
            gradeData.minBonus = it.crossDimCell('Min Bonus')
            gradeData.maxBonus = it.crossDimCell('Max Bonus')
            gradeDataMap[(it.getMemberName('Grades'))] = gradeData
            println(it.getMemberName('Grades') + ": " + gradeData)
        }
    }
    
    DataGrid grid = operation.grid
    // Construct an iterator that iterates over all data cells containing the Grade member.
    GridIterator itr = grid.dataCellIterator('Grade')
    
    // Throw a veto exception if the grid has at least one cell but does not contain any cells containing the Grade member.
    if(!grid.empty && !itr.hasNext()) {
        // Found 0 cells with Grade
        throwVetoException(mbl, "validation.missingmember.grade")
    }
    
    // Validate the values in the grid being saved against the values in gradeDataMap.
    itr.each {
        GradeData gradeData = gradeDataMap[it.DataAsSmartListMemberName]  
        if(gradeData == null) {
            println("Unable to locate grade data for grade: ${it.DataAsSmartListMemberName}, with data value: ${it.formattedValue}" )
        } else {  
            println(it.getMemberName('Employee') + ": " + gradeData.toString())
            DataCell salary = it.crossDimCell('Salary')
            if(salary == null)
                println("Unable to locate Salary")
            else if(salary.data < gradeData.minSalary.data || salary.data > gradeData.maxSalary.data) {
                salary.addValidationError(0xFF0000, "Salary is outside of the allowed range.")  
            }
            DataCell bonus = it.crossDimCell('Bonus')
            if(bonus == null) {
                println("Unable to locate Bonus")
            } else if(bonus.data < gradeData.minBonus.data || bonus.data > gradeData.maxBonus.data) {
                bonus.addValidationError(0xFF0000, "Bonus is outside of the allowed range.")  
            }
        }
    }
    
  7. Dans la barre d'outils, cliquez sur Enregistrement (Enregistrer) pour enregistrer le script, puis sur Valider et déployer (Valider et déployer) pour valider et déployer le script. Cliquez sur OK lorsque vous y êtes invité. Fermez Calculation Manager.

Expliquer la logique du script

Dans cette section, nous allons décrire la logique de script une section à la fois.

  1. Créer une classe.

    class GradeData { 
        Integer Grade
        DataGrid.DataCell minSalary
        DataGrid.DataCell maxSalary
        DataGrid.DataCell minBonus
        DataGrid.DataCell maxBonus
        public String toString() {
            return "minSalary: ${minSalary?.formattedValue}, 
                    maxSalary: ${maxSalary?.formattedValue}, 
                    minBonus: ${minBonus?.formattedValue}, 
                    maxBonus: ${maxBonus?.formattedValue}" 
        }
    }

    Créez une classe, GradeData, pour stocker les données de niveau d'employé (salaire minimum/maximum autorisé et prime minimum/maximum autorisée) à partir d'un cube d'inducteur.

    La méthode toString() renvoie une représentation de chaîne de l'objet GradeData. La méthode utilise l'opérateur de sécurité NULL (?.) fourni par Groovy. Si la variable avant le point d'interrogation est NULL, elle ne se poursuit pas et renvoie NULL. Par exemple, {minSalary?.formattedValue} renvoie la valeur NULL au lieu de générer une exception NullPointerException si minSalary est NULL.

  2. Créez un programme de chargement de groupe.
  3. // Create a resource bundle loader containing localized messages needed by this rule.  
    def mbUs = messageBundle( ["validation.missingmember.grade":"No Grades found on the Grid."] ) 
    def mbl = messageBundleLoader(["en" : mbUs])
    
    Cube lookupCube = operation.application.getCube("Plan1") 
    DataGridDefinitionBuilder builder = lookupCube.dataGridDefinitionBuilder() 
    builder.addPov(['Years', 'Scenario', 'Currency', 'Period', 'Version', 'Entity'], [['FY16'], 
    	['Current'], ['USD'], ['BegBalance'], ['BU Version_1'], ['No Entity']])
    builder.addColumn(['Account'], [ ['Min Salary', 'Max Salary', 'Min Bonus', 'Max Bonus'] ])
    builder.addRow(['Grades'], [ ['ILvl0Descendants("Grades")'] ])
    DataGridDefinition gridDefinition = builder.build() 
    

    Créez un programme de chargement de groupe de ressources contenant les messages localisés requis par cette règle.

    Obtenir le cube pilote/consultation.

    Obtenez une valeur DataGridDefinitionBuilder pour le cube. Utilisez le générateur pour construire une région à partir de laquelle charger les données en ajoutant les membres de PDV, les membres de colonne et les lignes.

    Créez l'objet DataGridDefinition.

  4. Chargez la grille de données du cube de consultation pour la région définie par l'objet DataGridDefinition.
  5. DataGrid dataGrid = lookupCube.loadGrid(gridDefinition, false)  
  6. Créer un mappage des données de grade (salaire minimum/maximum et prime) par nom de grade à partir de la grille de données.
    def gradeDataMap = new HashMap<String, GradeData>() 
    if(dataGrid) {
        println("dataGrid is not null")
        dataGrid.dataCellIterator('Min Salary').each { 
            def gradeData = new GradeData()
            gradeData.minSalary = it
            gradeData.maxSalary = it.crossDimCell('Max Salary')
            gradeData.minBonus = it.crossDimCell('Min Bonus')
            gradeData.maxBonus = it.crossDimCell('Max Bonus')
            gradeDataMap[(it.getMemberName('Grades'))] = gradeData
            println(it.getMemberName('Grades') + ": " + gradeData)
        }
    }

    Créez une correspondance nommée gradeDataMap de données de grade (salaire minimum/maximum et prime) par nom de grade.

    Remplissez la carte gradeDataMap avec les données de grade pour chaque grade. Grade est la clé et l'objet GradeData renseigné avec le salaire minimum/maximum et la prime est la valeur.

  7. Créez un itérateur qui itère sur toutes les cellules de données contenant le membre Grade dans la grille d'entrée actuelle.
  8. DataGrid grid = operation.grid
    GridIterator itr = grid.dataCellIterator('Grade')
  9. Générer une exception de veto.
  10. // Throw a veto exception if the grid has at least one cell but does not contain any cells containing the Grade member.
    if(!grid.empty && !itr.hasNext()) {  
        // Found 0 cells with Grade
        throwVetoException(mbl, "validation.missingmember.grade")
    }

    Vérifiez que la grille d'entrée comporte au moins une cellule contenant le membre Grade. Sinon, générez une exception de veto avec le message localisé.

  11. Validez les valeurs de grille.
  12. // Validate the values in the grid being saved against the values in gradeDataMap.
    itr.each {  
        GradeData gradeData = gradeDataMap[it.DataAsSmartListMemberName]  
        if(gradeData == null) {
            println("Unable to locate grade data for grade: ${it.DataAsSmartListMemberName}, 
            	with data value: ${it.formattedValue}" )
        } else {  
            println(it.getMemberName('Employee') + ": " + gradeData.toString())
            DataCell salary = it.crossDimCell('Salary') 
            if(salary == null)
                println("Unable to locate Salary")
            else if(salary.data < gradeData.minSalary.data || salary.data > gradeData.maxSalary.data) 
            	{
                salary.addValidationError(0xFF0000, "Salary is outside of the allowed range.")  
            }
            DataCell bonus = it.crossDimCell('Bonus') 
            if(bonus == null) {
                println("Unable to locate Bonus")
            } else if(bonus.data < gradeData.minBonus.data || bonus.data > gradeData.maxBonus.data) {
                bonus.addValidationError(0xFF0000, "Bonus is outside of the allowed range.")  
            }
        }
    }

    Validez les valeurs de la grille d'entrée en cours d'enregistrement par rapport aux valeurs de gradeDataMap. Le grade dans la grille d'entrée est un compte de type liste dynamique qui est dérivé de la hiérarchie de grade définie dans le cube de consultation. L'appel de it.DataAsSmartListMemberName permet d'obtenir le nom du membre à partir duquel la valeur de liste dynamique de la cellule en cours est dérivée, qui peut ensuite être utilisé comme clé dans la correspondance pour obtenir les données de grade.

    Effectuez une modification croisée dans la cellule Salaire et validez le salaire par rapport au salaire autorisé dans les données de grade.

    Effectuez une modification croisée dans la cellule Bonus et validez la prime par rapport à la prime autorisée dans les données de grade. Si le salaire ou la prime n'est pas dans les limites autorisées, définissez la couleur d'arrière-plan de la cellule sur rouge et ajoutez une erreur de validation dans la cellule en appelant l'API addValidationError(). Le message d'erreur sera défini en tant qu'info-bulle de la cellule et apparaîtra également dans les messages de validation de grille. En outre, si cette règle est en cours d'exécution après l'enregistrement, le système oppose son veto à l'opération d'enregistrement.

Test du script

  1. Dans le gestionnaire de formulaires, modifiez le formulaire ManageEmployees et associez la règle Groovy Validate Employee Data à exécuter Après le chargement et Avant l'enregistrement (vous devrez peut-être d'abord sélectionner Plan1 dans la liste Cube).
  2. Formulaire ManageEmployees avec la règle associée.
  3. Enregistrez le formulaire et fermez la fenêtre du Gestionnaire de formulaires.
  4. Ouvrez le tableau de bord Employés. Ajoutez une prime de 1000 pour l'employé 1, augmentez le salaire de l'employé 2 à 65000. Dans la barre d'outil du formulaire, cliquez sur Enregistrement (Enregistrer).
  5. Tableau de bord Employés.
  6. Dans la boîte de dialogue Message d'erreur, cliquez sur OK.
  7. Tableau de bord Employés.
  8. Passez le pointeur de la souris sur les globules rouges pour afficher les messages d'erreur détaillés sous forme d'info-bulles.

    Message d'erreur.

    Message d'erreur.

  9. Fermez le tableau de bord et ouvrez la console Jobs.
  10. Volet Recent Activity de la console des jobs.
  11. Cliquez sur Valider les données d'employé Groovy pour afficher les détails de l'emploi. Cliquez sur le statut Terminé pour voir les données de grade chargées à partir du cube de consultation et les données de grade par grade de chaque employé.
  12. Messages du journal.

Ressources de formation supplémentaires

Explorez d'autres ateliers sur le site docs.oracle.com/learn ou accédez à d'autres contenus d'apprentissage gratuits sur le canal Oracle Learning YouTube. En outre, visitez Oracle University pour consulter les ressources de formation disponibles.

Pour obtenir de la documentation sur le produit, consultez Oracle Help Center.