Skip to content
AI & Agents
Skill

/consumer-goods-promotion-bo-api-deploy

Use to enable the Consumer Goods Cloud TPM Promotion Business Object (BO) API framework in a Salesforce org, interview the user for the custom Workflow Step they want to add, generate and deploy that Apex class, wire it into the create/update/copy workflows, and prove it

From plugin
forcedotcom-sf-skills
997200 skills2 agents14 commands3 MCP
Install
$ npx -y skills add forcedotcom/afv-library --skill consumer-goods-promotion-bo-api-deploy --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/consumer-goods-promotion-bo-api-deploy

Context preview

The summary Claude sees to decide when to auto-load this skill.

Use to enable the Consumer Goods Cloud TPM Promotion Business Object (BO) API framework in a Salesforce org, interview the user for the custom Workflow Step they want to add, generate and deploy that Apex class, wire it into the create/update/copy workflows, and prove it

SKILL.md

consumer-goods-promotion-bo-api-deploy.SKILL.md
name: consumer-goods-promotion-bo-api-deploy
description: "Use to enable the Consumer Goods Cloud TPM Promotion Business Object (BO) API framework in a Salesforce org, interview the user for the custom Workflow Step they want to add, generate and deploy that Apex class, wire it into the create/update/copy workflows, and prove it end-to-end via headless REST ingest. Ships a worked reference example (SetCommentValue) but the customization is user-supplied per org. Triggers on \"deploy the promotion BO API\", \"set up promotion BO API\", \"headless promotion create\", \"add a BO API workflow step\"."
metadata:
  version: "1.0"
  domains: ["Consumer Goods"]
  minApiVersion: "60.0"
  cliTools:
    - tool: ["jq"]
      semver: ">=1.6"
    - tool: ["node"]
      semver: ">=20.17.0"
    - tool: ["sf"]
      semver: ">=2.0.0"
  accessCheck:
    - type: license
      value: "CGCRetailAndTPMMgmtPsl"

Deploy the Promotion BO API

What this does

Turns on the Consumer Goods Cloud TPM Promotion Business Object (BO) API in a Salesforce org, interviews the user for **one custom Workflow Step** to add to the promotion pipeline, generates and deploys that Apex class, registers it against a BO API entity, wires it into the customer's chosen subset of `{create, update, copy}` workflows, then proves the whole path end-to-end via three REST endpoints:

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

It is meant for **headless delivery**: point it at an org, answer the interview, and the skill installs the step and verifies it. The Promotion BO API ships in the CGCloud **managed package** (namespace `cgcloud` released, `cgcloud_dev` dev/beta). Every Apex identifier, object/field API name, and REST URL is derived from the detected package prefix at runtime — this skill never hard-codes it.

`derive` is out of scope here (a follow-up skill covers it). Detailed runbooks for the write and smoke phases live under `references/`:

  • `references/conventions-and-payload-rules.md` — sales-org partitioning, schema-first contract derivation, and the eight cross-workflow payload rules R1–R8.
  • `references/generate-and-wire.md` — Phase 5a (generate + deploy the class) and Phase 5b (register + wire the step), with the full `register-step.apex`.
  • `references/smoke-and-verify.md` — Phase 6 (contract derivation, payload materialization, create/update/copy legs + verification).
  • `references/reference-example-set-comment-value.md` — the shipped `SetCommentValue` preset (assets at `assets/set-comment-value/`).

Inputs to collect first

Ask before starting; do not guess.

1. **Org alias** — the `sf` alias of the target org. Required. 2. **Sales org** — required pre-parameter, default `0001`. Must be 4 chars, uppercase (mirrors `TPMSetupData.validateSalesOrg`). **Every** downstream lookup (promotion template, tactic template, anchor account, product filter criteria, SKUs) is scoped to this sales org — see `references/conventions-and-payload-rules.md` ("Sales-org partitioning"). 3. **Yes to seeding?** — Phase 3a fetches the packaged BO API seed and asks for confirmation before inserting ~232 rows across 8 objects. Offer `--yes` for CI callers. 4. **Dry run?** — `--dry-run` runs Phases 1, 2, 3a-preview, the Phase 5 interview, and a validate-only deploy. Writes nothing.

What the customization *is* gets collected in Phase 5's interview, once the framework state is known.

Find the namespace first

The prefix depends on the installed build — detect it, do not guess. Released package → `cgcloud`; dev/beta → `cgcloud_dev`; source-deployed → no prefix.

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

Read `records[0].NamespacePrefix` and bind three variables used everywhere below:

  • `PREFIX_DOT` — Apex references: `cgcloud.` / `cgcloud_dev.` / empty.
  • `PREFIX_UNDER` — object/field API names: `cgcloud__` / `cgcloud_dev__` / empty.
  • `URL_NS` — REST paths: `/cgcloud` / `/cgcloud_dev` / empty.

Every Apex call is `${PREFIX_DOT}ClassName.method(...)`; every SOQL object/field is `${PREFIX_UNDER}Object__c`; every REST URL is `/services/apexrest${URL_NS}/promotions/<endpoint>`. Substitute at run time.

Phase 1 — Preflight

Run these and stop on the first failure.

1. `sf --version`; `node --version` (only if running shipped scripts). 2. `sf org display --target-org <alias> --json` — confirm reachable, capture `instanceUrl` + org id (for display/logging only). Every REST call in later phases goes through `sf api request rest`, which uses the CLI's stored session — this skill never extracts the access token. 3. Validate the sales org locally: length 4, uppercase, non-blank (mirrors `TPMSetupData.validateSalesOrg`). Fail fast instead of surfacing an Apex stack trace. 4. **TPM entitlement (Permission Set License)** — the TPM app is licensed through the **`CGCRetailAndTPMMgmtPsl`** Permission Set License ("CGC Retail and Trade Promotion Management"); there is **no** `TPM App` UserLicense. Check the running user's PSL assignment:

   SELECT Id FROM PermissionSetLicenseAssign
    WHERE Assignee.Username = '<running-user-name>'
      AND PermissionSetLicense.DeveloperName = 'CGCRetailAndTPMMgmtPsl'

On scratch/dev-hub the PSL may be legitimately unassigned; detect env with `SELECT OrganizationType, IsSandbox FROM Organization`:

  • `OrganizationType = 'Developer Edition'` OR `IsSandbox = true` and empty → **warn** ("permset gate below is the real check"), continue.
  • Any other org shape and empty → **stop** ("TPM Permission Set License `CGCRetailAndTPMMgmtPsl` not assigned to the running user").

5. **Running-user permission set (TPM Admin persona)** — the setup needs a permission set granting the *TPM Master Data Admin* persona. The shipped permset is `TPM_Master_Data_Admin` (packaged; `Pe

Read more
Ships withforcedotcom-sf-skills

This repository provides a curated collection of Salesforce agent skills for building applications.

Get the whole plugin

Other skills on forcedotcom-sf-skills.