Almanac
Microsoft/d365salesDynamics 365

Consultant-focused KB for Microsoft Dynamics 365 Sales: implementation notes, gotchas, and configuration decisions beyond the official docs — across pipeline management, opportunities, forecasting, sequences, sales accelerator, Copilot, integrations, administration, and licensing.

feature-bpf-stage-reporting.mdv1 · history
CurrentApplies to AllUpdated 6 days agoSource Microsoft Learn

What it does

Every business process flow has its own Dataverse table holding the process instances, and that table — not the Opportunity record — is where the current stage and the stage history actually live. Anything that answers "how long do deals sit in Propose" or "how many deals moved stage last week" reads from there.

Key facts

  • Since v9.0 each activated BPF creates a table named after the process (for example, the Lead to Opportunity Sales Process table). You'll find it in Power Apps under Tables, and you can build views, charts and dashboards on it directly.
  • The Active Stage column on the BPF table is the supported place to read the current stage. The equivalent process columns that used to sit on the participating tables are deprecated — do not build new reporting on them.
  • A view or chart built on the BPF table can span the records of every table in a multi-table process, which is something you can't do from the Opportunity table alone.
  • If you must have the stage on the record itself — for a rollup, a view filter or an integration — the supported pattern is a cloud flow copying Active Stage into a custom column on the related record, one custom column per BPF if more than one process runs on that table.
  • Server-side logic is best hung off the BPF table: a classic Dataverse workflow or a cloud flow triggered when Active Stage changes. That's how you build "alert the manager if a deal has been in this stage more than 15 days" or "create a task on stage entry".
  • Client-side, the supported BPF client APIs let you show or hide form tabs and columns by stage, move the record forward or back, and run calculations. Reading the deprecated record columns in script is the thing to stop doing.
  • The BPF table is a real table for solution purposes and has to be added to a solution explicitly; it isn't carried along by the process definition.
  • Multiple concurrent process instances on one record each get their own row in their own BPF table, so a record with two active processes has two stage values, not one.

When to use / skip

This isn't optional if the client wants any stage-based metric beyond what the out-of-the-box pipeline chart gives them. Stage duration, stage conversion rates, deals-stuck reports and stage-change alerts all need the BPF table. The only projects that avoid it are the ones where "what stage is it in" never leaves the screen.

Where to be careful is the temptation to denormalise. Copying stage onto the Opportunity looks tidy and makes Advanced Find easier, and it's the pattern most consultants reach for. It's supported, but every copy is a thing that can drift, and if two processes run on the table you need two columns. Do it only where the reporting tool genuinely can't reach the BPF table — some older reporting layers and some integrations can't.

If the client's analytics live in a warehouse or Fabric, export the BPF table alongside Opportunity and do the stage-duration maths downstream rather than building rollups in Dataverse.

Configuration decisions

  • Whether stage reporting is done natively on the BPF table, denormalised onto the record, or handled entirely downstream in the warehouse.
  • If denormalising, how many custom stage columns are needed and what keeps them in step — a flow, and what happens when it fails.
  • Whether stage-change automation is a classic workflow on the BPF table or a cloud flow. Classic workflows are still the simpler option for synchronous stage-entry actions.
  • What "stuck" means numerically for this client, per stage, because the alerting rule needs a number and they'll want different ones for Qualify and Close.
  • Whether the BPF table is included in the ALM solution and in the data export profile from day one.
  • Whether historic stage data needs migrating at go-live, and if so what the starting stage is for records coming from a legacy system.

Gotchas

  • Reporting from the deprecated process columns on the Opportunity works today, which is exactly why people keep doing it. It's the thing that breaks quietly later.
  • Renaming a process doesn't rename the underlying table, and the display name shown on existing instances stays as it was. Reports keyed on names get confusing after a rebrand.
  • Deactivating and recreating a BPF instead of editing it creates a second table. The old data stays in the old table and nothing joins them for you.
  • The BPF table missing from a solution is a very common deployment failure — the process imports, the reporting doesn't.
  • Stage duration isn't a column. You calculate it from the process instance and stage change history; nothing gives it to you free.
  • Records with two concurrent processes will double-count in a naive report that joins BPF rows back to Opportunity.

Consultant notes

  • Show the client the BPF table in Power Apps early. Most have no idea it exists and assume stage is a field on the Opportunity.
  • When a client asks for "average time in stage", agree the definition before building — first entry, last entry, or total time including re-entries. They mean different things and give different numbers.
  • If someone on the team has written JavaScript reading process columns off the record, flag it as remediation work now rather than after the next platform update.
  • Add the BPF table to the solution and the data export as a checklist item, not a memory test.
  • Push back on stage-change alerts that email everyone. Start with a view of deals past their stage threshold and let the client ask for the email later.

Worth another look if Microsoft moves the deprecated process columns from deprecated to removed, or if the client stands up a Fabric pipeline for sales analytics.

Was this accurate?