关于 platform-custom-field-generate
用于生成和校验 Salesforce CustomField 元数据 XML 的技能,面向需要部署字段的用户。重点处理关系字段、汇总字段、选项列表等容易导致部署错误的约束。
主要功能
- 01生成 CustomField 元数据 XML
- 02校验字段类型要求
- 03应用 Master-Detail 限制
- 04处理 Roll-Up Summary 规则
- 05支持高级选项列表配置
适用场景
- 01创建可部署的自定义字段元数据
- 02构建 Master-Detail 关系
- 03定义汇总计算字段
- 04配置内联或引用选项列表
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ forcedotcom/ sf-skills --skill platform-custom-field-generate安装后在 Claude Code 中输入/platform-custom-field-generate确认已加载。
附带文件references/advanced-picklists.md
详细介绍
Salesforce 自定义字段生成器和验证器
概述
生成并验证 Salesforce CustomField 元数据 XML,并对失败率最高的类型——汇总摘要和主从关系——进行特殊处理。Agent 必须在输出 XML 前验证以下约束,以避免 Metadata API 部署错误。
1. 通用必需属性
每个生成的字段都必须包含以下标签:
| 属性 | 要求 | 说明 |
|---|---|---|
<fullName> | 必需 | 仅限字段名称:根据 <label> 生成——将每个单词首字母大写,将空格替换为 _,并追加 __c。必须以字母开头。例如,标签 Total Contract Value → Total_Contract_Value__c。此规则适用于字段名称。Picklist 值的 <fullName> 不同——必须完全按用户输入保留,包括空格,不加 __c(例如,Closed Won,而不是 Closed_Won)。参见 references/advanced-picklists.md(参考 §3)。 |
<label> | 必需 | UI 名称(标题式大小写) |
<description> | 始终包含 | 说明此字段存在的业务原因。 |
<inlineHelpText> | 始终包含 | 为最终用户提供可操作且超出标签信息的指导(例如,“输入含税的 USD 金额”,而不是“金额”)。 |
尽管 Metadata API 不强制要求 <description> 和 <inlineHelpText>,但它们仍是必需的——省略会导致元数据质量低下。
文件路径(SFDX 源格式): 将每个字段保存为 force-app/main/default/objects/<Object>/fields/<FieldName>__c.field-meta.xml,其中 <Object> 是对象的 API 名称(Account、Opportunity 或自定义对象 Inventory_Item__c)。XML 正确但路径错误时,Metadata API 将无法找到它。
外部 ID 配置
触发条件: 如果用户提及“集成”“导入数据”“外部系统 ID”或“来自 [System Name] 的唯一键”,则设置 <externalId>true</externalId>。
适用类型: Text、Number、Email
2. 精度、小数位数和长度规则
为确保部署成功,请遵循以下数学约束:
精度与小数位数规则
precision表示总位数;scale表示小数位数- 规则:
precision ≤ 18且scale ≤ precision - 计算: 小数点左侧的位数 =
precision - scale
“固定为 255”规则
TextArea:不要包含 <length>——API 会将其隐式固定为 255,并拒绝显式指定的值(“Can not specify 'length' for a CustomField of type TextArea”)。该字段只需要 <fullName>、<label> 和 <type>TextArea</type>。
可见行数
长文本/富文本字段和多选列表必须设置可见行数,以控制 UI 高度。
3. 字段数据类型
3.1 简单属性类型
| 类型 | <type> 值 | 必需属性 |
|---|---|---|
| 自动编号 | AutoNumber | displayFormat(必须包含 {0})、startingNumber |
| 复选框 | Checkbox | 将 defaultValue 默认设为 false |
| 日期 | Date | 无需指定精度/长度 |
| 日期/时间 | DateTime | 无需指定精度/长度 |
| 电子邮件 | Email | 内置格式验证 |
| 查找关系 | Lookup | referenceTo、relationshipName、deleteConstraint |
| 主从关系 | MasterDetail | referenceTo、relationshipName、relationshipOrder |
| 数字 | Number | precision、scale |
| 货币 | Currency | 默认精度:18,默认小数位数:2 |
| 百分比 | Percent | 默认精度:5,默认小数位数:2 |
| 电话 | Phone | 标准化电话号码格式 |
| 选项列表 | Picklist | valueSet,其中包含 valueSetDefinition(内联)或 valueSetName(引用)二者之一;restricted(参见下文“选项列表 restricted 默认值”;高级情况见 §3.4) |
| 文本 | Text | length(最多 255) |
| 文本区域 | TextArea | 无——不要包含 <length>;API 会将长度隐式固定为 255 |
| 长文本 | LongTextArea | length、visibleLines(默认值为 3) |
| 富文本 | Html | length、visibleLines(默认值为 25) |
| 时间 | Time | 仅存储时间(不含日期) |
| URL | Url | 验证协议和格式 |
3.2 计算类型和多值类型
| 类型 | <type> 值 | 必需属性 |
|---|---|---|
| 公式 | 结果类型(例如 Number) | formula、formulaTreatBlanksAs |
| 汇总汇总 | Summary | 完整要求见第 5 节 |
| 多选选项列表 | MultiselectPicklist | valueSet、visibleLines(默认值为 4) |
3.3 专用类型
| 类型 | <type> 值 | 必需属性 |
|---|---|---|
| 地理位置 | Location | scale、displayLocationInDecimal |
选项列表 restricted 默认值
除非用户明确说明选项列表应接受管理员定义列表以外的自定义值(例如“非受限”/“开放”),否则始终在 <valueSet> 中设置 <restricted>true</restricted>。受限选项集的总值数量上限为 1,000(包括启用和停用的值)。最简内联结构:
<valueSet>
<restricted>true</restricted>
<valueSetDefinition>
<sorted>false</sorted>
<value><fullName>Option_A</fullName><default>false</default><label>Option A</label></value>
</valueSetDefinition>
</valueSet>
3.4 高级选项列表
上面的内联 <valueSetDefinition> 是简单情况。以下所有内容的完整规则以及正确和错误示例,请参阅
references/advanced-picklists.md — 遇到任何
非简单选项列表时都应加载该文件。下文括号中的章节编号(例如“参考 §1”)指向该
参考文件,而非此技能。硬性规则:
- 选项集引用(参考 §1)。
<valueSet>只能包含<valueSetName>(引用)或<valueSetDefinition>(内联定义)之一——绝不能同时包含两者。引用时使用不带后缀的 开发者名称——标准选项集Industry、GlobalValueSetPriority_Levels,不要加__gvs或__c(__gvs后缀仅用于组织存储显示;Metadata API 使用不带后缀的名称)。基于选项集的 字段必须设置为<restricted>true</restricted>。创建选项集是platform-value-set-generate技能的职责;此技能只负责引用。 - 选项名称须保持原样(参考 §3)。 选项列表值的
<fullName>/<label>必须保留用户输入的 原文,包括空格(Closed Won,绝不要写成Closed_Won)。空格转换为_并添加__c的规则仅适用于 字段名称。 - 依赖选项列表(参考 §2)。 使用现代 API 38.0+ 格式:
<controllingField>+ 每组对应一个<valueSettings>(包含<controllingFieldValue>+<valueName>);绝不要使用旧版<picklist>/<picklistValues>/<controllingFieldValues>标签。控制字段和依赖字段都必须设置为<restricted>true</restricted>,即使请求中未提及。 - 增强选项属性(参考 §3)。
<value>条目还支持<color>(十六进制,带前导#)、<isActive>(false表示停用该选项)以及选项级别的<description>。 - 将选项列表限定到记录类型(参考 §5)。 按记录类型控制选项可见性,要在
RecordType 上设置(使用
<picklistValues>),而非字段上。RecordType 文件包含其自身的<fullName>(不带后缀的开发者名称)。首先判断对象是否需要 BusinessProcess: 只有 Opportunity / Lead / Case / Solution 需要;缺少<businessProcess>时将无法部署 (Required field is missing: businessProcess),即使只筛选了自定义选项列表也一样。对于这些对象,需要输出两个关联文件:businessProcesses/<Name>.businessProcess-meta.xml文件,以及<RecordType>中对应的<businessProcess><Name></businessProcess>(位于<active>之后、<picklistValues>之前;BP 文件中的<fullName>必须不带对象限定名)。自定义对象(*__c)和所有其他标准对象(Account、Contact……) 均不需要 BusinessProcess — 只输出 RecordType;不要自行添加。 范围限制: 仅限按记录类型控制选项值的可见性——不包括常规记录类型编写(紧凑布局、页面布局、品牌设置)。
4. 主从关系规则(重要)
主从字段有严格的属性限制,与查找字段不同。违反这些规则会导致部署失败。
主从字段上的禁止属性
主从字段上绝不能包含以下属性:
| 禁止的属性 | 原因 | 后果 |
|---|---|---|
<required> | 主从关系按设计始终为必填 | 部署错误 |
<deleteConstraint> | 主从关系始终级联删除 | 部署错误 |
<lookupFilter> | 仅查找字段支持 | 部署错误 |
主从关系与查找字段对比
| 属性 | 主从关系 | 查找 |
|---|---|---|
<required> | 禁止 | 可选 |
<deleteConstraint> | 禁止(始终为 CASCADE) | 必填(SetNull、Restrict、Cascade) |
<lookupFilter> | 禁止 | 可选 |
<relationshipOrder> | 必填(0 或 1) | 不适用 |
<reparentableMasterDetail> | 可选 | 不适用 |
<writeRequiresMasterRead> | 可选 | 不适用 |
错误 — 带有禁止属性的主从关系:
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Account__c</fullName>
<type>MasterDetail</type>
<referenceTo>Account</referenceTo>
<relationshipName>Contacts</relationshipName>
<relationshipOrder>0</relationshipOrder>
<required>true</required>
<deleteConstraint>Cascade</deleteConstraint>
<lookupFilter>...</lookupFilter>
</CustomField>
错误: Master-Detail Relationship Fields Cannot be Optional or Required · Can not specify 'deleteConstraint' for a CustomField of type MasterDetail · Lookup filters are only supported on Lookup Relationship Fields
正确 — 主从关系字段:
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Account__c</fullName>
<label>Account</label>
<description>Links this record to its parent Account</description>
<type>MasterDetail</type>
<referenceTo>Account</referenceTo>
<relationshipLabel>Child Records</relationshipLabel>
<relationshipName>ChildRecords</relationshipName>
<relationshipOrder>0</relationshipOrder>
<reparentableMasterDetail>false</reparentableMasterDetail>
<writeRequiresMasterRead>false</writeRequiresMasterRead>
</CustomField>
正确 — 查找字段(含可选属性):
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Related_Account__c</fullName>
<label>Related Account</label>
<description>Optional link to a related Account</description>
<type>Lookup</type>
<referenceTo>Account</referenceTo>
<relationshipLabel>Related Records</relationshipLabel>
<relationshipName>RelatedRecords</relationshipName>
<required>false</required>
<deleteConstraint>SetNull</deleteConstraint>
<lookupFilter>
<active>true</active>
<filterItems>
<field>Account.Type</field>
<operation>equals</operation>
<value>Customer</value>
</filterItems>
<isOptional>false</isOptional>
</lookupFilter>
</CustomField>
其他主从关系规则
- 关系顺序: 对象上的第一个主从关系 =
0,第二个 =1 - 关系名称: 必须是复数形式的 PascalCase 字符串(例如,
Travel_Bookings) - 连接对象: 对于标准多对多关系,使用两个主从关系字段(可启用汇总)
- 限制: 每个对象最多有 2 个主从关系。其他关系请使用查找关系。
5. 汇总字段规则(重要)
汇总字段的部署失败率最高。请严格遵循这些规则。
汇总字段的必需元素
| 元素 | 要求 | 格式 |
|---|---|---|
<type> | 必需 | 始终为 Summary |
<summaryOperation> | 必需 | count、sum、min 或 max |
<summaryForeignKey> | 必需 | ChildObject__c.MasterDetailField__c |
<summarizedField> | 有条件必需 | sum、min、max 时必需。count 时不需要 |
汇总字段的禁止元素
绝不要在汇总字段上包含以下属性:
| 禁止的属性 | 原因 |
|---|---|
<precision> | 汇总字段继承被汇总字段的属性 |
<scale> | 汇总字段继承被汇总字段的属性 |
<required> | 不适用于汇总字段 |
<length> | 不适用于汇总字段 |
summaryForeignKey 和 summarizedField 的格式规则
重要: summaryForeignKey 和 summarizedField 都必须使用完全限定格式:
ChildObjectAPIName__c.FieldAPIName__c
判定逻辑:
summaryForeignKey=ChildObject__c.MasterDetailFieldOnChild__csummarizedField=ChildObject__c.FieldToSummarize__c
错误 — 含有常见错误的汇总字段:
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Total_Amount__c</fullName>
<label>Total Amount</label>
<type>Summary</type>
<precision>18</precision>
<scale>2</scale>
<summaryOperation>sum</summaryOperation>
<summaryForeignKey>Order__c</summaryForeignKey>
<summarizedField>Amount__c</summarizedField>
</CustomField>
错误:
Can not specify 'precision' for a CustomField of type SummaryMust specify the name in the CustomObject.CustomField format (e.g. Account.MyNewCustomField)
正确 — 汇总字段(SUM 操作):
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Total_Amount__c</fullName>
<label>Total Amount</label>
<description>Sum of all line item amounts</description>
<inlineHelpText>Automatically calculated from child line items</inlineHelpText>
<type>Summary</type>
<summaryOperation>sum</summaryOperation>
<summarizedField>Order_Line_Item__c.Amount__c</summarizedField>
<summaryForeignKey>Order_Line_Item__c.Order__c</summaryForeignKey>
</CustomField>
COUNT: 与 SUM 类似,但省略 <summarizedField>(保留 <summaryForeignKey>)。MIN / MAX: 与 SUM 类似,将 <summaryOperation>min或max` 作为操作。
汇总字段速查表
| 操作 | 是否需要 summarizedField? | 用例 |
|---|---|---|
count | 否 | 统计子记录数量 |
sum | 是 | 累加数值 |
min | 是 | 查找最小值 |
max | 是 | 查找最大值 |
汇总字段的先决条件
- 汇总字段只能创建在主从关系中的父对象上
- 子对象必须有一个指向此父对象的主从关系字段
- 被汇总的字段必须存在于子对象上
6. 公式字段规则
公式结果类型
公式本身不是一种类型。<formula> 标签会添加到 <type> 为结果数据类型(Checkbox、Currency、Date、DateTime、Number、Percent、Text)的字段上。
- 公式字段绝不包含
<length>——文本结果的公式字段也不例外。API 会拒绝该属性:Can not specify a length for CustomFields that have a formula。
公式 XML 生成规则
<formula>标签的内容必须用<![CDATA[ ... ]]>包裹,以免解析器将公式运算符(&、<、>)识别为 XML 标记。- 如果公式文本本身包含字面序列
]]>,请通过拆分 CDATA 块来转义它,例如:<![CDATA[Text_Field__c & "]]]]><![CDATA[>"]]> - 绝不要使用名为
returnType的属性或标签。Metadata API 中不存在此项。<type>标签用于定义公式结果的返回数据类型。
formulaTreatBlanksAs 规则
决策逻辑:
- 如果公式结果类型为
Number、Currency或Percent→ 设置<formulaTreatBlanksAs>BlankAsZero</formulaTreatBlanksAs> - 如果公式结果类型为
Text、Date或DateTime→ 设置<formulaTreatBlanksAs>BlankAsBlank</formulaTreatBlanksAs>
错误示例 — 将 Formula 用作类型:
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Calculated_Value__c</fullName>
<type>Formula</type>
<returnType>Number</returnType>
<formula>Field1__c + Field2__c</formula>
</CustomField>
正确示例 — 公式字段:
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Calculated_Value__c</fullName>
<label>Calculated Value</label>
<description>Sum of Field1 and Field2</description>
<type>Number</type>
<precision>18</precision>
<scale>2</scale>
<formula><![CDATA[Field1__c + Field2__c]]></formula>
<formulaTreatBlanksAs>BlankAsZero</formulaTreatBlanksAs>
</CustomField>
公式字段依赖项和函数
- 如果公式字段引用了其他字段,而被引用字段不存在或尚未部署,部署就会失败 — 请先部署被引用的字段。
- 比较选项列表时使用
ISPICKVAL()(而不是==)。 - 完整的公式函数参考(TEXT/VALUE/CASE/DAY/MONTH/DATEVALUE/ISCHANGED 类型规则)请参阅
platform-validation-rule-generate技能,该技能负责公式函数的正确性。
7. 常见部署错误
| 错误消息 | 原因 | 修复方法 |
|---|---|---|
ConversionError: Invalid XML tags or unable to find matching parent xml file for CustomField | XML 注释位于根 <CustomField> 元素之前 | 删除 .field-meta.xml 文件中 <CustomField> 之前的 XML 注释(``) |
Field [FieldName] does not exist. Check spelling. | 被引用的字段不存在或尚未部署 | 确认被引用字段存在,并且已在此字段之前部署 |
DUPLICATE_DEVELOPER_NAME | 对象上已存在该字段的 fullName | 使用唯一且符合业务需求的名称 |
MAX_RELATIONSHIPS_EXCEEDED | 对象上的主从关系字段超过 2 个,或查找关系字段超过 15 个 | 第 3 个及之后的主从关系字段改用查找关系;检查查找关系字段数量 |
| 保留关键字错误 | 使用了 Order__c、Group__c 等 | 重命名为 Status_Order__c 等 |
Value set must reference a value set name or define a value set, but not both | <valueSet> 同时包含 <valueSetName> 和 <valueSetDefinition> | 只保留其中一个(参见第 3.4 节) |
duplicate value found: [X] is defined multiple times | 两个 <value> 条目的 <fullName> 相同 | 确保每个选项列表值的 <fullName> 都唯一 |
选项列表值出现 Invalid fullName | 值的 <fullName> 以数字开头或包含连字符 | 以字母开头;不要使用连字符,也不要以数字开头。允许使用空格 — 不要将空格替换为下划线(参见 §3.4 中的值名称保真要求) |
Element ...picklist is not allowed | 使用了已弃用的 ≤37.0 依赖选项列表语法(<picklist>/<picklistValues>/<controllingFieldValues>) | 使用新版 valueSettings/controllingFieldValue/valueName 格式(第 3.4 节) |
8. 验证清单
生成 CustomField XML 之前,请确认:
通用检查
-
<fullName>的格式是否有效,并以__c结尾? -
<description>和<inlineHelpText>是否都已填写且内容有意义? -
<label>是否采用标题式大小写? - 根
<CustomField>元素之前是否没有 XML 注释(``)?(根元素之前的注释会导致 SDR 解析器出错)
主从关系字段检查(重要)
- 是否未设置
<required>属性?(主从关系字段始终必填) - 是否未设置
<deleteConstraint>属性?(主从关系字段始终级联删除) - 是否未设置
<lookupFilter>块?(仅适用于查找关系字段) -
<relationshipOrder>是否设置为0或1? - 父对象的
<sharingModel>是否设置为ControlledByParent?
查找字段检查
-
<deleteConstraint>是否设为SetNull、Restrict或Cascade? -
<relationshipName>是否采用复数形式的 PascalCase?
选项列表字段检查
- 每个
<valueSet>是否只包含<valueSetName>或<valueSetDefinition>其中之一,绝不同时包含两者? - 对于值集引用,是否设置了
<restricted>true</restricted>? - 对于 StandardValueSet 引用,名称是否为不带
__c的纯枚举值(例如Industry)? - 对于 GlobalValueSet 引用,名称是否为不带
__gvs后缀的纯开发者名称? - 对于依赖选项列表,是否设置了
<controllingField>,并为每一对值设置一个<valueSettings>(<controllingFieldValue>+<valueName>)? - 对于依赖选项列表,是否未使用已弃用的
<picklist>/<picklistValues>/<controllingFieldValues>形式? - 所有选项列表值的
<fullName>是否均唯一、以字母开头且不含连字符?(允许包含空格——根据 §3.4 值名称保真规则,不要将空格替换为下划线)
汇总汇总字段检查(关键)
- 是否不存在
<precision>属性? - 是否不存在
<scale>属性? -
<summaryForeignKey>是否采用ChildObject__c.MasterDetailField__c格式? - 对于 SUM/MIN/MAX:
<summarizedField>是否采用ChildObject__c.FieldName__c格式? - 对于 COUNT:是否不存在
<summarizedField>? - 子对象是否具有指向此父对象的主从关系字段?
公式字段检查
-
<type>是否设为结果类型(而非“Formula”)? -
<formula>内容是否以<![CDATA[ ... ]]>包裹? - 是否不存在
<returnType>属性?(Metadata API 中不存在此属性) - 是否不存在
<length>?(公式字段从不包含长度,即使是文本结果公式也不例外) -
<formulaTreatBlanksAs>是否根据结果类型设置为BlankAsZero(数值结果)或BlankAsBlank(文本/日期结果)? - 所有引用的字段是否都存在,并且会在此字段之前部署?
数值字段检查
-
scale ≤ precision是否成立? -
precision ≤ 18是否成立?
文本区域检查
- 对于 TextArea:是否省略了
<length>?(API 会拒绝在 TextArea 字段上显式设置<length>值。) - 对于 LongTextArea/Html:是否设置了
<visibleLines>?
关系数量限制检查
- 对象上的主从关系是否不超过 2 个?
- 对象上的查找关系是否不超过 15 个?
命名检查
- API 名称是否不含保留字(如
Order、Group、Select等)? - API 名称在此对象上是否唯一?