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
SJ1234SJ1234 

Simple Trigger Help

Looking to create a simple trigger that will sync a check box on Opportunity Object with a similar check box on each line of Opportunity Product Object.  Then, if any of those becomes unchecked, the main Opp Object check box is unchecked.   

 

Anyone have a simple code they can share?

Sean TanSean Tan

Unfortunately there are a few little tricky parts about this. I've written something that should do the trick. You'll need to make a new class as well.

 

Trigger on opportunity:

trigger SyncCheckBoxOnOpportunity on Opportunity(after update) 
{
	OpportunitySyncUtil.syncLineItems(Trigger.new, Trigger.oldMap);
}

 Trigger on OpportunityLineItem (aka Opportunity Product):

trigger SyncCheckBoxOnOpportunityLineItem on OpportunityLineItem(after update)
{
	OpportunitySyncUtil.syncOpportunities(Trigger.new, Trigger.oldMap);
}

 Class:

public with sharing class OpportunitySyncUtil
{
	private static Boolean isSyncing = false;
	
	public static void syncLineItems(Opportunity[] newItems, Map<Id, Opportunity> oldItems)
	{
		//Prevent recursion
		if (!isSyncing)
		{
			isSyncing = true;
			
			Map<Id, Opportunity> opportunityMap = new Map<Id, Opportunity>{};
		
			for (Opportunity item : newItems)
			{
				if (item.Checkbox__c != oldItems.get(item.Id).Checkbox__c)
				{
					opportunityMap.put(item.Id, item);
				}
			}
			
			if (!opportunityMap.isEmpty())
			{
				OpportunityLineItem[] lineItemList = [ SELECT Id FROM OpportunityLineItem WHERE OpportunityId IN :opportunityMap.keySet() ];
				
				for (OpportunityLineItem item : lineItemList)
				{
					Opportunity o = opportunityMap.get(item.OpportunityId);
					item.Checkbox__c = o.Checkbox__c;
				}
				
				update lineItemList;
			}
		}		
	}
	
	public static void syncOpportunities(OpportunityLineItem[] newItems, Map<Id, OpportunityLineItem> oldItems)
	{
		//prevent recursion
		if (!isSyncing)
		{
			isSyncing = true;
			
			Map<Id, Opportunity> opportunityMap = new Map<Id, Opportunity>{};
		
			for (OpportunityLineItem item : newItems)
			{
				//It's changing from true to false
				if (item.Checkbox__c == false && oldItems.get(item.Id).Checkbox__c == true)
				{
					opportunityMap.put(item.OpportunityId, new Opportunity(Id=item.OpportunityId, Checkbox__c=false));
				}				
			}
			
			if (!opportunityMap.isEmpty())
			{
				update opportunityMap.values();
			}			
		}
	}
}

 This was written on the fly, so it may not compile immediately, change what you need. You'll also want to change the API Name of the checkbox to be whatever it needs to be.

vagishvagish

This can be done by two custom fields and a pretty simple trigger on Opportunity:

- Create two rollup summary fields of type count on Opportunity object as below:

1. Total line items (Total_Line_Items__c) - Rollup summary field - Select rollup type: count

                                                                            - Filter criteria should be: "All records should be included in the calculation"

Save this field. This field will contain total count of its line items.

 

2. Total Checked Line Items (Total_Checked_Line_Items__c) - Rollup summary field - Select rollup type: count

                           - Filter criteria should be: "Only records meeting certain criteria should be included in the calculation"

Now, I am assuming your check box field's api name is "Is_Checked__c" and obviously this field is present on Opportunity line item:

So, now select - "IsChecked equals true" on the filter criteria and save this field.

This field will have the count of all the line items, which have IsChecked = true.

 

You want to mark check box to be checked or unchecked on opportunity level, so below is the code:

 

Trigger MarkOpportunityChecked on Opportunity(before insert, before update) {
for(Opportunity opp : Trigger.new) {
if(opp.Total_Line_Items__c == opp.Total_Checked_Line_Items__c) {
opp.IsChecked__c = true;
}
}
}

 

Note: In this case, everytime when Opportunity record get updated, it will have correct checkbox value. If you want to reflact check box value real time (on insert/update of opportunity line item) then write 1 more trigger on Opportunity line item as below:

Trigger OpportunityUpdate on opportunitylineitem(before insert, before update) {

List<Opportunity> opps = new List<Opportunity>();

for(opportunitylineitem oppLI : Trigger.new) {

opps.add(new opportunity(id = oppLI.OpportunityId));

}

if(opps != null && opps.size() > 0) {

update opps;

}

}

 

Another note: You can avoide these two triggers also, if you replace your opportunity level check box with simple text field(containing true/false as a text value). Just have a formula field. And the formula will be simply:

if(Total_Line_Items__c == Total_Checked_Line_Items__c, 'true', 'false')

 

Thanks,

Vagish

 

 

SJ1234SJ1234

Vagish -- Thanks for the info. I like the idea of avoiding the trigger altogether.  I'm almost there, but for some reason, I cannot get the opportunity rollup field to see the field in the Opportunity Product line level.  It isn't an option as a field to select to roll up.  I've tried changing the type of field it is, but no matter what, it won't see it.  What would be the reason that a rollup field wouldn't see a field to count up?

 

Thanks!

vagishvagish

Can you be more specific where you are facing the problem? because creating
count based rollup field should not cause any problem.
Let me know few steps you are following to create these fields.

--
-Vagish

SJ1234SJ1234

At the opportunity product level, I have a formula text field (approved_c) that is Yes/No based on some basic rules.  It works great.

 

Then, at the opportunity level, I have done 2 fields. The one that counts total lines on the opportunity product works great.  Then, I'm trying to create a second one "Count_Yes_c" that is a rollup of the "approved_c" yes fields.  But, when I try to create the rollup field that is subject to only when it meets the "yes' criteria, it does not give me the "approved_c" field as an option for the filter criteria.  All the other opportunity product fields are there as options (some of which are formulas), but it won't let me use the "approved_c" formula field that I created.  I also tried creating "approved_c" as a number formula field with either 0 or 1 for No or Yes, but same problem.

 

Any thoughts as to why it won't let me filter for the rollup based on the "approved_c" field?

 

vagishvagish

There are certain limitation on type of complexity of formula fields, for more details you can refer below idea:

https://success.salesforce.com/questionDetail?qid=a1X30000000ICq0EAG

 

 

So your formula field may be falling in this category that's why it is not available for rollup field. 

You can use below work around for this condition:

1. Create another normal text field say 'Mimic_Approved__c' on Opportunity Product.

2. Create a workflow on Opportunity product and just have a field update in it, this field update will copy the value of your formula field 'approved__c' into 'Mimic_Approved__c' field.

3. Use Mimic_Approved__c field for your rollup field criteria.

 

Let me know if you face any issue with this approach.

SJ1234SJ1234

Thanks for the tip.  Now I’m having issues with the workflow.  I can’t get it to update unless I go in and manually edit the product line.  If I do, then it does update the field.  But otherwise, it doesn’t know to go in and update.  So frustrating.

 

Ideas?