简体   繁体   English

Salesforce.com触发条件:将联系人线索源复制到机会

[英]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... 希望您不会感到冒犯,这是一个很好的要求,也是一个学习的机会...

  1. 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.* 从定义上来说,如果您刚刚完成插入此机会,则其中将没有任何联系人角色。*
  2. 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会更好,因为您只需填写该值,即可免费将保存到数据库。
  3. You might have to replicate this logic to similar trigger on OpportunityContactRole I think? 您可能需要将此逻辑复制到OpportunityContactRole上的类似触发器上,我认为呢? Instead of duplicating code - use some class that could be called from both places? 而不是复制代码-使用可以在两个地方调用的类?
  4. I'm assuming you'd want to fill it in only if LeadSource on Opportunity would be null? 我假设您仅在机会上的LeadSource为null时才填写它?
  5. You have selects in a loop, that's a very bad practice ;) Your trigger isn't "bulk", it might fail when somebody updates 10 opportunities in one transaction (for example by using Data Loader) because we have a limit of max 20 queries in triggers. 您在一个循环中进行选择,这是一个非常糟糕的做法;)您的触发器不是“批量”的,当有人在一次交易中更新10个机会(例如使用Data Loader)时,触发器可能会失败,因为我们的上限为20触发器中的查询。
  6. You don't need ORDER BY , LIMIT 1 etc - Salesforce will protect you and allow only 1 contact to be primary. 您不需要ORDER BYLIMIT 1等-Salesforce将保护您,并且只允许1个主要联系人。 Even if you'd want to load them with such mistake with Data Loader. 即使您想使用Data Loader进行此类错误加载。
  7. It seems like you'd benefit from reading about how relationships work in Salesforce. 似乎您将从阅读有关Salesforce中的关系如何工作中受益。 The "dot notation" and subqueries look a bit weird compared to normal SQL languages but you can use them to greatly simplify your code. 与普通的SQL语言相比,“点符号”和子查询看起来有些怪异,但是您可以使用它们极大地简化代码。 Will help if you did some object oriented programming in the past. 如果您过去做过一些面向对象的编程,将会有所帮助。 Here's some guide and here are official docs 这是一些指南 ,这是官方文档

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.
}

  • Fine print to #1, for advanced scenarios ;) You could have Contact Roles right after saving if you have another after insert trigger that'd be adding them somewhere... But that'd be very messy (depending on which trigger fired first I'd say you'd get a really interesting random behaviour, good luck debugging). 精细打印到#1(适用于高级方案);)如果在插入触发器后又有一个触发器将添加到某个位置,则可以在保存后立即使用联系人角色……但这会很混乱(取决于首先触发哪个触发器)我想您会得到一个非常有趣的随机行为,祝您好运调试)。 If you do have more than one trigger on given object with same firing keyword in it it's advised to have only 1 trigger and be in full control of the order of actions. 如果在给定对象上使用相同的触发关键字确实有多个触发器,则建议仅使用一个触发器并完全控制操作顺序。 See http://www.embracingthecloud.com/2010/07/08/ASimpleTriggerTemplateForSalesforce.aspx for more. 有关更多信息,请参见http://www.embracingthecloud.com/2010/07/08/ASimpleTriggerTemplateForSalesforce.aspx

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已填写,则跳过”应该没问题,但是您仍然可能想探索两件事:

  • Use some helper static flag in a class , call it "skipTriggerOnOpps" you'd be setting this flag in trigger on OpportunityContactRoles and wrapping up whole code of Opportunity trigger in it so it won't execute if we already took care of lead source sync. 在类中使用一些帮助程序静态标志 ,将其称为“ skipTriggerOnOpps”,您将在OpportunityContactRoles的触发器中设置此标志,并在其中包装整个Opportunity触发器的代码,因此如果我们已经处理了潜在客户源同步,它将不会执行。
  • 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.

相关问题 Salesforce.com触发器-需要主要联系人以节省机会 - Salesforce.com Trigger- Require primary contact to save opportunity 批量删除前触发器(太多Soql语句)Salesforce.com - Bulk Before Delete Trigger (Too Many Soql Statements) Salesforce.com SalesForce.com-报告批准流程的解决方法 - SalesForce.com - Reporting on approval process workarounds Apex-Salesforce.com-我需要编写APEX类来测试我的工作触发器,需要帮助-聊天-监控特定关键字 - Apex - Salesforce.com - I need help writing an APEX class to test my working trigger - Chatter - Monitor specific keywords Salesforce-在相关机会上将DateTime值从事件复制到日期字段 - Salesforce - Copy DateTime value from Event to Date field on related Opportunity 创建触发器,每当Salesforce中存在新机会时,都会创建一个新的机会所有者 - Creating a Trigger that will create a new Opportunity Owner every time a there is a new Opportunity in Salesforce Salesforce.com:UNABLE_TO_LOCK_ROW,无法获得对此记录的排他访问 - Salesforce.com: UNABLE_TO_LOCK_ROW, unable to obtain exclusive access to this record 在Salesforce中的用户触发器中更新联系人电子邮件 - Updating contact email in user trigger in Salesforce Salesforce销售线索触发器CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY - Salesforce Lead Trigger CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY 在Salesforce中更改机会对象的所有者 - Changing the owner of Opportunity object in Salesforce
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM