You need to sign in to do that
Don't have an account?

Trigger on Custom Object to update field on Opportuntiy
Hi - I am new to Apex programming and triggers and have a simple question. We are tracking proposals which are a child to an opportunity. We may have multiple revisions of a proposal - the most recent is the one we should be using. We have approval process set up on the proposal.
I have a custom field - "Proposal Status" on the Proposal (New, Pending, Approved, or Rejected - updated through Approval Process field updates). I would like to copy the value from this field from the latest proposal to a correlating field on the Opportunity when the Proposal Status changes. Note: we can have multiple revisions of the same proposal and I want to use the latest one.
I've tried this with roll-up summaries and workflow rules but it doesn't work. Called SFDC support and told that I need a trigger to do this. Can you please help me? I already spent hours on this and I'm about to give up. Nothing seems to work. Please help! Thank you! :)
try this.
All Answers
Update:
I was able to put together the following trigger, but need help to modify. I need it to check if the value changes in the "Proposal_Status__c" field on the Proposal and if it does, to copy it the "Latest_Proposal_Approval_Status__c" field in the related Opportunity.
My trigger works when the value changes to "Approved" and it should work for any proposal status change (pending, rejected, etc.)
Thank you in advance for your help with this!
trigger UpdateProposalStatusOnOpty on Proposal__c (after update, after insert) {
Set<ID> oppIds = new Set<ID>();
for(Proposal__c PB : Trigger.new)
if(PB.Proposal_Status__c=='Approved')
{
oppIds.add(PB.Opportunity_Name__c);
}
List<Opportunity> UpdateOpp = [SELECT ID, Latest_Proposal_Approval_Status__c FROM Opportunity WHERE Opportunity.id IN : oppIds];
for(Opportunity ol: UpdateOpp)
{ol.Latest_Proposal_Approval_Status__c='Approved';}
update UpdateOpp;
}
try this.
Hello there, Just consider opportunities as time cards in the below code, Hope it helps
Thanks
Prady
This worked perfect! Thank you so much for your help. Couldn't have done it without you!!!
I have a follow-up question - is there an way to easily modify this trigger to address a possible situation where the proposal record is deleted and the Opportunity displays the Proposal Status from the Proposal that doesn't exist anymore?
Is there any specific status when the proposal is to be deleted on?
"New" & "Recalled" only.
I have the following statuses defined: New, Pending, Approved, Rejected, Recalled
In theory the regular user should not and will not be able to delete a proposal once he/she submits it for approval and it goes to Pending status, and then to Approved or Rejected. But in situations where the Proposal was not yet submitted for approval or was recalled it could pottentialy be deleted. Does this make sense?
So you want to set the opportunity status to proposal status when ever a proposal with status "New / Recalled" is deleted. right?
Ideally I would like to check to see how many proposals exist on the Opportunity.
If one and it gets deleted then I would like to update the Proposal Status to blank to indicate that no proposals exist.
If more then one, and the last one (new/recalled) is deleted, then i would like to display a Proposal status from the most recent proposal. Hope it makes sense - let me know if you need more clarification.
Now What happens If there is an opportunity test_Opp, and it has a Proposals and the staus is new, so opp status is new.
now if they change the proposal status to Pending, then the opportunity status changes to pending, now if they create another proposal with status new, opp status changes to new.
Is this a valid scenario?
Can opportunity have multiple Proposal and based on what proposal we set the status of the opportunity?
I worked on a similar scenario, where an opportunity can have more than one child and based on both the child records, we set the status of the opportunity..
eg: Opp has child1 and child2... if child1 is approved, and child2 is new.... status on opp is partially approved.... if child2 is approved...then opp status is fully approved...
Yes, that is a valid scenario and I guess it could get pretty complicated.... but we would base the Opportunity Proposal status on the proposal with the most current update/proposal status change. So if we had 2 proposals - one pending and one new, then the opty proposal status should be set to the satus of the last modified proposal. If in the meanitime the pending proposal would get approved then the opportunity would show as approved. Then if the new one would get submitted and changed to pending, it would change to pending again.
so what if the pending proposal is recalled, then opp status is recalled... and if the recalled proposal is deleted, then you need to change the opp status to the one we have ( approved).... right...??
but what if the recalled proposal is not deleted?? still the opp status should be recalled??
Yes, and yes :) and I thought this was going to be a simple trigger :) can we fix it or is it going to be a nightmare to address all the different possible situations?
give a try to this trigger.
You are absolutely BRILIANT!!!! This works like a charm!
I got some errors but was able to fix it (especially about the Opportunity__c name - changed it to Opportunity_Name__c) and it works!
Thank you so much for your help!!! I owe you big time!
Here is the latest Trigger:
Trigger UpdateProposalStatusOnOpty on Proposal__c(After Insert, After Update, Before Delete)
{
if(Trigger.isInsert || Trigger.isUpdate)
{
List<Id> OppIds = new List<Id>();
List<Proposal__c> pbList = new List<Proposal__c>();
List<Opportunity> OppList = new List<Opportunity>();
if(trigger.oldMap <> null)
{
for(Proposal__c PB : Trigger.new)
{
if(PB.Proposal_Status__c <> trigger.oldMap.get(PB.Id).Proposal_Status__c)
{
OppIds.add(PB.Opportunity_Name__c);
pbList.add(pb);
}
}
}
else
{
for(Proposal__c PB : Trigger.new)
{
OppIds.add(PB.Opportunity_Name__c);
pbList.add(pb);
}
}
Map<Id, Opportunity> oppMap = new Map<Id, Opportunity>([SELECT Id, Latest_Proposal_Approval_Status__c FROM Opportunity WHERE Id IN :OppIds]);
for(Proposal__c pb: pbList)
{
Opportunity Opp = oppMap.get(pb.Opportunity_Name__c);
Opp.Latest_Proposal_Approval_Status__c = pb.Proposal_Status__c;
OppList.add(Opp);
}
update OppList;
}
if(trigger.isDelete)
{
List<Id> OppIds = new List<Id>();
List<Proposal__c> pbList = new List<Proposal__c>();
List<Opportunity> OppList = new List<Opportunity>();
for(Proposal__c ps : Trigger.old)
{
OppIds.add(ps.Opportunity_Name__c);
}
Map<Id, List<Proposal__c>> OppProMap = new Map<Id, List<Proposal__c>>();
Map<Id, Opportunity> oppMap = new Map<Id, Opportunity>([SELECT Id, Latest_Proposal_Approval_Status__c FROM Opportunity WHERE Id IN :OppIds]);
for(Proposal__c ps : [SELECT Id, Name, Proposal_Status__c, Opportunity_Name__c, LastModifiedDate FROM Proposal__c WHERE Opportunity_Name__c IN :OppIds AND Id NOT IN :Trigger.OldMap.keySet()])
{
if(OppProMap.get(ps.Opportunity_Name__c) <> null)
{
List<Proposal__c> ProList = OppProMap.get(ps.Opportunity_Name__c);
ProList.add(ps);
OppProMap.put(ps.Opportunity_Name__c, ProList);
}
else
{
List<Proposal__c> ProList = new List<Proposal__c>();
ProList.add(ps);
OppProMap.put(ps.Opportunity_Name__c, ProList);
}
}
for(Opportunity opp : OppMap.values())
{
if(OppProMap.get(Opp.Id) <> null)
{
List<Proposal__c> proList = OppProMap.get(Opp.Id);
if(proList.size() == 1)
{
// If the opportunity has only one proposal, then set the proposal status to opportunity
Opp.Latest_Proposal_Approval_Status__c = proList[0].Proposal_Status__c;
}
else
{
//If opportunity has more than one proposal, then if there is
DateTime dte = null;
Proposal__c latestPro = new Proposal__c();
for(Proposal__c pro : proList)
{
//System.debug('--------------------------'+acc.LastModifiedDate);
DateTime dt = pro.LastModifiedDate;
if(dte == null)
{
dte = dt;
latestPro = pro;
}
else if(dte < dt)
{
dte = dt;
latestPro = pro;
}
}
Opp.Latest_Proposal_Approval_Status__c = latestPro.Proposal_Status__c;
}
}
else
{
// If there are no more proposals on the Opportunity, set the status on opp to what ever you should be...
Opp.Latest_Proposal_Approval_Status__c = 'New';
}
OppList.add(Opp);
}
update OppList;
}
}
One more question - I tested it in the sandbox and it works. Will it also work in Production or do I need a test class for this? Hope not - never wrote one in my life :)
If your org has above 75% coverage then you dont need a test class ( not a good way)... but every class should have a test class to make sure the class is working perfectly with out issues...
I appologize for my ignorance, what is coverage? as you can tell I'm brand new to triggers and development in apex, so I appologize for silly questions.
http://wiki.developerforce.com/page/An_Introduction_to_Apex_Code_Test_Methods
i guess this link will guide you through the process of creating a test class.
Let me know if you need any help.
Thank you Naidu for the link. This looks very complicated - don't know if I'll be able to write the test class :( does that mean that I won't be able to deploy the trigger in the Production without the test class?
try this simple test class... let me know if you are able to run this test class.
I updated the test class with the required field info (see belwo) and I keep getting the following error:
Error Message System.AssertException: Assertion Failed: Expected: new, Actual: null Stack Trace Class.OpportunityUpdateTriggerTest.OpportunityUpdateTriggerTest: line 20, column 1
Not sure how to fix it.
try this...
It worked but it only gave me 28% (15/53) coverage... don't think that's sufficient, is it?
try this.
To deploy a trigger, we need atleast 1% coverage on the trigger, so you can deploy it now... but having the coverage more than 75% is safe...
You are ubelievable! Thank you so much, this ran perfect and gave me 71% coverage.
Since you're so kind and helpfull, I thought I would ask you to help me write a class test for the following trigger. It checks for the attachments in the Notes & Attachemnt section of the Proposal__c custom object and updates a checkbox Attachment _Added__c to indicate whereter attachement was added or not.
Did you write this trigger? you need to bulkify this code.. it works only when you insert or delete one attachment... but fails in case you insert or delete more than one attachment....
Did you try inserting or deleting multiple attachments at a time?
Of course not - I would not be capable of writing this :) Had another food soul helping me - here's the link to the post where I posted a question about this: http://boards.developerforce.com/t5/Apex-Code-Development/Trigger-on-Attachments/td-p/592297
Someone had mentioned this to me already, but it worked when I manually added the attachments one at a time.
This whole programmig thing is cool, but only when you know what you're doing... and I'm green as you can be. Need to take some classes to get myself upto speed.
try this... this code is bulkified... try inserting and deleting multiple attachments... let me know how it goes...
try this test class
For the trigger I'm getting this error - it's pointing to the Count() in the Select statement.
Error: Compile Error: unexpected token: ')' at line 22 column 91
For the test class, I'm getting the following error:
Error: Compile Error: Invalid initial expression type for field Attachment.Body, expecting: Blob at line 20 column 82
I was able to fix the class - used this instead:
body = Blob.valueOf('Some Text')
Here's the final test class:
The trigger is causing some errors:
System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, CountAttachments: execution of AfterInsert
caused by: System.NullPointerException: Attempt to de-reference a null object
Trigger.CountAttachments: line 23, column 1: []
my mistake.. this will work...
I said that many times already, but you are simply BRILIANT!
THANK YOU so much for all your help!!! I'm really thankfull for good people like you that will take the time to help others in need. Couldn't have done it without you!
Sincerely,
Aneta