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

How to obtain the Id of a SObject in a test case before INSERT
Hi there,
I have a trigger which works fine in Sandbox, but cannot be deployed to production because there doesn't seem to be a way to obtain the Id of a SObject before the actual Insert, kind of a chicken and the egg thing. Here is what I have:
Trigger:
Opportunity[] opps = Trigger.new;
for (Opportunity o:opps)
{
OpportunityContactRole[] ocrs = [Select Id from OpportunityContactRole where OpportunityId=:o.Id];
if (ocrs.size() == 0)
{
o.addError('A contact role does not exist.');
}
}
The above trigger prevents a save on an Opportunity if there's no OpportunityContactRole associated to the Opportunity. It works like a charm.
The problem is that in order to test this trigger class, I need the ability to create an OpportunityContactRole before I can save the test Opportunity (otherwise, the system will not allow the test Opportunity to be saved because there's no OpportunityContactRole). Here are the challenges:
- In order to create an OpportunityContactRole test object, I have to associate it to an Opportunity object via the OpportunityId field (or establish a relationship between this OpportunityContactRole record and the soon to be created Opportunity record), but this ID is not generated until I call insert on the test Opportunity object.
- I cannot create the Opportunity first because the insert will fail for there's no OpportunityContactRole associated to the Opportunity.
- We cannot set a custom ID for an Opportunity object (not allowed to set Ids on any Sobjects).
The only thing I can think of is if there's a way to obtain a valid ID for an opportunity object before the insert call and use that to create the OpportunityContactRole first, and then call insert on the opportunity object. But I don't think this can be done .... How would you approach this problem?
thanks in advance for the feedback.
Pi
Has_Contact__c (Yes when the OpportunityContactRole's size is > 0, and No, if not) against the Opportunity and also created a validation rule against Has_Contact__c (for when it is = No). This successfully prevents an Opportunity from being created if it does not have an OpportunityContactRole (ie. it prevents users from creating a New opportunity from anywhere in the system unless they create it from a specific Contact page).
~pi
All Answers
Actually, maybe it helps to specify our use case. Here is the problem we are trying to tackle:
- If someone creates an Opportunity directly from the Opportunity tab using the New button, SF does not add a contact role to the Opportunity. So the trigger specified above would correctly catch this condition and prevent users from saving a record.
- If someone creates an Opportunity from an actual Contact page (using the New opportunity button there), an OpportunityContactRole record is created by SF and associated to the Opportunity object, so the trigger will not prevent them from saving.
In other words, the trigger is created so that it will allow folks to save an Opportunity only if they are creating it from a specific Contact page. It prevents users from creating opportunities from the Opportunity tab page itself (which does not create the OpportunityContactRole association).
Does this make sense?
thanks,
Pi
Hi,
Can't you just create a validation rule on Opps for that?
Miguel
Maybe I am missing something obvious :( how do you get to the OpportunityContactRole object from an Opportunity validation rule? Essentially, I would like the validation to be performed against the OpportunityContactRole records associated to each opportunity.
I had a similar requirement where I had to restrict the creation of a Target to a Contract record. Instead of a trigger, I created a Visualforce page to override the New Target button. The page pre-populates with information carried over from the contract:
<apex:page standardController="Target__c" showHeader="true" sidebar="true" tabStyle="Target__c" extensions="targetNewExt"> <style> .aField { width: 200px; } .nField { width: 380px; height:80px; } .cpsHeader { line-height: 1.5em; font-weight: bold; padding-left:0.3em; } </style> <script type="text/javascript"> function populate() { var error = ''; error += document.getElementById("{!$Component.myForm.pgB.tError}").innerHTML if ( error=='' ) { document.getElementById("{!$Component.myForm.pgB.pgBsec0.tAccount}").value = '{!contract.account.name}'; document.getElementById("{!$Component.myForm.pgB.pgBsec0.tContract}").value = '{!contract.contractnumber}'; document.getElementById("{!$Component.myForm.pgB.pgBsec0.tValid}").checked = true; document.getElementById("{!$Component.myForm.pgB.pgBsec0.tIDate}").value = '{!MONTH(contract.startDate)}/{!DAY(contract.startDate)}/{!YEAR(contract.startDate)}'; document.getElementById("{!$Component.myForm.pgB.pgBsec0.tFDate}").value = '{!MONTH(contract.endDate)}/{!DAY(contract.endDate)}/{!YEAR(contract.endDate)}'; } } window.onload=populate; </script> <apex:sectionHeader title="Target Edit" subtitle="New Target" /> <apex:form id="myForm"> <apex:pageBlock title="Target Edit" mode="edit" id="pgB"> <apex:pageMessages id="tError" ></apex:pageMessages> <apex:pageBlockButtons > <apex:commandButton value="Save" action="{!save}" rendered="{!validEntry}"/> <apex:commandButton value="Cancel" action="{!cancel}"/> </apex:pageBlockButtons> <apex:pageBlockSection title="Information" columns="2" id="pgBSec0" rendered="{!validEntry}"> <apex:inputField id="tAccount" value="{!Target__c.Account__c}" required="true" /> <apex:inputField id="tValid" value="{!Target__c.Valid__c}" /> . . . </apex:page>
The controller extension:
public class targetNewExt { String cid; Target__c nTarget; Contract contract; public targetNewExt(ApexPages.StandardController stdController) { nTarget = (Target__c)stdController.getRecord(); this.cid = ApexPages.currentPage().getParameters().get('cid'); if (cid == null) { ApexPages.addmessage(new ApexPages.message(ApexPages.severity.Error,'Please click the New button from a Contract record')); } } public boolean getvalidEntry(){ Boolean x; if(cid == null) { x = false; } else { x = true; } return x; } public Contract getContract() { if (cid!=null) { contract = [SELECT Id, AccountId, ContractNumber, Account.Name, StartDate, EndDate FROM Contract WHERE id = :cid]; return contract; } else { return null; } } . . . }
Next, I created a custom list button on the Target object with the URL:
/apex/targetNew?cid={!Contract.Id}
On the Contract page layout, I removed the standard "New" button on the Target related list, and replaced it with my custom button.
Here's what happens:
It may be a little more work, but it gets the job done :smileywink:
Has_Contact__c (Yes when the OpportunityContactRole's size is > 0, and No, if not) against the Opportunity and also created a validation rule against Has_Contact__c (for when it is = No). This successfully prevents an Opportunity from being created if it does not have an OpportunityContactRole (ie. it prevents users from creating a New opportunity from anywhere in the system unless they create it from a specific Contact page).
~pi