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
mgodseymgodsey 

Trigger error: System.StringException: Invalid id. (updating custom object field from Opp picklist)

I have two objects: Opportunity and ProposalFlight__c. They are in a master-detail relationship (ProposalFlight__c being the child). I also have a picklist field on both called ApprovalStatus__c. After an update on certain types of Opportunities, I want the ApprovalStatus__c picklist on ProposalFlight__c to change to match that on Opportunity. I wrote the following trigger and it saves, but when it tries to execute if gives me this error message:

 

Validation Errors While Saving Record(s)
There were custom validation error(s) encountered while saving the affected record(s). The first validation error encountered was "Apex trigger UpdatePFtoPending caused an unexpected exception, contact your administrator: UpdatePFtoPending: execution of AfterUpdate caused by: System.StringException: Invalid id: Approved: External entry point". 

 

Can anyone please explain to me what this error message means and any tips for how I can fix it? Thank you so much!

 

trigger UpdatePFtoPending on Opportunity (after update) {

//List of approved Master Terms Opportunities
List<ID> masterOpps = new List<ID> ();
    for (Opportunity opp : trigger.new){
    if (opp.VersionType__c=='Change Request'){
        masterOpps.add(opp.ApprovedPARENTOpportunity__c);}
        }

//List of Related Not Submitted Proposal Flights
List<ProposalFlight__c> pflights = [SELECT ID, ApprovalStatus__c, Opportunity__c
                                    FROM ProposalFlight__c
                                    WHERE Opportunity__c in:masterOpps AND ApprovalStatus__c  !='Approved'];
Map<id,ProposalFlight__c> mapofPFs = New Map<id, ProposalFlight__c>();

//Build map of Proposal Flights from List of IDs in trigger
    for(ProposalFlight__c pf : pflights)
    mapofPFs.put(pf.id,pf);

//for each record in this trigger
    for(Opportunity thiscropp :trigger.new){

//update approval status on Proposal Flight                                                                         
ProposalFlight__c thisPF = mapofPFs.get(thiscropp.ApprovalStatus__c);

    If(thiscropp.VersionType__c == 'Change Request'){
    thisPF.ApprovalStatus__c = thiscropp.ApprovalStatus__c;
    }}
    
    Update mapofPFs.values();                                    
                                         
}

 

Best Answer chosen by Admin (Salesforce Developers) 
SFAdmin5SFAdmin5

ok.  this trigger will update the child proposal flight record with the corresponding value in its parent opportunity record's approval status field, when the opp is updated.  the trigger will only fire on proposal flight records not in an approved status already, and the opp has to have versiontype = change request.

 

i'm still not sure where this parent opp thing fits in but i have a feeling this trigger will only need to be slightly tweaked for that.  essentially though this is a simple trigger to update a child record when a parent is edited, so adding in logic for a parent opp should be easy.  try this trigger to see how it works and let me know how you want to change it.

 

to test: 1. create a test opp with version type = change request. save.  2. create a proposal flight record on that opp and just leave approvalstatus blank.  3.edit the opp so that approval status = approved.  4. check the proposal flight record and see that the status matches that of the opp

 

 

trigger updateProposalFlight on Opportunity (after update)
{
    List<ProposalFlight__c> proposalFlightsToUpdate = new List<ProposalFlight__c>();
        for(ProposalFlight__c pf :[select Id, ApprovalStatus__c, Opportunity__c,Opportunity__r.ApprovalStatus__c 
                                   from ProposalFlight__c where Opportunity__r.VersionType__c = 'Change Request' AND
                                   ApprovalStatus__c != 'Approved' AND
                                   Opportunity__c in : trigger.new])
        {
            pf.ApprovalStatus__c = pf.Opportunity__r.ApprovalStatus__c;
            proposalFlightsToUpdate.add(pf);
        }
             if(!proposalFlightsToUpdate.isEmpty())
             update proposalFlightsToUpdate ;
}

 

All Answers

SFAdmin5SFAdmin5

turn off validation rules on those objects and then try the test again.  i think the trigger might be in conflict with an active validation rule

mgodseymgodsey

Hi Ross - thanks for your quick response. I don't think a validation rule is the issue though, because we don't have any yet on ProposalFlight__c (which is what is being updated in the trigger) and the debug log doesn't say anything about a validation rule error:

 

6:06:13.548 (548330000)|CODE_UNIT_FINISHED|CopyOwnerInformation on Opportunity trigger event BeforeUpdate for [006S0000006iHOq]
16:06:13.594 (594677000)|CODE_UNIT_STARTED|[EXTERNAL]|01qS00000008p3Z|UpdatePFtoPending on Opportunity trigger event AfterUpdate for [006S0000006iHOq]
16:06:13.595 (595014000)|SYSTEM_CONSTRUCTOR_ENTRY|[4]|<init>()
16:06:13.595 (595053000)|SYSTEM_CONSTRUCTOR_EXIT|[4]|<init>()
16:06:13.595 (595108000)|SYSTEM_METHOD_ENTRY|[5]|LIST<Opportunity>.iterator()
16:06:13.595 (595136000)|SYSTEM_METHOD_EXIT|[5]|LIST<Opportunity>.iterator()
16:06:13.595 (595153000)|SYSTEM_METHOD_ENTRY|[5]|system.ListIterator.hasNext()
16:06:13.595 (595170000)|SYSTEM_METHOD_EXIT|[5]|system.ListIterator.hasNext()
16:06:13.596 (596083000)|SYSTEM_METHOD_ENTRY|[7]|LIST<Id>.add(Object)
16:06:13.596 (596116000)|SYSTEM_METHOD_EXIT|[7]|LIST<Id>.add(Object)
16:06:13.596 (596127000)|SYSTEM_METHOD_ENTRY|[5]|system.ListIterator.hasNext()
16:06:13.596 (596138000)|SYSTEM_METHOD_EXIT|[5]|system.ListIterator.hasNext()
16:06:13.596 (596628000)|SOQL_EXECUTE_BEGIN|[11]|Aggregations:0|select ID, ApprovalStatus__c, Opportunity__c from ProposalFlight__c where (Opportunity__c IN :tmpVar1 and ApprovalStatus__c != 'Approved')
16:06:13.613 (613830000)|SOQL_EXECUTE_END|[11]|Rows:4
16:06:13.614 (614055000)|SYSTEM_METHOD_ENTRY|[17]|LIST<ProposalFlight__c>.iterator()
16:06:13.614 (614348000)|SYSTEM_METHOD_EXIT|[17]|LIST<ProposalFlight__c>.iterator()
16:06:13.614 (614374000)|SYSTEM_METHOD_ENTRY|[17]|system.ListIterator.hasNext()
16:06:13.614 (614390000)|SYSTEM_METHOD_EXIT|[17]|system.ListIterator.hasNext()
16:06:13.614 (614486000)|SYSTEM_METHOD_ENTRY|[18]|MAP<Id,ProposalFlight__c>.put(Object, Object)
16:06:13.614 (614525000)|SYSTEM_METHOD_EXIT|[18]|MAP<Id,ProposalFlight__c>.put(Object, Object)
16:06:13.614 (614537000)|SYSTEM_METHOD_ENTRY|[17]|system.ListIterator.hasNext()
16:06:13.614 (614548000)|SYSTEM_METHOD_EXIT|[17]|system.ListIterator.hasNext()
16:06:13.614 (614587000)|SYSTEM_METHOD_ENTRY|[18]|MAP<Id,ProposalFlight__c>.put(Object, Object)
16:06:13.614 (614601000)|SYSTEM_METHOD_EXIT|[18]|MAP<Id,ProposalFlight__c>.put(Object, Object)
16:06:13.614 (614609000)|SYSTEM_METHOD_ENTRY|[17]|system.ListIterator.hasNext()
16:06:13.614 (614619000)|SYSTEM_METHOD_EXIT|[17]|system.ListIterator.hasNext()
16:06:13.614 (614654000)|SYSTEM_METHOD_ENTRY|[18]|MAP<Id,ProposalFlight__c>.put(Object, Object)
16:06:13.614 (614667000)|SYSTEM_METHOD_EXIT|[18]|MAP<Id,ProposalFlight__c>.put(Object, Object)
16:06:13.614 (614674000)|SYSTEM_METHOD_ENTRY|[17]|system.ListIterator.hasNext()
16:06:13.614 (614684000)|SYSTEM_METHOD_EXIT|[17]|system.ListIterator.hasNext()
16:06:13.614 (614718000)|SYSTEM_METHOD_ENTRY|[18]|MAP<Id,ProposalFlight__c>.put(Object, Object)
16:06:13.614 (614732000)|SYSTEM_METHOD_EXIT|[18]|MAP<Id,ProposalFlight__c>.put(Object, Object)
16:06:13.614 (614739000)|SYSTEM_METHOD_ENTRY|[17]|system.ListIterator.hasNext()
16:06:13.614 (614749000)|SYSTEM_METHOD_EXIT|[17]|system.ListIterator.hasNext()
16:06:13.614 (614774000)|SYSTEM_METHOD_ENTRY|[21]|LIST<Opportunity>.iterator()
16:06:13.614 (614801000)|SYSTEM_METHOD_EXIT|[21]|LIST<Opportunity>.iterator()
16:06:13.614 (614811000)|SYSTEM_METHOD_ENTRY|[21]|system.ListIterator.hasNext()
16:06:13.614 (614822000)|SYSTEM_METHOD_EXIT|[21]|system.ListIterator.hasNext()
16:06:13.614 (614891000)|SYSTEM_METHOD_ENTRY|[25]|MAP<Id,ProposalFlight__c>.get(Object)
16:06:13.615 (615277000)|EXCEPTION_THROWN|[EXTERNAL]|System.StringException: Invalid id: Approved
16:06:13.615 (615457000)|SYSTEM_METHOD_EXIT|[25]|MAP<Id,ProposalFlight__c>.get(Object)
16:06:13.615 (615567000)|FATAL_ERROR|System.StringException: Invalid id: Approved

External entry point
16:06:13.615 (615579000)|FATAL_ERROR|System.StringException: Invalid id: Approved

 

Any other ideas of what is happening? In what situations does the system.stringexception: invalid id error message usually come up? 

SFAdmin5SFAdmin5

what type of field is 

 

ApprovedPARENTOpportunity__c

mgodseymgodsey

It's a lookup field to Opportunity.

 

We have two different types of Opportunities - "Master Terms" and "Change Requests". The Change Request Opportunities are related to the Master Terms Opportunities through the lookup field ApprovedPARENTOpportunity__c.

SFAdmin5SFAdmin5

ok.  this trigger will update the child proposal flight record with the corresponding value in its parent opportunity record's approval status field, when the opp is updated.  the trigger will only fire on proposal flight records not in an approved status already, and the opp has to have versiontype = change request.

 

i'm still not sure where this parent opp thing fits in but i have a feeling this trigger will only need to be slightly tweaked for that.  essentially though this is a simple trigger to update a child record when a parent is edited, so adding in logic for a parent opp should be easy.  try this trigger to see how it works and let me know how you want to change it.

 

to test: 1. create a test opp with version type = change request. save.  2. create a proposal flight record on that opp and just leave approvalstatus blank.  3.edit the opp so that approval status = approved.  4. check the proposal flight record and see that the status matches that of the opp

 

 

trigger updateProposalFlight on Opportunity (after update)
{
    List<ProposalFlight__c> proposalFlightsToUpdate = new List<ProposalFlight__c>();
        for(ProposalFlight__c pf :[select Id, ApprovalStatus__c, Opportunity__c,Opportunity__r.ApprovalStatus__c 
                                   from ProposalFlight__c where Opportunity__r.VersionType__c = 'Change Request' AND
                                   ApprovalStatus__c != 'Approved' AND
                                   Opportunity__c in : trigger.new])
        {
            pf.ApprovalStatus__c = pf.Opportunity__r.ApprovalStatus__c;
            proposalFlightsToUpdate.add(pf);
        }
             if(!proposalFlightsToUpdate.isEmpty())
             update proposalFlightsToUpdate ;
}

 

This was selected as the best answer
mgodseymgodsey

Thank you so much for your help on this! I really appreciate you taking the write out this trigger. I didn't realize you could put in those relationship fields in a SOQL query - I know I'll be using this as a reference quite often!

 

I'm sorry that I can't explain the parent/child opp thing better (the parent being the "Master Terms" and the child being the "Change Request). It's tricky to explain over the internet like this! But basically, the ProposalFlight__c will always be related to the Master Terms opp. However, it needs to be updated differently in the following scenarios:

 

1) "Master Terms" Proposal Flight - needs to be updated with the "Master Terms" Opportunity's Approval Status

2) "Change Request" Proposal Flight - needs to be updated with "Change Request" Opportunity's Approval Status

 

 

Your trigger is great for scenario 1, but I wasn't sure how to fit scenario 2 into it. However, I have a trigger that I developed last night that seems to be working. I combined the two below. They work when testing in the UI, but I'm very new to APEX and I worry that they are poorly compiled and possibly breaking best practices. Any glaring issues you see that I should be aware of? Thanks again!

 

trigger SFDCupdateProposalFlight on Opportunity (after update){

//make sure trigger only fires when the Approval Status is changed
for (Opportunity opp: trigger.new) {
    Opportunity oldopp = Trigger.oldMap.get(opp.ID);      
        if(opp.ApprovalStatus__c != oldopp.ApprovalStatus__c){
        
//------------------------------------FOR MASTER TERMS OPPORTUNITIES/PROPOSAL FLIGHTS---------------------------
if(opp.VersionType__c == 'Master Terms'){
   
//get list of Master Proposal Flights to update  
    List<ProposalFlight__c> proposalFlightsToUpdate = new List<ProposalFlight__c>();
        for(ProposalFlight__c pf :[select Id, ApprovalStatus__c, Opportunity__c,Opportunity__r.ApprovalStatus__c 
                                   from ProposalFlight__c where Opportunity__r.VersionType__c = 'Master Terms' AND
                                   ApprovalStatus__c != 'Approved' AND VersionType__c = 'Master Terms'AND
                                   Opportunity__c in : trigger.new])
        {
            pf.ApprovalStatus__c = pf.Opportunity__r.ApprovalStatus__c;
            proposalFlightsToUpdate.add(pf);
        }
             if(!proposalFlightsToUpdate.isEmpty())
             update proposalFlightsToUpdate ;
}
  

//------------------------------------FOR CHANGE REQUEST OPPORTUNITIES/PROPOSAL FLIGHTS-------------------------

if(opp.VersionType__c == 'Change Request'){

//List of Change Request Opportunities
List<Opportunity> CRopps = [SELECT ID, ApprovalStatus__c, VersionType__c
                           FROM Opportunity
                           WHERE Id in:Trigger.new];
                           
//List of approved Master Terms Opportunities IDs
List<ID> masterOppsIDs = new List<ID> ();
        masterOppsIDs.add(opp.ApprovedPARENTOpportunity__c);
        
//List of Related Not Submitted Proposal Flights
List<ProposalFlight__c> pflights = [SELECT ID, ApprovalStatus__c, Opportunity__c, VersionType__c
                                    FROM ProposalFlight__c
                                    WHERE Opportunity__c in:masterOppsIDs AND VersionType__c = 'Change Request' AND ApprovalStatus__c !='Approved'];

Map<ID,Opportunity> oppMap = new Map <ID,Opportunity>();
    for (Opportunity changeopp :CRopps){
    oppMap.put(opp.Id,opp);
    
    for(integer i=0; i<pflights.size();i++){
    if(changeopp.VersionType__c == 'Change Request'){
    pflights[i].ApprovalStatus__c = changeopp.ApprovalStatus__c;}
    }
    }
    
    update pflights;
 } 
 } 
 } 
} //end trigger

 

SFAdmin5SFAdmin5

sure i'll take a look.  would you mind marking my last response as resolution to this post?  thanks a lot