mcpField
C
consumer-goods-promotion-bo-api-deploy

consumer-goods-promotion-bo-api-deploy

github.com/forcedotcom开发1.1k145 次安装1 天前更新
代码仓库

关于 consumer-goods-promotion-bo-api-deploy

面向 Salesforce 管理员和开发者的技能,用于在 Consumer Goods Cloud 中启用 Promotion BO API,并生成、部署和接入自定义工作流步骤。通过端到端 REST 验证检查部署结果。

主要功能

  1. 01检查组织权限与包命名空间
  2. 02预览并应用 BO API 初始数据
  3. 03生成并部署 Apex 工作流步骤
  4. 04将步骤注册到选定工作流
  5. 05通过 REST 接口验证流程

适用场景

  1. 01为 Salesforce 组织启用 Promotion BO API
  2. 02向创建、更新或复制流程添加自定义步骤
  3. 03验证 Promotion API 的导入与状态接口

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/forcedotcom/sf-skills --skill consumer-goods-promotion-bo-api-deploy

安装后在 Claude Code 中输入/consumer-goods-promotion-bo-api-deploy确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/set-comment-value/
interview-answers.json
README.md
SetCommentValue.cls
SetCommentValue.cls-meta.xml
assets/set-comment-value/payloads/
copy.json
create.json
update.json
references/
conventions-and-payload-rules.md
generate-and-wire.md
preflight-and-seed-queries.md
reference-example-set-comment-value.md
smoke-and-verify.md

详细介绍

部署 Promotion BO API

功能说明

在 Salesforce 组织中启用 Consumer Goods Cloud TPM Promotion Business Object (BO) API,询问用户要添加到促销流水线中的一个自定义工作流步骤,生成并部署相应的 Apex 类,将其注册到 BO API 实体,并接入客户选定的 {create, update, copy} 工作流子集,最后通过以下三个 REST 端点端到端验证整个流程:

  • POST /services/apexrest/<prefix>/promotions/initialize
  • POST /services/apexrest/<prefix>/promotions/ingest
  • GET /services/apexrest/<prefix>/promotions/status?importId=...

此流程用于无界面交付:指定一个组织,回答访谈问题,技能即可安装并验证此步骤。Promotion BO API 随 CGCloud 托管包一同提供(已发布版本为 cgcloud,开发/测试版为 cgcloud_dev)。所有 Apex 标识符、对象/字段 API 名称和 REST URL 均在运行时根据检测到的包前缀生成。

derive 不在此处的范围内(后续技能会介绍)。写入和冒烟测试阶段的详细操作手册位于 references/ 下:

  • references/preflight-and-seed-queries.md — 第 1/2/3 阶段的 SOQL(TPM 权限、权限集门控、框架状态验证、静态资源检索步骤、批处理链轮询)。
  • references/conventions-and-payload-rules.md — 销售组织分区、优先根据架构推导契约,以及九条跨工作流载荷规则 R1–R9。
  • references/generate-and-wire.md — 第 5a 阶段(生成并部署类)和第 5b 阶段(注册并接入步骤),含完整的 register-step.apex。
  • references/smoke-and-verify.md — 第 6 阶段(契约推导、载荷生成、create/update/copy 流程及验证)。
  • references/reference-example-set-comment-value.md — 随附的 SetCommentValue 预设(资源位于 assets/set-comment-value/)。

请先收集输入信息

开始前先询问,不要猜测。

  1. 组织别名 — 目标组织的 sf 别名。必填。
  2. 销售组织 — 必填的预设参数,默认值为 0001。必须为 4 个字符且全部大写(与 TPMSetupData.validateSalesOrg 保持一致)。所有后续查找(促销模板、战术模板、锚定客户、产品筛选条件、SKU)都限定在此销售组织范围内——请参阅 references/conventions-and-payload-rules.md(“Sales-org partitioning”)。
  3. 是否同意植入种子数据? — 第 3a 阶段会获取打包的 BO API 种子数据,并在插入 8 个对象中的约 232 行之前征求确认。供 CI 调用方使用时可传入 --yes。
  4. 是否试运行? — --dry-run 会运行第 1、2、3a 预览阶段、第 5 阶段访谈,以及仅验证的部署。不写入任何内容。

待了解框架状态后,再通过第 5 阶段的访谈收集定制内容。

先查找命名空间

前缀取决于已安装的构建版本——请检测,不要猜测。已发布包 → cgcloud;开发/测试版 → cgcloud_dev;通过源代码部署 → 无前缀。

sf data query --target-org <alias> \
  --query "SELECT NamespacePrefix FROM ApexClass WHERE Name = 'TPMSetupData'" --json

读取 records[0].NamespacePrefix,并设置下文各处都会用到的三个变量:

  • PREFIX_DOT — Apex 引用:cgcloud. / cgcloud_dev. / 空。
  • PREFIX_UNDER — 对象/字段 API 名称:cgcloud__ / cgcloud_dev__ / 空。
  • URL_NS — REST 路径:/cgcloud / /cgcloud_dev / 空。

每次 Apex 调用均采用 ${PREFIX_DOT}ClassName.method(...);每个 SOQL 对象/字段均采用 ${PREFIX_UNDER}Object__c;每个 REST URL 均采用 /services/apexrest${URL_NS}/promotions/<endpoint>。在运行时替换。

阶段 1 — 预检

运行以下命令,并在首次失败时停止。

  1. sf --version;node --version(仅在运行随附脚本时)。另外,在会话开始时执行一次 export SF_SKIP_NEW_VERSION_CHECK=true,避免过时 CLI 的更新横幅输出到 stdout,导致下游任何 sf … --json | jq … 管道出错(替代的 sed 去除方式请参阅 references/smoke-and-verify.md 中的“解析注意事项”)。
  2. sf org display --target-org <alias> --json — 确认可访问;捕获 instanceUrl + org id(仅用于显示/日志记录)。REST 调用通过 sf api request rest 使用 CLI 中存储的会话 — 此技能绝不提取访问令牌。
  3. 在本地验证销售组织:长度为 4、大写、非空(与 TPMSetupData.validateSalesOrg 一致)。快速失败。
  4. TPM 授权(Permission Set License) — 当前用户的 CGCRetailAndTPMMgmtPsl PSL 分配。SOQL + 警告/停止路由见 references/preflight-and-seed-queries.md 第 4 步。
  5. 当前用户权限集(TPM 管理员角色) — 当前用户必须持有 TPM_Master_Data_Admin(或与 %TPM%Master Data Admin% 匹配的克隆);若缺失,请提供 sf org assign permset --name TPM_Master_Data_Admin --target-org <alias>,并等待完成。SOQL 见 references/preflight-and-seed-queries.md 第 5 步。确认具有管理员访问权限后方可继续。
  6. 命名空间发现(见上文)。
  7. 当前用户的 ${PREFIX_UNDER}Sales_Org__c 必须等于 <salesOrg>。 空值会抛出 SOU0003;不匹配会显示为“未找到”(创建/更新)或 TransformationError(复制)。SOQL 见 references/preflight-and-seed-queries.md 第 7 步。空值或 != '<salesOrg>' → 停止;仅修复用户记录。参见 references/conventions-and-payload-rules.md R6;类别访问权限将在阶段 6 根据 R9 进行预检。

阶段 2 — 验证 BO API 框架状态

只读;用于判断是否需要运行阶段 3。运行 references/preflight-and-seed-queries.md (“阶段 2 — 验证 BO API 框架状态”)中的三条按销售组织范围筛选的 SOQL 查询: 工作流行、步骤行数、连接行数 — 均限定为 <salesOrg>。

  • 工作流行数为零 → 此销售组织为全新状态,阶段 3 将进行播种。
  • 状态完整(4 条工作流行 create/update/copy/derive;步骤行 + 连接行均 >0) → 阶段 3 对此销售组织不执行任何操作(仍需运行以确保幂等;3a 会显示新增数为零)。
  • 状态不完整 → 错误;停止并报告缺少哪些行。由人工先检查。

阶段 3a — 预览默认 BO API 播种数据(获取 + 确认)

工作流/步骤/连接/实体/输入结构以 CSV 文件形式随附于打包的 TPMSetupData 静态资源中;TPMSetupData.setupBOApi 会读取并 执行 upsert。运行前,向用户展示将要写入的内容。

  1. 找到并检索 TPMSetupData 静态资源到专用的 setup-data/ 子项目(使只读托管资源不会进入阶段 5a 的部署树 ./.promotion-bo-api-deploy/force-app),然后确认每个目标 sObject 均存在。SOQL + 完整检索步骤 + 8 个 CSV 文件清单 + describe 循环见 references/preflight-and-seed-queries.md(“阶段 3a — 检索打包的播种数据”)。任何步骤失败 → 停止并显示打印出的差异/错误。
  2. 显示每个对象的行数(8 个对象合计约 232 行;“基于 Unique_Key__c 执行 upsert — 幂等”)+ 0_BO_API_Workflow__c.csv 和 0_BO_API_Workflow_Step__c.csv 的前 3 行,并替换其中的 {{NS}}/{{SALES_ORG}}。
  3. 等待确认,除非指定 --yes。“no”/空白 → 正常中止,并指出已检索的 BOApi/ 目录。
  4. 指定 --dry-run 时 → 在此处停止;不要运行 3b。

阶段 3b — 应用默认种子数据

仅在确认 3a 后执行。

  1. PHASE3_START=$(date -u +%FT%TZ)。
  2. 通过匿名 Apex 运行 metadata-wizard setup:${PREFIX_DOT}TPMSetupData.setupMetadataWizard('<salesOrg>'); → sf apex run --target-org <alias> --file ./.promotion-bo-api-deploy/setup-metadata-wizard.apex。
  3. 等待批处理链完成。GenericDemoSetupDataBatch 会通过 finish() 自行链接后续批处理,因此按类轮询,并使用连续两次结果为零的中断模式 + 最终的 NumberOfErrors/ExtendedStatus 检查。SOQL 查询见 references/preflight-and-seed-queries.md(“阶段 3b — 轮询批处理链”)。任何 Failed/Aborted/NumberOfErrors > 0 → 停止。
  4. 对 ${PREFIX_DOT}TPMSetupData.setupBOApi('<salesOrg>'); 重复步骤 2–3。

阶段 4 — 验证 BO API 框架已启用

重新运行阶段 2 的查询。预期有 4 条 BO_API_Workflow__c 记录(create/update/copy/derive,Unique_Key__c 唯一),≥46 条 BO_API_Workflow_Step__c 记录,≥54 条 BO_API_Workflow_Workflow_Step__c 关联记录。数量不足 → 停止,并输出缺少的内容。只要有组件失败,就绝不要声称成功。

阶段 5 — 访谈:用户想自定义什么?

框架现已启用。自定义内容由用户提供 — 不要跳过访谈,也不要自行编造答案。打印:

The Promotion BO API framework is installed. To add a custom step, tell me:
  - Which BO API entity does it target? (e.g. Promotion/Tactic — I'll list registered entities)
  - Which workflows should it fire in? (create, update, copy)
  - What does it read from the ingest input?
  - What does it write on the SObject or elsewhere?
  - Any preconditions or side effects?
Say "use the SetCommentValue reference" for a worked example.
5.1 — 需要收集的答案
字段必填说明
stepName是PascalCase Apex 类名 + BO API Workflow Step Name。在 ApexClass 中必须唯一。
entity是BO API 实体 Name — 必须与从 ${PREFIX_UNDER}BO_API_Entity__c 实时查询到的某条记录匹配(共享,不按销售组织分区)。常见记录包括 Promotion、Tactic、ProductFilter、ManualInputs、CustomState。查询组织 — 不要假设列表固定。
workflows是{create, update, copy} 的非空子集。derive 不在范围内。
actionName是类在 call(String action, ...) 中接收的符号操作字符串。约定为 stepName 的 lowerCamelCase 形式。
inputPaths是(≥1)要从 currentInput 读取的 JSON 路径,例如 ["Comment"]。
inputPathType是输入路径的 JSON 类型 — String、Array、Boolean、Number、Object。此值决定每条 SIS 记录的 RecordType;值错误会在摄取时导致 TransformationError: Expected <Type>。如果类型不同 → 按类型分组,每组运行一次阶段 5b。
inputPathRequired可选ingest payload 中是否必须包含 inputPaths。默认为 false。此值决定 BO_API_Step_Input_Structure__c.Required__c(平台默认值为 true — skill 始终显式写入)。参见 references/generate-and-wire.md。
outputWrites是(≥1){field, source} 对;field 是不带命名空间前缀的目标 API 名称(skill 会添加 ${PREFIX_UNDER}),source 引用 inputPaths 的值 / 字面量 / 计算表达式。
description是一句话描述步骤 → ${PREFIX_UNDER}Description__c + 类文档字符串。
preconditions可选写入前的自由文本条件。
sortAfter可选要排在其后的已命名打包步骤;默认值为 max(Sort__c) + 10。
5.2 — 访谈流程
  1. 预设快捷方式。 --preset set-comment-value(或“使用 SetCommentValue 参考”)会从 references/reference-example-set-comment-value.md(assets/set-comment-value/interview-answers.json)加载答案,并跳过交互式访谈。--interview-file <path> 会加载与 5.1 表格对应的 JSON(优先于 --preset)。
  2. 逐一提问(或一次性提出一组问题);在每个必填字段都有值之前,不要继续。
  3. 用户指定实体后,显示该实体可写字段:
    sf sobject describe --target-org <alias> --sobject '${PREFIX_UNDER}<Entity>__c' --json \
      | jq -r '.fields[] | select(.updateable == true and .createable == true) | .name'
    
    任何 outputWrites 字段都必须出现在这里;否则停止并要求用户换一个字段(FLS 的范围限定为调用方)。
  4. 确认计划(概述 Class/Entity/Workflows/Reads/Writes/Sort/Description →“部署并接线?[y/N]”)。如果 workflows 包含 copy,请预先说明两个仅适用于 copy 的前提,避免运行时才发现:(a) 每个子项的输入值来自源 promotion——outputWrites 仍会执行,但 <inputPaths> 的值会被忽略(只有 Slogan 这类顶层字段会传递);(b) 正在运行的 User.Sales_Org__c 必须与源模板的 Sales_Org__c 相同(在 Phase 1 第 7 步预检,并在每次 Phase 6 导入前重新检查;如果流程中途发生偏差,copy 会失败并报错 TransformationError: The User and the Promotion Template must have the same Sales org——请修复用户记录,不要在流程中途修改;参见 references/conventions-and-payload-rules.md R6)。输入 n/留空 → 将答案保存到 ./.promotion-bo-api-deploy/interview.json 并退出。输入 y → 执行 Phase 5a。

Phases 5a / 5b — 生成并部署、注册并接线

操作手册见 references/generate-and-wire.md。简而言之:检查类名以确保幂等性;确认目标字段可写;清理 ./.promotion-bo-api-deploy/force-app/main/default/classes/ 中任何过时的 .cls/.cls-meta.xml(遗留文件会导致 MDAPI 整批回滚且不显示错误);根据访谈内容生成与命名空间无关的 Callable——类和 call 方法都必须为 global(打包的 CallableManager 通过 Type.forName 跨越命名空间边界进行解析;在托管安装中,public 会导致运行时失败——参见操作手册);显示并确认;运行 sf project deploy start。然后,在一个 anon-Apex 事务中,upsert 一条 BO_API_Workflow_Step__c(Classname__c 中填写不带命名空间的类名)、为每个选定的工作流 upsert 一条 BO_API_Workflow_Workflow_Step__c 关联记录(不包含 derive),并 upsert BO_API_Step_Input_Structure__c 记录(根据 inputPathType 设置 RecordType,根据 inputPathRequired 显式设置 Required__c)。两个 upsert 都以 Unique_Key__c 为键(幂等)。

Phase 6 — 通过 REST 端点进行冒烟测试

操作手册见 references/smoke-and-verify.md。根据 BO_API_Step_Input_Structure__c(以架构为准)推导每个调用工作流的负载契约,应用 references/conventions-and-payload-rules.md 中的规则 R1–R9,在销售组织内解析所有引用,生成 ./out/smoke/{create,update,copy}.json,然后为每个选定的工作流运行 initialize → ingest → poll status。通过直接查询 BO_API_Transaction_Log__c 进行验证(任何行的值 != 'Calculated' → 失败),并断言 outputWrites 字段与 ./out/smoke/expected.json 相符。只有在访谈中包含 update 和 copy 时,才运行相应流程。

Phase 7 — 报告

简要状态:组织、销售组织、dry-run 标志;命名空间前缀;seed 行数(Phases 2 和 4 前后);访谈摘要;部署结果 + workflow-step id + junction ids;每个调用工作流的 smoke 导入 ids——全部状态为 Calculated 且断言相符,或准确列出失败项(SOQL、expected、actual);手动后续事项(无问题时填写 none)。

规则

  • 只要任何属于本次 smoke 导入 ID 的 BO_API_Transaction_Log__c 行满足 Status__c != 'Calculated',就绝不能宣称成功。Calculated 是最终成功状态(R2);选项列表中不存在 Processed。
  • 只要任何 outputWrites 断言失败,或自阶段开始以来仍有任何 GenericDemoSetupDataBatch AsyncApexJob 正在运行或已失败,就绝不能宣称成功。
  • 预检或验证检查一旦失败,立即停止;报告确切的失败原因。
  • 绝不能对命名空间前缀进行硬编码——所有 Apex/SOQL/REST 引用都必须由第 1 阶段的检测结果拼接而成。
  • 绝不能臆造 Apex 方法签名——使用已打包的 TPMSetupData / BO_API_* 对象以及正式发布的 REST 端点所声明的内容。
  • 已植入的 BO API 元数据属于打包内容——在调用 TPMSetupData.setupBOApi 之前,先预览并征得用户确认。
  • 绝不能臆造访谈答案。若没有用户输入,也没有 --preset/--interview-file,则停止并打印问题。
  • 绝不能接入访谈中未包含的工作流。create/update/copy 均需显式选择;derive 始终排除。
  • 绝不能根据硬编码模板拼接 smoke 负载——按工作流从 BO_API_Step_Input_Structure__c 推导可接受的路径,并先根据该契约验证用户输入。
  • 绝不能在没有销售组织筛选条件的情况下解析引用值。属于其他销售组织的记录对本次调用无效。
  • 绝不能生成可见性为 public 的 Callable 步骤类——类和 call 方法都必须声明为 global。public 仅适用于同一命名空间的开发组织;在托管安装中会失败并报错 Type "<stepName>" does not exist;事务日志会显示通用的 Error。请参阅 references/generate-and-wire.md。
  • 绝不能在多个步骤部署间重复使用 ./.promotion-bo-api-deploy/force-app/main/default/classes/——先删除上一个步骤的 .cls/.cls-meta.xml 文件。残留文件会触发 MDAPI 整批静默回滚,而 CLI 仍会报告 "created": true。
  • 插入 BO_API_Step_Input_Structure__c 行时,绝不能不显式设置 Required__c。平台默认值为 true;该技能的默认值为 false,只有设置 inputPathRequired 时才会启用。省略该字段会导致所有可选路径被静默设为必填。
  • 未确认运行用户的 ${PREFIX_UNDER}Sales_Org__c 等于 <salesOrg> 之前,绝不能越过第 1 阶段——值为空会抛出 SOU0003;不匹配会显示“未找到”(create/update)或 TransformationError(copy)。仅在用户记录上修复。请参阅 references/conventions-and-payload-rules.md R6。
  • 绝不能摄取这样的负载:其 ProductFilter.Criteria.<level> 引用了运行用户没有 Product_Category_Share__c Access_Level__c='ReadWrite' 权限的类别——请按照 references/conventions-and-payload-rules.md R9 在第 6 阶段预检。不要静默插入共享行。

评论

支持 Markdown