+ Start a Discussion
KSorensonKSorenson 

Apex trigger troubleshooting - update opportunity stage on a certain date

Hello,

I am trying to write what should be a simple Apex trigger but am having issues figuring out the correct code and syntax.  This is what I have so far - please forgive me, I am an admin, not a developer/coder.

What we are trying to accomplish here, is a trigger that will automatically change the stage of a Recurring Donation (opportunity) that has a pledged date that has come due (due today or overdue). There are a few other criteria involved (can't be a C&P payment type, must be pledged status etc).

I am currently getting the error: "Error: Condition expression must be of type Boolean at line 11 column 17" but I cannot figure out how to correct it.  (the line reads  if (Op.StageName ='Pledged'))

There is likely more wrong with my code, but this is where I am currently stuck. If you can find a better way to accomplish what I am doing, please make a suggestion. 
 
trigger AutoPost on Opportunity (after update) {

date myDate = date.today();

for (Opportunity op: Trigger.new)              //check if record is a monthly donation, record is due/overdue,record is status Pledged, not C&P payment
    {
        if (op.RecordType = '012i0000000Rt6LAAS')
        { 
            if(Op.CloseDate <= myDate)
            {
                if (Op.StageName ='Pledged')
                {
                    if (op.Payment_Method__c != 'Click & Pledge')
         
                    Op.StageName ='Posted';                      // Change the Opportunity.Stage to posted
                    
                }
            } 
        }                                    
    }
}

Thanks to all eyes and fingers in advance.
 
Malni Chandrasekaran 2Malni Chandrasekaran 2
Karen Sorenson,
Please use == operator to compare instead of just = which is a assignment operator.
 
KSorensonKSorenson
Thank you Malni. I will try that and post back the results.
KSorensonKSorenson
There were a few other little things that I had to correct before I got it to accept the code.  Problem number one solved - thank you Malni.

Problem two is that I have never created a test class, and am wondering what it should comprise of. Again, I am just an admin struggling my way through this. I am not asking for a written solution but I want to get it right, yet I do not know what the test class needs to include/cover for my specific situation above.  If someone could point me in the right direction it would be appreciated. TIA.

For anyone who might find this userful here is the code that worked.
trigger AutoPost on Opportunity (after update) 
{

date myDate = date.today();

for (Opportunity op: Trigger.new)                              
    {
      if (op.RecordType.ID == '012i0000000Rt6LAAS')                //check if record is a monthly donation, record is due (today or overdue), stage is Pledged, not C&P transaction
      { 
            if (Op.CloseDate <= myDate)
            {
                if (Op.StageName =='Pledged')
                {
                    if (op.Payment_Method__c != 'Click & Pledge')
         
                    Op.StageName ='Posted';                          // Change the Opportunity.Stage to posted
                    
                }
            } 
       }                                    
    }
}
KSorensonKSorenson
Sorry, I couldn't figure out how to edit my reply above.

I am also  wondering if my revised code above is correct regarding how I am attempting to update the Stage to "Posted".  The stage field is a picklist.  If this matters, how would I go about handling that?

TIA
Malni Chandrasekaran 2Malni Chandrasekaran 2
Karen Sorenson,
Please try this link - https://trailhead.salesforce.com/en/modules/apex_testing/units/apex_testing_triggers
It explains writing the test class in a simplest way. 
In Trigger test class, normally we do the data setup (data will not be committed and hence dont have to worry abt deleting data) and do the data manipulation which invokes the trigger (in your case it will update opportunity) and finally check for the expected result.
All the best! :)
KSorensonKSorenson
Malni, thanks for the link. I had already read that but wasn't really wrapping my head around how I would test my scenario. 

I am also  wondering if my revised code above is correct regarding how I am attempting to update the Stage to "Posted".  The stage field is a picklist.  If this matters, how would I go about handling that?

TIA
Malni Chandrasekaran 2Malni Chandrasekaran 2
Karen,
If I understood your question right,
Yes, you can update the Stage to 'Posted' as long as it matches the spelling given in picklist. My suggestion is to combine all the if s into one with '&& operator' if you are not going to write any 'else' statement.

For Testing,
if you are using developer console, write a regular class to do the data setup and then update the opportunity (update statement must be packed between Test.StartTest() and Test.StopTest() method),  then you can use System.AssertEquals method to check the result is a expected value.

you have to add '@isTest' annotation to make the above regular class to 'Test Class'

To run this test class, there is a menu 'Test' under that you can see 'New Run' which will list you the list of class under your org. Select the particular test class and then select the method and click on 'Run' button.
 
KSorensonKSorenson
I think I am very close - I believe I have a viable Test Class but it is not returning the desired result - StageName is not updating from Pledged to Posted. So I do believe that it has something to do with the StageName being a picklist in my Apex Trigger. Could you please let me know how to handle it? The piece that I believe is the problem is this:
Op.StageName ='Posted';

Here is the entire code from my Test Class:
@isTest
private class AutoPostTest {
static testMethod void insertNewOpportunity(){

Id RecType = [Select Id, Name from RecordType where name = 'Monthly Donation' limit 1].Id;

Account NewAcc = new Account (Name = 'Testy Tester');
insert NewAcc;

Opportunity NewOpp = new Opportunity (
                    AccountID = NewAcc.ID,
                    RecordTypeID = RecType, 
                    Name='Test Opp 1', 
                    StageName='Pledged', 
                    CloseDate=date.Today() + 30, 
                    Amount = 2
                    );

insert NewOpp;

newOpp.CloseDate = date.today();     

Test.startTest();

    update NewOpp;

Test.stopTest();
                     
Opportunity opp = [SELECT StageName, Name FROM Opportunity WHERE Name='Test Opp 1'];

System.Debug('opp stage ='+opp);
System.assertEquals('Posted', opp.StageName);


}}

Malni Chandrasekaran 2Malni Chandrasekaran 2
Karen,
Any data changes you do in the test class will not be committed. Hence you can not see the changes any ways. What matters is if your test class executed successfully with minimum 75% of code (corresponding class) coverage.
Malni Chandrasekaran 2Malni Chandrasekaran 2
Karen,
If you have to test your functionality, you may update the record in Query Editor which in turn call ur trigger and then you can check for the result.
Hope this helps!
Please mark best answer if any of my suggestions helped you.
KSorensonKSorenson
Hi,

I am still experiencing an error with my test code. When I run the test, I receive the following detailed error message:
Apex Test Result Detail 
Time Started15/05/2017 10:42 AM
ClassAutoPostTest
Method NameinsertNewOpportunity
Pass/FailFail
Error MessageSystem.QueryException: List has no rows for assignment to SObject
Stack TraceClass.AutoPostTest.insertNewOpportunity: line 25, column 1

Line 25 of my code is this: 
Opportunity opp = [SELECT StageName FROM Opportunity WHERE Name='Test Opp 1'];

Any idea how I can resolve this error and get my test class to pass?
KSorensonKSorenson
I don't know if this is relevant/helpful but in our organization we have a workflow that autonames all of our donations (including recurring donations). Could this a cause of the error, as the test cannot locate the new opportunity just inserted because a workflow would change the name of it? The auto-renaming is as follows:
 
Account.Name & " " & $RecordType.Name & " " & text(CloseDate)
For example, using the test opportunity de above, if manually created by an individual, would be renamed "Testy Tester Monthly Donation 2017-05-15".

Should that be what the test code checks for, this renamed opportunity name?


 
Malni Chandrasekaran 2Malni Chandrasekaran 2
Karen,
Normally, test class can access only the data it creates in addition to objects that are used to manage your organization, such as 
User
Profile
Organization
AsyncApexJob
CronTrigger
RecordType
ApexClass
ApexTrigger
ApexComponent
ApexPage

Please try adding @isTest(SeeAllData=true) in your test class to enable access to all data for that test method and try.

Please mark it best answer if it works for you.
Malni Chandrasekaran 2Malni Chandrasekaran 2
Karen,
I am sorry; I overlooked your question. If you have any doubt, you may try
SELECT StageName, Name FROM Opportunity WHERE Name LIKE '%Test Opp 1%' 

This filters any Name that contains particular text no matter what it is prefixed or postfixed with.
 
Malni Chandrasekaran 2Malni Chandrasekaran 2
And also you can try System.debug the Account Name before the select statement, to make sure what it has changed to.
KSorensonKSorenson
Hi Malni,

Thanks for your suggestions. I believe I have integrated them as you have intentioned.

I am still struggling to get this working, and have enough code coverage in order to move to production. I am still not sure if this trigger even works as I need it to - I don't really know how to test it. So far I have not been able to run the class successfully. Also the Code Coverage is only at 60% and I don't know enough to know why?

So here is the current code of my Apex trigger - I get an error "Loop variable must be of type SObject" on this line of code: "for (Opportunity op: Trigger.new) " - I am out of my depth and if someone could provide the right code that I need to use it would be appreciated.
trigger AutoPost on Opportunity (after update) 
{

//String Date1 = date.today().format(); 
//Date myDate = date.parse(Date1);

Id recType = [Select Id, Name from RecordType where name = 'Monthly Donation' limit 1].Id;

for (Opportunity op: Trigger.new)                                    //check if record is a monthly donation('012i0000000Rt6LAAS') record is due (today), record status is Pledged, not C&P transaction                      
    {
      if (op.RecordType.ID == recType)
      { 
            //if (Op.CloseDate <= myDate )
            if (Op.CloseDate <= date.today() )
            {
                if (Op.StageName =='Pledged')
                {
                    if (op.Payment_Method__c != 'Click & Pledge')
         
                        Op.StageName ='Posted';                      // Change the Opportunity.Stage to posted
                    
                }
            } 
       }                                    
    }
}

As well, here is the current code for the Test Class, again I get an error around SObject.
Class: AutoPostTest
Method: insertNewOpportunity
Result: fail
Errors: System.QueryException: List has no rows for assignment to SObject
Stak Trace: (CRMfusionDBR101)
 
@isTest(SeeAllData=true)
private class AutoPostTest {

static testMethod void insertNewOpportunity(){

Id RecType = [Select Id, Name from RecordType where name = 'Monthly Donation' limit 1].Id;


Test.startTest();

    Account NewAcc = new Account (Name = 'Testy Tester');
    insert NewAcc;
    
    Opportunity newOpp = new Opportunity (
                        AccountID = NewAcc.ID,
                        RecordTypeID = RecType, 
                        Name='Test Opp 1', 
                        StageName='Pledged', 
                        CloseDate= date.today()+30, 
                        Amount = 2
                        );
    insert newOpp;
    
    newOpp.CloseDate = date.Today();     
    
    update NewOpp;
    
Test.stopTest();

Opportunity opp = [SELECT StageName, Name FROM Opportunity WHERE Name LIKE '%Testy%'];

System.Debug('opp stage =' + opp.StageName);
System.assertEquals('Posted', opp.StageName);


}}


 
Malni Chandrasekaran 2Malni Chandrasekaran 2
Karen,

Please do the changes marked in bold and underlined
trigger AutoPost on Opportunity (before update)  // Trigger.new records will be read only as the records are not committed yet in After trigger.
{

//String Date1 = date.today().format(); 
//Date myDate = date.parse(Date1);

Id recType = [Select Id, Name from RecordType where name = 'Monthly Donation' limit 1].Id;
System.Debug('RecID from AutoPost Trigger ' + recType);
for (Opportunity op: Trigger.new)                                    //check if record is a monthly donation('012i0000000Rt6LAAS') record is due (today), record status is Pledged, not C&P transaction                      
    {
      if (op.RecordType.ID == recType)
      { 
System.Debug('RecordType is Monthly Donation ' + op.RecordType.ID);
            //if (Op.CloseDate <= myDate )
            if (Op.CloseDate <= date.today() )
            {
System.Debug('Overdue ' + Op.CloseDate);
                if (Op.StageName =='Pledged')
                {
System.Debug('StageName is Pledged  ' + Op.StageName);
                    if (op.Payment_Method__c != 'Click & Pledge')
System.Debug('payment method is not pledged  ' + op.Payment_Method__c);         
                        Op.StageName ='Posted';                      // Change the Opportunity.Stage to posted
                    
                }
            } 
       }                                    
    }
}


Try updating the record to invoke this trigger and let me know the debug logs.
KSorensonKSorenson
Thanks Malni, I am off for the day but I hope I can put aside some time tomorrow to make the changes as indicated and will report back. It may be two days before I can get back to this, however. Stay tuned and thanks again.