| name | bc-approval-workflow-generator |
| description | Automatically generate custom approval workflow implementations for Business Central entities following the standard Workflow engine pattern. Creates an Approval Status enum, table extension (or table field), approval management codeunit with integration events and event subscribers, workflow setup codeunit with category/template registration, and page extension actions (Send / Cancel). Use when user requests to create, generate, or build an approval workflow, add approvals to a table, implement send/cancel approval actions, or mentions custom workflow for a Business Central entity. Trigger phrases include "create approval workflow", "add approvals to [entity]", "generate workflow for [table]", "implement approval process", "send approval request for [entity]", or when implementing custom approval processes on standard or custom tables. |
Business Central Approval Workflow Generator
Overview
Generates all AL objects required to integrate a Business Central entity
(standard or custom table) into the built-in Workflow approval engine.
The generated code follows the pattern used by standard BC approvals
(Purchase Orders, Sales Orders) and subscribes to the same event hooks.
Quick Start
Example requests:
- "Create an approval workflow for Statistical Account"
- "Add approval process to my custom Job Request table"
- "Generate send/cancel approval actions for the Transfer Order card"
- "Implement approval workflow on the Vendor Card"
Prerequisites
- Available object IDs from
app.json → idRanges
- Project affix from
app.json → affixes
- The target table must already exist (standard or custom)
- Knowledge of which page(s) display the entity (Card and/or List)
Interview — Mandatory Questions
Before generating any code the skill MUST ask the user the following
questions using vscode_askQuestions. Do NOT proceed until every answer
is collected.
Question 1 — Target entity
Which table should have the approval workflow?
If the user already mentioned the entity, confirm it. Otherwise present
a free-text input. Validate the table exists in the workspace or is a
known standard BC table.
Question 2 — Table type
Is this a custom table you own, or a standard BC table that you will
extend via table extension?
| Option | Impact |
|---|
| Custom table | Field added directly; OnDelete trigger in table |
| Standard table (extension) | Field added via tableextension; OnBeforeDelete trigger |
Question 3 — Related sub-tables (lock-down)
Does this entity have related sub-tables (e.g. lines on a document)
that should be locked (Editable = false) when the approval status is
not Open?
If Yes, ask for the sub-table name(s) and the page part(s) that
display them. The generator will add Editable property binding on
those subpage parts.
Question 4 — Pages
Which pages should receive the Send / Cancel Approval Request actions?
Present options:
- Card page only
- List page only
- Both Card and List (default / recommended)
Ask for the exact page names if not obvious from the entity name.
Question 5 — Approver routing
Which approver routing should the workflow template default to?
| Option | Description |
|---|
| Direct Approver | Routes to the user's direct approver in Approval User Setup (default) |
| First Qualified Approver | Routes to the first user with sufficient approval limit |
| Approver Chain | Routes through the full approval hierarchy |
| Specific User | Always routes to a fixed user |
Code Generation Steps
Step 1 — Read project metadata
- Read
app.json to obtain idRanges, affixes, name, publisher.
- Determine the affix (e.g.
BCS).
- Allocate object IDs for: Enum, Codeunit (Approval Mgmt.), Codeunit
(Workflow Setup), and optionally Table Extension / Page Extensions.
Step 2 — Determine naming
Derive names from the entity name and project affix:
| Artefact | Naming pattern | Example (entity = Statistical Account, affix = BCS) |
|---|
| Enum | <Affix> <Short> Appr. Status | BCS Stat. Acc. Appr. Status |
| Table Extension | <Affix> <Entity> | BCS Statistical Account |
| Approval Mgmt. CU | <Affix> <Short> Approval Mgmt. | BCS Stat. Acc. Approval Mgmt. |
| Workflow Setup CU | <Affix> <Short> Workflow Setup | BCS Stat. Acc. Workflow Setup |
| Page Extension (Card) | <Affix> <Entity> Card | BCS Statistical Account Card |
| Page Extension (List) | <Affix> <Entity> List | BCS Statistical Account List |
Step 3 — Determine folder structure
Place generated files under the appropriate feature folder:
Custom table (you own the table and page objects):
<feature-folder>/
├── Enum/
│ └── <Affix><ShortPascal>ApprStatus.Enum.al
├── Table/
│ └── <Affix><Entity>.Table.al (add field + OnDelete)
├── Page/
│ ├── <Affix><Entity>Card.Page.al (add actions + triggers)
│ └── <Affix><Entity>List.Page.al
└── Codeunit/
├── <Affix><ShortPascal>ApprovalMgmt.Codeunit.al
└── <Affix><ShortPascal>WorkflowSetup.Codeunit.al
Standard table (extend via tableextension / pageextension):
<feature-folder>/
├── Enum/
│ └── <Affix><ShortPascal>ApprStatus.Enum.al
├── Table Extension/
│ └── <Affix><Entity>.TableExt.al
├── Page Extension/
│ ├── <Affix><Entity>Card.PageExt.al
│ └── <Affix><Entity>List.PageExt.al
└── Codeunit/
├── <Affix><ShortPascal>ApprovalMgmt.Codeunit.al
└── <Affix><ShortPascal>WorkflowSetup.Codeunit.al
Step 4 — Generate the Approval Status Enum
Create an enum with four values: Open, Pending Approval, Rejected,
Approved. Mark as Extensible = true.
See: references/enum-template.md
Step 5 — Generate the Table / Table Extension
Add a field of the enum type with:
Editable = false
DataClassification = CustomerContent
Deletion guard logic:
- Blocks deletion if status is Approved or Pending Approval.
- Calls
ApprovalsMgmt.DeleteApprovalEntries(Rec.RecordId).
| Table type | Trigger | Template |
|---|
| Custom table | OnDelete directly in the table | references/custom-table-template.md |
| Standard table | OnBeforeDelete in a tableextension | references/table-extension-template.md |
Step 6 — Generate the Approval Management Codeunit
This is the core object. It contains:
- Integration event publishers —
OnSend…ForApproval, OnCancel…ApprovalRequest
- Validation —
Check…ApprovalPossible, Is…ApprovalWorkflowEnabled
- Event code identifiers —
Run…Code(): Code[128]
- Event subscribers for workflow events — handle
HandleEvent calls
- Event subscribers for the workflow library — register events and predecessors
- Event subscribers for approval entry — populate entry arguments
- Event subscribers for status updates — pending, approve, reject
- Event subscribers for response handling — release, open, response predecessors
- Card page mapping —
OnConditionalCardPageIDNotFound
See: references/approval-mgmt-codeunit-template.md
Step 7 — Generate the Workflow Setup Codeunit
Subscribes to Workflow Setup events to register:
- A workflow category (short code + description)
- Table relations linking the entity to
Approval Entry
- A workflow template with pre-configured steps
See: references/workflow-setup-codeunit-template.md
Step 8 — Generate Page / Page Extension(s)
For each target page (Card / List), add:
- The
Approval Status field in layout (with StyleExpr)
- An Approval action group with Send / Cancel actions
OnAfterGetRecord trigger logic for button enablement
- If sub-tables are locked:
Editable binding on subpage parts
OnOpenPage to set initial page editability
| Page type | Template |
|---|
| Custom page (you own the page object) | references/custom-page-card-template.md |
| Standard page (extend via pageextension) | references/page-extension-card-template.md |
Step 9 — Summary and next steps
After generating all files, present a summary:
Approval Workflow Generated for: [Entity Name]
Objects created:
- Enum [ID] "[Name]" — [file path]
- Table Extension [ID] "[Name]" — [file path] (if applicable)
- Codeunit [ID] "[Name]" — [file path]
- Codeunit [ID] "[Name]" — [file path]
- Page Extension [ID] "[Name]" — [file path]
- Page Extension [ID] "[Name]" — [file path]
Post-publish setup:
1. Publish the extension
2. Navigate to Workflows → create workflow from template
3. Configure Approval User Setup
4. Enable the workflow
5. Test: Send → Approve / Reject / Delegate / Cancel
Event Subscriber Reference
The approval management codeunit must subscribe to these standard events:
| Standard Codeunit | Event | Purpose |
|---|
Workflow Event Handling | OnAddWorkflowEventsToLibrary | Register send & cancel events |
Workflow Event Handling | OnAddWorkflowEventPredecessorsToLibrary | Chain events |
Approvals Mgmt. | OnPopulateApprovalEntryArgument | Fill Document No. / Table ID |
Approvals Mgmt. | OnSetStatusToPendingApproval | Status → Pending |
Approvals Mgmt. | OnApproveApprovalRequest | Status → Approved |
Approvals Mgmt. | OnRejectApprovalRequest | Status → Rejected |
Approvals Mgmt. | OnBeforeShowCommonApprovalStatus | Display message |
Workflow Response Handling | OnReleaseDocument | Status → Approved |
Workflow Response Handling | OnOpenDocument | Status → Open |
Workflow Response Handling | OnAddWorkflowResponsePredecessorsToLibrary | Link responses |
Page Management | OnConditionalCardPageIDNotFound | Card page mapping |
Workflow Setup | OnAddWorkflowCategoriesToLibrary | Register category |
Workflow Setup | OnAfterInsertApprovalsTableRelations | Table → Approval Entry |
Workflow Setup | OnInsertWorkflowTemplates | Create template |
Rules
- Always use the project affix for all object and field names.
- Enum values must be:
Open (0), Pending Approval (1), Rejected (2), Approved (3).
- The approval status field must be
Editable = false.
- Event code identifiers (
Code[128]) must be uppercase and unique.
- All
Modify() calls in approval status updates must use Modify(true).
- The workflow category code must be ≤ 20 characters and
Locked = true.
- If sub-tables need locking, bind
Editable on the subpage part to the
header's approval status = Open.
- Follow the instruction files for naming, code style, and performance.