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
Gabe RothmanGabe Rothman 

Service class for trigger to update Oppty from related custom object

Can anyone give me some direction on a service class I'm trying to write?  Essentially, I have a custom object called Transactions__c, which looks up to another custom object called PD_Data__c, which in turn looks up to the Account.  When a field called Amount_Due__c on a Transaction record is updated to a value greater than 0, I want to set the stage on any open oppty on the same Account to closed won. See illustration below:

User-added image

I've written some of the code, but I'm kinda stuck and I'm not sure if I'm even on the right track.

public with sharing class CloseOutOpptyService {

    public static list<Transactions__c> filterAmountDueChange(map<id, Transactions__c> oldMap, list<Transactions__c> newList) {
    	list<Transactions__c> temp=new list<Transactions__c>();
    	for (Transactions__c trxs : newList){
 			if ( 
 			      (oldMap.get(trxs.id).pd_amount_due__c == null || oldMap.get(trxs.id).pd_amount_due__c == 0) 
 			      && (trxs.pd_amount_due__c > 0)
 			      ){
 			temp.add(trxs);
 			}
    		
    	}
    	return temp;  
    }
    
	public static Set<Id> closeOpptys (list<Transactions__c> trxAccount) {        
		list<Transactions__c> trxAccountIds = [SELECT Id, Parent_PD_Data__r.SFDC_Account__r.Id FROM Transactions__c Where Id in: trxAccount];

		Set<Id> accountIds = new Set<Id>();
		for(Transactions__c trxAccountId : trxAccountIds) {
       		accountIds.add(trxAccountId.Parent_PD_Data__r.SFDC_Account__c);
		}

		return accountIds;




Any help would be greatly appreciated.  Thanks!







Best Answer chosen by Gabe Rothman
Clay AshworthClay Ashworth
Seems to me you might be better off with a trigger so that when the pd_amount_due__c field gets updated you can get the opporunities updated without having to perform any additional steps. If that's the case then you can just use the code below to acomplish this.

trigger CloseOutOpptyService on Transaction__c (after update) {
	
	//Fire the trigger only when pd_amount_due__c field is >0
	if(trigger.new[0].Id > 0 && trigger.new[0].pd_amount_due__c > 0) {
		
		//Create an empty list for the opportunities
		List<Opportunity> olsit = new List<Opportunity>();
		
		//Query for the Account Id 
		Account a = [select id from Account where Id = :trigger.new[0].PD_Data__c.AccountId limit 1];

		//Run a query for the target opportunities for updating to Closed Won Stage
		olist = [select Id, Stage, AccountId from Opportunity 
			where AccountId = a.Id 
			and StageName != ‘Closed Won’ 
			and StageName != ‘Closed Lost’];

		//Run an iterative loop over each opportunity in the “olist” and update stage
		for(Opportunity o : olist) {

			o.StageName = ‘Closed Won’;

			}

		//Update the list to change the stages on all opportunities in the olist 
		update list;

	}

}



I did not write a test class to go with it and you will need one to deploy the trigger into production.

All Answers

Gabe RothmanGabe Rothman
Thanks Clay.  I am trying to limit myself to one trigger per object, and I already have other service classes being called from a Transaction trigger.  How would you modify this to work with that context?
Clay AshworthClay Ashworth
Seems to me you might be better off with a trigger so that when the pd_amount_due__c field gets updated you can get the opporunities updated without having to perform any additional steps. If that's the case then you can just use the code below to acomplish this.

trigger CloseOutOpptyService on Transaction__c (after update) {
	
	//Fire the trigger only when pd_amount_due__c field is >0
	if(trigger.new[0].Id > 0 && trigger.new[0].pd_amount_due__c > 0) {
		
		//Create an empty list for the opportunities
		List<Opportunity> olsit = new List<Opportunity>();
		
		//Query for the Account Id 
		Account a = [select id from Account where Id = :trigger.new[0].PD_Data__c.AccountId limit 1];

		//Run a query for the target opportunities for updating to Closed Won Stage
		olist = [select Id, Stage, AccountId from Opportunity 
			where AccountId = a.Id 
			and StageName != ‘Closed Won’ 
			and StageName != ‘Closed Lost’];

		//Run an iterative loop over each opportunity in the “olist” and update stage
		for(Opportunity o : olist) {

			o.StageName = ‘Closed Won’;

			}

		//Update the list to change the stages on all opportunities in the olist 
		update list;

	}

}



I did not write a test class to go with it and you will need one to deploy the trigger into production.
This was selected as the best answer
Clay AshworthClay Ashworth
Gabe,

I'm assuming that the one trigger you have firing for each object is making calls to public classes for methods to execute upon particular events ( insert, update, before/after, etc). If that's the case you can just strip out line 1 and 30 from above and build a method around it instead then insert it into an existing class. The add a line to your trigger for that SObject and call our the method to fire after update.

You will need to update anything that specifies trigger.new[0] in the above to  a variable you map to the record for Transaction__c.

Clay
Gabe RothmanGabe Rothman
That's correct. And thanks again for your input!