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
Kris WebsterKris Webster 

Deployment Error PLEASE HELP

Hello Community ! I am attemptimng to deploy a Apex Trigger to update resource requests on Opportunites with a Project name and change the status of the request as well. I want all this to occur when the opportunity hits closed won. 

WITH that said I have written the code and have it executing fully in the Sandbox wihtout any erros, and have my code coverage passing 100% when I run the tests for the test class in the SB.. 

What I am struggling with is deploying the code to Production.. 

When I attempt to deplot the code I am recieving the following error and I am not sure why i am at all.. 

Here is my Code 
public override void afterUpdate(SObject oldSo, SObject so)
    {
        Opportunity newOpp = (Opportunity)so;
        Opportunity oldOpp = (Opportunity)oldSo;
        
        if (newOpp.StageName == Constants.OPTY_STAGE_CLOSED_WON && newopp.Does_Not_Need_Resource_Request__c == FALSE){

        list<pse__Resource_Request__c> resourceRequests = [select ID, pse__Opportunity__c, Pse__Status__c FROM pse__Resource_Request__c];
        list<opportunity> opps = [Select ID, pse__Primary_Project__c from Opportunity];
        boolean isValid = false;
        
        for (pse__Resource_Request__c resourceRequest : resourceRequests)
        {

            if (resourceRequest.pse__Opportunity__c == newOpp.Id)
            {
            
                //there is a resource request that has the opportunity id of the current opp meaning the opp is valid
                isValid = true;
                resourceRequest.pse__Project__c = newOpp.pse__Primary_Project__c;
                resourceRequest.pse__Status__c = 'Assigned';

            }
        } 
        // if we get out of the loop and isValid is false, it means there were 0 opps that matched the resource request
        // return error
         if (!isValid) {
            so.addError('Please add Resource Requests to this Opportunity before marking it as "Closed Won." If no Resource Requests need to be added to the Opportunity please check the "Does Not Need Resource Request" checkbox in order to Close Win.');
                }

            }
        }

And here is my Test Class to go along with it. 
 
@isTest static void aftUpTest() 
        {

        TestDataFactory.initPermissionControls();


        //Prep the data 
        TestDataFactory.projects = TestDataFactory.createprojects(2);
        TestDataFactory.opportunities = TestDataFactory.createOpportunities(2);
        TestDataFactory.createResourceRequests(1, TestDataFactory.opportunities[0], TRUE);

	system.test.startTest();
            
        TestDataFactory.opportunities[0].StageName = Constants.OPTY_STAGE_CLOSED_WON;
        TestDataFactory.opportunities[0].Does_Not_Need_Resource_Request__c = FALSE;
        TestDataFactory.opportunities[0].Create_Project__c = FALSE;
        TestDataFactory.opportunities[0].Info_Complete__c = TRUE;
        TestDataFactory.opportunities[0].Pse__Primary_Project__c = TestDataFactory.projects[0].id;

        update TestDataFactory.opportunities;



        system.test.stopTest();

        }
 }

In the test code the test data factory is creating an opp for me, and setting it all up to be ready to close win, and then the test data factory is creating a resource request for me with the associated opportunity on the respource request set to the same opportunity the test data factory just created. 

With all this said the error message I am recieving when attempting to deploy the code to Production reads.. 


"Methods defined as TestMethod do not support Web service callouts 
Stack Trace: null"

PLEASE HELP. 


I have spent 3 days trying to uncover the error and still nothing, so any help would be MUCH appreciated! 
Kaustubh LabheKaustubh Labhe
How does the TestDataFactory look?
Kris WebsterKris Webster
Create opportunities looks like this 
 
public static list<Opportunity> createOpportunities(integer cnt)
    {
        return createOpportunities(cnt, true);
    }
    public static list<Opportunity> createOpportunities(integer cnt, boolean insertRecords)
    {
        return createOpportunities(cnt, null, accounts[0], regions[0], practices[0], groups[0], insertRecords);
    }
    public static list<Opportunity> createOpportunities(integer cnt, Opportunity parent)
    {
        return createOpportunities(cnt, parent, true);
    }
    public static list<Opportunity> createOpportunities(integer cnt, Opportunity parent, boolean insertRecords)
    {
        return createOpportunities(cnt, parent, accounts[0], regions[0], practices[0], groups[0], insertRecords);
    }
    public static list<Opportunity> createOpportunities(integer cnt, Opportunity parent, Account acct, pse__Region__c rgn, 
                                                        pse__Practice__c prac, pse__Grp__c grp)
    {
        return createOpportunities(cnt, parent, acct, rgn, prac, grp, true);
    }
    public static list<Opportunity> createOpportunities(integer cnt, Opportunity parent, Account acct, pse__Region__c rgn, 
                                                        pse__Practice__c prac, pse__Grp__c grp, boolean insertRecords)
    {
        list<Opportunity> optyList = new list<Opportunity>();

        for (integer i=1; i<=cnt; i++)
        {
            Opportunity o = new Opportunity();
            o.CurrencyIsoCode = currencyCode;
            o.Name = 'Test Opportunity ' + i + ' ' + key;
            o.AccountId = acct != null ? acct.Id : null;
            o.pse__Parent_Opportunity__c = parent != null ? parent.Id : null;
            o.StageName = Constants.TEST_DEFAULT_OPTY_STAGE;
            o.CloseDate = startDate.addDays(30);
            o.LeadSource = 'Test Source';
            o.pse__Region__c = rgn != null ? rgn.Id : null;
            o.pse__Practice__c = prac != null ? prac.Id : null;
            o.pse__Group__c = grp != null ? grp.Id : null;
            optyList.add(o);
        }

        if (insertRecords == true) { insert optyList; }
        return optyList;
    }

Create Resource Requests looks like this 
 
public static list<pse__Resource_Request__c> createResourceRequests(integer cnt)
    {
        return createResourceRequests(cnt, true);
    }
    public static list<pse__Resource_Request__c> createResourceRequests(integer cnt, boolean insertRecords)
    {
        return createResourceRequests(cnt, projects[0], null, insertRecords);
    }
    public static list<pse__Resource_Request__c> createResourceRequests(integer cnt, pse__Proj__c proj)
    {
        return createResourceRequests(cnt, proj, true);
    }
    public static list<pse__Resource_Request__c> createResourceRequests(integer cnt, Opportunity opty)
    {
        return createResourceRequests(cnt, opty, true);
    }
    public static list<pse__Resource_Request__c> createResourceRequests(integer cnt, pse__Proj__c proj, boolean insertRecords)
    {
        return createResourceRequests(cnt, proj, null, insertRecords);
    }
    public static list<pse__Resource_Request__c> createResourceRequests(integer cnt, Opportunity opty, boolean insertRecords)
    {
        return createResourceRequests(cnt, null, opty, insertRecords);
    }
    public static list<pse__Resource_Request__c> createResourceRequests(integer cnt, pse__Proj__c proj, Opportunity opty, boolean insertRecords)
    {
        list<pse__Resource_Request__c> reqList = new list<pse__Resource_Request__c>();

        for (integer i=1; i<=cnt; i++)
        {        
            pse__Resource_Request__c req = new pse__Resource_Request__c();
            req.CurrencyIsoCode = currencyCode;
            req.pse__Resource_Request_Name__c = 'Test request ' + i + ' ' + key;
            req.pse__Opportunity__c = opty != null ? opty.Id : null;
            req.pse__Start_Date__c = startDate;
            req.pse__End_Date__c = startDate.addDays(duration);
            req.pse__Region__c = proj != null ? proj.pse__Region__c : opty.pse__Region__c;
            req.pse__Practice__c = proj != null ? proj.pse__Practice__c : opty.pse__Practice__c;
            req.pse__Group__c = proj != null ? proj.pse__Group__c : opty.pse__Group__c;
            req.pse__Resource_Role__c = Constants.TEST_DEFAULT_RES_ROLE;
            req.pse__Requested_Bill_Rate__c = 200.0;
            req.pse__SOW_Hours__c = 500;
            req.pse__Planned_Bill_Rate__c = 200.0;
            req.pse__Notes__c = 'Test';
            req.pse__Status__c = Constants.TEST_DEFAULT_RESOURCE_REQUEST_STATUS;
            reqList.add(req);
        }

        if (insertRecords == true) { insert reqList; }
        return reqList;
    }

Create Projects Looks like this
 
public static list<pse__Proj__c> createProjects(integer cnt)
    {
        return createProjects(cnt, true);
    }
    public static list<pse__Proj__c> createProjects(integer cnt, boolean insertRecords)
    {
        return createProjects(cnt, accounts[0], null, regions[0], practices[0], groups[0], resources[0], insertRecords);
    }
    public static list<pse__Proj__c> createProjects(integer cnt, Account acct, Opportunity opty, pse__Region__c rgn, 
                                                    pse__Practice__c prac, pse__Grp__c grp, Contact projMgr)
    {
        return createProjects(cnt, acct, opty, rgn, prac, grp, projMgr, true);
    }
    public static list<pse__Proj__c> createProjects(integer cnt, Account acct, Opportunity opty, pse__Region__c rgn, 
                                                    pse__Practice__c prac, pse__Grp__c grp, Contact projMgr, 
                                                    boolean insertRecords)
    {
        list<pse__Proj__c> projList = new list<pse__Proj__c>();

        for (integer i=1; i<=cnt; i++)
        {
            pse__Proj__c p = new pse__Proj__c();
            p.CurrencyIsoCode = currencyCode;
            p.Name = 'Test Project ' + i + ' ' + key;
            p.pse__Account__c = acct != null ? acct.Id : null;
            p.pse__Opportunity__c = opty != null ? opty.Id : null;
            p.pse__Opportunity_Owner__c = opty != null ? opty.OwnerId : UserInfo.getUserId();
            p.pse__Region__c = rgn != null ? rgn.Id : null;
            p.pse__Practice__c = prac != null ? prac.Id : null;
            p.pse__Group__c = grp != null ? grp.Id : null;
            p.pse__Project_Manager__c = projMgr != null ? projMgr.Id : null;
            p.pse__Start_Date__c = startDate;
            p.pse__End_Date__c = p.pse__Start_Date__c.addDays(duration);
            p.pse__Is_Active__c = true;
            p.pse__Is_Billable__c = true;
            p.pse__Daily_Timecard_Notes_Required__c = false;
            p.pse__Allow_Timecards_Without_Assignment__c = true;
            p.pse__Allow_Expenses_Without_Assignment__c = true;
            p.pse__Project_Type__c = Constants.TEST_DEFAULT_PROJ_TYPE;
            p.pse__Billing_Type__c = Constants.TEST_DEFAULT_PROJ_BILL_TYPE;
            p.pse__Stage__c = Constants.TEST_DEFAULT_PROJ_STAGE;
            p.Time_Approval_Method__c = Constants.TEST_DEFAULT_PROJ_TIME_APPROVAL_METHOD;
            p.Expense_Approval_Method__c = Constants.TEST_DEFAULT_PROJ_EXP_APPROVAL_METHOD;
            projList.add(p);
        }

        if (insertRecords == true) { insert projList; }
        return projList;
    }

@Kaustubh Labhe
System Admin 995System Admin 995
Have you tried setting up a mock response (https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_callouts_wsdl2apex_testing.htm) for the callout? Is there any proccess that could be going off in production that is causing a callout to be preformed? 
Kris WebsterKris Webster
So I have tried this as well. I have attempted to deploy the test class with implementing the Mock response like so.. 
 
@isTest static void aftUpTest() 
        {

        TestDataFactory.initPermissionControls();

        Test.setMock(HttpCalloutMock.class, new YourHttpCalloutMockImpl());

        //Prep the data 
        TestDataFactory.projects = TestDataFactory.createprojects(2);
        TestDataFactory.opportunities = TestDataFactory.createOpportunities(2);
        TestDataFactory.createResourceRequests(1, TestDataFactory.opportunities[0], TRUE);

	system.test.startTest();
            
        TestDataFactory.opportunities[0].StageName = Constants.OPTY_STAGE_CLOSED_WON;
        TestDataFactory.opportunities[0].Does_Not_Need_Resource_Request__c = FALSE;
        TestDataFactory.opportunities[0].Create_Project__c = FALSE;
        TestDataFactory.opportunities[0].Info_Complete__c = TRUE;
        TestDataFactory.opportunities[0].Pse__Primary_Project__c = TestDataFactory.projects[0].id;

        update TestDataFactory.opportunities;



        system.test.stopTest();

        }

The setMock is pulling from a class that looks like this.. 
 
global class YourHttpCalloutMockImpl implements HttpCalloutMock {
    global HTTPResponse respond(HTTPRequest req) {
        HttpResponse resp = new HTTPResponse();
        resp.setHeader('Content-Type', 'application/JSON');
        resp.setBody('Your body');
        resp.setStatusCode(201);
        return resp;
    }
}

The error I get when trying to deploy the test class like this looks like this.. 

System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out 
Stack Trace: Class.SlackPublisher.QueueableSlackPost.execute: line 51, column 1 

NOW WHEN READING THAT ERROR
 we can look at the class it is refrencing here.. 
 
public with sharing class SlackPublisher {
     
    private static final String SLACK_URL = 'https://hooks.slack.com/services/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';
           
    public class Oppty {
        @InvocableVariable(label='Opportunity Name')
        public String opptyName;               
        @InvocableVariable(label='Opportunity Pipeline')
        public String pipeline;
        @InvocableVariable(label='Opportunity Amount')
        public String amount;
        @InvocableVariable(label='Owner First Name')
        public String ownerFirstName;
        @InvocableVariable(label='Owner Last Name')
        public String ownerLastName;
        @InvocableVariable(label='Account Name')
        public String accountName;
    }
     
    @InvocableMethod(label='Post to Slack')
    public static void postToSlack ( List<Oppty> opps ) {
        Oppty o = opps[0]; // bulkify the code later
        
        Map<String,Object> msg = new Map<String,Object>();
        msg.put('text', 'New deal won! :celebrate:\n*' + o.opptyName + '*\n>*Amount*: ' + o.amount + '\n>*Pipeline*: ' + o.pipeline
               + '\n>*Owner*: ' + o.ownerFirstName + ' ' + o.ownerLastName + '\n>*Account Name*: ' + o.accountName);
        msg.put('mrkdwn', true);
        
        String body = JSON.serialize(msg);   
        System.enqueueJob(new QueueableSlackPost(SLACK_URL, 'POST', body));
    }
     
    public class QueueableSlackPost implements System.Queueable, Database.AllowsCallouts {
         
        private final String url;
        private final String method;
        private final String body;
         
        public QueueableSlackPost(String url, String method, String body) {
            this.url = url;
            this.method = method;
            this.body = body;
        }
         
        public void execute(System.QueueableContext ctx) {
            HttpRequest req = new HttpRequest();
            req.setEndpoint(url);
            req.setMethod(method);
            req.setBody(body);
            Http http = new Http();
            HttpResponse res = http.send(req);
        }
    }
}

the error is coming from the very last line of the code "HttpResponse res = http.send(req);"

SO I am really unsure why I am getting an error from a class that is not even referenced in my initial test class. I hope this gives you all the information needed to potentially give me some help.. I REALLY APPRECIATE IT!! 

@System Admin 995
System Admin 995System Admin 995
Are there any triggers going off from the test class? can you try surrounding the line like this?
if(!test.isRunningTest()){
    HttpResponse res = http.send(req);
}

 
Kris WebsterKris Webster
which line should i surround with that code?? 
Kris WebsterKris Webster
@System Admin 995
 
System Admin 995System Admin 995
line 51 of SlackPublisher