Use Case:
Write a trigger, to achieve the following:
- If an opportunity is closed then, no one should be able to delete it except user having System Administrator profile.
- Once an opportunity is marked as closed won, send an email to the following users:
- Opportunity Owner
- 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 truefor(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 updatedif(Trigger.isAfter && Trigger.isUpdate) {// Get all the Closed Won opportunities which were updatedList<Opportunity> oportunities = [Select Id, OwnerId, Name, StageName, Account.OwnerId, Owner.Email, Account.Owner.EmailFrom 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 emailsif(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 emailsMessaging.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.
@isTestprivate class OpportunityTriggerTest {// Test Data setup method@testSetupstatic void dataSetup() {// Insert an accountAccount 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 opportunityProfile 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.@isTeststatic 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 orgUser 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.');}}}@isTeststatic 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 deletedTest.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@isTeststatic 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 updatedTest.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@isTeststatic 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 anythingTest.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%