You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LeadConvert的Apex负载字段缺失原因排查及修改方法

Lead Convert触发的Apex Webhook负载字段缺失问题

问题描述

针对Lead的Convert操作编写了after update触发器,调用Webhook发送JSON负载。开发环境中负载包含完整的Lead字段(含Id),但在第三方Salesforce账户中,负载仅保留少量字段,大量字段(包括Id)缺失。

触发器原代码:

trigger WebhookSenderTriggerLeadConvert on Lead (after update) {
    if (Trigger.new.size() == 1) {
        if (Trigger.old[0].isConverted == false && Trigger.new[0].isConverted == true) {
            if (Trigger.new[0].ConvertedAccountId != null) {
                String url = 'https://mydomain.io';
                String content = WebhookSender.jsonContent(Trigger.new, Trigger.old);
                WebhookSender.callout(url, content);
            }
        }
    }
}

WebhookSender原代码:

public class WebhookSender {
    public static String jsonContent(List<Object> triggerNew, List<Object> triggerOld) {
        String newObjects = '[]';
        if (triggerNew != null) {
            newObjects = JSON.serialize(triggerNew);
        }

        String oldObjects = '[]';
        if (triggerOld != null) {
            oldObjects = JSON.serialize(triggerOld);
        }
        String userId = JSON.serialize(UserInfo.getUserId());

        String content = '{"new": ' + newObjects + ', "old": ' + oldObjects + ', "userId": ' + userId + '}';
        return content;
    }

    @future(callout=true)
    public static void callout(String url, String content) {
        Http h = new Http();

        HttpRequest req = new HttpRequest();
        req.setEndpoint(url);
        req.setMethod('POST');
        req.setHeader('Content-Type', 'application/json');
        req.setHeader('Authorization', 'someKey');
        req.setBody(content);

        if (!Test.isRunningTest()) {h.send(req);}
    }

    public static Map<String, Object> ParseRequest(RestRequest req) {
        String body = req.requestBody.toString();
        Map<String, Object> data = (Map<String, Object>) JSON.deserializeUntyped(body);
        return data;
    }
}

原因分析

  • 触发器上下文字段限制:Salesforce触发器的Trigger.new和Trigger.old仅包含实际被修改的字段及少量系统字段。Lead Convert操作中,第三方环境仅标记IsConverted、ConvertedAccountId等核心转换字段为修改状态,因此上下文变量仅携带这些字段,不会包含未修改的其他字段。
  • 直接序列化上下文的局限性:JSON序列化Trigger.new/old时,只会序列化上下文变量中存在的字段,无法自动补充未被修改的字段内容。

解决方案

通过显式查询获取完整的Lead记录(新旧状态),替代直接使用触发器上下文变量进行序列化。

方案1:仅获取转换后的完整新记录

如果不需要转换前的完整旧记录,修改原触发器即可:

trigger WebhookSenderTriggerLeadConvert on Lead (after update) {
    if (Trigger.new.size() == 1) {
        Lead oldLead = Trigger.old[0];
        Lead newLead = Trigger.new[0];
        if (!oldLead.isConverted && newLead.isConverted && newLead.ConvertedAccountId != null) {
            // 显式查询转换后的完整Lead记录,列出所有需要的字段
            List<Lead> fullNewLeads = [
                SELECT Id, Name, Email, Phone, Company, ConvertedAccountId, ConvertedContactId, ConvertedOpportunityId, IsConverted
                FROM Lead WHERE Id = :newLead.Id
            ];
            // 使用Trigger.old的Id查询记录(注意:此时数据库中已为转换后状态)
            List<Lead> fullOldLeads = [
                SELECT Id, Name, Email, Phone, Company
                FROM Lead WHERE Id = :oldLead.Id
            ];
            
            String url = 'https://mydomain.io';
            String content = WebhookSender.jsonContent(fullNewLeads, fullOldLeads);
            WebhookSender.callout(url, content);
        }
    }
}

方案2:同时获取转换前后的完整记录

如果需要转换前的完整旧记录,需通过before update触发器缓存旧状态:

  1. 新建缓存类:
public class LeadConvertCache {
    public static List<Lead> oldFullLeads;
}
  1. 新增before update触发器:
trigger LeadConvertBeforeTrigger on Lead (before update) {
    if (Trigger.new.size() == 1) {
        Lead oldLead = Trigger.old[0];
        if (!oldLead.isConverted && Trigger.new[0].isConverted) {
            // 查询并缓存转换前的完整Lead记录
            LeadConvertCache.oldFullLeads = [
                SELECT Id, Name, Email, Phone, Company
                FROM Lead WHERE Id = :oldLead.Id
            ];
        }
    }
}
  1. 修改原after update触发器:
trigger WebhookSenderTriggerLeadConvert on Lead (after update) {
    if (Trigger.new.size() == 1) {
        Lead newLead = Trigger.new[0];
        if (newLead.isConverted && newLead.ConvertedAccountId != null && LeadConvertCache.oldFullLeads != null) {
            // 查询转换后的完整Lead记录
            List<Lead> fullNewLeads = [
                SELECT Id, Name, Email, Phone, Company, ConvertedAccountId, ConvertedContactId, IsConverted
                FROM Lead WHERE Id = :newLead.Id
            ];
            
            String url = 'https://mydomain.io';
            String content = WebhookSender.jsonContent(fullNewLeads, LeadConvertCache.oldFullLeads);
            WebhookSender.callout(url, content);
        }
    }
}

注意事项

  • 必须明确列出需要查询的字段,避免使用SELECT *,这是Salesforce的最佳实践,能提升查询性能并避免字段权限问题。
  • 可将WebhookSender类的jsonContent方法参数类型改为List<SObject>,使其更通用,原List<Object>也可兼容。

内容的提问来源于stack exchange,提问作者Jason

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 07:00:58