You need to sign in to do that
Don't have an account?
Felix Quinones
MicrosoftGraphAPI
Apex - Send a Calendar Invite a new Deliverable record is created.
Hello All,
I'm trying to send a calendar invite to specific departments any time a new Deliverable record is created. To do that, I established several Apex Classes (below). After many changes, it continue giving me a Code Coverage Failure. Here, I have remove the client id, client secret key, tenant ID, and emails.
Error: Your code coverage is 71%. You need at least 75% coverage to complete this deployment.
Questions:
- How can I improve the different Apex Classes to increase coverage failure?
- What can I do different to received the same result?
- Any free app or low cost that could do this?
OutlookCalendarInvite
public class OutlookCalendarInvite { public static void sendCalendarInvite(List<npsp__Grant_Deadline__c> deadlines) { // Query related Opportunities Set<Id> oppIds = new Set<Id>(); for (npsp__Grant_Deadline__c deadline : deadlines) { oppIds.add(deadline.npsp__Opportunity__c); } Map<Id, Opportunity> oppMap = new Map<Id, Opportunity>([ SELECT Id, Name FROM Opportunity WHERE Id IN :oppIds ]); List<Messaging.SingleEmailMessage> emailMessages = new List<Messaging.SingleEmailMessage>(); for (npsp__Grant_Deadline__c deadline : deadlines) { String emailAddress = getEmailByDepartment(deadline.Department__c); if (emailAddress == null) { System.debug('Email address is null for department: ' + deadline.Department__c); continue; } // Generate the ICS file for the deadline NPS_MeetingInviteGenerator icsGenerator = new NPS_MeetingInviteGenerator(); List<Messaging.Emailfileattachment> fileAttachments = new List<Messaging.Emailfileattachment>(); DateTime dueDate = deadline.npsp__Grant_Deadline_Due_Date__c; String bodyContent = 'Hello ' + deadline.Department__c + ' Team,\n\n' + 'Please find attached the calendar invite for grant opportunity ' + deadline.npsp__Opportunity__c + ' with the following deadline: ' + dueDate + '\n\n' + 'Deliverable Type: ' + deadline.npsp__Type__c + '\n\n' + 'Deliverable Sub-Type: ' + deadline.SubType__c + '\n\n' + 'Requirements: ' + deadline.npsp__Grant_Deliverable_Requirements__c + '\n\n' + 'Note: This is an automated message from Salesforce.'; icsGenerator.meetingSubject = 'Invite - ' + deadline.Name; icsGenerator.meetingBody = bodyContent; icsGenerator.startDate = dueDate.format('dd/MM/yyyy hh:mm:ss a'); icsGenerator.endDate = dueDate.addHours(1).format('dd/MM/yyyy hh:mm:ss a'); icsGenerator.fromAddress = 'salesforce@nscaphila.org'; icsGenerator.displayName = 'NSCA Salesforce Team'; icsGenerator.attachmentName = 'MeetingInvite.ics'; icsGenerator.toAddressList = new List<String> {emailAddress}; Messaging.EmailFileAttachment meetingInviteIcs = icsGenerator.generateMeetingInvite(); fileAttachments.add(meetingInviteIcs); // Send the email with the ICS attachment NPS_EmailUtility emailUtils = new NPS_EmailUtility(); emailUtils.toAddressList = new String[] {emailAddress}; emailUtils.subject = 'Calendar Invite: ' + deadline.Name; OrgWideEmailAddress[] orgWideEmailAddr = [select Id from OrgWideEmailAddress]; if (!orgWideEmailAddr.isEmpty()) { emailUtils.orgWideEmailAddrId = orgWideEmailAddr[0].Id; } emailUtils.body = bodyContent; emailUtils.emailAttachmentList = fileAttachments; if (!Test.isRunningTest()) { emailUtils.sendEmail(); } } } private static String getEmailByDepartment(String department) { if (department == 'Finance') { return 'finance@emailexample.org'; } else if (department == 'Economic Mobility') { return 'programs@emailexample.org'; } else if (department == 'Human Resources') { return 'hr@emailexample.org'; } else if (department == 'Executive Team') { return 'executive@emailexample.org'; } else if (department == 'Property Management') { return 'facilities@emailexample.org'; } else if (department == 'Resource Development') { return 'resources@emailexample.org'; } else { return null; } } }
OutlookCalendarInviteTest
@isTest private class OutlookCalendarInviteTest { @isTest static void testSendCalendarInvite() { // Create test Opportunity Opportunity testOpportunity = new Opportunity( Name = 'Test Opportunity', CloseDate = Date.today(), StageName = 'Prospecting' ); insert testOpportunity; // Create test data List<npsp__Grant_Deadline__c> testDeadlines = new List<npsp__Grant_Deadline__c>(); for (Integer i = 0; i < 6; i++) { npsp__Grant_Deadline__c deadline = new npsp__Grant_Deadline__c(); deadline.Name = 'Test Deadline ' + i; deadline.npsp__Grant_Deadline_Due_Date__c = Date.today().addDays(i); deadline.Department__c = getDepartmentByIndex(i); deadline.npsp__Opportunity__c = testOpportunity.Id; testDeadlines.add(deadline); } // Insert test data insert testDeadlines; // Get the list of deadline IDs List<Id> deadlineIds = new List<Id>(); for (npsp__Grant_Deadline__c deadline : testDeadlines) { deadlineIds.add(deadline.Id); } // Call sendOutlookCalendarInvite method Test.startTest(); Test.setMock(HttpCalloutMock.class, new MicrosoftGraphAPIMock()); OutlookCalendarInvite.sendOutlookCalendarInvite(deadlineIds); Test.stopTest(); } private static String getDepartmentByIndex(Integer index) { List<String> departments = new List<String>{ 'Finance', 'Economic Mobility', 'Human Resources', 'Executive Team', 'Property Management', 'Resource Development' }; return departments[Math.mod(index, departments.size())]; } }
OutlookCalendarEvent
public class OutlookCalendarEvent { public String subject; public Body body; public DateTimeTimeZone startDateTimeZone; public DateTimeTimeZone endDateTimeZone; public Boolean isAllDay; public class Body { public String contentType; public String content; public Body(String content, String contentType) { this.content = content; this.contentType = contentType; } } public class DateTimeTimeZone { public String dateTimeValue; public String timeZone; public DateTimeTimeZone(DateTime dateTimeValue, String timeZone) { this.dateTimeValue = dateTimeValue.format('yyyy-MM-dd\'T\'HH:mm:ss'); this.timeZone = timeZone; } } }OutlookCalendarInviteMock
@isTest global class OutlookCalendarInviteMock implements HttpCalloutMock { global HttpResponse respond(HttpRequest request) { HttpResponse response = new HttpResponse(); response.setStatusCode(201); // Assuming successful creation of the calendar event response.setBody('{}'); // Set an empty JSON object as the body return response; } }
MicrosoftGraphAPI
public class MicrosoftGraphAPI { private static final String CLIENT_ID = 'myclientid'; private static final String CLIENT_SECRET = 'myclientsecret'; private static final String TENANT_ID = 'mytenantid'; public static final String MICROSOFTGRAPHENDPOINT = 'https://graph.microsoft.com'; public class OAuth2 { public String token_type {get; set;} public String expires_in {get; set;} public String ext_expires_in {get; set;} public String access_token {get; set;} } public static OAuth2 getAccessToken() { String tokenEndpoint = 'https://login.microsoftonline.com/' + TENANT_ID + '/oauth2/token'; HttpRequest req = new HttpRequest(); req.setMethod('POST'); req.setEndpoint(tokenEndpoint); req.setHeader('Content-Type', 'application/x-www-form-urlencoded'); String body = 'grant_type=client_credentials' + '&client_id=' + CLIENT_ID + '&client_secret=' + CLIENT_SECRET + '&resource=https://graph.microsoft.com'; req.setBody(body); Http http = new Http(); HttpResponse res = http.send(req); if (res.getStatusCode() == 200) { return (OAuth2) JSON.deserialize(res.getBody(), OAuth2.class); } else { return null; } } }MicrosoftGraphAPIMock
@isTest global class MicrosoftGraphAPIMock implements HttpCalloutMock { global HttpResponse respond(HttpRequest req) { HttpResponse res = new HttpResponse(); res.setHeader('Content-Type', 'application/json'); if (req.getEndpoint().contains('/oauth2/v2.0/token')) { res.setStatusCode(200); String responseBody = '{"token_type": "Bearer", "expires_in": "3599", "ext_expires_in": "3599", "access_token": "mock_access_token"}'; res.setBody(responseBody); } else if (req.getEndpoint().contains('/v1.0/me/calendars/')) { res.setStatusCode(201); String responseBody = '{"id": "mock_event_id", "subject": "mock_subject", "start": {"dateTime": "2023-05-05T00:00:00.000Z", "timeZone": "UTC"}, "end": {"dateTime": "2023-05-06T00:00:00.000Z", "timeZone": "UTC"}}'; res.setBody(responseBody); } return res; } }GrantDeadlineTrigger
trigger GrantDeadlineTrigger on npsp__Grant_Deadline__c (after insert, after update) { List<npsp__Grant_Deadline__c> deadlinesToNotify = new List<npsp__Grant_Deadline__c>(); for (npsp__Grant_Deadline__c deadline : Trigger.new) { if (deadline.npsp__Type__c == 'Final Report' && deadline.Email_Sent__c == false) { deadlinesToNotify.add(deadline); } } if (!deadlinesToNotify.isEmpty()) { System.enqueueJob(new OutlookCalendarInvite(deadlinesToNotify)); } }