Take the 2-minute tour ×
Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. It's 100% free, no registration required.

Thank you for taking the time to look into my question, this is my first Apex/Salesforce project, I am familiar with Java and javascript.

I have been tasked to creating a new Object called 'Service Agreement' from the Opportunity. I just need to automate the creation of the object and fill in certain fields that I get from the Opportunity and related Quote, I also need to do some calculations and such. It seems to me that making a class is the best solution and calling the method within the class from a button in the Opportunity. So the button I assume should use Javascript.

My questions are as follows:

  1. Is this the best approach? ( I could use a db trigger but if the object is created outside of the Opportunity there would be errors)
  2. If I want to do alert('var') in javascript and also return a boolean of true or false is it possible? (I want to customize the visual errors this way for the user)

I will be using

CurrentPageId = ApexPages.CurrentPage().getParameters().get('id'); 

To get the id from the opportunity and then use SOQL to get the necessary field info.

Any opinions would be greatly appreciated, I have been reading into this, and becoming more and more confused

share|improve this question
    
First I would follow up on, "if the object is created outside the Opp" - if you hang a trigger on Opp, not sure why this would be an issue. Mostly asking because it sounds like your use case is intended to be automatic as possible. –  joshbirk Feb 11 '13 at 18:36
    
Thanks for responding josh, you are correct I am trying to make it as automatic as possible. If i were to create a trigger it would be on New 'Service Agreement' but since it can be created outside an Opportunity I would think it would be wiser to just make a class instead of a trigger and class the class from the opportunity. –  jnoel10 Feb 11 '13 at 18:40
    
also, I need the service agreement to be a singleton and in-case someone edits the opportunity i dont want a second service agreement to be created by mistake. –  jnoel10 Feb 11 '13 at 18:41
add comment

1 Answer

up vote 4 down vote accepted

Is there a specific scenario when this Service Agreement object needs to be created? For instance, this really sounds like a good candidate for a trigger. Say this object needs to be created at a certain stage of the opportunity or once certain information of that opportunity is created, a trigger would be perfect for this as you can add logic in the trigger to validate the conditions are met before actually creating anything. It also reduces a user from having to manually click a button. However I don't know exactly when this object is created and it could be arbitrary and require user input.

Take a look at the Trigger documentation. I would use something like:

trigger OpportunityTrigger on Opportunity (after update) {
    List<Id> oppIds = new List<Id>();
    for(Opportunity opp:Trigger.new){
        oppIds.add(opp.Id);
    }
    List<Opportunity> oppsFromDb = [SELECT 
                                        Id, Stage, (SELECT Id FROM Service_Agreement__r)
                                    FROM
                                        Opportunity
                                    WHERE
                                        Id IN :oppIds
    ];
    List<Service_Agreement__c> agreements = new List<Service_Agreement__c>();
    for(Opportunity opp:oppsFromDb){
        if(opp.Stage == 'Pending Service Agreement' && opp.Service_Agreement__r.size() == 0){
            agreements.add(new Service_Agreement__c(OppId__c = opp.Id);
        }
    }

    insert agreements;
}

Note: Objects in a trigger do not have their child object relationships loaded by default. That is why you need to loop over those objects and get them from the database again before performing an operation on them.


If you absolutely can not use a trigger, I would suggest using a custom button on the opportunity. This button should link to a custom Visualforce page. This Visualforce page should be blank except for an action on the apex:page element. Something like:

<apex:page controller="ServiceAgreementCreationController" action="{!doCreateAgreement}">
</apex:page>

The way this would work is you would have a ServiceAgreementCreationController class. You can't perform DML statements in your constructor, so you would set an action on the page to immediately perform that action. The constructor would look something like:

public class ServiceAgreementCreationController {
   public Id oppId {get;set;}

   public AllStarInvoiceGenerationController() {
       oppId = System.currentPageReference().getParameters().get('oppId');
   }

   public PageReference doCreateAgreement(){
       // Do all of your logic here. Load the opp, then create the Service agreement
       Opportunity opp = [SELECT Id FROM Opportunity WHERE Id = :oppId];
       Service_Agreement__c agreement = new Service_Agreement__c(OppId__c = opp.Id);
       insert agreement;

       // return the user back to the opportunity once it is done
       PageReference reference = new ApexPages.StandardController(opp).view();
       return reference;
   }
}

This would eliminate the need for Javascript or creating anything custom on the Opportunity. You should be able to continue to the use the page layouts and move all of the functionality out into a separate page. The way this works would be:

  • User clicks the "Create Service Agreement" button
  • User is redirected to new page that loads as a blank white page briefly
  • Immediately the action is called with no action taken by the user.
  • Service agreement is created
  • User is redirected to opportunity

This will all happen in a matter of a few seconds. Hopefully all of this helps. I would still suggest using a trigger first if possible.

share|improve this answer
    
Thanks Jesse, this is very helpful and I believe you are correct a trigger would be better. Since it verifies the trigger on update would I need to reference the old Opportunity to make sure old.opp.Stage != 'Pending Service Agreement' so it doesnt create another agreement? Thanks again for all your help –  jnoel10 Feb 12 '13 at 14:58
    
You shouldn't need to do that since it already checks if there is a child object already created opp.Service_Agreement__r.size == 0 –  Jesse Altman Feb 12 '13 at 15:06
    
Brilliant! I can ask this as a separate question as well, but within the trigger if i want to do error checking and have a pop-up to say they are missing information on a field is that possible without JS? –  jnoel10 Feb 12 '13 at 15:07
    
Yes that is definitely possible (although it wouldn't be with a popup, that isn't really how Salesforce works). You would use the addError method. salesforce.com/us/developer/docs/apexcode/Content/… - You need to do this in a before trigger though. Essentially it will act as custom validation then and the error message you add will be displayed at the top of the page and prevent the save. –  Jesse Altman Feb 12 '13 at 15:10
    
So, I can use the same trigger as mentioned above, except Apex Trigger Operation would be 'before update' ? –  jnoel10 Feb 12 '13 at 15:18
show 4 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.