[英]Salesforce.com Trigger: Copy Contact Lead Source to Opportunity
I'm stuck on the syntax (and maybe the logic) of writing this Salesforce.com Trigger. 我停留在编写此Salesforce.com触发器的语法(也许是逻辑)上。 I want the trigger to check to see if a primary contact is listed in the ContactRoles on the Opportunity.
我希望触发器检查机会列表上的ContactRoles中是否列出了主要联系人。 If there's a primary listed, I need to lookup the LeadSource from the corresponding contact and insert that value in the the Lead Source of the Opportunity.
如果列出了主要联系人,则需要从相应的联系人中查找LeadSource并将该值插入商机的Lead Source中。
Any hints or tips are greatly appreciated! 任何提示或技巧将不胜感激!
trigger UpdateContactLeadSource on Opportunity (after insert, after update) {
//Declare the Lead Source Variable which will hold the contact's lead source
string leadsource;
// See if there is a primary contact listed on the Opportunity
for (Opportunity o : Trigger.new) {
OpportunityContactRole[] contactRoleArray =
[select ContactID, isPrimary from OpportunityContactRole where OpportunityId = :o.id ORDER BY isPrimary DESC, createdDate];
// If the there is a primary contact, then...
if (contactRoleArray.size() > 0) {
// Lookup ContactID on the Contacts table to find the lead source
for (Contact contact : [SELECT LeadSource FROM Contact WHERE Contact.Id = :OpportunityContactRole.ContactId LIMIT 1])
// Store the actual lead source in the leadsource variable
{ Contact.LeadSource = leadsource;}
update Opportunity.LeadSource = leadsource; }
}
}
There are couple of seriously bad things in your code. 您的代码中有几处非常糟糕的事情。 Hope you won't feel offended, it's a nice requirement and a learning opportunity too...
希望您不会感到冒犯,这是一个很好的要求,也是一个学习的机会...
after insert
doesn't make any sense here. after insert
在这里没有任何意义。 By very definition if you've just finished inserting this Opportunity it won't have any contact roles in it yet.* after update
is OK-ish. after update
可以了。 before update
would be nicer because you'd just fill in the value and you'll get the save to database for free. before update
会更好,因为您只需填写该值,即可免费将保存到数据库。 LeadSource
on Opportunity would be null? LeadSource
为null时才填写它? ORDER BY
, LIMIT 1
etc - Salesforce will protect you and allow only 1 contact to be primary. ORDER BY
, LIMIT 1
等-Salesforce将保护您,并且只允许1个主要联系人。 Even if you'd want to load them with such mistake with Data Loader. TL;DR TL; DR
trigger fillLeadSource on Opportunity (before update) {
/* I'm assuming you want to fill LeadSource in only if it was blank.
If that's not the case - just delete this first part of code and in the query instead of ":oppsToFill" bind to ":trigger.new" or
":trigger.newMap.keyset()".
(I know they look weird but you can do it, bind objects/collections in queries that expect Ids / collections of Ids)
*/
Set<Id> oppsToFill = new Set<Id>();
for(Opportunity o : trigger.new){
if(o.LeadSource == null) {
oppsToFill.add(o.Id);
}
}
// Now we'll select all possible contacts wasting only 1 query.
if(!oppsToFill.isEmpty()){
List<OpportunityContactRole> roles = [SELECT OpportunityId, Contact.Name, Contact.LeadSource
FROM OpportunityContactRole
WHERE isPrimary = true AND Contact.LeadSource != null AND OpportunityId IN :oppsToFill];
if(!roles.isEmpty()){
for(OpportunityContactRole ocr : roles){
Opportunity oppToBeFilled = trigger.newMap.get(ocr.OpportunityId);
System.debug('Changing lead source on ' + oppToBeFilled.Name + ' from ' + oppToBeFilled.LeadSource + ' to ' + ocr.Contact.LeadSource + ' (thx to ' + ocr.Contact.Name + ' being the Primary Contact).');
oppToBeFilled.LeadSource = ocr.Contact.LeadSource;
}
}
}
// That's it. If there was a primary contact with Lead source, data will be copied over.
// If there was no primary contact or he didn't have the source filled in - tough luck, we did our best.
// Since it's before update, you get save to database for free.
}
EDIT to answer question from comment re #3 编辑以回答评论#3中的问题
You'd need similar but not identical code in a new trigger (in this case it doesn't matter much whether it's before
or after
- we need to explicitly update Opportunities). 您需要在新触发器中使用相似但不相同的代码(在这种情况下,
before
还是after
都没关系-我们需要显式更新机会)。 It's a bit worse here also because the fields you want to look at aren't directly available - you have access to OpportunityId, ContactId but not Contact.LeadSource. 这里的情况更糟,因为您要查看的字段不是直接可用的-您可以访问OpportunityId,ContactId,但不能访问Contact.LeadSource。 Something like this should do the trick:
这样的事情应该可以解决问题:
trigger ContactRoleRollup on OpportunityContactRole(after insert, after update){
Map<Id,Id> oppToContactMap = new Map<Id, Id>();
for(OpportunityContactRole ocr : trigger.new){
if(ocr.isPrimary){
oppToContactMap.put(ocr.OpportunityId, ocr.ContactId);
}
}
if(!oppToContactMap.isEmpty()){
List<Opportunity> oppsToUpdate = [SELECT Id FROM Opportunity WHERE LeadSource = null AND Id IN :oppToContactMap.keyset()];
Map<Id, Contact> contacts = [SELECT Id, LeadSource FROM Contact WHERE LeadSource != null AND Id IN :oppToContactMap.values()];
for(Opportunity o : oppsToUpdate){
Id contactId = oppToContactMap.get(o.Id);
Contact c = contacts.get(contactId);
if(c != null){
o.LeadSource = c.LeadSource;
}
}
update oppsToUpdate;
}
}
It gets interesting here because this update will fire our old trigger on opportunities. 之所以在这里变得有趣,是因为此更新将激发我们的旧机会。 It should be fine if you have left my "skip if leadSource is filled in" but still you might want to explore 2 things:
如果您离开了我的“如果leadSource已填写,则跳过”应该没问题,但是您仍然可能想探索两件事:
Theoretically you could just "touch" the Opportunities without changing anything (treat the old trigger as a benefit, not unwanted side effect in this case). 从理论上讲,您可以“触摸”机会而无需进行任何更改(将旧触发器作为一种好处,在这种情况下可以避免不必要的副作用)。 For me it'd look a bit too magical but if it's well commented what's going on here it might lead to less code, less logic duplication, less unit tests... It will work as long as it's
after
trigger so the query for contact roles we've just modified will see new values. 对我来说,它看起来有些不可思议,但是如果它很好地说明了这里发生的事情,则可能会导致更少的代码,更少的逻辑重复,更少的单元测试...只要
after
触发after
它就可以工作,因此联系查询我们刚刚修改的角色将看到新的价值。 It'd have to look like that 它必须看起来像
trigger ContactRoleRollup on OpportunityContactRole(after insert, after update){ Set<Id> oppIds = new Set<Id>(); for(OpportunityContactRole ocr : trigger.new){ if(ocr.isPrimary){ oppIds.add(ocr.OpportunityId); } } if(!oppIds.isEmpty()){ update [SELECT Id FROM Opportunity WHERE LeadSource = null AND Id IN :oppIds]; // That's it. Call update directly on returned list without changing anything, let the other trigger worry about the logic } }
eyescream's opportunity trigger is most helpful and is solving a problem for me. 眼霜的机会触发机制最有帮助,并且正在为我解决问题。 It's worth pointing out, though, that the OpportunityContactRole triggers he hypothesises are unfortunately not yet supported by SFDC.
但是,值得指出的是,不幸的是,SFDC尚未支持他的假设的OpportunityContactRole触发器。 As this idea ( https://success.salesforce.com/ideaview?id=08730000000BrdvAAC ) notes, triggers on OCR are not possible at this time.
正如这个想法( https://success.salesforce.com/ideaview?id=08730000000BrdvAAC )指出的那样,此时无法在OCR上触发。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.