Thanks to the latest Salesforce release, Winter '24, we now have a small window into what they call "Unified Activities", by way of Standard Reports. That seems to be the only available mechanism at the moment, so I've created a simple batch job to run every so often to toss the latest scheduled event on the related Account. The key is to define a new report using their new Accounts with Unified Events
Report Type and then just make sure that there are two columns: Account Name and Activity Date/Time (IMPORTANT: sorted DESC
). I set a filter to show the last week's worth of activities so that a failed batch would be "self-healed" by the next batch (plus some buffer) and my Report's DeveloperName was saved as AccountsWithUnifiedEvents
:
public class BatchUpdateUnifiedEvents implements Database.Batchable<sObject> {
public Database.QueryLocator start(Database.BatchableContext bc) {
return Database.getQueryLocator([SELECT Id, DeveloperName FROM Report WHERE DeveloperName = 'AccountsWithUnifiedEvents']);
}
public void execute(Database.BatchableContext bc, List<Report> rpts) {
Map<Id, Account> accounts = new Map<Id, Account>();
for (Report rpt : rpts) {
Reports.ReportMetadata mdt = Reports.ReportManager.describeReport(rpt.Id).getReportMetadata();
mdt.setHasDetailRows(true);
Reports.ReportResults results = Reports.ReportManager.runReport(rpt.Id, mdt, true);
if (rpt != null) {
for (Reports.ReportFact fact : results.getFactMap().values()) {
Reports.ReportFactWithDetails factDetails = (Reports.ReportFactWithDetails)fact;
for (Reports.ReportDetailRow detail : factDetails.getRows()) {
String accountId;
DateTime eventAt;
for (Reports.ReportDataCell cell : detail.getDataCells()) {
if (cell.getValue() instanceOf String && String.valueOf(cell.getValue()).length() == 18 && String.valueOf(cell.getValue()).startsWith('001')) {
accountId = String.valueOf(cell.getValue());
} else if (cell.getValue() instanceOf DateTime) {
eventAt = DateTime.valueOf(cell.getValue());
}
}
if (eventAt != null && String.isNotBlank(accountId) && !accounts.containsKey(accountId)) {
accounts.put(accountId, new Account(
Id = accountId,
LatestScheduledUnifiedEvent__c = eventAt
));
}
}
}
}
}
if (!accounts.isEmpty()) {
update accounts.values();
}
}
}