IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Salesforce.com Discussion :

Trigger de conversion d'un montant


Sujet :

Salesforce.com

  1. #1
    Membre habitué Avatar de TheChovix
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2014
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2014
    Messages : 77
    Points : 166
    Points
    166
    Par défaut Trigger de conversion d'un montant
    Bonjour à tous,

    Ravi de voir qu'il existe des discussions francophones à propos de SalesForce, ça change.

    Bref, j'aurai besoin de conseils pour la rédaction d'un trigger, étant novice dans le langage APEX, j'ai quand même essayé de produire quelque chose, ayant tout de même des compétences en langages orientés objet et en SQL.

    Le fonctionnement recherché ici est de convertir un montant donné en fonction de la valeur d'une devise.
    Je m'explique, le module de gestion des devises ne permettant pas le fonctionnement voulu par mon entreprise, le fonctionnement est tourné de telle manière :
    - Il y a 3 objets custom : Notes de Frais, Ligne de frais et currency,
    - qui enregistrent respectivement [un montant total et une devise], [un montant, un montant converti, une date et un champs de détail lié à Note de Frais] et [une date, une devise et la valeur de la devise].
    - Le but étant de contrôler la devise utilisée par la note de frais correspondante, récupérer en fonction de ce champs la valeur enregistrée à une date donnée dans l'objet currency et de convertir le montant.

    Ouff, c'est long.

    Voici un exemple simplifié du code que j'essaye de faire :

    Code JAVA : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    trigger convertirMontant on Ligne_de_frais__c(before insert, before update) {  
        //Pour chaque membre de l'objet List LignedeFrais, remplie avec les champs insérés, ...
        for(Ligne_de_frais__c LignedeFrais : Trigger.new){
            // ... On crée une chaine et on lui affecte la valeur du champs de détail ligne_associee, ...
            // __r permet d'accéder par un pointage au champs DEVISE__c de l'objet perso Note_de_Frais__c
            String DEVISE = [SELECT DEVISE__c FROM Note_de_Frais__c c WHERE c.DEVISE__c = :LignedeFrais.ligne_associee__r.DEVISE__c LIMIT 1].DEVISE__c;
     
            // ... On récupère la date d'aujourd'hui ...
            Date today = Date.today();
     
            // ... Puis on récupère dans une variable Decimal, en fonction de la devise et de sa date de création
            // sa valeur correspondante ...  
            Decimal VALEUR = [SELECT valeur_devise__c FROM currency__c WHERE (DEVISE__c =: DEVISE) AND DAY_ONLY(LastModifiedDate) = :today LIMIT 1].valeur_devise__c;
     
            // ... Enfin, on utilise cette VALEUR en la multipliant au montant de la journée pour obtenir le montant converti
            LignedeFrais.Montant_converti__c = LignedeFrais.Montant_de_la_journ_e__c * VALEUR;
        }
    }

    Malheureusement, je me heurte à chaque fois à une QueryException me notifiant que ma requête ne retourne aucun résultat. N'ayant pas les connaissances requises, je n'ai pas réussi à résoudre mon problème ou réfléchit à un autre fonctionnement.
    Donc si quelqu'un dans l'assemblée pourrait m'éclairer, tout conseil est bon à prendre. On est ici pour apprendre après tout.

    Merci d'avance.
    Le seul bogue à ne pas corriger c'est celui qui fait fonctionner le projet.

  2. #2
    Membre habitué Avatar de TheChovix
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2014
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2014
    Messages : 77
    Points : 166
    Points
    166
    Par défaut
    J'ai finalement réussi à régler mon problème.

    Il a donc fallu que je revois complètement le fonctionnement. En effet, vu que j'utilise un champs Master-Detail qui référence l'objet parent Note_de_frais__c, il fallait que je crée le trigger sur cet objet et non sur l'objet enfant Ligne_de_frais__c.

    Voici donc mon code, pas encore totalement abouti mais j'espère qu'il pourra aider les gens qui était dans ce cas de figure :

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    trigger conversionLigne on Note_de_Frais__c (after insert, after update){
       Set<Id> LignesAModifier = new Set<Id>{};
       Date TODAY = Date.today();
       DateTime NOW = DateTime.now();
       DateTime PAST = NOW.addMinutes(-1);
       
       for(Note_de_Frais__c r: Trigger.new){
          if (r.DEVISE__c == 'CAD' || r.DEVISE__c == 'USD' || r.DEVISE__c == 'EUR')
          LignesAModifier.add(r.Id);
       }
    
       List<Ligne_de_frais__c> LIGNE = [SELECT Id, Montant_de_la_journ_e__c, Montant_converti__c, date__c, ligne_associee__r.DEVISE__c FROM Ligne_de_frais__c c WHERE c.ligne_associee__r.Id IN :LignesAModifier];
    
       for(Ligne_de_frais__c rr: LIGNE){
          if(rr.date__c == TODAY){
              String DEVISE = rr.ligne_associee__r.DEVISE__c;
              Decimal VALEUR = [SELECT valeur_devise__c, DEVISE__c FROM currency__c WHERE DEVISE__c = :DEVISE and LastModifiedDate > :PAST AND LastModifiedDate < :NOW LIMIT 1].valeur_devise__c;
              rr.Montant_converti__c = rr.Montant_de_la_journ_e__c * VALEUR;
           }
           else
               rr.Montant_converti__c = rr.Montant_de_la_journ_e__c * 1;
       }
       
       if(Trigger.isInsert)
           insert LIGNE;
       else
           update LIGNE;
    }

    Vous remarquerez que pour améliorer la gestion des devises, j'utilise la variable LastModifiedDate avec deux instances de DateTime, avec une minute d'écart pour plus de précision afin d'éviter des doublons.

    Ceci étant réglé je met cette "discussion" résolue.
    Le seul bogue à ne pas corriger c'est celui qui fait fonctionner le projet.

  3. #3
    Modérateur
    Avatar de Overcrash
    Homme Profil pro
    Architecte Logiciel et responsable CRM (Salesforce)
    Inscrit en
    Mai 2008
    Messages
    1 254
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Architecte Logiciel et responsable CRM (Salesforce)
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 1 254
    Points : 1 875
    Points
    1 875
    Par défaut
    Bonjour,

    Sujet à controverse, mais il ne faut pas mettre du code dans un trigger selon les best practices.

    En gros le trigger sert juste à appeler ta classe ou controller qui va s'occuper du reste.
    Tu peux à la limite mettre juste un filtre de résultat sur le trigger mais pas plus.

    Pour passer les éléments du trigger à une classe voir : trigger.New, trigger.Old qui sont des collections (list).

    Over
    ---
    Overcrash

    Je ne lis pas les codes qui ne sont pas indentés.
    Merci de les messages utiles en cliquant en bas à droite du message

    Bloqué par le firewall pour accéder au chat ? Essayez avec l'adresse en direct : http://87.98.168.209/

  4. #4
    Membre habitué Avatar de TheChovix
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2014
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2014
    Messages : 77
    Points : 166
    Points
    166
    Par défaut [RE]
    Merci pour ton conseil,

    Comme je l'avais notifié, je suis un novice en la matière, j'avais résolu mon problème avec ce bout de code et je pensais en avoir terminé mais j'étais bien loin du compte.

    Entre le passage en production et les exceptions SalesForce à répétition, il m'a fallu adapter mon code en fonction.
    J'ai donc fait comme tu viens de le conseiller, c'est à dire créer une classe contenant la liste à modifier dans une méthode et dans mon trigger j'ai seulement garder les traitements indépendants.
    C'est plus propre, et si je ne me trompe pas, cela évite la plupart des problèmes communs que pourraient rencontrer mon trigger.

    Je pense que je vais modifier mon dernier commentaire. Cela permettra d'éviter de donner de mauvais exemple !

    En te remerciant !

    TheChovix
    Le seul bogue à ne pas corriger c'est celui qui fait fonctionner le projet.

  5. #5
    Modérateur
    Avatar de Overcrash
    Homme Profil pro
    Architecte Logiciel et responsable CRM (Salesforce)
    Inscrit en
    Mai 2008
    Messages
    1 254
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Architecte Logiciel et responsable CRM (Salesforce)
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 1 254
    Points : 1 875
    Points
    1 875
    Par défaut
    Aucun soucis on débute tous
    ---
    Overcrash

    Je ne lis pas les codes qui ne sont pas indentés.
    Merci de les messages utiles en cliquant en bas à droite du message

    Bloqué par le firewall pour accéder au chat ? Essayez avec l'adresse en direct : http://87.98.168.209/

  6. #6
    Membre habitué Avatar de TheChovix
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2014
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2014
    Messages : 77
    Points : 166
    Points
    166
    Par défaut Besoin de vos lumières
    Je retire la mention résolu de cette discussion car j'aurai besoin de vos conseils.
    Au passage, je notifie que la solution précédente n'est plus d'actualité, puisqu'elle n'était pas aboutie.


    Bon, avant de redemander de l'aide, il est bon de réexpliquer le contexte : je traite des notes de frais avec des dépenses journalières qui peuvent être en plusieurs devises selon le pays où intervient un technicien. SalesForce gère ses devises par une mise à jour quotidienne des taux de change de ses devises. Là où ce système ne répond plus à mon besoin, c'est que je ne peux pas récupérer la valeur de la devise utilisée en € en fonction de la date renseignée dans une ligne de frais (enfant d'une note de frais : champs Master/Detail, etc.). Utilisant des objets personnalisés, il ne m'est pas possible d'avoir ce que je veux avec l'outil de gestion des devises de SalesForce.

    J'ai donc écrit une classe et un trigger (after update) qui récupère les informations d'une ligne de frais, et en fonction du champs date entré et de la valeur de la devise correspondante me donne un champs converti en €.

    Tout fonctionne comme il faut, toutefois mon besoin est désormais de pouvoir convertir également, de manière détaillée, les différentes dépenses entrées dans le formulaire de la ligne de frais. Pour ainsi renvoyer à terme un rapport détaillé des dépenses tenant compte de la devise.
    Ce qui serait utile pour le processus de comptabilité de mon entreprise (=> Formule de devise, champs compte, prise en compte de la TVA pour chaque type de dépenses, etc.).

    Voici donc le code la classe :

    Code JAVA : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    public class classConversion {
        public static void convertirMontant(Ligne_de_frais__c[] LIGNES) {
            for (Ligne_de_frais__c LIGNE :LIGNES){
                Decimal VALEUR = 1;
                String DEVISE = LIGNE.CurrencyIsoCode;
     
                try{
                    VALEUR = [SELECT ConversionRate, IsoCode, StartDate FROM DatedConversionRate WHERE IsoCode = :DEVISE and StartDate = :LIGNE.Date__c LIMIT 1].ConversionRate;
                }catch(QueryException e){
                    System.debug('Erreur SOQL : ' + e.getMessage());
                }finally{
                    LIGNE.Total_frais_converti__c = LIGNE.Total_frais_journ_e__c / VALEUR;
     
                    try{
                        if(LIGNE.Carburant_carte_soci_t__c != null && LIGNE.Carburant_carte_soci_t__c != 0)
                            LIGNE.Carburant_carte_soci_t__c = LIGNE.Carburant_carte_soci_t__c / VALEUR;
                        if(LIGNE.Carburant_rembourser__c != null && LIGNE.Carburant_rembourser__c != 0)
                            LIGNE.Carburant_rembourser__c = LIGNE.Carburant_rembourser__c / VALEUR; 
                        if(LIGNE.Entretien_lavage__c != null && LIGNE.Entretien_lavage__c != 0)    
                            LIGNE.Entretien_lavage__c = LIGNE.Entretien_lavage__c / VALEUR; 
                        if(LIGNE.P_age_parking__c != null && LIGNE.P_age_parking__c != 0)
                            LIGNE.P_age_parking__c = LIGNE.P_age_parking__c / VALEUR; 
                        if(LIGNE.D_p_d_jeuner__c != null && LIGNE.D_p_d_jeuner__c != 0)
                            LIGNE.D_p_d_jeuner__c = LIGNE.D_p_d_jeuner__c / VALEUR;
                    }catch(NullPointerException e){
                        System.debug('Champs vides : ' + e.getMessage());
                    }
                }
                break;
            }
        }
    }

    et le trigger associé :

    Code JAVA : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    //Ajout de tous les champs concernés par la conversionLigne
    trigger conversionLigne on Infogramme__c (after insert, after update){
        Set<Id> LignesAModifier = new Set<Id>{};
        for(Infogramme__c NOTE : Trigger.new){
            if (NOTE.CurrencyIsoCode == 'CAD' || NOTE.CurrencyIsoCode == 'USD' || NOTE.CurrencyIsoCode == 'EUR' || NOTE.CurrencyIsoCode == 'AED' || NOTE.CurrencyIsoCode == 'RUB' || NOTE.CurrencyIsoCode == 'DKK'){
                LignesAModifier.add(NOTE.Id);
            }
        }
     
        LignesAModifier.remove(null);
        List<Ligne_de_frais__c> LIGNES = [SELECT Id, Total_frais_journ_e__c, Total_frais_converti__c, Date__c, CurrencyIsoCode, 
                                                Carburant_carte_soci_t__c, Carburant_rembourser__c, Entretien_lavage__c, P_age_parking__c, D_p_d_jeuner__c, 
                                                D_p_d_ner__c, D_p_soir_e_tape__c, Inv_d_jeuner__c, Inv_d_ner__c, Avion__c, Train__c, 
                                                Autre_transport__c, Affr_courrier__c, Autres_frais__c, Fourniture_admin__c 
                                          FROM Ligne_de_frais__c WHERE Infogramme__r.Id IN :LignesAModifier];
     
        classConversion.convertirMontant(LIGNES);
     
        upsert LIGNES;
    }

    Je n'ai pas référencé tous les champs dont j'ai besoin, j'ai simplifié un peu mais voici l'erreur que SalesForce me retourne :

    System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, conversionLigne: execution of AfterUpdate

    caused by: System.DmlException: Upsert failed. First exception on row 0 with id YYYYYYYYYYYYYYY; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, conversionLigne: maximum trigger depth exceeded
    Infogramme trigger event AfterUpdate for [XXXXXXXXXXXXX]
    Infogramme trigger event AfterUpdate for [XXXXXXXXXXXXX]
    Infogramme trigger event AfterUpdate for [XXXXXXXXXXXXX]
    Infogramme trigger event AfterUpdate for [XXXXXXXXXXXXX]
    Infogramme trigger event AfterUpdate for [XXXXXXXXXXXXX]: []

    Trigger.conversionLigne: line 22, column 1: []


    Selon ce que j'ai pu voir à propos de cette erreur, et lorsque j'ai lancé la console de débogage, c'est que le traitement de la boucle est infini et donc dépasse la limite de récursivité de SalesForce.
    J'ai également vu qu'il est conseillé de sortir toutes les requêtes SOQL de la boucle FOR mais je ne vois pas comment faire ici.

    Tous conseil est bon à prendre. En espérant que cela inspire quelqu'un.

    Merci d'avance !
    Le seul bogue à ne pas corriger c'est celui qui fait fonctionner le projet.

  7. #7
    Modérateur
    Avatar de Overcrash
    Homme Profil pro
    Architecte Logiciel et responsable CRM (Salesforce)
    Inscrit en
    Mai 2008
    Messages
    1 254
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Architecte Logiciel et responsable CRM (Salesforce)
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 1 254
    Points : 1 875
    Points
    1 875
    Par défaut
    Je regarde ça ce weekend je suis pas mal débordé cette semaine

    Over
    ---
    Overcrash

    Je ne lis pas les codes qui ne sont pas indentés.
    Merci de les messages utiles en cliquant en bas à droite du message

    Bloqué par le firewall pour accéder au chat ? Essayez avec l'adresse en direct : http://87.98.168.209/

  8. #8
    Membre régulier
    Homme Profil pro
    Salesforce Developer
    Inscrit en
    Mai 2013
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Australie

    Informations professionnelles :
    Activité : Salesforce Developer

    Informations forums :
    Inscription : Mai 2013
    Messages : 14
    Points : 99
    Points
    99
    Par défaut
    Ton problem est que quand tu insert/update Infograme__c, tu update Ligne_de_Frais__c.
    Tes 2 object sont probablement liee par une Master-Relationship et le fait que tu update tes lignes de frais update de nouveau ton parent, qui est Infograme__c, voila ta boucle infini.
    Un trigger qui appelle un trigger qui appelle un trigger indefiniment.

    Le truc c'est de bloquer ton trigger avec une variable static juste avant de update lignes de frais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Utils
    {
           public static boolean triggerTracker {get; set;}
    }
    trigger conversionLigne on Infogramme__c (after insert, after update){
        if (Utils.triggerTracker == true) return;
        //...
        Utils.triggerTracker  = true;
        upsert LIGNES;
    }
    ////

  9. #9
    Membre habitué Avatar de TheChovix
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2014
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2014
    Messages : 77
    Points : 166
    Points
    166
    Par défaut
    Merci brovasi pour ta réponse très pertinente.

    En effet, je me rend compte que cela aurait pu être une solution.

    Toutefois, j'ai depuis trouvé une alternative fonctionnelle à mon problème.

    J'ai également revu le fonctionnement du trigger. En effet, le besoin n'était plus ici de modifier des champs dans la table mais bel et bien de créer des valeurs en fonction du taux de change d'une devise, et d'utiliser ces valeurs avec des champs de type Formule pour les extraire ensuite dans un rapport SalesForce.

    Mais, n'ayant pas les compétences requises pour valider le bon fonctionnement de ce code, j'aimerai savoir ce que vous en pensez.

    Voici le code de la classe:

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    public class classConversion {
        public static void convertirMontant(Ligne_de_frais__c[] LIGNES) {
            for (Ligne_de_frais__c LIGNE :LIGNES){
                List<DatedConversionRate> DeviseActuelle = [SELECT ConversionRate, IsoCode, StartDate FROM DatedConversionRate WHERE IsoCode = :LIGNE.CurrencyIsoCode AND StartDate = :LIGNE.Date__c LIMIT 1];
                for(DatedConversionRate devise: DeviseActuelle){
                    LIGNE.Valeur_devise_actuelle__c = devise.ConversionRate;
                    break;
                }
     
                if(LIGNE.CurrencyIsoCode == 'EUR'){
                    LIGNE.Valeur_devise_actuelle__c = 1;
                    LIGNE.Valeur_devise_vers_EUR__c = 1;
                }
                else{
                    LIGNE.Valeur_devise_vers_EUR__c = LIGNE.Valeur_devise_actuelle__c;
                }                
     
                List<DatedConversionRate> listeDevise=[SELECT ConversionRate, IsoCode, StartDate FROM DatedConversionRate WHERE StartDate = :LIGNE.Date__c];
                for(DatedConversionRate ValeurDevise :listeDevise){
                    if(ValeurDevise.IsoCode == 'CAD'){
                        LIGNE.Valeur_devise_vers_CAD__c = LIGNE.Valeur_devise_actuelle__c / ValeurDevise.ConversionRate;
                        continue;
                    }
                    else if(ValeurDevise.IsoCode == 'USD'){
                        LIGNE.Valeur_devise_vers_USD__c = LIGNE.Valeur_devise_actuelle__c / ValeurDevise.ConversionRate;
                        continue;
                    }
                    else if(ValeurDevise.IsoCode == 'GBP'){
                        LIGNE.Valeur_devise_vers_GBP__c = LIGNE.Valeur_devise_actuelle__c / ValeurDevise.ConversionRate;
                        continue;
                    }
                    else if(ValeurDevise.IsoCode == 'AED'){
                        LIGNE.Valeur_devise_vers_AED__c = LIGNE.Valeur_devise_actuelle__c / ValeurDevise.ConversionRate;
                        continue;
                    }
                    else if(ValeurDevise.IsoCode == 'DKK'){
                        LIGNE.Valeur_devise_vers_DKK__c = LIGNE.Valeur_devise_actuelle__c / ValeurDevise.ConversionRate;
                        continue;
                    }
                    else if(ValeurDevise.IsoCode == 'RUB'){
                        LIGNE.Valeur_devise_vers_RUB__c = LIGNE.Valeur_devise_actuelle__c / ValeurDevise.ConversionRate;
                        continue;
                    }
                    else
                        break;
                }
                continue;
            }
        }
    }

    Et celui du trigger :

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    trigger conversionLigne on Infogramme__c (after insert, after update){
        Set<Id> LignesAModifier = new Set<Id>{};
        for(Infogramme__c NOTE : Trigger.new){
            List<DatedConversionRate> ListeDevise = [SELECT IsoCode, StartDate FROM DatedConversionRate WHERE IsoCode = :NOTE.CurrencyIsoCode LIMIT 1];
            for(DatedConversionRate LISTE : ListeDevise){
                LignesAModifier.add(NOTE.Id);
                    break;
            }
        }
     
        List<Ligne_de_frais__c> LIGNES = [SELECT Id, Valeur_devise_actuelle__c, Valeur_devise_vers_CAD__c, Valeur_devise_vers_USD__c, 
                                            Valeur_devise_vers_GBP__c, Valeur_devise_vers_EUR__c, Valeur_devise_vers_DKK__c, Valeur_devise_vers_RUB__c, 
                                            Valeur_devise_vers_AED__c, Date__c, CurrencyIsoCode
                                            FROM Ligne_de_frais__c WHERE Infogramme__r.Id IN :LignesAModifier];
     
     
        classConversion.convertirMontant(LIGNES);
     
        upsert LIGNES;
    }

    Merci encore pour ta réponse.
    Le seul bogue à ne pas corriger c'est celui qui fait fonctionner le projet.

  10. #10
    Membre régulier
    Homme Profil pro
    Salesforce Developer
    Inscrit en
    Mai 2013
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Australie

    Informations professionnelles :
    Activité : Salesforce Developer

    Informations forums :
    Inscription : Mai 2013
    Messages : 14
    Points : 99
    Points
    99
    Par défaut
    1) Un truc que tu dois changer absolument c'est ta SQL query dans ta boucle for, tres mauvais ca ;-) not best practice.
    Salesforce limite le nombre de query a 100 par transaction. Donc si tu a plus de 100 lignes de frais, tu aura une erreur.
    Tu fais la faute plusieurs fois je vois, tu devrais vraiment revoir ta logique si tu veux optimiser ton code.
    L'utilisation de map aide beaucoup par exemple, c'est ce que j'utilise le plus.
    Voici un simple example, si je me base sur ton code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    trigger conversionLigne on Infogramme__c (after insert, after update){
        Set<Id> LignesAModifier = new Set<Id>{};
        Map<String,DatedConversionRate> rates = new Map<String,DatedConversionRate>();
        for(Infogramme__c NOTE : Trigger.new){
            rates.put(NOTE.CurrencyIsoCode,null);
        }
    
        for(DatedConversionRate r : [SELECT IsoCode, StartDate FROM DatedConversionRate WHERE IsoCode IN :rates.keySet()]){
            rates.put(r.IsoCode,r)
        }
    
        for(Infogramme__c NOTE : Trigger.new){
            if (rates.get(NOTE>CurrencyISOCode) != null){
                LignesAModifier.add(NOTE.ID);
            }
        }
     
        List<Ligne_de_frais__c> LIGNES = [SELECT Id, Valeur_devise_actuelle__c, Valeur_devise_vers_CAD__c, Valeur_devise_vers_USD__c, 
                                            Valeur_devise_vers_GBP__c, Valeur_devise_vers_EUR__c, Valeur_devise_vers_DKK__c, Valeur_devise_vers_RUB__c, 
                                            Valeur_devise_vers_AED__c, Date__c, CurrencyIsoCode
                                            FROM Ligne_de_frais__c WHERE Infogramme__r.Id IN :LignesAModifier];
     
     
        classConversion.convertirMontant(LIGNES);
     
        upsert LIGNES;
    }
    2) Ton after insert est tres inutile parce que tu n'aura jamais de ligne de frais quand tu crees un Infograme__c

    3) J'aurais plutot cree le trigger sur l'object Ligne_de_frais__c et non Infograme__c

  11. #11
    Membre habitué Avatar de TheChovix
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2014
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2014
    Messages : 77
    Points : 166
    Points
    166
    Par défaut
    Merci pour tes réponses, elles me sont vraiment très utiles.

    1) J'avais déjà eu ce problème de dépassement de la limite des requêtes SOQL à cause des boucles FOR, et j'avais donc essayé de toutes les enlever mais je ne savais pas par quel moyen. Je vais essayé ce nouveau fonctionnement.

    2) Concernant le after insert, je l'ai retiré dans une version précédente de mon code. Je m'étais également aperçu que le code en after insert n'était pas couvert, j'ai juste oublié de faire la modification. My bad !

    3) C'est ce que j'avais déjà essayé de faire au commencement de mon projet sur SalesForce, mais je m'étais heurté à beaucoup de problèmes, en particulier parce que je suis novice en la matière, et les attentes de mon supérieur m'ont obligées à produire une solution rapidement.

    C'est pour cela que, maintenant le projet déployé en production, je peux réfléchir en SandBox à une version optimisée et plus en accord avec les bonnes pratiques. Cela me permet également de me former.
    D'ailleurs, j'aurai quelques questions...

    Est-ce que tu pourrais me commenter le code que tu as publié ? A quoi sert le Map ?

    Finalement, j'ai compris le fonctionnement, j'aurai du mieux le relire avant de répondre.
    Ce que j'aimerai plutôt savoir, vu que tu es visiblement plus compétent que moi dans ce domaine, comment est-ce je pourrai optimiser le code de ma classe ?

    Encore merci !
    Le seul bogue à ne pas corriger c'est celui qui fait fonctionner le projet.

  12. #12
    Membre régulier
    Homme Profil pro
    Salesforce Developer
    Inscrit en
    Mai 2013
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Australie

    Informations professionnelles :
    Activité : Salesforce Developer

    Informations forums :
    Inscription : Mai 2013
    Messages : 14
    Points : 99
    Points
    99
    Par défaut
    Je pense que si deja tu enleve tes requetes SQL de tes boucles et que tu utilise des maps, ce sera deja un bon debut. Regarde mon example et essai de faire un peu pareil

  13. #13
    Membre habitué Avatar de TheChovix
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2014
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2014
    Messages : 77
    Points : 166
    Points
    166
    Par défaut
    C'est ce que je vais faire, merci encore.
    Le seul bogue à ne pas corriger c'est celui qui fait fonctionner le projet.

  14. #14
    Membre régulier
    Homme Profil pro
    Salesforce Developer
    Inscrit en
    Mai 2013
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Australie

    Informations professionnelles :
    Activité : Salesforce Developer

    Informations forums :
    Inscription : Mai 2013
    Messages : 14
    Points : 99
    Points
    99
    Par défaut
    Hesite pas a me montrer ton code quand tu aura finis ou si tu as des question bien specifiques, happy to help.

  15. #15
    Modérateur
    Avatar de Overcrash
    Homme Profil pro
    Architecte Logiciel et responsable CRM (Salesforce)
    Inscrit en
    Mai 2008
    Messages
    1 254
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Architecte Logiciel et responsable CRM (Salesforce)
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 1 254
    Points : 1 875
    Points
    1 875
    Par défaut
    Comme dit brovasi,

    Les requêtes SOQL jamais dans une boucle
    Tu la mets au dessous et tu boucle sur le résultat sinon tu fais comment dans l'exemple qu'il a donné ou tu la passe directement dans le foreach.
    ---
    Overcrash

    Je ne lis pas les codes qui ne sont pas indentés.
    Merci de les messages utiles en cliquant en bas à droite du message

    Bloqué par le firewall pour accéder au chat ? Essayez avec l'adresse en direct : http://87.98.168.209/

  16. #16
    Membre habitué Avatar de TheChovix
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2014
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2014
    Messages : 77
    Points : 166
    Points
    166
    Par défaut
    Merci de vos conseils,

    Je n'ai malheureusement pas trop eu le temps de modifier mon code, compte tenu que j'ai été redirigé vers d'autres missions.

    Je ne suis pas encore bien sûr de maîtriser le fonctionnement du Map mais je vais quand même essayer d'adapter le code à ma classe afin d'éviter ces requêtes SOQL dans la boucle.

    Il faudra également que j'améliore l'évolutivité de mon code, qui laisse vraiment à désirer, mais bon ça c'est une autre histoire.

    Merci encore, je posterai mon code si j'ai des questions.
    Le seul bogue à ne pas corriger c'est celui qui fait fonctionner le projet.

  17. #17
    Modérateur
    Avatar de Overcrash
    Homme Profil pro
    Architecte Logiciel et responsable CRM (Salesforce)
    Inscrit en
    Mai 2008
    Messages
    1 254
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Architecte Logiciel et responsable CRM (Salesforce)
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 1 254
    Points : 1 875
    Points
    1 875
    Par défaut
    La map c'est simple c'est une table qui fonctionne comme ceci
    Clef - Valeur
    Donc en gros chaque clef est associé à une valeur. Je te conseille de lire la doc à ce sujet.

    Pour les requêtes dans une boucle c'est pas déconseillé mais interdit Tu vas faire péter les limites rapidement et dés que tu vas avoir un peu de données c'est mort... Donc à toi de voir si tu as le choix faut le faire
    ---
    Overcrash

    Je ne lis pas les codes qui ne sont pas indentés.
    Merci de les messages utiles en cliquant en bas à droite du message

    Bloqué par le firewall pour accéder au chat ? Essayez avec l'adresse en direct : http://87.98.168.209/

Discussions similaires

  1. [sql serveur 2005] Conversion d'un montant en lettre (continuité)
    Par amine_co2 dans le forum MS SQL Server
    Réponses: 1
    Dernier message: 26/11/2009, 10h06
  2. [TP] Conversion d'un montant en lettres
    Par ildiodelgsm dans le forum Turbo Pascal
    Réponses: 11
    Dernier message: 05/05/2008, 17h45
  3. [WinDev 7.5] Conversion d'un montant en lettres
    Par HRAICHI dans le forum WinDev
    Réponses: 8
    Dernier message: 02/10/2006, 12h57

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo