2

Whenever a status of a meeting is changed to complete, i want to lock it for editing. so we created a custom field on a the Event_Details__C field, and a validation on the Event.

whenever this field equals true, an error should pop.

Field Name: Event_Locked__C

Validation: Event_Details__r.Event_Locked__c

That's the code that populates this field:

private void populateMeetingStatus()
    {
        system.debug('populateMeetingStatus');

        if(isExecutingPopulateMeetingStatus){ // if was executed during the same context,avoid recursion
            return;
        }
        isExecutingPopulateMeetingStatus = true;

        Set<Id> eventDetailsSetId = new Set<Id>();

        Map<Id, boolean> eventDetailsToStatusMap = new Map<Id, boolean>();

        for(Event event_i : (List<Event >)Trigger.new)
        {
            if(event_i.Event_Details__C != null)
            {
                if( ((Event)trigger.oldMap.get(event_i.Id)).Meeting_Status__c != event_i.Meeting_Status__c)
                {

                    if(event_i.Meeting_Status__c == 'Completed' )
                    {
                        eventDetailsToStatusMap.put(event_i.Event_Details__C,true); 
                    }
                }
            }
        }

        if(!eventDetailsToStatusMap.isEmpty())
        {
            eventDetailsSetId = eventDetailsToStatusMap.keySet();

            List<Event_Details__C> listToUpdate = [SELECT Id,Event_Locked__C From Event_Details__C where Id in:eventDetailsSetId];

            if(!listToUpdate.isEmpty())
            {
                for(Event_Details__C e : listToUpdate)
                {
                    e.Event_Locked__c = eventDetailsToStatusMap.get(e.Id);
                }
            }

            try
            {
                update listToUpdate;
            }
            catch  (DmlException ex)
            {
                Trigger.New.get(0).addError(ex);
            }
        }
    }

this code runs in afterInsert and afterUpdate

for some reason, why i try to edit the event status from open to complete i receive the following error:

Error:Update failed. First exception on row 0 with id a1G9E000000ImGuUAK; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, Update failed. First exception on row 0 with id 00U9E000001guqcUAA; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, You cannot edit a 'Completed' Meeting. Please contact your Productivity Analyst.: [Meeting_Status__c]: []

i have no idea why, tried everything

3
  • 1
    I don't believe it's related to your error, but I'm skeptical of that try/catch pattern. Trapping all DML exceptions and laying them against the first record in the transaction may cause problems in other circumstances.
    – David Reed
    Jan 10, 2018 at 13:54
  • 1
    The first thing that comes to mind is that you may have some workflow field update that's causing your update trigger to fire again. You do have some recursion control I see, but the given code doesn't include the declaration of your recursion control variable, so I can't assume that your recursion control is actually working. Also, why after insert and after update (as opposed to using before triggers)? Why use Apex at all here? A workflow rule + field update + validation rule would be my first stop. After that, I'd use Approval.lock().
    – Derek F
    Jan 10, 2018 at 13:58
  • Derek, youre right. What happened is Event Object update Event_Details__C, and Event_Details__C tried to update Event back. i bypassed it and it works
    – Dana Griff
    Jan 11, 2018 at 13:08

3 Answers 3

0

Your validation rule isn't checking to see whether the Event_Locked__c field is changed, so it's firing when your trigger actually updates that field. Since you cannot use the ISCHANGED() function with a cross-object relationship (I stand corrected on this point), you'll need to populate the lock field on the Event object itself rather than the related Event Details object.

5
  • no, because next time a user wants to edit the record, i want the validation to fire. and it wont, because the event locked field wasnt changed
    – Dana Griff
    Jan 10, 2018 at 14:18
  • 1
    That's why you need to look for !ISCHANGED(). You can also write it NOT(ISCHANGED()). That should fire the validation only when the Lock field is not changed.
    – David Reed
    Jan 10, 2018 at 14:19
  • i see, but i don't think its possible to create a validation rule on a relationship
    – Dana Griff
    Jan 10, 2018 at 16:13
  • @DanaGriff You can create a validation rule on a relationship, but I was mistaken in that you cannot use the ISCHANGED() function on a cross-object reference. You may need to alter your data model slightly.
    – David Reed
    Jan 10, 2018 at 16:40
  • what do you mean by altering my data model?
    – Dana Griff
    Jan 11, 2018 at 9:56
0

What happened is Event Object updated Event_Details__C, and Event_Details__C tried to update Event back (some other update), when the trigger fired. i prevented the trigger from running and it works now.

-2

you are checking for Meeting_Status__c == 'Completed' .Which is wrong. you should check for not equal to Completed

private void populateMeetingStatus()
{
    system.debug('populateMeetingStatus');

    if(isExecutingPopulateMeetingStatus){ // if was executed during the same context,avoid recursion
        return;
    }
    isExecutingPopulateMeetingStatus = false;

    Set<Id> eventDetailsSetId = new Set<Id>();

    Map<Id, boolean> eventDetailsToStatusMap = new Map<Id, boolean>();

    for(Event event_i : (List<Event >)Trigger.new)
    {
        if(event_i.Event_Details__C != null)
        {
            if( ((Event)trigger.oldMap.get(event_i.Id)).Meeting_Status__c != event_i.Meeting_Status__c)
            {

                if(event_i.Meeting_Status__c == 'Completed' )
                {
                    eventDetailsToStatusMap.put(event_i.Event_Details__C,true); 
                }
            }
        }
    }

    if(!eventDetailsToStatusMap.isEmpty())
    {
        eventDetailsSetId = eventDetailsToStatusMap.keySet();

        List<Event_Details__C> listToUpdate = [SELECT Id,Event_Locked__C From Event_Details__C where Id in:eventDetailsSetId];

        if(!listToUpdate.isEmpty())
        {
            for(Event_Details__C e : listToUpdate)
            {
                e.Event_Locked__c = eventDetailsToStatusMap.get(e.Id);
            }
        }

        try
        {
            update listToUpdate;
        }
        catch  (DmlException ex)
        {
            Trigger.New.get(0).addError(ex);
        }
    }
}
4
  • Why? The code as posted appears to be correct in setting the lock field when the status is changed to Completed.
    – David Reed
    Jan 10, 2018 at 14:30
  • Oh i see .set the isExecutingPopulateMeetingStatus to false inside the method.due to this it is causing recursion.and set it true where you have declared it.I have updated the code
    – keepler
    Jan 10, 2018 at 14:40
  • no, it should be true and not false. when its true i prevent it from running again
    – Dana Griff
    Jan 10, 2018 at 16:12
  • @jdow, please explain the changes you are asking for. They do not make sense as a solution to the stated problem.
    – David Reed
    Jan 10, 2018 at 16:38

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .