Apex 检索为客户的所有联系人角色分配给当前用户的任务
Apex Retrieve Tasks Assigned to Current User For All Contact Roles on an Account
我有一个 Apex class,其目的是检索和删除用户刚刚调用的联系人角色(与帐户相关)的逾期任务。我需要修改它,以便它查询分配给帐户上所有联系人角色的用户的所有逾期任务,但我正在努力获得正确的查询。
这里是有问题的部分代码,我认为最相关的部分:
/***************************************************
Brief Description: Deletes overdue Tasks or Events.
****************************************************/
public class DSDenali_DeleteOverDueActivities {
private static List<Task> followUpTasksToDelete = new List<Task>();
private static List<Event> followUpEventsToDelete = new List<Event>();
private static Map<Id, Set<String>> ownerOfActivities = new Map<Id, Set<String>>();
@InvocableMethod (label = 'DialSource Denali Delete Overdue Activities')
public static void gatherData(List<Data> requests)
{
Map<Id, String> results = new Map<Id, String>();
for (Data request : requests)
results.put(request.contactRoleID, request.assignedTo);
for (Id key : results.keySet())
{
Set<String> assignedToValues = parseAssignedTo(results.get(key));
System.debug('assignedToValues: ' + assignedToValues);
ownerOfActivities.put(key, assignedToValues);
System.debug(ownerOfActivities);
}
queryAndFilterData();
deleteOverdueActivities();
}
//Query for the Tasks and Events and filter the ones to delete
private static void queryAndFilterData()
{
List<Contact_Role__c> contactRoles = [SELECT Id,
(SELECT Id, Owner.UserRole.Name, OwnerId FROM Tasks WHERE status != 'Completed' AND ActivityDate <= :system.TODAY() AND Type__c = 'Outbound Call'),
(SELECT Id, Owner.UserRole.Name, OwnerId, Description FROM Events WHERE EndDateTime <= :system.NOW())
FROM Contact_Role__c
WHERE Id IN :ownerOfActivities.keySet()];
for (Contact_Role__c contactRole : contactRoles)
{
for (Task currentTask : contactRole.Tasks)
{
if (ownerOfActivities.get(contactRole.Id).contains(currentTask.OwnerId))
{
if (currentTask.OwnerId != '0050B000006ET37' && currentTask.Owner.UserRole != NULL && Pattern.matches('.*Altair.*', currentTask.Owner.UserRole.Name))
followUpTasksToDelete.add(currentTask);
else if (currentTask.OwnerId == '0050B000006ET37')
followUpTasksToDelete.add(currentTask);
else
continue;
}
else if (ownerOfActivities.get(contactRole.Id).contains('ALL'))
{
if (currentTask.Owner.UserRole != NULL && Pattern.matches('.*Altair.*', currentTask.Owner.UserRole.Name))
followUpTasksToDelete.add(currentTask);
else
continue;
}
}
for (Event currentEvent : contactRole.Events)
{
if (ownerOfActivities.get(contactRole.Id).contains(currentEvent.OwnerId) && currentEvent.Description == NULL)
{
if (currentEvent.OwnerId != '0050B000006ET37' && currentEvent.Owner.UserRole != NULL && Pattern.matches('.*Altair.*', currentEvent.Owner.UserRole.Name))
followUpEventsToDelete.add(currentEvent);
else if (currentEvent.OwnerId == '0050B000006ET37')
followUpEventsToDelete.add(currentEvent);
else
continue;
}
else if (ownerOfActivities.get(contactRole.Id).contains('ALL') && currentEvent.Description == NULL)
{
if (currentEvent.Owner.UserRole != NULL && Pattern.matches('.*Altair.*', currentEvent.Owner.UserRole.Name))
followUpEventsToDelete.add(currentEvent);
else
continue;
}
}
}
}
//Delete overdue Events/Tasks
private static void deleteOverdueActivities()
{
try{
delete followUpTasksToDelete;
}
catch (DmlException e){
System.debug('The following error occured (DSDenali_DeleteOverDueActivities): ' + e);
}
try{
delete followUpEventsToDelete;
}
catch (DmlException e){
System.debug('The following error occured (DSDenali_DeleteOverDueActivities): ' + e);
}
}
//Parse the CSVs of possible owners
private static Set<String> parseAssignedTo(String assignedTo)
{
Set<String> assignedToValues = new Set<String>();
assignedToValues.addAll(assignedTo.deleteWhitespace().split(','));
return assignedToValues;
}
public class Data
{
@InvocableVariable (required=true)
public String assignedTo;
@InvocableVariable (required=false)
public Id contactRoleID;
}
}
(在 OP post 编辑了更多代码并要求进行代码审查后更新)
这不是糟糕的代码,可以使用一些注释。考虑 post 在 https://codereview.stackexchange.com/ (although not many SF-related posts end up there) or on https://salesforce.stackexchange.com
中使用它
gatherData()
您的输入变量(经过一些解析后)是 Map<Id, Set<String>>
,其中键是联系人角色的 ID。用户(所有者)的那组字符串有点误导。乍一看,您会立即问自己为什么不能 Set<Id>
。只有在代码的深处,您才能看到显然 "All" 是允许的值之一。这……不太好。我很想在这里制作两种方法,一种采用合法的 Map<Id, Set<Id>>
,另一种采用简单的 Set<Id>
,如果你知道你正在有效地跳过第二个参数的话。
queryAndFilterData()
你只有一个查询,而且不在循环中,非常好。 我的技巧(编辑之前的)对你不起作用(你实际上没有 Account__c
或者输入中的字段名为 anywere,你只有记录 id。如果你想检查/删除该帐户下角色的所有任务,最干净的方法可能是使用两个查询
// 1st the helper to collect all accounts...
Set<Id> allAccounts = new Map<Id, Account>([SELECT Id
FROM Account
WHERE Id IN (SELECT Account__c FROM Contact_Role__c WHERE Id IN :ownerOfActivities.keyset()]).keyset();
// then the outline of the main query would be bit like this
SELECT Id,
(SELECT ... FROM Tasks WHERE ...),
(SELECT ... FROM Events WHERE ...)
FROM Contact_Role__c
WHERE Account__c IN :allAccounts
AND ...
我会检查有多少过滤逻辑可以推送到查询本身,而不是手动检查每个returned 行。我的意思是看看那个:
假设我们走简单的路线(忽略 "All" 用户的概念),假设您有另一个 Set<Id> allUsers;
变量(由所有数据片段中提到的所有 ID 组成)
Tasks 的查询可以变得像
一样简单
(SELECT Id
FROM Tasks
WHERE Status != 'Completed'
AND ActivityDate <= TODAY
AND Type__c = 'Outbound Call'
AND OwnerId IN :allUsers
AND (OwnerId = '0050B000006ET37' OR Owner.UserRole.Name LIKE '%.Altair.%')
)
你仍然需要遍历它们来验证是否真的可以删除每个(仅仅匹配所有用户是不够的,它还必须检查这个特定的用户是否可以 Contact_Role__c ,对吗?)但是类似的东西应该 return 更少的行并且没有更多的正则表达式匹配......应该更快一些。
我不会为那个特殊所有者的 id 设置一个魔法变量。理想情况下,会有其他描述此特殊用户的内容(角色?个人资料?用户记录上的自定义字段?个人资料中 "Author Apex" 的权限?)。至少将它移动到文件顶部的 helper Id
变量,这样它就不会被复制粘贴到各处。并询问您的业务用户,如果那个人(默认任务所有者?某个集成帐户?)离开公司会发生什么,因为便便会严重撞击螺旋桨。
如果您对这个版本的查询感到满意,"ALL" 版本会变得更简单吗?没有 "all users",没有 "magic id" & 工作完成了吗?
(SELECT Id
FROM Tasks
WHERE Status != 'Completed'
AND ActivityDate <= TODAY
AND Type__c = 'Outbound Call'
Owner.UserRole.Name LIKE '%.Altair.%'
)
不要相信互联网上随机出现的不了解您的业务流程的人,但是,是的,还有一些改进的余地。彻底测试一下:)
deleteOverdueActivities()
这不是很好的 try-catch 模式。您只是在调试日志中提出它,但默默地吞下了错误。让它失败(让错误冒泡给用户)或者做一些适当的错误处理,比如插入一些东西到 helper Log__c 对象或者发送电子邮件/聊天 post 给管理员...
parseAssignedTo()
不错。我希望当您将 null 传递给它时它会可怕地爆炸。通过在最后几行中标记所需的变量,您可以免受它的影响,但我认为此注释仅适用于 Flows。从其他 Apex 代码调用它的保护不够。
我有一个 Apex class,其目的是检索和删除用户刚刚调用的联系人角色(与帐户相关)的逾期任务。我需要修改它,以便它查询分配给帐户上所有联系人角色的用户的所有逾期任务,但我正在努力获得正确的查询。
这里是有问题的部分代码,我认为最相关的部分:
/***************************************************
Brief Description: Deletes overdue Tasks or Events.
****************************************************/
public class DSDenali_DeleteOverDueActivities {
private static List<Task> followUpTasksToDelete = new List<Task>();
private static List<Event> followUpEventsToDelete = new List<Event>();
private static Map<Id, Set<String>> ownerOfActivities = new Map<Id, Set<String>>();
@InvocableMethod (label = 'DialSource Denali Delete Overdue Activities')
public static void gatherData(List<Data> requests)
{
Map<Id, String> results = new Map<Id, String>();
for (Data request : requests)
results.put(request.contactRoleID, request.assignedTo);
for (Id key : results.keySet())
{
Set<String> assignedToValues = parseAssignedTo(results.get(key));
System.debug('assignedToValues: ' + assignedToValues);
ownerOfActivities.put(key, assignedToValues);
System.debug(ownerOfActivities);
}
queryAndFilterData();
deleteOverdueActivities();
}
//Query for the Tasks and Events and filter the ones to delete
private static void queryAndFilterData()
{
List<Contact_Role__c> contactRoles = [SELECT Id,
(SELECT Id, Owner.UserRole.Name, OwnerId FROM Tasks WHERE status != 'Completed' AND ActivityDate <= :system.TODAY() AND Type__c = 'Outbound Call'),
(SELECT Id, Owner.UserRole.Name, OwnerId, Description FROM Events WHERE EndDateTime <= :system.NOW())
FROM Contact_Role__c
WHERE Id IN :ownerOfActivities.keySet()];
for (Contact_Role__c contactRole : contactRoles)
{
for (Task currentTask : contactRole.Tasks)
{
if (ownerOfActivities.get(contactRole.Id).contains(currentTask.OwnerId))
{
if (currentTask.OwnerId != '0050B000006ET37' && currentTask.Owner.UserRole != NULL && Pattern.matches('.*Altair.*', currentTask.Owner.UserRole.Name))
followUpTasksToDelete.add(currentTask);
else if (currentTask.OwnerId == '0050B000006ET37')
followUpTasksToDelete.add(currentTask);
else
continue;
}
else if (ownerOfActivities.get(contactRole.Id).contains('ALL'))
{
if (currentTask.Owner.UserRole != NULL && Pattern.matches('.*Altair.*', currentTask.Owner.UserRole.Name))
followUpTasksToDelete.add(currentTask);
else
continue;
}
}
for (Event currentEvent : contactRole.Events)
{
if (ownerOfActivities.get(contactRole.Id).contains(currentEvent.OwnerId) && currentEvent.Description == NULL)
{
if (currentEvent.OwnerId != '0050B000006ET37' && currentEvent.Owner.UserRole != NULL && Pattern.matches('.*Altair.*', currentEvent.Owner.UserRole.Name))
followUpEventsToDelete.add(currentEvent);
else if (currentEvent.OwnerId == '0050B000006ET37')
followUpEventsToDelete.add(currentEvent);
else
continue;
}
else if (ownerOfActivities.get(contactRole.Id).contains('ALL') && currentEvent.Description == NULL)
{
if (currentEvent.Owner.UserRole != NULL && Pattern.matches('.*Altair.*', currentEvent.Owner.UserRole.Name))
followUpEventsToDelete.add(currentEvent);
else
continue;
}
}
}
}
//Delete overdue Events/Tasks
private static void deleteOverdueActivities()
{
try{
delete followUpTasksToDelete;
}
catch (DmlException e){
System.debug('The following error occured (DSDenali_DeleteOverDueActivities): ' + e);
}
try{
delete followUpEventsToDelete;
}
catch (DmlException e){
System.debug('The following error occured (DSDenali_DeleteOverDueActivities): ' + e);
}
}
//Parse the CSVs of possible owners
private static Set<String> parseAssignedTo(String assignedTo)
{
Set<String> assignedToValues = new Set<String>();
assignedToValues.addAll(assignedTo.deleteWhitespace().split(','));
return assignedToValues;
}
public class Data
{
@InvocableVariable (required=true)
public String assignedTo;
@InvocableVariable (required=false)
public Id contactRoleID;
}
}
(在 OP post 编辑了更多代码并要求进行代码审查后更新)
这不是糟糕的代码,可以使用一些注释。考虑 post 在 https://codereview.stackexchange.com/ (although not many SF-related posts end up there) or on https://salesforce.stackexchange.com
中使用它gatherData()
您的输入变量(经过一些解析后)是 Map<Id, Set<String>>
,其中键是联系人角色的 ID。用户(所有者)的那组字符串有点误导。乍一看,您会立即问自己为什么不能 Set<Id>
。只有在代码的深处,您才能看到显然 "All" 是允许的值之一。这……不太好。我很想在这里制作两种方法,一种采用合法的 Map<Id, Set<Id>>
,另一种采用简单的 Set<Id>
,如果你知道你正在有效地跳过第二个参数的话。
queryAndFilterData()
你只有一个查询,而且不在循环中,非常好。 我的技巧(编辑之前的)对你不起作用(你实际上没有 Account__c
或者输入中的字段名为 anywere,你只有记录 id。如果你想检查/删除该帐户下角色的所有任务,最干净的方法可能是使用两个查询
// 1st the helper to collect all accounts...
Set<Id> allAccounts = new Map<Id, Account>([SELECT Id
FROM Account
WHERE Id IN (SELECT Account__c FROM Contact_Role__c WHERE Id IN :ownerOfActivities.keyset()]).keyset();
// then the outline of the main query would be bit like this
SELECT Id,
(SELECT ... FROM Tasks WHERE ...),
(SELECT ... FROM Events WHERE ...)
FROM Contact_Role__c
WHERE Account__c IN :allAccounts
AND ...
我会检查有多少过滤逻辑可以推送到查询本身,而不是手动检查每个returned 行。我的意思是看看那个:
假设我们走简单的路线(忽略 "All" 用户的概念),假设您有另一个 Set<Id> allUsers;
变量(由所有数据片段中提到的所有 ID 组成)
Tasks 的查询可以变得像
一样简单(SELECT Id
FROM Tasks
WHERE Status != 'Completed'
AND ActivityDate <= TODAY
AND Type__c = 'Outbound Call'
AND OwnerId IN :allUsers
AND (OwnerId = '0050B000006ET37' OR Owner.UserRole.Name LIKE '%.Altair.%')
)
你仍然需要遍历它们来验证是否真的可以删除每个(仅仅匹配所有用户是不够的,它还必须检查这个特定的用户是否可以 Contact_Role__c ,对吗?)但是类似的东西应该 return 更少的行并且没有更多的正则表达式匹配......应该更快一些。
我不会为那个特殊所有者的 id 设置一个魔法变量。理想情况下,会有其他描述此特殊用户的内容(角色?个人资料?用户记录上的自定义字段?个人资料中 "Author Apex" 的权限?)。至少将它移动到文件顶部的 helper Id
变量,这样它就不会被复制粘贴到各处。并询问您的业务用户,如果那个人(默认任务所有者?某个集成帐户?)离开公司会发生什么,因为便便会严重撞击螺旋桨。
如果您对这个版本的查询感到满意,"ALL" 版本会变得更简单吗?没有 "all users",没有 "magic id" & 工作完成了吗?
(SELECT Id
FROM Tasks
WHERE Status != 'Completed'
AND ActivityDate <= TODAY
AND Type__c = 'Outbound Call'
Owner.UserRole.Name LIKE '%.Altair.%'
)
不要相信互联网上随机出现的不了解您的业务流程的人,但是,是的,还有一些改进的余地。彻底测试一下:)
deleteOverdueActivities()
这不是很好的 try-catch 模式。您只是在调试日志中提出它,但默默地吞下了错误。让它失败(让错误冒泡给用户)或者做一些适当的错误处理,比如插入一些东西到 helper Log__c 对象或者发送电子邮件/聊天 post 给管理员...
parseAssignedTo()
不错。我希望当您将 null 传递给它时它会可怕地爆炸。通过在最后几行中标记所需的变量,您可以免受它的影响,但我认为此注释仅适用于 Flows。从其他 Apex 代码调用它的保护不够。