Présentation

Ce tutoriel explique comment mettre en oeuvre un script Groovy qui valide l'entrée de données par rapport aux intervalles autorisés stockés dans un cube de pilote.

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 d'échelon d'employé (salaire minimum/maximum permis et prime minimum/maximum permis) d'un cube d'inducteur dans une grille temporaire en mémoire, puis valide les valeurs de salaire et de prime entrées par rapport aux intervalles autorisés.

Préalables

Les tutoriels pratiques Cloud EPM peuvent nécessiter l'importation d'un instantané dans votre instance Cloud EPM Enterprise Service. Avant d'importer un instantané de tutoriel, vous devez demander une autre instance du service Cloud EPM Enterprise ou supprimer l'application et le processus d'affaires courants. L'instantané du tutoriel ne sera pas importé sur votre application ou processus d'affaires existant, et il ne remplacera pas ou ne restaurera pas automatiquement l'application ou le processus d'affaires avec lequel vous travaillez actuellement.

Avant de commencer ce tutoriel, vous devez :

  • Permet à 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 précédemment chargé l'instantané pour un autre tutoriel Groovy, vous pouvez continuer à utiliser le même instantané.

Note :

Si vous rencontrez des erreurs de migration lors de l'importation de l'instantané, réexécutez la migration à l'exclusion du composant HSS-Shared Services, ainsi que des artefacts Security et User Preferences du composant Core. Pour plus d'informations sur le chargement et l'importation d'instantanés, consultez la documentation sur l'administration de la migration pour Oracle Enterprise Performance Management Cloud.

Conseil :

Les scripts dont vous avez besoin pour ce tutoriel sont liés sous forme de 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ègle, remplacez l'option Concepteur par Modifier le script et réglez le type de script à Script Groovy.
  4. Options de l'éditeur de règle
  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 Enregistrer (Enregistrer) pour enregistrer le script, puis cliquez 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 du script une section à la fois.

  1. Créez 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 d'échelon d'employé (salaire minimum/maximum permis et prime minimum/maximum permis) à partir d'un cube d'inducteur.

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

  2. Créez un chargeur d'ensembles.
  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 chargeur d'ensembles de ressources contenant les messages localisés requis par cette règle.

    Obtenir le cube inducteur/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 PDV, les membres de colonne et les lignes.

    Créez l'objet DataGridDefinition.

  4. Chargez la grille de données à partir du cube de consultation pour la région définie par l'objet DataGridDefinition.
  5. DataGrid dataGrid = lookupCube.loadGrid(gridDefinition, false)  
  6. Créez une mappe de données d'échelon (salaire minimal/maximal et prime) par nom d'échelon à 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 carte nommée gradeDataMap des données d'échelon (salaire minimal/maximal et prime) par nom d'échelon.

    Alimentez la carte gradeDataMap avec les données d'échelon pour chaque échelon. L'échelon est la clé et l'objet GradeData alimenté avec le salaire minimum/maximum et la prime est la valeur.

  7. Créez un itérateur qui effectue une itération sur toutes les cellules de données contenant le membre Grade dans la grille d'entrée courante.
  8. DataGrid grid = operation.grid
    GridIterator itr = grid.dataCellIterator('Grade')
  9. Lancez 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 contient au moins une cellule contenant le membre Grade. Sinon, lancez une exception de veto avec le message localisé.

  11. Validez les valeurs du tableau.
  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. L'échelon dans la grille d'entrée est un compte de type liste dynamique qui est dérivé de la hiérarchie d'échelon définie dans le cube de consultation. L'appel de it.DataAsSmartListMemberName obtient le nom du membre à partir duquel la valeur de liste dynamique de la cellule courante est dérivée, qui peut ensuite être utilisée comme clé dans la carte pour obtenir les données d'échelon.

    Transférer la dimension dans la cellule Salary et valider le salaire par rapport au salaire autorisé dans les données d'échelon.

    Transférer dim dans la cellule Bonus et valider le Bonus par rapport au Bonus autorisé dans les données d'échelon. Si le salaire ou la prime n'est pas compris dans les limites autorisées, réglez la couleur d'arrière-plan de la cellule à rouge et ajoutez une erreur de validation à la cellule en appelant l'API addValidationError(). Le message d'erreur sera défini en tant qu'infobulle de la cellule et apparaîtra également dans les messages de validation de grille. De plus, si cette règle est exécutée après l'enregistrement, le système opposera son veto à l'opération d'enregistrement.

Tester le script

  1. Dans le gestionnaire de formulaires, modifiez le formulaire ManageEmployees et associez la règle Groovy Valider les données d'employé à exécuter Après le chargement et Avant l'enregistrement (vous devrez peut-être sélectionner Plan1 dans la liste Cube en premier).
  2. Formulaire ManageEmployees avec la règle associée.
  3. Enregistrez le formulaire et fermez la fenêtre Form Manager.
  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'outils du formulaire, cliquez sur Enregistrer (Enregistrer).
  5. Le tableau de bord Employés.
  6. Dans la boîte de dialogue Message d'erreur, cliquez sur OK.
  7. Le tableau de bord Employés.
  8. Pointez la souris sur les cellules rouges pour voir les messages d'erreur détaillés sous forme d'infobulles.

    Message d'erreur.

    Message d'erreur.

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

Autres ressources d'apprentissage

Explorez d'autres laboratoires sur le site docs.oracle.com/learn ou accédez à plus de contenu d'apprentissage gratuit sur le canal Oracle Learning YouTube. De plus, visitez Oracle University pour voir les ressources de formation disponibles.

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