+ Start a Discussion
BrittanyBrittany 

Trigger Approval Process for an Opportunity

Hi all,

 

I am new to writing triggers and I am having a little trouble writing the test class code for the trigger. The trigger is suppose to fire when several Oppportunity fields met a certain criteria. Below is the criteria:

  • Product Line = Non-Standard
  • Products = YES
  • Stage = Propose
  • Opportunity Record Type is not "Active Client : Renewal", "Active Client : Services Only", or "New Client : Services Only"

Now I was not sure how to modifiy the trigger code to look at the Opportunity Record Type field (kept getting an error message saying something about SObject), so instead I created a formula field that puts the Opportunity Record Type field into text (called it Oppty Record Type). The trigger works great when I manually test it out but when I wrote the test class code I get an error message saying

 Error: Compile Error: Field is not writeable: Opportunity.Oppty_Record_Type__c at line 12 column 9

 

So iam assuming that I am getting this error message because it is a formula field, maybe? Is it possible for someone to tell me how to use the Opportunity Record Type as a criteria field in the trigger code or how to modify the test class code?

 

Below is both the trigger and the test class

 

Trigger

trigger OpportunitySubmitForApproval on Opportunity (after update) {
 
    list<Opportunity>updateOpps = new list<Opportunity>();
    
    for (Opportunity opp : trigger.new) {
 
        if (opp.StageName == 'Propose' && opp.Products__c == 'YES' && opp.Product_Line__c == 'Non-Standard' &&
        (opp.Oppty_Record_Type__c != 'Active_Client_Renewal' && opp.Oppty_Record_Type__c != 'Active_Client_Services_Only' && opp.Oppty_Record_Type__c != 'New_Client_Services_Only')) {

            // create the new approval request to submit
            Approval.ProcessSubmitRequest req = new Approval.ProcessSubmitRequest();
            req.setComments('Submitted for approval. Please approve.');
            req.setObjectId(opp.id);
            // submit the approval request for processing
            Approval.ProcessResult result = Approval.process(req);
            // display if the request was successful
            System.debug('Submitted for approval successfully: '+result.isSuccess());
 
        }
     }
}

 Test Class

@isTest
private class TestOpportunitySubmitForApproval {
 
    static testMethod void testApprovalSuccess() {
 
        Opportunity opp = new Opportunity();
        opp.Name = 'Non-Standard Approval test';
        opp.StageName = 'Demonstrate';
        opp.Product_Line__c = 'Non-Standard';
        opp.CloseDate = Date.today();
        opp.LeadSource = 'Other';
        opp.Oppty_Record_Type__c = 'New_Client_New_System';
        // insert the new opp
        insert opp;
        // change the probability of the opp so the trigger submits it for approval
    opp.StageName = 'Propose';
    // update the opp which should submit it for approval
    update opp;
 
        // ensure that the opp was submitted for approval
        List<ProcessInstance> processInstances = [select Id, Status from ProcessInstance where TargetObjectId = :opp.id];
    System.assertEquals(processInstances.size(),1);
 
    }
 
}

 

Thank you!

  
Deepu 8.ax1468Deepu 8.ax1468

record type is an object . you need to create a new record type and then reference the id of the record type to the record type id of your opportunity in the test class.

 

Thanks,

Sandeep peddireddy

HariDineshHariDinesh

Hi,

 

Yes as mentioned above Record type is like object.

 

Include below statements in your test method.

 

RecordType[] RecID = [Select id from RecordType where name = 'New_Client_New_System'];

 

opp.RecordTypeId = RecID[0].Id;

 

Now your code looks like

@isTest
private class TestOpportunitySubmitForApproval {
 
    static testMethod void testApprovalSuccess() 
	{
        
RecordType[] RecID = [Select id from RecordType where name = 'New_Client_New_System']; Opportunity opp = new Opportunity(); opp.Name = 'Non-Standard Approval test'; opp.StageName = 'Demonstrate'; opp.Product_Line__c = 'Non-Standard'; opp.CloseDate = Date.today(); opp.LeadSource = 'Other';
opp.RecordTypeId = RecID[0].Id;
// insert the new opp insert opp; // change the probability of the opp so the trigger submits it for approval opp.StageName = 'Propose'; // update the opp which should submit it for approval update opp; // ensure that the opp was submitted for approval List<ProcessInstance> processInstances = [select Id, Status from ProcessInstance where TargetObjectId = :opp.id]; System.assertEquals(processInstances.size(),1); } }

 

Here 

 

RecordType[] RecID = [Select id from RecordType where name = 'New_Client_New_System'];

 

In above statement change the name "New_Client_New_System" with your correct Record type name.

 

Yes your assumption is right, as it is formula field you can't write value into it.

 

Let me know if you still face any problem.

BrittanyBrittany

Thank you for that!

 

However, I am getting other error message now

 

Error MessageSystem.AssertException: Assertion Failed: Expected: 0, Actual: 1

Stack TraceClass.TestOpportunity11xSubmitForApproval.testApprovalSuccess: line 23, column 1

 

Not sure what that means.

BrittanyBrittany

Sorry my bad forgot to add that second line but i am still receiving an error message

 

Error MessageSystem.ListException: List index out of bounds: 0

Stack TraceClass.TestOpportunity11xSubmitForApproval.testApprovalSuccess: line 14, column 1

HariDineshHariDinesh

Hi,

 

Here you are not using any List here in 14 line.

 

Why you are getting this. Might be from some other class  (by seeing the Error message).

 

Try to check condition like list.size()>0 before using the list in your classes.

 

if you still have problem post complete code and confirm what is 14 line.

 

BrittanyBrittany

Unfortunately, I am still getting the error message. (the name of the Approval Process is NonStandard)

 

Here is the whole error message

 

Apex Test Result Detail 
Time Started9/7/2012 9:30 AM
ClassTestOpportunity11xSubmitForApproval
Method NametestApprovalSuccess
Pass/FailFail
Error MessageSystem.ListException: List index out of bounds: 0
Stack TraceClass.TestOpportunity11xSubmitForApproval.testApprovalSuccess: line 14, column 1

 

Here is the trigger code

 

trigger Opportunity11xSubmitForApproval on Opportunity (after update) {
 
    list<Opportunity>updateOpps = new list<Opportunity>();
    
    for (Opportunity opp : trigger.new) {
 
        if (opp.StageName == 'Propose' && opp.Products__c == 'YES' && opp.Product_Line__c == '11x Non-Standard' &&
        (opp.Oppty_Record_Type__c != 'Active_Client_Renewal' && opp.Oppty_Record_Type__c != 'Active_Client_Services_Only' && opp.Oppty_Record_Type__c != 'New_Client_Services_Only')) {

            // create the new approval request to submit
            Approval.ProcessSubmitRequest req = new Approval.ProcessSubmitRequest();
            req.setComments('Submitted for approval. Please approve.');
            req.setObjectId(opp.id);
            // submit the approval request for processing
            Approval.ProcessResult result = Approval.process(req);
            // display if the request was successful
            System.debug('Submitted for approval successfully: '+result.isSuccess());
 
        }
     }
}

 

Here is the test class code

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@isTest
private class TestOpportunity11xSubmitForApproval {
 
    static testMethod void testApprovalSuccess() {
 
        RecordType[] RecID = [Select id from RecordType where name = 'New_Client_New_System'];
        
        Opportunity opp = new Opportunity();
        opp.Name = 'Non-Standard Approval test';
        opp.StageName = 'Demonstrate';
        opp.Product_Line__c = '11x Non-Standard';
        opp.CloseDate = Date.today();
        opp.LeadSource = 'Other';
        opp.RecordTypeId = RecID[0].Id;
        // insert the new opp
        insert opp;
        // change the probability of the opp so the trigger submits it for approval
    opp.StageName = 'Propose';
    // update the opp which should submit it for approval
    update opp;
 
        // ensure that the opp was submitted for approval
        List<ProcessInstance> processInstances = [select Id, Status from ProcessInstance where TargetObjectId = :opp.id];
    System.assertEquals(processInstances.size(),1);
 
    }
 
}

 

 

If I manually create an opportunity with the criteria listed in the test code and then move it to propose it works so I am a little confused on why the test class is failing.


Thank you very much for all your help!!!!

 

BrittanyBrittany

Sorry I didnt realize the trigger code was getting cut off

 

here it is:

 

trigger Opportunity11xSubmitForApproval on Opportunity (after update) {
 
    list<Opportunity>updateOpps = new list<Opportunity>();
    
    for (Opportunity opp : trigger.new) {
 
        if (opp.StageName == 'Propose' && opp.Products__c == 'YES' && opp.Product_Line__c == '11x Non-Standard' &&
        (opp.Oppty_Record_Type__c != 'Active_Client_Renewal' && opp.Oppty_Record_Type__c != 'Active_Client_Services_Only' && opp.Oppty_Record_Type__c != 'New_Client_Services_Only')) {

            // create the new approval request to submit
            Approval.ProcessSubmitRequest req = new Approval.ProcessSubmitRequest();
            req.setComments('Submitted for approval. Please approve.');
            req.setObjectId(opp.id);
            // submit the approval request for processing
            Approval.ProcessResult result = Approval.process(req);
            // display if the request was successful
            System.debug('Submitted for approval successfully: '+result.isSuccess());
 
        }
     }
}

HariDineshHariDinesh

Hi,

 

Here you did simple mistake,

You didn’t read clearly what I wrote in my post.

 

 

Do small change in this line

 

  RecordType [] RecID = [Select id from RecordType where name = 'New_Client_New_System'];

 

Replace New_Client_New_System with the your record type name. I just gave it as sample.

 

The problem y ur getting error is there is not record type with the name New_Client_New_System.

And you are assuming that list has some rows and trying to get id from list.

 

BrittanyBrittany

Ok. Now I am getting the same error message but at line 24.

 

here is the error message

Time Started9/7/2012 12:54 PM
ClassTestOpportunity11xSubmitForApproval
Method NametestApprovalSuccess
Pass/FailFail
Error MessageSystem.AssertException: Assertion Failed: Expected: 0, Actual: 1
Stack TraceClass.TestOpportunity11xSubmitForApproval.testApprovalSuccess: line 24, column 1

 

here is the code

 

trigger Opportunity11xSubmitForApproval on Opportunity (after update) {
 
    list<Opportunity>updateOpps = new list<Opportunity>();
    
    for (Opportunity opp : trigger.new) {
 
        if (opp.StageName == 'Propose' && opp.Products__c == 'YES' && opp.Product_Line__c == '11x Non-Standard' &&
        (opp.Oppty_Record_Type__c != 'Active_Client_Renewal' && opp.Oppty_Record_Type__c != 'Active_Client_Services_Only' && opp.Oppty_Record_Type__c != 'New_Client_Services_Only')) {

            // create the new approval request to submit
            Approval.ProcessSubmitRequest req = new Approval.ProcessSubmitRequest();
            req.setComments('Submitted for approval. Please approve.');
            req.setObjectId(opp.id);
            // submit the approval request for processing
            Approval.ProcessResult result = Approval.process(req);
            // display if the request was successful
            System.debug('Submitted for approval successfully: '+result.isSuccess());
 
        }
     }
}

 

here is the test class code

 

@isTest
private class TestOpportunity11xSubmitForApproval {
 
    static testMethod void testApprovalSuccess() {
 
        RecordType[] RecID = [Select id from RecordType where name = 'New Client : New System'];
        
        Opportunity opp = new Opportunity();
        opp.Name = 'Non-Standard Approval test';
        opp.StageName = 'Demonstrate';
        opp.Product_Line__c = '11x Non-Standard';
        opp.CloseDate = Date.today();
        opp.LeadSource = 'Other';
        opp.RecordTypeId = RecID[0].Id;
        // insert the new opp
        insert opp;
        // change the probability of the opp so the trigger submits it for approval
    opp.StageName = 'Propose';
    // update the opp which should submit it for approval
    update opp;
 
        // ensure that the opp was submitted for approval
        List<ProcessInstance> processInstances = [select Id, Status from ProcessInstance where TargetObjectId = :opp.id];
    System.assertEquals(processInstances.size(),1);
 
    }
 
}

 

 

 

 



 

 

 

HariDineshHariDinesh

Ok,

 

This happens because your trigger didn't submit any record for approval process.

means your IF condition is not satisfies with the test data you have given.

 

if (opp.StageName == 'Propose' && opp.Products__c == 'YES' && opp.Product_Line__c == '11x Non-Standard' &&
        (opp.Oppty_Record_Type__c != 'Active_Client_Renewal' && opp.Oppty_Record_Type__c != 'Active_Client_Services_Only' && opp.Oppty_Record_Type__c != 'New_Client_Services_Only')) {

 

Please try to understand how test method will execute.

 

Your if condition will only be satisfies when

1) opp.StageName == 'Propose'--------- > but you gave   opp.StageName = 'Demonstrate';

Then how it will satisfies the IF condition.

 

I hope you understood, try to give data like it satisfies if condition and then run the test.

for now comment the system.assert statement to make 0 test failures, so that you can understood which part is covered and which is not.

 

 

 

HariDineshHariDinesh

OK,

 

Modify your test class like below and try.

 

Let me know any test failures, if not let me know the coverage and which lines are not covered.

the after you can uncomment the system. Assert statement.

 

@isTest
private class TestOpportunity11xSubmitForApproval {
 
    static testMethod void testApprovalSuccess() {
 
        RecordType[] RecID = [Select id from RecordType where name = 'New Client : New System'];
        
        Opportunity opp = new Opportunity();
        opp.Name = 'Propose';
        opp.Products__c == 'YES'
        opp.StageName = 'Demonstrate';
        opp.Product_Line__c = '11x Non-Standard';
        opp.CloseDate = Date.today();
        opp.LeadSource = 'Other';
        opp.RecordTypeId = RecID[0].Id;
        // insert the new opp
        insert opp;
        // change the probability of the opp so the trigger submits it for approval
    opp.StageName = 'Propose';
    // update the opp which should submit it for approval
    update opp;
 
        // ensure that the opp was submitted for approval
        List<ProcessInstance> processInstances = [select Id, Status from ProcessInstance where TargetObjectId = :opp.id];
   // System.assertEquals(processInstances.size(),1);
 
    }
 
}

 

BrittanyBrittany

Ok. So I think I know what the issue is. The Products__c field is other formula field. What it is meant to do is see if there are any products listed in the opportunity, if so the field = 'YES' (if not it = 'NO'). Now I am trying to figure out how to just use the SFDC standard object field "HasLineItems', I am not too sure how to replace the Products__c field in the trigger code with this object field nor modify the test code. Do I really have to insert a quote too in the test code or is there a way to have the haslineitems = true?

 

 

 

 

HariDineshHariDinesh

Hi,

 

Ok,

 

As Products__c is formula field you cann't insertdata from Test method as above.

You have to insert data such that it will be calculated as YES.

What is the formula in it?

 

Are you talking about HasOpportunityLineItem field in Opportunity Object?

You can’t give data for that also directly.

 

Below description will be useful for you.

 

 HasOpportunityLineItem

 

Read-only field that indicates whether the opportunity has associated line items. A value of true means that Opportunity line items have been created for the opportunity. An opportunity can have opportunity line items only if the opportunity has a price book. The opportunity line items must correspond to PricebookEntry objects that are listed in the opportunity Pricebook2. However, you can insert opportunity line items on an opportunity that does not have an associated Pricebook2. For the first opportunity line item that you insert on an opportunity without a Pricebook2, the API automatically sets the Pricebook2Id field, if the opportunity line item corresponds to a PricebookEntryin an active Pricebook2 that has a CurrencyIsoCode field that matches the CurrencyIsoCode field of the opportunity. If the Pricebook2 is not active or theCurrencyIsoCode fields do not match, then the API returns an error. You can’t update the Pricebook2Id or PricebookId fields if opportunity line items exist on theOpportunity. You must delete the line items before attempting to update the PricebookId field.

 

http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_objects_opportunity.htm

 

Any ways try to make/insert data such that Products__c will be calculated as YES.