Knowing the current stage of a Business Process Flow (BPF) lets you lock fields, hide buttons, or trigger downstream logic. Below are two generic patterns that work in every online environment—no proprietary entity names, no deprecated APIs, and no plug-ins.
1 | When You’re Already on the Form
Fastest – zero Web API calls.
/**
* Returns true if the form’s active stage matches any item
* in stageNames
(case-insensitive).
*
* @param {Xrm.ExecutionContext} executionContext
* @param {string[]} stageNames e.g. ["expense authority","decision made"]
*/
function isCurrentStage(executionContext, stageNames)
{
const formContext = executionContext.getFormContext();
const activeStage = formContext.data.process.getActiveStage();
if (!activeStage) { return false; }
const name = (activeStage.getName() || "").toLowerCase();
return stageNames.map(s => s.toLowerCase()).includes(name);
}
/* Usage */
if (isCurrentStage(executionContext, ["stage a","stage b"])) {
// lock / hide / validate
}
2 | When the Record Is Not Open
(Ribbon, Sub-grid, Power Automate …)
Every BPF you create is backed by an auto-generated table (BPF entity). That table stores:
- a lookup to the primary record (column name starts with
_bpf_…
) activestageid
– the current stage GUID- the formatted value of
activestageid
– the readable stage name
2.1 Find the BPF Table Name
- Solution → Processes → <Your BPF> → Properties
“Entity Name” shows something likenew_recoveryclaimbpf
. - Maker Portal → Tables → All tables (filter
by Type = Process) – same name ending in
bpf
. - Advanced Find / Modern Advanced Find – look for a table with a puzzle-piece icon.
General naming pattern:
<publisher-prefix>_<first 50 chars of BPF name>bpf
2.2 Generic Helper
/**
* Fetches the lower-case stage name by querying the record’s BPF row.
*
* @param {string} bpfTable e.g. "new_recoveryclaimbpf"
* @param {string} primaryLookup e.g. "_bpf_projectclaimid_value"
* @param {string} recordId GUID without braces
* @return {Promise<string|null>}
*/
function fetchStageName(bpfTable, primaryLookup, recordId)
{
const query =
`?$select=_activestageid_value` +
`&$filter=${primaryLookup} eq ${recordId} and statecode eq 0` +
`&$top=1`;
return Xrm.WebApi.retrieveMultipleRecords(bpfTable, query)
.then(r => {
if (!r.entities.length) { return null; }
return (r.entities[0]
["_activestageid_value@OData.Community.Display.V1.FormattedValue"] || "")
.toLowerCase();
});
}
2.3 Check the Stage
fetchStageName(
"new_recoveryclaimbpf", // BPF table
"_bpf_projectclaimid_value", // lookup to parent
someRecordId // target GUID
).then(stage => {
if (stage && ["expense authority","decision made"].includes(stage)) {
// record is in one of the target stages
}
});
3 | Field-Lock Example
/**
* Locks / unlocks a decision field based on
* the parent record’s BPF stage and the user’s role.
*/
function lockDecision(executionContext)
{
const formContext = executionContext.getFormContext();
const decisionAttr = formContext.getAttribute("prefix_decision");
if (!decisionAttr) { return; }
/** 1 ▸ privileged role bypass */
if (myUtility.userHasRole("Data Fix")) { toggle(false); return; }
/** 2 ▸ parent record ID */
const parent = formContext.getAttribute("prefix_parentid")?.getValue();
if (!parent?.length) { toggle(false); return; }
const parentId = parent[0].id.replace(/[{}]/g, "");
/** 3 ▸ stage check */
fetchStageName(
"prefix_parentbpf", // BPF table
"_bpf_parentid_value", // lookup column
parentId
).then(stage => {
const lock = ["expense authority","decision made"].includes(stage || "");
toggle(lock);
}).catch(() => toggle(false));
function toggle(disabled) {
decisionAttr.controls.forEach(c => c.setDisabled(disabled));
}
}
4 | Key Take-aways
- Same form →
formContext.data.process.getActiveStage()
- Elsewhere → query the hidden BPF table once and read the formatted stage name.
- Each BPF always has its own table; locate it in the solution or maker portal.
- Compare stage names in lower-case to avoid localisation or casing issues.
These two patterns let you tailor UX or logic to a record’s exact BPF stage in under 20 lines of code.
2/2
No comments:
Post a Comment