Use Case:

Write a trigger, to achieve the following:

  1. If an opportunity is closed then, no one should be able to delete it except user having System Administrator profile.
  2. Once an opportunity is marked as closed won, send an email to the following users:
    1. Opportunity Owner
    2. Account Owner
trigger OpportunityTrigger on Opportunity (before delete, after update) {
// Run this code for before delete operation.
if(Trigger.isBefore && Trigger.isDelete) {
// Get the admin profile.
Profile adminProfile = [Select Id From Profile Where Name = 'System Administrator' LIMIT 1];
// Iterate through each opportunity and check if the current user's profile is admin
// and if the opportunity is closed won or closed lost
// throws the error if the above condition is true
for(Opportunity opp : Trigger.old) {
if(System.UserInfo.getProfileId() != adminProfile.Id && (opp.StageName == 'Closed Won' || opp.StageName == 'Closed Lost')) {
opp.addError('You do not have necessary permissions to delete Closed opportunities.');
}
}
}
// Run this code whenever opportunity is updated
if(Trigger.isAfter && Trigger.isUpdate) {
// Get all the Closed Won opportunities which were updated
List<Opportunity> oportunities = [Select Id, OwnerId, Name, StageName, Account.OwnerId, Owner.Email, Account.Owner.Email
From Opportunity Where Id IN :Trigger.newMap.keySet()
AND StageName='Closed Won'];
if(!oportunities.isEmpty()) {
// Create an empty list of mail messages which need to be sent.
List<Messaging.SingleEmailMessage> mails = new List<Messaging.SingleEmailMessage>();
for(Opportunity opp : oportunities) {
Messaging.SingleEmailMessage emailMessage = new Messaging.SingleEmailMessage();
// Check if Opportunity owner and account owner are same
// if yes, then set only 1 email address to the 'To Address' so that 2 emails are not sent to the same owner
// else add email of both owners
// set subject and text body of the email as well and add the email to list of emails
if(opp.OwnerId == opp.Account.OwnerId) {
emailMessage.setToAddresses(new List<String> {opp.Owner.Email});
}
else {
emailMessage.setToAddresses(new List<String> {opp.Owner.Email, opp.Account.Owner.Email});
}
emailMessage.setSubject('Opportunity - Closed Won');
emailMessage.setPlainTextBody('Below Opportunity with Opportunity Id and Name is now Closed Won.\n' +
'Opportunity Id: ' + opp.Id + '\n' +
'Name: ' + opp.Name);
mails.add(emailMessage);
}
// Send list of emails
Messaging.sendEmail(mails);
}
}
}

Test Class:

Scenario 1- We will try to delete a closed opportunity with user having profile standard user and verify that the user should not be able to delete it. 

Scenario 2- We will try to delete a closed opportunity with user having profile System admin and verify that the user should be able to delete it. 

Scenario 3- We will verify that once an opportunity is closed won, email invocation count is increased.

@isTest
private class OpportunityTriggerTest {
// Test Data setup method
@testSetup
static void dataSetup() {
// Insert an account
Account acc = new Account(Name='TestAccount');
insert acc;
Opportunity opp1 = new Opportunity(Name='AdminOpp', AccountId=acc.Id, StageName = 'Prospecting', CloseDate = System.today());
insert opp1;
// Insert an opportunity related to the account as a standard user so that owner would be different for this opportunity
Profile standUserProfile = [Select Id From Profile Where Name = 'Standard User'];
User standardUser = new User(Alias = 'standt', Email='standarduser@testclasses.com',
EmailEncodingKey='UTF-8', LastName='TestUser', LanguageLocaleKey='en_US',
LocaleSidKey='en_US', ProfileId = standUserProfile.Id,
TimeZoneSidKey='America/Los_Angeles', UserName='standarduser@testclasses.com');
System.runAs(standardUser) {
Opportunity opp2 = new Opportunity(Name='StandOpp', AccountId=acc.Id, StageName = 'Prospecting', CloseDate = System.today());
insert opp2;
}

}
// Test once opportunity is closed, only admin should be able to delete it.
// First we will try to delete using standard user, in this case the user should not be able to delete it.
// Then we will try to delete using admin, user should be able to delete the opportunity.
    @isTest
static void test_beforeDelete_standUser() {
Opportunity opp = [Select Id, Name From Opportunity Where Name = 'StandOpp' LIMIT 1];
opp.StageName = 'Closed Won';
update opp;
// Perform the deletion using Standard User
// and assert that error is thrown and opportunity still exists in the org
User standUser = [Select Id From User Where Email = 'standarduser@testclasses.com'];
System.runAs(standUser) {
try {
delete opp;
}
catch(DMLException e) {
    System.assert(e.getMessage().contains('You do not have necessary permissions to delete Closed opportunities'),
'Exception was not thrown');
System.assertEquals(1, [Select Id, Name From Opportunity Where Name = 'StandOpp' LIMIT 1].size(),
'Opportunity count is not correct.');
    }
}
}
    @isTest
static void test_beforeDelete_admin() {
Opportunity opp = [Select Id, Name From Opportunity Where Name = 'StandOpp' LIMIT 1];
opp.StageName = 'Closed Won';
update opp;
// Perform the deletion using admin and assert that opportunity should be deleted
Test.startTest();
delete opp;
Test.stopTest();
System.assertEquals(0, [Select Id, Name From Opportunity Where Name = 'StandOpp' LIMIT 1].size(),
'Opportunity was not deleted.');
}
// Test method to verify that email is sent to account and opportunity owners when opportunity is Closed Won
@isTest
static void test_afterUpdate_closedWonOpp() {
Account acc = [Select Id, OwnerId From Account Where Name = 'TestAccount'];
List<Opportunity> opportunities = [Select Id, OwnerId, StageName From Opportunity];
for(Opportunity opp : opportunities) {
System.assert(opp.StageName != 'Closed Won', 'Opportunity should not be closed won already.');
}

// If email is sent, then method Limits.getEmailInvocations() should be updated
Test.startTest();
for(Opportunity opp : opportunities) {
opp.StageName = 'Closed Won';
}
update opportunities;
    System.assertEquals(1, Limits.getEmailInvocations(), 'Email invocation should only be 1.');
Test.stopTest();
}
// Test method to verify that email is not sent to account and opportunity owners when opportunity is not closed won
@isTest
static void test_afterUpdate_notClosedWonOpp() {
Account acc = [Select Id, OwnerId From Account Where Name = 'TestAccount'];
List<Opportunity> opportunities = [Select Id, OwnerId, StageName From Opportunity];
for(Opportunity opp : opportunities) {
System.assert(opp.StageName != 'Closed Won', 'Opportunity should not be closed won already.');
}

// If email is not sent, then method Limits.getEmailInvocations() should not be updated anything
Test.startTest();
for(Opportunity opp : opportunities) {
opp.StageName = 'Needs Analysis';
}
update opportunities;
    System.assertEquals(0, Limits.getEmailInvocations(), 'Email invocation should only be 0.');
Test.stopTest();
}
}
Code Coverage: 100%
Like it ? Share : Do Nothing

Leave a Reply