• K.G.
  • NEWBIE
  • 20 Points
  • Member since 2014

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 4
    Questions
  • 15
    Replies
Dear Salesforce Developer community,

Every time "Opportunity.StageName" or "Opportunity.Program__c" gets changed in any way (user edit, Apex, Workflow, Process), my department needs the value of "Opportunity.OwnerId" verified and possibly changed.

The rules of the change are complicated enough that I need to put them in code, which I'm comfortable doing.

According to business rules, I want to enforce this being the "final clean-up" on DML to "Opportunity" records.  If some Apex/WF/PB's themselves that I don't personally write/control change "StageName" or "Program__c," I want to clean up after that.

What I can't figure out is how to actually squeeze my code in "last" without causing infinite loops.

I can follow best practices like consolidating what triggers already exist into "1 per object," using "RUN_ONCE" logic on the methods they call, etc.

But how do I account for developers after me or fellow admins writing Processes (which seem to execute after, rather than before, triggers) and try to squeeze this logic in "after" their potential effects on "Opportunity.StageName" and "Opportunity.Program__c"?

Thanks so much,
K
  • January 11, 2016
  • Like
  • 0
Dear Developer community,
I wrote the big code block at the bottom of this post, and it works nicely (in a sandbox with 20 Contacts) from the following call:
ScheduledMiscellany.updateHasOppTypeGAOnContact((new Map<Id,SObject>([SELECT Id FROM Contact])).keySet());
Now I want to run it at midnight every night.  And since my production environment has over 100,000 Contacts - so I need to break up the processing into chunks.
(Right now, it will be our 1st scheduled bit of code, but it might not be the last once I know what I'm doing.)

I am pretty mind-boggled by the documentation I'm reading on batch and scheduling - I am just not figuring out how to do it.

Would anyone mind showing me how to do it with my code?

Thanks!
-K

 
public class ScheduledMiscellany {   
    
    public static void updateHasOppTypeGAOnContact(Set<Id> cIdSet) {
        // Indicate that this method's execution is starting
        System.debug('START: ScheduledMiscellany.updateGAOppCountsOnContact()');
        
        Id defaultOppRecordTypeID = [SELECT Id FROM RecordType 
                                     WHERE RecordType.DeveloperName = 'Graduate_Admissions' 
                                     AND RecordType.SObjectType = 'Opportunity' LIMIT 1].Id;
        if (defaultOppRecordTypeID == NULL) {
            System.debug('WARNING: Opportunity query would fail. Unable to find opportunity record type ( Graduate Admissions ).');
            return;      // Do not proceed.
        }
        
        // Set up a map to hold the values to write
        Map<Id, Boolean> contactsAndValuesMap = new Map<Id, Boolean>();
        
        // Pull a SOQL query showing all Contacts with an un-checked checkbox that needs to get checked
        List<AggregateResult> gaNeedsChangeToTrue = [SELECT ContactID
                                                     FROM OpportunityContactRole
                                                     WHERE IsPrimary = true
                                                     AND IsDeleted=false 
                                                     AND Opportunity.RecordTypeID = :defaultOppRecordTypeID 
                                                     AND Opportunity.IsDeleted = false 
                                                     AND ContactID IN :cIdSet
                                                     AND Contact.Has_Any_Opportunities_Grad_Admissions__c = false 
                                                     GROUP BY ContactID 
                                                     HAVING COUNT(ID) > 0];
        
        
        // Pull a different query showing all Contacts with a checked checkbox that needs to get un-checked
        List<Contact> gaNeedsChangeToFalse = [SELECT Id
                                              FROM Contact
                                              WHERE Has_Any_Opportunities_Grad_Admissions__c = true 
                                              AND Id IN :cIdSet
                                              AND Id NOT IN (SELECT ContactId 
                                                             FROM OpportunityContactRole 
                                                             WHERE IsPrimary = true
                                                             AND IsDeleted=false 
                                                             AND Opportunity.RecordTypeID = :defaultOppRecordTypeID 
                                                             AND Opportunity.IsDeleted = false)];
        
        // Iterate through the two lists, casting their parts to new data types and setting the values of the Map defined above.
        for (AggregateResult x : gaNeedsChangeToTrue) { contactsAndValuesMap.put((Id)x.get('ContactId'), true); }
        for (Contact x : gaNeedsChangeToFalse) { contactsAndValuesMap.put((Id)x.get('Id'), false); }
        
        // Create a list of all Contact objects needing a change
        List<Contact> cs = [SELECT Id, Has_Any_Opportunities_Grad_Admissions__c FROM Contact 
                                    WHERE IsDeleted = false
                                    AND Id IN :contactsAndValuesMap.keySet()];
        
        
        
        // Update the list of Contact objects with their values from the Map (or 0 if Contact not in the map)
        System.debug('About to start the for loop that assigns true/false to Has_Any_Opportunities_Grad_Admissions__c');
        for (Contact c : cs) {
            if (contactsAndValuesMap.get(c.Id) == null) {
                System.debug('Unexpected error - Contact no longer exists');
            } else {
                System.debug('Has_Any_Opportunities_Grad_Admissions__c for ' + c.Id + ' is ' + c.Has_Any_Opportunities_Grad_Admissions__c);
                System.debug('Setting the true/false ' + c.Id + ' to be ' + contactsAndValuesMap.get(c.Id));
                c.Has_Any_Opportunities_Grad_Admissions__c = contactsAndValuesMap.get(c.Id);
                System.debug('Has_Any_Opportunities_Grad_Admissions__c for ' + c.Id + ' is ' + c.Has_Any_Opportunities_Grad_Admissions__c);
            }
            System.debug('Just ended the for loop that assigns true/false to Has_Any_Opportunities_Grad_Admissions__c');
        }

        
        // Save changes to database
        System.debug('About to start DML to the list of Contacts');
        try {
            UPDATE cs;
            System.debug('Database Confirmation: Update to list of Contacts succeeded.');
        }
        catch (System.DmlException e) {
            System.debug('Database Error: Update failed.');
            for (Integer i = 0; i < e.getNumDml(); i++) {
                System.debug(e.getDmlMessage(i)); 
            }
        }
        System.debug('Just ended the DML to the list of Contacts');
        
        // Indicate that this method's execution is ending
        System.debug('END: ScheduledMiscellany.updateGAOppCountsOnContact()');
    }
}




 
  • November 20, 2015
  • Like
  • 0
Hi Developers,
I am writing a VisualForce page that displays a pageBlockTable full of "wrapper-class"-wrapped CampaignMember records (and their associated details). It is for quick marking of whether people came or not at the event itself.

I'd like to have a column at the far right of my table with a "Set Status To Attended" button (or link) that does an IMMEDIATE update (including DML ... I might scale that back if performance is an issue, but right now the request is "live edits") of the "Status" of the CampaignMember record represented by the row the button appears in.

The reason I don't just want to expose "Status" as an "inlineEdit" or "inputField" is that SalesForce natively exposes more possibilities than are appropriate for the Campaign attached to that CampaignMember. Plus, users would like the single button better.

Even though my wrapped CampaignMember record is already identified as 'var="cm"' to the pageBlockTable, I can't figure out how to pass that back to a method in my controller as part of what the button/link does when clicked.

How should I get the "record whose button is being clicked" back to a method in the controller so that I can have the method do its magic? Apex Params don't seem to do what I thought they would (pass a parameter to a public Java method).

Thank you!
  • July 28, 2015
  • Like
  • 0
Hi Developer Forums,
I need to take a String of the format "July 9, 2015" and turn it into a Date object.

Apex doesn't seem to let me instantiate DateFormat / SimpleDateFormat objects, so I can't write my own format to use with a ".parse()" method.  The "9" and the "2015" are close enough to integers, so I can do some annoying string transformation to get my input to "Date.parse()" into the type of string Apex expects, but I really don't want to write 12 lines of code to turn spelled-out months into numbers.

Ordinarily in Java, I'd just try this:
DateFormat myFormat = new SimpleDateFormat('MMMM d, yyyy', Locale.ENGLISH);
Date myDate = myFormat.parse(myQuirkyDateString);
(via http://stackoverflow.com/a/11493647)

But that doesn't compile in Apex.

What can I do to turn this type of string into a Date?

Thanks!
-K.
  • July 09, 2015
  • Like
  • 0
Dear Salesforce Developer community,

Every time "Opportunity.StageName" or "Opportunity.Program__c" gets changed in any way (user edit, Apex, Workflow, Process), my department needs the value of "Opportunity.OwnerId" verified and possibly changed.

The rules of the change are complicated enough that I need to put them in code, which I'm comfortable doing.

According to business rules, I want to enforce this being the "final clean-up" on DML to "Opportunity" records.  If some Apex/WF/PB's themselves that I don't personally write/control change "StageName" or "Program__c," I want to clean up after that.

What I can't figure out is how to actually squeeze my code in "last" without causing infinite loops.

I can follow best practices like consolidating what triggers already exist into "1 per object," using "RUN_ONCE" logic on the methods they call, etc.

But how do I account for developers after me or fellow admins writing Processes (which seem to execute after, rather than before, triggers) and try to squeeze this logic in "after" their potential effects on "Opportunity.StageName" and "Opportunity.Program__c"?

Thanks so much,
K
  • January 11, 2016
  • Like
  • 0
Hi Developer Forums,
I need to take a String of the format "July 9, 2015" and turn it into a Date object.

Apex doesn't seem to let me instantiate DateFormat / SimpleDateFormat objects, so I can't write my own format to use with a ".parse()" method.  The "9" and the "2015" are close enough to integers, so I can do some annoying string transformation to get my input to "Date.parse()" into the type of string Apex expects, but I really don't want to write 12 lines of code to turn spelled-out months into numbers.

Ordinarily in Java, I'd just try this:
DateFormat myFormat = new SimpleDateFormat('MMMM d, yyyy', Locale.ENGLISH);
Date myDate = myFormat.parse(myQuirkyDateString);
(via http://stackoverflow.com/a/11493647)

But that doesn't compile in Apex.

What can I do to turn this type of string into a Date?

Thanks!
-K.
  • July 09, 2015
  • Like
  • 0
How can take entire metadata backup of my production org apart from using Force.com IDE or Third party priced tools.
Solutions and suggestion are welcome, thanks in advance.
 
i am trying to fetch fields from a aggregteresult but it is giving me error :Invalid field Time_Account_Mapping__c for SObject AggregateResult
 
Time__c tes = [select Time_Account_Mapping__c from Time__c order by LastModifiedById desc limit 1];
     
        AggregateResult obj = [Select Time_Account_Mapping__c,sum(Hours__c) from time__c group by Time_Account_Mapping__c having Time_Account_Mapping__c in (:tes.Time_Account_Mapping__c)];

	Account ppla = new Account();
        ppla.id = obj.Time_Account_Mapping__c;
        ppla.Total_Client_Hour__c=obj.sum(Hours__c);
    //    ppla.Total_Client_Hour__c = test.Unknown_Field__1;
        update ppla;
Help me out here.
Thanks
I accidentialy pressed the downvote instead of upvote button on ideas https://success.salesforce.com/ideaSearch. Now I can't "undo" this. Any way to upvote it?
I am looking to find which contacts are our most prolific.
Is there a simple way without triggers?

Set<String> setUserID = new Set<String>{'1','55','80','12', '6','22','87'};

 

Now I want to select random element from it.  Below random method is not yet exist. So how can I select random element from this set. Any other idea?

 

System.debug('Random Set Element  = ' +setUserID.random());

 

I am trying to delete an Action Plan from an account record.  Here is the error that I get:

 

There were custom validation error(s) encountered while saving the affected record(s). The first validation error encountered was "Apex trigger ActionPlanTrigger caused an unexpected exception, contact your administrator: ActionPlanTrigger: execution of BeforeDelete caused by: System.QueryException: Non-selective query against large object type (more than 100000 rows). Consider an indexed filter or contact salesforce.com about custom indexing. Even if a field is indexed a filter might still not be selective when: 1. The filter value includes null (for instance binding with a list that contains null) 2. Data skew exists whereby the number of matching rows is very large (for instance, filtering for a particular foreign key value that occurs many times): Trigger.ActionPlanTrigger: line 18, column 1". 

 

Any help on this would be appreciated!  Thanks, in advance!

 

Steve

I've written a trigger in my sandbox to copy the primary contact Role and ID values into 2 opportunity custom fields but it's not firing and I just cant figure out why.

 

Any help would be appreciated, I'm sure it's an oversight on my part.

 

Trigger PrimaryContactCopy on Opportunity(before insert,before update){
OpportunityContactRole Roles = new OpportunityContactRole();
for(Opportunity opp:Trigger.new){
Roles = [select Id,IsPrimary,ContactId, Role from OpportunityContactRole where IsPrimary=True AND opportunity.id=:opp.Id];
opp.Name__c = Roles.ContactId;
opp.Email__c = Roles.Role;
update opp;
 } 
}

 

  • December 13, 2010
  • Like
  • 0