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
Laytro80Laytro80 

Apex Triggers

Hi,

 

Very new to salesforce APEX development.  

 

I have created a custom object called file note (file_note__c).  

 

The object contains a checkbox field called new opportunity (new_opportunity__c).  

 

When I save a new or updated file note record I want a trigger to run.

 

Trigger

 

If the 'new opportunity checkbox' is ticked (set to true) I need to create a new opportunity (as in take me to create a new opportunity page).

 

Best case scenario would be to have the new opportunity created and linked to the filenote (a simple lookup on file note called (opportunity__c).  And the opportunity to be in edit mode to fill in some of the data.

 

However if that's not possible just the ability to create a new activity will be fine. 

 

 

Apologies I have no idea how to begin, any advice would be much appreciated. 

Best Answer chosen by Admin (Salesforce Developers) 
ColinKenworthy1ColinKenworthy1

trigger myFirstTrigger on file_note__c (after insert, after update) { System.Debug('## >>> Trigger executing run by ' + UserInfo.getName()); file_note__c[] myNotesToProcess = new file_note__c[]{}; for(Integer i=0 ; i<Trigger.new.size() ; i++) { if ( Trigger.new[i].new_opportunity__c == true ) { myNotesToProcess.add(Trigger.new[i]); // build list of recs to process } } if(myNotesToProcess.size()>0){

Opportunity[] myNewOpportunities = new Opportunity[]{};

for (file_note__c myNote : myNotesToProcess) {

Opportunity oppy = new Opportunity();

oppy.field1 = value1;

oppy.field2 = value2; etc, etc...

 

myNewOpportunities.add(oppy);

} insert myNewOpportunities; } System.Debug('## >>> Trigger END <<<'); }

 

 

though it sounds to me that this would be better done through visualforce with a custom apex controller extension.

All Answers

Anand@SAASAnand@SAAS

You can certainly create the opportunity using a trigger but you cannot navigate the user to another record from a trigger.

 

Here are a few options:

1. Use "visual force" and "retURL" or "saveURL" in order to take you to the opportunity record

2. Override "edit" of "File_Note__c" with a visual force page and manage the logic that you mention in the controller extension. More info here

 

 

Laytro80Laytro80

Thanks for the quick reply.

 

I can certainly recreate my filenote to look how it does currently.

 

Not sure how to write the apex code to evaluate if the new opportunity checkbox is true and if creating a new opportunity do you have an example of sample code.

 

Thanks again

 

Much appreciated.

 

ColinKenworthy1ColinKenworthy1

trigger myFirstTrigger on file_note__c (after insert, after update) { System.Debug('## >>> Trigger executing run by ' + UserInfo.getName()); file_note__c[] myNotesToProcess = new file_note__c[]{}; for(Integer i=0 ; i<Trigger.new.size() ; i++) { if ( Trigger.new[i].new_opportunity__c == true ) { myNotesToProcess.add(Trigger.new[i]); // build list of recs to process } } if(myNotesToProcess.size()>0){

Opportunity[] myNewOpportunities = new Opportunity[]{};

for (file_note__c myNote : myNotesToProcess) {

Opportunity oppy = new Opportunity();

oppy.field1 = value1;

oppy.field2 = value2; etc, etc...

 

myNewOpportunities.add(oppy);

} insert myNewOpportunities; } System.Debug('## >>> Trigger END <<<'); }

 

 

though it sounds to me that this would be better done through visualforce with a custom apex controller extension.

This was selected as the best answer
Laytro80Laytro80

Thanks Colin,

 

This method worked really well, I really appreciate you taking the time to reply, couple of quick questions.

 

First, at the moment a new opportunity requires mandatory fields to be completed before I can save. To get the trigger to work I have just added manual strings to test. If I wanted to map the opportunity fields required to fields that exist on the filenote which triggers this process how do I map.  I thought I would change oppy.field1 = value1; to oppy.name = file_note_c.subject__c;     But when I do I keep getting a error?

 

Second questions and I am not sure if it is possible but I have a look-up on the filenote to the opportunity object.  Is it possible using this trigger to populate the look-up with the newly created opportunity.

 

I am also going to investigate a visualforce solution as per your note.

 

Thanks again for all your help.

 

Cheers

 

Ross 

Laytro80Laytro80

Have figured out an answer to question 1.

 

I just need to know now if it is possible to link the newly create opportunity to the filenote.

 

Cheers

 

ColinKenworthy1ColinKenworthy1

In this for loop the the instance of the file_note__c has been named myNote (make up any naming system you like).

 

So to use the fields you should use e.g. oppy.Name = myNote.Subject__c;

 

The Id field in the opportunities is not known until after the INSERT. It would be rather easier in this case if the Opportunity had a lookup field to the file_note__c  e.g. oppy.file_note_lookup__c = myNote.Id;

 

However in this case you could add another for loop just after the insert that looped through the File Notes and Opportunities again adding the oppy Id to the File Note then doing an update.

 

for(i=0 ; i<myNotesToProcess.size() ; i++) { myNotesToProcess[i].my_Opportunity_lookup_field__c = myNewOpportunities[i].Id; } update myNotesToProcess;

I think the Notes and Opportunities arrays would be in the same order. If there is just one record then they will, however this is the 'bulk' way of writing it (as recommended by SF).

 

(Should it be update? Not sure, if this was an after insert trigger execution it might complain. Will "upsert myNotesToProcess" work instead...)

 

Message Edited by ColinKenworthy1 on 11-06-2009 09:04 PM
Laytro80Laytro80

Thanks again Colin,

 

I have amended my code see below and it looked like it worked and saved okay.

 

Problem is which I try the process I get this error message

 

Error: Invalid Data. 
Review all error messages below to correct your data.

Apex trigger myFirstTrigger caused an unexpected exception, contact your administrator: myFirstTrigger: execution of AfterUpdate caused by: System.Exception: Record is read-only: Trigger.myFirstTrigger: line 31, column 33 

 



trigger myFirstTrigger on file_note__c (after insert, after update) {
System.Debug('## >>> Trigger executing run by ' + UserInfo.getName());

file_note__c[] myNotesToProcess = new file_note__c[]{};
for(Integer i=0 ; i<Trigger.new.size() ; i++) {
if ( Trigger.new[i].new_opportunity__c == true ) {

myNotesToProcess.add(Trigger.new[i]); // build list of recs to process

}
}
if(myNotesToProcess.size()>0){

Opportunity[] myNewOpportunities = new Opportunity[]{};

for (file_note__c myNote : myNotesToProcess) {

Opportunity oppy = new Opportunity();

oppy.name = myNote.Opportunity_name__c;
oppy.closedate = myNote.close_date__c;
oppy.stagename = myNote.stage__c;
oppy.description = myNote.nature_of_opportunity__c;

myNewOpportunities.add(oppy);

}
insert myNewOpportunities;

for(Integer i=0 ; i<myNotesToProcess.size() ; i++) {
myNotesToProcess[i].Opportunity__c = myNewOpportunities[i].Id;
}
update myNotesToProcess;
}

System.Debug('## >>> Trigger END <<<'); 

} 

 

 

 

Laytro80Laytro80
Have also tried upsert same error message
ColinKenworthy1ColinKenworthy1

Hi,

 

I think you should change these to "before insert" and "before update" triggers then you won't need the "update myNotesToProcess;" line at all. Personally I think this is nicer as a before trigger (since you are also updating the file_note__c in the trigger) BUT maybe in future with workflow field updates in place you may need to make this an after trigger to pickup some of the updated fields.

 

My bad - I didn't realise you only had read access to file_note__c in an after trigger on class file_note__c. Yes these have to be before triggers since you are updating file_note__c.

 

Please look at Triggers in the index of Apex especially "understanding" and "execution order".  :smileyhappy:

Laytro80Laytro80

Hi Colin, 

 

Thanks again for all your help will read through the help files mentioned.  Requirements changed slightly which I thought would make this a lot easier.

 

Have added two fields to the opportunity record one checkbox which indicates if the source was a filenote and the other a link to the filenote.

 

Amended code is below, only problem I have is the opportunity filenote lookup is not being populated?

 

trigger myFirstTrigger on file_note__c (before insert, before update) {
System.Debug('## >>> Trigger executing run by ' + UserInfo.getName());

    file_note__c[] myNotesToProcess = new file_note__c[]{};
    for(Integer i=0 ; i<Trigger.new.size() ; i++) {
        if (  Trigger.new[i].new_opportunity__c == true ) {
            
            myNotesToProcess.add(Trigger.new[i]);  // build list of recs to process
    
        }
    }
    if(myNotesToProcess.size()>0){

        Opportunity[] myNewOpportunities = new Opportunity[]{};

        for (file_note__c myNote : myNotesToProcess) {

            Opportunity oppy = new Opportunity();

            oppy.name = myNote.Opportunity_name__c;
            oppy.closedate = myNote.close_date__c;
            oppy.stagename = myNote.stage__c;
            oppy.description = myNote.nature_of_opportunity__c;   
            oppy.Source_Filenote__c = TRUE;
            oppy.File_Note__c = myNote.Id;
            

            myNewOpportunities.add(oppy);   
            
            }      
            insert myNewOpportunities;
        }
    
System.Debug('## >>> Trigger END <<<'); 

 

ColinKenworthy1ColinKenworthy1

In the case where this runs as a 'before insert' trigger the file_note__c objects have not been assigned an Id yet. That only happens when they are inserted in to the database. And this is a before insert trigger.

If it is running as a 'before update' then it should work OK.

 

Since the reason for making this a 'before' trigger (i.e. the storing of the opportunity Id on the file_note__c) has now been removed (I don't see it in your code any longer) you can just set this back to an "after insert, after update" trigger and all should be well.

Laytro80Laytro80

Thanks for all your help Colin, works like a charm. :)

 

 

ColinKenworthy1ColinKenworthy1

Please read this post - it explains things quite simply about before and after triggers.

http://community.salesforce.com/sforce/board/message?board.id=apex&message.id=22429#M22429