Building a Document Output extension app
The Continia Document Output Extension Builder lets you generate a ready-to-finish Document Output (DO) extension for your own documents and tables, without hand-writing the boilerplate that wires a page and its table into Document Output.
You tell the tool which email templates and which Microsoft Dynamics 365 Business Central pages you want to enable for Document Output, and it generates:
- FactBox pages that host the Document Output actions (Open/Send/Queue email, Print PDF, Save PDF).
- Page extensions that place those actions and a Document Output Log FactBox on your pages.
- Table extensions that expose the same actions as callable procedures.
- A subscriber codeunit that tells Document Output how to resolve your records (the
OnGetVariantRecordevent). - Optionally, a stub codeunit for supplying your own merge-field values.
Wichtig
The output is source code, not an installable app. The tool produces AL source files packaged into a .zip that your browser downloads. It does not produce a compiled .app. You open the ZIP in Visual Studio Code, review and finish the code, compile it yourself, and then publish it to your environment.
The feature is exposed to users through the page Document Output Extension Apps (found using the search () field). Internally, the objects are named Extension App (there's no object literally called "Extension Builder").
Prerequisites
Before you can download an app, the following must be filled in. These are enforced by the tool and will raise an error if missing.
On the app header (the card)
The following required fields must be filled in:
- App Name
- Publisher
- Version
- Object ID Range Min.
- Object ID Range Max.
You must own (be licensed for) the object ID range you enter – the generated objects are numbered inside it.
For each email template you add (Templates list)
- Template Code – an existing Document Output email template.
- FactBox Page No. and FactBox Name – auto-filled when you pick the template, but must not be blank at download time.
- The selected email template header must have a First Table in Report defined. This is the table the generated FactBox page and table extension are built on. A template without a first report table can't be used.
For each page you add (Pages to extend list)
- Page No. to extend – the Business Central page you want to enable.
- Page Extension Name – auto-filled from the page name, but must not be blank.
- Email Template Code – see the following note:
Hinweis
A page row is only generated if its Email Template Code matches one of your Template rows.
Generation walks the templates and, for each one, emits page extensions only for the page rows whose Email Template Code equals that template's code. A page row with a blank or non-matching template code is silently skipped. Always set the template code on every page row.
Limitation: two primary-key fields at most
The source table behind a page you extend may have no more than two primary-key fields. If it has three or more, the download fails with the following message:
Table <no> <name> has more then 2 primary keys. This is not allowed.
This limit exists because the generated Document Output Log FactBox links to your record using only Primary Key Field 1 Value and Primary Key Field 2 Value. Tables with a three-part (or larger) primary key can't be wired up automatically – you'd need to build the extension by hand for those.
To generate an extension app
The editor is a standard Card page – there's no assisted setup guide. Work top to bottom.
To generate an extension app, follow these steps:
Search () for and select Document Output Extension Apps. The list of previously created apps appears.
To create a new app, click New. A card opens with sensible defaults already filled in:
- App ID – a new GUID.
- Version –
1.0.0.0. - App Name – an incrementing default such as DO extension for project1.
- Publisher – Default publisher.
- Object ID Range Min./Max. – the next free 50-ID window (see Object ID range handling below).
Fill in the General group: Replace the defaults with your real App Name, Publisher, and Version, and set the Object ID Range Min./Max. to a range you own. Turn on Add MergeFieldValueFinder Codeunit if you want the merge-field stub included.
Note
The On Premise settings (Developer Services SSL Enabled/Port) only matter for on-premises debugging. Leave them blank for cloud.
Optional: Add dependency apps: In Dependency Apps, add a row for every extra app your generated code will reference (beyond Continia Document Output, which is always added). Fill in App ID, App Name, App Publisher, App Version, and leave Enabled on. Disabled rows and rows with an empty App ID are ignored.
Add email templates: In Templates used with this app, add a row and pick a Template Code. The tool auto-fills:
FactBox Page No. – the next free ID in your range.
FactBox Name – the template code in lower case followed by
Actions(for example,salesinvoiceActions).Note
It also shows the template's First Table in Report (number and name) so you can confirm which table the app will target.
Add pages to extend: In Pages to extend with Document Output FactBoxes, add a row and set Page No. to extend. The tool auto-fills:
- Page Extension No. – the next free ID in your range.
- Page Extension Name – the page name without spaces followed by
FactBox.
Set the Email Template Code to match the template this page uses (required – see the note in Prerequisites above). Leave Document Output Action FactBox and Document Output Log FactBox on unless you want to omit one of them.
Click Download App to download. The tool validates everything and builds the ZIP, and your browser downloads
<App Name>.zip.
Object ID range handling
The generated objects are numbered from Object ID Range Min. upward, so getting the range right matters.
- Defaults. A brand-new app starts at 52500–52549 (a 50-ID window).
- Automatic free range. When you create a new app, the tool scans existing apps and, if the default window overlaps one, moves your window past it – preserving the same width. So the second app you create lands on 52550–52599, and so on.
- Changing the minimum. If you edit Object ID Range Min. after adding templates or pages, the tool asks "Do you want to renumber existing pages?". Choosing Yes renumbers the FactBox pages and page extensions sequentially from the new minimum. Either way, Object ID Range Max. is recalculated to keep the original span.
- How generated objects are numbered:
| Generated object | ID |
|---|---|
| FactBox pages and page extensions | Assigned from Min upward as you add rows (first come, first served) |
| Table extensions (one per source table) | Min, Min+1, Min+2, etc. |
OnGetVariantSubscriber codeunit | Min |
MyMergeFieldValueFinder codeunit (optional) | Min+1 |
Pages, table extensions, and codeunits can share the same number (for example page 52500, table extension 52500, codeunit 52500) because AL object IDs are unique per object type. Make sure your range is wide enough for the number of pages you add – the generated page IDs climb from Min and are not capped at Max.
What the download contains
Unzipping <App Name>.zip gives you a normal AL project:
| File | Purpose |
|---|---|
app.json | The app manifest: your ID/name/publisher/version, your ID range, and dependencies. A dependency on Continia Document Output (Continia Software) is always declared, plus any dependency apps you added. application, platform, and runtime are derived from the environment you downloaded from; target is Cloud. |
.vscode\launch.json | A single AL launch configuration pre-filled from your current Business Central session (see Finishing the app in Visual Studio Code below). |
Page <id> <FactBoxName>.al | One FactBox page (CardPart) per template. Hosts the Recipient field and the Open/Send/Queue email, Print PDF, and Save PDF actions, calling the CDO Email Handler codeunit. |
Pageextension <id> <name>.al | One page extension per "page to extend" row. Adds the Document Output actions FactBox and/or Log FactBox to the page, plus a Document Output action group (and promoted group) with the five actions. |
TableExtensions.al | One table extension per distinct source table, named DO<TableName>Ext, adding CDOOpenEMail, CDOSendEMail, CDOQueueEMail, CDOPrintPDF, and CDOSavePDF procedures. |
Codeunit <id> OnGetVariantSubscriber.al | Subscribes to CDO Events.OnGetVariantRecord and, per source table, hands Document Output the correct record variant. This is what lets Document Output resolve your documents. |
Codeunit <id> MyMergeFieldValueFinder.al | Only if Add MergeFieldValueFinder Codeunit was on. A stub for returning your own merge-field values (see Finishing the app in Visual Studio Code below). |
Finishing the app in Visual Studio Code
This is the developer part. The ZIP is a starting point, not a finished, compilable app.
To finish the app in Visual Studio Code, follow these steps:
Unzip and open: Extract the ZIP and open the folder in VS Code with the AL Language extension installed.
Download symbols: The generated
.vscode\launch.jsonis pre-filled from the Business Central session you downloaded from – environment type (on-premises/production/sandbox), server, server instance, and (on-premises) port. Use it to run AL: Download Symbols.Note
The launch configuration's authentication is hard-coded to
Windows. For a cloud/SaaS target, you'll need to change it (for example toMicrosoftEntraID) before symbols download or publishing will work.Make dependency symbols available: Compilation needs the symbol packages for everything in
app.json: Continia Document Output, the base Application/System apps, and any Dependency Apps you added. The Document Output dependency is pinned to a fixed version inapp.json– adjust it to match the version installed in your target environment.Implement the merge-field finder (if generated):
MyMergeFieldValueFinderships as a placeholder. It contains the comment "Replace the sample code to return your merge field value here" and aSalesHeaderGetFullDocTypesample that only works when the template's table is Sales Header. Replace the sample'YourParameter'case and the sample procedure with your own logic for your tables.Review the rest: Update the placeholder
brief/descriptioninapp.json, confirm the generated object names and IDs, and check that the FactBox/page extensions look right.Compile, then build and publish: Compile the project, build the
.appyourself (there's no server-side build – nothing produced a.appfor you), and publish/install it into the target environment.
Button and field reference
Page: Document Output Extension Apps (list)
| Action | What it does |
|---|---|
| Download App | Generates the source ZIP for the selected app and downloads it. (The tooltip currently says ".app", but it's in fact a source .zip.) |
| Field | Meaning |
|---|---|
| App ID | The app's GUID (generated). |
| App Name | Name of the app. |
| Publisher | Publisher of the app. |
| Version | App version. |
| Templates | Number of email templates configured on this app. |
| Pages to extend | Number of pages that will get Document Output FactBoxes. |
New rows can't be inserted directly on the list. Clicking New opens the card.
Page: Extension App Card
General group
| Field | What to enter |
|---|---|
| App ID | GUID of the app (generated; normally leave as is). |
| App Name | The name of the extension app. Also used as the ZIP file name. |
| Publisher | Your publisher name. |
| Version | The app version (defaults to 1.0.0.0). |
| Object ID Range Min. | First object ID to use. Must be in a range you own. Changing it can renumber existing pages. |
| Object ID Range Max. | Last object ID to use. Recalculated to keep the range width when you change the minimum. |
| Add MergeFieldValueFinder Codeunit | Include the merge-field-finder stub codeunit in the download. |
On Premise settings group (on-premises only)
| Field | What to enter |
|---|---|
| Developer Services SSL Enabled | Whether the dev services endpoint uses SSL. Written into launch.json. |
| Developer Services Port | The dev services port. Written into launch.json when non-zero. |
Action
| Action | What it does |
|---|---|
| Download App | Validates the setup and downloads the source ZIP. |
Sub-page: Templates used with this app
| Field | What to enter/meaning |
|---|---|
| Template Code | The Document Output email template to expose. Selecting it auto-fills FactBox Page No. and FactBox Name. |
| FactBox Page No. | ID of the generated FactBox page (auto-filled from the ID range). |
| FactBox Name | Object name of the generated FactBox page (auto: template code + Actions). |
| First Table in Report | The table number the template is built on (from the template header). |
| First Table in Report Name | The name of that table. |
Sub-page: Pages to extend with Document Output FactBoxes
| Field | What to enter/meaning |
|---|---|
| Page No. to extend | The Business Central page to extend. Selecting it auto-fills the extension no. and name. |
| Page No. to extend Name | Name of the page being extended (read-only). |
| Page Extension No. | ID of the generated page extension (auto-filled from the ID range). |
| Page Extension Name | Object name of the generated page extension (auto: page name + FactBox). |
| Email Template Code | The template whose FactBox goes on this page. Must match a Templates row, or the page is skipped. |
| Document Output Action FactBox | Include the Document Output actions FactBox on the page (default on). |
| Document Output Log FactBox | Include the Document Output Log FactBox on the page (default on). |
Sub-page: Dependency Apps
| Field | What to enter / meaning |
|---|---|
| Enabled | Include this dependency in app.json (default on). |
| App ID | GUID of the dependency app. Rows with an empty ID are ignored. |
| App Name | Name of the dependency app. |
| App Publisher | Publisher of the dependency app. |
| App Version | Version of the dependency app. |