Skip to content

Commit f35b111

Browse files
added new example to sign pdf
1 parent af56acc commit f35b111

7 files changed

Lines changed: 512 additions & 8 deletions

File tree

README.md

Lines changed: 253 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,258 @@
1-
# AL-Go Per Tenant Extension Template
1+
# Beyond PDF Signature - Custom Implementation Example
22

3-
This template repository can be used for managing AppSource Apps for Business Central.
3+
This repository demonstrates how to implement custom PDF signature functionality in Microsoft Dynamics 365 Business Central using the Beyond PDF Signature extension. The example shows how to add PDF signing capabilities to the Sales Shipment Header table, but the pattern can be applied to any table in Business Central.
44

5-
Please go to https://aka.ms/AL-Go to learn more.
5+
## Overview
66

7-
## Contributing
7+
This implementation provides:
8+
- **PDF Generation**: Automatically generates PDFs from Business Central reports
9+
- **Digital Signature**: Allows users to digitally sign PDF documents
10+
- **Document Storage**: Saves signed PDFs directly to the record using Media fields
11+
- **User Interface**: Adds signing actions to existing pages with intuitive controls
812

9-
Please read [this](https://github.com/microsoft/AL-Go/blob/main/Scenarios/Contribute.md) description on how to contribute to AL-Go for GitHub.
13+
## Architecture
1014

11-
We do not accept Pull Requests on the template repository directly.
15+
The solution consists of three main components:
16+
17+
### 1. Table Extension ([`SalesShipmentHeader.TableExt.al`](app/src/SalesShipmentHeader.TableExt.al))
18+
Extends the target table to store signed documents:
19+
20+
```al
21+
tableextension 50251 "ABC Sales Shipment Header" extends "Sales Shipment Header"
22+
{
23+
fields
24+
{
25+
field(50251; "ABC My Signed Document"; Media)
26+
{
27+
Caption = 'My Signed Document';
28+
Description = 'Holds the signed version of the sales shipment document after signing.';
29+
}
30+
}
31+
}
32+
```
33+
34+
### 2. Page Extension ([`PostedSalesShipment.PageExt.al`](app/src/PostedSalesShipment.PageExt.al))
35+
Adds signing functionality to the user interface:
36+
37+
- **Sign Document**: Action to initiate the signing process
38+
- **Show Signed Document**: Action to view previously signed documents
39+
- **Smart Enabling**: Actions are enabled/disabled based on document state
40+
41+
### 3. Handler Codeunit ([`SignSalesShipment.Codeunit.al`](app/src/SignSalesShipment.Codeunit.al))
42+
Implements the [`BYD PDF SIG IHandler`](app/src/SignSalesShipment.Codeunit.al:1) interface to handle PDF operations:
43+
44+
- **LoadPDF()**: Generates PDF from Business Central reports
45+
- **SavePDF()**: Stores signed PDF back to the record
46+
- **Initialization**: Sets up the handler with the current record
47+
48+
## How It Works
49+
50+
### Signing Process Flow
51+
52+
1. **User Initiates Signing**: User clicks "Sign Document with your Customer" action
53+
2. **PDF Generation**: System generates PDF using Business Central's report selection
54+
3. **Signature Interface**: [`BYD PDF SIG Signpad`](app/src/PostedSalesShipment.PageExt.al:23) page opens with the PDF
55+
4. **Digital Signing**: User and customer sign the document digitally
56+
5. **Document Storage**: Signed PDF is saved to the [`"ABC My Signed Document"`](app/src/SalesShipmentHeader.TableExt.al:5) field
57+
6. **UI Updates**: "Show Signed Document" action becomes available
58+
59+
### Key Features
60+
61+
- **Duplicate Prevention**: Warns users if document is already signed
62+
- **Report Integration**: Uses Business Central's standard report selection mechanism
63+
- **Media Storage**: Leverages native Media field type for efficient storage
64+
- **File Naming**: Generates consistent filenames for signed documents
65+
66+
## Implementation Guide
67+
68+
Follow these steps to implement PDF signature functionality for any table:
69+
70+
### Step 1: Create Table Extension
71+
72+
Create a table extension for your target table:
73+
74+
```al
75+
tableextension [YourID] "[Your Prefix] [Table Name]" extends "[Target Table]"
76+
{
77+
fields
78+
{
79+
field([YourFieldID]; "[Your Prefix] Signed Document"; Media)
80+
{
81+
Caption = 'Signed Document';
82+
Description = 'Holds the signed version of the document after signing.';
83+
}
84+
}
85+
}
86+
```
87+
88+
### Step 2: Create Handler Codeunit
89+
90+
Implement the [`BYD PDF SIG IHandler`](app/src/SignSalesShipment.Codeunit.al:1) interface:
91+
92+
```al
93+
codeunit [YourID] "[Your Prefix] Sign [Entity]" implements "BYD PDF SIG IHandler"
94+
{
95+
var
96+
[YourRecord]: Record "[Your Table]";
97+
TempBlob: Codeunit "Temp Blob";
98+
IsInitialized: Boolean;
99+
100+
procedure LoadPDF(var PDFStream: InStream): Boolean
101+
begin
102+
// Generate PDF from your report
103+
// Use ReportSelection.GetPdfReportForCust() or Report.SaveAs()
104+
// Return true if successful
105+
end;
106+
107+
procedure SavePDF(var PDFStream: InStream): Boolean
108+
begin
109+
// Save signed PDF to your Media field
110+
[YourRecord]."[Your Prefix] Signed Document".ImportStream(PDFStream, FileName, 'application/pdf');
111+
[YourRecord].Modify();
112+
exit([YourRecord]."[Your Prefix] Signed Document".HasValue());
113+
end;
114+
115+
procedure Set[YourRecord](Rec: Record "[Your Table]")
116+
begin
117+
[YourRecord] := Rec;
118+
IsInitialized := true;
119+
end;
120+
}
121+
```
122+
123+
### Step 3: Create Page Extension
124+
125+
Add signing actions to your page:
126+
127+
```al
128+
pageextension [YourID] "[Your Prefix] [Page Name]" extends "[Target Page]"
129+
{
130+
actions
131+
{
132+
addafter([ExistingAction])
133+
{
134+
action("[Your Prefix] Sign")
135+
{
136+
ApplicationArea = All;
137+
Caption = 'Sign Document';
138+
Image = Signature;
139+
140+
trigger OnAction()
141+
var
142+
[YourHandler]: Codeunit "[Your Prefix] Sign [Entity]";
143+
PDFSignaturePage: Page "BYD PDF SIG Signpad";
144+
begin
145+
// Initialize handler
146+
[YourHandler].Set[YourRecord](Rec);
147+
148+
// Set handler in PDF signature page
149+
PDFSignaturePage.SetPDFHandler([YourHandler]);
150+
151+
// Open signature page
152+
PDFSignaturePage.RunModal();
153+
end;
154+
}
155+
156+
action("[Your Prefix] ShowSigned")
157+
{
158+
ApplicationArea = All;
159+
Caption = 'Show Signed Document';
160+
Image = DocumentEdit;
161+
Enabled = IsAlreadySigned;
162+
163+
trigger OnAction()
164+
var
165+
TenantMedia: Record "Tenant Media";
166+
InS: InStream;
167+
begin
168+
if TenantMedia.Get(Rec."[Your Prefix] Signed Document".MediaId()) then
169+
if TenantMedia.Content.HasValue then begin
170+
TenantMedia.CalcFields(Content);
171+
TenantMedia.Content.CreateInStream(InS);
172+
File.ViewFromStream(InS, 'SignedDocument.pdf');
173+
end;
174+
end;
175+
}
176+
}
177+
}
178+
179+
trigger OnAfterGetCurrRecord()
180+
begin
181+
IsAlreadySigned := IsSignedAndSaved();
182+
end;
183+
184+
local procedure IsSignedAndSaved(): Boolean
185+
var
186+
TenantMedia: Record "Tenant Media";
187+
begin
188+
if not TenantMedia.Get(Rec."[Your Prefix] Signed Document".MediaId()) then
189+
exit(false);
190+
exit(TenantMedia.Content.HasValue());
191+
end;
192+
193+
var
194+
IsAlreadySigned: Boolean;
195+
}
196+
```
197+
198+
## Prerequisites
199+
200+
1. **Beyond PDF Signature Extension**: Install the Beyond PDF Signature extension in your Business Central environment from Appsource
201+
2. **Report Configuration**: Ensure your target table has associated reports configured in Report Selections
202+
3. **Permissions**: Users need appropriate permissions to modify the target table and access the signing functionality
203+
204+
## Customization Options
205+
206+
### PDF Source Customization
207+
208+
Modify the [`LoadPDF()`](app/src/SignSalesShipment.Codeunit.al:14) method to:
209+
- Use different reports
210+
- Apply custom filters
211+
- Generate PDFs from multiple sources
212+
- Add custom headers/footers
213+
214+
### Storage Customization
215+
216+
Modify the [`SavePDF()`](app/src/SignSalesShipment.Codeunit.al:39) method to:
217+
- Save to Document Attachments instead of Media fields
218+
- Implement custom file naming conventions
219+
- Add metadata or tags
220+
- Integrate with external document management systems
221+
222+
### UI Customization
223+
224+
Modify the page extension to:
225+
- Add custom validation before signing
226+
- Implement approval workflows
227+
- Add audit trail functionality
228+
- Customize action placement and appearance
229+
230+
## Best Practices
231+
232+
1. **Error Handling**: Implement comprehensive error handling for PDF generation and storage
233+
2. **Performance**: Use temporary blobs for large PDF operations
234+
3. **Security**: Validate user permissions before allowing signing operations
235+
4. **Naming Conventions**: Use consistent prefixes to avoid conflicts
236+
5. **Testing**: Test with various document sizes and user scenarios
237+
238+
## Troubleshooting
239+
240+
### Common Issues
241+
242+
- **PDF Generation Fails**: Check report selection configuration and permissions
243+
- **Signing Page Doesn't Open**: Verify Beyond PDF Signature extension is installed and configured
244+
- **Signed Document Not Saved**: Check table permissions and Media field configuration
245+
246+
### Debug Tips
247+
248+
- Use the debugger to step through the [`LoadPDF()`](app/src/SignSalesShipment.Codeunit.al:14) and [`SavePDF()`](app/src/SignSalesShipment.Codeunit.al:39) methods
249+
- Check the Event Log for any system errors
250+
- Verify the TempBlob has content before attempting to save
251+
252+
## Support
253+
254+
For issues related to the Beyond PDF Signature extension itself, contact the extension provider. For implementation questions, refer to the Microsoft Dynamics 365 Business Central documentation.
255+
256+
## License
257+
258+
This example implementation is provided as-is for educational purposes. Ensure compliance with your organization's licensing requirements when implementing in production environments.

al.code-workspace

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,39 @@
22
"folders": [
33
{
44
"path": ".AL-Go"
5+
},
6+
{
7+
"path": "app"
8+
},
9+
{
10+
"path": ".alpackages"
511
}
612
],
7-
"settings": {}
8-
}
13+
"settings": {
14+
"CRS.FileNamePattern": "<ObjectNameShort>.<ObjectTypeShortPascalCase>.al",
15+
"CRS.FileNamePatternExtensions": "<ObjectNameShort>.<ObjectTypeShortPascalCase>.al",
16+
"CRS.FileNamePatternPageCustomizations": "<ObjectNameShort>.<ObjectTypeShortPascalCase>.al",
17+
"CRS.OnSaveAlFileAction": "Rename",
18+
"CRS.RenameWithGit": false,
19+
"CRS.ObjectNamePrefix": "ABC ",
20+
"CRS.RemovePrefixFromFilename": true,
21+
"workbench.iconTheme": "vscode-icons",
22+
"todo-tree.highlights.enabled": true,
23+
"telemetry.enableTelemetry": false,
24+
"editor.quickSuggestionsDelay": 2,
25+
"editor.suggestSelection": "first",
26+
"editor.quickSuggestions": {
27+
"other": true,
28+
"comments": false,
29+
"strings": false
30+
},
31+
"editor.tabCompletion": "onlySnippets",
32+
"al.enableCodeActions": true,
33+
"al.enableCodeAnalysis": true,
34+
"al.codeAnalyzers": [
35+
"${CodeCop}",
36+
"${UICop}"
37+
],
38+
"al-test-runner.sendDebugTelemetry": false
39+
}
40+
}

app/.vscode/launch.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
{
5+
"name": "Your own server",
6+
"request": "launch",
7+
"type": "al",
8+
"environmentType": "OnPrem",
9+
"server": "http://de-bc26",
10+
"serverInstance": "BC",
11+
"authentication": "UserPassword",
12+
"startupObjectId": 130,
13+
"startupObjectType": "Page",
14+
"breakOnError": "All",
15+
"launchBrowser": true,
16+
"enableLongRunningSqlStatements": true,
17+
"enableSqlInformationDebugger": true,
18+
"tenant": "default",
19+
"usePublicURLFromServer": true,
20+
"schemaUpdateMode": "ForceSync"
21+
}
22+
]
23+
}

app/app.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"id": "92e2f306-78cd-47d6-ad6a-371870a24a11",
3+
"name": "BeyondPDFSignature for Shipment Notes",
4+
"publisher": "BEYONDIT GmbH",
5+
"version": "2025.8.0.0",
6+
"brief": "Manage your invoices with BeyondSignature in Business Central.",
7+
"description": "Visit https://www.beyondit.gmbh/",
8+
"url": "https://beyond365.de",
9+
"supportedLocales": [
10+
"de-DE",
11+
"en-US"
12+
],
13+
"propagateDependencies": true,
14+
"dependencies": [
15+
{
16+
"id": "a2c0b38e-ee2e-4d28-b499-1b763776384b",
17+
"name": "Beyond PDF Signature",
18+
"publisher": "BEYONDIT GmbH",
19+
"version": "2025.0.0.0"
20+
}
21+
],
22+
"application": "26.0.0.0",
23+
"platform": "26.0.0.0",
24+
"idRanges": [
25+
{
26+
"from": 50251,
27+
"to": 50260
28+
}
29+
],
30+
"runtime": "15.0",
31+
"features": [
32+
"TranslationFile",
33+
"NoImplicitWith"
34+
],
35+
"target": "Cloud"
36+
}

0 commit comments

Comments
 (0)