function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
OnCloud9OnCloud9 

Snapshot of current opportunity stage

Folks-

 

Have a quick question.  And hopefully you have a quick solution.

 

I have a master detail relationship between Opportunity (master) and Opportunity Contacts (child).

 

What I'd like to do is take a "snapshot" of the current opportunity stage when a certain Opportunity Contacts picklist value = "ABCD".

 

I can do a roll-up summary of the "last modified date" and stamp that on the opportunity.  Then I created this formula field on the opportunity to see if A) the date is populated and B) stamp the current opportunity stage.

 

IF(NOT(ISNULL( Test_roll_up__c )), text(StageName),"")

 

However, after the fact, if I change the stage, the field above ^^ also changes.  I tried to stop this via validation rule but it stopped the opportunity from saving all together.

 

Now I'm stuck and need your help.  How can I "stamp" the current stage and never allow it to be changed?  Any ideas/thoughts are appreciated.

 

Thank you-

Andy BoettcherAndy Boettcher

My gut reaction is "hey!  Workflow initiated Field Update!".  However - cross object Workflow isn't coming out until Spring...so don't base your current decision on that.

 

For right now - if you use a Formula field, that value is dynamic and will change.  If you need a true historical "snapshot" of data, you'll have to head to an APEX trigger to save the data off to a custom field.

 

If you need help framing it up, let me know.

 

-Andy

OnCloud9OnCloud9
Hey Andy,
Thanks for the reply.  I wish they had full cross object workflow live already =)
As far as the apex is concerned, I'm a newbie but trying to learn.  Can you please help me setup a trigger that'll accomplish this?
 

 

Andy BoettcherAndy Boettcher

Aaack - my apologies...you cannot trigger off of the Opportunity Contacts directly, but we could trigger on the Opportunity object based on your Custom Rollup Summary field changing.

 

The way this should work is that once you update your Opportunity Contact - part of that save process will update the Rollup Summary you have already defined and kick off the save process for the Opportunity object.  We should be able to catch that RS and action off of it.

 

If you created a new field called "Historical Stage" (feel free to rename that) this is what the trigger would look like:

 

trigger OpportunityUpdateHistoricalStage on Opportunity (before update) {

	///////////////////////////////////
	// This trigger pulls a historical stamp of the StageName
	// when the OppContacts are updated.
	///////////////////////////////////
	
	if(trigger.isUpdate && trigger.isBefore) {
		
		for(Opportunity o : trigger.new) {
			
			if(trigger.oldMap.get(o.Id).Test_roll_up__c != trigger.newMap.get(o.Id).Test_roll_up__c) {
				o.Historical_Stage__c = o.StageName;
			}
			
		}
	}

}

 

OnCloud9OnCloud9

Thanks for the quick reply! I forgot to mention that Opportunity Contacts is a custom object.  We needed some more flexibility so we chose to go that route.  Since Opportunity Contacts has master/detail to opportunity, would I need to alter the trigger to do a after insert,after update on Opportunity_Contacts__c?

 

 

Andy BoettcherAndy Boettcher

That's correct!  You can trigger off of any custom object.  The logic in my previous post can be tapped, but wouldn't be your ultimate solution.  It adds a little bit of complexity to the overall trigger, but nothing crazy.

 

I can mock some code up for you - what is the field that you're updating in the Opportunity Contacts object and the value you're looking to spark the Opportunity Stage history capture?

 

-Andy

 

 

OnCloud9OnCloud9

Ahh ok, gotcha.  


The custom field is: Opportunity_Contact__c.Role__c = "Executive Sponsor"

OnCloud9OnCloud9

So on the opportunity, we'd just want to capture when an "Executive Sponsor" opportunity contact is added, by the current stage value.

 

I was using a [last modified] datestamp to roll this up, but if you have a better solution- feel free to share.  

 

Thank you!! 

Andy BoettcherAndy Boettcher

Here ya go - I mocked up the objects in a Developer Org and tested this code out.  Granted, if your field names are different, you'll have to monkey with that.  =)

 

trigger OpportunityContactUpdateHistoricalStage on Opportunity_Contact__c (after insert, after update) {

	//////////////////////////////
	// This trigger will record the Opportunity.StageName in
	// a historical field when the OppContact role is updated
	//////////////////////////////
	
	if(trigger.isAfter && (trigger.isInsert || trigger.isUpdate)) {
		
		// Pull list of parent OpportunityIds
		Set<Id> setOpportunityIds = new Set<Id>();
		for(Opportunity_Contact__c oc : trigger.new) { setOpportunityIds.add(oc.Opportunity__c); }
		
		// Create Map of Opportunities to test against
		Map<Id, Opportunity> mapOpportunities = new Map<Id, Opportunity>([SELECT Id, StageName, Historical_Stage__c 
																			FROM Opportunity WHERE Id IN :setOpportunityIds]);
																			
		System.Debug('/n/n mapOpportunities = ' + mapOpportunities + '/n/n');

		// Create List to update and loop through new records
		List<Opportunity> lstOppsToUpdate = new List<Opportunity>();
		for(Opportunity_Contact__c oc : trigger.new) {
			
			System.Debug('/n/n Checking = ' + oc + '/n/n');
			
			// BUSINESS RULE:  If Role = 'Executive Sponsor', copy the Opp StageName to Historical Stage
			if(oc.Role__c == 'Executive Sponsor' && (trigger.oldMap.get(oc.Id).Role__c != trigger.newMap.get(oc.Id).Role__c)) {
				
				System.Debug('/n/n SUCCESS! /n/n');
				
				Opportunity oUpdate = mapOpportunities.get(oc.Opportunity__c);
				oUpdate.Historical_Stage__c = oUpdate.StageName;
				lstOppsToUpdate.add(oUpdate);
			}
			
		}
		
		// Update List of applicable Opportunities
		if(lstOppsToUpdate.size() > 0) { update lstOppsToUpdate; }
		
	}

}

 Let me know if that works out for you!

 

-Andy

OnCloud9OnCloud9

Thank you Andy!! I will try this out...your help is highly appreciated.  Hope you have an awesome welcome to 2012.

Andy BoettcherAndy Boettcher

Keep in mind that you'll need to whip up a corresponding Test Class - if you need help with that too, let me know.

Andy BoettcherAndy Boettcher

BTW - you're very welcome!  Good luck!

Andy BoettcherAndy Boettcher

OnCloud9 - did that work for you?